422 lines
13 KiB
Perl
Executable File
422 lines
13 KiB
Perl
Executable File
#!/usr/bin/perl
|
|
#
|
|
|
|
package LJ::Con;
|
|
|
|
use strict;
|
|
use vars qw(%cmd);
|
|
|
|
$cmd{'expunge_userpic'}->{'handler'} = \&expunge_userpic;
|
|
$cmd{'suspend'}->{'handler'} = \&suspend;
|
|
$cmd{'unsuspend'}->{'handler'} = \&suspend;
|
|
$cmd{'getemail'}->{'handler'} = \&getemail;
|
|
$cmd{'get_maintainer'}->{'handler'} = \&get_maintainer;
|
|
$cmd{'get_moderator'}->{'handler'} = \&get_moderator;
|
|
$cmd{'finduser'}->{'handler'} = \&finduser;
|
|
$cmd{'infohistory'}->{'handler'} = \&infohistory;
|
|
$cmd{'change_journal_status'}->{'handler'} = \&change_journal_status;
|
|
$cmd{'set_underage'}->{'handler'} = \&set_underage;
|
|
|
|
sub set_underage {
|
|
my ($dbh, $remote, $args, $out) = @_;
|
|
|
|
my $err = sub { push @$out, [ "error", shift ]; 0; };
|
|
my $info = sub { push @$out, [ "info", shift ]; 1; };
|
|
|
|
return $err->("This command takes three arguments. Consult the reference for details.")
|
|
unless scalar(@$args) == 4;
|
|
return $err->("You don't have the necessary privilege (siteadmin:underage) to change an account's underage flag.")
|
|
unless LJ::check_priv($remote, 'siteadmin', 'underage') || LJ::check_priv($remote, 'siteadmin', '*');
|
|
|
|
my $u = LJ::load_user($args->[1]);
|
|
return $err->("Invalid user.")
|
|
unless $u;
|
|
return $err->("Account is not a person type account.")
|
|
unless $u->{journaltype} eq 'P';
|
|
|
|
return $err->("Second argument must be 'on' or 'off'.")
|
|
unless $args->[2] =~ /^(?:on|off)$/;
|
|
my $on = $args->[2] eq 'on' ? 1 : 0;
|
|
|
|
my $note = $args->[3];
|
|
return $err->("You must provide a reason for this change as the third argument.")
|
|
unless $note;
|
|
|
|
# can't set state to what it is already
|
|
return $err->("User is already of the requested underage state.")
|
|
unless $on ^ $u->underage;
|
|
|
|
my ($res, $sh, $status);
|
|
if ($on) {
|
|
$status = 'M'; # "M"anually turned on
|
|
$res = "User marked as underage.";
|
|
$sh = "marked; $note";
|
|
} else {
|
|
$status = undef; # no status change
|
|
$res = "User no longer marked as underaged.";
|
|
$sh = "unmarked; $note";
|
|
}
|
|
|
|
# now record this change (yes we log it twice)
|
|
LJ::statushistory_add($u->{userid}, $remote->{userid}, "set_underage", $sh);
|
|
$u->underage($on, $status, "manual");
|
|
return $info->($res);
|
|
}
|
|
|
|
sub change_journal_status {
|
|
my ($dbh, $remote, $args, $out) = @_;
|
|
|
|
my $err = sub { push @$out, [ "error", shift ]; 0; };
|
|
my $info = sub { push @$out, [ "info", shift ]; 1; };
|
|
|
|
return $err->("This command takes two arguments. Consult the reference for details.")
|
|
unless scalar(@$args) == 3;
|
|
return $err->("You don't have the necessary privilege (siteadmin:users) to change account status.")
|
|
unless LJ::check_priv($remote, 'siteadmin', 'users') || LJ::check_priv($remote, 'siteadmin', '*');
|
|
|
|
my $u = LJ::load_user($args->[1]);
|
|
return $err->("Invalid user.")
|
|
unless $u;
|
|
|
|
# figure out the new status
|
|
my $status = $args->[2];
|
|
my $opts = {
|
|
#name => [ 'status-to', 'valid-statuses-from', 'error-message-if-from-fails', 'success-message' ]
|
|
normal => [ 'V', 'ML', 'The user must be in memorial or locked status first.', 'User status set back to normal.' ],
|
|
memorial => [ 'M', 'V', 'The user must be in normal status first.', 'User account set as memorial.' ],
|
|
locked => [ 'L', 'V', 'The user must be in normal status first.', 'User account has been locked.' ],
|
|
}->{$status};
|
|
|
|
# make sure we got a valid $opts arrayref
|
|
return $err->("Invalid status. Consult the reference for more information.")
|
|
unless defined $opts && ref $opts eq 'ARRAY';
|
|
|
|
# verify user's from-statusvis is okay (it's contained in $opts->[1])
|
|
return $err->($opts->[2]) unless $opts->[1] =~ /$u->{statusvis}/;
|
|
|
|
# okay, so we need to update the user now and update statushistory
|
|
LJ::statushistory_add($u->{userid}, $remote->{userid}, "journal_status", "Changed status to $status from $u->{statusvis}.");
|
|
LJ::update_user($u->{'userid'}, { statusvis => $opts->[0], raw => 'statusvisdate=NOW()' });
|
|
return $info->($opts->[3]);
|
|
}
|
|
|
|
sub expunge_userpic {
|
|
my ($dbh, $remote, $args, $out) = @_;
|
|
|
|
unless (scalar(@$args) == 3) {
|
|
push @$out, [ "error", "This command takes exactly two arguments, username and picid. Consult the reference." ];
|
|
return 0;
|
|
}
|
|
|
|
my $user = $args->[1];
|
|
my $picid = $args->[2]+0;
|
|
|
|
unless (LJ::check_priv($remote, 'siteadmin', 'userpics') || LJ::check_priv($remote, 'siteadmin', '*')) {
|
|
push @$out, [ "error", "You don't have access to expunge user picture icons." ];
|
|
return 0;
|
|
}
|
|
|
|
my $u = LJ::load_user($user);
|
|
|
|
# the actual expunging happens in ljlib
|
|
my ($rval, $hookval) = LJ::expunge_userpic($u, $picid);
|
|
push @$out, $hookval if @{$hookval || []};
|
|
|
|
# now load up from the return value we got
|
|
unless ($rval && $u) {
|
|
push @$out, [ "error", "Error expunging user picture icon." ];
|
|
return 0;
|
|
}
|
|
|
|
# but make sure to log it
|
|
LJ::statushistory_add($u->{userid}, $remote->{userid}, 'expunge_userpic', "expunged userpic; id=$picid");
|
|
push @$out, [ "info", "User picture icon $picid for $u->{user} expunged from $LJ::SITENAMESHORT." ];
|
|
|
|
return 1;
|
|
}
|
|
|
|
sub suspend
|
|
{
|
|
my ($dbh, $remote, $args, $out) = @_;
|
|
|
|
my $confirmed = 0;
|
|
if (scalar(@$args) == 4 && $args->[3] eq 'confirm') {
|
|
pop @$args;
|
|
$confirmed = 1;
|
|
}
|
|
|
|
unless (scalar(@$args) == 3) {
|
|
push @$out, [ "error", "This command takes exactly 2 arguments. Consult the reference." ];
|
|
return 0;
|
|
}
|
|
|
|
my $cmd = $args->[0];
|
|
my ($user, $reason) = ($args->[1], $args->[2]);
|
|
|
|
if ($cmd eq "suspend" && $reason eq "off") {
|
|
push @$out, [ "error", "The second argument to the 'suspend' command is no longer 'off' to unsuspend. Use the 'unsuspend' command instead." ];
|
|
return 0;
|
|
}
|
|
|
|
unless ($remote->{'priv'}->{'suspend'}) {
|
|
push @$out, [ "error", "You don't have access to $cmd users." ];
|
|
return 0;
|
|
}
|
|
|
|
# if the user argument is an email address...
|
|
my @users;
|
|
if ($user =~ /@/) {
|
|
push @$out, [ "info", "Acting on users matching email $user..." ];
|
|
|
|
my $dbr = LJ::get_db_reader();
|
|
my $names = $dbr->selectcol_arrayref('SELECT user FROM user WHERE email = ?', undef, $user);
|
|
if ($dbr->err) {
|
|
push @$out, [ "error", "Database error: " . $dbr->errstr ];
|
|
return 0;
|
|
}
|
|
unless ($names && @$names) {
|
|
push @$out, [ "error", "No users found matching the email address $user." ];
|
|
return 0;
|
|
}
|
|
|
|
# bail unless they've confirmed this mass action
|
|
unless ($confirmed) {
|
|
push @$out, [ "info", " $_" ] foreach @$names;
|
|
push @$out, [ "info", "To actually confirm this action, please do this again:" ];
|
|
push @$out, [ "info", " $cmd $user \"$reason\" confirm" ];
|
|
return 1;
|
|
}
|
|
|
|
push @users, $_ foreach @$names;
|
|
} else {
|
|
push @users, $user;
|
|
}
|
|
|
|
foreach my $username (@users) {
|
|
my $u = LJ::load_user($username);
|
|
unless ($u) {
|
|
push @$out, [ "error", "$username invalid/unable to load." ];
|
|
next;
|
|
}
|
|
|
|
my $status = ($cmd eq "unsuspend") ? "V" : "S";
|
|
if ($u->{'statusvis'} eq $status) {
|
|
push @$out, [ "error", "$username was already in that state ($status)" ];
|
|
next;
|
|
}
|
|
|
|
LJ::update_user($u->{'userid'}, { statusvis => $status, raw => 'statusvisdate=NOW()' });
|
|
$u->{statusvis} = $status;
|
|
|
|
LJ::statushistory_add($u->{'userid'}, $remote->{'userid'}, $cmd, $reason);
|
|
|
|
LJ::Con::fb_push( $u );
|
|
|
|
push @$out, [ "info", "User '$username' ${cmd}ed." ];
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
sub getemail
|
|
{
|
|
my ($dbh, $remote, $args, $out) = @_;
|
|
|
|
unless (scalar(@$args) == 2) {
|
|
push @$out, [ "error", "This command takes exactly 1 argument. Consult the reference." ];
|
|
return 0;
|
|
}
|
|
|
|
my ($user) = ($args->[1]);
|
|
my $userid = &LJ::get_userid($user);
|
|
|
|
unless ($remote->{'priv'}->{'suspend'}) {
|
|
push @$out, [ "error", "You don't have access to see email addresses." ];
|
|
return 0;
|
|
}
|
|
|
|
unless ($userid) {
|
|
push @$out, [ "error", "Invalid user \"$user\"" ];
|
|
return 0;
|
|
}
|
|
|
|
my $sth = $dbh->prepare("SELECT email, status FROM user WHERE userid=$userid");
|
|
$sth->execute;
|
|
my ($email, $status) = $sth->fetchrow_array;
|
|
|
|
push @$out, [ "info", "User: $user" ];
|
|
push @$out, [ "info", "Email: $email" ];
|
|
push @$out, [ "info", "Status: $status (A=approved, N=new, T=transferring)" ];
|
|
|
|
return 1;
|
|
}
|
|
|
|
sub finduser
|
|
{
|
|
my ($dbh, $remote, $args, $out) = @_;
|
|
|
|
unless ($remote->{'priv'}->{'finduser'}) {
|
|
push @$out, [ "error", "$remote->{'user'}, you are not authorized to use this command." ];
|
|
return 0;
|
|
}
|
|
|
|
my ($crit, $data);
|
|
if (scalar(@$args) == 2) {
|
|
# new form; we can auto-detect emails easy enough
|
|
$data = $args->[1];
|
|
if ($data =~ /@/) {
|
|
$crit = 'email';
|
|
} else {
|
|
$crit = 'user';
|
|
}
|
|
} else {
|
|
# old format...but new variation
|
|
$crit = $args->[1];
|
|
$data = $args->[2];
|
|
|
|
# if they gave us a username and want to search by email, instead find
|
|
# all users with that email address
|
|
if ($crit eq 'email' && $data !~ /@/) {
|
|
my $u = LJ::load_user($data);
|
|
unless ($u) {
|
|
push @$out, [ "error", "User doesn't exist." ];
|
|
return 0;
|
|
}
|
|
|
|
$data = $u->{email};
|
|
}
|
|
}
|
|
|
|
my $qd = $dbh->quote($data);
|
|
|
|
my $where;
|
|
if ($crit eq "email") {
|
|
$where = "email=$qd";
|
|
} elsif ($crit eq "userid") {
|
|
$where = "userid=$qd";
|
|
} elsif ($crit eq "user") {
|
|
$where = "user=$qd";
|
|
}
|
|
|
|
unless ($where) {
|
|
push @$out, [ "error", "Invalid search criteria. See reference." ];
|
|
return 0;
|
|
}
|
|
|
|
my $userids = $dbh->selectcol_arrayref("SELECT userid FROM user WHERE $where");
|
|
if ($dbh->err) {
|
|
push @$out, [ "error", "Error in database query: " . $dbh->errstr ];
|
|
return 0;
|
|
}
|
|
unless ($userids && @$userids) {
|
|
push @$out, [ "error", "No matches." ];
|
|
return 0;
|
|
}
|
|
|
|
my $us = LJ::load_userids(@$userids);
|
|
foreach my $u (sort { $a->{userid} <=> $b->{userid} } values %$us) {
|
|
push @$out, [ "info", "User: $u->{'user'} ".
|
|
"($u->{'userid'}), journaltype: $u->{'journaltype'}, statusvis: $u->{'statusvis'}, email: ($u->{'status'}) $u->{'email'}" ];
|
|
if ($u->underage) {
|
|
my $reason;
|
|
if ($u->underage_status eq 'M') {
|
|
$reason = "manual set (see statushistory type set_underage)";
|
|
} elsif ($u->underage_status eq 'Y') {
|
|
$reason = "provided birthdate";
|
|
} elsif ($u->underage_status eq 'O') {
|
|
$reason = "unique cookie";
|
|
}
|
|
push @$out, [ "info", " User is marked underage due to $reason." ];
|
|
}
|
|
foreach (LJ::run_hooks("finduser_extrainfo", { 'dbh' => $dbh, 'u' => $u })) {
|
|
next unless $_->[0];
|
|
foreach (split(/\n/, $_->[0])) {
|
|
push @$out, [ "info", $_ ];
|
|
}
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
sub get_maintainer
|
|
{
|
|
my ($dbh, $remote, $args, $out, $edge) = @_;
|
|
$edge ||= 'A';
|
|
|
|
unless (scalar(@$args) == 2) {
|
|
push @$out, [ "error", "This command takes exactly 1 argument. Consult the reference." ];
|
|
return 0;
|
|
}
|
|
|
|
unless ($remote->{'priv'}->{'finduser'}) {
|
|
push @$out, [ "error", "$remote->{'user'}, you are not authorized to use this command." ];
|
|
return 0;
|
|
}
|
|
|
|
my $user = $args->[1];
|
|
my $u = LJ::load_user($user);
|
|
|
|
unless ($u) {
|
|
push @$out, [ "error", "Invalid user \"$user\"" ];
|
|
return 0;
|
|
}
|
|
|
|
# journaltype eq 'P' means we're calling get_maintainer on a
|
|
# plain user and we should get a list of what they maintain instead of
|
|
# getting a list of what maintains them
|
|
my $ids = $u->{journaltype} eq 'P' ?
|
|
LJ::load_rel_target($u->{userid}, $edge) :
|
|
LJ::load_rel_user($u->{userid}, $edge);
|
|
$ids ||= [];
|
|
|
|
# finduser loop
|
|
finduser($dbh, $remote, ['finduser', 'userid', $_], $out) foreach @$ids;
|
|
|
|
return 1;
|
|
}
|
|
|
|
sub get_moderator
|
|
{
|
|
# simple pass through, but specify to use the 'M' edge
|
|
return get_maintainer(@_, 'M');
|
|
}
|
|
|
|
sub infohistory
|
|
{
|
|
my ($dbh, $remote, $args, $out) = @_;
|
|
|
|
unless ($remote->{'privarg'}->{'finduser'}->{'infohistory'}) {
|
|
push @$out, [ "error", "$remote->{'user'}, you are not authorized to use this command." ];
|
|
return 0;
|
|
}
|
|
|
|
my $user = $args->[1];
|
|
my $userid = LJ::get_userid($user);
|
|
|
|
unless ($userid) {
|
|
push @$out, [ "error", "Invalid user $user" ];
|
|
return 0;
|
|
}
|
|
|
|
my $sth = $dbh->prepare("SELECT * FROM infohistory WHERE userid='$userid'");
|
|
$sth->execute;
|
|
if (! $sth->rows) {
|
|
push @$out, [ "error", "No matches." ];
|
|
} else {
|
|
push @$out, ["info", "Infohistory of user: $user"];
|
|
while (my $info = $sth->fetchrow_hashref) {
|
|
$info->{'oldvalue'} ||= '(none)';
|
|
push @$out, [ "info",
|
|
"Changed $info->{'what'} at $info->{'timechange'}.\n".
|
|
"Old value of $info->{'what'} was $info->{'oldvalue'}.".
|
|
($info->{'other'} ?
|
|
"\nOther information recorded: $info->{'other'}" : "") ];
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
1;
|
|
|