[dw-free] Routing should output text/plain errors for unknown ( and non-HTML ) formats
[commit: http://hg.dwscoalition.org/dw-free/rev/2ab32ff63973]
http://bugs.dwscoalition.org/show_bug.cgi?id=3171
Deprecate checkfriends; add new protocol method checkforupdates. See http
://dw-dev.dreamwidth.org/78628.html for more details.
Patch by
fu.
Files modified:
http://bugs.dwscoalition.org/show_bug.cgi?id=3171
Deprecate checkfriends; add new protocol method checkforupdates. See http
://dw-dev.dreamwidth.org/78628.html for more details.
Patch by
![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Files modified:
- cgi-bin/LJ/User.pm
- cgi-bin/ljprotocol.pl
- t/protocol.t
-------------------------------------------------------------------------------- diff -r 5288d9d5a226 -r 2ab32ff63973 cgi-bin/LJ/User.pm --- a/cgi-bin/LJ/User.pm Tue Jan 04 08:17:10 2011 +0800 +++ b/cgi-bin/LJ/User.pm Tue Jan 04 08:21:24 2011 +0800 @@ -2098,7 +2098,7 @@ sub can_track_thread { return $_[0]->get_cap( 'track_thread' ) ? 1 : 0; } -sub can_use_checkfriends { +sub can_use_checkforupdates { return $_[0]->get_cap( 'checkfriends' ) ? 1 : 0; } diff -r 5288d9d5a226 -r 2ab32ff63973 cgi-bin/ljprotocol.pl --- a/cgi-bin/ljprotocol.pl Tue Jan 04 08:17:10 2011 +0800 +++ b/cgi-bin/ljprotocol.pl Tue Jan 04 08:21:24 2011 +0800 @@ -184,6 +184,7 @@ sub do_request if ($method eq "editcircle") { return editcircle(@args); } if ($method eq "friendof") { return friendof(@args); } if ($method eq "checkfriends") { return checkfriends(@args); } + if ($method eq "checkforupdates") { return checkforupdates(@args); } if ($method eq "getdaycounts") { return getdaycounts(@args); } if ($method eq "postevent") { return postevent(@args); } if ($method eq "editevent") { return editevent(@args); } @@ -814,20 +815,20 @@ sub friendof return $res; } -sub checkfriends -{ - my ($req, $err, $flags) = @_; - return undef unless authenticate($req, $err, $flags); - my $u = $flags->{'u'}; - my $res = {}; - - # FIXME: not updated for WTF yet - return fail( $err, 507 ); +sub checkfriends { + return fail( $_[1], 504, "Use 'checkforupdates' instead." ); +} +sub checkforupdates +{ + my ($req, $err, $flags) = @_; + return undef unless authenticate($req, $err, $flags); + my $u = $flags->{'u'}; + my $res = {}; # return immediately if they can't use this mode - unless ( $u->can_use_checkfriends ) { + unless ( $u->can_use_checkforupdates ) { $res->{'new'} = 0; - $res->{'interval'} = 36000; # tell client to bugger off + $res->{'interval'} = 36000; return $res; } @@ -843,23 +844,36 @@ sub checkfriends my $interval = LJ::get_cap_min($u, "checkfriends_interval"); $res->{'interval'} = $interval; - my $mask; - if ($req->{'mask'} and $req->{'mask'} !~ /\D/) { - $mask = $req->{'mask'}; - } - - my $memkey = [$u->{'userid'},"checkfriends:$u->{userid}:$mask"]; + my $filter; + if ( $req->{filter} ) { + $filter = $u->content_filters( name => $req->{filter} ); + return fail( $err, 203, "Invalid filter name. Trying to check updates for a filter that does not exist." ) + unless $filter; + } + + my $memkey = [ $u->id, "checkforupdates:$u->{userid}:" . ( $filter ? $filter->id : "" ) ]; my $update = LJ::MemCache::get($memkey); unless ($update) { - # TAG:FR:protocol:checkfriends (wants reading list of mask, not "friends") - my $fr = LJ::get_friends($u, $mask); - unless ($fr && %$fr) { + my @fr = $u->watched_userids; + + # FIXME: see whether we can just get the list of users who are in the filter + if ( $filter ) { + my @filter_users; + + foreach my $fid ( @fr ) { + push @filter_users, $fid + if $filter->contains_userid( $fid ); + } + @fr = @filter_users; + } + + unless ( @fr ) { $res->{'new'} = 0; $res->{'lastupdate'} = $lastupdate; return $res; } if (@LJ::MEMCACHE_SERVERS) { - my $tu = LJ::get_timeupdate_multi({ memcache_only => 1 }, keys %$fr); + my $tu = LJ::get_timeupdate_multi({ memcache_only => 1 }, @fr); my $max = 0; while ($_ = each %$tu) { $max = $tu->{$_} if $tu->{$_} > $max; @@ -874,7 +888,7 @@ sub checkfriends $res->{'lastupdate'} = $lastupdate; return $res; } - my $list = join(", ", map { int($_) } keys %$fr); + my $list = join(", ", map { int($_) } @fr ); if ($list) { my $sql = "SELECT MAX(timeupdate) FROM userusage ". "WHERE userid IN ($list)"; @@ -3309,6 +3323,9 @@ sub do_request if ($req->{'mode'} eq "checkfriends") { return checkfriends($req, $res, $flags); } + if ($req->{'mode'} eq "checkforupdates") { + return checkforupdates($req, $res, $flags); + } if ($req->{'mode'} eq "getdaycounts") { return getdaycounts($req, $res, $flags); } @@ -3607,6 +3624,28 @@ sub checkfriends $res->{'new'} = $rs->{'new'}; $res->{'lastupdate'} = $rs->{'lastupdate'}; $res->{'interval'} = $rs->{'interval'}; + return 1; +} + +## flat wrapper +sub checkforupdates +{ + my ( $req, $res, $flags ) = @_; + + my $err = 0; + my $rq = upgrade_request( $req ); + + my $rs = LJ::Protocol::do_request( "checkforupdates", $rq, \$err, $flags ); + unless ( $rs ) { + $res->{success} = "FAIL"; + $res->{errmsg} = LJ::Protocol::error_message( $err ); + return 0; + } + + $res->{success} = "OK"; + $res->{new} = $rs->{new}; + $res->{lastupdate} = $rs->{lastupdate}; + $res->{interval} = $rs->{interval}; return 1; } diff -r 5288d9d5a226 -r 2ab32ff63973 t/protocol.t --- a/t/protocol.t Tue Jan 04 08:17:10 2011 +0800 +++ b/t/protocol.t Tue Jan 04 08:21:24 2011 +0800 @@ -3,7 +3,7 @@ use warnings; use warnings; use Test::More; -plan tests => 201; +plan tests => 222; use lib "$ENV{LJHOME}/cgi-bin"; require 'ljlib.pl'; @@ -49,27 +49,28 @@ my $do_request = sub { my $check_err = sub { - my ( $responsecode, $expectedcode, $testmsg ) = @_; + my ( $expectedcode, $testmsg ) = @_; - is( $responsecode, $expectedcode, + # code is either in the form of ###, or ###:description + like( $err, qr/^$expectedcode(?:$|[:])/, "$testmsg Protocol error ($err) = " . LJ::Protocol::error_message( $err ) ); }; my $success = sub { - my ( $responsecode, $testmsg ) = @_; + my ( $testmsg ) = @_; - is( $responsecode, 0, "$testmsg (success)" ); + is( $err, 0, "$testmsg (success)" ); }; note( "getfriendgroups" ); { ( $res, $err ) = $do_request->( "getfriendgroups" ); - $check_err->( $err, 504, "'getfriendgroups' is deprecated." ); + $check_err->( 504, "'getfriendgroups' is deprecated." ); is( $res, undef, "No response expected." ); ( $res, $err ) = $do_request->( "getfriendgroups", username => $u->user ); - $check_err->( $err, 504, "'getfriendgroups' is deprecated." ); + $check_err->( 504, "'getfriendgroups' is deprecated." ); is( $res, undef, "No response expected." ); } @@ -79,12 +80,12 @@ note( "gettrustgroups" ); # username ( $res, $err ) = $do_request->( "gettrustgroups" ); - $check_err->( $err, 200, "'gettrustgroups' needs a user." ); + $check_err->( 200, "'gettrustgroups' needs a user." ); is( $res, undef, "No response expected." ); ( $res, $err ) = $do_request->( "gettrustgroups", username => $u->user ); - $success->( $err, "'gettrustgroups' for user." ); + $success->( "'gettrustgroups' for user." ); ok( ref $res->{trustgroups} eq "ARRAY" && scalar @{$res->{trustgroups}} == 0, "Empty trust groups list." ); }; @@ -101,11 +102,11 @@ note( "getcircle" ); # includetrustedusers ( $res, $err ) = $do_request->( "getcircle" ); - $check_err->( $err, 200, "'getcircle' needs a user." ); + $check_err->( 200, "'getcircle' needs a user." ); is( $res, undef, "No response expected." ); ( $res, $err ) = $do_request->( "getcircle", username => $u->user ); - $success->( $err, "'getcircle' for user." ); + $success->( "'getcircle' for user." ); is( scalar keys %$res, 0, "Empty circle; no arguments provided to select the subset of the circle." ); my %circle_args = ( @@ -117,7 +118,7 @@ note( "getcircle" ); ); while( my ( $include, $val ) = each %circle_args ) { ( $res, $err ) = $do_request->( "getcircle", username => $u->user, $include => 1 ); - $success->( $err, "'getcircle' => $include" ); + $success->( "'getcircle' => $include" ); is( scalar keys %$res, 1, "One key: " . (keys %$res)[0] ); is( ref $res->{$val->[0]}, "ARRAY", "Returned an arrayref of this user's $include." ); @@ -144,7 +145,7 @@ note( "getcircle" ); ( $res, $err ) = $do_request->( "getcircle", username => $u->user, $include => 1, limit => $LJ::MAX_WT_EDGES_LOAD + 1 ); - $success->( $err, "'getcircle' => $include" ); + $success->( "'getcircle' => $include" ); # check that the users we got back are from the users we added # don't check the other way, since we are over limit @@ -157,14 +158,14 @@ note( "getcircle" ); } ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includetrustgroups => 1 ); - $success->( $err, "'getcircle' => includetrustgroups" ); + $success->( "'getcircle' => includetrustgroups" ); is( scalar keys %$res, 1, "One key: " . (keys %$res)[0] ); ok( ref $res->{trustgroups} eq "ARRAY" && scalar @{$res->{trustgroups}} == 0, "Empty trust groups list." ); ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includecontentfilters => 1 ); - $success->( $err, "'getcircle' => includecontentfilters" ); + $success->( "'getcircle' => includecontentfilters" ); is( scalar keys %$res, 1, "One key: " . (keys %$res)[0] ); ok( ref $res->{contentfilters} eq "ARRAY" && scalar @{$res->{contentfilters}} == 0, "Empty list of content filters for this user." ); @@ -183,12 +184,12 @@ note( "editcircle" ); # deletefromcontentfilters ( $res, $err ) = $do_request->( "editcircle", settrustgroups => 1 ); - $check_err->( $err, 200, "'editcircle' needs a user." ); + $check_err->( 200, "'editcircle' needs a user." ); is( $res, undef, "No response expected." ); ( $res, $err ) = $do_request->( "editcircle", username => $u->user, settrustgroups => 1 ); - $success->( $err, "No valid action provided for editcircle; ignore." ); + $success->( "No valid action provided for editcircle; ignore." ); is( scalar keys %$res, 0, "No action taken." ); @@ -206,7 +207,7 @@ note( "editcircle" ); } ); ( $res, $err ) = $do_request->( "editcircle", username => $u->user, settrustgroups => \%trustgroups ); - $success->( $err, "Set trust groups." ); + $success->( "Set trust groups." ); is( scalar keys %$res, 0, "No response expected." ); ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includetrustgroups => 1 ); @@ -235,7 +236,7 @@ note( "editcircle" ); $trustgroups{20} = $new; ( $res, $err ) = $do_request->( "editcircle", username => $u->user, settrustgroups => { 10 => $edited, 20 => $new } ); - $success->( $err, "Edited trust groups; those not mentioned should not be affected." ); + $success->( "Edited trust groups; those not mentioned should not be affected." ); is( scalar keys %$res, 0, "No response expected." ); ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includetrustgroups => 1 ); @@ -254,7 +255,7 @@ note( "editcircle" ); delete $trustgroups{5}; delete $trustgroups{10}; ( $res, $err ) = $do_request->( "editcircle", username => $u->user, deletetrustgroups => [ 10, 5 ] ); - $success->( $err, "Deleted a trust group." ); + $success->( "Deleted a trust group." ); is( scalar keys %$res, 0, "No response expected." ); ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includetrustgroups => 1 ); @@ -271,7 +272,7 @@ note( "editcircle" ); # now add / edit some users' status in your circle ( $res, $err ) = $do_request->( "editcircle", username => $u->user, add => [ { username => "invalidusername" } ] ); - $check_err->( $err, 203, "Tried to edit invalid user." ); + $check_err->( 203, "Tried to edit invalid user." ); is( scalar keys %$res, 0, "No response expected." ); # let's make our watch/trust mutual @@ -355,7 +356,7 @@ note( "editcircle" ); ); ( $res, $err ) = $do_request->( "editcircle", username => $u->user, setcontentfilters => \%contentfilters ); - $success->( $err, "Set content filters." ); + $success->( "Set content filters." ); is( scalar keys %$res, 1, "Response contains only the newly added content filters." ); is( scalar @{$res->{addedcontentfilters}}, scalar keys %contentfilters, "Got back the newly-added content filters." ); @@ -384,7 +385,7 @@ note( "editcircle" ); $contentfilters{3} = $new; ( $res, $err ) = $do_request->( "editcircle", username => $u->user, setcontentfilters => { 2 => $edited, 3 => $new } ); - $success->( $err, "Edited content filters; those not mentioned should not be affected." ); + $success->( "Edited content filters; those not mentioned should not be affected." ); is( scalar keys %$res, 1, "Response contains only the newly added content filters." ); is( scalar @{$res->{addedcontentfilters}}, 1, "Got back the newly-added content filter." ); @@ -404,7 +405,7 @@ note( "editcircle" ); delete $contentfilters{1}; delete $contentfilters{3}; ( $res, $err ) = $do_request->( "editcircle", username => $u->user, deletecontentfilters => [ 1, 3 ] ); - $success->( $err, "Deleted content filters." ); + $success->( "Deleted content filters." ); is( scalar keys %$res, 0, "No response expected." ); ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includecontentfilters => 1 ); @@ -428,7 +429,7 @@ note( "editcircle" ); username => "invalid_user", id => 2 } ] ); - $check_err->( $err, 203, "Tried to add an invalid user to a content filter." ); + $check_err->( 203, "Tried to add an invalid user to a content filter." ); ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includecontentfilters => 1 ); ok( $res->{contentfilters}->[0]->{data} eq "", "No data for the content filter." ); @@ -438,7 +439,7 @@ note( "editcircle" ); username => $watched->user, id => 2 } ] ); - $success->( $err, "Added a user to a content filter." ); + $success->( "Added a user to a content filter." ); is( scalar keys %$res, 0, "No response expected." ); ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includecontentfilters => 1 ); @@ -450,7 +451,7 @@ note( "editcircle" ); username => "invalid_user", id => 2 } ] ); - $check_err->( $err, 203, "Tried to remove an invalid user from a content filter." ); + $check_err->( 203, "Tried to remove an invalid user from a content filter." ); ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includecontentfilters => 1 ); ok( $res->{contentfilters}->[0]->{data} ne "", "Some data in the content filter." ); @@ -460,7 +461,7 @@ note( "editcircle" ); username => $watchedtrusted->user, id => 2 } ] ); - $success->( $err, "Tried to remove a user who was not in the content filter." ); + $success->( "Tried to remove a user who was not in the content filter." ); ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includecontentfilters => 1 ); ok( $res->{contentfilters}->[0]->{data} ne "", "Some data in the content filter." ); @@ -469,7 +470,7 @@ note( "editcircle" ); username => $watched->user, id => 2 } ] ); - $success->( $err, "Removed a user from a content filter." ); + $success->( "Removed a user from a content filter." ); is( scalar keys %$res, 0, "No response expected." ); ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includecontentfilters => 1 ); @@ -506,7 +507,7 @@ note( "post to community by various jour event => "new test post to community", tz => "guess", ); - $success->( $err, "Entry posted successfully to community by personal journal." ); + $success->( "Entry posted successfully to community by personal journal." ); my $comm2 = temp_comm(); @@ -515,7 +516,7 @@ note( "post to community by various jour usejournal => $comm->user, event => "new test post to community by community2" ); - $check_err->( $err, 300, "Communities cannot post entries." ); + $check_err->( 300, "Communities cannot post entries." ); ( $res, $err ) = $do_request->( "postevent", username => $comm->user, @@ -524,7 +525,7 @@ note( "post to community by various jour event => "new test post to self by a community", tz => "guess", ); - $check_err->( $err, 300, "Communities cannot post entries, not even to themselves." ); + $check_err->( 300, "Communities cannot post entries, not even to themselves." ); @@ -539,7 +540,7 @@ note( "post to community by various jour event => "new test post to a community by an identity user", tz => "guess", ); - $check_err->( $err, 150, "OpenID users cannot post entries to communities with no OpenID posting prop." ); + $check_err->( 150, "OpenID users cannot post entries to communities with no OpenID posting prop." ); ( $res, $err ) = $do_request->( "postevent", @@ -551,7 +552,7 @@ note( "post to community by various jour flags => { importer_bypass => 1 }, ); - $success->( $err, "Always allow posting with the importer bypass." ); + $success->( "Always allow posting with the importer bypass." ); # allow all users to add and control tags (for convenience) @@ -577,5 +578,151 @@ note( "post to community by various jour props => { taglist => "testing" }, tz => "guess", ); - $success->( $err, "OpenID users can post entries to communities with the appropriate prop." ); + $success->( "OpenID users can post entries to communities with the appropriate prop." ); } + + +note( "checkforupdates" ); +{ + + my $u = temp_user(); + + my $start = 0; + my $end = 15; + + # make sure no one can use the protocol... + $LJ::CAP{$_}->{checkfriends} = 0 + foreach( 0.. 15 ); + + ( $res, $err ) = $do_request->( "checkfriends" ); + $check_err->( 504, "Use 'checkforupdates' instead" ); + + + ( $res, $err ) = $do_request->( "checkforupdates" ); + $check_err->( 200, "Needs arguments" ); + + ( $res, $err ) = $do_request->( "checkforupdates", + username => $u->user, + flags => { noauth => 0 }, + ); + $check_err->( 101, "Have all arguments, but needs authorization" ); + + ( $res, $err ) = $do_request->( "checkforupdates", + username => $u->user, + ); + $success->( "Not authorized to use checkforupdates" ); + is_deeply( $res, { + interval => 36000, + new => 0 + }, "Not authorized to use checkforupdates; no new entries, check back in an hour" ); + + + # make sure everyone can use the protocol, and set interval to a known variable we can check against + # (not using $LJ::T_HAS_ALL_CAPS = 1, because that makes everyone readonly) + $LJ::CAP{$_}->{checkfriends} = 1 + foreach( 0.. 15 ); + $LJ::CAP{$_}->{checkfriends_interval} = 7 + foreach( 0.. 15 ); + + ( $res, $err ) = $do_request->( "checkforupdates", + username => $u->user, + ); + $success->( "Checkforupdates. We don't watch anyone, but that's okay" ); + is( scalar %{ $u->watch_list }, 0, "Not watching anyone" ); + is_deeply( $res, { + interval => 7, + new => 0, + lastupdate => "0000-00-00 00:00:00", + }, "Watching no one." ); + + + # now we watch some people (who have no updates yet) + my $userinfilter = temp_user(); + $u->add_edge( $userinfilter, watch => { nonotify => 1 } ); + $u->create_content_filter( name => "filter" ); + my $filter = $u->content_filters( name => "filter" ); + $filter->add_row( userid => $userinfilter->userid ); + + my $usernotinfilter = temp_user(); + $u->add_edge( $usernotinfilter, watch => { nonotify => 1 } ); + + + # and go through the protocol again + ( $res, $err ) = $do_request->( "checkforupdates", + username => $u->user, + ); + $success->( "Checkforupdates. No one has updated." ); + is( scalar $u->watched_userids,2 ); + is_deeply( $res, { + interval => 7, + new => 0, + lastupdate => "0000-00-00 00:00:00", + }, "No new entries." ); + + + # and then let's see what happens when they get updates + $do_request->( "postevent", username => $userinfilter->user, event => "update", tz => "guess" ); + sleep( 1 ); # pause so we have different time stamps (for checking against) + $do_request->( "postevent", username => $usernotinfilter->user, event => "update", tz => "guess" ); + + # use variables to make it easier to determine what I'm trying to check for + # In some tests, I will deliberately *not* use the variables + my $earlierupdate = $userinfilter->timeupdate; + my $laterupdate = $usernotinfilter->timeupdate; + ok( $earlierupdate < $laterupdate, "Timestamps need to be unequal for when we're testing stuff." ); + + # and go through the protocol again + ( $res, $err ) = $do_request->( "checkforupdates", + username => $u->user, + ); + $success->( "Checkforupdates. Users have updated." ); + is_deeply( $res, { + interval => 7, + new => 0, + lastupdate => LJ::mysql_time( $usernotinfilter->timeupdate ), + }, "No new entries." ); + + + # and we also check a subset (filter) + ( $res, $err ) = $do_request->( "checkforupdates", + username => $u->user, + filter => $filter->name, + ); + $success->( "Checkforupdates of a subset of watched users." ); + is_deeply( $res, { + interval => 7, + new => 0, + lastupdate => LJ::mysql_time( $userinfilter->timeupdate ), + }, "No new entries." ); + + + # optional argument lastupdate + ( $res, $err ) = $do_request->( "checkforupdates", + username => $u->user, + lastupdate => $earlierupdate + ); + $check_err->( 203, "lastupdate argument needs to be in mysql_time format." ); + + ( $res, $err ) = $do_request->( "checkforupdates", + username => $u->user, + lastupdate => LJ::mysql_time( $earlierupdate ), + ); + $success->( "Checkforupdates since lastupdate. Have new updates" ); + is_deeply( $res, { + interval => 7, + new => 1, + lastupdate => LJ::mysql_time( $laterupdate ), + }, "Have new entries." ); + + ( $res, $err ) = $do_request->( "checkforupdates", + username => $u->user, + lastupdate => LJ::mysql_time( $laterupdate ), + ); + $success->( "Checkforupdates since lastupdate. No new updates" ); + is_deeply( $res, { + interval => 7, + new => 0, + lastupdate => LJ::mysql_time( $laterupdate ), + }, "No new entries." ); + +} --------------------------------------------------------------------------------