Skip to content

Commit

Permalink
Merge pull request #4663 from codeforamerica/TBE-85-Bugcrowd-Authoriz…
Browse files Browse the repository at this point in the history
…ation-to-be-added

TBE 85 Bugcrowd: Add verification for emails for unsubscribe/subscribe
  • Loading branch information
jnf authored Aug 14, 2024
2 parents 1cdb55e + 3d9116d commit e924553
Show file tree
Hide file tree
Showing 17 changed files with 235 additions and 68 deletions.
33 changes: 33 additions & 0 deletions app/controllers/concerns/email_subscription_updater_concern.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module EmailSubscriptionUpdaterConcern
extend ActiveSupport::Concern

def update_email_subscription(direction:, column_name:, show_flash_and_render: false)
verifier = ActiveSupport::MessageVerifier.new(Rails.application.secret_key_base)

if params[:email_address].blank?
flash[:alert] = I18n.t("notifications_settings.no_record")
return
end

begin
email_address = verifier.verify(params[:email_address])
matching_intakes = matching_intakes(email_address)

if matching_intakes.present?
matching_intakes.each do |intake|
intake.update(column_name => direction)
end

if show_flash_and_render
flash[:notice] = I18n.t("notifications_settings.subscribe_to_emails.flash")
render :unsubscribe_from_emails
end
else
flash[:alert] = I18n.t("notifications_settings.no_record")
end
rescue ActiveSupport::MessageVerifier::InvalidSignature
flash[:alert] = I18n.t("notifications_settings.invalid_link")
end
end
end

26 changes: 3 additions & 23 deletions app/controllers/notifications_settings_controller.rb
Original file line number Diff line number Diff line change
@@ -1,35 +1,15 @@
class NotificationsSettingsController < ApplicationController
include EmailSubscriptionUpdaterConcern

def unsubscribe_from_emails
matching_intakes = matching_intakes(params[:email_address])

if matching_intakes.present?
matching_intakes.each do |intake|
intake.update(email_notification_opt_in: "no")
end
else
flash[:alert] = "No record found"
end
update_email_subscription(direction: "no", column_name: :email_notification_opt_in)
end

def subscribe_to_emails
matching_intakes = matching_intakes(params[:email_address])

if matching_intakes.present?
matching_intakes.each do |intake|
intake.update(email_notification_opt_in: "yes")
end

flash[:notice] = I18n.t("notifications_settings.subscribe_to_emails.flash")
render :unsubscribe_from_emails
else
flash[:alert] = "No record found"
end
update_email_subscription(direction: "yes", column_name: :email_notification_opt_in, show_flash_and_render: true)
end

private


def matching_intakes(email_address)
return if email_address.blank?

Expand Down
28 changes: 5 additions & 23 deletions app/controllers/state_file/notifications_settings_controller.rb
Original file line number Diff line number Diff line change
@@ -1,32 +1,14 @@
module StateFile
class NotificationsSettingsController < ApplicationController
layout "state_file"
include EmailSubscriptionUpdaterConcern

def unsubscribe_email
matching_intakes = matching_intakes(params[:email_address])

if matching_intakes.present?
matching_intakes.each do |intake|
intake.update(unsubscribed_from_email: true)
end
else
flash[:alert] = "No record found"
end
def unsubscribe_from_emails
update_email_subscription(direction: true, column_name: :unsubscribed_from_email)
end

def subscribe_email
matching_intakes = matching_intakes(params[:email_address])

if matching_intakes.present?
matching_intakes.each do |intake|
intake.update(unsubscribed_from_email: false)
end

flash[:notice] = I18n.t("state_file.notifications_settings.subscribe_email.flash")
render :unsubscribe_email
else
flash[:alert] = "No record found"
end
def subscribe_to_emails
update_email_subscription(direction: false, column_name: :unsubscribed_from_email, show_flash_and_render: true)
end

private
Expand Down
6 changes: 5 additions & 1 deletion app/mailers/diy_intake_email_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ def high_support_message(diy_intake:)
@diy_intake = diy_intake
service = MultiTenantService.new(:gyr)
attachments.inline['logo.png'] = service.email_logo

verifier = ActiveSupport::MessageVerifier.new(Rails.application.secret_key_base)
signed_email = verifier.generate(diy_intake.email_address)

@unsubscribe_link = Rails.application.routes.url_helpers.url_for(
{
host: MultiTenantService.new(:gyr).host,
controller: "notifications_settings",
action: :unsubscribe_from_emails,
locale: I18n.locale,
_recall: {},
email_address: diy_intake.email_address
email_address: signed_email
}
)
I18n.with_locale(diy_intake.locale) do
Expand Down
5 changes: 4 additions & 1 deletion app/mailers/outgoing_email_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ def user_message(outgoing_email:)

@body = outgoing_email.body

verifier = ActiveSupport::MessageVerifier.new(Rails.application.secret_key_base)
signed_email = verifier.generate(outgoing_email.to)

@unsubscribe_link = Rails.application.routes.url_helpers.url_for(
{
host: MultiTenantService.new(:gyr).host,
controller: "notifications_settings",
action: :unsubscribe_from_emails,
locale: I18n.locale,
_recall: {},
email_address: outgoing_email.to
email_address: signed_email
}
)
@subject = outgoing_email.subject
Expand Down
8 changes: 6 additions & 2 deletions app/mailers/state_file/notification_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ def user_message(notification_email:)
service = MultiTenantService.new(:statefile)
@body = notification_email.body
attachments.inline['logo.png'] = service.email_logo

verifier = ActiveSupport::MessageVerifier.new(Rails.application.secret_key_base)
signed_email = verifier.generate(notification_email.to)

@unsubscribe_link = Rails.application.routes.url_helpers.url_for(
{
host: MultiTenantService.new(:statefile).host,
controller: "state_file/notifications_settings",
action: :unsubscribe_email,
action: :unsubscribe_from_emails,
locale: I18n.locale,
_recall: {},
email_address: notification_email.to
email_address: signed_email
}
)
mail(
Expand Down
5 changes: 4 additions & 1 deletion app/mailers/user_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@ def assignment_email(
service = MultiTenantService.new(:gyr)
attachments.inline['logo.png'] = service.email_logo

verifier = ActiveSupport::MessageVerifier.new(Rails.application.secret_key_base)
signed_email = verifier.generate(@assigned_user.email)

@unsubscribe_link = Rails.application.routes.url_helpers.url_for(
{
host: MultiTenantService.new(:gyr).host,
controller: "notifications_settings",
action: :unsubscribe_from_emails,
locale: I18n.locale,
_recall: {},
email_address: @assigned_user.email
email_address: signed_email
}
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<p>
<%= t(".mistake") %>
<%= link_to t(".link_text"), state_file_subscribe_email_path(email_address: params[:email_address]), method: :post %>
<%= link_to t(".link_text"), state_file_subscribe_to_emails_path(email_address: params[:email_address]), method: :post %>
</p>

<p><%= t(".help_text_html") %></p>
Expand Down
6 changes: 3 additions & 3 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1773,6 +1773,8 @@ en:
intake:
your_spouse: Your spouse
notifications_settings:
invalid_link: Invalid subscription link
no_record: No record found
subscribe_to_emails:
flash: You are successfully re-subscribed to email notifications.
unsubscribe_from_emails:
Expand Down Expand Up @@ -2096,9 +2098,7 @@ en:
user_message:
unsubscribe: If you would like to unsubscribe from emails, click <a href="%{unsubscribe_link}">here</a>.
notifications_settings:
subscribe_email:
flash: You are successfully re-subscribed to email notifications.
unsubscribe_email:
unsubscribe_from_emails:
help_text_html: If you change your mind and would like to opt in later, <a class="open-intercom">chat with us</a> or email us at <a href="mailto:[email protected]">[email protected].</a>
link_text: Opt in again.
mistake: Is this a mistake?
Expand Down
6 changes: 3 additions & 3 deletions config/locales/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1737,6 +1737,8 @@ es:
intake:
your_spouse: Su cónyuge
notifications_settings:
invalid_link: Enlace de suscripción no válido
no_record: Ningún record fue encontrado
subscribe_to_emails:
flash: Te has vuelto a suscribir con éxito a las notificaciones por correo electrónico.
unsubscribe_from_emails:
Expand Down Expand Up @@ -2060,9 +2062,7 @@ es:
user_message:
unsubscribe: Si deseas cancelar la suscripción a los correos electrónicos, haz clic <a href="%{unsubscribe_link}">aquí</a>.
notifications_settings:
subscribe_email:
flash: Has sido exitosamente re-suscrito a las notificaciones por correo electrónico.
unsubscribe_email:
unsubscribe_from_emails:
help_text_html: Si cambias de opinión y deseas suscribirte más tarde, <a class="open-intercom">chatea con nosotros</a> o envíanos un correo electrónico a <a href="mailto:[email protected]">[email protected].</a>
link_text: Vuelve a suscribirte.
mistake: "¿Es un error?"
Expand Down
4 changes: 2 additions & 2 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -612,8 +612,8 @@ def scoped_navigation_routes(context, navigation)
get "/coming-soon", to: "state_file_pages#coming_soon"
post "/clear_session", to: 'state_file_pages#clear_session'
get "/privacy-policy", to: "state_file_pages#privacy_policy"
get "/unsubscribe_email", to: "notifications_settings#unsubscribe_email", as: :unsubscribe_email
post "/subscribe_email", to: "notifications_settings#subscribe_email", as: :subscribe_email
get "/unsubscribe_from_emails", to: "notifications_settings#unsubscribe_from_emails", as: :unsubscribe_from_emails
post "/subscribe_to_emails", to: "notifications_settings#subscribe_to_emails", as: :subscribe_to_emails
end
end
end
Expand Down
87 changes: 87 additions & 0 deletions spec/controllers/notifications_settings_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
require "rails_helper"

RSpec.describe NotificationsSettingsController do
describe "#unsubscribe_from_emails" do
render_views

let!(:intake) { create :intake, email_address: "[email protected]", email_notification_opt_in: "yes" }
let(:verifier) { ActiveSupport::MessageVerifier.new(Rails.application.secret_key_base) }
let(:signed_email) { verifier.generate("[email protected]") }
let(:signed_email_without_intake) { verifier.generate("[email protected]") }

it "unsubscribes the intake from email" do
get :unsubscribe_from_emails, params: { email_address: signed_email }

expect(intake.reload.email_notification_opt_in).to eq "no"
expect(response.body).to include subscribe_to_emails_path(email_address: signed_email)
end

context "no matching intakes" do
it "shows a message" do
get :unsubscribe_from_emails, params: { email_address: signed_email_without_intake }

expect(flash[:alert]).to eq "No record found"
end
end

context "unsigned email" do
it "shows a message" do
get :unsubscribe_from_emails, params: { email_address: "[email protected]" }

expect(flash[:alert]).to eq "Invalid subscription link"
end
end

context "no email address" do
let!(:intake) { create :intake, email_address: nil }

it "does not match with intakes that have nil email address" do
get :unsubscribe_from_emails

expect(flash[:alert]).to eq "No record found"
end
end
end

describe "#subscribe_to_emails" do
let!(:intake) { create :intake, email_address: "[email protected]", email_notification_opt_in: "no" }
let!(:matching_intake) { create :intake, email_address: "[email protected]", email_notification_opt_in: "no" }
let(:verifier) { ActiveSupport::MessageVerifier.new(Rails.application.secret_key_base) }
let(:signed_email) { verifier.generate("[email protected]") }
let(:signed_email_without_intake) { verifier.generate("[email protected]") }

it "resubscribes all intakes with matching email to email notifications" do
post :subscribe_to_emails, params: { email_address: signed_email }

expect(intake.reload.email_notification_opt_in).to eq "yes"
expect(matching_intake.reload.email_notification_opt_in).to eq "yes"
expect(flash[:notice]).to eq "You are successfully re-subscribed to email notifications."
end

context "no matching intakes" do
it "shows a message" do
get :subscribe_to_emails, params: { email_address: signed_email_without_intake }

expect(flash[:alert]).to eq "No record found"
end
end

context "unsigned email" do
it "shows a message" do
get :subscribe_to_emails, params: { email_address: "[email protected]" }

expect(flash[:alert]).to eq "Invalid subscription link"
end
end

context "no email address" do
let!(:intake) { create :intake, email_address: nil }

it "does not match with intakes that have nil email address" do
get :subscribe_to_emails

expect(flash[:alert]).to eq "No record found"
end
end
end
end
Loading

0 comments on commit e924553

Please sign in to comment.