ssafronova (ssafronova) wrote in changelog,
ssafronova
ssafronova
changelog

[ljcom] r10079: LJSUP-7762: Mail.ru connect

Committer: ssafronova
LJSUP-7762: Mail.ru connect
U   trunk/bin/upgrading/proplists-local.dat
A   trunk/cgi-bin/LJ/Identity/MailRU.pm
A   trunk/htdocs/identity/callback-mailru.bml
U   trunk/htdocs/identity/login.bml.text.local
A   trunk/htdocs/identity/mailru-interstitial.bml
A   trunk/htdocs/identity/mailru-interstitial.bml.text.local
U   trunk/htdocs/userinfo.bml.text.local
A   trunk/templates/Identity/Login-mailru.tmpl
Modified: trunk/bin/upgrading/proplists-local.dat
===================================================================
--- trunk/bin/upgrading/proplists-local.dat	2011-02-18 08:48:10 UTC (rev 10078)
+++ trunk/bin/upgrading/proplists-local.dat	2011-02-18 10:19:13 UTC (rev 10079)
@@ -642,3 +642,35 @@
     indexed: 0
     multihomed: 0
     prettyname: Create post
+
+userproplist.mailru_access_token:
+  indexed: 0
+  cldversion: 8
+  multihomed: 0
+  datatype: char
+  des: an access token for accessing the user's data on mail.ru
+  prettyname: access token for mail.ru
+
+userproplist.mailru_refresh_token:
+  indexed: 0
+  cldversion: 8
+  multihomed: 0
+  datatype: char
+  des: token for restoring expired access token for mail.ru
+  prettyname: refresh token for mail.ru
+
+userproplist.mailru_nick:
+  indexed: 0
+  cldversion: 8
+  multihomed: 0
+  datatype: char
+  des: nick at mail.ru for this identity account
+  prettyname: mail.ru nick
+
+userproplist.mailru_link:
+  indexed: 0
+  cldversion: 8
+  multihomed: 0
+  datatype: char
+  des: link in mail.ru for this identity account
+  prettyname: mail.ru nick

Added: trunk/cgi-bin/LJ/Identity/MailRU.pm
===================================================================
--- trunk/cgi-bin/LJ/Identity/MailRU.pm	                        (rev 0)
+++ trunk/cgi-bin/LJ/Identity/MailRU.pm	2011-02-18 10:19:13 UTC (rev 10079)
@@ -0,0 +1,144 @@
+package LJ::Identity::MailRU;
+use strict;
+
+use base qw(LJ::Identity);
+use Digest::MD5;
+
+sub typeid { 'M' }
+sub pretty_type { 'Mail.ru' }
+sub short_code { 'mailru' }
+
+sub enabled {
+    return $LJ::MAILRU_CONNECT_CLIENT_ID;
+}
+
+sub attempt_login {
+    my ($class, $errs, %opts) = @_;
+
+    my $forwhat = $opts{'forwhat'} || 'login';
+
+    my $callback_url = "$LJ::SITEROOT/identity/callback-mailru.bml?" .
+                       'forwhat=' . $forwhat;
+
+    my $addr = 'https://connect.mail.ru/oauth/authorize?' .
+               "client_id=$LJ::MAILRU_CONNECT_CLIENT_ID&" .
+               'response_type=code&redirect_uri=' . LJ::Text->eurl($callback_url);
+
+    return LJ::Request->redirect($addr);
+}
+
+sub url { 
+    my ($self, $u) = @_;
+
+    return $u->prop('mailru_link');
+}
+
+sub initialize_user {
+    my ($self, $u, $extra) = @_;
+
+warn 'initialize_user';
+
+=comment: example of $extra
+{
+  "refresh_token":"a45529ac9bf6b32be761975c043ef9e3",
+  "expires_in":86400,
+  "access_token":"56a59ff5d5cf9645b872750454d8a27b",
+  "x_mailru_vid":"1324730981306483817"
+}
+=cut
+
+    my $token = $extra->{'access_token'};
+    die "no access token passed" unless $token;
+
+    my $ua = LJ::get_useragent( 'role' => 'mailru_auth' );
+
+    my %fields = (
+        method => 'users.getInfo',
+        app_id => $LJ::MAILRU_CONNECT_CLIENT_ID,
+        session_key => $token,
+        secure => 1, # server-server
+        format => 'json', # 'json' or 'xml'
+        uids => $extra->{'x_mailru_vid'},
+    );
+
+    my $params = join('', map { "$_=$fields{$_}" } sort keys %fields ) . $LJ::MAILRU_SECRET_API_KEY;
+    my $sig = Digest::MD5::md5_hex($params);
+
+    my $res = $ua->get('http://www.appsmail.ru/platform/api?' .
+                       join('&', map { "$_=$fields{$_}" } keys %fields) .
+                       "&sig=$sig" 
+                      );
+
+=comment Error codes:
+1   Unknown error: Please resubmit the request.
+2   Unknown method called.
+3   Method is deprecated.
+100 One of the parameters specified is missing or invalid.
+102 User authorization failed: the session key or uid is incorrect.
+103 Application lookup failed: the application id is not correct.
+104 Incorrect signature.
+105 Application is not installed for this user.
+200 Permission error: the application does not have permission to perform this action.
+=cut
+
+    my $userdata = eval { LJ::JSON->from_json($res->content) };
+    die "Strange answer from mail.ru about '$fields{uids}', error: $@, returned: <" . $res->content . ">"
+        if $@;
+    die "Strange answer rom mail.ru about '$fields{uids}', not an array ref,  returned: <" . $res->content . ">"
+        unless ref $userdata eq 'ARRAY';
+    $userdata = $userdata->[0];
+
+    die "Strange answer from mail.ru about '$fields{uids}' user: <" . $res->content . ">, '$userdata->{uid}'"
+        unless $userdata->{uid} eq $fields{uids};
+
+    $u->set_prop({ mailru_access_token  => $extra->{'access_token'},
+                   mailru_refresh_token => $extra->{'refresh_token'},
+                   mailru_nick          => $userdata->{'nick'},
+                   mailru_link          => $userdata->{'link'},
+                   gender               => ($userdata->{'sex'} ? 'F' : 'M'), 
+                   # TODO: city, state, country must be here
+                });
+
+    my ($bday, $bmonth, $byear) = ($userdata->{'birthday'} =~ /^(\d+)\.(\d+)\.(\d+)$/);
+
+    LJ::update_user($u, { name  => "$userdata->{'first_name'} $userdata->{'last_name'}",
+                          ( $bday and $bmonth and $byear ? (bdate => "$byear-$bmonth-$bday") : () ),
+                          opt_gettalkemail => 'N',
+                          status           => 'A', # we don't care, set it as validated as well
+                    });
+
+    $u->set_email($userdata->{'email'});
+
+    # userpic
+    $res = $ua->get($userdata->{'pic'});
+    my $upidata = eval { $res->content };
+    my $userpic = eval { LJ::Userpic->create($u, data => \$upidata) };
+    $userpic->make_default if $userpic;
+
+    $u->add_to_class('plus');
+
+    # ping events feed to let subscribers know of this account
+    LJ::run_hooks('profile_save', $u);
+}
+
+sub display_name {
+    my ($self, $u) = @_;
+    return $u->prop('mailru_nick') || $u->username;
+}
+
+sub ljuser_display_params {
+    my ($self, $u, $opts) = @_;
+
+    return {
+        'journal_url'  => $u->prop('mailru_link') || 'about:blank',
+        'journal_name' => $u->display_name,
+        'userhead'     => 'mailru-profile.gif',
+        'userhead_w'   => 16,
+    };
+}
+
+sub profile_window_title {
+    return LJ::Lang::ml('/userinfo.bml.title.mailruprofile');
+}
+
+1;

Added: trunk/htdocs/identity/callback-mailru.bml
===================================================================
--- trunk/htdocs/identity/callback-mailru.bml	                        (rev 0)
+++ trunk/htdocs/identity/callback-mailru.bml	2011-02-18 10:19:13 UTC (rev 10079)
@@ -0,0 +1,92 @@
+<?page
+body<=
+<?_code
+{
+#line 6
+    use strict;
+    use vars qw($title);
+
+    # this title used in case of hard errors
+    $title = 'Mail.ru Connecting Page';
+
+    my $forwhat = LJ::Request->get_param('forwhat') || 'login';
+
+    my ($returl, $returl_fail);
+    eval {
+        ($returl, $returl_fail) =
+        LJ::Identity::MailRU->unpack_forwhat($forwhat);
+    };
+
+    return LJ::Lang::ml('error.invalidform') if $@;
+
+
+    unless (LJ::Identity::MailRU->enabled) {
+        return 'This feature is disabled.';
+    }
+
+    my $code = LJ::Request->get_param('code');
+
+    unless ($code) {
+        return LJ::Request->redirect($returl_fail)
+            if LJ::Request->get_param('error_reason') eq 'user_denied';
+
+        require Data::Dumper;
+        warn "mail.ru (code) connectivity error: " .
+            Data::Dumper::Dumper(\%GET);
+
+        return '<?errorbar Mail.ru connectivity error errorbar?>';
+    }
+
+    # "redirect_uri — адрес вашей принимающей страницы, который вы указывали при обращении к /oauth/authorize"
+    # cite from http://api.mail.ru/docs/guides/oauth/sites/ (russian only)
+    my $selfurl = "$LJ::SITEROOT/identity/callback-mailru.bml?" .
+                  'forwhat=' . $forwhat;
+
+    my $ua = LJ::get_useragent( 'role' => 'mailru_auth' );
+    my $res = $ua->post('https://connect.mail.ru/oauth/token',
+                        [ client_id => $LJ::MAILRU_CONNECT_CLIENT_ID, # '[]' are important here
+                        client_secret => $LJ::MAILRU_SECRET_API_KEY,
+                        grant_type => 'authorization_code',
+                        redirect_uri => $selfurl,
+                        code => $code, ]
+                       );
+
+    unless ($res->is_success) {
+        require Data::Dumper;
+        warn "mailru (tokens) connectivity error: " .
+            Data::Dumper::Dumper($res);
+
+        return '<?errorbar Mail.ru connectivity error errorbar?>';
+    }
+
+    my $params = eval { LJ::JSON->from_json($res->content) };
+
+    my $created;
+    # x_mailru_vid from authorization_code grant_type, mailru_vid from password grant type
+    # I am afraid of mistyping in documentation
+    my $u = LJ::User::load_identity_user('M', $params->{'x_mailru_vid'} || $params->{'mailru_vid'}, $params, \$created);
+
+    # send out a P3P header thing so as to work around IE's
+    # unwillingness to receive our cookies while we're in an iframe
+    # affects the partner sites authorization
+    LJ::Session->allow_login_from_iframe;
+
+    $u->make_login_session('long', 0);
+    LJ::set_remote($u);
+
+    return LJ::Request->redirect($returl) unless $created;
+
+    my $redirect_url = "$LJ::SITEROOT/identity/mailru-interstitial.bml?" .
+                       'ret=' . LJ::eurl($returl) . '&' .
+                       'forwhat=' . LJ::eurl($forwhat);
+
+    return LJ::Request->redirect($redirect_url);
+
+}
+_code?>
+<=body
+title=><?_code return $title; _code?>
+head<=
+<?_code return $headextra; _code?>
+<=head
+page?>

Modified: trunk/htdocs/identity/login.bml.text.local
===================================================================
--- trunk/htdocs/identity/login.bml.text.local	2011-02-18 08:48:10 UTC (rev 10078)
+++ trunk/htdocs/identity/login.bml.text.local	2011-02-18 10:19:13 UTC (rev 10079)
@@ -2,8 +2,14 @@
 
 .facebook.desc=Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut gravida nunc vitae purus egestas lobortis. Morbi varius ligula vitae diam vehicula a elementum felis sagittis. Morbi in sapien sit amet lectus dignissim consequat nec eu arcu.
 
+.mailru.btn.connect=Enter from @Mail.ru
+
+.mailru.desc=Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut gravida nunc vitae purus egestas lobortis. Morbi varius ligula vitae diam vehicula a elementum felis sagittis. Morbi in sapien sit amet lectus dignissim consequat nec eu arcu.
+
 .tab.facebook=Facebook
 
+.tab.mailru=Mail.ru
+
 .tab.user=LiveJournal
 
 .tab.twitter=Twitter

Added: trunk/htdocs/identity/mailru-interstitial.bml
===================================================================
--- trunk/htdocs/identity/mailru-interstitial.bml	                        (rev 0)
+++ trunk/htdocs/identity/mailru-interstitial.bml	2011-02-18 10:19:13 UTC (rev 10079)
@@ -0,0 +1,148 @@
+<?page
+body<=
+<?_code
+{
+#line 6
+    use strict;
+    use vars qw($title);
+
+# copy from facebook-interstitial.bml, with little modifications
+
+    use Carp qw();
+
+    $title = LJ::Lang::ml('.title');
+
+    my $remote = LJ::get_remote();
+    unless (    $remote
+             && $remote->is_identity
+             && $remote->identity->short_code eq 'mailru' )
+    {
+        return LJ::Request->redirect("$LJ::SITEROOT/login.bml");
+    }
+
+    my $returl  = LJ::Request->get_param('ret') || $LJ::SITEROOT;
+    my $forwhat = LJ::Request->get_param('forwhat') || 'login';
+
+    my $external_site_case = ( $forwhat eq 'external' );
+
+    my @errors;
+
+    my $subscribe = sub {
+        my ($u) = @_;
+
+        # default is 'Y' which is unappropriate for us
+        LJ::update_user($u, {'opt_gettalkemail' => 'N'});
+
+        my @subs = (
+            'CommentReply',
+            'Befriended-u',
+            'UserMessageRecvd-u',
+            'InvitedFriendJoins-u',
+            'NewUserpic',
+            'Birthday',
+            'NewVGift',
+        );
+
+        ## LJINT-362 (Comments for side projects):
+        ## in case an account is created on an external site, only
+        ## subscribe them to comment replies
+        if ( $external_site_case ) {
+            @subs = qw( CommentReply );
+        }
+
+        my $set = LJ::Subscription::GroupSet->fetch_for_user($u);
+        my $newset = $set->clone;
+
+        my @ntypeids = map { LJ::NotificationMethod->method_to_ntypeid($_) }
+            qw(Inbox Email);
+
+        foreach my $subcode (@subs) {
+            my $journalid = 0;
+
+            if ($subcode =~ /\-u$/) {
+                $journalid = $u->id;
+                $subcode =~ s/\-u$//;
+            }
+
+            my %sub = (
+                'userid' => $u->id,
+                'journalid' => $journalid,
+                'etypeid' => LJ::Event->event_to_etypeid($subcode),
+                'arg1' => 0,
+                'arg2' => 0,
+                'is_dirty' => 0,
+                'ntypeid' => 0,
+                'createtime' => time,
+                'expiretime' => 0,
+                'flags' => 0,
+            );
+
+            foreach my $ntypeid (@ntypeids) {
+                $sub{'ntypeid'} = $ntypeid;
+                $newset->insert_sub(bless({%sub}, 'LJ::Subscription'));
+            }
+        }
+
+        eval {
+            $set->update($newset);
+        };
+
+        if ($@) {
+            # theoretically, we didn't subscribe to any tracking subs yet,
+            # so there shouldn't be any errors, but if there are any,
+            # let's report
+            Carp::cluck "error subscribing user: " . $u->id;
+        }
+
+        return LJ::Request->redirect($returl);
+    };
+
+    my $handle_post = sub {
+        if (!LJ::check_form_auth()) {
+            push @errors, LJ::Lang::ml('error.invalidform');
+            return;
+        }
+
+        if (!LJ::Request->post_param('subscribe')) {
+            return LJ::Request->redirect($returl);
+        }
+
+        return $subscribe->($remote);
+    };
+
+    ## LJINT-362 (Comments for side projects):
+    ## in case an account is created on an external site, subscribe
+    ## them to comment replies and redirect back immediately
+    if ( $external_site_case ) {
+        return $subscribe->($remote);
+    }
+
+    if (LJ::Request->did_post) {
+        $handle_post->();
+        return if LJ::Request->redirected;
+    }
+
+    my $template = LJ::HTML::Template->new(
+        { use_expr => 1 }, # force HTML::Template::Pro with Expr support
+        filename => "$ENV{'LJHOME'}/templates/Identity/MailruInterstitial.tmpl",
+        die_on_bad_params => 0,
+        strict => 0,
+    ) or die "Can't open template: $!";
+
+    $template->param(
+        'errors' => [ map { { 'error' => $_ } } @errors ],
+        'form_intro' => LJ::form_auth(),
+        'ml_congrats' => LJ::Lang::ml('.congrats', {
+            'username' => $remote->ljuser_display,
+        }),
+    );
+
+    return $template->output;
+}
+_code?>
+<=body
+title=><?_code return $title; _code?>
+head<=
+<?_code return $headextra; _code?>
+<=head
+page?>

Added: trunk/htdocs/identity/mailru-interstitial.bml.text.local
===================================================================
--- trunk/htdocs/identity/mailru-interstitial.bml.text.local	                        (rev 0)
+++ trunk/htdocs/identity/mailru-interstitial.bml.text.local	2011-02-18 10:19:13 UTC (rev 10079)
@@ -0,0 +1,13 @@
+.btn.proceed=Save
+
+.congrats=Congratulations, [[username]], your accounts are now connected.
+
+.desc=Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut gravida nunc vitae purus egestas lobortis. Morbi varius ligula vitae diam vehicula a elementum felis sagittis. Morbi in sapien sit amet lectus dignissim consequat nec eu arcu.
+
+.heading.subscribe=Do you want to receive email notifications?
+
+.label.subscribe.yes=Yes
+
+.label.subscribe.no=No
+
+.title=Login with Mail.ru

Modified: trunk/htdocs/userinfo.bml.text.local
===================================================================
--- trunk/htdocs/userinfo.bml.text.local	2011-02-18 08:48:10 UTC (rev 10078)
+++ trunk/htdocs/userinfo.bml.text.local	2011-02-18 10:19:13 UTC (rev 10079)
@@ -136,6 +136,8 @@
 
 .title.facebookprofile=Profile
 
+.title.mailruprofile=Mail.ru profile
+
 .title.twitterprofile=Profile
 
 .userinfo.body2=Below is user information for [[username]]. If you are this user, you can edit your information (or choose what information is considered public) at the <a [[aopts]]>Edit Profile</a> page.

Added: trunk/templates/Identity/Login-mailru.tmpl
===================================================================
--- trunk/templates/Identity/Login-mailru.tmpl	                        (rev 0)
+++ trunk/templates/Identity/Login-mailru.tmpl	2011-02-18 10:19:13 UTC (rev 10079)
@@ -0,0 +1,3 @@
+<button type="submit" class="b-mailrubtn" title="<TMPL_VAR expr="ml('/identity/login.bml.mailru.btn.connect')">"><span><i></i><TMPL_VAR expr="ml('/identity/login.bml.mailru.btn.connect')"></span></button>
+<p class="b-auth-desc"><TMPL_VAR expr="ml('/identity/login.bml.mailru.desc')"></p>
+<TMPL_IF errors><TMPL_LOOP errors><p class="b-auth-error"><span class="i-message i-message-error"><TMPL_VAR error></span></p></TMPL_LOOP></TMPL_IF>

Tags: bml, dat, ljcom, local, pm, ssafronova, tmpl
Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 0 comments