18F/identity-idp

View on GitHub
app/controllers/users/email_confirmations_controller.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
# frozen_string_literal: true

module Users
  class EmailConfirmationsController < ApplicationController
    def create
      result = email_confirmation_token_validator.submit
      analytics.add_email_confirmation(**result.to_h)
      if result.success?
        process_successful_confirmation(email_address)
      else
        process_unsuccessful_confirmation
      end
    end

    private

    def email_address
      return @email_address if defined?(@email_address)

      email_address = EmailAddress.find_with_confirmation_token(
        confirmation_params[:confirmation_token],
      )
      if email_address&.user&.confirmed?
        @email_address = email_address
      else
        @email_address = nil
      end
    end

    def email_confirmation_token_validator
      @email_confirmation_token_validator ||= begin
        EmailConfirmationTokenValidator.new(
          email_address,
          current_user,
        )
      end
    end

    def email_address_already_confirmed?
      email_confirmation_token_validator.email_address_already_confirmed?
    end

    def process_successful_confirmation(email_address)
      confirm_and_notify(email_address)
      if current_user
        flash[:success] = t('devise.confirmations.confirmed')
        redirect_to account_url
      else
        flash[:success] = t('devise.confirmations.confirmed_but_sign_in')
        redirect_to root_url
      end
    end

    def confirm_and_notify(email_address)
      email_address.update!(confirmed_at: Time.zone.now)
      email_address.user.confirmed_email_addresses.each do |confirmed_email_address|
        UserMailer.with(user: email_address.user, email_address: confirmed_email_address).
          email_added.deliver_now_or_later
      end
      notify_subscribers(email_address)
    end

    def notify_subscribers(email_address)
      user = email_address.user
      email_event = PushNotification::EmailChangedEvent.new(user: user, email: email_address.email)
      PushNotification::HttpPush.deliver(email_event)
      recovery_event = PushNotification::RecoveryInformationChangedEvent.new(user: user)
      PushNotification::HttpPush.deliver(recovery_event)
    end

    def process_unsuccessful_confirmation
      return process_already_confirmed_user if email_address_already_confirmed?
      flash[:error] = t('errors.messages.confirmation_invalid_token')
      redirect_to root_url
    end

    def process_already_confirmed_user
      flash[:error] = message_for_already_confirmed_user
      redirect_to current_user ? account_url : root_url
    end

    def message_for_already_confirmed_user
      if email_address_already_confirmed_by_current_user?
        t('devise.confirmations.already_confirmed', action: nil)
      elsif user_signed_in?
        t('devise.confirmations.confirmed_but_remove_from_other_account', app_name: APP_NAME)
      else
        action_text = t('devise.confirmations.sign_in')
        t('devise.confirmations.already_confirmed', action: action_text)
      end
    end

    def email_address_already_confirmed_by_current_user?
      user_signed_in? &&
        email_confirmation_token_validator.email_address_already_confirmed_by_user?(current_user)
    end

    def confirmation_params
      params.permit(:confirmation_token)
    end
  end
end