#!/usr/bin/perl # # # lib: cgi-bin/ljlib.pl # use strict; use Getopt::Long; require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl"; sub usage { die "Usage: [--swap --force] \n"; } my %args = ( swap => 0, force => 0 ); usage() unless GetOptions('swap' => \$args{swap}, 'force' => \$args{force}, ); my $error; my $from = shift @ARGV; my $to = shift @ARGV; usage() unless $from =~ /^\w{1,15}$/ && $to =~ /^\w{1,15}$/; my $dbh = LJ::get_db_writer(); unless ($args{swap}) { if (rename_user($from, $to)) { print "Success. Renamed $from -> $to.\n"; } else { print "Failed: $error\n"; } exit; } ### check that emails/passwords match, and that at least one is verified my $qfrom = $dbh->quote(lc($from)); my $qto = $dbh->quote(lc($to)); unless ($args{force}) { my $sth = $dbh->prepare("SELECT user, email, password, status FROM user WHERE user IN ($qfrom, $qto)"); $sth->execute; { my @acct; while (my $l = $sth->fetchrow_hashref) { push @acct, $l; } unless (@acct == 2) { print "Both accounts aren't valid.\n"; exit 1; } unless (lc($acct[0]->{'email'}) eq lc($acct[1]->{'email'})) { print "Email addresses don't match.\n"; print " $acct[0]->{'email'}\n"; print " $acct[1]->{'email'}\n"; exit 1; } unless ($acct[0]->{'password'} eq $acct[1]->{'password'}) { print "Passwords don't match.\n"; exit 1; } unless ($acct[0]->{'status'} eq "A" || $acct[1]->{'status'} eq "A") { print "At least one account isn't verified.\n"; exit 1; } } } my $swapnum = 0; print "Swapping 1/3...\n"; until ($swapnum == 10 || rename_user($from, "lj_swap_$swapnum")) { $swapnum++; } if ($swapnum == 10) { print "Couldn't find a swap position?\n"; exit 1; } print "Swapping 2/3...\n"; unless (rename_user($to, $from)) { print "Swap failed in the middle, from $to -> $from failed.\n"; exit 1; } print "Swapping 3/3...\n"; unless (rename_user("lj_swap_$swapnum", $to)) { print "Swap failed in the middle, from lj_swap_$swapnum -> $to failed.\n"; exit 1; } # check for circular 'renamedto' references { # if the fromuser had redirection on, make sure it points to the new $to user my $fromu = LJ::load_user($from, 'force'); LJ::load_user_props($fromu, 'renamedto'); if ($fromu->{renamedto} && $fromu->{renamedto} ne $to) { print "Setting redirection: $from => $to\n"; unless (LJ::set_userprop($fromu, 'renamedto' => $to)) { print "Error setting 'renamedto' userprop for $from\n"; exit 1; } } # if the $to user had redirection, they shouldn't anymore my $tou = LJ::load_user($to, 'force'); LJ::load_user_props($tou, 'renamedto'); if ($tou->{renamedto}) { print "Removing redirection for user: $to\n"; unless (LJ::set_userprop($tou, 'renamedto' => undef)) { print "Error setting 'renamedto' userprop for $to\n"; exit 1; } } } print "Swapped.\n"; exit 0; sub rename_user { my $from = shift; my $to = shift; my $qfrom = $dbh->quote(LJ::canonical_username($from)); my $qto = $dbh->quote(LJ::canonical_username($to)); print "Renaming $from -> $to\n"; my $u = LJ::load_user($from, 'force'); unless ($u) { $error = "Invalid source user: $from"; return 0; } foreach my $table (qw(user useridmap overrides style)) { $dbh->do("UPDATE $table SET user=$qto WHERE user=$qfrom"); if ($dbh->err) { $error = $dbh->errstr; return 0; } } # from user is now invalidated LJ::memcache_kill($u->{userid}, "userid"); LJ::MemCache::delete("uidof:$from"); LJ::MemCache::delete("uidof:$to"); LJ::procnotify_add("rename_user", { 'user' => $u->{'user'}, 'userid' => $u->{'userid'} }); $dbh->do("INSERT INTO renames (renid, token, payid, userid, fromuser, touser, rendate) ". "VALUES (NULL,'[manual]',0,$u->{userid},$qfrom,$qto,NOW())"); return 1; }