[dw-free] Implement renaming for communities
[commit: http://hg.dwscoalition.org/dw-free/rev/3467e0caff10]
http://bugs.dwscoalition.org/show_bug.cgi?id=2281
Community renames: communities may rename to personal journals under the
maintainer's control, or to unregistered usernames.
Patch by
fu.
Files modified:
http://bugs.dwscoalition.org/show_bug.cgi?id=2281
Community renames: communities may rename to personal journals under the
maintainer's control, or to unregistered usernames.
Patch by
![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Files modified:
- bin/upgrading/en.dat
- cgi-bin/DW/Controller/Rename.pm
- cgi-bin/DW/User/Rename.pm
- cgi-bin/weblib.pl
- htdocs/shop/renames.bml.text
- t/rename.t
- views/rename.tt
- views/rename.tt.text
-------------------------------------------------------------------------------- diff -r 4954905b7319 -r 3467e0caff10 bin/upgrading/en.dat --- a/bin/upgrading/en.dat Fri Aug 20 14:25:23 2010 +0800 +++ b/bin/upgrading/en.dat Fri Aug 20 18:22:13 2010 +0800 @@ -2433,6 +2433,8 @@ protocol.readonly=Your account is tempor rename.error.invalidaccounttype=Only personal journals can own rename tokens. +rename.error.invalidjournaltypeto=This username is in use and is not a personal journal; only personal journals may be renamed to. + rename.error.invalidfrom=Tried to rename an invalid journal. rename.error.invalidstatusfrom=Cannot rename [[from]]: must be an active journal, not deleted or suspended. diff -r 4954905b7319 -r 3467e0caff10 cgi-bin/DW/Controller/Rename.pm --- a/cgi-bin/DW/Controller/Rename.pm Fri Aug 20 14:25:23 2010 +0800 +++ b/cgi-bin/DW/Controller/Rename.pm Fri Aug 20 18:22:13 2010 +0800 @@ -47,6 +47,9 @@ sub rename_handler { my $post_args = DW::Request->get->post_args || {}; my $get_args = DW::Request->get->get_args || {}; + $get_args->{type} ||= "P"; + $get_args->{type} = "P" unless $get_args->{type} =~ m/^(P|C)$/; + 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 @@ -74,15 +77,31 @@ sub rename_handler { } else { $vars->{token} = $token; + # not using the regular authas logic because we want to exclude the current username + my $authas = LJ::make_authas_select( $remote, + { selectonly => 1, + type => $get_args->{type}, + authas => $post_args->{authas} || $get_args->{authas}, + } ); + + $authas .= $remote->user if $get_args->{type} eq "P"; + + my @rel_types = $get_args->{type} eq "P" + ? qw( trusted_by watched_by trusted watched communities ) + : (); + # initialize the form based on previous posts (in case of error) or with some default values $vars->{form} = { - from => $remote->user, - journalurl => $remote->journal_base, + authas => $authas, + journaltype => $get_args->{type}, + journalurl => $get_args->{type} eq "P" ? $remote->journal_base : LJ::journal_base( "communityname", "community" ), + pageurl => "/rename/" . $token->token, token => $token->token, to => $post_args->{touser} || $get_args->{to} || "", redirect => $post_args->{redirect} || "disconnect", + rel_types => \@rel_types, rel_options => %$post_args ? { map { $_ => 1 } $post_args->get( "rel_options" ) } - : { map { $_ => 1 } qw( trusted_by watched_by trusted watched communities ) }, + : { map { $_ => 1 } @rel_types }, others => %$post_args ? { map { $_ => 1 } $post_args->get( "others" ) } : { email => 0 }, }; @@ -102,13 +121,12 @@ sub handle_post { sub handle_post { my ( $token, $post_args ) = @_; - # FIXME: replace with official tt-implementation return ( 0, [ LJ::Lang::ml( '/rename.tt.error.invalidform' ) ] ) unless LJ::check_form_auth( $post_args->{lj_form_auth} ); my $errref = []; # the journal we are going to rename; yourself or (eventually) a community you maintain - my $journal = LJ::get_remote(); + my $journal = LJ::get_authas_user( $post_args->{authas} ); push @$errref, LJ::Lang::ml( '/rename.tt.error.nojournal' ) unless $journal; my $fromusername = $journal ? $journal->user : ""; @@ -136,7 +154,7 @@ sub handle_post { } # try the rename and see if there are any errors - $journal->rename( $tousername, token => $token, redirect => $redirect_journal, redirect_email => $other_opts{email}, %del_rel, errref => $errref ); + $journal->rename( $tousername, user => LJ::get_remote(), token => $token, redirect => $redirect_journal, redirect_email => $other_opts{email}, %del_rel, errref => $errref ); return ( 1, success_ml( "/rename.tt.success", { from => $fromusername, to => $journal->user } ) ) unless @$errref; diff -r 4954905b7319 -r 3467e0caff10 cgi-bin/DW/User/Rename.pm --- a/cgi-bin/DW/User/Rename.pm Fri Aug 20 14:25:23 2010 +0800 +++ b/cgi-bin/DW/User/Rename.pm Fri Aug 20 18:22:13 2010 +0800 @@ -99,22 +99,37 @@ sub can_rename_to { return 0; } - # only personal accounts can be renamed + my $check_basics = sub { + my ( $fromu, $tou ) = @_; + + # able to rename to unregistered accounts + return { ret => 1 } unless $tou; + + # some journals can not be renamed to + if ( $tou->is_suspended || $tou->is_readonly || $tou->is_locked || $tou->is_memorial || $tou->is_renamed ) { + push @$errref, LJ::Lang::ml( 'rename.error.invalidstatusto', { to => $tou->ljuser_display } ); + return { ret => 0 }; + } + + # expunged users can always be renamed to + return { ret => 1 } if $tou->is_expunged; + + # communities cannot be renamed to + if ( ! $tou->is_personal ) { + push @$errref, LJ::Lang::ml( 'rename.error.invalidjournaltypeto' ); + return { ret => 0 }; + } + }; + + # only personal and community accounts can be renamed if ( $self->is_personal ) { # able to rename to unregistered accounts my $tou = LJ::load_user( $tousername ); - return 1 unless $tou; - # some journals can not be renamed to - if ( $tou->is_suspended || $tou->is_readonly || $tou->is_locked || $tou->is_memorial || $tou->is_renamed ) { - push @$errref, LJ::Lang::ml( 'rename.error.invalidstatusto', { to => $self->ljuser_display } ); - return 0; - } - - # expunged users can always be renamed to - return 1 if $tou->is_expunged; - + # check basic stuff that is common for all types of renames + my $rv = $check_basics->( $self, $tou ); + return $rv->{ret} if $rv; # deleted and visible journals have extra safeguards: # person-to-person @@ -122,6 +137,21 @@ sub can_rename_to { 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 ); + + my $tou = LJ::load_user( $tousername ); + + # check basic stuff that is common for all renames + my $rv = $check_basics->( $self, $tou ); + return $rv->{ret} if $rv; + + # 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 ); } # be strict in what we accept @@ -147,8 +177,9 @@ sub rename { my $errref = $opts{errref} || []; + my $remote = LJ::isu( $opts{user} ) ? $opts{user} : $self; push @$errref, LJ::Lang::ml( 'rename.error.tokeninvalid' ) unless $opts{token} && $opts{token}->isa( "DW::RenameToken" ) - && $opts{token}->ownerid == $self->userid; + && $opts{token}->ownerid == $remote->userid; push @$errref, LJ::Lang::ml( 'rename.error.tokenapplied' ) if $opts{token} && $opts{token}->applied; my $can_rename_to = $self->can_rename_to( $tousername, %opts ); @@ -254,7 +285,16 @@ sub _rename { $self->break_redirects; DW::User::Rename->create_redirect_journal( $fromusername, $tousername ) if $opts{redirect}; - my $del = $self->delete_relationships( del_trusted_by => $opts{del_trusted_by}, del_watched_by => $opts{del_watched_by}, del_trusted => $opts{del_trusted}, del_watched => $opts{del_watched}, del_communities => $opts{del_communities} ); + + my $del = ""; + if ( $self->is_personal ) { + $del = $self->delete_relationships( + del_trusted_by => $opts{del_trusted_by}, + del_watched_by => $opts{del_watched_by}, + del_trusted => $opts{del_trusted}, + del_watched => $opts{del_watched}, + del_communities => $opts{del_communities} ); + } # this deletes the email under the old username DW::User::Rename->break_email_redirection( $fromusername, $tousername ) unless $opts{redirect} && $opts{redirect_email}; @@ -350,6 +390,8 @@ sub delete_relationships { sub delete_relationships { my ( $self, %opts ) = @_; + return unless $self->is_personal; + if ( $opts{del_trusted_by} ) { foreach ( $self->trusted_by_users ) { $_->remove_edge( $self, trust => {} ); diff -r 4954905b7319 -r 3467e0caff10 cgi-bin/weblib.pl --- a/cgi-bin/weblib.pl Fri Aug 20 14:25:23 2010 +0800 +++ b/cgi-bin/weblib.pl Fri Aug 20 18:22:13 2010 +0800 @@ -191,15 +191,20 @@ sub make_authas_select { # only do most of form if there are options to select from if (@list > 1 || $list[0] ne $u->{'user'}) { my $ret; - my $label = $BML::ML{'web.authas.label'}; - $label = $BML::ML{'web.authas.label.comm'} if ($opts->{'type'} eq "C"); - $ret = ($opts->{'label'} || $label) . " "; + unless ( $opts->{selectonly} ) { + my $label = $BML::ML{'web.authas.label'}; + $label = $BML::ML{'web.authas.label.comm'} if ($opts->{'type'} eq "C"); + $ret = ($opts->{'label'} || $label) . " "; + } + $ret .= LJ::html_select({ 'name' => 'authas', 'selected' => $opts->{'authas'} || $u->{'user'}, 'class' => 'hideable', }, map { $_, $_ } @list) . " "; - $ret .= LJ::html_submit(undef, $opts->{'button'} || $BML::ML{'web.authas.btn'}); + $ret .= LJ::html_submit(undef, $opts->{'button'} || $BML::ML{'web.authas.btn'}) + unless $opts->{selectonly}; + return $ret; } diff -r 4954905b7319 -r 3467e0caff10 htdocs/shop/renames.bml.text --- a/htdocs/shop/renames.bml.text Fri Aug 20 14:25:23 2010 +0800 +++ b/htdocs/shop/renames.bml.text Fri Aug 20 18:22:13 2010 +0800 @@ -12,9 +12,9 @@ .giftfor.username=Username to receive this rename token: -.intro.gift=Buy a rename token for someone else to allow them to change their journal's username. +.intro.gift=Buy a rename token for someone else to allow them to change their journal's username, or the username of a community they manage. -.intro.self=Buy a rename token for your journal to change your username. +.intro.self=Buy a rename token for your journal to change your username, or the username of a community you manage. .action=Once your payment has gone through, the token will be listed on <a [[aopts]]>the rename page</a>. diff -r 4954905b7319 -r 3467e0caff10 t/rename.t --- a/t/rename.t Fri Aug 20 14:25:23 2010 +0800 +++ b/t/rename.t Fri Aug 20 18:22:13 2010 +0800 @@ -299,8 +299,7 @@ note( "-- username issues" ); } note( "-- community-to-unregistered" ); -TODO: { - local $TODO = "community to unregistered"; +{ my $admin = temp_user(); my $fromu = temp_comm(); my $tousername = $fromu->username . "_renameto"; @@ -315,8 +314,9 @@ TODO: { ok( ! LJ::load_user( $tousername ), "Username '$tousername' is unregistered" ); ok( $fromu->can_rename_to( $tousername, user => $admin ), "Can rename to $tousername" ); - ok( $fromu->rename( $tousername, token => new_token( $fromu ), user => $admin ), "Renamed community to $tousername" ); + ok( $fromu->rename( $tousername, token => new_token( $admin ), user => $admin ), "Renamed community to $tousername" ); + LJ::update_user( $admin, { status => 'A' } ); ok( $admin->is_validated, "Admin was validated so could rename."); LJ::update_user( $admin, { status => 'N' } ); ok( ! $admin->is_validated && ! $fromu->can_rename_to( $tousername . "_rename", user => $admin ), "Admin no longer validated; can no longer rename" ); @@ -351,13 +351,12 @@ TODO: { 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( $fromu ), user => $admin ), $admin->user . " renamed community fromu to existing community $tousername" ); + ok( $fromu->rename( $tousername, token => new_token( $admin ), user => $admin ), $admin->user . " renamed community fromu to existing community $tousername" ); } note( "-- community-to-personal" ); -TODO: { - local $TODO = "community to personal"; - my ( $admin, $tou ) = $create_users->(); +{ + my ( $admin, $tou ) = $create_users->( validated => 1 ); my $fromu = temp_comm(); my $tousername = $tou->user; @@ -367,14 +366,14 @@ TODO: { ok( ! $fromu->can_rename_to( $tousername, user => $admin ), "Cannot rename fromu to existing user $tousername (tou is a personal journal not under admin's control)" ); - ( $admin, $tou ) = $create_users->( match => 1 ); + ( $admin, $tou ) = $create_users->( match => 1, validated => 1 ); $tousername = $tou->user; # make admin of fromu LJ::set_rel( $fromu, $admin, "A" ); delete $LJ::REQ_CACHE_REL{$fromu->userid."-".$admin->userid."-A"}; ok( $fromu->can_rename_to( $tousername, user => $admin ), $admin->user . " can rename community fromu to existing user $tousername (tou is a personal journal under admin's control)" ); - ok( $fromu->rename( $tousername, token => new_token( $fromu ), user => $admin ), $admin->user . " renamed community fromu to existing community $tousername" ); + ok( $fromu->rename( $tousername, token => new_token( $admin ), user => $admin ), $admin->user . " renamed community fromu to existing community $tousername" ); } note( "-- personal-to-community" ); diff -r 4954905b7319 -r 3467e0caff10 views/rename.tt --- a/views/rename.tt Fri Aug 20 14:25:23 2010 +0800 +++ b/views/rename.tt Fri Aug 20 18:22:13 2010 +0800 @@ -34,31 +34,38 @@ the same terms as Perl itself. For a co <label for="token">[%- '.form.rename.token.label' | ml -%]</label> [%- form.token | html -%] </div> <div class="formfield"> - <label>[%- '.form.rename.fromuser.label' | ml -%]</label> [% form.from | html %] + <label>[%- '.form.rename.fromuser.label' | ml -%]</label> [% form.authas %] + [% IF form.journaltype == "P" %] + <a href="[%- form.pageurl | url -%]?type=C">[%- '.form.switchtype.comm' | ml -%]</a> + [% ELSE %] + <a href="[%- form.pageurl | url -%]">[%- '.form.switchtype.journal' | ml -%]</a> + [% END %] </div> <div class="formfield"> <label for="touser">[%- '.form.rename.touser.label' | ml -%]</label><input type="text" id="touser" name="touser" value="[%- form.to | html -%]" /> </div> <div class="formfield"> <fieldset> - <legend>What do you want to do with your old username?</legend> - <input type="radio" name="redirect" value="forward" id="redirect_forward" [% 'checked="checked"' IF form.redirect == "forward" %]/><label for="redirect_forward">[%- '.form.rename.forward.label' | ml %]</label> - <p class='detail'>[%- '.form.rename.forward.note' | ml( journalurl = form.journalurl ) %]</p> - <input type="radio" name="redirect" value="disconnect" id="redirect_disconnect" [% 'checked="checked"' IF form.redirect == 'disconnect' %]/><label for="redirect_disconnect">[%- '.form.rename.disconnect.label' | ml %]</label> - <p class='detail'>[%- '.form.rename.disconnect.note' | ml( journalurl = form.journalurl ) %]</p> + <legend>[%- '.form.rename.oldusername.header.' _ form.journaltype | ml -%]</legend> + <input type="radio" name="redirect" value="forward" id="redirect_forward" [% 'checked="checked"' IF form.redirect == "forward" %]/><label for="redirect_forward">[%- '.form.rename.forward.label.' _ form.journaltype | ml %]</label> + <p class='detail'>[%- '.form.rename.forward.note.' _ form.journaltype | ml( journalurl = form.journalurl ) %]</p> + <input type="radio" name="redirect" value="disconnect" id="redirect_disconnect" [% 'checked="checked"' IF form.redirect == 'disconnect' %]/><label for="redirect_disconnect">[%- '.form.rename.disconnect.label.' _ form.journaltype | ml %]</label> + <p class='detail'>[%- '.form.rename.disconnect.note.' _ form.journaltype | ml( journalurl = form.journalurl ) %]</p> </fieldset> </div> </fieldset> + [% IF form.rel_types.size > 0 %] <fieldset class="relationships"> <legend>[% '.form.relationships.header' | ml %]</legend> - [% FOREACH rel IN [ "watched_by", "trusted_by", "watched", "trusted", "communities" ] %] + [% FOREACH rel IN form.rel_types %] <div class="formfield"> <input type="checkbox" name="rel_options" value="[% rel %]" id="rel_[% rel %]" [%- 'checked="checked"' IF form.rel_options.$rel -%] /><label for="rel_[% rel %]">[% ".form.relationships.$rel" | ml %]</label> </div> [% END %] </fieldset> + [% END %] <fieldset class="others"> <legend>[% '.form.others.header' | ml %]</legend> @@ -105,14 +112,23 @@ the same terms as Perl itself. For a co <p>[% '.token.list.header' | ml %]</p> <ul> [% FOREACH token = unused_tokens %] - <li>[% token.token | html %] - <a href="/rename/[%- token.token | url %] - [%- IF checkusername.user AND checkusername.status == 'available' ~%] - ?to=[% checkusername.user | url ~%] - ">[% '.token.list.item.withname' | ml( username = checkusername.user ) %] - [%- ELSE ~%] - ">[% '.token.list.item' | ml %] - [% END ~%] - </a></li> + <li>[% token.token | html %] - <a href="[%- dw.site | url %]/rename/[% token.token | url %] + [%~ IF checkusername.user AND checkusername.status == 'available' ~%] + ?to=[%~ checkusername.user | url ~%] + ">[%~ '.token.list.item.withname' | ml( username = checkusername.user ) ~%] + [%~ ELSE ~%] + ">[%~ '.token.list.item' | ml ~%] + [%~ END ~%] + </a> + <a href="[%- dw.site | url %]/rename/[% token.token | url %]?type=C + [%~ IF checkusername.user AND checkusername.status == 'available' ~%] + &to=[%~ checkusername.user | url ~%] + ">[%~ '.token.list.item.comm.withname' | ml( username = checkusername.user ) ~%] + [%~ ELSE ~%] + ">[%~ '.token.list.item.comm' | ml ~%] + [%~ END ~%] + </a> + </li> [% END %] </ul> [% ELSE %] diff -r 4954905b7319 -r 3467e0caff10 views/rename.tt.text --- a/views/rename.tt.text Fri Aug 20 14:25:23 2010 +0800 +++ b/views/rename.tt.text Fri Aug 20 18:22:13 2010 +0800 @@ -44,19 +44,35 @@ .form.rename.header=Rename -.form.rename.disconnect.label=Disconnect your old username from your new username, leaving the old username free to use +.form.rename.disconnect.label.C=Disconnect the old username from the new username, leaving the old username free to use -.form.rename.disconnect.note=[[journalurl]] will not point to your new username; comments and community entries that you posted will still show your new username. +.form.rename.disconnect.label.P=Disconnect your old username from your new username, leaving the old username free to use -.form.rename.forward.label=Forward your old username to your new username +.form.rename.disconnect.note.C=[[journalurl]] will not point to the new username. -.form.rename.forward.note=[[journalurl]] will automatically redirect to your new username. +.form.rename.disconnect.note.P=[[journalurl]] will not point to your new username; comments and community entries that you posted will still show your new username. + +.form.rename.forward.label.C=Forward your community's old username to the new username + +.form.rename.forward.label.P=Forward your old username to your new username + +.form.rename.forward.note.C=[[journalurl]] will automatically redirect to your community's new username. + +.form.rename.forward.note.P=[[journalurl]] will automatically redirect to your new username. .form.rename.fromuser.label=Rename from + +.form.rename.oldusername.header.C=What do you want to do with your community's old username? + +.form.rename.oldusername.header.P=What do you want to do with your old username? .form.rename.token.label=Rename token .form.rename.touser.label=Rename to + +.form.switchtype.comm=rename a community you own + +.form.switchtype.journal=rename your journal .success=Successfully renamed journal from [[from]] to [[to]]. @@ -71,6 +87,10 @@ .token.list.item.withname=Use token to rename journal to [[username]] +.token.list.item.comm= Use token to rename a community + +.token.list.item.comm.withname=Use token to rename a community to [[username]] + .token.notoken=<a [[aopts]]>Purchase a rename token</a> to perform a rename. .token.used=Token has been used: [[token]] --------------------------------------------------------------------------------