# This code was forked from the LiveJournal project owned and operated # by Live Journal, Inc. The code has been modified and expanded by # Dreamwidth Studios, LLC. These files were originally licensed under # the terms of the license supplied by Live Journal, Inc, which can # currently be found at: # # http://code.livejournal.org/trac/livejournal/browser/trunk/LICENSE-LiveJournal.txt # # In accordance with the original license, this code and all its # modifications are provided under the GNU General Public License. # A copy of that license can be found in the LICENSE file included as # part of this distribution. package LJ::MassPrivacy; # LJ::MassPrivacy object # # Used to handle Schwartz job for updating privacy of posts en masse # use strict; use v5.10; use Log::Log4perl; my $log = Log::Log4perl->get_logger(__PACKAGE__); use Carp qw(croak); use DateTime; use DW::Task::MassPrivacy; sub schwartz_capabilities { return qw(LJ::Worker::MassPrivacy); } # enqueue job to update privacy sub enqueue_job { my ( $class, %opts ) = @_; croak "enqueue_job is a class method" unless $class eq __PACKAGE__; croak "missing options argument" unless %opts; # Check options if ( !( $opts{s_security} =~ m/[private|usemask|public]/ ) || !( $opts{e_security} =~ m/[private|usemask|public]/ ) ) { croak "invalid privacy option"; } if ( $opts{'start_date'} || $opts{'end_date'} ) { croak "start or end date not defined" if ( !$opts{'start_date'} || !$opts{'end_date'} ); if ( !( $opts{'start_date'} >= 0 ) || !( $opts{'end_date'} >= 0 ) || !( $opts{'start_date'} <= $LJ::EndOfTime ) || !( $opts{'end_date'} <= $LJ::EndOfTime ) ) { return undef; } } return DW::TaskQueue->dispatch( DW::Task::MassPrivacy->new( \%opts ) ); } sub handle { my ( $class, $opts ) = @_; croak "missing options argument" unless $opts; my $u = LJ::load_userid( $opts->{'userid'} ); # we only handle changes to or from locked security # Allowmask for locked is 1, public and private are 0. my $s_allowmask = ( $opts->{s_security} eq 'usemask' ) ? 1 : 0; my $e_allowmask = ( $opts->{e_security} eq 'usemask' ) ? 1 : 0; my %privacy = ( private => 'private', usemask => 'locked', public => 'public', ); my @jids; my $timeframe = ''; # date range string or empty # If there is a date range # add 24h to the final date; otherwise we don't get entries on that date if ( $opts->{s_unixtime} && $opts->{e_unixtime} ) { @jids = $u->get_post_ids( 'security' => $opts->{'s_security'}, 'allowmask' => $s_allowmask, 'start_date' => $opts->{'s_unixtime'}, 'end_date' => $opts->{'e_unixtime'} + 24 * 60 * 60 ); my $s_dt = DateTime->from_epoch( epoch => $opts->{s_unixtime} ); my $e_dt = DateTime->from_epoch( epoch => $opts->{e_unixtime} ); $timeframe = "between " . $s_dt->ymd . " and " . $e_dt->ymd; } else { @jids = $u->get_post_ids( 'security' => $opts->{'s_security'}, 'allowmask' => $s_allowmask, ); } # check if there are any posts to update return 1 unless ( scalar @jids ); my @errs; my $okay_ct = 0; # Update each event using the API foreach my $itemid (@jids) { my %res = (); my %req = ( 'mode' => 'editevent', 'ver' => $LJ::PROTOCOL_VER, 'user' => $u->{'user'}, 'itemid' => $itemid, 'security' => $opts->{e_security}, 'allowmask' => $e_allowmask, ); # do editevent request LJ::do_request( \%req, \%res, { 'noauth' => 1, 'u' => $u, 'use_old_content' => 1 } ); # check response if ( $res{'success'} eq "OK" ) { $okay_ct++; } else { push @errs, $res{'errmsg'}; } } # better logging # only print 200 characters of error message to log # allow some space at the end for error location message if (@errs) { my $errmsg = join( ', ', @errs ); $errmsg = substr( $errmsg, 0, 200 ) . "... "; LJ::statushistory_add( $u, $u, "mass_privacy", "Error: $errmsg" ); die $errmsg; } my $subject = LJ::Lang::ml( 'email.massprivacy.subject', { user => $u->user } ); my $msg = LJ::Lang::ml( 'email.massprivacy.body', { user => $u->user, sitenameshort => $LJ::SITENAMESHORT, siteroot => $LJ::SITEROOT, count => $okay_ct, timeframe => $timeframe, oldsecurity => $privacy{ $opts->{s_security} }, newsecurity => $privacy{ $opts->{e_security} }, privacyurl => "$LJ::SITEROOT/editprivacy", } ); LJ::send_mail( { 'to' => $u->email_raw, 'from' => $LJ::BOGUS_EMAIL, 'fromname' => $LJ::SITENAMESHORT, 'wrap' => 1, 'charset' => 'utf-8', 'subject' => $subject, 'body' => $msg, } ); LJ::statushistory_add( $u, $u, "mass_privacy", "Success: $okay_ct " . $privacy{ $opts->{s_security} } . " entries " . $timeframe . "have now " . "been changed to be " . $privacy{ $opts->{e_security} } ); return 1; } # Schwartz job for processing changes to privacy en masse package LJ::Worker::MassPrivacy; use base 'TheSchwartz::Worker'; use LJ::MassPrivacy; sub work { my ( $class, $job ) = @_; my $opts = $job->arg; unless ($opts) { $job->failed; return; } LJ::MassPrivacy->handle($opts); return $job->completed; } sub keep_exit_status_for { 0 } sub grab_for { 300 } sub max_retries { 5 } sub retry_delay { my ( $class, $fails ) = @_; return ( 10, 30, 60, 300, 600 )[$fails]; } 1;