Committer: ssafronova
LJSUP-5494: Re-registered first validated email cannot remove newer email addressesU trunk/cgi-bin/LJ/User.pm U trunk/htdocs/tools/emailmanage.bml
Modified: trunk/cgi-bin/LJ/User.pm =================================================================== --- trunk/cgi-bin/LJ/User.pm 2011-01-20 09:02:03 UTC (rev 18065) +++ trunk/cgi-bin/LJ/User.pm 2011-01-20 10:31:45 UTC (rev 18066) @@ -2542,6 +2542,68 @@ return sort keys %ret; } +# read emails and calculate primitives: +# date of last leaving +# date of chain start +# returns data of emails_info function with additional keys ('leaving', may be undef, and 'starting') +# skips internal steps of chains +# skips deleted emails +# cleans out all chains, which are unusable for password restoring, i.e. 'leaving' is newer than 6 month old +# must return array for printing on tools/emailmanage.bml +sub emails_chained_info { + my $u = shift; + + return $u->{'_emails_chained'} if defined $u->{'_emails_chained'}; + + my $emails = $u->emails_info; + my @email_addresses = $u->emails_unique; + + my @chains; + + # process all elements + foreach my $addr (@email_addresses) { + # find all information about this element + my ($starting, $leaving); + my $lc_addr = lc $addr; + + my @relevant = grep { lc($_->{email}) eq $lc_addr } @$emails; + # already sorted by MySQL + + my $step; + foreach $step (@relevant) { + + next unless $step->{status} eq 'A'; # restoring can be done only by validated addressed + + if ($step->{deleted}) { + undef $starting; + undef $leaving; + next; + } + + if (defined $leaving and $step->{set} - $leaving > $LJ::EMAIL_FORGET_AGE) { + # forget old chain - because it is unusable for password restoring + undef $starting; # start new chain + undef $leaving; + } + + # most early starting + $starting = $step->{set} unless defined $starting and $starting < $step->{set}; + + # most late leaving + $leaving = $step->{changed} unless defined $leaving and defined $step->{changed} and $step->{changed} < $leaving; + } + + if ($starting and time - $leaving < $LJ::EMAIL_FORGET_AGE) { + push @chains, { email => $step->{email}, leaving => $leaving, starting => $starting }; # fix this chain + # we store address with upper case letters possibly, + # to make it more comfort for user when he/she reads address + } + } + + $u->{'_emails_chained'} = \@chains; + return \@chains; +} + # returns time when the user has last stopped using the given email # (that is, switched their current address to a different one) # this ASSUMES that the address is not a current one, but that it was @@ -2573,10 +2635,18 @@ sub can_delete_email { my ($u, $addr) = @_; - my $lastchange = $u->email_lastchange($addr); + my $chains = $u->emails_chained_info; - return 0 unless defined $lastchange; - return $lastchange < time - 86400 * 180; # this is six months + # reformat as email => parameters hash + my %chains = map { lc($_->{email}) => $_ } @$chains; + + my $current = lc $u->email_raw; + my $edge_age = $chains{$current}->{starting}; + + my $aim_value = $chains{lc $addr}->{starting}; + + return 0 unless defined $edge_age and $aim_value; + return $aim_value > $edge_age; } # delete the given email from user's history, disabling the user from sending @@ -2636,12 +2706,22 @@ sub can_reset_password_using_email { my ($u, $addr) = @_; - return 1 if lc($addr) eq lc($u->email_raw); + return 0 unless $LJ::DISABLED{'limit_password_reset'}; - return 0 unless $LJ::DISABLED{'limit_password_reset'}; - return - $u->is_email_validated($addr) && # validated - $u->email_lastchange($addr) > time - 86400 * 180; # six months + my $current = lc $u->email_raw; + return 1 if lc($addr) eq $current; + + return 0 unless $u->is_email_validated($addr); + + my $chains = $u->emails_chained_info; + + # reformat as email => parameters hash + my %chains = map { lc($_->{email}) => $_ } @$chains; + + my $aim_value = $chains{lc $addr}->{leaving}; + + return 0 unless defined $aim_value; + return time - $aim_value < $LJ::EMAIL_FORGET_AGE; } # returns date when the user has last changed their email Modified: trunk/htdocs/tools/emailmanage.bml =================================================================== --- trunk/htdocs/tools/emailmanage.bml 2011-01-20 09:02:03 UTC (rev 18065) +++ trunk/htdocs/tools/emailmanage.bml 2011-01-20 10:31:45 UTC (rev 18066) @@ -20,8 +20,8 @@ return LJ::bad_input($ML{'error.invalidauth'}) unless $u; - my $emails = $u->emails_info; - my @emails_unique = $u->emails_unique; + my $emails = $u->emails_chained_info; + my @emails_unique = map { lc $_->{email} } @$emails; my $email_current = $u->email_raw; my @delete_log; @@ -77,17 +77,19 @@ $ret .= "<table border='1' cellpadding='2' style='margin-bottom: 3px;'>\n"; my $can_delete = 0; - foreach my $addr (@emails_unique) { - next if lc($addr) eq lc($email_current); + foreach my $addr (@$emails) { + next if lc($addr->{email}) eq lc($email_current); - next unless $u->is_email_validated($addr); - my $time = $dump_time->($u->email_lastchange($addr)); + next unless $u->is_email_validated($addr->{email}); + my $time = $dump_time->($addr->{leaving}); my $can_delete_this = $u->can_delete_email($addr); $can_delete ||= $can_delete_this; - $ret .= "<tr><td>" . LJ::html_check({ 'type' => 'check', 'name' => "$addr", + my $starting = $GET{debug} ? "<td>$addr->{starting}</td>" : ""; + + $ret .= "<tr><td>" . LJ::html_check({ 'type' => 'check', 'name' => "$addr->{email}", 'disabled' => !$can_delete_this } ) . "</td>"; - $ret .= "<td>$addr</td><td>$time</td></tr>\n"; + $ret .= "<td>$addr->{email}</td><td>$time</td>$starting</tr>\n"; } $ret .= "</table>\n";