mark: A photo of Mark kneeling on top of the Taal Volcano in the Philippines. It was a long hike. (Default)
Mark Smith ([staff profile] mark) wrote in [site community profile] changelog2009-03-07 07:10 am

[dw-free] [community]/read isn't up

[commit: http://hg.dwscoalition.org/dw-free/rev/035ff3532833]

http://bugs.dwscoalition.org/show_bug.cgi?id=387

* Fix but in ordering for delete_trust_group that would never clear memcache
trustmask since it nuked user memberships too early.

* Add watch_list( community_okay => 1 ) flag which can be passed to get the
watch_list for a community. This flag should only be passed by the reading
page logic - we don't want to accidentally invoke loading community members
as being on the watch_list.

Patch by [staff profile] mark.

Files modified:
  • bin/test/test-wtf
  • cgi-bin/DW/Logic/LogItems.pm
  • cgi-bin/DW/User/Edges/WatchTrust.pm
  • cgi-bin/DW/User/Edges/WatchTrust/Loader.pm
--------------------------------------------------------------------------------
diff -r dfd18646e8e7 -r 035ff3532833 bin/test/test-wtf
--- a/bin/test/test-wtf	Sat Mar 07 06:07:58 2009 +0000
+++ b/bin/test/test-wtf	Sat Mar 07 07:10:16 2009 +0000
@@ -11,22 +11,27 @@ use Data::Dumper;
 # much time passes ...
 my $u1 = LJ::load_user( 'tester0394' ) or die 'no tester0394';
 my $u2 = LJ::load_user( 'tester0395' ) or die 'no tester0395';
+my $uc = LJ::load_user( 'testcomm' ) or die 'no testcomm';
+$uc->is_community or die 'testcomm not a community :(';
 
 my @tests;
 print "Beginning tests...\n";
 print "    u1 = " . $u1->user . '(' . $u1->id . ")\n";
-print "    u2 = " . $u2->user . '(' . $u2->id . ")\n\n";
+print "    u2 = " . $u2->user . '(' . $u2->id . ")\n";
+print "    uc = " . $uc->user . '(' . $uc->id . ")\n\n";
 
 my $dbh = LJ::get_db_writer();
 
 # reset, delete, etc
 sub rst {
     $dbh->do( 'DELETE FROM wt_edges WHERE from_userid = ? OR to_userid = ?', undef, $_, $_ )
-        foreach ( $u1->id, $u2->id );
+        foreach ( $u1->id, $u2->id, $uc->id );
     $dbh->do( 'DELETE FROM trust_groups WHERE userid = ?', undef, $_ )
-        foreach ( $u1->id, $u2->id );
+        foreach ( $u1->id, $u2->id, $uc->id );
+    $dbh->do( 'DELETE FROM reluser WHERE userid = ? OR targetid = ?', undef, $_, $_ )
+        foreach ( $u1->id, $u2->id, $uc->id );
 
-    foreach my $u ( $u1, $u2 ) {
+    foreach my $u ( $u1, $u2, $uc ) {
         foreach my $mc ( qw/ trust_group wt_list / ) {
             LJ::memcache_kill( $u, $mc );
         }
@@ -478,6 +483,26 @@ push @tests, [ 'allowed to watch and tru
 } ];
 
 ################################################################################
+push @tests, [ 'join community', sub
+{
+    rst();
+    $u1->add_edge( $uc, member => 1 );
+    return ( scalar( $uc->member_userids ) == 1 ) ? 1 : 0;
+} ];
+
+################################################################################
+push @tests, [ 'community watch list has zero', sub
+{
+    return ( scalar( keys %{ $uc->watch_list } ) == 0 ) ? 1 : 0;
+} ];
+
+################################################################################
+push @tests, [ 'community watch list has one', sub
+{
+    return ( scalar( keys %{ $uc->watch_list( community_okay => 1 ) } ) == 1 ) ? 1 : 0;
+} ];
+
+################################################################################
 $| = 1;
 my $id = 1;
 foreach my $test ( @tests ) {
diff -r dfd18646e8e7 -r 035ff3532833 cgi-bin/DW/Logic/LogItems.pm
--- a/cgi-bin/DW/Logic/LogItems.pm	Sat Mar 07 06:07:58 2009 +0000
+++ b/cgi-bin/DW/Logic/LogItems.pm	Sat Mar 07 07:10:16 2009 +0000
@@ -120,7 +120,7 @@ sub watch_items
         return undef if $fr_loaded;
 
         # get all friends for this user and groupmask
-        my $friends = $u->watch_list;
+        my $friends = $u->watch_list( community_okay => 1 );
         my %friends_u;
 
         # strip out rows with invalid journal types
diff -r dfd18646e8e7 -r 035ff3532833 cgi-bin/DW/User/Edges/WatchTrust.pm
--- a/cgi-bin/DW/User/Edges/WatchTrust.pm	Sat Mar 07 06:07:58 2009 +0000
+++ b/cgi-bin/DW/User/Edges/WatchTrust.pm	Sat Mar 07 07:10:16 2009 +0000
@@ -559,7 +559,7 @@ sub trust_list {
     return {} if $memc_only;
 
     # damn you memcache for not having our data
-    return DW::User::Edges::WatchTrust::Loader::_trust_list_db( $u );
+    return DW::User::Edges::WatchTrust::Loader::_trust_list_db( $u, force_database => $db_only );
 }
 *LJ::User::trust_list = \&trust_list;
 
@@ -612,7 +612,7 @@ sub trust_group_list {
     return {} if $memc_only;
 
     # damn you memcache for not having our data
-    return DW::User::Edges::WatchTrust::Loader::_trust_group_list_db( $mask, $u );
+    return DW::User::Edges::WatchTrust::Loader::_trust_group_list_db( $mask, $u, force_database => $db_only );
 }
 *LJ::User::trust_group_list = \&trust_group_list;
 
@@ -634,6 +634,7 @@ sub watch_list {
     $u = LJ::want_user( $u ) or confess 'invalid user object';
     my $memc_only = delete $args{memcache_only} || 0;
     my $db_only = delete $args{force_database} || 0;
+    my $comm_okay = delete $args{community_okay} || 0;
     confess 'extra/invalid arguments' if %args;
 
     # special case, we can disable loading friends for a user if there is a site
@@ -642,7 +643,7 @@ sub watch_list {
 
     # attempt memcache if allowed
     unless ( $db_only ) {
-        my $memc = DW::User::Edges::WatchTrust::Loader::_watch_list_memc( $u );
+        my $memc = DW::User::Edges::WatchTrust::Loader::_watch_list_memc( $u, community_okay => $comm_okay );
         return $memc if $memc;
     }
 
@@ -651,7 +652,11 @@ sub watch_list {
     return {} if $memc_only;
 
     # damn you memcache for not having our data
-    return DW::User::Edges::WatchTrust::Loader::_watch_list_db( $u );
+    return DW::User::Edges::WatchTrust::Loader::_watch_list_db(
+        $u,
+        force_database => $db_only,
+        community_okay => $comm_okay
+    );
 }
 *LJ::User::watch_list = \&watch_list;
 
@@ -794,15 +799,6 @@ sub delete_trust_group {
     my $bit = $grp->{groupnum}+0;
     return 0 unless $bit >= 1 && $bit <= 60;
 
-    # remove the bits for deleted groups from all friends groupmasks
-    my $dbh = LJ::get_db_writer()
-        or return 0;
-    $dbh->do(
-        q{UPDATE wt_edges SET groupmask = groupmask & ~(1 << ?) WHERE from_userid = ?},
-        undef, $bit, $u->id
-    );
-    return 0 if $dbh->err;
-
     # remove all posts from allowing that group:
     my @posts_to_clean = @{ $u->selectcol_arrayref(
         q{SELECT jitemid FROM logsec2 WHERE journalid = ? AND allowmask & (1 << ?)},
@@ -832,8 +828,13 @@ sub delete_trust_group {
     # notify the tags system so it can do its thing
     LJ::Tags::deleted_trust_group( $u, $bit );
 
+    # used here down
+    my $dbh = LJ::get_db_writer()
+        or return 0;
+
     # iterate over everybody in this group and remove the bit
-    foreach my $tid ( keys %{ $u->trust_group_list( id => $bit ) || {} } ) {
+    my $tglist = $u->trust_group_list( id => $bit, force_database => 1 );
+    foreach my $tid ( keys %{ $tglist || {} } ) {
         $dbh->do(
             q{UPDATE wt_edges SET groupmask = groupmask & ~(1 << ?) WHERE from_userid = ? AND to_userid = ?},
             undef, $bit, $u->id, $tid
diff -r dfd18646e8e7 -r 035ff3532833 cgi-bin/DW/User/Edges/WatchTrust/Loader.pm
--- a/cgi-bin/DW/User/Edges/WatchTrust/Loader.pm	Sat Mar 07 06:07:58 2009 +0000
+++ b/cgi-bin/DW/User/Edges/WatchTrust/Loader.pm	Sat Mar 07 07:10:16 2009 +0000
@@ -143,7 +143,7 @@ sub _trust_group_list_db   { return _fil
 
 # attempt to load a user's watch list from memcache
 sub _wt_list_memc {
-    my $u = $_[0];
+    my ( $u, %args ) = @_;
 
     # variable setup
     my %rows;                 # rows to be returned
@@ -154,7 +154,8 @@ sub _wt_list_memc {
     my @cols    = qw/ to_userid fgcolor bgcolor groupmask showbydefault /;
 
     # first, check memcache
-    my $memkey = [$userid, "wt_list:$userid"];
+    my $key = ( $args{community_okay} && $u->is_community ) ? 'c_wt_list' : 'wt_list';
+    my $memkey = [$userid, "$key:$userid"];
     my $memdata = LJ::MemCache::get($memkey);
     return undef unless $memdata;
 
@@ -185,7 +186,7 @@ sub _wt_list_memc {
 
 # attempt to load a user's watch list from the database
 sub _wt_list_db {
-    my $u = $_[0];
+    my ( $u, %args ) = @_;
 
     my $userid = $u->id;
     my $dbh = LJ::get_db_writer();
@@ -200,8 +201,8 @@ sub _wt_list_db {
     my $lock = LJ::get_lock($dbh, "global", $lockname);
     return {} unless $lock;
 
-    # in lock, try memcache
-    my $memc = _wt_list_memc( $u );
+    # in lock, try memcache first (unless told not to)
+    my $memc = $args{force_database} ? undef : _wt_list_memc( $u, community_okay => $args{community_okay} );
     return $release_lock->( $memc ) if $memc;
 
     # we are now inside the lock, but memcache was empty, so we must query
@@ -209,14 +210,54 @@ sub _wt_list_db {
 
     # memcache data info
     my $ver     = 2;         # memcache data version
-    my $memkey  = [$userid, "wt_list:$userid"];
+    my $key     = ( $args{community_okay} && $u->is_community ) ? 'c_wt_list' : 'wt_list';
+    my $memkey  = [$userid, "$key:$userid"];
     my $packfmt = "NH6H6QC"; # pack format
     my $packlen = 19;        # length of $packfmt
 
     # columns we're selecting
-    my @cols = qw/ to_userid fgcolor bgcolor groupmask showbydefault /;
     my $mempack = $ver; # full packed string to insert into memcache, byte 1 is dversion
     my %rows;           # rows object to be returned, all groupmasks match
+
+    # at this point we branch.  if we're trying to get the list of things the community
+    # watches - for usage in the friends page only - then we change paths.
+    if ( $u->is_community && $args{community_okay} ) {
+        # simply get userids from elsewhen to build %rows
+        foreach my $uid ( $u->member_userids ) {
+            # pack data into list, but only store up to 950k of data before
+            # bailing.  (practical limit of 64k watch list entries.)
+            #
+            # also note that we fake a lot of this, since communities don't actually
+            # have a watch list.
+            my $newpack = pack( $packfmt, ( $uid, '000000', 'ffffff', 1 << 61, '1' ) );
+            last if length($mempack) + length($newpack) > 950*1024;
+
+            $mempack .= $newpack;
+
+            # more faking it for fun and profit
+            $rows{$uid} = {
+                to_userid     => $uid,
+                fgcolor       => '#000000',
+                bgcolor       => '#ffffff',
+                groupmask     => 1 << 61,
+                showbydefault => '1',
+            };
+        }
+
+        # now stuff in memcache and bail
+        LJ::MemCache::set( $memkey, $mempack );
+        return $release_lock->( \%rows );
+    }
+
+    # at this point, if they're not an individual, then throw an empty set of data in memcache
+    # and bail out.  only individuals have watch lists.
+    unless ( $u->is_individual ) {
+        LJ::MemCache::set( $memkey, $mempack );
+        return $release_lock->( \%rows );
+    }
+
+    # actual watching path
+    my @cols = qw/ to_userid fgcolor bgcolor groupmask showbydefault /;
 
     # try the SQL on the master database
     my $sth = $dbh->prepare( 'SELECT to_userid, fgcolor, bgcolor, groupmask, showbydefault ' .
@@ -248,7 +289,7 @@ sub _wt_list_db {
     }
 
     # now stuff in memcache
-    LJ::MemCache::add($memkey, $mempack);
+    LJ::MemCache::set($memkey, $mempack);
 
     # finished with lock, release it
     return $release_lock->( \%rows );
--------------------------------------------------------------------------------