Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LG-13665: Add option to change selected email shared with partner #11196

Merged
merged 13 commits into from
Sep 5, 2024
2 changes: 2 additions & 0 deletions app/components/status_page_component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@
<%= troubleshooting_options %>
</div>
<% end %>

<%= footer %>
1 change: 1 addition & 0 deletions app/components/status_page_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class StatusPageComponent < BaseComponent
ButtonComponent.new(**button_options, big: true, wide: true)
end
renders_one :troubleshooting_options, TroubleshootingOptionsComponent
renders_one :footer, PageFooterComponent
aduth marked this conversation as resolved.
Show resolved Hide resolved

attr_reader :status, :icon

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# frozen_string_literal: true

module Accounts
module ConnectedAccounts
class SelectedEmailController < ApplicationController
before_action :confirm_two_factor_authenticated
before_action :validate_identity

def edit
@identity = identity
@select_email_form = build_select_email_form
analytics.sp_select_email_visited
end

def update
@select_email_form = build_select_email_form

result = @select_email_form.submit(form_params)

analytics.sp_select_email_submitted(**result.to_h)

if result.success?
redirect_to account_connected_accounts_path
else
flash[:error] = result.first_error_message
redirect_to edit_connected_account_selected_email_path(identity.id)
end
end

private

def form_params
params.require(:select_email_form).permit(:selected_email_id)
end

def build_select_email_form
SelectEmailForm.new(user: current_user, identity:)
end

def validate_identity
render_not_found if identity.blank?
end

def identity
return @identity if defined?(@identity)
@identity = current_user.identities.find_by(id: params[:identity_id])
end
end
end
end
2 changes: 1 addition & 1 deletion app/controllers/sign_up/select_email_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def user_emails
private

def build_select_email_form
SelectEmailForm.new(current_user)
SelectEmailForm.new(user: current_user)
end

def form_params
Expand Down
14 changes: 7 additions & 7 deletions app/forms/select_email_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,28 @@ class SelectEmailForm
include ActiveModel::Model
include ActionView::Helpers::TranslationHelper

attr_reader :user, :selected_email_id
attr_reader :user, :identity, :selected_email_id

validate :validate_owns_selected_email

def initialize(user)
def initialize(user:, identity: nil)
@user = user
@identity = identity
end

def submit(params)
@selected_email_id = params[:selected_email_id]

success = valid?
FormResponse.new(success:, errors:)
identity.update(email_address_id: selected_email_id) if success && identity
zachmargolis marked this conversation as resolved.
Show resolved Hide resolved

FormResponse.new(success:, errors:, serialize_error_details_only: true)
end

private

def validate_owns_selected_email
return if user.confirmed_email_addresses.exists?(id: selected_email_id)

errors.add :email, I18n.t(
'email_address.not_found',
), type: :selected_email_id
errors.add(:selected_email_id, :not_found, message: t('email_address.not_found'))
end
end
27 changes: 27 additions & 0 deletions app/services/analytics_events.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6135,6 +6135,33 @@ def sp_revoke_consent_visited(issuer:, **extra)
)
end

# User submitted form to change email shared with service provider
# @param [Boolean] success Whether form validation was successful
# @param [Hash] error_details Details for errors that occurred in unsuccessful submission
# @param [String, nil] needs_completion_screen_reason Reason for the consent screen being shown,
# if user is changing email in consent flow
def sp_select_email_submitted(
success:,
error_details: nil,
needs_completion_screen_reason: nil,
**extra
)
track_event(
:sp_select_email_submitted,
success:,
error_details:,
needs_completion_screen_reason:,
**extra,
)
end

# User visited form to change email shared with service provider
# @param [String, nil] needs_completion_screen_reason Reason for the consent screen being shown,
# if user is changing email in consent flow
def sp_select_email_visited(needs_completion_screen_reason: nil, **extra)
track_event(:sp_select_email_visited, needs_completion_screen_reason:, **extra)
end

# @param [String] area_code Area code of phone number
# @param [String] country_code Abbreviated 2-letter country code associated with phone number
# @param [String] phone_fingerprint HMAC fingerprint of the phone number formatted as E.164
Expand Down
23 changes: 19 additions & 4 deletions app/views/accounts/_connected_app.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,25 @@
<% end %>
</h2>

<%= t(
'account.connected_apps.associated_html',
timestamp_html: render(TimeComponent.new(time: identity.created_at)),
) %>
<% if IdentityConfig.store.feature_select_email_to_share_enabled %>
<%= t(
'account.connected_apps.associated_attributes_html',
timestamp_html: render(TimeComponent.new(time: identity.created_at)),
) %>
<br />
<strong>
<%= identity.email_address&.email || t('account.connected_apps.email_not_selected') %>
</strong>
<%= link_to(
t('help_text.requested_attributes.change_email_link'),
edit_connected_account_selected_email_path(identity_id: identity.id),
) %>
<% else %>
<%= t(
'account.connected_apps.associated_html',
timestamp_html: render(TimeComponent.new(time: identity.created_at)),
) %>
<% end %>

<% if identity.service_provider_id %>
<div class="margin-y-1">
Expand Down
40 changes: 40 additions & 0 deletions app/views/accounts/connected_accounts/selected_email/edit.html.erb
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To do: Write spec for this view. Ideally include spec covering be_logically_grouped expectations, avoiding similar regression addressed for email language in 7f4c413 & 4b256c1 .

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<% self.title = t('titles.select_email') %>

<%= render StatusPageComponent.new(status: :info, icon: :question) do |c| %>
<% c.with_header { t('titles.select_email') } %>

<p id="select-email-intro">
<%= t('help_text.select_preferred_email', sp: @identity.display_name, app_name: APP_NAME) %>
</p>

<%= simple_form_for(
@select_email_form,
url: connected_account_selected_email_path(@identity.id),
method: :patch,
) do |f| %>
<%= f.input(
:selected_email_id,
as: :radio_buttons,
label: false,
wrapper_html: { aria: { labelledby: 'select-email-intro' } },
collection: current_user.confirmed_email_addresses.map do |email|
[
email.email,
email.id,
checked: email.id == @identity.email_address_id,
]
end,
) %>
<%= f.submit t('help_text.requested_attributes.change_email_link'), class: 'margin-top-1' %>
<% end %>

<%= render ButtonComponent.new(
url: add_email_path,
outline: true,
big: true,
wide: true,
class: 'margin-top-2',
).with_content(t('account.index.email_add')) %>

<% c.with_footer { link_to t('forms.buttons.back'), account_connected_accounts_path } %>
<% end %>
4 changes: 1 addition & 3 deletions config/initializers/simple_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,7 @@
item_wrapper_tag: nil,
item_label_class: item_label_class do |b|
b.use :html5_no_aria_required
b.wrapper :legend, tag: 'legend', class: legend_class do |ba|
ba.use :label_text
end
b.optional :label, wrap_with: { tag: 'legend', class: legend_class }
b.optional :hint, wrap_with: { tag: 'div', class: 'usa-hint margin-bottom-05' }
b.wrapper :grid_row, tag: :div, class: 'grid-row margin-bottom-neg-1' do |gr|
gr.wrapper :grid_column_radios, tag: :div, class: 'grid-col-fill' do |gc|
Expand Down
2 changes: 2 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ account_reset.request.info:
account_reset.request.no_cancel: Cancel
account_reset.request.title: Account deletion and reset
account_reset.request.yes_continue: Yes, continue deletion
account.connected_apps.associated_attributes_html: 'Connected %{timestamp_html} with:'
account.connected_apps.associated_html: Connected %{timestamp_html}
account.connected_apps.description: With your %{app_name} account, you can securely connect to multiple government accounts online. Below is a list of all the accounts you currently have connected.
account.connected_apps.email_not_selected: Email not yet selected
account.email_language.default: '%{language} (default)'
account.email_language.edit_title: Edit email language preference
account.email_language.languages_list: You will receive emails from %{app_name} in the language you choose.
Expand Down
2 changes: 2 additions & 0 deletions config/locales/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ account_reset.request.info:
account_reset.request.no_cancel: Cancelar
account_reset.request.title: Eliminación y restablecimiento de cuenta
account_reset.request.yes_continue: Sí, continuar con la eliminación
account.connected_apps.associated_attributes_html: 'Conectado el %{timestamp_html} con:'
account.connected_apps.associated_html: 'Conectado: %{timestamp_html}'
account.connected_apps.description: Con su cuenta de %{app_name}, puede conectarse de manera segura a muchas cuentas del gobierno en línea. Esta es una lista de todas las cuentas que tiene conectadas actualmente.
account.connected_apps.email_not_selected: Email not yet selected
account.email_language.default: '%{language} (predeterminado)'
account.email_language.edit_title: Editar la preferencia de idioma del correo electrónico
account.email_language.languages_list: Recibirá mensajes de correo electrónico de %{app_name} en el idioma que elija.
Expand Down
2 changes: 2 additions & 0 deletions config/locales/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ account_reset.request.info:
account_reset.request.no_cancel: Annuler
account_reset.request.title: Suppression et réinitialisation de compte
account_reset.request.yes_continue: Oui, continuer la suppression
account.connected_apps.associated_attributes_html: 'Connecté %{timestamp_html} avec :'
account.connected_apps.associated_html: Connecté %{timestamp_html}
account.connected_apps.description: Avec votre compte %{app_name}, vous pouvez vous connecter en toute sécurité à plusieurs comptes de l’administration en ligne. Vous trouverez ci-dessous une liste de tous vos comptes actuellement connectés.
account.connected_apps.email_not_selected: Email not yet selected
account.email_language.default: '%{language} (par défaut)'
account.email_language.edit_title: Modifier la langue dans laquelle vous préférez recevoir les e-mails
account.email_language.languages_list: Vous recevrez des e-mails de %{app_name} dans la langue de votre choix.
Expand Down
2 changes: 2 additions & 0 deletions config/locales/zh.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ account_reset.request.info:
account_reset.request.no_cancel: 取消
account_reset.request.title: 账户删除和重设
account_reset.request.yes_continue: 是的,继续删除
account.connected_apps.associated_attributes_html: '在 %{timestamp_html} 用以下电邮做的连接:'
account.connected_apps.associated_html: 已连接 %{timestamp_html}
account.connected_apps.description: 使用你的 %{app_name} 账户,你可以安全地连接到网上多个政府账户。以下列出了你目前已连接的所有账户。
account.connected_apps.email_not_selected: Email not yet selected
account.email_language.default: '%{language} (默认)'
account.email_language.edit_title: 编辑电邮语言选择
account.email_language.languages_list: 您将收到%{app_name}用您选择的语言发送的电子邮件。
Expand Down
4 changes: 4 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,10 @@

get '/account' => 'accounts#show'
get '/account/connected_accounts' => 'accounts/connected_accounts#show'
get '/account/connected_accounts/:identity_id/selected_email' => 'accounts/connected_accounts/selected_email#edit',
as: :edit_connected_account_selected_email
patch '/account/connected_accounts/:identity_id/selected_email' => 'accounts/connected_accounts/selected_email#update',
as: :connected_account_selected_email
post '/account/reauthentication' => 'accounts#reauthentication'
get '/account/devices/:id/events' => 'events#show', as: :account_events
get '/account/delete' => 'users/delete#show', as: :account_delete
Expand Down
16 changes: 16 additions & 0 deletions spec/components/status_page_component_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@
expect(rendered).to have_link('Option', href: '/')
end

it 'does not render page footer' do
rendered = render_inline(StatusPageComponent.new)

expect(rendered).not_to have_css('.page-footer')
end

it 'validates status' do
expect do
render_inline StatusPageComponent.new(status: :foo)
Expand All @@ -76,4 +82,14 @@
render_inline StatusPageComponent.new(status: :info)
end.to raise_error(ActiveModel::ValidationError)
end

context 'with footer' do
it 'renders page footer' do
rendered = render_inline(StatusPageComponent.new) do |c|
c.with_footer.with_content('Footer')
end

expect(rendered).to have_css('.page-footer', text: 'Footer')
end
end
end
Loading