wallaby-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +31 -0
- data/app/controllers/wallaby/application_controller.rb +84 -0
- data/app/controllers/wallaby/resources_controller.rb +381 -0
- data/app/controllers/wallaby/secure_controller.rb +81 -0
- data/app/security/ability.rb +13 -0
- data/config/locales/wallaby.en.yml +140 -0
- data/config/locales/wallaby_class.en.yml +30 -0
- data/config/routes.rb +39 -0
- data/lib/adaptors/wallaby/custom.rb +7 -0
- data/lib/adaptors/wallaby/custom/default_provider.rb +9 -0
- data/lib/adaptors/wallaby/custom/model_decorator.rb +71 -0
- data/lib/adaptors/wallaby/custom/model_finder.rb +13 -0
- data/lib/adaptors/wallaby/custom/model_pagination_provider.rb +14 -0
- data/lib/adaptors/wallaby/custom/model_service_provider.rb +48 -0
- data/lib/authorizers/wallaby/cancancan_authorization_provider.rb +72 -0
- data/lib/authorizers/wallaby/default_authorization_provider.rb +58 -0
- data/lib/authorizers/wallaby/model_authorizer.rb +100 -0
- data/lib/authorizers/wallaby/pundit_authorization_provider.rb +89 -0
- data/lib/concerns/wallaby/authorizable.rb +103 -0
- data/lib/concerns/wallaby/baseable.rb +36 -0
- data/lib/concerns/wallaby/decoratable.rb +101 -0
- data/lib/concerns/wallaby/defaultable.rb +38 -0
- data/lib/concerns/wallaby/engineable.rb +61 -0
- data/lib/concerns/wallaby/fieldable.rb +78 -0
- data/lib/concerns/wallaby/paginatable.rb +72 -0
- data/lib/concerns/wallaby/rails_overridden_methods.rb +42 -0
- data/lib/concerns/wallaby/resourcable.rb +149 -0
- data/lib/concerns/wallaby/servicable.rb +68 -0
- data/lib/concerns/wallaby/shared_helpers.rb +22 -0
- data/lib/concerns/wallaby/themeable.rb +40 -0
- data/lib/decorators/wallaby/resource_decorator.rb +189 -0
- data/lib/errors/wallaby/cell_handling.rb +6 -0
- data/lib/errors/wallaby/forbidden.rb +6 -0
- data/lib/errors/wallaby/general_error.rb +6 -0
- data/lib/errors/wallaby/invalid_error.rb +6 -0
- data/lib/errors/wallaby/model_not_found.rb +11 -0
- data/lib/errors/wallaby/not_authenticated.rb +6 -0
- data/lib/errors/wallaby/not_found.rb +6 -0
- data/lib/errors/wallaby/not_implemented.rb +6 -0
- data/lib/errors/wallaby/resource_not_found.rb +11 -0
- data/lib/errors/wallaby/unprocessable_entity.rb +6 -0
- data/lib/forms/wallaby/form_builder.rb +60 -0
- data/lib/helpers/wallaby/application_helper.rb +79 -0
- data/lib/helpers/wallaby/base_helper.rb +65 -0
- data/lib/helpers/wallaby/configuration_helper.rb +18 -0
- data/lib/helpers/wallaby/form_helper.rb +62 -0
- data/lib/helpers/wallaby/index_helper.rb +84 -0
- data/lib/helpers/wallaby/links_helper.rb +213 -0
- data/lib/helpers/wallaby/resources_helper.rb +52 -0
- data/lib/helpers/wallaby/secure_helper.rb +54 -0
- data/lib/helpers/wallaby/styling_helper.rb +82 -0
- data/lib/interfaces/wallaby/mode.rb +72 -0
- data/lib/interfaces/wallaby/model_authorization_provider.rb +99 -0
- data/lib/interfaces/wallaby/model_decorator.rb +168 -0
- data/lib/interfaces/wallaby/model_finder.rb +12 -0
- data/lib/interfaces/wallaby/model_pagination_provider.rb +107 -0
- data/lib/interfaces/wallaby/model_service_provider.rb +84 -0
- data/lib/paginators/wallaby/model_paginator.rb +115 -0
- data/lib/paginators/wallaby/resource_paginator.rb +12 -0
- data/lib/parsers/wallaby/parser.rb +34 -0
- data/lib/renderers/wallaby/cell.rb +137 -0
- data/lib/renderers/wallaby/cell_resolver.rb +89 -0
- data/lib/renderers/wallaby/custom_lookup_context.rb +64 -0
- data/lib/renderers/wallaby/custom_partial_renderer.rb +33 -0
- data/lib/renderers/wallaby/custom_renderer.rb +16 -0
- data/lib/responders/wallaby/json_api_responder.rb +101 -0
- data/lib/responders/wallaby/resources_responder.rb +28 -0
- data/lib/routes/wallaby/resources_router.rb +72 -0
- data/lib/servicers/wallaby/model_servicer.rb +154 -0
- data/lib/services/wallaby/engine_name_finder.rb +22 -0
- data/lib/services/wallaby/engine_url_for.rb +46 -0
- data/lib/services/wallaby/link_options_normalizer.rb +19 -0
- data/lib/services/wallaby/map/mode_mapper.rb +27 -0
- data/lib/services/wallaby/map/model_class_collector.rb +49 -0
- data/lib/services/wallaby/map/model_class_mapper.rb +38 -0
- data/lib/services/wallaby/prefixes_builder.rb +66 -0
- data/lib/services/wallaby/sorting/hash_builder.rb +19 -0
- data/lib/services/wallaby/sorting/link_builder.rb +69 -0
- data/lib/services/wallaby/sorting/next_builder.rb +63 -0
- data/lib/services/wallaby/sorting/single_builder.rb +20 -0
- data/lib/services/wallaby/type_renderer.rb +50 -0
- data/lib/support/action_dispatch/routing/mapper.rb +75 -0
- data/lib/tree/wallaby/node.rb +25 -0
- data/lib/utils/wallaby/cell_utils.rb +34 -0
- data/lib/utils/wallaby/field_utils.rb +43 -0
- data/lib/utils/wallaby/filter_utils.rb +20 -0
- data/lib/utils/wallaby/model_utils.rb +51 -0
- data/lib/utils/wallaby/module_utils.rb +46 -0
- data/lib/utils/wallaby/params_utils.rb +14 -0
- data/lib/utils/wallaby/preload_utils.rb +44 -0
- data/lib/utils/wallaby/test_utils.rb +34 -0
- data/lib/utils/wallaby/utils.rb +27 -0
- data/lib/wallaby/configuration.rb +103 -0
- data/lib/wallaby/configuration/features.rb +24 -0
- data/lib/wallaby/configuration/mapping.rb +140 -0
- data/lib/wallaby/configuration/metadata.rb +23 -0
- data/lib/wallaby/configuration/models.rb +46 -0
- data/lib/wallaby/configuration/pagination.rb +30 -0
- data/lib/wallaby/configuration/security.rb +98 -0
- data/lib/wallaby/configuration/sorting.rb +28 -0
- data/lib/wallaby/constants.rb +45 -0
- data/lib/wallaby/core.rb +117 -0
- data/lib/wallaby/core/version.rb +7 -0
- data/lib/wallaby/engine.rb +43 -0
- data/lib/wallaby/map.rb +170 -0
- metadata +222 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Cancancan base authorization provider
|
|
5
|
+
class CancancanAuthorizationProvider < ModelAuthorizationProvider
|
|
6
|
+
# Detect and see if Cancancan is in use.
|
|
7
|
+
# @param context [ActionController::Base]
|
|
8
|
+
# @return [true] if Cancancan is in use.
|
|
9
|
+
# @return [false] if Cancancan is not in use.
|
|
10
|
+
def self.available?(context)
|
|
11
|
+
defined?(CanCanCan) && defined?(Ability) && context.respond_to?(:current_ability)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# This will pull out the args required for contruction from context
|
|
15
|
+
# @param context [ActionController::Base]
|
|
16
|
+
# @return [Hash] args for initialize
|
|
17
|
+
def self.args_from(context)
|
|
18
|
+
{ ability: context.current_ability, user: ModuleUtils.try_to(context, :current_user) }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @!attribute [r] ability
|
|
22
|
+
# @return [Ability]
|
|
23
|
+
attr_reader :ability
|
|
24
|
+
|
|
25
|
+
def initialize(ability:, user: nil)
|
|
26
|
+
@ability = ability
|
|
27
|
+
@user = user
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Check user's permission for an action on given subject.
|
|
31
|
+
# This method will be used in controller.
|
|
32
|
+
# @param action [Symbol, String]
|
|
33
|
+
# @param subject [Object, Class]
|
|
34
|
+
# @raise [Wallaby::Forbidden] when user is not authorized to perform the action.
|
|
35
|
+
def authorize(action, subject)
|
|
36
|
+
ability.authorize! action, subject
|
|
37
|
+
rescue ::CanCan::AccessDenied
|
|
38
|
+
Rails.logger.info I18n.t('errors.unauthorized', user: user, action: action, subject: subject)
|
|
39
|
+
raise Forbidden
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Check and see if user is allowed to perform an action on given subject.
|
|
43
|
+
# @param action [Symbol, String]
|
|
44
|
+
# @param subject [Object, Class]
|
|
45
|
+
# @return [Boolean]
|
|
46
|
+
def authorized?(action, subject)
|
|
47
|
+
ability.can? action, subject
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Restrict user to access certain scope.
|
|
51
|
+
# @param action [Symbol, String]
|
|
52
|
+
# @param scope [Object]
|
|
53
|
+
# @return [Object]
|
|
54
|
+
def accessible_for(action, scope)
|
|
55
|
+
ModuleUtils.try_to(scope, :accessible_by, ability, action) || scope
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Restrict user to assign certain values.
|
|
59
|
+
# @param action [Symbol, String]
|
|
60
|
+
# @param subject [Object]
|
|
61
|
+
# @return nil
|
|
62
|
+
delegate :attributes_for, to: :ability
|
|
63
|
+
|
|
64
|
+
# Just return nil
|
|
65
|
+
# @param action [Symbol, String]
|
|
66
|
+
# @param subject [Object]
|
|
67
|
+
# @return [nil]
|
|
68
|
+
def permit_params(action, subject)
|
|
69
|
+
# Do nothing
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Default authorization provider
|
|
5
|
+
class DefaultAuthorizationProvider < ModelAuthorizationProvider
|
|
6
|
+
# Always available.
|
|
7
|
+
# @param _context [ActionController::Base]
|
|
8
|
+
# @return [true]
|
|
9
|
+
def self.available?(_context)
|
|
10
|
+
true
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# This will pull out the args required for contruction from context
|
|
14
|
+
# @param _context [ActionController::Base]
|
|
15
|
+
# @return [Hash] args for initialize
|
|
16
|
+
def self.args_from(_context)
|
|
17
|
+
{}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Do nothing
|
|
21
|
+
# @param _action [Symbol, String]
|
|
22
|
+
# @param subject [Object, Class]
|
|
23
|
+
def authorize(_action, subject)
|
|
24
|
+
subject
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Always return true
|
|
28
|
+
# @param _action [Symbol, String]
|
|
29
|
+
# @param _subject [Object, Class]
|
|
30
|
+
# @return [true]
|
|
31
|
+
def authorized?(_action, _subject)
|
|
32
|
+
true
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Do nothing
|
|
36
|
+
# @param _action [Symbol, String]
|
|
37
|
+
# @param scope [Object]
|
|
38
|
+
def accessible_for(_action, scope)
|
|
39
|
+
scope
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Return empty attributes
|
|
43
|
+
# @param _action [Symbol, String]
|
|
44
|
+
# @param _subject [Object]
|
|
45
|
+
# @return [Hash] empty hash
|
|
46
|
+
def attributes_for(_action, _subject)
|
|
47
|
+
{}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @note Please make sure to return nil when the authorization doesn't support this feature.
|
|
51
|
+
# @param _action [Symbol, String]
|
|
52
|
+
# @param _subject [Object]
|
|
53
|
+
# @return [nil]
|
|
54
|
+
def permit_params(_action, _subject)
|
|
55
|
+
# Do nothing
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Model Authorizer to provide authorization functions
|
|
5
|
+
# @since 5.2.0
|
|
6
|
+
class ModelAuthorizer
|
|
7
|
+
extend Baseable::ClassMethods
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
# @!attribute [w] model_class
|
|
11
|
+
attr_writer :model_class
|
|
12
|
+
|
|
13
|
+
# @!attribute [r] model_class
|
|
14
|
+
# Return associated model class, e.g. return **Product** for **ProductAuthorizer**.
|
|
15
|
+
#
|
|
16
|
+
# If Wallaby can't recognise the model class for Authorizer, it's required to be configured as below example:
|
|
17
|
+
# @example To configure model class
|
|
18
|
+
# class Admin::ProductAuthorizer < Admin::ApplicationAuthorizer
|
|
19
|
+
# self.model_class = Product
|
|
20
|
+
# end
|
|
21
|
+
# @example To configure model class for version below 5.2.0
|
|
22
|
+
# class Admin::ProductAuthorizer < Admin::ApplicationAuthorizer
|
|
23
|
+
# def self.model_class
|
|
24
|
+
# Product
|
|
25
|
+
# end
|
|
26
|
+
# end
|
|
27
|
+
# @return [Class] assoicated model class
|
|
28
|
+
# @return [nil] if current class is marked as base class
|
|
29
|
+
# @return [nil] if current class is the same as the value of {Wallaby::Configuration::Mapping#model_authorizer}
|
|
30
|
+
# @return [nil] if current class is {Wallaby::ModelAuthorizer}
|
|
31
|
+
# @return [nil] if assoicated model class is not found
|
|
32
|
+
def model_class
|
|
33
|
+
return unless self < ModelAuthorizer
|
|
34
|
+
return if base_class? || self == Wallaby.configuration.mapping.model_authorizer
|
|
35
|
+
|
|
36
|
+
@model_class ||= Map.model_class_map(name.gsub(/(^#{namespace}::)|(Authorizer$)/, EMPTY_STRING))
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @!attribute [w] provider_name
|
|
40
|
+
attr_writer :provider_name
|
|
41
|
+
|
|
42
|
+
# @!attribute [r] provider_name
|
|
43
|
+
# @return [String, Symbol] provider name of the authorization framework used
|
|
44
|
+
def provider_name
|
|
45
|
+
@provider_name ||= ModuleUtils.try_to superclass, :provider_name
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Factory method to create the model authorizer
|
|
49
|
+
# @param context [ActionController::Base]
|
|
50
|
+
# @param model_class [Class]
|
|
51
|
+
# @return [Wallaby::ModelAuthorizer]
|
|
52
|
+
def create(context, model_class)
|
|
53
|
+
model_class ||= self.model_class
|
|
54
|
+
provider_class = guess_provider_class context, model_class
|
|
55
|
+
new model_class, provider_class, provider_class.args_from(context)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
# @param context [ActionController::Base]
|
|
61
|
+
# @param model_class [Class]
|
|
62
|
+
# @return [Class] provider class
|
|
63
|
+
def guess_provider_class(context, model_class)
|
|
64
|
+
providers = Map.authorizer_provider_map model_class
|
|
65
|
+
providers[provider_name] || providers.values.find { |klass| klass.available? context }
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
delegate(*ModelAuthorizationProvider.instance_methods(false), to: :@provider)
|
|
70
|
+
|
|
71
|
+
# @!attribute [r] model_class
|
|
72
|
+
# @return [Class]
|
|
73
|
+
attr_reader :model_class
|
|
74
|
+
|
|
75
|
+
# @!attribute [r] provider
|
|
76
|
+
# @return [Wallaby::ModelAuthorizationProvider]
|
|
77
|
+
# @since 5.2.0
|
|
78
|
+
attr_reader :provider
|
|
79
|
+
|
|
80
|
+
# @param model_class [Class]
|
|
81
|
+
# @param provider_name_or_class [String, Symbol, Class]
|
|
82
|
+
# @param options [Hash]
|
|
83
|
+
def initialize(model_class, provider_name_or_class, options = {})
|
|
84
|
+
@model_class = model_class || self.class.model_class
|
|
85
|
+
@provider = init_provider provider_name_or_class, options
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
protected
|
|
89
|
+
|
|
90
|
+
# Go through provider list and detect which provider is used.
|
|
91
|
+
# @param provider_name_or_class [String, Symbol, Class]
|
|
92
|
+
# @param options [Hash]
|
|
93
|
+
# @return [Wallaby::Authorizer]
|
|
94
|
+
def init_provider(provider_name_or_class, options)
|
|
95
|
+
providers = Map.authorizer_provider_map model_class
|
|
96
|
+
provider_class = provider_name_or_class.is_a?(Class) ? provider_name_or_class : providers[provider_name_or_class]
|
|
97
|
+
provider_class.new(**options)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Pundit base authorization provider
|
|
5
|
+
class PunditAuthorizationProvider < ModelAuthorizationProvider
|
|
6
|
+
# Detect and see if Pundit is in use.
|
|
7
|
+
# @param context [ActionController::Base]
|
|
8
|
+
# @return [true] if Pundit is in use.
|
|
9
|
+
# @return [false] if Pundit is not in use.
|
|
10
|
+
def self.available?(context)
|
|
11
|
+
defined?(Pundit) && context.respond_to?(:pundit_user)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# This will pull out the args required for contruction from context
|
|
15
|
+
# @param context [ActionController::Base]
|
|
16
|
+
# @return [Hash] args for initialize
|
|
17
|
+
def self.args_from(context)
|
|
18
|
+
{ user: context.pundit_user }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @param user [Object]
|
|
22
|
+
def initialize(user:)
|
|
23
|
+
@user = user
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Check user's permission for an action on given subject.
|
|
27
|
+
#
|
|
28
|
+
# This method will be used in controller.
|
|
29
|
+
# @param action [Symbol, String]
|
|
30
|
+
# @param subject [Object, Class]
|
|
31
|
+
# @raise [Wallaby::Forbidden] when user is not authorized to perform the action.
|
|
32
|
+
def authorize(action, subject)
|
|
33
|
+
Pundit.authorize(user, subject, normalize(action)) && subject
|
|
34
|
+
rescue ::Pundit::NotAuthorizedError
|
|
35
|
+
Rails.logger.info I18n.t('errors.unauthorized', user: user, action: action, subject: subject)
|
|
36
|
+
raise Forbidden
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Check and see if user is allowed to perform an action on given subject
|
|
40
|
+
# @param action [Symbol, String]
|
|
41
|
+
# @param subject [Object, Class]
|
|
42
|
+
# @return [Boolean]
|
|
43
|
+
def authorized?(action, subject)
|
|
44
|
+
policy = Pundit.policy! user, subject
|
|
45
|
+
ModuleUtils.try_to policy, normalize(action)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Restrict user to assign certain values.
|
|
49
|
+
#
|
|
50
|
+
# It will do a lookup in policy's methods and pick the first available method:
|
|
51
|
+
#
|
|
52
|
+
# - attributes\_for\_#\{ action \}
|
|
53
|
+
# - attributes\_for
|
|
54
|
+
# @param action [Symbol, String]
|
|
55
|
+
# @param subject [Object]
|
|
56
|
+
# @return [Hash] field value paired hash that user's allowed to assign
|
|
57
|
+
def attributes_for(action, subject)
|
|
58
|
+
policy = Pundit.policy! user, subject
|
|
59
|
+
value = ModuleUtils.try_to(policy, "attributes_for_#{action}") || ModuleUtils.try_to(policy, 'attributes_for')
|
|
60
|
+
Rails.logger.warn I18n.t('error.pundit.not_found.attributes_for', subject: subject) unless value
|
|
61
|
+
value || {}
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Restrict user for mass assignment.
|
|
65
|
+
#
|
|
66
|
+
# It will do a lookup in policy's methods and pick the first available method:
|
|
67
|
+
#
|
|
68
|
+
# - permitted\_attributes\_for\_#\{ action \}
|
|
69
|
+
# - permitted\_attributes
|
|
70
|
+
# @param action [Symbol, String]
|
|
71
|
+
# @param subject [Object]
|
|
72
|
+
# @return [Array] field list that user's allowed to change.
|
|
73
|
+
def permit_params(action, subject)
|
|
74
|
+
policy = Pundit.policy! user, subject
|
|
75
|
+
# @see https://github.com/varvet/pundit/blob/master/lib/pundit.rb#L258
|
|
76
|
+
ModuleUtils.try_to(policy, "permitted_attributes_for_#{action}") \
|
|
77
|
+
|| ModuleUtils.try_to(policy, 'permitted_attributes')
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
# Convert action to pundit method name
|
|
83
|
+
# @param action [Symbol, String]
|
|
84
|
+
# @return [String] e.g. `create?`
|
|
85
|
+
def normalize(action)
|
|
86
|
+
"#{action}?".tr('??', '?')
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Authorizer related attributes
|
|
5
|
+
module Authorizable
|
|
6
|
+
# Configurable attribute for authorizer related
|
|
7
|
+
module ClassMethods
|
|
8
|
+
# @!attribute [w] model_authorizer
|
|
9
|
+
def model_authorizer=(model_authorizer)
|
|
10
|
+
ModuleUtils.inheritance_check model_authorizer, application_authorizer
|
|
11
|
+
@model_authorizer = model_authorizer
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# @!attribute [r] model_authorizer
|
|
15
|
+
# If Wallaby doesn't get it right, please specify the **model_authorizer**.
|
|
16
|
+
# @example To set model authorizer
|
|
17
|
+
# class Admin::ProductionsController < Admin::ApplicationController
|
|
18
|
+
# self.model_authorizer = ProductAuthorizer
|
|
19
|
+
# end
|
|
20
|
+
# @return [Class] model authorizer
|
|
21
|
+
# @raise [ArgumentError] when **model_authorizer** doesn't inherit from **application_authorizer**
|
|
22
|
+
# @see Wallaby::ModelAuthorizer
|
|
23
|
+
# @since 5.2.0
|
|
24
|
+
attr_reader :model_authorizer
|
|
25
|
+
|
|
26
|
+
# @!attribute [w] application_authorizer
|
|
27
|
+
def application_authorizer=(application_authorizer)
|
|
28
|
+
ModuleUtils.inheritance_check model_authorizer, application_authorizer
|
|
29
|
+
@application_authorizer = application_authorizer
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @!attribute [r] application_authorizer
|
|
33
|
+
# The **application_authorizer** is as the base class of {#model_authorizer}.
|
|
34
|
+
# @example To set application decorator:
|
|
35
|
+
# class Admin::ApplicationController < Wallaby::ResourcesController
|
|
36
|
+
# self.application_authorizer = AnotherApplicationAuthorizer
|
|
37
|
+
# end
|
|
38
|
+
# @return [Class] application decorator
|
|
39
|
+
# @raise [ArgumentError] when **model_authorizer** doesn't inherit from **application_authorizer**
|
|
40
|
+
# @see Wallaby::ModelAuthorizer
|
|
41
|
+
# @since 5.2.0
|
|
42
|
+
def application_authorizer
|
|
43
|
+
@application_authorizer ||= ModuleUtils.try_to superclass, :application_authorizer
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Model authorizer for current modal class.
|
|
48
|
+
#
|
|
49
|
+
# It can be configured in following class attributes:
|
|
50
|
+
#
|
|
51
|
+
# - controller configuration {Wallaby::Authorizable::ClassMethods#model_authorizer .model_authorizer}
|
|
52
|
+
# - a generic authorizer based on
|
|
53
|
+
# {Wallaby::Authorizable::ClassMethods#application_authorizer .application_authorizer}
|
|
54
|
+
# @return [Wallaby::ModelAuthorizer] model authorizer
|
|
55
|
+
# @since 5.2.0
|
|
56
|
+
def current_authorizer
|
|
57
|
+
@current_authorizer ||=
|
|
58
|
+
authorizer_of(current_model_class, controller_to_get(:model_authorizer)).tap do |authorizer|
|
|
59
|
+
Rails.logger.info %( - Current authorizer: #{authorizer.try(:class)})
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Check if user is allowed to perform action on given subject
|
|
64
|
+
# @param action [Symbol, String]
|
|
65
|
+
# @param subject [Object, Class]
|
|
66
|
+
# @return [true] if allowed
|
|
67
|
+
# @return [false] if not allowed
|
|
68
|
+
# @since 5.2.0
|
|
69
|
+
def authorized?(action, subject)
|
|
70
|
+
return false unless subject
|
|
71
|
+
|
|
72
|
+
klass = subject.is_a?(Class) ? subject : subject.class
|
|
73
|
+
authorizer_of(klass).authorized? action, subject
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Check if user is allowed to perform action on given subject
|
|
77
|
+
# @param action [Symbol, String]
|
|
78
|
+
# @param subject [Object, Class]
|
|
79
|
+
# @return [true] if not allowed
|
|
80
|
+
# @return [false] if allowed
|
|
81
|
+
# @since 5.2.0
|
|
82
|
+
def unauthorized?(action, subject)
|
|
83
|
+
!authorized? action, subject
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @deprecated Use {#current_authorizer} instead. It will be removed from 5.3.*
|
|
87
|
+
def authorizer
|
|
88
|
+
Utils.deprecate 'deprecation.authorizer', caller: caller
|
|
89
|
+
current_authorizer
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
protected
|
|
93
|
+
|
|
94
|
+
# @param model_class [Class]
|
|
95
|
+
# @param authorizer_class [Class, nil]
|
|
96
|
+
# @return [Wallaby::ModelAuthorizer] model authorizer for given model
|
|
97
|
+
# @since 5.2.0
|
|
98
|
+
def authorizer_of(model_class, authorizer_class = nil)
|
|
99
|
+
authorizer_class ||= Map.authorizer_map(model_class, controller_to_get(:application_authorizer))
|
|
100
|
+
authorizer_class.try :create, self, model_class
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Abstract related class methods
|
|
5
|
+
module Baseable
|
|
6
|
+
# Configurable attributes and class methods for marking a class the base class
|
|
7
|
+
# and skipping {Wallaby::Map Wallaby mapping}
|
|
8
|
+
module ClassMethods
|
|
9
|
+
# @return [true] if class is a base class
|
|
10
|
+
# @return [false] if class is not a base class
|
|
11
|
+
def base_class?
|
|
12
|
+
@base_class ||= false
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Mark class a base class
|
|
16
|
+
# @return [true]
|
|
17
|
+
def base_class!
|
|
18
|
+
@base_class = true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @!attribute [w] namespace
|
|
22
|
+
# Used by `model_class`
|
|
23
|
+
# @since 5.2.0
|
|
24
|
+
attr_writer :namespace
|
|
25
|
+
|
|
26
|
+
# @!attribute [r] namespace
|
|
27
|
+
# @return [String] namespace
|
|
28
|
+
# @since 5.2.0
|
|
29
|
+
def namespace
|
|
30
|
+
@namespace ||=
|
|
31
|
+
ModuleUtils.try_to(superclass, :namespace) \
|
|
32
|
+
|| name.deconstantize.gsub(/Wallaby(::)?/, EMPTY_STRING).presence
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|