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-11-24 08:03 pm

[dw-free] "Maintainer only" posting security in communities

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

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

Add 'Maintainers' security option when posting entries to communities.

Patch by [personal profile] afuna.

Files modified:
  • bin/upgrading/en.dat
  • cgi-bin/DW/Logic/LogItems.pm
  • cgi-bin/LJ/Entry.pm
  • cgi-bin/LJ/S2/DayPage.pm
  • cgi-bin/LJ/S2/MonthPage.pm
  • cgi-bin/LJ/Setting/MinSecurity.pm
  • cgi-bin/LJ/Talk.pm
  • cgi-bin/LJ/User.pm
  • cgi-bin/ljhooks.pl
  • cgi-bin/ljprotocol.pl
  • cgi-bin/weblib.pl
  • htdocs/js/entry.js
  • htdocs/tools/endpoints/getsecurityoptions.bml
--------------------------------------------------------------------------------
diff -r dbaae7e52705 -r e36a761d81b3 bin/upgrading/en.dat
--- a/bin/upgrading/en.dat	Tue Nov 24 19:51:11 2009 +0000
+++ b/bin/upgrading/en.dat	Tue Nov 24 20:03:33 2009 +0000
@@ -2751,6 +2751,8 @@ setting.minsecurity.option.select.friend
 
 setting.minsecurity.option.select.members=members
 
+setting.minsecurity.option.select.admin=administrators
+
 setting.minsecurity.option.select.private=just me (private)
 
 setting.minsecurity.option.select.public=everyone (public)
diff -r dbaae7e52705 -r e36a761d81b3 cgi-bin/DW/Logic/LogItems.pm
--- a/cgi-bin/DW/Logic/LogItems.pm	Tue Nov 24 19:51:11 2009 +0000
+++ b/cgi-bin/DW/Logic/LogItems.pm	Tue Nov 24 20:03:33 2009 +0000
@@ -412,8 +412,11 @@ sub recent_items
 
     # decide what level of security the remote user can see
     my $secwhere = "";
-    if ($userid == $remoteid || $args{'viewall'}) {
+    if ( $userid == $remoteid
+        || ( $remote && $remote->can_manage( $u ) )
+        || $args{'viewall'} ) {
         # no extra where restrictions... user can see all their own stuff
+        # community administrators can also see everything in their comms
         # alternatively, if 'viewall' opt flag is set, security is off.
     } elsif ($mask) {
         # can see public or things with them in the mask
diff -r dbaae7e52705 -r e36a761d81b3 cgi-bin/LJ/Entry.pm
--- a/cgi-bin/LJ/Entry.pm	Tue Nov 24 19:51:11 2009 +0000
+++ b/cgi-bin/LJ/Entry.pm	Tue Nov 24 20:03:33 2009 +0000
@@ -764,24 +764,34 @@ sub visible_to
     # owners can always see their own.
     return 1 if $userid == $remoteid;
 
-    # other people can't read private
-    return 0 if $self->{'security'} eq "private";
+    # should be 'usemask' or 'private' security from here out, otherwise
+    # assume it's something new and return 0
+    return 0 unless $self->{security} eq "usemask" || $self->{security} eq "private";
 
-    # should be 'usemask' security from here out, otherwise
-    # assume it's something new and return 0
-    return 0 unless $self->{'security'} eq "usemask";
-
-    # if it's usemask, we have to refuse non-personal journals,
-    # so we have to load the user
     return 0 unless $remote->is_individual;
 
-    # check if it's a community and they're a member
-    return 1 if $self->journal->is_community &&
+    if ( $self->security eq "private" ) {
+        # other people can't read private on personal journals
+        return 0 if $self->journal->is_individual;
+
+        # but community administrators can read private entries on communities
+        return 1 if $self->journal->is_community && $remote->can_manage( $self->journal );
+
+        # private entry on a community; we're not allowed to see this
+        return 0;
+    }
+
+    if ( $self->security eq "usemask" ) {
+        # check if it's a community and they're a member
+        return 1 if $self->journal->is_community &&
                 $remote->member_of( $self->journal );
+    
+        my $gmask = $self->journal->trustmask( $remote );
+        my $allowed = (int($gmask) & int($self->{'allowmask'}));
+        return $allowed ? 1 : 0;  # no need to return matching mask
+    }
 
-    my $gmask = $self->journal->trustmask( $remote );
-    my $allowed = (int($gmask) & int($self->{'allowmask'}));
-    return $allowed ? 1 : 0;  # no need to return matching mask
+    return 0;
 }
 
 # returns hashref of (kwid => tag) for tags on the entry
@@ -1548,8 +1558,12 @@ sub get_log2_recent_user
         last unless $left;
         last if $notafter and $item->{'rlogtime'} > $notafter;
         next unless $remote || $item->{'security'} eq 'public';
-        next if $item->{'security'} eq 'private'
-            and $item->{'journalid'} != $remote->{'userid'};
+
+        if ( $item->{security} eq 'private' and $item->{journalid} != $remote->{userid} ) {
+            my $ju = LJ::load_userid( $item->{journalid} );
+            next unless $remote->can_manage( $ju );
+        }
+
         if ($item->{'security'} eq 'usemask') {
             next unless $remote->is_individual;
             my $permit = ($item->{'journalid'} == $remote->{'userid'});
diff -r dbaae7e52705 -r e36a761d81b3 cgi-bin/LJ/S2/DayPage.pm
--- a/cgi-bin/LJ/S2/DayPage.pm	Tue Nov 24 19:51:11 2009 +0000
+++ b/cgi-bin/LJ/S2/DayPage.pm	Tue Nov 24 20:03:33 2009 +0000
@@ -52,7 +52,7 @@ sub DayPage
         ( $viewall, $viewsome ) =
             $remote->view_priv_check( $u, $get->{viewall}, 'day' );
 
-        if ( $viewall || $remote->equals( $u ) ) {
+        if ( $viewall || $remote->equals( $u ) || $remote->can_manage( $u ) ) {
             $secwhere = "";   # see everything
         } elsif ( $remote->is_individual ) {
             my $gmask = $u->is_community ? $remote->member_of( $u ) : $u->trustmask( $remote );
diff -r dbaae7e52705 -r e36a761d81b3 cgi-bin/LJ/S2/MonthPage.pm
--- a/cgi-bin/LJ/S2/MonthPage.pm	Tue Nov 24 19:51:11 2009 +0000
+++ b/cgi-bin/LJ/S2/MonthPage.pm	Tue Nov 24 20:03:33 2009 +0000
@@ -52,7 +52,7 @@ sub MonthPage
         ( $viewall, $viewsome ) =
             $remote->view_priv_check( $u, $get->{viewall}, 'month' );
 
-        if ( $viewall || $remote->equals( $u ) ) {
+        if ( $viewall || $remote->equals( $u ) || $remote->can_manage( $u ) ) {
             $secwhere = "";   # see everything
         } elsif ( $remote->is_individual ) {
             my $gmask = $u->is_community ? $remote->member_of( $u ) : $u->trustmask( $remote );
diff -r dbaae7e52705 -r e36a761d81b3 cgi-bin/LJ/Setting/MinSecurity.pm
--- a/cgi-bin/LJ/Setting/MinSecurity.pm	Tue Nov 24 19:51:11 2009 +0000
+++ b/cgi-bin/LJ/Setting/MinSecurity.pm	Tue Nov 24 20:03:33 2009 +0000
@@ -30,9 +30,11 @@ sub option {
     my @options = (
         "" => $class->ml('setting.minsecurity.option.select.public'),
         friends => $u->is_community ? $class->ml('setting.minsecurity.option.select.members') : $class->ml('setting.minsecurity.option.select.friends'),
+        private => $u->is_community ?
+        $class->ml( 'setting.minsecurity.option.select.admin' ) :
+        $class->ml( 'setting.minsecurity.option.select.private' )
     );
-    push @options, ( private => $class->ml('setting.minsecurity.option.select.private') )
-        if $u->is_personal;
+
 
     my $ret = "<label for='${key}minsecurity'>" . $class->ml('setting.minsecurity.option') . "</label> ";
     $ret .= LJ::html_select({
@@ -48,11 +50,7 @@ sub save {
     my ($class, $u, $args) = @_;
 
     my $val = $class->get_arg($args, "minsecurity");
-    if ($u->is_community) {
-        $val = "" unless $val =~ /^(friends)$/;
-    } else {
-        $val = "" unless $val =~ /^(friends|private)$/;
-    }
+    $val = "" unless $val =~ /^(friends|private)$/;
 
     $u->set_prop( newpost_minsecurity => $val );
 
diff -r dbaae7e52705 -r e36a761d81b3 cgi-bin/LJ/Talk.pm
--- a/cgi-bin/LJ/Talk.pm	Tue Nov 24 19:51:11 2009 +0000
+++ b/cgi-bin/LJ/Talk.pm	Tue Nov 24 20:03:33 2009 +0000
@@ -258,7 +258,7 @@ sub check_viewable
         my $journalname = $journal->username;
 
         if (defined $remote) {
-            if ( $journal->is_community && ! $journal->is_closed_membership && $remote ) {
+            if ( $journal->is_community && ! $journal->is_closed_membership && $remote && $item->{security} ne "private" ) {
                 return $err->( BML::ml( 'talk.error.notauthorised.comm.open', { aopts => "href='$LJ::SITEROOT/community/join?comm=$journalname'" } ) );
             } elsif ( $journal->is_community && $journal->is_closed_membership ) {
                 return $err->( BML::ml( 'talk.error.notauthorised.comm.closed' ) );
diff -r dbaae7e52705 -r e36a761d81b3 cgi-bin/LJ/User.pm
--- a/cgi-bin/LJ/User.pm	Tue Nov 24 19:51:11 2009 +0000
+++ b/cgi-bin/LJ/User.pm	Tue Nov 24 20:03:33 2009 +0000
@@ -7711,27 +7711,37 @@ sub can_view
     # owners can always see their own.
     return 1 if $userid == $remoteid;
 
-    # other people can't read private
-    return 0 if $item->{'security'} eq "private";
-
-    # should be 'usemask' security from here out, otherwise
+    # should be 'usemask' or 'private' security from here out, otherwise
     # assume it's something new and return 0
-    return 0 unless $item->{'security'} eq "usemask";
-
-    # if it's usemask, we have to refuse non-personal journals,
-    # so we have to load the user
+    return 0 unless $item->{security} eq "usemask" || $item->{security} eq "private";
+
     return 0 unless $remote->is_individual;
 
     # this far down we have to load the user
     my $u = LJ::want_user( $userid ) or return 0;
 
-    # check if it's a community and they're a member
-    return 1 if $u->is_community &&
-                $remote->member_of( $u );
-
-    # now load allowmask
-    my $allowed = ( $u->trustmask( $remoteid ) & int($item->{'allowmask'}) );
-    return $allowed ? 1 : 0;  # no need to return matching mask
+    if ( $item->{security} eq "private" ) {
+        # other people can't read private on personal journals
+        return 0 if $u->is_individual;
+
+        # but community administrators can read private entries on communities
+        return 1 if $u->is_community && $remote->can_manage( $u );
+
+        # private entry on a community; we're not allowed to see this
+        return 0;
+    }
+
+    if ( $item->{security} eq "usemask" ) {
+        # check if it's a community and they're a member
+        return 1 if $u->is_community &&
+                    $remote->member_of( $u );
+    
+        # now load allowmask
+        my $allowed = ( $u->trustmask( $remoteid ) & int($item->{'allowmask'}) );
+        return $allowed ? 1 : 0;  # no need to return matching mask
+    }
+
+    return 0;
 }
 
 
@@ -8021,7 +8031,7 @@ sub get_daycounts
                 "viewall", "calendar" );
         }
 
-        if ( $remote->userid == $uid || $viewall ) {
+        if ( $remote->userid == $uid || $viewall || $remote->can_manage( $u ) ) {
             $secwhere = "";   # see everything
             $memkind = 'a'; # all
         } elsif ( $remote->is_individual ) {
diff -r dbaae7e52705 -r e36a761d81b3 cgi-bin/ljhooks.pl
--- a/cgi-bin/ljhooks.pl	Tue Nov 24 19:51:11 2009 +0000
+++ b/cgi-bin/ljhooks.pl	Tue Nov 24 20:03:33 2009 +0000
@@ -112,12 +112,9 @@ register_setter("newpost_minsecurity", s
         $$err = "Illegal value.  Must be 'public', 'access' (for personal journals), 'members' (for communities), or 'private'";
         return 0;
     }
-    # Don't let commmunities be private or access-locked
+    # Don't let commmunities be access-locked
     if ( $u->is_community ) {
-        if ( $value eq "private" ) {
-            $$err = "newpost_minsecurity cannot be private for communities";
-            return 0;
-        } elsif ( $value eq "access" ) {
+       if ( $value eq "access" ) {
             $$err = "newpost_minsecurity cannot be access-locked for communities (use 'members' instead)";
             return 0;
         }
diff -r dbaae7e52705 -r e36a761d81b3 cgi-bin/ljprotocol.pl
--- a/cgi-bin/ljprotocol.pl	Tue Nov 24 19:51:11 2009 +0000
+++ b/cgi-bin/ljprotocol.pl	Tue Nov 24 20:03:33 2009 +0000
@@ -40,10 +40,11 @@ my %e = (
      # User Errors
      "100" => [ E_PERM, "Invalid username" ],
      "101" => [ E_PERM, "Invalid password" ],
-     "102" => [ E_PERM, "Can't use custom/private security on shared/community journals." ],
+     "102" => [ E_PERM, "Can't use custom security on community journals." ],
      "103" => [ E_PERM, "Poll error" ],
      "104" => [ E_TEMP, "Error adding one or more friends" ],
      "105" => [ E_PERM, "Challenge expired" ],
+     "106" => [ E_PERM, "Can only use administrator-locked security on community journals you manage." ],
      "150" => [ E_PERM, "Can't post as non-user" ],
      "151" => [ E_TEMP, "Banned from journal" ],
      "152" => [ E_PERM, "Can't make back-dated entries in non-personal journal." ],
@@ -1184,11 +1185,16 @@ sub postevent
 
     my $qsecurity = $dbh->quote($security);
 
-    ### make sure user can't post with "custom/private security" on shared journals
+    ### make sure user can't post with "custom security" on communities
     return fail($err,102)
-        if ($ownerid != $posterid && # community post
-            ($req->{'security'} eq "private" ||
-            ($req->{'security'} eq "usemask" && $qallowmask != 1 )));
+        if $ownerid != $posterid && # community post
+           $req->{'security'} eq "usemask" && $qallowmask != 1;
+
+    ## make sure user can't post with "private security" on communities they don't manage
+    return fail( $err, 106 )
+        if $ownerid != $posterid && # community post
+           $req->{'security'} eq "private" &&
+           ! $u->can_manage( $uowner );
 
     # make sure this user isn't banned from posting here (if
     # this is a community journal)
@@ -1632,11 +1638,16 @@ sub editevent
     return fail($err, 203, "Invalid friends group security set.")
         if $qallowmask > 1 && $qallowmask % 2;
 
-    ### make sure user can't change a post to "custom/private security" on shared journals
+    ### make sure user can't post with "custom security" on communities
     return fail($err,102)
-        if ($ownerid != $posterid && # community post
-            ($req->{'security'} eq "private" ||
-            ($req->{'security'} eq "usemask" && $qallowmask != 1 )));
+        if $ownerid != $posterid && # community post
+           $req->{'security'} eq "usemask" && $qallowmask != 1;
+
+    ## make sure user can't post with "private security" on communities they don't manage
+    return fail( $err, 106 )
+        if $ownerid != $posterid && # community post
+           $req->{'security'} eq "private" &&
+           ! $u->can_manage( $uowner );
 
     # make sure the new entry's under the char limit
     # NOTE: as in postevent, this requires $req->{event} to be binary data
diff -r dbaae7e52705 -r e36a761d81b3 cgi-bin/weblib.pl
--- a/cgi-bin/weblib.pl	Tue Nov 24 19:51:11 2009 +0000
+++ b/cgi-bin/weblib.pl	Tue Nov 24 20:03:33 2009 +0000
@@ -1828,6 +1828,7 @@ PREVIEW
                 my $string_friends = LJ::ejs(BML::ml('label.security.accesslist'));
                 my $string_friends_comm = LJ::ejs(BML::ml('label.security.members'));
                 my $string_private = LJ::ejs(BML::ml('label.security.private2'));
+                my $string_admin = LJ::ejs( BML::ml( 'label.security.maintainers' ) );
                 my $string_custom = LJ::ejs(BML::ml('label.security.custom'));
 
                 $out .= qq{
@@ -1836,12 +1837,15 @@ PREVIEW
                     UpdateFormStrings.friends = "$string_friends";
                     UpdateFormStrings.friends_comm = "$string_friends_comm";
                     UpdateFormStrings.private = "$string_private";
-                    UpdateFormStrings.custom = "$string_custom";</script>
+                    UpdateFormStrings.custom = "$string_custom";
+                    UpdateFormStrings.admin = "$string_admin";</script>
                 };
+
 
                 $$onload .= " setColumns();" if $remote;
                 my @secs = ("public", $string_public, "friends", $is_comm ? $string_friends_comm : $string_friends);
                 push @secs, ("private", $string_private) unless $is_comm;
+                push @secs, ( "private", $string_admin ) if $is_comm && $remote && $remote->can_manage( $usejournalu );
 
                 my ( @secopts, @trust_groups );
                 @trust_groups = $remote->trust_groups if $remote;
diff -r dbaae7e52705 -r e36a761d81b3 htdocs/js/entry.js
--- a/htdocs/js/entry.js	Tue Nov 24 19:51:11 2009 +0000
+++ b/htdocs/js/entry.js	Tue Nov 24 20:03:33 2009 +0000
@@ -412,6 +412,9 @@ function changeSecurityOptions(defaultjo
                     if (data.ret['is_comm']) {
                         $('security').options[0] = new Option(UpdateFormStrings.public, 'public');
                         $('security').options[1] = new Option(UpdateFormStrings.friends_comm, 'friends');
+                        if ( data.ret['can_manage'] ) {
+                            $('security').options[2] = new Option(UpdateFormStrings.admin, 'private');
+                        }
                     } else {
                         $('security').options[0] = new Option(UpdateFormStrings.public, 'public');
                         $('security').options[1] = new Option(UpdateFormStrings.friends, 'friends');
diff -r dbaae7e52705 -r e36a761d81b3 htdocs/tools/endpoints/getsecurityoptions.bml
--- a/htdocs/tools/endpoints/getsecurityoptions.bml	Tue Nov 24 19:51:11 2009 +0000
+++ b/htdocs/tools/endpoints/getsecurityoptions.bml	Tue Nov 24 20:03:33 2009 +0000
@@ -19,6 +19,7 @@
 
     my %ret = (
         is_comm => $u->is_comm ? 1 : 0,
+        can_manage =>  $remote && $remote->can_manage( $u ) ? 1 : 0,
     );
 
     return JSON::objToJson({ ret => \%ret }) unless $remote && $remote->can_post_to($u);
--------------------------------------------------------------------------------