aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStruan Donald <struan@exo.org.uk>2018-04-19 15:58:02 +0100
committerStruan Donald <struan@exo.org.uk>2018-06-25 10:12:25 +0100
commit7c009ce048fbe36db24dd1a24f3542503db2e898 (patch)
treedba5f5e7d0b4bab9a5d3565781fe1bbd12aff807
parent43ef59400d632c3c29321c6908128932a31148a7 (diff)
add a send login email button to user edit page
Add a button to the user edit page that sends a login token email to the user. Helpful for user support situations where someone is having trouble logging in. Also for situations where you have added a user and want to get them logged in. Fixes #2041
-rw-r--r--CHANGELOG.md1
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin.pm43
-rw-r--r--perllib/FixMyStreet/App/Controller/Auth.pm3
-rw-r--r--t/app/controller/admin/users.t65
-rw-r--r--templates/web/base/admin/user-form.html7
5 files changed, 111 insertions, 8 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1d070c62f..a6bf42122 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,7 @@
- Defect type is recorded if category change made. #2172
- Admin improvements:
- Mandatory defect type selection if defect raised.
+ - Send login email button on user edit page #2041
- Open311 improvements:
- CLOSED status maps to 'closed' state if extended statuses are enabled.
diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm
index 9d6c7d922..dfea6f8d4 100644
--- a/perllib/FixMyStreet/App/Controller/Admin.pm
+++ b/perllib/FixMyStreet/App/Controller/Admin.pm
@@ -1417,12 +1417,6 @@ sub user_add : Path('user_edit') : Args(0) {
my $email_v = $c->get_param('email_verified');
my $phone_v = $c->get_param('phone_verified');
- unless ($email || $phone) {
- $c->stash->{field_errors}->{username} = _('Please enter a valid email or phone number');
- }
- if (!$email_v && !$phone_v) {
- $c->stash->{field_errors}->{username} = _('Please verify at least one of email/phone');
- }
if ($email && !is_valid_email($email)) {
$c->stash->{field_errors}->{email} = _('Please enter a valid email');
}
@@ -1430,6 +1424,13 @@ sub user_add : Path('user_edit') : Args(0) {
$c->stash->{field_errors}->{name} = _('Please enter a name');
}
+ unless ($email || $phone) {
+ $c->stash->{field_errors}->{username} = _('Please enter a valid email or phone number');
+ }
+ if (!$email_v && !$phone_v) {
+ $c->stash->{field_errors}->{username} = _('Please verify at least one of email/phone');
+ }
+
if ($phone_v) {
my $parsed_phone = $c->forward('phone_check', [ $phone ]);
$phone = $parsed_phone if $parsed_phone;
@@ -1503,6 +1504,11 @@ sub user_edit : Path('user_edit') : Args(1) {
$c->forward('user_hide_everywhere', [ $user ]);
} elsif ( $c->get_param('submit') and $c->get_param('remove_account') ) {
$c->forward('user_remove_account', [ $user ]);
+ } elsif ( $c->get_param('submit') and $c->get_param('send_login_email') ) {
+ my $email = lc $c->get_param('email');
+ my %args = ( email => $email );
+ $args{user_id} = $id if $user->email ne $email || !$user->email_verified;
+ $c->forward('send_login_email', [ \%args ]);
} elsif ( $c->get_param('submit') ) {
my $edited = 0;
@@ -1917,6 +1923,31 @@ sub user_hide_everywhere : Private {
$c->stash->{status_message} = _('That user’s reports and updates have been hidden.');
}
+sub send_login_email : Private {
+ my ( $self, $c, $args ) = @_;
+
+ my $token_data = {
+ email => $args->{email},
+ };
+
+ $token_data->{old_user_id} = $args->{user_id} if $args->{user_id};
+ $token_data->{name} = $args->{name} if $args->{name};
+
+ my $token_obj = $c->model('DB::Token')->create({
+ scope => 'email_sign_in',
+ data => $token_data,
+ });
+
+ $c->stash->{token} = $token_obj->token;
+ my $template = 'login.txt';
+
+ # do not use relative URIs in the email, obvs.
+ $c->uri_disposition('absolute');
+ $c->send_email( $template, { to => $args->{email} } );
+
+ $c->stash->{status_message} = _('The user has been sent a login email');
+}
+
# Anonymize and remove name from all problems/updates, disable all alerts.
# Remove their account's email address, phone number, password, etc.
sub user_remove_account : Private {
diff --git a/perllib/FixMyStreet/App/Controller/Auth.pm b/perllib/FixMyStreet/App/Controller/Auth.pm
index fa3403f6d..41674e377 100644
--- a/perllib/FixMyStreet/App/Controller/Auth.pm
+++ b/perllib/FixMyStreet/App/Controller/Auth.pm
@@ -224,7 +224,8 @@ sub token : Path('/M') : Args(1) {
my $data = $c->forward('get_token', [ $url_token, 'email_sign_in' ]) || return;
$c->stash->{token_not_found} = 1, return
- if $data->{old_user_id} && (!$c->user_exists || $c->user->id ne $data->{old_user_id});
+ if $data->{old_user_id} && $data->{r} && $data->{r} eq 'auth/change_email/success'
+ && (!$c->user_exists || $c->user->id ne $data->{old_user_id});
my $type = $data->{login_type} || 'email';
$c->detach( '/auth/process_login', [ $data, $type ] );
diff --git a/t/app/controller/admin/users.t b/t/app/controller/admin/users.t
index 0d8290c37..37d95feed 100644
--- a/t/app/controller/admin/users.t
+++ b/t/app/controller/admin/users.t
@@ -401,6 +401,71 @@ FixMyStreet::override_config {
$user = $mech->create_user_ok('test@example.com', name => 'Test User');
+subtest "Send login email from admin" => sub {
+ $mech->email_count_is(0);
+ $mech->get_ok( '/admin/user_edit/' . $user->id );
+ $mech->submit_form_ok(
+ {
+ button => 'send_login_email'
+ },
+ "send login email form submitted"
+ );
+
+ my $email = $mech->get_email;
+ ok $email, "got an email";
+
+ is $email->header('Subject'), "Your FixMyStreet account details",
+ "subject is correct";
+ is $email->header('To'), $user->email, "to is correct";
+
+ my $link = $mech->get_link_from_email($email);
+
+ my $mech2 = FixMyStreet::TestMech->new;
+ $mech2->not_logged_in_ok;
+ $mech2->get_ok($link);
+ $mech2->logged_in_ok;
+ $mech2->log_out_ok;
+
+ $mech->clear_emails_ok;
+};
+
+subtest "Send login email from admin for unverified email" => sub {
+ $user->update( { email_verified => 0 } );
+ $mech->email_count_is(0);
+ $mech->get_ok( '/admin/user_edit/' . $user->id );
+ $mech->submit_form_ok(
+ {
+ button => 'send_login_email'
+ },
+ "send login email form submitted"
+ );
+
+ my $email = $mech->get_email;
+ ok $email, "got an email";
+
+ is $email->header('Subject'), "Your FixMyStreet account details",
+ "subject is correct";
+ is $email->header('To'), 'test@example.com', "to is correct";
+
+ my $link = $mech->get_link_from_email($email);
+
+ my $mech2 = FixMyStreet::TestMech->new;
+ $mech2->not_logged_in_ok;
+ $mech2->get_ok($link);
+ $mech2->logged_in_ok;
+
+ my $test_user = FixMyStreet::DB->resultset('User')->search({
+ email => $user->email
+ }, { order_by => [ { -desc => 'id' } ] } );
+ $user->discard_changes;
+
+ is $test_user->count, 1, "only one user";
+ is $test_user->first->id, $user->id, "User is same";
+ ok $user->email_verified, 'email is verified now';
+ $mech2->log_out_ok;
+ $user->update( { email_verified => 1 } );
+};
+
subtest "Anonymizing user from admin" => sub {
$mech->create_problems_for_body(4, 2237, 'Title');
my $count_p = FixMyStreet::DB->resultset('Problem')->search({ user_id => $user->id })->count;
diff --git a/templates/web/base/admin/user-form.html b/templates/web/base/admin/user-form.html
index e8e647a09..bb8511726 100644
--- a/templates/web/base/admin/user-form.html
+++ b/templates/web/base/admin/user-form.html
@@ -17,7 +17,11 @@
<input type='text' class="form-control" name='name' id='name' value='[% user.name | html %]'>
</li>
<li><label for="email">[% loc('Email:') %]</label>
- <input type='text' class="form-control" id='email' name='email' value='[% user.email | html %]'></li>
+ <input type='text' class="form-control" id='email' name='email' value='[% user.email | html %]'>
+ [% IF user %]
+ <input class="btn" type="submit" name="send_login_email" value="[% loc('Send login email') %]">
+ [% END %]
+ </li>
<li><label class="inline" for="email_verified">[% loc('Email verified:') %]</label>
<input type="checkbox" id="email_verified" name="email_verified" value="1" [% user.email_verified ? ' checked' : '' %]>
<li><label for="phone">[% loc('Phone:') %]</label>
@@ -190,6 +194,7 @@
<p>
<input type="submit" class="btn" name="Submit changes" value="[% loc('Submit changes') %]" >
</p>
+
[% IF user AND NOT user.from_body %]
<ul class="no-bullets danger-zone">
<li><input class="btn-danger" type="submit" name="logout_everywhere" value="[% loc('Log out of all sessions') %]">