lib/ronflex/configuration.rb
# frozen_string_literal: true require "ronflex/rule" require "ronflex/errors" # Module Ronflex # # This module provides configuration to manage access rules based on templates and queries, # with options to exclude certain paths or customize logic via a provider. # # @example Basic setup # Ronflex.configure do |config| # # add path to exclude all rule # config.excluded_path << "/public" # # add a provider to identify the model user # config.provider = ->(env) { env[:current_user] } # # add rule for administrator # config.add_rule(:admin) do |user, request| # # admins can access to all routes, expected "/restricted" # !request.path.start_with?("/restricted") # end # # add rule for guest # config.add_rule(:guest) do |user, request| # # guests can only acces public path # request.path.start_with?("/public") # end # # # add custom page maintenance # config.maintenance_page = "/path/to/your/custom/maintenance/page.html" # end module Ronflex class Configuration # List of paths excluded by default. # These paths are ignored by the defined rules. # # @return [Array<String>] DEFAULT_EXCLUDED_PATHS = ["/health_check"] # Default provider. # by default, it is a lambda which returns `nil`. # # @return [Proc] DEFAULT_PROVIDER = -> (env) { nil } # Attribute for desable or enable th feature # # @return [Boolean] attr_accessor :enable # List of paths excluded from rule evaluation. # # @return [Array<String>] attr_accessor :excluded_path # Custom provider to retrieve a model based on the environment. # # @return [Proc] attr_accessor :provider # List of defined access rules. # # @return [Array<Rule>] attr_accessor :rules # Path to a custom maintenance page (either an HTML or ERB file). # # @return [String] attr_accessor :maintenance_page # Initializes a new configuration with default values. def initialize @excluded_path = DEFAULT_EXCLUDED_PATHS.dup @provider = DEFAULT_PROVIDER @enable = false @maintenance_page = nil @rules = [] end # Adds an access rule for a specific type. # # A rule is a block of code that determines whether a model is allowed to access a given query. # # @param type [Symbol, String] The type or role of the model (e.g. `:admin`, `:user`). # @yield [model, request] The rule block, which takes a model and a request as parameters. # @yieldparam model [Object] The evaluated model. # @yieldparam request [Object] The evaluated request. # @return [void] # # @example Add a rule for administrators # config.add_rule(:admin) do |model, request| # request.path.start_with?("/admin") # end def add_rule(type, &block) raise RonflexArgumentError, "Rule type must be provided" if type.nil? raise RonflexArgumentError, "Block must be provided for the rule" unless block_given? @rules << Rule.new(type, &block) end # Checks if a model is allowed to access a given query. # # This method iterates through the defined rules and applies those matching the pattern. # # @param model [Object] The model to check (e.g. a user or a symbolic role). # @param request [Object] The request to check, which should respond to methods like `path`. # @return [Boolean] `true` if at least one rule authorizes access, `false` otherwise. # # @example Check an authorization # model = :admin # request = OpenStruct.new(path: "/admin/dashboard") # config.allowed?(model, request) # => true or false def allowed?(model, request) rules.any? { |rule| rule.matches?(model, request) } end # Checks if a model is valid (present). # # @param model [Object] The model to check. # @return [Boolean] `true` if the model is valid, `false` otherwise. # # @note This method uses the `present?` method, which is typically available in Rails. # If you are not using Rails, you may need to override this method. def model_present?(model) !model.nil? && !(model.respond_to?(:empty?) && model.empty?) end end end