diff --git a/.reek b/.reek
index 54bff8852c2..0253240c30a 100644
--- a/.reek
+++ b/.reek
@@ -161,6 +161,7 @@ UtilityFunction:
- LocaleHelper#locale_url_param
- IdvSession#timed_out_vendor_error
- JWT::Signature#sign
+ - SmsAccountResetCancellationNotifierJob#perform
'app/controllers':
InstanceVariableAssumption:
enabled: false
diff --git a/app/controllers/account_reset/cancel_controller.rb b/app/controllers/account_reset/cancel_controller.rb
index 7c12994e22e..8cbe8659e7f 100644
--- a/app/controllers/account_reset/cancel_controller.rb
+++ b/app/controllers/account_reset/cancel_controller.rb
@@ -1,8 +1,9 @@
module AccountReset
class CancelController < ApplicationController
def cancel
- if AccountResetService.cancel_request(params[:token])
- handle_success
+ account_reset = AccountResetService.cancel_request(params[:token])
+ if account_reset
+ handle_success(account_reset.user)
else
handle_failure
end
@@ -11,9 +12,13 @@ def cancel
private
- def handle_success
- analytics.track_event(Analytics::ACCOUNT_RESET, event: :cancel, token_valid: true)
+ def handle_success(user)
+ analytics.track_event(Analytics::ACCOUNT_RESET,
+ event: :cancel, token_valid: true, user_id: user.uuid)
sign_out if current_user
+ UserMailer.account_reset_cancel(user.email).deliver_later
+ phone = user.phone
+ SmsAccountResetCancellationNotifierJob.perform_now(phone: phone) if phone.present?
flash[:success] = t('devise.two_factor_authentication.account_reset.successful_cancel')
end
diff --git a/app/controllers/account_reset/delete_account_controller.rb b/app/controllers/account_reset/delete_account_controller.rb
index b97d9c5a2b3..d6a13530dc8 100644
--- a/app/controllers/account_reset/delete_account_controller.rb
+++ b/app/controllers/account_reset/delete_account_controller.rb
@@ -7,8 +7,10 @@ class DeleteAccountController < ApplicationController
def show; end
def delete
- analytics.track_event(Analytics::ACCOUNT_RESET, event: :delete, token_valid: true)
- email = reset_session_and_set_email
+ user = @account_reset_request.user
+ analytics.track_event(Analytics::ACCOUNT_RESET,
+ event: :delete, token_valid: true, user_id: user.uuid)
+ email = reset_session_and_set_email(user)
UserMailer.account_reset_complete(email).deliver_later
redirect_to account_reset_confirm_delete_account_url
end
@@ -19,8 +21,7 @@ def check_feature_enabled
redirect_to root_url unless FeatureManagement.account_reset_enabled?
end
- def reset_session_and_set_email
- user = @account_reset_request.user
+ def reset_session_and_set_email(user)
email = user.email
user.destroy!
sign_out
diff --git a/app/controllers/account_reset/request_controller.rb b/app/controllers/account_reset/request_controller.rb
index 0b99bc2ace5..0eb7e428faa 100644
--- a/app/controllers/account_reset/request_controller.rb
+++ b/app/controllers/account_reset/request_controller.rb
@@ -28,10 +28,13 @@ def reset_session_with_email
end
def send_notifications
- SmsAccountResetNotifierJob.perform_now(
- phone: current_user.phone,
- cancel_token: current_user.account_reset_request.request_token
- )
+ phone = current_user.phone
+ if phone
+ SmsAccountResetNotifierJob.perform_now(
+ phone: phone,
+ cancel_token: current_user.account_reset_request.request_token
+ )
+ end
UserMailer.account_reset_request(current_user).deliver_later
end
diff --git a/app/jobs/sms_account_reset_cancellation_notifier_job.rb b/app/jobs/sms_account_reset_cancellation_notifier_job.rb
new file mode 100644
index 00000000000..d8f96b51e87
--- /dev/null
+++ b/app/jobs/sms_account_reset_cancellation_notifier_job.rb
@@ -0,0 +1,13 @@
+class SmsAccountResetCancellationNotifierJob < ApplicationJob
+ queue_as :sms
+
+ def perform(phone:)
+ TwilioService::Utils.new.send_sms(
+ to: phone,
+ body: I18n.t(
+ 'jobs.sms_account_reset_cancel_job.message',
+ app: APP_NAME
+ )
+ )
+ end
+end
diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb
index 72ff09e8954..2c6aa0e24e2 100644
--- a/app/mailers/user_mailer.rb
+++ b/app/mailers/user_mailer.rb
@@ -42,4 +42,8 @@ def account_reset_granted(user, account_reset)
def account_reset_complete(email)
mail(to: email, subject: t('user_mailer.account_reset_complete.subject'))
end
+
+ def account_reset_cancel(email)
+ mail(to: email, subject: t('user_mailer.account_reset_cancel.subject'))
+ end
end
diff --git a/app/services/account_reset_service.rb b/app/services/account_reset_service.rb
index eefae3f4c12..901bdc5ee18 100644
--- a/app/services/account_reset_service.rb
+++ b/app/services/account_reset_service.rb
@@ -18,6 +18,7 @@ def self.cancel_request(token)
account_reset.update(cancelled_at: Time.zone.now,
request_token: nil,
granted_token: nil)
+ account_reset
end
def self.report_fraud(token)
diff --git a/app/views/user_mailer/account_reset_cancel.html.slim b/app/views/user_mailer/account_reset_cancel.html.slim
new file mode 100644
index 00000000000..530ae2ec5f9
--- /dev/null
+++ b/app/views/user_mailer/account_reset_cancel.html.slim
@@ -0,0 +1,16 @@
+p.lead == t('.intro', app: link_to(APP_NAME, Figaro.env.mailer_domain_name, class: 'gray'))
+
+table.spacer
+ tbody
+ tr
+ td.s10 height="10px"
+ |
+table.hr
+ tr
+ th
+ |
+
+p == t('.help',
+ app: link_to(APP_NAME, Figaro.env.mailer_domain_name, class: 'gray'),
+ help_link: link_to(t('user_mailer.help_link_text'), MarketingSite.help_url),
+ contact_link: link_to(t('user_mailer.contact_link_text'), MarketingSite.contact_url))
diff --git a/config/locales/devise/en.yml b/config/locales/devise/en.yml
index e9602f0374c..1a0248de049 100644
--- a/config/locales/devise/en.yml
+++ b/config/locales/devise/en.yml
@@ -146,7 +146,7 @@ en:
code below.
please_try_again_html: Please try again in %{time_remaining}.
account_reset:
- successful_cancel: Thank you. The request to delete your login.gov account
+ successful_cancel: Thank you. Your request to delete your login.gov account
has been cancelled.
link: deleting your account
text_html: If you can't use any of these security options above, you can reset
diff --git a/config/locales/devise/es.yml b/config/locales/devise/es.yml
index 1e273df55ee..72c5de6f910 100644
--- a/config/locales/devise/es.yml
+++ b/config/locales/devise/es.yml
@@ -151,8 +151,8 @@ es:
el código de seguridad a continuación.
please_try_again_html: Inténtelo de nuevo en %{time_remaining}.
account_reset:
- successful_cancel: Gracias. La solicitud para eliminar su cuenta de login.gov
- ha sido cancelado.
+ successful_cancel: Gracias. Su solicitud para eliminar su cuenta de login.gov
+ ha sido cancelada.
link: eliminando su cuenta
text_html: Si no puede usar ninguna de estas opciones de seguridad anteriores,
puede restablecer tus preferencias por %{link}.
diff --git a/config/locales/devise/fr.yml b/config/locales/devise/fr.yml
index f9f764116c5..a295a39d818 100644
--- a/config/locales/devise/fr.yml
+++ b/config/locales/devise/fr.yml
@@ -158,8 +158,8 @@ fr:
le code de sécurité ci-dessous.
please_try_again_html: Veuillez essayer de nouveau dans %{time_remaining}.
account_reset:
- successful_cancel: Je vous remercie. La demande de suppression de votre compte
- login.gov a été annulé.
+ successful_cancel: Je vous remercie. Votre demande de suppression de votre
+ compte login.gov a été annulée.
link: supprimer votre compte
text_html: Si vous ne pouvez pas utiliser l'une de ces options de sécurité
ci-dessus, vous pouvez réinitialiser vos préférences par %{link}.
diff --git a/config/locales/jobs/en.yml b/config/locales/jobs/en.yml
index d7d47937775..e2b078abf16 100644
--- a/config/locales/jobs/en.yml
+++ b/config/locales/jobs/en.yml
@@ -4,6 +4,8 @@ en:
sms_otp_sender_job:
message: "%{code} is your %{app} one-time security code. This code will expire
in %{expiration} minutes."
+ sms_account_reset_cancel_job:
+ message: Your request to delete your login.gov account has been cancelled.
sms_account_reset_notifier_job:
message: 'You''ve requested to delete your login.gov account. Your request will
be processed in 24 hours. If you don’t want to delete your account, please
diff --git a/config/locales/jobs/es.yml b/config/locales/jobs/es.yml
index e0f5c767b71..6ead589ceff 100644
--- a/config/locales/jobs/es.yml
+++ b/config/locales/jobs/es.yml
@@ -4,6 +4,8 @@ es:
sms_otp_sender_job:
message: "%{code} es su %{app} código de seguridad de sólo un uso. Este código
caducará en %{expiration} minutos."
+ sms_account_reset_cancel_job:
+ message: Su solicitud para eliminar su cuenta de login.gov ha sido cancelada.
sms_account_reset_notifier_job:
message: 'Has solicitado eliminar tu cuenta de login.gov. Su solicitud será
ser procesado en 24 horas. Si no desea eliminar su cuenta, por favor cancelar:
diff --git a/config/locales/jobs/fr.yml b/config/locales/jobs/fr.yml
index 76c1a828e42..f4509827b37 100644
--- a/config/locales/jobs/fr.yml
+++ b/config/locales/jobs/fr.yml
@@ -4,6 +4,8 @@ fr:
sms_otp_sender_job:
message: "%{code} est votre %{app} code de sécurité à utilisation unique. Ce
code expirera dans %{expiration} minutes."
+ sms_account_reset_cancel_job:
+ message: Votre demande de suppression de votre compte login.gov a été annulée.
sms_account_reset_notifier_job:
message: 'Vous avez demandé à supprimer votre compte login.gov. Votre demande
sera être traité en 24 heures. Si vous ne souhaitez pas supprimer votre compte,
diff --git a/config/locales/user_mailer/en.yml b/config/locales/user_mailer/en.yml
index 0ba57faca25..21e09a1bfdf 100644
--- a/config/locales/user_mailer/en.yml
+++ b/config/locales/user_mailer/en.yml
@@ -8,6 +8,11 @@ en:
didn't request a password reset, you can ignore this message.
link_text: Create your account
subject: Your login.gov password reset request
+ account_reset_cancel:
+ intro: This email confirms you have cancelled the request to delete your login.gov
+ account.
+ subject: Delete your account
+ help: ''
account_reset_request:
help: ''
intro: You’ve requested to delete your login.gov account.
Your
diff --git a/config/locales/user_mailer/es.yml b/config/locales/user_mailer/es.yml
index 0c4d9b723a7..a7349619979 100644
--- a/config/locales/user_mailer/es.yml
+++ b/config/locales/user_mailer/es.yml
@@ -5,6 +5,11 @@ es:
intro: NOT TRANSLATED YET
link_text: NOT TRANSLATED YET
subject: NOT TRANSLATED YET
+ account_reset_cancel:
+ intro: Este correo electrónico confirma que ha cancelado la solicitud para eliminar
+ su cuenta de login.gov.
+ subject: Eliminar su cuenta
+ help: ''
account_reset_request:
help: ''
intro: Has solicitado eliminar tu cuenta de login.gov.
Su la
diff --git a/config/locales/user_mailer/fr.yml b/config/locales/user_mailer/fr.yml
index 632f237141b..18556d9a1fd 100644
--- a/config/locales/user_mailer/fr.yml
+++ b/config/locales/user_mailer/fr.yml
@@ -5,6 +5,11 @@ fr:
intro: NOT TRANSLATED YET
link_text: NOT TRANSLATED YET
subject: NOT TRANSLATED YET
+ account_reset_cancel:
+ intro: Cet e-mail confirme que vous avez annulé la demande de suppression de
+ votre compte login.gov.
+ subject: Supprimer votre compte
+ help: ''
account_reset_request:
help: ''
intro: Vous avez demandé à supprimer votre compte login.gov.
Votre
diff --git a/spec/controllers/account_reset/cancel_controller_spec.rb b/spec/controllers/account_reset/cancel_controller_spec.rb
index d7f40f8377f..2cc508be842 100644
--- a/spec/controllers/account_reset/cancel_controller_spec.rb
+++ b/spec/controllers/account_reset/cancel_controller_spec.rb
@@ -1,14 +1,19 @@
require 'rails_helper'
describe AccountReset::CancelController do
+ let(:user) { create(:user, :signed_up, phone: '+1 (703) 555-0000') }
+ before do
+ TwilioService::Utils.telephony_service = FakeSms
+ end
+
describe '#cancel' do
it 'logs a good token to the analytics' do
- user = create(:user)
AccountResetService.new(user).create_request
stub_analytics
expect(@analytics).to receive(:track_event).
- with(Analytics::ACCOUNT_RESET, event: :cancel, token_valid: true)
+ with(Analytics::ACCOUNT_RESET,
+ event: :cancel, token_valid: true, user_id: user.uuid)
post :cancel, params: { token: AccountResetRequest.all[0].request_token }
end
@@ -25,5 +30,37 @@
post :cancel
expect(response).to redirect_to root_url
end
+
+ it 'sends an SMS if there is a phone' do
+ AccountResetService.new(user).create_request
+ allow(SmsAccountResetCancellationNotifierJob).to receive(:perform_now)
+
+ post :cancel, params: { token: AccountResetRequest.all[0].request_token }
+
+ expect(SmsAccountResetCancellationNotifierJob).to have_received(:perform_now).with(
+ phone: user.phone
+ )
+ end
+
+ it 'does not send an SMS if there is no phone' do
+ AccountResetService.new(user).create_request
+ allow(SmsAccountResetCancellationNotifierJob).to receive(:perform_now)
+ user.phone = nil
+ user.save!
+
+ post :cancel, params: { token: AccountResetRequest.all[0].request_token }
+
+ expect(SmsAccountResetCancellationNotifierJob).to_not have_received(:perform_now)
+ end
+
+ it 'sends an email' do
+ AccountResetService.new(user).create_request
+
+ @mailer = instance_double(ActionMailer::MessageDelivery, deliver_later: true)
+ allow(UserMailer).to receive(:account_reset_cancel).with(user.email).
+ and_return(@mailer)
+
+ post :cancel, params: { token: AccountResetRequest.all[0].request_token }
+ end
end
end
diff --git a/spec/controllers/account_reset/delete_account_controller_spec.rb b/spec/controllers/account_reset/delete_account_controller_spec.rb
index 909ecff1b84..c9c5030b982 100644
--- a/spec/controllers/account_reset/delete_account_controller_spec.rb
+++ b/spec/controllers/account_reset/delete_account_controller_spec.rb
@@ -10,7 +10,7 @@
session[:granted_token] = AccountResetRequest.all[0].granted_token
stub_analytics
expect(@analytics).to receive(:track_event).
- with(Analytics::ACCOUNT_RESET, event: :delete, token_valid: true)
+ with(Analytics::ACCOUNT_RESET, event: :delete, token_valid: true, user_id: user.uuid)
delete :delete
end
diff --git a/spec/jobs/sms_account_reset_cancellation_notifier_job_spec.rb b/spec/jobs/sms_account_reset_cancellation_notifier_job_spec.rb
new file mode 100644
index 00000000000..2960013b35d
--- /dev/null
+++ b/spec/jobs/sms_account_reset_cancellation_notifier_job_spec.rb
@@ -0,0 +1,38 @@
+require 'rails_helper'
+
+describe SmsAccountResetCancellationNotifierJob do
+ include Features::ActiveJobHelper
+
+ describe '.perform' do
+ before do
+ reset_job_queues
+ TwilioService::Utils.telephony_service = FakeSms
+ FakeSms.messages = []
+ end
+
+ subject(:perform) do
+ SmsAccountResetCancellationNotifierJob.perform_now(
+ phone: '+1 (888) 555-5555'
+ )
+ end
+
+ it 'sends a message to the mobile number', twilio: true do
+ allow(Figaro.env).to receive(:twilio_messaging_service_sid).and_return('fake_sid')
+
+ TwilioService::Utils.telephony_service = FakeSms
+
+ perform
+
+ messages = FakeSms.messages
+
+ expect(messages.size).to eq(1)
+
+ msg = messages.first
+
+ expect(msg.messaging_service_sid).to eq('fake_sid')
+ expect(msg.to).to eq('+1 (888) 555-5555')
+ expect(msg.body).
+ to eq(I18n.t('jobs.sms_account_reset_cancel_job.message', app: APP_NAME))
+ end
+ end
+end
diff --git a/spec/services/account_reset_service_spec.rb b/spec/services/account_reset_service_spec.rb
index 55670c9f9b2..6ad96b17490 100644
--- a/spec/services/account_reset_service_spec.rb
+++ b/spec/services/account_reset_service_spec.rb
@@ -37,12 +37,13 @@
describe '#cancel_request' do
it 'removes tokens from a account reset request' do
subject.create_request
- AccountResetService.cancel_request(user.account_reset_request.request_token)
+ cancel = AccountResetService.cancel_request(user.account_reset_request.request_token)
arr = AccountResetRequest.find_by(user_id: user.id)
expect(arr.request_token).to_not be_present
expect(arr.granted_token).to_not be_present
expect(arr.requested_at).to be_present
expect(arr.cancelled_at).to be_present
+ expect(arr).to eq(cancel)
end
it 'does not raise an error for a cancel request with a blank token' do