[dw-free] trust groups for xml-rpc protocol
[commit: http://hg.dwscoalition.org/dw-free/rev/74a45a47496a]
http://bugs.dwscoalition.org/show_bug.cgi?id=2451
Added gettrustgroups, getcircle, editcircle to the protocol.
Patch by
catness.
Files modified:
http://bugs.dwscoalition.org/show_bug.cgi?id=2451
Added gettrustgroups, getcircle, editcircle to the protocol.
Patch by
![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Files modified:
- cgi-bin/ljprotocol.pl
- t/protocol.t
-------------------------------------------------------------------------------- diff -r 2b2eefda745d -r 74a45a47496a cgi-bin/ljprotocol.pl --- a/cgi-bin/ljprotocol.pl Mon Aug 23 13:00:23 2010 +0800 +++ b/cgi-bin/ljprotocol.pl Mon Aug 23 18:25:43 2010 +0800 @@ -179,7 +179,10 @@ sub do_request if ($method eq "login") { return login(@args); } if ($method eq "getfriendgroups") { return getfriendgroups(@args); } + if ($method eq "gettrustgroups") { return gettrustgroups(@args); } if ($method eq "getfriends") { return getfriends(@args); } + if ($method eq "getcircle") { return getcircle(@args); } + if ($method eq "editcircle") { return editcircle(@args); } if ($method eq "friendof") { return friendof(@args); } if ($method eq "checkfriends") { return checkfriends(@args); } if ($method eq "getdaycounts") { return getdaycounts(@args); } @@ -651,17 +654,23 @@ sub login return $res; } +#deprecated sub getfriendgroups { - my ($req, $err, $flags) = @_; - return undef unless authenticate($req, $err, $flags); - my $u = $flags->{'u'}; - my $res = {}; - $res->{'friendgroups'} = list_friendgroups($u); - return fail($err, 502, "Error loading friend groups") unless $res->{'friendgroups'}; - if ($req->{'ver'} >= 1) { - foreach (@{$res->{'friendgroups'} || []}) { - LJ::text_out(\$_->{'name'}); + return fail( $_[1], 504 ); +} + +sub gettrustgroups +{ + my ( $req, $err, $flags ) = @_; + return undef unless authenticate( $req, $err, $flags ); + my $u = $flags->{u}; + my $res = {}; + $res->{trustgroups} = list_trustgroups( $u ); + return fail( $err, 502, "Error loading trust groups" ) unless $res->{trustgroups}; + if ( $req->{ver} >= 1 ) { + foreach ( @{$res->{trustgroups} || []} ) { + LJ::text_out( \$_->{name} ); } } return $res; @@ -714,6 +723,77 @@ sub getfriends }); if ($req->{'ver'} >= 1) { foreach(@{$res->{'friends'}}) { LJ::text_out(\$_->{'fullname'}) }; + } + return $res; +} + +sub getcircle +{ + my ( $req, $err, $flags ) = @_; + return undef unless authenticate( $req, $err, $flags ); + my $u = $flags->{u}; + my $res = {}; + my $limit = $LJ::MAX_WT_EDGES_LOAD; + $limit = $req->{limit} + if defined $req->{limit} && $req->{limit} < $limit; + + if ( $req->{includetrustgroups} ) { + $res->{trustgroups} = list_trustgroups( $u ); + return fail( $err, 502, "Error loading trust groups" ) unless $res->{trustgroups}; + if ( $req->{ver} >= 1 ) { + LJ::text_out( \$_->{name} ) + foreach ( @{$res->{trustgroups} || []} ); + } + } + if ( $req->{includecontentfilters} ) { + $res->{contentfilters} = list_contentfilters( $u ); + return fail( $err, 502, "Error loading content filters" ) unless $res->{contentfilters}; + if ( $req->{ver} >= 1 ) { + LJ::text_out( \$_->{name} ) + foreach ( @{$res->{contentfilters} || []} ); + } + } + if ( $req->{includewatchedusers} ) { + $res->{watchedusers} = list_users( $u, + limit => $limit, + watched => 1, + includebdays => $req->{includebdays}, + ); + if ( $req->{ver} >= 1 ) { + LJ::text_out( \$_->{fullname} ) + foreach ( @{$res->{watchedusers} || []} ); + } + } + if ( $req->{includewatchedby} ) { + $res->{watchedbys} = list_users( $u, + limit => $limit, + watchedby => 1, + ); + if ( $req->{ver} >= 1 ) { + LJ::text_out( \$_->{fullname} ) + foreach ( @{$res->{watchedbys} || []} ); + } + } + if ( $req->{includetrustedusers} ) { + $res->{trustedusers} = list_users( $u, + limit => $limit, + trusted => 1, + includebdays => $req->{includebdays}, + ); + if ($req->{ver} >= 1) { + LJ::text_out(\$_->{fullname}) + foreach (@{$res->{trustedusers} || []}); + } + } + if ( $req->{includetrustedby} ) { + $res->{trustedbys} = list_users( $u, + limit => $limit, + trustedby => 1, + ); + if ( $req->{ver} >= 1 ) { + LJ::text_out( \$_->{fullname} ) + foreach ( @{$res->{trustedbys} || []} ); + } } return $res; } @@ -2412,6 +2492,144 @@ sub editfriendgroups { return fail( $_[1], 504 ); } +sub editcircle +{ + my ( $req, $err, $flags ) = @_; + return undef unless authenticate( $req, $err, $flags ); + + my $u = $flags->{u}; + my $res = {}; + + if ( ref $req->{settrustgroups} eq 'HASH' ) { + while ( my ( $bit, $group ) = each %{$req->{settrustgroups}} ) { + my $name = $group->{name}; + my $sortorder = $group->{sort}; + my $public = $group->{public}; + my %params = ( id => $bit, + groupname => $name, + _force_create => 1 + ); + + $params{sortorder} = $sortorder if defined $sortorder; + $params{is_public} = $public if defined $public; + $u->edit_trust_group( %params ); + } + } + + if ( ref $req->{deletetrustgroups} eq 'ARRAY' ) { + foreach my $bit ( @{$req->{deletetrustgroups}} ) { + $u->delete_trust_group( id => $bit ); + } + } + + if ( ref $req->{setcontentfilters} eq 'HASH' ) { + while ( my ( $bit, $group ) = each %{$req->{setcontentfilters} } ) { + my $name = $group->{name}; + my $public = $group->{public}; + my $sortorder = $group->{sort}; + my $cf = $u->content_filters( id => $bit ); + if ( $cf ) { + $cf->name( $name ) + if $name && $name ne $cf->name; + $cf->public( $public ) + if ( defined $public ) && $public ne $cf->public; + $cf->sortorder( $sortorder ) + if ( defined $sortorder ) && $sortorder ne $cf->sortorder; + } else { + my $fid = $u->create_content_filter( name => $name, public => $public, sortorder => $sortorder ); + my $added = { + id => $fid, + name => $name, + }; + push @{$res->{addedcontentfilters}}, $added; + } + } + } + + if ( ref $req->{deletecontentfilters} eq 'ARRAY' ) { + foreach my $bit ( @{$req->{deletecontentfilters}} ) { + $u->delete_content_filter( id => $bit ); + } + } + + if ( ref $req->{add} eq 'ARRAY' ) { + foreach my $row ( @{$req->{add}} ) { + my $other_user = LJ::load_user( $row->{username} ); + return fail( $err, 203 ) unless $other_user; + my $other_userid = $other_user->{userid}; + + if ( defined ( $row->{groupmask} ) ) { + $u->add_edge( $other_userid, trust => { + mask => $row->{groupmask}, + nonotify => 1, + } ); + } else { + if ( $row->{edge} & 1 ) { + $u->add_edge ( $other_userid, trust => { + nonotify => $u->trusts ( $other_userid ) ? 1 : 0, + } ); + } else { + $u->remove_edge ( $other_userid, trust => { + nonotify => $u->trusts ( $other_userid ) ? 0 : 1, + } ); + } + if ( $row->{edge} & 2 ) { + my $fg = $row->{fgcolor} || "#000000"; + my $bg = $row->{bgcolor} || "#FFFFFF"; + $u->add_edge ( $other_userid, watch => { + fgcolor => LJ::color_todb( $fg ), + bgcolor => LJ::color_todb( $bg ), + nonotify => $u->watches ( $other_userid ) ? 1 : 0, + } ); + } else { + $u->remove_edge ( $other_userid, watch => { + nonotify => $u->watches ( $other_userid ) ? 0 : 1, + } ); + } + if ( $row->{edge} ) { + my $myid = $u->userid; + my $added = { + username => $other_user->{user}, + fullname => $other_user->{name}, + trusted => $u->trusts ( $other_userid ), + trustedby => $other_user->trusts ( $myid ), + watched => $u->watches ( $other_userid ), + watchedby => $other_user->watches ( $myid ) + }; + push @{$res->{added}}, $added; + } + } + } + } + + # if ( ref $req->{delete} eq 'ARRAY' ) { + # foreach my $row ( @{$req->{delete}} ) { + # not implemented yet - maybe unnecessary + # } + # } + + if ( ref $req->{addtocontentfilters} eq 'ARRAY' ) { + foreach my $row ( @{$req->{addtocontentfilters}} ) { + my $other_user = LJ::load_user( $row->{username} ); + return fail( $err, 203 ) unless $other_user; + my $other_userid = $other_user->{userid}; + my $cf = $u->content_filters( id => $row->{id} ); + $cf->add_row( userid => $other_userid ) if $cf; + } + } + + if ( ref $req->{deletefromcontentfilters} eq 'ARRAY' ) { + foreach my $row ( @{$req->{deletefromcontentfilters}} ) { + my $other_user = LJ::load_user( $row->{username} ); + return fail( $err, 203 ) unless $other_user; + my $other_userid = $other_user->{userid}; + my $cf = $u->content_filters( id => $row->{id} ); + $cf->delete_row( $other_userid ) if $cf; + } + } + return $res; +} + sub sessionexpire { my ($req, $err, $flags) = @_; return undef unless authenticate($req, $err, $flags); @@ -2544,6 +2762,74 @@ sub list_friends last if @$res == $limitnum; } return $res; +} + +sub list_users +{ + my ($u, %opts) = @_; + + my %hide; + my $list = LJ::load_rel_user( $u, 'B' ); + $hide{$_} = 1 foreach @{$list||[]}; + + + my $friendof = $opts{trustedby} || $opts{watchedby}; + my ( $filter, @userids ); + if ( $friendof ) { + @userids = $opts{trustedby} ? $u->trusted_by_userids : $u->watched_by_userids; + } else { + $filter = $opts{trusted} ? $u->trust_list : $u->watch_list; + @userids = keys %{$filter}; + } + + my $limitnum = $opts{limit} + 0; + my @res; + + my $us = LJ::load_userids( @userids ); + while ( my( $userid, $u ) = each %$us ) { + next unless LJ::isu( $u ); + next if $friendof && ! $u->is_visible; + next if $hide{$userid}; + + my $r = { + username => $u->user, + fullname => $u->display_name + }; + + if ( $u->identity ) { + my $i = $u->identity; + $r->{identity_type} = $i->pretty_type; + $r->{identity_value} = $i->value; + $r->{identity_display} = $u->display_name; + } + + if ( $opts{includebdays} ) { + $r->{birthday} = $u->bday_string; + } + + unless ( $friendof ) { + $r->{fgcolor} = LJ::color_fromdb( $filter->{$userid}->{fgcolor} ); + $r->{bgcolor} = LJ::color_fromdb( $filter->{$userid}->{bgcolor} ); + $r->{groupmask} = $filter->{$userid}->{groupmask}; + } + + $r->{type} = { + C => 'community', + Y => 'syndicated', + I => 'identity', + }->{$u->journaltype} unless $u->is_person; + + $r->{status} = { + D => 'deleted', + S => 'suspended', + X => 'purged', + }->{$u->statusvis} unless $u->is_visible; + + push @res, $r; + # won't happen for zero limit (which means no limit) + last if scalar @res == $limitnum; + } + return \@res; } sub syncitems @@ -2686,13 +2972,13 @@ sub list_friendgroups # warn "ljprotocol.pl: list_friendgroups called.\n"; return []; - -# TODO(mark): this needs updating to determine if we should send trust groups? -# answer is yes, but we also need to move this to list_trustgroups -# so clients don't think those are friend groups. - - # get the groups for this user, return undef if error - my $groups = LJ::get_friend_group($u); +} + +sub list_trustgroups +{ + my $u = shift; + + my $groups = $u->trust_groups; return undef unless $groups; # we got all of the groups, so put them into an arrayref sorted by the @@ -2705,6 +2991,23 @@ sub list_friendgroups values %$groups; return \@res; +} + +sub list_contentfilters +{ + my $u = shift; + my @filters = $u->content_filters; + return [] unless @filters; + + my @res = map { { id => $_->{id}, name => $_->{name}, + public => $_->{public}, sortorder => $_->{sortorder}, + data => join ( ' ', + map { my $uid = $_; + LJ::load_userid( $uid )->user } + ( keys %{$u->content_filters (id => $_->id )->data} ) ) } } + @filters; + + return \@res; } sub list_usejournals { @@ -2980,6 +3283,9 @@ sub do_request if ($req->{'mode'} eq "getfriendgroups") { return getfriendgroups($req, $res, $flags); } + if ($req->{'mode'} eq "gettrustgroups") { + return gettrustgroups($req, $res, $flags); + } if ($req->{'mode'} eq "getfriends") { return getfriends($req, $res, $flags); } @@ -3155,6 +3461,26 @@ sub getfriendgroups } $res->{'success'} = "OK"; populate_friend_groups($res, $rs->{'friendgroups'}); + + return 1; +} + +## flat wrapper +sub gettrustgroups +{ + my ($req, $res, $flags) = @_; + + my $err = 0; + my $rq = upgrade_request($req); + + my $rs = LJ::Protocol::do_request('gettrustgroups', $rq, \$err, $flags); + unless ($rs) { + $res->{success} = "FAIL"; + $res->{errmsg} = LJ::Protocol::error_message($err); + return 0; + } + $res->{success} = "OK"; + populate_groups($res, 'tr', $rs->{trustgroups}); return 1; } @@ -3675,6 +4001,22 @@ sub populate_friend_groups $res->{'frgrp_maxnum'} = $maxnum; } +## given a $res hashref and trust group (arrayref), flattens it +sub populate_groups +{ + my ($res, $pfx, $fr) = @_; + + my $maxnum = 0; + foreach my $fg ( @$fr ) { + my $num = $fg->{id}; + $res->{"${pfx}_${num}_name"} = $fg->{name}; + $res->{"${pfx}_${num}_sortorder"} = $fg->{sortorder}; + $res->{"${pfx}_${num}_public"} = 1 if $fg->{public}; + $maxnum = $num if ($num > $maxnum); + } + $res->{"${pfx}_maxnum"} = $maxnum; +} + ## given a menu tree, flattens it into $res hashref sub populate_web_menu { diff -r 2b2eefda745d -r 74a45a47496a t/protocol.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/t/protocol.t Mon Aug 23 18:25:43 2010 +0800 @@ -0,0 +1,475 @@ +#!/usr/bin/perl +use strict; +use warnings; + +use Test::More; +plan tests => 191; + +use lib "$ENV{LJHOME}/cgi-bin"; +require 'ljlib.pl'; +require 'ljprotocol.pl'; + +use LJ::Test qw( temp_user temp_comm ); + +my $u = temp_user(); +my $watched = temp_user(); +my $trusted = temp_user(); +my $watchedtrusted = temp_user(); +my $comm = temp_comm(); + +my $watcher = temp_user(); +my $truster = temp_user(); +my $watchertruster = temp_user(); + +my @watched = ( $watched, $watchedtrusted, $comm ); +my @trusted = ( $trusted, $watchedtrusted ); +my @watchedby = ( $watcher, $watchertruster ); +my @trustedby = ( $truster, $watchertruster ); + +$u->add_edge( $_, watch => { nonotify => 1 } ) foreach @watched; +$u->add_edge( $_, trust => { nonotify => 1 } ) foreach @trusted; +$_->add_edge( $u, watch => { nonotify => 1 } ) foreach @watchedby; +$_->add_edge( $u, trust => { nonotify => 1 } ) foreach @trustedby; + +my $err = 0; +my $res = {}; + +my $do_request = sub { + my ( $mode, %request_args ) = @_; + + my $err = 0; + my $req = \%request_args; + + my $res = LJ::Protocol::do_request( $mode, $req, \$err, { noauth => 1 } ); + + return ( $res, $err ); +}; + + +my $check_err = sub { + my ( $responsecode, $expectedcode, $testmsg ) = @_; + + is( $responsecode, $expectedcode, + "$testmsg Protocol error ($err) = " . LJ::Protocol::error_message( $err ) ); +}; + +my $success = sub { + my ( $responsecode, $testmsg ) = @_; + + is( $responsecode, 0, "$testmsg (success)" ); +}; + +note( "getfriendgroups" ); +{ + ( $res, $err ) = $do_request->( "getfriendgroups" ); + $check_err->( $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." ); + is( $res, undef, "No response expected." ); +} + +note( "gettrustgroups" ); +{ + # test arguments: + # username + + ( $res, $err ) = $do_request->( "gettrustgroups" ); + $check_err->( $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." ); + ok( ref $res->{trustgroups} eq "ARRAY" && scalar @{$res->{trustgroups}} == 0, + "Empty trust groups list." ); +}; + +note( "getcircle" ); +{ + # test arguments: + # username + # limit + # includetrustgroups + # includecontentfilters + # includewatchedusers + # includewatchedby + # includetrustedusers + + ( $res, $err ) = $do_request->( "getcircle" ); + $check_err->( $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." ); + is( scalar keys %$res, 0, "Empty circle; no arguments provided to select the subset of the circle." ); + + my %circle_args = ( + # request hash key => response hash key, users + includewatchedby => [ "watchedbys", \@watchedby ], + includetrustedby => [ "trustedbys", \@trustedby ], + includewatchedusers => [ "watchedusers", \@watched ], + includetrustedusers => [ "trustedusers", \@trusted ], + ); + while( my ( $include, $val ) = each %circle_args ) { + ( $res, $err ) = $do_request->( "getcircle", username => $u->user, $include => 1 ); + $success->( $err, "'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." ); + + my @cached_users = @{$val->[1]}; + my @response_users = @{$res->{$val->[0]}}; + is ( scalar @response_users, scalar @cached_users, "Matched the number of users who are watching/trusting." ); + + # check both ways that the users we added are the users we got back + my %cached_users = map { $_->user => 0 } @cached_users; + foreach my $user ( @response_users ) { + ok( ++$cached_users{$user->{username}}, "User from response is expected to be there." ); + } + ok( $cached_users{$_}, "User appeared in the response." ) foreach keys %cached_users; + } + + # set a limit, and check against that + my $old_limit = $LJ::MAX_WT_EDGES_LOAD; + $LJ::MAX_WT_EDGES_LOAD = 2; + while( my ( $include, $val ) = each %circle_args ) { + my @cached_users = @{$val->[1]}; + my $limit = scalar @cached_users > $LJ::MAX_WT_EDGES_LOAD + ? $LJ::MAX_WT_EDGES_LOAD + : scalar @cached_users; + + ( $res, $err ) = $do_request->( "getcircle", username => $u->user, $include => 1, + limit => $LJ::MAX_WT_EDGES_LOAD + 1 ); + $success->( $err, "'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 + my @response_users = @{$res->{$val->[0]}}; + is ( scalar @response_users, $limit, "Check that the number of users who can be fetched is limited." ); + my %cached_users = map { $_->user => 0 } @cached_users; + foreach my $user ( @response_users ) { + ok( ++$cached_users{$user->{username}}, "User from response is expected to be there." ); + } + } + + ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includetrustgroups => 1 ); + $success->( $err, "'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" ); + 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." ); + + $LJ::MAX_WT_EDGES_LOAD = $old_limit; +} + +note( "editcircle" ); +{ + # test arguments: + # settrustgroups + # deletetrustgroups + # setcontentfilters + # deletecontentfilters + # add + # addtocontentfilters + # deletefromcontentfilters + + ( $res, $err ) = $do_request->( "editcircle", settrustgroups => 1 ); + $check_err->( $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." ); + is( scalar keys %$res, 0, "No action taken." ); + + + my %trustgroups = ( + 1 => { + name => "first", + sort => 1, + public => 0 + }, + 5 => { + name => "incomplete" + }, + 10 => { + # no name? + } + ); + ( $res, $err ) = $do_request->( "editcircle", username => $u->user, settrustgroups => \%trustgroups ); + $success->( $err, "Set trust groups." ); + is( scalar keys %$res, 0, "No response expected." ); + + ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includetrustgroups => 1 ); + is( scalar @{$res->{trustgroups}}, scalar keys %trustgroups, "Number of trust groups match." ); + foreach my $trustgroup ( @{$res->{trustgroups}} ) { + my $id = $trustgroup->{id}; + my $orig_trustgroup = $trustgroups{$id}; + + is( $trustgroup->{name}, $orig_trustgroup->{name} || "", "Trustgroup name matches." ); + is( $trustgroup->{public}, $orig_trustgroup->{public} || 0, "Trustgroup public setting matches." ); + is( $trustgroup->{sortorder}, $orig_trustgroup->{sort} || 50, "Trustgroup sortorder matches." ); + } + + + # then edit one trust group, and add another + my $edited = { + name => "hasname", + sortorder => 20, + public => 1, + }; + $trustgroups{10} = $edited; + + my $new = { + name => "new", + }; + $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." ); + is( scalar keys %$res, 0, "No response expected." ); + + ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includetrustgroups => 1 ); + is( scalar @{$res->{trustgroups}}, scalar keys %trustgroups, "Number of trust groups match." ); + foreach my $trustgroup ( @{$res->{trustgroups}} ) { + my $id = $trustgroup->{id}; + my $orig_trustgroup = $trustgroups{$id}; + + is( $trustgroup->{name}, $orig_trustgroup->{name} || "", "Trustgroup name matches." ); + is( $trustgroup->{public}, $orig_trustgroup->{public} || 0, "Trustgroup public setting matches." ); + is( $trustgroup->{sortorder}, $orig_trustgroup->{sort} || 50, "Trustgroup sortorder matches." ); + } + + + # then delete some trust groups + delete $trustgroups{5}; + delete $trustgroups{10}; + ( $res, $err ) = $do_request->( "editcircle", username => $u->user, deletetrustgroups => [ 10, 5 ] ); + $success->( $err, "Deleted a trust group." ); + is( scalar keys %$res, 0, "No response expected." ); + + ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includetrustgroups => 1 ); + is( scalar @{$res->{trustgroups}}, scalar keys %trustgroups, "Number of trust groups match." ); + foreach my $trustgroup ( @{$res->{trustgroups}} ) { + my $id = $trustgroup->{id}; + my $orig_trustgroup = $trustgroups{$id}; + + is( $trustgroup->{name}, $orig_trustgroup->{name} || "", "Trustgroup name matches." ); + is( $trustgroup->{public}, $orig_trustgroup->{public} || 0, "Trustgroup public setting matches." ); + is( $trustgroup->{sortorder}, $orig_trustgroup->{sort} || 50, "Trustgroup sortorder matches." ); + } + + + # 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." ); + is( scalar keys %$res, 0, "No response expected." ); + + # let's make our watch/trust mutual + # ... but not yet + ( $res, $err ) = $do_request->( "editcircle", username => $u->user, add => [ { username => $watchertruster->user } ] ); + ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includewatchedusers => 1, includetrustedusers => 1 ); + + is( scalar @{$res->{watchedusers}}, scalar @watched, "Number of watched users did not change." ); + is( scalar @{$res->{trustedusers}}, scalar @trusted, "Number of trusted users did not change." ); + + # add with trust group + is( $u->trustmask( $watchertruster ), 0, "Currently not trusted." ); + ok( ! $u->trusts( $watchertruster ), "Currently not trusted." ); + ok( ! $u->watches( $watchertruster ), "Currently not watched." ); + ok( $watchertruster->trusts( $u ), "Trusted by." ); + ok( $watchertruster->watches( $u ), "Watched by." ); + + ( $res, $err ) = $do_request->( "editcircle", username => $u->user, add => [ { username => $watchertruster->user, groupmask => 201 } ] ); + ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includewatchedusers => 1, includetrustedusers => 1 ); + is( scalar @{$res->{watchedusers}}, scalar @watched, "Number of watched users did not change." ); + is( scalar @{$res->{trustedusers}}, scalar @trusted + 1, "Trusted this user." ); + is( $u->trustmask( $watchertruster ), 201, "Trusted, with trust group that matches." ); + ok( $u->trusts( $watchertruster ), "Currently trusted." ); + ok( ! $u->watches( $watchertruster ), "Currently not watched." ); + ok( $watchertruster->trusts( $u ), "Trusted by." ); + ok( $watchertruster->watches( $u ), "Watched by." ); + + + # add and remove + ( $res, $err ) = $do_request->( "editcircle", username => $u->user, add => [ { username => $watchertruster->user, edge => 0b00 } ] ); + is( $u->trustmask( $watchertruster ), 0, "Not trusted." ); + ok( ! $u->trusts( $watchertruster ), "Currently not trusted." ); + ok( ! $u->watches( $watchertruster ), "Currently not watched." ); + ok( $watchertruster->trusts( $u ), "Trusted by." ); + ok( $watchertruster->watches( $u ), "Watched by." ); + + + ( $res, $err ) = $do_request->( "editcircle", username => $u->user, add => [ { username => $watchertruster->user, edge => 0b01 } ] ); + is( $u->trustmask( $watchertruster ), 1, "Just trust." ); + ok( $u->trusts( $watchertruster ), "Currently trusted." ); + ok( ! $u->watches( $watchertruster ), "Currently not watched." ); + ok( $watchertruster->trusts( $u ), "Trusted by." ); + ok( $watchertruster->watches( $u ), "Watched by." ); + + + ( $res, $err ) = $do_request->( "editcircle", username => $u->user, add => [ { username => $watchertruster->user, edge => 0b10 } ] ); + is( $u->trustmask( $watchertruster ), 0, "Not trusted." ); + ok( ! $u->trusts( $watchertruster ), "Currently not trusted." ); + ok( $u->watches( $watchertruster ), "Currently watched." ); + ok( $watchertruster->trusts( $u ), "Trusted by." ); + ok( $watchertruster->watches( $u ), "Watched by." ); + + + ( $res, $err ) = $do_request->( "editcircle", username => $u->user, add => [ { username => $watchertruster->user, edge => 0b11 } ] ); + is( $u->trustmask( $watchertruster ), 1, "Just trust." ); + ok( $u->trusts( $watchertruster ), "Currently trusted." ); + ok( $u->watches( $watchertruster ), "Currently watched." ); + ok( $watchertruster->trusts( $u ), "Trusted by." ); + ok( $watchertruster->watches( $u ), "Watched by." ); + + + # edit again with groupmask, after already having created a trust mask + ( $res, $err ) = $do_request->( "editcircle", username => $u->user, add => [ { username => $watchertruster->user, groupmask => 201 } ] ); + is( $u->trustmask( $watchertruster ), 201, "Trusted, with trust group that matches." ); + ok( $u->trusts( $watchertruster ), "Currently trusted." ); + ok( $u->watches( $watchertruster ), "Currently watched." ); + ok( $watchertruster->trusts( $u ), "Trusted by." ); + ok( $watchertruster->watches( $u ), "Watched by." ); + + + # now to + my %contentfilters = ( + 1 => { + name => "first", + sort => 1, + public => 0 + }, + 2 => { + name => "incomplete" + }, + ); + + ( $res, $err ) = $do_request->( "editcircle", username => $u->user, setcontentfilters => \%contentfilters ); + $success->( $err, "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." ); + + ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includecontentfilters => 1 ); + is( scalar @{$res->{contentfilters}}, scalar keys %contentfilters, "Number of content filters match." ); + foreach my $filter ( @{$res->{contentfilters}} ) { + my $id = $filter->{id}; + my $orig_filter = $contentfilters{$id}; + + is( $filter->{name}, $orig_filter->{name} || "", "Filter name matches." ); + is( $filter->{public}, $orig_filter->{public} || 0, "Filter public setting matches." ); + is( $filter->{sortorder}, $orig_filter->{sort} || 0, "Filter sortorder matches." ); + } + + # then edit one filter, and add another + $edited = { + name => "not so incomplete", + sortorder => 20, + public => 1, + }; + $contentfilters{2} = $edited; + + $new = { + name => "new", + }; + $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." ); + 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." ); + + ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includecontentfilters => 1 ); + is( scalar @{$res->{contentfilters}}, scalar keys %contentfilters, "Number of content filters match." ); + foreach my $filter ( @{$res->{contentfilters}} ) { + my $id = $filter->{id}; + my $orig_filter = $contentfilters{$id}; + + is( $filter->{name}, $orig_filter->{name} || "", "Filter name matches." ); + is( $filter->{public}, $orig_filter->{public} || 0, "Filter public setting matches." ); + is( $filter->{sortorder}, $orig_filter->{sort} || 0, "Filter sortorder matches." ); + } + + + # then delete some content filters + delete $contentfilters{1}; + delete $contentfilters{3}; + ( $res, $err ) = $do_request->( "editcircle", username => $u->user, deletecontentfilters => [ 1, 3 ] ); + $success->( $err, "Deleted content filters." ); + is( scalar keys %$res, 0, "No response expected." ); + + ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includecontentfilters => 1 ); + is( scalar @{$res->{contentfilters}}, scalar keys %contentfilters, "Number of content filters match." ); + foreach my $filter ( @{$res->{contentfilters}} ) { + my $id = $filter->{id}; + my $orig_filter = $contentfilters{$id}; + + is( $filter->{name}, $orig_filter->{name} || "", "Filter name matches." ); + is( $filter->{public}, $orig_filter->{public} || 0, "Filter public setting matches." ); + is( $filter->{sortorder}, $orig_filter->{sort} || 0, "Filter sortorder matches." ); + } + + + ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includecontentfilters => 1 ); + ok( $res->{contentfilters}->[0]->{data} eq "", "No data for the content filter." ); + + + # added non-existent user + ( $res, $err ) = $do_request->( "editcircle", username => $u->user, addtocontentfilters => [ { + username => "invalid_user", + id => 2 + } ] ); + $check_err->( $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." ); + + + # added a valid user + ( $res, $err ) = $do_request->( "editcircle", username => $u->user, addtocontentfilters => [ { + username => $watched->user, + id => 2 + } ] ); + $success->( $err, "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 ); + ok( $res->{contentfilters}->[0]->{data} ne "", "Some data in the content filter." ); + + + # tried to remove a non-existent user + ( $res, $err ) = $do_request->( "editcircle", username => $u->user, deletefromcontentfilters => [ { + username => "invalid_user", + id => 2 + } ] ); + $check_err->( $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." ); + + + # tried to remove a valid user, but one not in the content filter + ( $res, $err ) = $do_request->( "editcircle", username => $u->user, deletefromcontentfilters => [ { + username => $watchedtrusted->user, + id => 2 + } ] ); + $success->( $err, "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." ); + + + ( $res, $err ) = $do_request->( "editcircle", username => $u->user, deletefromcontentfilters => [ { + username => $watched->user, + id => 2 + } ] ); + $success->( $err, "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 ); + ok( $res->{contentfilters}->[0]->{data} eq "", "No more data in the content filter." ); +} --------------------------------------------------------------------------------