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

Fyst 1516 add email validation step to prior year access flow #5300

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
30dd34b
i don't know why i had to do this
jnf Dec 27, 2024
2d1f3f1
can navigate to email address page
Dec 27, 2024
36a8be4
rename files and add link
Dec 27, 2024
eb43c45
delete unused controller
Dec 27, 2024
ca18535
remove unused data migration
Dec 27, 2024
a8ad9db
i18n health
Dec 27, 2024
1cfc369
intake archiving (models and migrations) (#5299)
jnf Dec 27, 2024
5b22894
wip
Dec 28, 2024
a32e759
merge in migrations
Dec 28, 2024
a0969e3
wip
Dec 30, 2024
f1e5246
Fyst 1515 add prior year access link button to homepage (#5296)
DrewProebstel Dec 30, 2024
234b1e3
wip
Jan 2, 2025
1b95140
Merge branch 'main' into FYST-1466-prior-year-access-mvp
jnf Jan 6, 2025
0798ab6
email form is not using questions controller
Jan 6, 2025
4181a66
update unused file
Jan 6, 2025
5162bf6
remove unused prys
Jan 6, 2025
c39a237
pages navigate
Jan 6, 2025
be8795e
Revert "Fyst 1515 add prior year access link button to homepage (#529…
DrewProebstel Jan 6, 2025
e7d479c
Merge remote-tracking branch 'origin/FYST-1466-prior-year-access-mvp'…
Jan 6, 2025
90da001
delete unused views
Jan 6, 2025
10b64ec
Merge remote-tracking branch 'origin/main' into FYST-1466-prior-year-…
anisharamnani Jan 6, 2025
e3be6ee
some tests
Jan 7, 2025
4bc1aaf
update schema
Jan 7, 2025
8b830ce
Add last year verification email (#5314)
squanto Jan 7, 2025
32803b9
wip
Jan 7, 2025
9b26ce6
Merge branch 'FYST-1466-prior-year-access-mvp' into FYST-1516-add-ema…
Jan 7, 2025
cff9432
verification code is being sent
Jan 7, 2025
a9df1c4
remove pry
Jan 7, 2025
8d0787e
adds missing form
Jan 7, 2025
01a2ea6
wip
Jan 8, 2025
9fa60cb
add devise table
Jan 9, 2025
33a7375
add flipper
Jan 9, 2025
7b4a3eb
improved flipper
Jan 9, 2025
192cecc
update tests
Jan 10, 2025
a6edbfd
remove redunt column for access logs
Jan 10, 2025
a75955b
update some tests
Jan 10, 2025
b5ec8d3
remove a save and open
Jan 10, 2025
48a8f45
fixes a test
Jan 10, 2025
d3e415f
Merge branch 'refs/heads/main' into FYST-1466-prior-year-access-mvp
mpidcock Jan 10, 2025
ad8f820
Add data backfill task for StateFileArchivedIntake (#5305)
jnf Jan 10, 2025
72af870
wip
Jan 10, 2025
2daf9d2
Add Lockable Devise Attributes to State File Archived Requests
anisharamnani Jan 10, 2025
d49f10c
Merge branch 'refs/heads/main' into FYST-1466-prior-year-access-mvp
mpidcock Jan 10, 2025
5206023
update lockout time to 1 hour
Jan 10, 2025
d357bbc
annotate
mpidcock Jan 10, 2025
dc36bc6
remove uneeded change
Jan 10, 2025
77f5d38
merged
Jan 10, 2025
aea0433
update formating
Jan 11, 2025
e0e9bd1
annotate
Jan 11, 2025
b44de74
merge main
Jan 11, 2025
a9218ae
i18n health
Jan 13, 2025
d92c736
Merge branch 'main' into FYST-1516-add-email-validation-step-to-prior…
Jan 13, 2025
2a67c98
return remove changes to base intake
Jan 13, 2025
8ff20b5
updates after review
Jan 13, 2025
85fe8b2
Add feature spec for prior year access flow
anisharamnani Jan 13, 2025
6b2ed42
remove unncessary fields from intake requests and access logs
anisharamnani Jan 13, 2025
cd48cc0
pr review changes
Jan 14, 2025
016c423
merge main
Jan 14, 2025
1ff7332
update archive intake request factory to allow intake to be nil'
Jan 14, 2025
9364004
write specs for the mailer
Jan 14, 2025
d3c660d
remove old verification code for previous year job
anisharamnani Jan 14, 2025
49c8800
Unignore locale test so that it will fail when translations are added
anisharamnani Jan 14, 2025
347645d
Merge remote-tracking branch 'origin/main' into FYST-1516-add-email-v…
anisharamnani Jan 14, 2025
495406f
merge main
Jan 14, 2025
884e042
adds a test for nil archived intake
Jan 14, 2025
7c0bd3c
Add test verifying that PDF Access is hidden
anisharamnani Jan 14, 2025
94035b6
fix bug where email was not displayed
Jan 14, 2025
3f68533
Merge branch 'FYST-1516-add-email-validation-step-to-prior-year-acces…
Jan 14, 2025
94ec192
merge main
Jan 14, 2025
0c89122
i18n
Jan 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module StateFile
module ArchivedIntakes
class ArchivedIntakeController < ApplicationController
def current_request
StateFileArchivedIntakeRequest.find_by(ip_address: ip_for_irs, email_address: session[:email_address])
end

def create_state_file_access_log(event_type)
StateFileArchivedIntakeAccessLog.create!(
event_type: event_type,
state_file_archived_intake_request: current_request
)
end

def check_feature_flag
unless Flipper.enabled?(:get_your_pdf)
# this redirect to be changed when we have an offboarding page
redirect_to root_path
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module StateFile
module ArchivedIntakes
class EmailAddressController < ArchivedIntakeController
before_action :check_feature_flag
def edit
@form = EmailAddressForm.new
end

def update
@form = EmailAddressForm.new(email_address_form_params)

if @form.valid?
archived_intake = StateFileArchivedIntake.find_by(email_address: @form.email_address)
session[:email_address] = @form.email_address
StateFileArchivedIntakeRequest.find_or_create_by(email_address: @form.email_address, ip_address: ip_for_irs, state_file_archived_intakes_id: archived_intake&.id )
DrewProebstel marked this conversation as resolved.
Show resolved Hide resolved
create_state_file_access_log("issued_email_challenge")

redirect_to state_file_archived_intakes_edit_verification_code_path
else
render :edit
end
end

private

def email_address_form_params
params.require(:state_file_archived_intakes_email_address_form).permit(:email_address)
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
module StateFile
module ArchivedIntakes
class VerificationCodeController < ArchivedIntakeController
before_action :check_feature_flag
def edit
if current_request.access_locked?
DrewProebstel marked this conversation as resolved.
Show resolved Hide resolved
# this redirect to be changed when we have an offboarding page
redirect_to root_path
DrewProebstel marked this conversation as resolved.
Show resolved Hide resolved
return
end
@form = VerificationCodeForm.new(email_address: current_request.email_address)
@email_address = current_request.email_address
ArchivedIntakeEmailVerificationCodeJob.perform_later(
email_address: @email_address,
locale: I18n.locale
)
end

def update
@form = VerificationCodeForm.new(verification_code_form_params, email_address: current_request.email_address)
@email_address = current_request.email_address

if @form.valid?
create_state_file_access_log("correct_email_code")
current_request.reset_failed_attempts!
# this should take us to the ssn page
redirect_to root_path
DrewProebstel marked this conversation as resolved.
Show resolved Hide resolved
else
create_state_file_access_log("incorrect_email_code")
current_request.increment_failed_attempts
if current_request.access_locked?
create_state_file_access_log("client_lockout_begin")
# this redirect to be changed when we have an offboarding page
redirect_to root_path
return
end
render :edit
end
end

private

def verification_code_form_params
params.require(:state_file_archived_intakes_verification_code_form).permit(:verification_code)
end
end
end
end
10 changes: 10 additions & 0 deletions app/forms/state_file/archived_intakes/email_address_form.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module StateFile
module ArchivedIntakes
class EmailAddressForm < Form
attr_accessor :email_address

validates :email_address, presence: true, 'valid_email_2/email': true

end
end
end
23 changes: 23 additions & 0 deletions app/forms/state_file/archived_intakes/verification_code_form.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module StateFile
module ArchivedIntakes
class VerificationCodeForm < Form
attr_accessor :verification_code, :email_address
Copy link
Contributor

@jenny-heath jenny-heath Jan 13, 2025

Choose a reason for hiding this comment

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

sorry i should have asked this during the mob review but why attr_accessor instead of set_attributes_for? is it because we're not actually updating any db records?


validates :verification_code, presence: true
def initialize(attributes = {}, email_address: nil)
super(attributes)
@email_address = email_address
end

def valid?
hashed_verification_code = VerificationCodeService.hash_verification_code_with_contact_info(@email_address, verification_code)

valid_code = EmailAccessToken.lookup(hashed_verification_code).exists?

errors.add(:verification_code, I18n.t("state_file.archived_intakes.verification_code.edit.error_message")) unless valid_code

valid_code.present?
end
end
end
end
11 changes: 11 additions & 0 deletions app/jobs/archived_intake_email_verification_code_job.rb
DrewProebstel marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class ArchivedIntakeEmailVerificationCodeJob < ApplicationJob
retry_on Mailgun::CommunicationError

def priority
PRIORITY_HIGH - 1 # Subtracting one to push to the top of the queue
Copy link
Contributor

Choose a reason for hiding this comment

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

is this normal? seems weird to me

Copy link
Contributor

@arinchoi03 arinchoi03 Jan 13, 2025

Choose a reason for hiding this comment

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

this seemed weird to me too but it seems like we use this pattern 🙈 maybe there should be PRIORITY_IMMEDIATE or something...PRIORITY_HIGHEST?

end

def perform(email_address:, locale:)
ArchivedIntakeEmailVerificationCodeService.request_code(email_address: email_address, locale: locale)
Copy link
Contributor

Choose a reason for hiding this comment

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

[pebble] also i wanted to point out here, if you're renaming this file in your PR, you'd want to delete the old one too. i don't see that happening in the PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

fixed this!

end
end
11 changes: 0 additions & 11 deletions app/jobs/request_verification_code_for_previous_year_job.rb

This file was deleted.

2 changes: 1 addition & 1 deletion app/models/state_file_archived_intake.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@
#
class StateFileArchivedIntake < ApplicationRecord
has_one_attached :submission_pdf
has_many :access_logs, class_name: 'StateFileArchivedIntakeAccessLog'
has_many :intake_requests, class_name: 'StateFileArchivedIntakeRequest'
end
21 changes: 8 additions & 13 deletions app/models/state_file_archived_intake_access_log.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,19 @@
#
# Table name: state_file_archived_intake_access_logs
#
# id :bigint not null, primary key
# details :jsonb
# event_type :integer
# ip_address :string
# created_at :datetime not null
# updated_at :datetime not null
# state_file_archived_intakes_id :bigint
#
# Indexes
#
# idx_on_state_file_archived_intakes_id_e878049c06 (state_file_archived_intakes_id)
# id :bigint not null, primary key
# details :jsonb
# event_type :integer
# created_at :datetime not null
# updated_at :datetime not null
# state_file_archived_intake_request_id :bigint
#
# Foreign Keys
#
# fk_rails_... (state_file_archived_intakes_id => state_file_archived_intakes.id)
# fk_rails_... (state_file_archived_intake_request_id => state_file_archived_intake_requests.id)
#
class StateFileArchivedIntakeAccessLog < ApplicationRecord
belongs_to :state_file_archived_intake
belongs_to :state_file_archived_intake_request, optional: true
enum event_type: {
issued_email_challenge: 0,
correct_email_code: 1,
Expand Down
36 changes: 36 additions & 0 deletions app/models/state_file_archived_intake_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# == Schema Information
#
# Table name: state_file_archived_intake_requests
#
# id :bigint not null, primary key
# email_address :string
# failed_attempts :integer default(0), not null
# ip_address :string
# locked_at :datetime
# created_at :datetime not null
# updated_at :datetime not null
# state_file_archived_intakes_id :bigint
#
# Indexes
#
# idx_on_state_file_archived_intakes_id_31501c23f8 (state_file_archived_intakes_id)
#
# Foreign Keys
#
# fk_rails_... (state_file_archived_intakes_id => state_file_archived_intakes.id)
#
class StateFileArchivedIntakeRequest < ApplicationRecord
devise :lockable, unlock_in: 60.minutes, unlock_strategy: :time
has_many :access_logs, class_name: 'StateFileArchivedIntakeAccessLog'

def self.maximum_attempts
2
end

def increment_failed_attempts
super
if attempts_exceeded? && !access_locked?
lock_access!
end
end
DrewProebstel marked this conversation as resolved.
Show resolved Hide resolved
end
19 changes: 19 additions & 0 deletions app/services/archived_intake_email_verification_code_service.rb
DrewProebstel marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class ArchivedIntakeEmailVerificationCodeService
def initialize(email_address: , locale: :en)
@email_address = email_address
@locale = locale
end

def request_code
verification_code, = EmailAccessToken.generate!(email_address: @email_address)
VerificationCodeMailer.archived_intake_verification_code(
to: @email_address,
verification_code: verification_code,
locale: @locale
).deliver_now
end

def self.request_code(**args)
new(**args).request_code
end
DrewProebstel marked this conversation as resolved.
Show resolved Hide resolved
end
21 changes: 21 additions & 0 deletions app/views/state_file/archived_intakes/email_address/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<% title = t(".enter_email") %>
<% content_for :page_title, title %>
<section class="slab question-layout <%= controller_name.gsub("_", "-") %>-outer">
<div class="grid">
<div class="grid__item question-wrapper">
<h1 class="h2" id="main-question"><%= title %></h1>
<%= form_with model: @form, url: state_file_archived_intakes_email_address_path, local: true, method: :patch, builder: VitaMinFormBuilder do |f| %>
<div class="white-group">
<%= f.cfa_input_field(:email_address, t("state_file.questions.email_address.edit.email_address_label"), help_text: '[email protected]', classes: ["form-width--long"]) %>
</div>

<div class="form-actions">
<button type="submit" class="button button--primary button--wide spacing-below-15">
<%= t("state_file.questions.email_address.edit.action") %>
</button>
</div>
<% end %>
</div>
</div>
</section>

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<% title = t(".title_html", email_address: @email_address) %>
<section class="slab question-layout <%= controller_name.gsub("_", "-") %>-outer">
<div class="grid">
<div class="grid__item question-wrapper">
<div class="grid__item question-wrapper">
<% content_for :page_title, title %>
<%= form_with model: @form, url: { action: :update }, local: true, method: :patch, builder: VitaMinFormBuilder do |f| %>
<h1 class="h2" id="main-question"><%= title %></h1>
<p><%= t(".subtitle_html") %></p>
<p><%= t(".subtitle_html_2") %></p>
<div class="white-group">
<%= f.cfa_input_field(:verification_code, t("state_file.questions.verification_code.edit.verification_code_label"), classes: ["form-width--long"]) %>
</div>
<div class="form-actions">
<button type="submit" class="button button--primary button--wide spacing-below-15">
<%= t(".verify") %>
</button>
</div>
<% end %>
</div>
</div>
</div>
</section>
11 changes: 10 additions & 1 deletion app/views/state_file/state_file_pages/about_page.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,13 @@
</div>
<% end %>
</section>
<% end %>
<% end %>

<% if Flipper.enabled?(:get_your_pdf) %>
<div>
<%= t(".looking_for_return_html")%>
<div class = "spacing-above-10">
<%= link_to t(".tax_return_link"), state_file_archived_intakes_edit_email_address_path %>
</div>
</div>
DrewProebstel marked this conversation as resolved.
Show resolved Hide resolved
<% end %>
13 changes: 13 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2063,6 +2063,17 @@ en:
04_detail_links_html: See our <a href="%{terms_link}" target="_blank" rel="noopener noreferrer">Terms and Conditions</a> and <a href="%{privacy_link}" target="_blank" rel="noopener noreferrer">Privacy Policy.</a>
subheader: Please sign up here to receive a notification when we open in January.
state_file:
archived_intakes:
email_address:
edit:
enter_email: Enter the email address linked to your account
verification_code:
edit:
error_message: Incorrect verification code. After 2 failed attempts, accounts are locked.
subtitle_html: If you didn’t receive a code, please check your spam folder.
subtitle_html_2: If you still need help resubscribing, chat with us.
title_html: We’ve sent your code to <strong>%{email_address}</strong>
verify: Verify code
faq:
index:
title: Common questions from %{state} taxpayers
Expand Down Expand Up @@ -3900,6 +3911,7 @@ en:
Already filed your state taxes with us? <strong>You can download a copy of your state return until December 31, 2024</strong><br /><br />
header: A free state filing service for taxpayers using IRS Direct File
helper_heading_html: "<strong>How does this service work? </strong>"
looking_for_return_html: "<strong>Looking for your 2023 Arizona or New York State Tax Return?</strong>"
section1_html: |
<ol class="list--numbered" style="padding-left: 2rem">
<li>File and submit your federal return with <a target="_blank" rel="nofollow noopener" href="https://directfile.irs.gov/">IRS Direct File</a> before using this service.</li>
Expand All @@ -3919,6 +3931,7 @@ en:
<strong>In 2025, this service will support filing state tax returns in Arizona, Idaho, North Carolina, New Jersey, and Maryland.</strong>
subheader_2_html: To start filing your federal return, go to <a target="_blank" rel="nofollow noopener" href="https://directfile.irs.gov/">directfile.irs.gov.</a>
subheader_3_html: "<strong>Already filed your federal return with IRS Direct File and need to complete your state return?</strong> <a href=%{login_path}>Sign in here</a>."
tax_return_link: Click here to access your tax return
card_postscript:
responses_saved_html: Your responses are saved. If you need a break, you can come back and log in to your account at <a href="https://fileyourstatetaxes.org">fileyourstatetaxes.org</a>.
coming_soon:
Expand Down
Loading
Loading