Committer: ssafronova
LJSUP-7762: Mail.ru connectU 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>