#!/usr/bin/perl # # 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. use strict; use Getopt::Long; BEGIN { 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,25}$/ && $to =~ /^\w{1,25}$/; my $dbh = LJ::get_db_writer() or die "Could not get DB handle"; 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 unless ( $args{force} ) { my @acct = grep { $_ } LJ::DB::no_cache( sub { return ( LJ::load_user($from), LJ::load_user($to) ); } ); unless ( @acct == 2 ) { print "Both accounts aren't valid.\n"; exit 1; } unless ( $acct[0]->has_same_email_as( $acct[1] ) ) { print "Email addresses don't match.\n"; print " " . $acct[0]->email_raw . "\n"; print " " . $acct[1]->email_raw . "\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' ); my $fromu_r = $fromu ? $fromu->prop('renamedto') : undef; if ( $fromu_r && $fromu_r ne $to ) { print "Setting redirection: $from => $to\n"; unless ( $fromu->set_prop( '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' ); if ( $tou && $tou->prop('renamedto') ) { print "Removing redirection for user: $to\n"; unless ( $tou->set_prop( '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; } if ( LJ::load_user( $to, 'force' ) ) { $error = "User already exists: $to"; return 0; } foreach my $table (qw(user useridmap)) { $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"); # ...existing code... $dbh->do( "INSERT INTO renames (renid, auth, cartid, renuserid, fromuser, touser, rendate) " . "VALUES ( NULL, '[manual]', 0, ?, $qfrom, $qto, ? )", undef, $u->userid, time ); return 1; }