180 lines
6.1 KiB
Perl
180 lines
6.1 KiB
Perl
#!/usr/bin/perl
|
|
#
|
|
# DW::Controller::Admin::Approve
|
|
#
|
|
# Interface for screening new accounts for spam content.
|
|
#
|
|
# Authors:
|
|
# Jen Griffin <kareila@livejournal.com>
|
|
#
|
|
# Copyright (c) 2020 by Dreamwidth Studios, LLC.
|
|
#
|
|
# This program is free software; you may redistribute it and/or modify it under
|
|
# the same terms as Perl itself. For a copy of the license, please reference
|
|
# 'perldoc perlartistic' or 'perldoc perlgpl'.
|
|
#
|
|
|
|
package DW::Controller::Admin::Approve;
|
|
|
|
use strict;
|
|
|
|
use DW::Controller;
|
|
use DW::Routing;
|
|
use DW::Template;
|
|
use DW::FormErrors;
|
|
|
|
my $privs = [
|
|
'siteadmin:approvenew', # just for this page
|
|
'siteadmin:spamreports', # include existing antispam team
|
|
'suspend', # include anyone with generic suspend privs
|
|
'suspend:recent', # just for this page
|
|
];
|
|
|
|
DW::Controller::Admin->register_admin_page(
|
|
'/',
|
|
path => 'recent_accounts',
|
|
ml_scope => '/admin/recent_accounts/review.tt',
|
|
privs => $privs
|
|
);
|
|
|
|
DW::Routing->register_string( '/admin/recent_accounts', \&approve_handler, app => 1 );
|
|
|
|
sub approve_handler {
|
|
my ( $ok, $rv ) = controller( form_auth => 1, privcheck => $privs );
|
|
return $rv unless $ok;
|
|
|
|
my $scope = '/admin/recent_accounts/review.tt';
|
|
|
|
my $prop = LJ::get_prop( 'user', 'not_approved' );
|
|
return error_ml( "$scope.error.disabled", { sitenameshort => $LJ::SITENAMESHORT } )
|
|
unless $prop && LJ::is_enabled('approvenew');
|
|
|
|
my $r = $rv->{r};
|
|
my $remote = $rv->{remote};
|
|
my $form_args = $r->post_args;
|
|
my $vars = {};
|
|
|
|
$vars->{can_suspend} = 1
|
|
if $remote->has_priv( 'suspend', '' ) || $remote->has_priv( 'suspend', 'recent' );
|
|
|
|
return DW::Template->render_template( 'admin/recent_accounts/review.tt', $vars )
|
|
unless $r->did_post;
|
|
|
|
my $dbr = LJ::get_db_reader();
|
|
my $sth = $dbr->prepare( "SELECT userid FROM userproplite "
|
|
. "WHERE upropid=? AND value=? ORDER BY userid LIMIT ?" );
|
|
|
|
my $get_users = sub {
|
|
my ( $value, $limit ) = @_;
|
|
$sth->execute( $prop->{id}, $value, $limit );
|
|
die $dbr->errstr if $dbr->err;
|
|
|
|
my @uids;
|
|
push @uids, $_->[0] while $_ = $sth->fetchrow_arrayref;
|
|
return LJ::load_userids(@uids); # hashref
|
|
};
|
|
|
|
if ( $form_args->{begin} ) {
|
|
|
|
# get a user to review - we don't want to just get the first result,
|
|
# high chance of collision with multiple active reviewers
|
|
my $users = $get_users->( 1, 5 );
|
|
|
|
# make sure the accounts are at least an hour old - sorting
|
|
# SELECT by userid means oldest accounts will be reviewed first
|
|
my $now = time;
|
|
foreach ( keys %$users ) {
|
|
delete $users->{$_} if $users->{$_}->timecreate > $now - 3600;
|
|
}
|
|
|
|
my @ids = sort keys %$users;
|
|
if ( my $num = scalar @ids ) {
|
|
my $pickrand = int( rand($num) );
|
|
$vars->{user} = $users->{ $ids[$pickrand] };
|
|
$vars->{ago} = LJ::diff_ago_text( $vars->{user}->timecreate );
|
|
return DW::Template->render_template( 'admin/recent_accounts/user.tt',
|
|
$vars, { no_sitescheme => 1 } );
|
|
}
|
|
else {
|
|
return error_ml("$scope.error.nousers");
|
|
}
|
|
}
|
|
|
|
if ( $form_args->{uid} ) {
|
|
my $u = LJ::load_userid( $form_args->{uid} );
|
|
my $success = DW::FormErrors->new;
|
|
my $value;
|
|
|
|
# take action based on form_args - either clear or escalate
|
|
$value = 0 if $form_args->{yes};
|
|
$value = 2 if $form_args->{no};
|
|
|
|
return error_ml('error.invalidform') unless defined $value;
|
|
|
|
my $act = $value ? 'rejected' : 'approved';
|
|
$success->add( '', ".success.$act", { user => $u->ljuser_display } );
|
|
|
|
# reinforce the different colors for rejection vs approval
|
|
$vars->{ $value ? 'errors' : 'success' } = $success;
|
|
|
|
# force lookup in case someone else just changed this - we still show
|
|
# the success message to the user, but don't perform the actions again
|
|
delete $u->{"not_approved"};
|
|
$u->preload_props( { use_master => 1 }, "not_approved" );
|
|
|
|
if ( $u->prop('not_approved') && $u->prop('not_approved') == 1 ) {
|
|
$u->set_prop( not_approved => $value );
|
|
my $msg = sprintf( "new account %s $act by %s", $u->user, $remote->user );
|
|
LJ::statushistory_add( $u, $remote, 'approvenew', $msg );
|
|
|
|
# I thought about automatically doing the suspension here if
|
|
# $remote had suspend privs, but I think it's better to give the
|
|
# user a chance to review their actions in case of fat fingering
|
|
}
|
|
|
|
return DW::Template->render_template( 'admin/recent_accounts/review.tt', $vars );
|
|
}
|
|
|
|
if ( $form_args->{suspend} ) {
|
|
return $r->redirect("$LJ::SITEROOT/admin/recent_accounts")
|
|
unless $vars->{can_suspend};
|
|
|
|
# get a list of flagged users to review for suspension
|
|
$vars->{users} = $get_users->( 2, 10 );
|
|
|
|
return DW::Template->render_template( 'admin/recent_accounts/suspend.tt', $vars );
|
|
}
|
|
|
|
if ( $form_args->{do_suspend} ) {
|
|
my @ids = split / /, $form_args->{uids};
|
|
return error_ml('error.invalidform') unless @ids && $vars->{can_suspend};
|
|
|
|
my $users = LJ::load_userids(@ids);
|
|
my $success = DW::FormErrors->new;
|
|
my $count = 0;
|
|
|
|
foreach my $uid (@ids) {
|
|
my $u = $users->{$uid};
|
|
next if $u->is_suspended; # already done
|
|
|
|
if ( $form_args->{"user_$uid"} ) {
|
|
$u->set_suspended( $remote, "from /admin/recent_accounts" );
|
|
$count++;
|
|
}
|
|
else {
|
|
$u->set_prop( not_approved => 0 );
|
|
LJ::statushistory_add( $u, $remote, 'approvenew',
|
|
sprintf( "new account %s approved by %s", $u->user, $remote->user ) );
|
|
}
|
|
}
|
|
|
|
$success->add( '', '.success.suspend', { count => $count } );
|
|
$vars->{success} = $success;
|
|
|
|
return DW::Template->render_template( 'admin/recent_accounts/review.tt', $vars );
|
|
}
|
|
|
|
return error_ml('error.invalidform'); # no form args we know how to handle
|
|
}
|
|
|
|
1;
|