3scale/porta

View on GitHub
app/controllers/concerns/error_handling.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

module ErrorHandling
  extend ActiveSupport::Concern

  included do
    include Handlers
    rescue_from ActiveRecord::RecordNotFound, with: :handle_not_found
    rescue_from WillPaginate::InvalidPage, with: :handle_not_found
    before_bugsnag_notify :add_user_info_to_bugsnag
    # rescue_from StandardError, :with => :handle_server_error
  end

  module Handlers
    protected

    def handle_server_error(exception)
      System::ErrorReporting.report_error(exception)
      handle_error(exception, :internal_server_error)
    end

    def handle_not_found(exception)
      handle_error(exception, :not_found)
    end

    def handle_access_denied(exception)
      handle_error(exception, :forbidden)
    end

    def handle_forgery_protection(exception)
      System::ErrorReporting.report_error(exception) if params[:authenticity_token].present?
      handle_error(exception, :forbidden)
    end

    def log_error(exception, status)
      logger.error "Handling Exception: #{exception} with status #{status}"
      logger.debug exception.backtrace.join("\n") if exception&.backtrace
    end

    def handle_error(exception, status)
      log_error(exception, status)
      @_exception_handled = exception

      # our tests are sending this format without appropriate accepts header
      # request.format = :html if request.format.url_encoded_form

      # this is prepared for handling errors in js/json/xml
      title = status.to_s.humanize

      respond_to do |format|
        format.html do
          if Account.is_admin_domain?(request.internal_host) || site_account.master?
            handle_provider_side(status, exception, title)
          else
            handle_buyer_side(status)
          end
        end

        format.json { render json: {status: title}, status: status }

        format.xml  { head status }

        format.any  { render plain: title, status: status }
      end
    end

    def add_user_info_to_bugsnag(notification)
      # Set the user that this bug affected
      # Email, name and id are searchable on bugsnag.com
      site_account = try(:site_account)
      current_user = User.current
      current_account = current_user.try(:account)

      notification.user = {
        provider: site_account.try(:org_name),
          provider_id: site_account.try(:id),
          email: current_user.try(:email),
          account_id: current_account.try(:id),
          id: current_user.try(:id)
      }

      # Add some app-specific data which will be displayed on a custom
      # "Provider" tab on each error page on bugsnag.com
      notification.add_metadata(:provider, {
                                  name: site_account.try(:org_name),
                                  admin_domain: site_account.try(:self_domain),
                                  domain: site_account.try(:domain)
                                })
    end

    def handle_provider_side(status, exception, title)
      render layout: "error",
             template: "errors/provider/#{status}",
             status: status,
             locals: { exception: exception, title: title,
                            site_account: defined?(site_account) ? site_account : Account.master }
    end

    def handle_buyer_side(status)
      add_liquid_view_paths

      page_name = "errors/#{status}"

      if (error_page = site_account.builtin_pages.find_by(system_name: page_name))
        assign_drops page: Liquid::Drops::Page.new(error_page)
        layout = error_page.layout&.system_name
      end

      render page_name, layout: layout || 'error', status: status, handlers: [:liquid]
    end
  end
end