rubygems/rubygems.org

View on GitHub
app/avo/actions/base_action.rb

Summary

Maintainability
A
0 mins
Test Coverage
class BaseAction < Avo::BaseAction
  include SemanticLogger::Loggable

  field :comment, as: :textarea, required: true,
    help: "A comment explaining why this action was taken.<br>Will be saved in the audit log.<br>Must be more than 10 characters."

  def self.inherited(base)
    super
    base.items_holder = Avo::ItemsHolder.new
    base.items_holder.instance_variable_get(:@items).replace items_holder.instance_variable_get(:@items).deep_dup
    base.items_holder.invalid_fields.replace items_holder.invalid_fields.deep_dup
  end

  class ActionHandler
    include Auditable
    include SemanticLogger::Loggable

    include ActiveSupport::Callbacks
    define_callbacks :handle, terminator: lambda { |target, result_lambda|
      result_lambda.call
      target.errored?
    }
    define_callbacks :handle_model, terminator: lambda { |target, result_lambda|
      result_lambda.call
      target.errored?
    }
    define_callbacks :handle_standalone, terminator: lambda { |target, result_lambda|
      result_lambda.call
      target.errored?
    }

    def initialize( # rubocop:disable Metrics/ParameterLists
      fields:,
      current_user:,
      arguments:,
      resource:,
      action:,
      models: nil
    )
      @models = models
      @fields = fields
      @current_user = current_user
      @arguments = arguments
      @resource = resource

      @action = action
    end

    attr_reader :models, :fields, :current_user, :arguments, :resource

    delegate :error, :avo, :keep_modal_open, :redirect_to, :inform, :action_name, :succeed, :logger,
      to: :@action

    set_callback :handle, :before do
      error "Must supply a sufficiently detailed comment" unless fields[:comment].presence&.then { _1.length >= 10 }
    end

    set_callback :handle, :around, lambda { |_, block|
      begin
        block.call
      rescue StandardError => e
        Rails.error.report(e, handled: true)
        error e.message.truncate(300)
      end
    }

    def do_handle
      run_callbacks :handle do
        handle
      end
    ensure
      keep_modal_open if errored?
    end

    def do_handle_model(model)
      run_callbacks :handle_model do
        handle_model(model)
      end
    end

    def errored?
      @action.response[:messages].any? { _1[:type] == :error }
    end

    def do_handle_standalone
      _, audit = in_audited_transaction(
        auditable: :return,
        admin_github_user: current_user,
        action: action_name,
        fields:,
        arguments:,
        models:
      ) do
        run_callbacks :handle_standalone do
          handle_standalone
        end
      end
      redirect_to avo.resources_audit_path(audit)
    end

    def handle
      return do_handle_standalone if models.nil?
      models.each do |model|
        _, audit = in_audited_transaction(
          auditable: model,
          admin_github_user: current_user,
          action: action_name,
          fields:,
          arguments:,
          models:
        ) do
          do_handle_model(model)
        end
        redirect_to avo.resources_audit_path(audit)
      end
    end
  end

  def handle(**args)
    "#{self.class}::ActionHandler"
      .constantize
      .new(**args, arguments:, action: self)
      .do_handle
  end
end