class CmAdmin::Model

def actions(only: [], except: [])

Insert into actions according to config block
def actions(only: [], except: [])
  acts = CmAdmin::DEFAULT_ACTIONS.keys
  acts &= ([] << only).flatten if only.present?
  acts -= ([] << except).flatten if except.present?
  acts.each do |act|
    action_defaults = CmAdmin::DEFAULT_ACTIONS[act]
    @available_actions << CmAdmin::Models::Action.new(name: act.to_s, verb: action_defaults[:verb], path: action_defaults[:path])
  end
  @actions_set = true
end

def alert_box(options = {})

def alert_box(options = {})
  @alerts << CmAdmin::Models::Alert.new(options)
end

def custom_controller_action(action_name, params)

def custom_controller_action(action_name, params)
  current_action = CmAdmin::Models::Action.find_by(self, name: action_name.to_s)
  return unless current_action
  @current_action = current_action
  @ar_object = @ar_model.name.classify.constantize.find(params[:id])
  if @current_action.child_records
    child_records = @ar_object.send(@current_action.child_records)
    @associated_model = CmAdmin::Model.find_by(name: @ar_model.reflect_on_association(@current_action.child_records).klass.name)
    @associated_ar_object = if child_records.is_a? ActiveRecord::Relation
                              filter_by(params, child_records)
                            else
                              child_records
                            end
    return @ar_object, @associated_model, @associated_ar_object
  end
  @ar_object
end

def define_controller

If model is User, controller will be UsersController
Controller defined for each model
def define_controller
  if $available_actions.present?
    klass = Class.new(CmAdmin::ResourceController) do
      include Pundit::Authorization
      rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
      $available_actions.each do |action|
        define_method action.name.to_sym do
          # controller_name & action_name from ActionController
          @model = CmAdmin::Model.find_by(name: controller_name.classify)
          @model.params = params
          @action = CmAdmin::Models::Action.find_by(@model, name: action_name)
          @model.current_action = @action
          send(@action.controller_action_name, params)
          # @ar_object = @model.try(@action.parent || action_name, params)
        end
      end
      def pundit_user
        Current.user
      end
      private
      def user_not_authorized
        flash[:alert] = 'You are not authorized to perform this action.'
        redirect_to CmAdmin::Engine.mount_path + '/access-denied'
      end
    end
  end
  CmAdmin.const_set "#{@name}Controller", klass
end

def define_pundit_policy(ar_model)

def define_pundit_policy(ar_model)
  if $available_actions.present?
    klass = Class.new(ApplicationPolicy) do
      $available_actions.each do |action|
        define_method "#{action.name}?".to_sym do
          return false unless Current.user.respond_to?(:cm_role_id)
          return false if Current.user.cm_role.nil?
          Current.user.cm_role.cm_permissions.where(action_name: action.name, ar_model_name: ar_model.name).present?
        end
      end
    end
  end
  policy = CmAdmin.const_set "#{ar_model.name}Policy", klass
  $available_actions.each do |action|
    next if %w[custom_action_modal custom_action create update].include?(action.name)
    klass = Class.new(policy) do
      def initialize(user, scope)
        @user = user
        @scope = scope
      end
      define_method :resolve do
        # action_name = Current.request_params.dig("action")
        permission = Current.user.cm_role.cm_permissions.find_by(action_name: action.name, ar_model_name: ar_model.name)
        if permission.present? && permission.scope_name.present?
          scope.send(permission.scope_name)
        else
          scope.all
        end
      end
      private
      attr_reader :user, :scope
    end
    policy.const_set "#{action.name.classify}Scope", klass
  end
end

def filter_params(params)

Shared between export controller and resource controller
def filter_params(params)
  # OPTIMIZE: Need to check if we can permit the filter_params in a better way
  date_columns = filters.select { |x| x.filter_type.eql?(:date) }.map(&:db_column_name)
  range_columns = filters.select { |x| x.filter_type.eql?(:range) }.map(&:db_column_name)
  single_select_columns = filters.select { |x| x.filter_type.eql?(:single_select) }.map(&:db_column_name)
  multi_select_columns = filters.select { |x| x.filter_type.eql?(:multi_select) }.map { |x| Hash["#{x.db_column_name}", []] }
  params.require(:filters).permit(:search, date: date_columns, range: range_columns, single_select: single_select_columns, multi_select: multi_select_columns) if params[:filters]
end

def find_by(search_hash)

def find_by(search_hash)
  CmAdmin.config.cm_admin_models.find { |x| x.name == search_hash[:name] }
end

def formatted_name

def formatted_name
  @display_name != @name ? @display_name : @name.titleize
end

def importable(class_name:, importer_type:, sample_file_path: nil)

def importable(class_name:, importer_type:, sample_file_path: nil)
  @importer = CmAdmin::Models::Importer.new(class_name, importer_type, sample_file_path)
end

def initialize(entity, &block)

def initialize(entity, &block)
  @name = entity.name
  @display_name = entity.name
  @ar_model = entity
  @is_visible_on_sidebar = true
  @icon_name = 'fa fa-th-large'
  @available_actions ||= []
  @bulk_actions ||= []
  @additional_permitted_fields ||= []
  @current_action = nil
  @available_tabs ||= []
  @available_fields ||= { index: [], show: [], edit: [], new: [] }
  @params = nil
  @override_policy = false
  @filters ||= []
  @policy_scopes ||= [{ display_name: 'Full Access', scope_name: 'all' }]
  @sort_columns ||= []
  @default_sort_direction ||= 'asc'
  @alerts = []
  instance_eval(&block) if block_given?
  actions unless @actions_set
  $available_actions = @available_actions.dup
  define_controller
  define_pundit_policy(@ar_model) unless @override_policy
end

def initialize(user, scope)

def initialize(user, scope)
  @user = user
  @scope = scope
end

def model_name

def model_name
  @display_name.present? ? @display_name : @name
end

def override_pundit_policy(override_status = false)

def override_pundit_policy(override_status = false)
  @override_policy = override_status
end

def permit_additional_fields(fields = [])

def permit_additional_fields(fields = [])
  @additional_permitted_fields = fields
end

def pundit_user

def pundit_user
  Current.user
end

def set_display_name(name)

def set_display_name(name)
  @display_name = name
end

def set_icon(name)

def set_icon(name)
  @icon_name = name
end

def set_policy_scopes(scopes = [])

def set_policy_scopes(scopes = [])
  @policy_scopes = ([{ display_name: 'Full Access', scope_name: 'all' }] + scopes).uniq
end

def user_not_authorized

def user_not_authorized
  flash[:alert] = 'You are not authorized to perform this action.'
  redirect_to CmAdmin::Engine.mount_path + '/access-denied'
end

def visible_on_sidebar(visible_option)

def visible_on_sidebar(visible_option)
  @is_visible_on_sidebar = visible_option
end