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

Open
wants to merge 51 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 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
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,16 @@
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
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
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.save
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 )
create_state_file_access_log(0)

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

def check_feature_flag
unless Flipper.enabled?(:get_your_pdf)
redirect_to root_path
end
end

end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
module StateFile
module ArchivedIntakes
class VerificationCodeController < ArchivedIntakeController
before_action :check_feature_flag
def edit
if current_request.access_locked?
redirect_to root_path
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)

if @form.valid?
create_state_file_access_log(1)
current_request.reset_failed_attempts!
redirect_to root_path
DrewProebstel marked this conversation as resolved.
Show resolved Hide resolved
else
create_state_file_access_log(2)
current_request.increment_failed_attempts
if current_request.access_locked?
create_state_file_access_log(6)
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

def check_feature_flag
unless Flipper.enabled?(:get_your_pdf)
redirect_to root_path
end
end
end
end
end
21 changes: 21 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,21 @@
module StateFile
module ArchivedIntakes
class EmailAddressForm < Form
attr_accessor :email_address

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

def initialize(attributes = {})
super
assign_attributes(attributes)
end

def save
run_callbacks :save do
valid?
end
end
end
end
end
30 changes: 30 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,30 @@
module StateFile
module ArchivedIntakes
class VerificationCodeForm < Form
attr_accessor :verification_code, :email_address

validates :verification_code, presence: true
def initialize(attributes = {}, email_address: nil)
super(attributes)
@email_address = email_address
assign_attributes(attributes)
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

def save
run_callbacks :save do
valid?
end
end
end
end
end
12 changes: 12 additions & 0 deletions app/jobs/archived_intake_email_verification_code_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class ArchivedIntakeEmailVerificationCodeJob < ApplicationJob
retry_on Mailgun::CommunicationError

def priority
PRIORITY_HIGH - 1 # Subtracting one to push to the top of the queue
end

# def perform(email_address: nil, locale:)
def perform(email_address:, locale:)
ArchivedIntakeEmailVerificationCodeService.request_code(email_address: email_address, locale: locale)
end
end
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
enum event_type: {
issued_email_challenge: 0,
correct_email_code: 1,
Expand Down
38 changes: 38 additions & 0 deletions app/models/state_file_archived_intake_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# == Schema Information
#
# Table name: state_file_archived_intake_requests
#
# id :bigint not null, primary key
# details :jsonb
# 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
# Include default devise modules. Others available are:
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
end
4 changes: 2 additions & 2 deletions app/models/state_file_base_intake.rb
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,8 @@ def synchronize_df_w2s_to_database
box_14_values[deduction[:other_description]] = deduction[:other_amount]
end
state_file_w2.assign_attributes(
box14_ui_wf_swf: box_14_values['UIWFSWF'],
box14_ui_hc_wd: box_14_values['UIHCWD'],
box14_ui_wf_swf: box_14_values['UI/WF/SWF'],
box14_ui_hc_wd: box_14_values['UI/HC/WD'],
box14_fli: box_14_values['FLI'],
box14_stpickup: box_14_values['STPICKUP'],
employer_ein: direct_file_w2.EmployerEIN,
Expand Down
19 changes: 19 additions & 0 deletions app/services/archived_intake_email_verification_code_service.rb
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
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: 'example@email.com', 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("state_file.questions.email_address.edit.action") %>
</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 @@ -42,4 +42,13 @@
</div>
<% end %>
</section>
<% end %>
<% end %>

<div>
<% if Flipper.enabled?(:get_your_pdf) %>
<%= 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>
<% end %>
</div>
12 changes: 12 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2063,6 +2063,16 @@ 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>
faq:
index:
title: Common questions from %{state} taxpayers
Expand Down Expand Up @@ -3828,6 +3838,7 @@ en:
<strong>We're closed for the tax season. Unfortunately you can no longer file your state return with us this year.</strong><br /><br />
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
looking_for_return_html: "<strong>Looking for your 2023 Arizona or New York State Tax Return?</strong>"
section1_html: |
<strong>How does it work?</strong>
<ol class="list--numbered">
Expand All @@ -3842,6 +3853,7 @@ en:
subheader_1_html: "<strong>FileYourStateTaxes</strong> integrates with <strong>IRS Direct File</strong> to help you complete your state tax return <strong>for free.</strong>"
subheader_2_html: IRS Direct File is now broadly available to all eligible taxpayers through April 15, 2024. For more information on timeline and eligibility, or to start filing your federal return, go to <strong><a target="_blank" rel="nofollow noopener" href="https://directfile.irs.gov/">directfile.irs.gov</a></strong>
subheader_3_html: Already filed your federal return with IRS Direct File and need to complete your state return? <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