BookingSync/bookingsync-engine

View on GitHub
lib/bookingsync/engine/auth_helpers.rb

Summary

Maintainability
A
0 mins
Test Coverage
require "repost"

module BookingSync::Engine::AuthHelpers
  extend ActiveSupport::Concern

  included do
    rescue_from OAuth2::Error, with: :handle_oauth_error
    rescue_from BookingSync::API::Unauthorized, with: :reset_authorization!
    if respond_to?(:helper_method)
      helper_method :current_account
    end
  end

  private

  # @return [Account, nil] currently authorized Account or nil if unauthorized
  def current_account
    return if session[:account_id].nil?

    @current_account ||=
      ::BookingSyncEngine.account_model.find_by_host_and_bookingsync_id_key(request.host, session[:account_id])
  end

  # Callback after account is authorized.
  #
  # Stores the authorized account's synced_id in the session.
  #
  # @param account [Account] the just authorized account
  def account_authorized(account)
    session[:account_id] = account.public_send(BookingSyncEngine.bookingsync_id_key).to_s
  end

  # Clear authorization if the account passed from the BookingSync app store
  # embed doesn't match the currently authorized account
  def enforce_requested_account_authorized!
    clear_authorization! unless requested_account_authorized?
  end

  # Checks if the account requested from the BookingSync app store embed
  # matches currently authorized account.
  def requested_account_authorized?
    session[:_bookingsync_account_id].blank? ||
      session[:_bookingsync_account_id] == session[:account_id]
  end

  # Removes the authorization from session. Will not redirect to any other
  # page, see {#reset_authorization!}
  def clear_authorization!
    session[:account_id] = nil
  end

  # Removes authorization from session and requests new authorization.
  # For removing authorization without redirecting, see {#clear_authorization!}.
  def reset_authorization!
    session[:_bookingsync_account_id] =
      params[:account_id].presence || session[:account_id]
    clear_authorization!
    request_authorization!
  end

  # Request a new authorization.
  def request_authorization!
    respond_to do |format|
      format.html do
        if request.xhr?
          request_authorization_for_xhr!
        elsif BookingSync::Engine.embedded
          request_authorization_for_embedded!
        else
          request_authorization_for_standalone!
        end
      end

      format.json do
        head :unauthorized
      end

      format.api_json do
        head :unauthorized
      end
    end
  end

  # Request a new authorization for Ajax requests.
  #
  # Renders the new auto submit form with 401 Unauthorized status by default.
  def request_authorization_for_xhr!
    render html: auto_submit_form_html, status: :unauthorized
  end

  # Request a new authorization for Embedded Apps.
  #
  # Load the new authorization path using Javascript by default.
  def request_authorization_for_embedded!
    allow_bookingsync_iframe
    render html: auto_submit_form_html
  end

  # Request a new authorization for Standalone Apps.
  #
  # Redirects to new authorization path by default.
  def request_authorization_for_standalone!
    render html: auto_submit_form_html
  end

  # Path which will be used in POST request to start a new
  # Authorization process.
  #
  # Default to /auth/bookingsync
  NEW_AUTHORIZATION_URL = "/auth/bookingsync".freeze
  def new_authorization_path
    NEW_AUTHORIZATION_URL
  end

  def new_authorization_url
    request.base_url + new_authorization_path
  end

  # Handler to rescue OAuth errors
  #
  # @param error [OAuth2::Error] the rescued error
  def handle_oauth_error(error)
    if error.code == "Not authorized"
      current_account.try(:clear_token!)
      reset_authorization!
    else
      raise
    end
  end

  # Path to which the user should be redirected after successful authorization.
  # This method should be overridden in applications using this engine.
  #
  # Defaults to root_path.
  def after_bookingsync_sign_in_path
    root_path
  end

  # Path to which the user should be redirected after sign out.
  # This method should be overridden in applications using this engine.
  #
  # Defaults to root_path.
  def after_bookingsync_sign_out_path
    root_path
  end

  # Requests authorization if not currently authorized.
  def authenticate_account!
    store_bookingsync_account_id if BookingSync::Engine.embedded
    sign_out_if_inactive
    enforce_requested_account_authorized!
    request_authorization! if current_account.nil?
  end

  def store_bookingsync_account_id # :nodoc:
    session[:_bookingsync_account_id] = params.delete(:_bookingsync_account_id)
  end

  def auto_submit_form_html
    Repost::Senpai.perform(
      new_authorization_path,
      params: { account_id: session[:_bookingsync_account_id] },
      options: { authenticity_token: Rack::Protection::AuthenticityToken.token(session) }
    ).html_safe
  end
end