diff --git a/app/controllers/state_file/questions/email_address_controller.rb b/app/controllers/state_file/questions/email_address_controller.rb deleted file mode 100644 index 4eed05430f..0000000000 --- a/app/controllers/state_file/questions/email_address_controller.rb +++ /dev/null @@ -1,9 +0,0 @@ -module StateFile - module Questions - class EmailAddressController < QuestionsController - def self.show?(intake) - intake.contact_preference == "email" - end - end - end -end \ No newline at end of file diff --git a/app/controllers/state_file/questions/email_sign_up_controller.rb b/app/controllers/state_file/questions/email_sign_up_controller.rb new file mode 100644 index 0000000000..91237d176c --- /dev/null +++ b/app/controllers/state_file/questions/email_sign_up_controller.rb @@ -0,0 +1,95 @@ +module StateFile + module Questions + class EmailSignUpController < QuestionsController + + def self.show?(intake) + intake.contact_preference == "email" + end + + def edit + # Show the email address form + super + end + + def create + # Send a verification code to the email address + # Show the form which will collect the verification code + @form = initialized_update_form + if @form.valid? + send_verification_code + else + after_update_failure + track_validation_error + render :edit + end + end + + def update + @form = initialized_update_form + if @form.valid? && @form.verification_code_valid? + intake = current_intake + existing_intake = get_existing_intake(intake, @form.contact_info) + if existing_intake.present? + redirect_into_login(@form.contact_info, intake, existing_intake) + return + end + @form.save + after_update_success + track_question_answer + redirect_to(next_path) + else + after_update_failure + track_validation_error + render :create + end + end + + private + + def send_verification_code + RequestVerificationCodeEmailJob.perform_later( + email_address: @form.email_address, + locale: I18n.locale, + visitor_id: current_intake.visitor_id, + client_id: nil, + service_type: :statefile + ) + end + + def get_existing_intake(intake, contact_info) + search = intake.class.where.not(id: intake.id) + search = search.where(email_address: contact_info) + search.first + end + + def redirect_into_login(contact_info, intake, existing_intake) + hashed_verification_code = VerificationCodeService.hash_verification_code_with_contact_info( + @form.contact_info, @form.verification_code + ) + @form.intake = existing_intake + intake.destroy unless intake.id == existing_intake.id + sign_in existing_intake + if existing_intake.raw_direct_file_data.present? + redirect_to IntakeLoginsController.to_path_helper( + action: :edit, + id: hashed_verification_code, + us_state: params[:us_state] + ) + else + redirect_to(next_path) + end + end + + def after_update_success + messaging_service = StateFile::MessagingService.new( + message: StateFile::AutomatedMessage::Welcome, + intake: current_intake, + sms: false, + email: true, + body_args: {intake_id: current_intake.id} + ) + messaging_service.send_message + end + end + end +end \ No newline at end of file diff --git a/app/controllers/state_file/questions/phone_number_controller.rb b/app/controllers/state_file/questions/phone_number_controller.rb deleted file mode 100644 index 2460e0a22f..0000000000 --- a/app/controllers/state_file/questions/phone_number_controller.rb +++ /dev/null @@ -1,9 +0,0 @@ -module StateFile - module Questions - class PhoneNumberController < QuestionsController - def self.show?(intake) - intake.contact_preference == "text" - end - end - end -end \ No newline at end of file diff --git a/app/controllers/state_file/questions/phone_number_sign_up_controller.rb b/app/controllers/state_file/questions/phone_number_sign_up_controller.rb new file mode 100644 index 0000000000..80e64c06fe --- /dev/null +++ b/app/controllers/state_file/questions/phone_number_sign_up_controller.rb @@ -0,0 +1,40 @@ +module StateFile + module Questions + class PhoneNumberSignUpController < EmailSignUpController + + def self.show?(intake) + intake.contact_preference == "text" + end + + private + + def send_verification_code + RequestVerificationCodeTextMessageJob.perform_later( + phone_number: @form.phone_number, + locale: I18n.locale, + visitor_id: current_intake.visitor_id, + client_id: nil, + service_type: :statefile + ) + end + + def get_existing_intake(intake, contact_info) + search = intake.class.where.not(id: intake.id) + search = search.where(phone_number: contact_info) + search.first + end + + def after_update_success + messaging_service = StateFile::MessagingService.new( + message: StateFile::AutomatedMessage::Welcome, + intake: current_intake, + sms: true, + email: false, + body_args: {intake_id: current_intake.id} + ) + messaging_service.send_message + end + + end + end +end \ No newline at end of file diff --git a/app/controllers/state_file/questions/verification_code_controller.rb b/app/controllers/state_file/questions/verification_code_controller.rb deleted file mode 100644 index 8588f87037..0000000000 --- a/app/controllers/state_file/questions/verification_code_controller.rb +++ /dev/null @@ -1,79 +0,0 @@ -module StateFile - module Questions - class VerificationCodeController < QuestionsController - def edit - # TODO: Sending a code here feels icky. By convention, edit should not trigger mutations - case current_intake.contact_preference - when "text" - RequestVerificationCodeTextMessageJob.perform_later( - phone_number: current_intake.phone_number, - locale: I18n.locale, - visitor_id: current_intake.visitor_id, - client_id: nil, - service_type: :statefile - ) - @contact_info = PhoneParser.formatted_phone_number(current_intake.phone_number) - when "email" - RequestVerificationCodeEmailJob.perform_later( - email_address: current_intake.email_address, - locale: I18n.locale, - visitor_id: current_intake.visitor_id, - client_id: nil, - service_type: :statefile - ) - @contact_info = current_intake.email_address - end - super - end - - def update - @form = initialized_update_form - if @form.valid? - intake = current_intake - existing_intake = get_existing_intake(intake) - if existing_intake.present? - redirect_into_login(intake, existing_intake) and return - end - @form.save - after_update_success - track_question_answer - redirect_to(next_path) - else - after_update_failure - track_validation_error - render :edit - end - end - - private - - def get_existing_intake(intake) - search = intake.class.where.not(id: intake.id, raw_direct_file_data: nil) - search = search.where(phone_number: intake.phone_number) if intake.phone_number.present? - search = search.where(email_address: intake.email_address) if intake.email_address.present? - search.first - end - - def redirect_into_login(intake, existing_intake) - contact_info = ( - if intake.contact_preference == "email" - intake.email_address - else - intake.phone_number - end - ) - hashed_verification_code = VerificationCodeService.hash_verification_code_with_contact_info( - contact_info, @form.verification_code - ) - @form.intake = existing_intake - intake.destroy unless intake.id == existing_intake.id - sign_in existing_intake - redirect_to IntakeLoginsController.to_path_helper( - action: :edit, - id: hashed_verification_code, - us_state: params[:us_state] - ) - end - end - end -end \ No newline at end of file diff --git a/app/forms/state_file/email_sign_up_form.rb b/app/forms/state_file/email_sign_up_form.rb new file mode 100644 index 0000000000..b8dd85066c --- /dev/null +++ b/app/forms/state_file/email_sign_up_form.rb @@ -0,0 +1,42 @@ +module StateFile + class EmailSignUpForm < QuestionsForm + set_attributes_for :intake, :email_address + attr_accessor :verification_code + + validates :email_address, 'valid_email_2/email': true + validates :email_address, presence: true + + def save + @intake.update(attributes_for(:intake).merge(email_address_verified_at: DateTime.now)) + end + + def contact_info + email_address + end + + def verification_code_valid? + hashed_verification_code = VerificationCodeService.hash_verification_code_with_contact_info(email_address, verification_code) + # Magic codes provide a way of bypassing security in a development context. + # The easiest way to do this was to update the last entry to actually have the magic code. + if Rails.configuration.allow_magic_verification_code && verification_code == "000000" + token = EmailAccessToken.where(email_address: email_address).last + if token.present? + token.update( + token: Devise.token_generator.digest(EmailAccessToken, :token, hashed_verification_code), + ) + end + return true + end + + valid_code = EmailAccessToken.lookup(hashed_verification_code).exists? + + errors.add(:verification_code, I18n.t("views.questions.verification.error_message")) unless valid_code + + valid_code.present? + end + + def self.attribute_names + [:email_address, :verification_code] + end + end +end \ No newline at end of file diff --git a/app/forms/state_file/phone_number_sign_up_form.rb b/app/forms/state_file/phone_number_sign_up_form.rb new file mode 100644 index 0000000000..5c111dd182 --- /dev/null +++ b/app/forms/state_file/phone_number_sign_up_form.rb @@ -0,0 +1,37 @@ +module StateFile + class PhoneNumberSignUpForm < QuestionsForm + set_attributes_for :intake, :phone_number + + before_validation :normalize_phone_number + attr_accessor :verification_code + validates :phone_number, e164_phone: true + + def save + @intake.update(attributes_for(:intake).merge(phone_number_verified_at: DateTime.now)) + end + + def contact_info + PhoneParser.formatted_phone_number(phone_number) + end + + def normalize_phone_number + self.phone_number = PhoneParser.normalize(phone_number) if phone_number.present? + end + + def verification_code_valid? + return true if Rails.configuration.allow_magic_verification_code && verification_code == "000000" + + hashed_verification_code = VerificationCodeService.hash_verification_code_with_contact_info(phone_number, verification_code) + + valid_code = TextMessageAccessToken.lookup(hashed_verification_code).exists? + + errors.add(:verification_code, I18n.t("views.ctc.questions.verification.error_message")) unless valid_code + + valid_code.present? + end + + def self.attribute_names + [:phone_number, :verification_code] + end + end +end \ No newline at end of file diff --git a/app/forms/state_file/verification_code_form.rb b/app/forms/state_file/verification_code_form.rb deleted file mode 100644 index fa7c02d145..0000000000 --- a/app/forms/state_file/verification_code_form.rb +++ /dev/null @@ -1,44 +0,0 @@ -module StateFile - class VerificationCodeForm < QuestionsForm - set_attributes_for :misc, :verification_code - - def valid? - # Delegate validation to a phone or email verification form. - # If there's no contact preference, use the email form. - validation_form_class = is_text_based? ? PhoneVerificationForm : EmailVerificationForm - form = validation_form_class.new(intake, attributes_for(:misc)) - is_valid = form.valid? - unless is_valid - errors.add(:verification_code, form.errors[:verification_code]) - end - - is_valid - end - - def save - is_first_time_verifying = intake.phone_number_verified_at.blank? && intake.email_address_verified_at.blank? - intake.touch(:phone_number_verified_at) if is_text_based? - intake.touch(:email_address_verified_at) if is_email_based? - if is_first_time_verifying - messaging_service = StateFile::MessagingService.new( - message: StateFile::AutomatedMessage::Welcome, - intake: intake, - sms: is_text_based?, - email: is_email_based?, - body_args: {intake_id: intake.id} - ) - messaging_service.send_message - end - end - - private - - def is_text_based? - intake.contact_preference == "text" - end - - def is_email_based? - intake.contact_preference == "email" - end - end -end \ No newline at end of file diff --git a/app/lib/navigation/state_file_az_question_navigation.rb b/app/lib/navigation/state_file_az_question_navigation.rb index c26370a33d..aa3a439792 100644 --- a/app/lib/navigation/state_file_az_question_navigation.rb +++ b/app/lib/navigation/state_file_az_question_navigation.rb @@ -15,9 +15,8 @@ class StateFileAzQuestionNavigation ]), Navigation::NavigationSection.new("state_file.navigation.section_2", [ Navigation::NavigationStep.new(StateFile::Questions::ContactPreferenceController), - Navigation::NavigationStep.new(StateFile::Questions::PhoneNumberController), - Navigation::NavigationStep.new(StateFile::Questions::EmailAddressController), - Navigation::NavigationStep.new(StateFile::Questions::VerificationCodeController), + Navigation::NavigationStep.new(StateFile::Questions::PhoneNumberSignUpController), + Navigation::NavigationStep.new(StateFile::Questions::EmailSignUpController), Navigation::NavigationStep.new(StateFile::Questions::CodeVerifiedController), ]), Navigation::NavigationSection.new("state_file.navigation.section_3", [ diff --git a/app/lib/navigation/state_file_ny_question_navigation.rb b/app/lib/navigation/state_file_ny_question_navigation.rb index 081af91c3c..81831dfdab 100644 --- a/app/lib/navigation/state_file_ny_question_navigation.rb +++ b/app/lib/navigation/state_file_ny_question_navigation.rb @@ -16,9 +16,8 @@ class StateFileNyQuestionNavigation ]), Navigation::NavigationSection.new("state_file.navigation.section_2", [ Navigation::NavigationStep.new(StateFile::Questions::ContactPreferenceController), - Navigation::NavigationStep.new(StateFile::Questions::PhoneNumberController), - Navigation::NavigationStep.new(StateFile::Questions::EmailAddressController), - Navigation::NavigationStep.new(StateFile::Questions::VerificationCodeController), + Navigation::NavigationStep.new(StateFile::Questions::PhoneNumberSignUpController), + Navigation::NavigationStep.new(StateFile::Questions::EmailSignUpController), Navigation::NavigationStep.new(StateFile::Questions::CodeVerifiedController), ]), Navigation::NavigationSection.new("state_file.navigation.section_3", [ diff --git a/app/views/state_file/intake_logins/new.html.erb b/app/views/state_file/intake_logins/new.html.erb index 9e7db2aa85..78f3e642ec 100644 --- a/app/views/state_file/intake_logins/new.html.erb +++ b/app/views/state_file/intake_logins/new.html.erb @@ -7,7 +7,7 @@
<%= f.cfa_input_field(@contact_method.to_sym, t(".#{@contact_method}.label"), classes: ["form-width--long"]) %>
- <%= f.submit t("state_file.questions.email_address.edit.action"), class: "button button--primary button--wide spacing-below-15" %> + <%= f.submit t("state_file.questions.email_sign_up.edit.action"), class: "button button--primary button--wide spacing-below-15" %> <% end %> <%= render 'state_file/questions/shared/verification_shortcut' %> <% end %> \ No newline at end of file diff --git a/app/views/state_file/questions/verification_code/edit.html.erb b/app/views/state_file/questions/email_sign_up/create.html.erb similarity index 65% rename from app/views/state_file/questions/verification_code/edit.html.erb rename to app/views/state_file/questions/email_sign_up/create.html.erb index a6f672372e..c79a4604b8 100644 --- a/app/views/state_file/questions/verification_code/edit.html.erb +++ b/app/views/state_file/questions/email_sign_up/create.html.erb @@ -2,10 +2,11 @@ <% content_for :page_title, title %> <% content_for :card do %> <%= form_with model: @form, url: { action: :update }, local: true, method: "put", builder: VitaMinFormBuilder do |f| %> + <%= f.hidden_field :email_address %>

<%= title %>

-

<%= t(".subtitle_html", contact_info: @contact_info) %>

+

<%= t(".subtitle_html", contact_info: @form.email_address) %>

- <%= f.cfa_input_field(:verification_code, t(".verification_code_label"), classes: ["form-width--long"]) %> + <%= f.cfa_input_field(:verification_code, t(".verification_code_label"), classes: ["form-width--long"]) %>
<%= f.submit t(".action"), class: "button button--primary button--wide spacing-below-15"%> <% end %> diff --git a/app/views/state_file/questions/phone_number/edit.html.erb b/app/views/state_file/questions/email_sign_up/edit.html.erb similarity index 50% rename from app/views/state_file/questions/phone_number/edit.html.erb rename to app/views/state_file/questions/email_sign_up/edit.html.erb index 357371af9e..54de57389e 100644 --- a/app/views/state_file/questions/phone_number/edit.html.erb +++ b/app/views/state_file/questions/email_sign_up/edit.html.erb @@ -3,13 +3,12 @@ <% content_for :card do %>

<%= title %>

- <%= form_with model: @form, url: { action: :update }, local: true, method: "put", builder: VitaMinFormBuilder do |f| %> + <%= form_with model: @form, url: { action: :create }, local: true, method: "post", builder: VitaMinFormBuilder do |f| %>
- <%= f.cfa_input_field(:phone_number, t(".phone_number_label"), classes: ["form-width--long"]) %> + <%= f.cfa_input_field(:email_address, t(".email_address_label"), classes: ["form-width--long"]) %>
- <%= f.submit t(".action"), class: "button button--primary button--wide spacing-below-15" %> - <% end %> - + <%= f.submit t(".action"), class: "button button--primary button--wide spacing-below-15" %> + <% end %> <%= render 'state_file/questions/shared/verification_shortcut' %> <% end %> diff --git a/app/views/state_file/questions/phone_number_sign_up/create.html.erb b/app/views/state_file/questions/phone_number_sign_up/create.html.erb new file mode 100644 index 0000000000..06fc351700 --- /dev/null +++ b/app/views/state_file/questions/phone_number_sign_up/create.html.erb @@ -0,0 +1,13 @@ +<% title = t(".title") %> +<% content_for :page_title, title %> +<% content_for :card do %> + <%= form_with model: @form, url: { action: :update }, local: true, method: "put", builder: VitaMinFormBuilder do |f| %> + <%= f.hidden_field :phone_number %> +

<%= title %>

+

<%= t(".subtitle_html", contact_info: PhoneParser.formatted_phone_number(@form.phone_number)) %>

+
+ <%= f.cfa_input_field(:verification_code, t(".verification_code_label"), classes: ["form-width--long"]) %> +
+ <%= f.submit t(".action"), class: "button button--primary button--wide spacing-below-15"%> + <% end %> +<% end %> diff --git a/app/views/state_file/questions/email_address/edit.html.erb b/app/views/state_file/questions/phone_number_sign_up/edit.html.erb similarity index 68% rename from app/views/state_file/questions/email_address/edit.html.erb rename to app/views/state_file/questions/phone_number_sign_up/edit.html.erb index d7b6276d8e..2a810f8aea 100644 --- a/app/views/state_file/questions/email_address/edit.html.erb +++ b/app/views/state_file/questions/phone_number_sign_up/edit.html.erb @@ -3,12 +3,13 @@ <% content_for :card do %>

<%= title %>

- <%= form_with model: @form, url: { action: :update }, local: true, method: "put", builder: VitaMinFormBuilder do |f| %> + <%= form_with model: @form, url: { action: :create }, local: true, method: "post", builder: VitaMinFormBuilder do |f| %>
- <%= f.cfa_input_field(:email_address, t(".email_address_label"), classes: ["form-width--long"]) %> + <%= f.cfa_input_field(:phone_number, t(".phone_number_label"), classes: ["form-width--long"]) %>
<%= f.submit t(".action"), class: "button button--primary button--wide spacing-below-15" %> <% end %> + <%= render 'state_file/questions/shared/verification_shortcut' %> <% end %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 5bc70b0faa..5d4c5b083b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2371,7 +2371,12 @@ en: subtractions_225_military: Military combat pay subtractions_225_native_american: Native American Income Exclusion subtractions_225_student_loan: Student loan forgiveness award - email_address: + email_sign_up: + create: + action: Verify code + subtitle_html: We’ve sent your code to %{contact_info}. + title: Enter the code to continue + verification_code_label: Enter the 6-digit code edit: action: Send code email_address_label: Your email address (use an email you can access) @@ -2568,7 +2573,12 @@ en: We’re sorry to keep you waiting. Your federal tax return must be accepted before you can file your state tax return.

You’ll receive an email from IRS Direct File when your federal tax return is accepted with a link to bring you back here. - phone_number: + phone_number_sign_up: + create: + action: Verify code + subtitle_html: We’ve sent your code to %{contact_info}. + title: Enter the code to continue + verification_code_label: Enter the 6-digit code edit: action: Send code phone_number_label: Your phone number @@ -2756,12 +2766,6 @@ en: delete_confirmation: Are you sure you want to delete this 1099-G? lets_review: Great! Thanks for sharing that information. Let’s review. unemployment_compensation: 'Unemployment compensation: $%{amount}' - verification_code: - edit: - action: Verify code - subtitle_html: We’ve sent your code to %{contact_info}. - title: Enter the code to continue - verification_code_label: Enter the 6-digit code w2: edit: box15_html: | diff --git a/config/locales/es.yml b/config/locales/es.yml index 5adfdeb33d..2a0ba078e2 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -2338,7 +2338,12 @@ es: subtractions_225_military: Pago por combate militar subtractions_225_native_american: Exclusión de ingresos para Nativos Americanos subtractions_225_student_loan: Premios por condonación de préstamos estudiantiles - email_address: + email_sign_up: + create: + action: Verificar el código + subtitle_html: Te enviamos tu código a %{contact_info}. + title: Ingresa el código para continuar + verification_code_label: Ingresa el código de 6 dígitos edit: action: Enviar el código email_address_label: Tu dirección de correo electrónico (utiliza un correo electrónico al que puedas acceder) @@ -2548,7 +2553,12 @@ es: Lamentamos hacerte esperar. Tu declaración federal debe ser aceptada antes de que puedas presentar tu declaración de impuestos estatales.

Recibirás un correo electrónico de IRS Direct File cuando tu declaración de impuestos federales sea aceptada con un enlace para traerte de vuelta aquí. - phone_number: + phone_number_sign_up: + create: + action: Verificar el código + subtitle_html: Te enviamos tu código a %{contact_info}. + title: Ingresa el código para continuar + verification_code_label: Ingresa el código de 6 dígitos edit: action: Enviar el código phone_number_label: Tu número de teléfono @@ -2737,12 +2747,6 @@ es: delete_confirmation: "¿Estás seguro de que quieres eliminar este formulario 1099-G?" lets_review: "¡Excelente! Gracias por compartir esa información. Revisémosla." unemployment_compensation: 'Compensación por desempleo: $%{amount}' - verification_code: - edit: - action: " Verificar el código" - subtitle_html: Te enviamos tu código a %{contact_info}. - title: Ingresa el código para continuar - verification_code_label: Ingresa el código de 6 dígitos w2: edit: box15_html: | diff --git a/config/routes.rb b/config/routes.rb index f38b83ef80..5cf8105cfe 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -583,6 +583,8 @@ def scoped_navigation_routes(context, navigation) match("/questions/pending-federal-return", action: :edit, controller: "state_file/questions/pending_federal_return", via: :get) match("/questions/pending_federal_return", action: :edit, controller: "state_file/questions/pending_federal_return", via: :get) resources :w2, only: [:index, :edit, :update, :create], module: 'state_file/questions', path: 'questions/w2' + resources :email_sign_up, only: [:edit, :create, :update], module: 'state_file/questions', path: 'questions/email-sign-up' + resources :phone_number_sign_up, only: [:edit, :create, :update], module: 'state_file/questions', path: 'questions/phone-number-sign-up' end scope ':us_state', as: 'az', constraints: { us_state: :az } do @@ -591,8 +593,6 @@ def scoped_navigation_routes(context, navigation) scope ':us_state', as: 'ny', constraints: { us_state: :ny } do scoped_navigation_routes(:questions, Navigation::StateFileNyQuestionNavigation) - # TODO: ny_w2 route can be deleted once no intake has w2 as the current step - resources :w2, only: [:index, :edit, :update, :create], module: 'state_file/questions', path: 'questions/ny_w2' end scope ':us_state', as: 'us', constraints: { us_state: :us } do diff --git a/spec/controllers/state_file/questions/email_address_controller_spec.rb b/spec/controllers/state_file/questions/email_address_controller_spec.rb deleted file mode 100644 index e752e13e9d..0000000000 --- a/spec/controllers/state_file/questions/email_address_controller_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -require 'rails_helper' - -RSpec.describe StateFile::Questions::EmailAddressController do - describe ".show?" do - context "when contact preference is email" do - it "returns true" do - intake = create(:state_file_az_intake, contact_preference: "email") - expect(described_class.show?(intake)).to eq true - end - end - - context "when contact preference is not email" do - it "returns false" do - intake = create(:state_file_az_intake) - expect(described_class.show?(intake)).to eq false - end - end - end -end \ No newline at end of file diff --git a/spec/controllers/state_file/questions/email_sign_up_controller_spec.rb b/spec/controllers/state_file/questions/email_sign_up_controller_spec.rb new file mode 100644 index 0000000000..469e8593e0 --- /dev/null +++ b/spec/controllers/state_file/questions/email_sign_up_controller_spec.rb @@ -0,0 +1,121 @@ +require 'rails_helper' + +RSpec.describe StateFile::Questions::EmailSignUpController do + render_views + let(:intake) { create(:state_file_az_intake, contact_preference: "email", visitor_id: "v1s1t1n9") } + before do + sign_in intake + end + + describe ".show?" do + context "when contact preference is email" do + it "returns true" do + expect(described_class.show?(intake)).to eq true + end + end + + context "when contact preference is not email" do + let(:intake) { create(:state_file_az_intake) } + + it "returns false" do + expect(described_class.show?(intake)).to eq false + end + end + end + + describe "#edit" do + + it "displays a form for entering an email address" do + get :edit, params: { us_state: "az" } + expect(response).to be_ok + expect(response.body).to have_text("Enter your email address") + end + end + + describe "#create" do + + it "enqueues a job to send verification code text message" do + expect { + post :create, params: { + us_state: "az", + state_file_email_sign_up_form: { + email_address: "admin@fileyourstatetaxes.org" + } + } + }.to have_enqueued_job(RequestVerificationCodeEmailJob).with( + email_address: "admin@fileyourstatetaxes.org", + locale: I18n.locale, + visitor_id: intake.visitor_id, + client_id: nil, + service_type: :statefile + ) + expect(response.body).to have_text("Enter the 6-digit code") + end + end + + describe "#update" do + let(:token) { EmailAccessToken.generate!(email_address: "admin@fileyourstatetaxes.org") } + let(:request_params) do + { + us_state: "az", + state_file_email_sign_up_form: { + email_address: "admin@fileyourstatetaxes.org", + verification_code: token[0] + } + } + end + + it "validates the access token" do + put :update, params: request_params + expect(response).to redirect_to( + StateFile::Questions::CodeVerifiedController.to_path_helper( + action: :edit, + us_state: "az" + ) + ) + end + + context "when the magic verification code is enabled" do + before do + allow(Rails.configuration).to receive(:allow_magic_verification_code).and_return(true) + end + let(:request_params) do + result = super() + result[:state_file_email_sign_up_form][:verification_code] = "000000" + result + end + + it "will accept the magic verification code as valid" do + put :update, params: request_params + expect(response).to redirect_to( + StateFile::Questions::CodeVerifiedController.to_path_helper( + action: :edit, + us_state: "az" + ) + ) + end + end + + context "with an intake matching an existing intake" do + before do + create(:state_file_az_intake, + contact_preference: "email", + email_address: "admin@fileyourstatetaxes.org", + visitor_id: "v1s1t1n9" + ) + end + + it "redirects to login" do + post :update, params: request_params + login_location = StateFile::IntakeLoginsController.to_path_helper( + action: :edit, + id: VerificationCodeService.hash_verification_code_with_contact_info( + "admin@fileyourstatetaxes.org", token[0] + ), + us_state: "az" + ) + expect(response).to redirect_to(login_location) + end + end + end +end \ No newline at end of file diff --git a/spec/controllers/state_file/questions/phone_number_controller_spec.rb b/spec/controllers/state_file/questions/phone_number_controller_spec.rb deleted file mode 100644 index cc639ecfbc..0000000000 --- a/spec/controllers/state_file/questions/phone_number_controller_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -require 'rails_helper' - -RSpec.describe StateFile::Questions::PhoneNumberController do - describe ".show?" do - context "when contact preference is text message" do - it "returns true" do - intake = create(:state_file_az_intake, contact_preference: "text") - expect(described_class.show?(intake)).to eq true - end - end - - context "when contact preference is not text message" do - it "returns false" do - intake = create(:state_file_az_intake) - expect(described_class.show?(intake)).to eq false - end - end - end -end \ No newline at end of file diff --git a/spec/controllers/state_file/questions/phone_number_sign_up_controller_spec.rb b/spec/controllers/state_file/questions/phone_number_sign_up_controller_spec.rb new file mode 100644 index 0000000000..6063ecb750 --- /dev/null +++ b/spec/controllers/state_file/questions/phone_number_sign_up_controller_spec.rb @@ -0,0 +1,46 @@ +require 'rails_helper' + +RSpec.describe StateFile::Questions::PhoneNumberSignUpController do + describe ".show?" do + context "when contact preference is text message" do + it "returns true" do + intake = create(:state_file_az_intake, contact_preference: "text") + expect(described_class.show?(intake)).to eq true + end + end + + context "when contact preference is not text message" do + it "returns false" do + intake = create(:state_file_az_intake) + expect(described_class.show?(intake)).to eq false + end + end + + describe "#update" do + let(:intake) { create(:state_file_az_intake, contact_preference: "text", visitor_id: "v1s1t1n9") } + before do + sign_in intake + end + let(:token) { TextMessageAccessToken.generate!(sms_phone_number: "+14155551212") } + let(:request_params) do + { + us_state: "az", + state_file_phone_number_sign_up_form: { + phone_number: "+14155551212", + verification_code: token[0] + } + } + end + + it "validates the access token" do + put :update, params: request_params + expect(response).to redirect_to( + StateFile::Questions::CodeVerifiedController.to_path_helper( + action: :edit, + us_state: "az" + ) + ) + end + end + end +end \ No newline at end of file diff --git a/spec/controllers/state_file/questions/verification_code_controller_spec.rb b/spec/controllers/state_file/questions/verification_code_controller_spec.rb deleted file mode 100644 index 016805fb6b..0000000000 --- a/spec/controllers/state_file/questions/verification_code_controller_spec.rb +++ /dev/null @@ -1,70 +0,0 @@ -require 'rails_helper' - -RSpec.describe StateFile::Questions::VerificationCodeController do - describe "#edit" do - before do - sign_in intake - end - - context "with an intake that prefers text message" do - let(:intake) { create(:state_file_az_intake, contact_preference: "text", phone_number: "+14153334444", visitor_id: "v1s1t1n9") } - - it "sets @contact_info to a pretty phone number" do - get :edit, params: { us_state: "az" } - - expect(assigns(:contact_info)).to eq "(415) 333-4444" - end - - it "enqueues a job to send verification code text message" do - expect { - get :edit, params: { us_state: "az" } - }.to have_enqueued_job(RequestVerificationCodeTextMessageJob).with( - phone_number: intake.phone_number, - locale: I18n.locale, - visitor_id: intake.visitor_id, - client_id: nil, - service_type: :statefile - ) - end - end - - context "with an intake that prefers email" do - let(:intake) { create(:state_file_az_intake, contact_preference: "email", email_address: "someone@example.com", visitor_id: "v1s1t1n9") } - - it "sets @contact_info to an email address" do - get :edit, params: { us_state: "az" } - - expect(assigns(:contact_info)).to eq "someone@example.com" - end - - it "enqueues a job to send verification code email" do - expect { - get :edit, params: { us_state: "az" } - }.to have_enqueued_job(RequestVerificationCodeEmailJob).with( - email_address: intake.email_address, - locale: I18n.locale, - visitor_id: intake.visitor_id, - client_id: nil, - service_type: :statefile - ) - end - end - - context "with an intake matching an existing intake" do - let(:intake) { create(:state_file_az_intake, contact_preference: "email", email_address: "someone@example.com", visitor_id: "v1s1t1n9") } - let(:token) { EmailAccessToken.generate!(email_address: "someone@example.com") } - - it "redirects to login" do - post :update, params: { us_state: "az", state_file_verification_code_form: { verification_code: token[0] }} - login_location = StateFile::IntakeLoginsController.to_path_helper( - action: :edit, - id: VerificationCodeService.hash_verification_code_with_contact_info( - "someone@example.com", token[0] - ), - us_state: "az" - ) - expect(response).to redirect_to(login_location) - end - end - end -end \ No newline at end of file diff --git a/spec/features/state_file/edit_return_spec.rb b/spec/features/state_file/edit_return_spec.rb index 651ad44844..af2c4b680d 100644 --- a/spec/features/state_file/edit_return_spec.rb +++ b/spec/features/state_file/edit_return_spec.rb @@ -70,7 +70,7 @@ expect(page).to have_text "Sign in with your email address" fill_in I18n.t("state_file.intake_logins.new.email_address.label"), with: email_address perform_enqueued_jobs do - click_on I18n.t("state_file.questions.email_address.edit.action") + click_on I18n.t("state_file.questions.email_sign_up.edit.action") end mail = ActionMailer::Base.deliveries.last diff --git a/spec/features/state_file/login_spec.rb b/spec/features/state_file/login_spec.rb index 8cf501ca29..4d467d5ce3 100644 --- a/spec/features/state_file/login_spec.rb +++ b/spec/features/state_file/login_spec.rb @@ -34,7 +34,7 @@ expect(page).to have_text "Sign in with your phone number" fill_in "Your phone number", with: phone_number perform_enqueued_jobs do - click_on I18n.t("state_file.questions.email_address.edit.action") + click_on I18n.t("state_file.questions.email_sign_up.edit.action") end expect(TwilioService).to have_received(:send_text_message).with( @@ -62,7 +62,7 @@ expect(page).to have_text "Sign in with your email address" fill_in I18n.t("state_file.intake_logins.new.email_address.label"), with: email_address perform_enqueued_jobs do - click_on I18n.t("state_file.questions.email_address.edit.action") + click_on I18n.t("state_file.questions.email_sign_up.edit.action") end mail = ActionMailer::Base.deliveries.last diff --git a/spec/forms/state_file/verification_code_form_spec.rb b/spec/forms/state_file/verification_code_form_spec.rb deleted file mode 100644 index 0359f2611f..0000000000 --- a/spec/forms/state_file/verification_code_form_spec.rb +++ /dev/null @@ -1,113 +0,0 @@ -require 'rails_helper' - -RSpec.describe StateFile::VerificationCodeForm do - let(:intake) { create :state_file_ny_intake } - - describe "#valid?" do - describe "verification_code" do - context "without a verification code" do - it "returns false and adds an error" do - form = described_class.new(intake, { verification_code: "" }) - - expect(form).not_to be_valid - expect(form.errors).to include(:verification_code) - end - end - - context "when the magic verification code is enabled" do - before do - allow(Rails.configuration).to receive(:allow_magic_verification_code).and_return(true) - end - - it "will accept the magic verification code as valid" do - form = described_class.new(intake, { verification_code: "000000" }) - expect(form).to be_valid - end - end - - context "when the intake is using email" do - let(:intake) { create :state_file_ny_intake, contact_preference: :email, email_address: "someone@example.com" } - - context "when the verification code with email has a match" do - let(:verification_code) do - EmailAccessToken.generate!(email_address: intake.email_address).first - end - - it "returns true" do - form = described_class.new(intake, { verification_code: verification_code }) - expect(form).to be_valid - end - end - - context "when there is no matching verification code with the same email" do - it "returns false and adds an error" do - form = described_class.new(intake, { verification_code: "123456" }) - expect(form).not_to be_valid - expect(form.errors).to include :verification_code - end - end - end - - context "when the intake is using text messaging" do - let(:intake) { create :state_file_ny_intake, contact_preference: :text, phone_number: "+14155551212" } - - context "when the verification code with phone number has a match" do - let(:verification_code) do - TextMessageAccessToken.generate!(sms_phone_number: intake.phone_number).first - end - - it "returns true" do - form = described_class.new(intake, { verification_code: verification_code }) - expect(form).to be_valid - end - end - - context "when there is no matching verification code with the same phone number" do - it "returns false and adds an error" do - form = described_class.new(intake, { verification_code: "123456" }) - expect(form).not_to be_valid - expect(form.errors).to include :verification_code - end - end - end - end - end - - describe "#save" do - context "when the intake is using email" do - - let(:intake) { create :state_file_ny_intake, contact_preference: :email, email_address: "someone@example.com" } - let(:verification_code) do - EmailAccessToken.generate!(email_address: intake.email_address).first - end - - it "timestamps the email verification" do - form = described_class.new(intake, verification_code: verification_code) - expect { - form.save - }.to change(intake, :email_address_verified_at).from(nil) - end - - it "sends a welcome email" do - form = described_class.new(intake, verification_code: verification_code) - expect { - form.save - }.to change { StateFileNotificationEmail.where(to: intake.email_address).count }.from(0).to(1) - end - end - - context "when the intake is using text message" do - let(:intake) { create :state_file_ny_intake, contact_preference: :text, phone_number: "+14155551212" } - let(:verification_code) do - TextMessageAccessToken.generate!(sms_phone_number: intake.phone_number).first - end - - it "timestamps the phone number verification" do - form = described_class.new(intake, verification_code: verification_code) - expect { - form.save - }.to change(intake, :phone_number_verified_at).from(nil) - end - end - end -end \ No newline at end of file diff --git a/spec/lib/navigation/state_file_az_question_navigation_spec.rb b/spec/lib/navigation/state_file_az_question_navigation_spec.rb index 84c29587a3..12cd62b7f8 100644 --- a/spec/lib/navigation/state_file_az_question_navigation_spec.rb +++ b/spec/lib/navigation/state_file_az_question_navigation_spec.rb @@ -11,9 +11,8 @@ StateFile::Questions::EligibilityOffboardingController, StateFile::Questions::EligibleController, StateFile::Questions::ContactPreferenceController, - StateFile::Questions::PhoneNumberController, - StateFile::Questions::EmailAddressController, - StateFile::Questions::VerificationCodeController, + StateFile::Questions::PhoneNumberSignUpController, + StateFile::Questions::EmailSignUpController, StateFile::Questions::CodeVerifiedController, StateFile::Questions::TermsAndConditionsController, StateFile::Questions::DeclinedTermsAndConditionsController, diff --git a/spec/lib/navigation/state_file_ny_question_navigation_spec.rb b/spec/lib/navigation/state_file_ny_question_navigation_spec.rb index 41b15c0273..8bd6d80dbf 100644 --- a/spec/lib/navigation/state_file_ny_question_navigation_spec.rb +++ b/spec/lib/navigation/state_file_ny_question_navigation_spec.rb @@ -12,9 +12,8 @@ StateFile::Questions::EligibilityOffboardingController, StateFile::Questions::EligibleController, StateFile::Questions::ContactPreferenceController, - StateFile::Questions::PhoneNumberController, - StateFile::Questions::EmailAddressController, - StateFile::Questions::VerificationCodeController, + StateFile::Questions::PhoneNumberSignUpController, + StateFile::Questions::EmailSignUpController, StateFile::Questions::CodeVerifiedController, StateFile::Questions::TermsAndConditionsController, StateFile::Questions::DeclinedTermsAndConditionsController, diff --git a/spec/models/efile_error_spec.rb b/spec/models/efile_error_spec.rb index 9c5a8ef7bd..51a2a7d921 100644 --- a/spec/models/efile_error_spec.rb +++ b/spec/models/efile_error_spec.rb @@ -53,7 +53,7 @@ "eligibility-out-of-state-income", "eligibility-residence", "eligible", - "email-address", + "email-sign-up", "esign-declaration", "federal-info", "initiate-data-transfer", @@ -69,14 +69,13 @@ "ny-spouse-state-id", "ny-third-party-designee", "nyc-residency", - "phone-number", + "phone-number-sign-up", "return-status", "submission-confirmation", "tax-refund", "taxes-owed", "terms-and-conditions", "unemployment", - "verification-code", "w2", "waiting-to-load-data" ] diff --git a/spec/support/helpers/state_file_intake_helper.rb b/spec/support/helpers/state_file_intake_helper.rb index 17d8eab653..74b3f4c961 100644 --- a/spec/support/helpers/state_file_intake_helper.rb +++ b/spec/support/helpers/state_file_intake_helper.rb @@ -38,8 +38,7 @@ def step_through_initial_authentication(contact_preference: :text_message) fill_in "Your phone number", with: "4153334444" click_on "Send code" - - expect(page).to have_text I18n.t("state_file.questions.verification_code.edit.title") + expect(page).to have_text I18n.t("state_file.questions.phone_number_sign_up.create.title") expect(page).to have_text "We’ve sent your code to (415) 333-4444." perform_enqueued_jobs @@ -49,10 +48,10 @@ def step_through_initial_authentication(contact_preference: :text_message) click_on "Email me a code" expect(page).to have_text "Enter your email address" - fill_in I18n.t("state_file.questions.email_address.edit.email_address_label"), with: "someone@example.com" + fill_in I18n.t("state_file.questions.email_sign_up.edit.email_address_label"), with: "someone@example.com" click_on "Send code" - expect(page).to have_text I18n.t("state_file.questions.verification_code.edit.title") + expect(page).to have_text I18n.t("state_file.questions.email_sign_up.create.title") expect(page).to have_text "We’ve sent your code to someone@example.com." perform_enqueued_jobs