fu: Close-up of Fu, bringing a scoop of water to her mouth (Default)
fu ([personal profile] fu) wrote in [site community profile] changelog2010-11-03 02:55 am

[dw-free] Implement two-token swap of two usernames

[commit: http://hg.dwscoalition.org/dw-free/rev/c0efdc40d201]

http://bugs.dwscoalition.org/show_bug.cgi?id=2317

Two token swap of usernames; new page linked to from /rename, changes to
community renames so that you can only rename a community (or rename to a
community, because it then gets renamed to ex_*), when you are the only
community member. This is to avoid surprises.

Patch by [personal profile] fu.

Files modified:
  • bin/upgrading/en.dat
  • cgi-bin/DW/Controller/Rename.pm
  • cgi-bin/DW/User/Rename.pm
  • t/rename.t
  • views/rename.tt
  • views/rename/swap.tt
  • views/rename/swap.tt.text
--------------------------------------------------------------------------------
diff -r 485f2b7ff657 -r c0efdc40d201 bin/upgrading/en.dat
--- a/bin/upgrading/en.dat	Tue Nov 02 18:49:58 2010 +0800
+++ b/bin/upgrading/en.dat	Wed Nov 03 10:55:19 2010 +0800
@@ -2485,11 +2485,15 @@ rename.error.reserved="[[to]]" is a rese
 
 rename.error.unauthorized=[[to]] is not under your control.
 
+rename.error.unauthorized.forcomm=The community [[comm]] must have no members, and must be under your control.
+
 rename.error.unknown=Cannot rename to "[[to]]".
 
 rename.error.tokenapplied=This token has already been used.
 
 rename.error.tokeninvalid=The provided token is not a valid token.
+
+rename.error.tokentoofew=Too few tokens; you need two to perform a swap.
 
 rename.ex.toomanytries=We had some trouble trying to move aside the account you are trying to rename to ([[tousername]]). Please try again.
 
diff -r 485f2b7ff657 -r c0efdc40d201 cgi-bin/DW/Controller/Rename.pm
--- a/cgi-bin/DW/Controller/Rename.pm	Tue Nov 02 18:49:58 2010 +0800
+++ b/cgi-bin/DW/Controller/Rename.pm	Wed Nov 03 10:55:19 2010 +0800
@@ -25,6 +25,8 @@ use DW::Controller::Admin;
 
 use DW::RenameToken;
 use DW::Shop;
+
+DW::Routing->register_string( "/rename/swap", \&swap_handler, app => 1 );
 
 # be lax in accepting what goes in the URL in case of typos or mis-copy/paste
 # we validate the token inside and return an appropriate message (instead of 404)
@@ -174,6 +176,74 @@ sub handle_post {
     return ( 0, $errref );
 }
 
+
+sub swap_handler {
+    my $r = DW::Request->get;
+
+    my ( $ok, $rv ) = controller( authas => 1 );
+    return $rv unless $ok;
+
+    my $remote = $rv->{remote};
+    return error_ml( 'rename.error.invalidaccounttype' ) unless $remote->is_personal;
+
+    my $vars = {};
+
+    my $post_args = DW::Request->get->post_args || {};
+
+    my @unused_tokens = @{DW::RenameToken->by_owner_unused( userid => $remote->userid ) || []};
+    $vars->{numtokens} = scalar @unused_tokens;
+
+    if ( $r->method eq "POST" ) {
+        # this is kind of ugly. Basically, it's a rendered template if it's a success, and a list of errors if it failed
+        my ( $post_ok, $rv ) = handle_swap_post( $post_args, tokens => \@unused_tokens, user => $remote );
+        return $rv if $post_ok;
+
+        $vars->{error_list} = $rv;
+    }
+
+    my $authas =  LJ::make_authas_select( $remote,
+        {   selectonly => 1,
+            authas => $post_args->{authas},
+        } );
+
+    $vars->{form} = {
+        authas => $authas,
+    };
+
+    return DW::Template->render_template( 'rename/swap.tt', $vars );
+}
+
+sub handle_swap_post {
+    my ( $post_args, %opts ) = @_;
+
+    my @errors = ();
+    push @errors, LJ::Lang::ml( '/rename.tt.error.invalidform' ) unless LJ::check_form_auth( $post_args->{lj_form_auth} );
+
+    my $journal = LJ::get_authas_user( $post_args->{authas} );
+    push @errors, LJ::Lang::ml( '/rename/swap.tt.error.nojournal' ) unless $journal;
+
+    my $swapjournal = LJ::load_user( $post_args->{swapjournal} );
+    push @errors, LJ::Lang::ml( '/rename/swap.tt.error.invalidswapjournal' ) unless $swapjournal;
+
+    return ( 0, \@errors ) if @errors;
+
+
+    ( $journal, $swapjournal ) = ( $swapjournal, $journal )
+        if $journal->is_community && $swapjournal->is_personal;
+
+    # let's do this
+    my $errref = [];
+    $journal->swap_usernames( $swapjournal, user => $opts{user}, tokens => $opts{tokens}, errref => $errref );
+
+    return ( 1, success_ml( "/rename/swap.tt.success", {
+            journal => $journal->ljuser_display,
+            swapjournal => $swapjournal->ljuser_display,
+    } ) ) unless @$errref;
+
+    # return the list of errors, because we want to print out other things as well...
+    return ( 0, $errref );
+}
+
 sub rename_admin_handler {
     my ( $ok, $rv ) = controller( privcheck => [ "siteadmin:rename" ] );
     return $rv unless $ok;
diff -r 485f2b7ff657 -r c0efdc40d201 cgi-bin/DW/User/Rename.pm
--- a/cgi-bin/DW/User/Rename.pm	Tue Nov 02 18:49:58 2010 +0800
+++ b/cgi-bin/DW/User/Rename.pm	Wed Nov 03 10:55:19 2010 +0800
@@ -114,8 +114,8 @@ sub can_rename_to {
         # expunged users can always be renamed to
         return { ret => 1 } if $tou->is_expunged;
 
-        # communities cannot be renamed to
-        if ( ! $tou->is_personal ) {
+        # only personal journals and communities can be renamed
+        if ( ! ( $tou->is_personal || $tou->is_community ) ) {
             push @$errref, LJ::Lang::ml( 'rename.error.invalidjournaltypeto' );
             return { ret => 0 };
         }
@@ -135,13 +135,20 @@ sub can_rename_to {
         # person-to-person
         return 1 if DW::User::Rename::_are_same_person( $self, $tou );
 
+        # person-to-community (only under restricted circumstances for the community)
+        return 1 if DW::User::Rename::_is_authorized_for_comm( $self, $tou );
+
         push @$errref, LJ::Lang::ml( 'rename.error.unauthorized', { to => $tou->ljuser_display } );
         return 0;
     } elsif ( $self->is_community && LJ::isu( $opts{user} ) ) {
         my $admin = $opts{user};
 
-        # user must be able to control (be an admin of) community
-        return 0 unless $admin->can_manage_other( $self );
+        # make sure that the community journal is under the admin's control
+        # and satisfies all other conditions that ensure we don't leave members hanging
+        unless ( DW::User::Rename::_is_authorized_for_comm( $admin, $self ) ) {
+            push @$errref, LJ::Lang::ml( 'rename.error.unauthorized.forcomm', { comm => $self->ljuser_display } );
+            return 0;
+        }
 
         my $tou = LJ::load_user( $tousername );
 
@@ -151,7 +158,12 @@ sub can_rename_to {
 
         # community-to-person
         # able to rename to another personal journal under admin's control
-        return 1 if DW::User::Rename::_are_same_person( $admin, $tou );
+        return 1 if $tou->is_person && DW::User::Rename::_are_same_person( $admin, $tou );
+
+        # community-to-community
+        # we checked early on that the admin is authorized to rename this community
+        # so we don't need to check again here
+        return 1 if $tou->is_community;
     }
 
     # be strict in what we accept
@@ -198,12 +210,55 @@ sub rename {
 
 =head2 C<< $self->swap_usernames( $touser [, %opts ] ) >>
 
-Swap the usernames of these two users. Currently unimplemented.
+Swap the usernames of these two users.
 
 =cut
 
 sub swap_usernames {
-    my ( $self, $touser, %opts ) = @_;
+    my ( $u1, $u2, %opts ) = @_;
+
+    my $errref = $opts{errref} || [];
+
+    my $admin = LJ::isu( $opts{user} ) ? $opts{user} : $u1;
+    my @tokens = @{ $opts{tokens} || [] };
+
+    foreach my $token ( @tokens ) {
+        push @$errref, LJ::Lang::ml( 'rename.error.tokeninvalid' )
+            unless $token && $token->isa( "DW::RenameToken" )
+                && $token->ownerid == $admin->userid;
+
+        push @$errref, LJ::Lang::ml( 'rename.error.tokenapplied' )
+            if $token->applied;
+    }
+
+    if ( scalar @tokens >= 2 ) {
+        push @$errref, LJ::Lang::ml( 'rename.error.tokeninvalid' )
+            if ( $tokens[0]->token eq $tokens[1]->token );
+    } else {
+        push @$errref, LJ::Lang::ml( 'rename.error.tokentoofew' );
+    }
+
+    my %admin_opts = $u2->is_community ? ( user => $admin ) : ();
+
+    my $can_rename = $u1->can_rename_to( $u2->username, %opts, %admin_opts )
+        && $u2->can_rename_to( $u1->username, %opts, %admin_opts );
+    return 0 if @$errref || ! $can_rename;
+
+    my $u1name = $u1->user;
+    my $u2name = $u2->user;
+
+    my $did_rename = 1;
+    $did_rename &&= DW::User::Rename::_rename_to_ex( $u2, errref => $opts{errref} );
+    return 0 unless $did_rename;
+
+    # ugh, but need it to avoid duplicate timestamps in infohistory
+    sleep( 1 );
+
+    $did_rename &&= DW::User::Rename::_rename( $u1, $u2name, %opts, %admin_opts, token => $tokens[0] );
+    return 0 unless $did_rename;
+
+    $did_rename &&= DW::User::Rename::_rename( $u2, $u1name, %opts, %admin_opts, token => $tokens[1] );
+    return $did_rename;
 }
 
 =head2 C<< $self->_clear_from_cache >>
@@ -242,6 +297,26 @@ sub _are_same_person {
     return 0 unless lc( $p1->email_raw ) eq lc( $p2->email_raw );
     return 0 unless $p1->password eq $p2->password;
     return 0 unless $p1->is_validated || $p2->is_validated;
+
+    return 1;
+}
+
+=head2 C<< $self->_is_authorized_for_comm >>
+
+Internal function to determine whether an account can control / manage another account
+
+=cut
+
+sub _is_authorized_for_comm {
+    my ( $admin, $journal ) = @_;
+
+    return 0 unless $admin->is_person && $journal->is_community;
+    return 0 unless $admin->can_manage_other( $journal );
+
+    # community must have no users, to avoid confusion
+    my @member_userids = $journal->member_userids;
+    return 0 if scalar @member_userids > 1;
+    return 0 if scalar @member_userids == 1 && $member_userids[0] != $admin->userid;
 
     return 1;
 }
diff -r 485f2b7ff657 -r c0efdc40d201 t/rename.t
--- a/t/rename.t	Tue Nov 02 18:49:58 2010 +0800
+++ b/t/rename.t	Wed Nov 03 10:55:19 2010 +0800
@@ -3,7 +3,7 @@ use warnings;
 use warnings;
 
 use Test::More;
-plan tests => 137;
+plan tests => 152;
 
 use lib "$ENV{LJHOME}/cgi-bin";
 require 'ljlib.pl';
@@ -385,6 +385,7 @@ note( "-- community-to-unregistered" );
 {
     my $admin = temp_user();
     my $fromu = temp_comm();
+    my $oldusername = $fromu->username;
     my $tousername = $fromu->username . "_renameto";
 
     ok( ! $admin->can_manage( $fromu ), "User cannot manage community fromu." );
@@ -405,36 +406,13 @@ note( "-- community-to-unregistered" );
     ok( ! $admin->is_validated && ! $fromu->can_rename_to( $tousername . "_rename", user => $admin ), "Admin no longer validated; can no longer rename" );
 
     ok( ! $fromu->can_rename_to( $tousername ), "Cannot rename community without providing a user doing the renaming" );
-}
 
-note( "-- community-to-community" );
-TODO: {
-    local $TODO = "community to community";
-    my $admin = temp_user();
-    my $fromu = temp_comm();
-    my $tou = temp_comm();
-    my $tousername = $tou->user;
+    my $member = temp_user();
+    $member->join_community( $fromu );
+    ok( ! $fromu->can_rename_to( $oldusername, user => $admin ), "Cannot rename a community with members" );
 
-    ok( ! $admin->can_manage( $fromu ), "User cannot manage community fromu" );
-    ok( ! $admin->can_manage( $tou ), "User cannot manage community tou" );
-    ok( ! $fromu->can_rename_to( $tousername, user => $admin ), $admin->user . " cannot rename community fromu to existing community $tousername (because: not admin)" );
-
-    # make admin of fromu
-    LJ::set_rel( $fromu, $admin, "A" );
-    delete $LJ::REQ_CACHE_REL{$fromu->userid."-".$admin->userid."-A"};
-    ok( $admin->can_manage( $fromu ), "User can manage community fromu" );
-    ok( ! $admin->can_manage( $tou ), "User cannot manage community tou" );
-
-    ok( ! $fromu->can_rename_to( $tousername, user => $admin ), $admin->user . " cannot rename community fromu to existing community $tousername (because: not admin of tou)" );
-
-    # make admin of tou
-    LJ::set_rel( $tou, $admin, "A" );
-    delete $LJ::REQ_CACHE_REL{$tou->userid."-".$admin->userid."-A"};
-    ok( $admin->can_manage( $fromu ), "User can manage community fromu" );
-    ok( $admin->can_manage( $tou ), "User can manage community tou" );
-
-    ok( $fromu->can_rename_to( $tousername, user => $admin ), $admin->user . " can rename community fromu to existing community $tousername (is admin of both)" );
-    ok( $fromu->rename( $tousername, token => new_token( $admin ), user => $admin ), $admin->user . " renamed community fromu to existing community $tousername" );
+    $member->leave_community( $fromu );
+    ok( $fromu->can_rename_to( $oldusername, user => $admin ), "Can rename community again, no members." );
 }
 
 note( "-- community-to-personal" );
@@ -460,9 +438,10 @@ note( "-- community-to-personal" );
 }
 
 note( "-- personal-to-community" );
-TODO: {
-    local $TODO = "personal to community";
+{
     my $fromu = temp_user();
+    LJ::update_user( $fromu, { status => 'A' } );
+
     my $tou = temp_comm();
     my $tousername = $tou->user;
 
@@ -470,23 +449,15 @@ TODO: {
     LJ::set_rel( $tou, $fromu, "A" );
     delete $LJ::REQ_CACHE_REL{$tou->userid."-".$fromu->userid."-A"};
 
-    ok( $fromu->can_rename_to( $tousername ), "Can rename to a community under your own control." );
-    ok( $fromu->rename( $tousername, token => new_token( $fromu ) ), "Renamed personal journal fromu to existing community $tousername" );
-}
+    my $member = temp_user();
+    $member->join_community( $tou );
+    ok( ! $fromu->can_rename_to( $tousername, user => $fromu, verbose => 1 ), "Cannot rename a community with members" );
 
-TODO: {
-    local $TODO = "community with multiple admins";
-    my $admin1 = temp_user();
-    my $admin2 = temp_user();
-    my $tou = temp_comm();
-    my $tousername = $tou->user;
-
-    # make admins of tou
-    LJ::set_rel_multi( [ $tou, $admin1, "A" ], [ $tou, $admin2, "A"] );
-    delete $LJ::REQ_CACHE_REL{$tou->userid."-".$admin1->userid."-A"};
-    delete $LJ::REQ_CACHE_REL{$tou->userid."-".$admin2->userid."-A"};
-
-    ok( ! $admin1->can_rename_to( $tousername ), "Cannot rename to a community under your own control if there are multiple admins." );
+    $member->leave_community( $tou );
+    ok( $fromu->can_rename_to( $tousername ),
+        "Can rename to a community under your own control if it has no members.");
+    ok( $fromu->rename( $tousername, token => new_token( $fromu ) ),
+        "Renamed personal journal fromu to existing community." );
 }
 
 note( "-- openid and feeds" );
@@ -500,7 +471,165 @@ note( "-- openid and feeds" );
     ok( ! $u->can_rename_to( $u->user . "_rename" ), "Cannot rename feed accounts" );
 }
 
-TODO: {
-    local $TODO = "two username swap";
+note( "-- two username swap (personal to personal)" );
+{
+    my ( $u1, $u2 ) = $create_users->( match => 1, validated => 1 );
+
+    my $u1id = $u1->userid;
+    my $u2id = $u2->userid;
+    my $u1sername = $u1->user;
+    my $u2sername = $u2->user;
+
+    ok( $u1sername ne $u2sername, "Not the same username" );
+
+    my $token = new_token( $u1 );
+    ok( ! $u1->swap_usernames(
+        $u2,
+        tokens => [ $token, $token ]
+     ), "Can't swap, token is the same" );
+
+
+    ok( $u1->swap_usernames(
+        $u2,
+        tokens => [ new_token( $u1 ), new_token( $u1 ) ]
+     ), "Swap usernames" );
+
+    $u1 = LJ::load_userid( $u1->userid );
+    $u2 = LJ::load_userid( $u2->userid );
+
+    is( $u1->user, $u2sername, "Swap usernames of u1 and u2" );
+    is( $u2->user, $u1sername, "Swap usernames of u2 and u1" );
+
+    is( $u1->userid, $u1id, "Id of u1 remains the same after rename." );
+    is( $u2->userid, $u2id, "Id of u2 remains the same after rename." );    
 }
 
+note( "-- two username swap (one user is suspended)" );
+{
+    my ( $u1, $u2 ) = $create_users->( match => 1, validated => 1 );
+    $u2->set_statusvis( "S" );
+
+    my $u1id = $u1->userid;
+    my $u2id = $u2->userid;
+    my $u1sername = $u1->user;
+    my $u2sername = $u2->user;
+
+    ok( $u1sername ne $u2sername, "Not the same username" );
+
+    ok( ! $u1->swap_usernames(
+        $u2,
+        tokens => [ new_token( $u1 ), new_token( $u1 ) ]
+     ), "Cannot swap usernames." );
+
+    $u1 = LJ::load_userid( $u1->userid );
+    $u2 = LJ::load_userid( $u2->userid );
+
+    is( $u1->user, $u1sername, "No swap" );
+    is( $u2->user, $u2sername, "No swap" );
+}
+
+note( "-- two username swap personal <=> community " );
+{
+    my $u = temp_user();
+    LJ::update_user( $u, { status => 'A' } );
+
+    my $comm = temp_comm();
+    my $uname = $u->user;
+    my $commname = $comm->user;
+
+    ok( ! $u->swap_usernames(
+        $comm,
+        tokens => [ new_token( $u ), new_token( $u ) ]
+     ), "Cannot swap personal and community usernames (not an admin)" );
+
+    # make admin of u
+    LJ::set_rel( $comm, $u, "A" );
+    delete $LJ::REQ_CACHE_REL{$comm->userid."-".$u->userid."-A"};
+
+    ok( $u->swap_usernames(
+        $comm,
+        tokens => [ new_token( $u ), new_token( $u ) ],
+     ), "Swap personal and community usernames" );
+
+    is( $u->user, $commname, "Swap usernames u => comm" );
+    is( $comm->user, $uname, "Swap usernames comm => u" );
+}
+
+note( "-- two username swap personal <=> community (with malice)" );
+{
+    my ( $u, $u2 ) = $create_users->( validate => 1 );
+
+    my $comm = temp_comm();
+    my $uname = $u->user;
+    my $commname = $comm->user;
+
+    # make admin of u
+    LJ::set_rel( $comm, $u, "A" );
+    delete $LJ::REQ_CACHE_REL{$comm->userid."-".$u->userid."-A"};
+
+    LJ::set_rel( $comm, $u2, "A" );
+    delete $LJ::REQ_CACHE_REL{$comm->userid."-".$u2->userid."-A"};
+
+    ok( ! $u->swap_usernames(
+        $u2,
+        tokens => [ new_token( $u ), new_token( $u ) ],
+     ), "Swap usernames with someone not under your control" );
+
+    ok ( ! $comm->swap_usernames(
+        $u2,
+        user => $u,
+        tokens => [ new_token( $u ), new_token( $u )],
+    ), "Swapping the username of a co-admin");
+}
+
+note( "-- two username swap community <=> personal" );
+{
+    my $u = temp_user();
+    LJ::update_user( $u, { status => 'A' } );
+
+    my $comm = temp_comm();
+    my $uname = $u->user;
+    my $commname = $comm->user;
+
+    ok( ! $comm->swap_usernames(
+        $u,
+        tokens => [ new_token( $u ), new_token( $u ) ]
+     ), "Cannot swap personal and community usernames (not an admin)" );
+
+    # make admin of u
+    LJ::set_rel( $comm, $u, "A" );
+    delete $LJ::REQ_CACHE_REL{$comm->userid."-".$u->userid."-A"};
+
+    ok( ! $comm->swap_usernames(
+        $u,
+        tokens => [ new_token( $u ), new_token( $u ) ]
+     ), "Cannot swap community and personal when acting on the community" );
+}
+
+note( "-- two username swap (community and community)" );
+{
+    my $admin = temp_user();
+    LJ::update_user( $admin, { status => 'A' } );
+
+    my $c1 = temp_comm();
+    my $c2 = temp_comm();
+
+    LJ::set_rel( $c1, $admin, "A" );
+    delete $LJ::REQ_CACHE_REL{$c1->userid."-".$admin->userid."-A"};
+    LJ::set_rel( $c2, $admin, "A" );
+    delete $LJ::REQ_CACHE_REL{$c2->userid."-".$admin->userid."-A"};
+
+    my $c1sername = $c1->user;
+    my $c2sername = $c2->user;
+
+    ok( $c1sername ne $c2sername, "Not the same username" );
+
+    ok( $c1->swap_usernames(
+        $c2,
+        user => $admin,
+        tokens => [ new_token( $admin ), new_token( $admin ) ],
+     ), "Swap community usernames" );
+
+    is( $c1->user, $c2sername, "Swap usernames of c1 and c2" );
+    is( $c2->user, $c1sername, "Swap usernames of c2 and c1" );
+}
diff -r 485f2b7ff657 -r c0efdc40d201 views/rename.tt
--- a/views/rename.tt	Tue Nov 02 18:49:58 2010 +0800
+++ b/views/rename.tt	Wed Nov 03 10:55:19 2010 +0800
@@ -104,6 +104,11 @@ the same terms as Perl itself.  For a co
             <label for="username_for_rename">[% '.checkusername.label' | ml %]: <input id="username_for_rename" name="checkuser" value="[% checkusername.user | html %]" />
             <input type="submit" value="[% '.checkusername.submit' | ml %]" />
         </form>
+
+        <hr />
+
+        <a href="[%dw.site|url%]/rename/swap">Swap usernames with a journal under your control</a>
+        <p class='note'>You will require two tokens</p>
     [% END %]
 
     <hr />
diff -r 485f2b7ff657 -r c0efdc40d201 views/rename/swap.tt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/views/rename/swap.tt	Wed Nov 03 10:55:19 2010 +0800
@@ -0,0 +1,45 @@
+[%# rename/swap.tt
+
+Page where you can swap the usernames of two journals under your control.
+
+Authors:
+    Afuna <coder.dw@afunamatata.com>
+
+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'.
+%]
+
+[%- dw.need_res( 'stc/rename.css' ) -%]
+
+[%- sections.title = '.title' | ml -%]
+
+[% IF error_list %]
+    <p>[% '.error.header' | ml %]</p>
+    <ul class='error-list'>
+        [% FOREACH error = error_list %]
+            <li>[% error %] </li>
+        [% END %]
+    </ul>
+[% END %]
+
+<p>[% '.intro' | ml %]</p>
+[% IF numtokens >= 2 %]
+    <form id="renameform" method="POST">
+        [% dw.form_auth %]
+        <div class='formfield'>
+            <label for='authas'>[% '.form.journal' | ml %]</label>
+            [% form.authas %]
+        </div>
+        <div class='formfield'>
+            <label for='swapjournal'>[% '.form.swapjournal' | ml %]</label>
+            <input type='text' name='swapjournal' id='swapjournal' />
+        </div>
+
+        <input type='submit' value='Swap' />
+    </form>
+[% ELSE %]
+    [%- '.numtokens.toofew' | ml(aopts = "href='/shop/renames?for=self'") -%]
+[% END %]
+
+
diff -r 485f2b7ff657 -r c0efdc40d201 views/rename/swap.tt.text
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/views/rename/swap.tt.text	Wed Nov 03 10:55:19 2010 +0800
@@ -0,0 +1,17 @@
+.error.header=Unable to perform username swap. Please correct the following and try again:
+
+.error.invalidswapjournal=Invalid username was provided to swap with.
+
+.error.nojournal=No journal selected to swap usernames.
+
+.form.journal=Select Journal
+
+.form.swapjournal=Swap With
+
+.intro=You may swap the usernames of two personal journals, or of your journal and a community under your control. None of your settings will change. This will use two of your rename tokens.
+
+.numtokens.toofew=You do not have enough tokens to do a swap. You can <a [[aopts]]>purchase rename tokens</a> in the shop.
+
+.success=Successfully swapped [[journal]] and [[swapjournal]].
+
+.title=Swap Journal Usernames
--------------------------------------------------------------------------------