wallaby-core 0.2.0 → 0.2.4
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 +4 -4
- data/README.md +42 -1
- data/app/controllers/wallaby/resources_controller.rb +15 -375
- data/app/security/ability.rb +1 -1
- data/config/locales/wallaby.en.yml +92 -128
- data/config/locales/wallaby_class.en.yml +2 -23
- data/lib/adaptors/wallaby/custom/default_provider.rb +1 -1
- data/lib/adaptors/wallaby/custom/model_decorator.rb +8 -7
- data/lib/adaptors/wallaby/custom/model_finder.rb +3 -2
- data/lib/adaptors/wallaby/custom/model_pagination_provider.rb +1 -1
- data/lib/adaptors/wallaby/custom/model_service_provider.rb +1 -40
- data/lib/authorizers/wallaby/cancancan_authorization_provider.rb +30 -24
- data/lib/authorizers/wallaby/default_authorization_provider.rb +6 -13
- data/lib/authorizers/wallaby/model_authorizer.rb +43 -67
- data/lib/authorizers/wallaby/pundit_authorization_provider.rb +21 -30
- data/lib/concerns/wallaby/application_concern.rb +110 -0
- data/lib/concerns/wallaby/authentication_concern.rb +162 -0
- data/lib/concerns/wallaby/authorizable.rb +8 -8
- data/lib/concerns/wallaby/baseable.rb +91 -10
- data/lib/concerns/wallaby/decoratable.rb +3 -3
- data/lib/concerns/wallaby/engineable.rb +1 -1
- data/lib/concerns/wallaby/fieldable.rb +4 -4
- data/lib/concerns/wallaby/paginatable.rb +3 -3
- data/lib/concerns/wallaby/resourcable.rb +4 -35
- data/lib/concerns/wallaby/resources_concern.rb +434 -0
- data/lib/concerns/wallaby/servicable.rb +4 -4
- data/lib/decorators/wallaby/resource_decorator.rb +53 -80
- data/lib/errors/wallaby/class_not_found.rb +6 -0
- data/lib/errors/wallaby/model_not_found.rb +3 -1
- data/lib/errors/wallaby/resource_not_found.rb +1 -1
- data/lib/helpers/wallaby/application_helper.rb +6 -0
- data/lib/helpers/wallaby/form_helper.rb +2 -3
- data/lib/helpers/wallaby/index_helper.rb +2 -2
- data/lib/helpers/wallaby/links_helper.rb +5 -5
- data/lib/helpers/wallaby/resources_helper.rb +3 -0
- data/lib/helpers/wallaby/secure_helper.rb +3 -3
- data/lib/helpers/wallaby/styling_helper.rb +17 -3
- data/lib/interfaces/wallaby/mode.rb +5 -5
- data/lib/interfaces/wallaby/model_authorization_provider.rb +15 -13
- data/lib/interfaces/wallaby/model_decorator.rb +15 -3
- data/lib/paginators/wallaby/model_paginator.rb +14 -45
- data/lib/routes/wallaby/resources_router.rb +1 -1
- data/lib/servicers/wallaby/model_servicer.rb +32 -62
- data/lib/services/wallaby/map/mode_mapper.rb +14 -14
- data/lib/services/wallaby/map/model_class_collector.rb +2 -2
- data/lib/services/wallaby/map/model_class_mapper.rb +7 -26
- data/lib/services/wallaby/type_renderer.rb +2 -12
- data/lib/utils/wallaby/locale.rb +53 -0
- data/lib/utils/wallaby/model_utils.rb +4 -3
- data/lib/utils/wallaby/module_utils.rb +1 -1
- data/lib/utils/wallaby/utils.rb +23 -9
- data/lib/wallaby/class_array.rb +75 -0
- data/lib/wallaby/class_hash.rb +94 -0
- data/lib/wallaby/classifier.rb +29 -0
- data/lib/wallaby/configuration/mapping.rb +33 -21
- data/lib/wallaby/configuration/metadata.rb +1 -1
- data/lib/wallaby/configuration/models.rb +5 -9
- data/lib/wallaby/configuration/security.rb +6 -3
- data/lib/wallaby/configuration/sorting.rb +1 -1
- data/lib/wallaby/configuration.rb +31 -2
- data/lib/wallaby/core/version.rb +1 -1
- data/lib/wallaby/core.rb +18 -6
- data/lib/wallaby/engine.rb +9 -20
- data/lib/wallaby/logger.rb +35 -0
- data/lib/wallaby/map.rb +20 -17
- data/lib/wallaby/preloader.rb +77 -0
- metadata +16 -9
- data/app/controllers/wallaby/application_controller.rb +0 -84
- data/app/controllers/wallaby/secure_controller.rb +0 -81
- data/lib/utils/wallaby/preload_utils.rb +0 -44
@@ -1,140 +1,104 @@
|
|
1
|
-
# Files in the config/locales directory are used for internationalization
|
2
|
-
# and are automatically loaded by Rails. If you want to use locales other
|
3
|
-
# than English, add the necessary files in this directory.
|
4
|
-
#
|
5
|
-
# To use the locales, use `I18n.t`:
|
6
|
-
#
|
7
|
-
# I18n.t 'hello'
|
8
|
-
#
|
9
|
-
# In views, this is aliased to just `t`:
|
10
|
-
#
|
11
|
-
# <%= t('hello') %>
|
12
|
-
#
|
13
|
-
# To use a different locale, set it with `I18n.locale`:
|
14
|
-
#
|
15
|
-
# I18n.locale = :es
|
16
|
-
#
|
17
|
-
# This would use the information in config/locales/es.yml.
|
18
|
-
#
|
19
|
-
# To learn more, please read the Rails Internationalization guide
|
20
|
-
# available at http://guides.rubyonrails.org/i18n.html.
|
21
|
-
|
22
1
|
en:
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
2
|
+
wallaby:
|
3
|
+
labels:
|
4
|
+
count: 'Count: '
|
5
|
+
auto_select_hint: 'Type to select...'
|
6
|
+
upload: 'Upload'
|
7
|
+
empty: 'null'
|
8
|
+
na: 'n/a'
|
9
|
+
edit: 'Edit # %{id}'
|
10
|
+
create: 'Create a %{model}'
|
31
11
|
|
32
|
-
|
33
|
-
|
12
|
+
buttons:
|
13
|
+
save: 'Save'
|
34
14
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
15
|
+
links:
|
16
|
+
new: 'Create %{model}'
|
17
|
+
show: 'Show'
|
18
|
+
edit: 'Edit'
|
19
|
+
delete: 'Delete'
|
20
|
+
cancel: 'Cancel'
|
21
|
+
confirm:
|
22
|
+
delete: 'Please confirm to delete'
|
23
|
+
export: 'Export as %{ext}'
|
44
24
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
25
|
+
http_errors:
|
26
|
+
report_error_html: 'And report the error <a href="https://github.com/reinteractive/wallaby/issues/new" target="_blank">here</a>.'
|
27
|
+
not_implemented: 'Not implemented.'
|
28
|
+
internal_server_error: 'Hope you feel better.'
|
29
|
+
bad_request: 'Your request is not supported.'
|
30
|
+
not_found: 'Not found.'
|
31
|
+
unprocessable_entity: 'Your request cannot be processed.'
|
32
|
+
unauthorized: 'You need to sign in to access this page.'
|
33
|
+
forbidden: 'You need permission to access this page.'
|
54
34
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
35
|
+
json_errors:
|
36
|
+
not_implemented: 'Not implemented.'
|
37
|
+
internal_server_error: 'Internal server error.'
|
38
|
+
bad_request: 'Your request is not supported.'
|
39
|
+
not_found: 'Not found.'
|
40
|
+
unprocessable_entity: 'Your request cannot be processed.'
|
41
|
+
unauthorized: 'You need to sign in to access this page.'
|
42
|
+
forbidden: 'You need permission to access this page.'
|
63
43
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
not_found:
|
70
|
-
collection: 'Records cannot be found. Click + button to add one.'
|
71
|
-
model: 'Model %{model} cannot be found.'
|
72
|
-
resource: 'Record %{resource} cannot be found.'
|
73
|
-
unprocessable_entity:
|
74
|
-
keyword_search: 'Unable to perform keyword search when no text fields can be used.'
|
75
|
-
field_colon_search: 'Unable to perform field colon search for %{invalid_fields}.'
|
76
|
-
model: 'Unable to handle model %{model}.'
|
77
|
-
unauthorized: 'User %{user} is trying to perform %{action} on %{subject}'
|
78
|
-
pundit:
|
44
|
+
errors:
|
45
|
+
invalid:
|
46
|
+
models: '%{models} are invalid models.'
|
47
|
+
inheritance: '%{klass} does not inherit from %{parent}.'
|
48
|
+
type_required: 'Type is required for %{field_name}.'
|
79
49
|
not_found:
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
pages: 'Page Number'
|
50
|
+
collection: 'Records cannot be found. Click + button to add one.'
|
51
|
+
model: 'Model %{model} cannot be found.'
|
52
|
+
resource: 'Record %{resource} cannot be found.'
|
53
|
+
unprocessable_entity:
|
54
|
+
keyword_search: 'Unable to perform keyword search when no text fields can be used.'
|
55
|
+
field_colon_search: 'Unable to perform field colon search for %{invalid_fields}.'
|
56
|
+
model: 'Unable to handle model %{model}.'
|
57
|
+
unauthorized: 'User %{user} is trying to perform %{action} on %{subject}'
|
58
|
+
pundit:
|
59
|
+
not_found:
|
60
|
+
scope_policy: 'Cannot find scope policy for %{scope}.'
|
61
|
+
attributes_for: 'Cannot find attributes for %{subject}.'
|
62
|
+
required: '%{subject} is required.'
|
63
|
+
not_implemented:
|
64
|
+
model_servicer: 'Custom model servicer method `%{method_name}` is not implemented'
|
96
65
|
|
97
|
-
|
98
|
-
|
99
|
-
|
66
|
+
pagination:
|
67
|
+
prev: 'Prev'
|
68
|
+
next: 'Next'
|
69
|
+
from_to: '%{from} to %{to}'
|
70
|
+
of: ' of '
|
71
|
+
total_count: '%{total}'
|
72
|
+
pers: 'Page Size'
|
73
|
+
pages: 'Page Number'
|
100
74
|
|
101
|
-
|
102
|
-
|
75
|
+
filters:
|
76
|
+
title: 'Filters'
|
77
|
+
all: 'All'
|
103
78
|
|
104
|
-
|
105
|
-
|
106
|
-
cidr_html: 'Example: <code>192.168.1.1/24</code> which holds an IPv4 or IPv6 network specification.'
|
107
|
-
circle_html: 'Format: <code><(x, y), r></code> where <i>(x,y)</i> is the center point and <i>r</i> is the radius of the circle.'
|
108
|
-
hstore_html: 'Format: <code>"Key1" => "Value1", "Key2" => "Value2"</code> is used for input and output, includes zero or more <i>key => value</i> pairs separated by commas.'
|
109
|
-
inet_html: 'Example: <code>192.168.1.1/24</code> which holds an IPv4 or IPv6 network specification.'
|
110
|
-
line_html: 'Format: <code>{ A, B, C }</code> which are represented by the linear equation <i>Ax + By + C = 0</i>.'
|
111
|
-
lseg_html: 'Format: <code>[(x1, y1), (x2, y2)]</code> where <i>(x1,y1)</i> and <i>(x2,y2)</i> are the end points of the line segment.'
|
112
|
-
ltree_html: 'Example: <code>Top.Countries.Europe.Russia</code> which is a sequence of zero or more labels separated by dots.'
|
113
|
-
macaddr_html: 'Example: <code>08:00:2b:01:02:03</code> which stores MAC addresses.'
|
114
|
-
path_html: 'Format: <code>((x1, y1) , ... , (xn, yn))</code> where the points are the end points of the line segments comprising the path.'
|
115
|
-
polygon_html: 'Format: <code>((x1, y1) , ... , (xn, yn))</code> where the points are the end points of the line segments comprising the boundary of the polygon.'
|
79
|
+
search:
|
80
|
+
hint: 'Press enter to search.'
|
116
81
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
82
|
+
hints:
|
83
|
+
box_html: 'Format: <code>(x1, y1), (x2, y2)</code> where <i>(x1,y1)</i> and <i>(x2,y2)</i> are any two opposite corners of the box.'
|
84
|
+
cidr_html: 'Example: <code>192.168.1.1/24</code> which holds an IPv4 or IPv6 network specification.'
|
85
|
+
circle_html: 'Format: <code><(x, y), r></code> where <i>(x,y)</i> is the center point and <i>r</i> is the radius of the circle.'
|
86
|
+
hstore_html: 'Format: <code>"Key1" => "Value1", "Key2" => "Value2"</code> is used for input and output, includes zero or more <i>key => value</i> pairs separated by commas.'
|
87
|
+
inet_html: 'Example: <code>192.168.1.1/24</code> which holds an IPv4 or IPv6 network specification.'
|
88
|
+
line_html: 'Format: <code>{ A, B, C }</code> which are represented by the linear equation <i>Ax + By + C = 0</i>.'
|
89
|
+
lseg_html: 'Format: <code>[(x1, y1), (x2, y2)]</code> where <i>(x1,y1)</i> and <i>(x2,y2)</i> are the end points of the line segment.'
|
90
|
+
ltree_html: 'Example: <code>Top.Countries.Europe.Russia</code> which is a sequence of zero or more labels separated by dots.'
|
91
|
+
macaddr_html: 'Example: <code>08:00:2b:01:02:03</code> which stores MAC addresses.'
|
92
|
+
path_html: 'Format: <code>((x1, y1) , ... , (xn, yn))</code> where the points are the end points of the line segments comprising the path.'
|
93
|
+
polygon_html: 'Format: <code>((x1, y1) , ... , (xn, yn))</code> where the points are the end points of the line segments comprising the boundary of the polygon.'
|
127
94
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
user: 'user-o'
|
139
|
-
v5:
|
140
|
-
no-need: 'no-need'
|
95
|
+
deprecation:
|
96
|
+
authorizer: "[DEPRECATION] `authorizer` will be removed from 5.3.*. Please use `current_authorizer` instead.\n(called from %{from})"
|
97
|
+
current_model_service: "[DEPRECATION] `current_model_service` will be removed from 5.3.*. Please use `current_servicer` instead.\n(called from %{from})"
|
98
|
+
find_filter_name: "[DEPRECATION] `Wallaby::Utils.find_filter_name` will be removed from 5.3.*. Please use `Wallaby::FilterUtils.filter_name_by` instead.\n(called from %{from})"
|
99
|
+
form_type_partial_render: "[DEPRECATION] `form_type_partial_render` will be removed from 5.3.*. Please use `type_render` instead.\n(called from %{from})"
|
100
|
+
index_params: "[DEPRECATION] `index_params` will be removed from 5.3.*.\n(called from %{from})"
|
101
|
+
paginator_of: "[DEPRECATION] `paginator_of` will be removed from 5.3.*. Please use `current_paginator` instead.\n(called from %{from})"
|
102
|
+
resource_paginator_inheirtance: "[DEPRECATION] `Wallaby::ResourcePaginator` will be removed from 5.3.*. Please inherit from `Wallaby::ModelPaginator` instead.\n(called from %{from})"
|
103
|
+
resource_paginator=: "[DEPRECATION] `resource_paginator=` will be removed from 5.3.*. Please use `model_paginator=` instead.\n(called from %{from})"
|
104
|
+
type_partial_render: "[DEPRECATION] `type_partial_render` will be removed from 5.3.*. Please use `type_render` instead.\n(called from %{from})"
|
@@ -1,30 +1,9 @@
|
|
1
|
-
# Files in the config/locales directory are used for internationalization
|
2
|
-
# and are automatically loaded by Rails. If you want to use locales other
|
3
|
-
# than English, add the necessary files in this directory.
|
4
|
-
#
|
5
|
-
# To use the locales, use `I18n.t`:
|
6
|
-
#
|
7
|
-
# I18n.t 'hello'
|
8
|
-
#
|
9
|
-
# In views, this is aliased to just `t`:
|
10
|
-
#
|
11
|
-
# <%= t('hello') %>
|
12
|
-
#
|
13
|
-
# To use a different locale, set it with `I18n.locale`:
|
14
|
-
#
|
15
|
-
# I18n.locale = :es
|
16
|
-
#
|
17
|
-
# This would use the information in config/locales/es.yml.
|
18
|
-
#
|
19
|
-
# To learn more, please read the Rails Internationalization guide
|
20
|
-
# available at http://guides.rubyonrails.org/i18n.html.
|
21
|
-
|
22
1
|
en:
|
23
2
|
wallaby:
|
24
3
|
map:
|
25
|
-
missing_mode_for_model_class: "
|
4
|
+
missing_mode_for_model_class: "Don't know how to handle this model %{model}."
|
26
5
|
model_class_mapper:
|
27
|
-
missing_model_class: "
|
6
|
+
missing_model_class: "Please define self.model_class for %{model} or set it as global.\n @see Wallaby.configuration.mapping"
|
28
7
|
|
29
8
|
mode:
|
30
9
|
inherit_required: '%{klass} must inherit from %{parent}.'
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Wallaby
|
4
4
|
class Custom
|
5
|
-
# Custom
|
5
|
+
# {Wallaby::Custom} mode decorator that only pulls out all the attributes from setter/getter methods.
|
6
6
|
class ModelDecorator < ::Wallaby::ModelDecorator
|
7
7
|
# Assume that attributes come from the setter/getter, e.g. `name=`/`name`
|
8
8
|
# @return [ActiveSupport::HashWithIndifferentAccess] metadata
|
@@ -11,8 +11,7 @@ module Wallaby
|
|
11
11
|
::ActiveSupport::HashWithIndifferentAccess.new.tap do |hash|
|
12
12
|
methods = model_class.public_instance_methods(false).map(&:to_s)
|
13
13
|
methods
|
14
|
-
.grep(/[^=]$/)
|
15
|
-
.select { |method_id| methods.include? "#{method_id}=" }
|
14
|
+
.grep(/[^=]$/).select { |method_id| methods.include? "#{method_id}=" }
|
16
15
|
.each { |attribute| hash[attribute] = { label: attribute.humanize, type: 'string' } }
|
17
16
|
end.freeze
|
18
17
|
end
|
@@ -50,21 +49,23 @@ module Wallaby
|
|
50
49
|
@form_field_names ||= form_fields.keys - [primary_key.to_s]
|
51
50
|
end
|
52
51
|
|
52
|
+
# @param resource [Object]
|
53
53
|
# @return [ActiveModel::Errors]
|
54
54
|
def form_active_errors(resource)
|
55
55
|
@form_active_errors ||= ActiveModel::Errors.new resource
|
56
56
|
end
|
57
57
|
|
58
|
-
# @return [String, Symbole]
|
58
|
+
# @return [String, Symbole] default to `:id`
|
59
59
|
def primary_key
|
60
60
|
@primary_key ||= :id
|
61
61
|
end
|
62
62
|
|
63
63
|
# @param resource [Object]
|
64
|
-
# @return [String]
|
64
|
+
# @return [String, nil]
|
65
65
|
def guess_title(resource)
|
66
|
-
|
67
|
-
|
66
|
+
FieldUtils
|
67
|
+
.first_field_by({ name: /name|title|subject/ }, fields)
|
68
|
+
.try { |field_name| resource.try field_name }
|
68
69
|
end
|
69
70
|
end
|
70
71
|
end
|
@@ -2,9 +2,10 @@
|
|
2
2
|
|
3
3
|
module Wallaby
|
4
4
|
class Custom
|
5
|
-
# Model finder
|
5
|
+
# Model finder for {Wallaby::Custom} mode that returns the list of model set by
|
6
|
+
# {Wallaby::Configuration#custom_models}
|
6
7
|
class ModelFinder < ::Wallaby::ModelFinder
|
7
|
-
# @return [
|
8
|
+
# @return [Wallaby::ClashArray] a list of classes
|
8
9
|
def all
|
9
10
|
Wallaby.configuration.custom_models.presence
|
10
11
|
end
|
@@ -2,47 +2,8 @@
|
|
2
2
|
|
3
3
|
module Wallaby
|
4
4
|
class Custom
|
5
|
-
# Model service provider
|
5
|
+
# Model service provider for {Wallaby::Custom} mode
|
6
6
|
class ModelServiceProvider < ::Wallaby::ModelServiceProvider
|
7
|
-
# @raise [Wallaby::NotImplemented]
|
8
|
-
def permit(*)
|
9
|
-
raise Wallaby::NotImplemented, I18n.t('errors.not_implemented.model_servicer', method_name: __callee__)
|
10
|
-
end
|
11
|
-
|
12
|
-
# @raise [Wallaby::NotImplemented]
|
13
|
-
def collection(*)
|
14
|
-
raise Wallaby::NotImplemented, I18n.t('errors.not_implemented.model_servicer', method_name: __callee__)
|
15
|
-
end
|
16
|
-
|
17
|
-
# @raise [Wallaby::NotImplemented]
|
18
|
-
def paginate(*)
|
19
|
-
raise Wallaby::NotImplemented, I18n.t('errors.not_implemented.model_servicer', method_name: __callee__)
|
20
|
-
end
|
21
|
-
|
22
|
-
# @raise [Wallaby::NotImplemented]
|
23
|
-
def new(*)
|
24
|
-
raise Wallaby::NotImplemented, I18n.t('errors.not_implemented.model_servicer', method_name: __callee__)
|
25
|
-
end
|
26
|
-
|
27
|
-
# @raise [Wallaby::NotImplemented]
|
28
|
-
def find(*)
|
29
|
-
raise Wallaby::NotImplemented, I18n.t('errors.not_implemented.model_servicer', method_name: __callee__)
|
30
|
-
end
|
31
|
-
|
32
|
-
# @raise [Wallaby::NotImplemented]
|
33
|
-
def create(*)
|
34
|
-
raise Wallaby::NotImplemented, I18n.t('errors.not_implemented.model_servicer', method_name: __callee__)
|
35
|
-
end
|
36
|
-
|
37
|
-
# @raise [Wallaby::NotImplemented]
|
38
|
-
def update(*)
|
39
|
-
raise Wallaby::NotImplemented, I18n.t('errors.not_implemented.model_servicer', method_name: __callee__)
|
40
|
-
end
|
41
|
-
|
42
|
-
# @raise [Wallaby::NotImplemented]
|
43
|
-
def destroy(*)
|
44
|
-
raise Wallaby::NotImplemented, I18n.t('errors.not_implemented.model_servicer', method_name: __callee__)
|
45
|
-
end
|
46
7
|
end
|
47
8
|
end
|
48
9
|
end
|
@@ -1,67 +1,73 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Wallaby
|
4
|
-
#
|
4
|
+
# @note This authorization provider DOES NOT use the existing
|
5
|
+
# {https://www.rubydoc.info/github/CanCanCommunity/cancancan/CanCan%2FControllerAdditions:current_ability
|
6
|
+
# current_ability} helper. It has its own version of {#ability} instance.
|
7
|
+
# {https://github.com/CanCanCommunity/cancancan CanCanCan} base authorization provider.
|
5
8
|
class CancancanAuthorizationProvider < ModelAuthorizationProvider
|
6
|
-
# Detect and see if
|
7
|
-
# @param context [ActionController::Base]
|
8
|
-
# @return [true] if
|
9
|
-
# @return [false]
|
9
|
+
# Detect and see if CanCanCan is in use.
|
10
|
+
# @param context [ActionController::Base, ActionView::Base]
|
11
|
+
# @return [true] if CanCanCan is in use
|
12
|
+
# @return [false] otherwise.
|
10
13
|
def self.available?(context)
|
11
|
-
defined?(CanCanCan) &&
|
14
|
+
defined?(CanCanCan) && context.respond_to?(:current_ability)
|
12
15
|
end
|
13
16
|
|
14
|
-
#
|
15
|
-
|
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
|
17
|
+
# @!attribute [w] ability
|
18
|
+
attr_writer :ability
|
20
19
|
|
21
20
|
# @!attribute [r] ability
|
22
|
-
# @return [Ability]
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
@
|
21
|
+
# @return [Ability] the Ability instance for {#user #user} (which is a
|
22
|
+
# {Wallaby::AuthenticationConcern#wallaby_user #wallaby_user})
|
23
|
+
def ability
|
24
|
+
# NOTE: use current_ability's class to create the ability instance.
|
25
|
+
# just in case that developer uses a different Ability class (e.g. UserAbility)
|
26
|
+
@ability ||= options[:ability] || Ability.new(user)
|
27
|
+
rescue ArgumentError, NameError
|
28
|
+
context.current_ability
|
28
29
|
end
|
29
30
|
|
30
31
|
# Check user's permission for an action on given subject.
|
31
|
-
#
|
32
|
+
#
|
33
|
+
# This method will be mostly used in controller.
|
32
34
|
# @param action [Symbol, String]
|
33
35
|
# @param subject [Object, Class]
|
34
36
|
# @raise [Wallaby::Forbidden] when user is not authorized to perform the action.
|
35
37
|
def authorize(action, subject)
|
36
38
|
ability.authorize! action, subject
|
37
39
|
rescue ::CanCan::AccessDenied
|
38
|
-
|
40
|
+
Logger.error <<~MESSAGE
|
41
|
+
#{Utils.inspect user} is forbidden to perform #{action} on #{Utils.inspect subject}
|
42
|
+
MESSAGE
|
39
43
|
raise Forbidden
|
40
44
|
end
|
41
45
|
|
42
46
|
# Check and see if user is allowed to perform an action on given subject.
|
43
47
|
# @param action [Symbol, String]
|
44
48
|
# @param subject [Object, Class]
|
45
|
-
# @return [
|
49
|
+
# @return [true] if user is allowed to perform the action
|
50
|
+
# @return [false] otherwise
|
46
51
|
def authorized?(action, subject)
|
47
52
|
ability.can? action, subject
|
48
53
|
end
|
49
54
|
|
50
|
-
# Restrict user to access certain scope.
|
55
|
+
# Restrict user to access certain scope/query.
|
51
56
|
# @param action [Symbol, String]
|
52
57
|
# @param scope [Object]
|
53
58
|
# @return [Object]
|
54
59
|
def accessible_for(action, scope)
|
55
|
-
|
60
|
+
scope.try(:accessible_by, ability, action) || scope
|
56
61
|
end
|
57
62
|
|
63
|
+
# @!method attributes_for(action, subject)
|
58
64
|
# Restrict user to assign certain values.
|
59
65
|
# @param action [Symbol, String]
|
60
66
|
# @param subject [Object]
|
61
67
|
# @return nil
|
62
68
|
delegate :attributes_for, to: :ability
|
63
69
|
|
64
|
-
#
|
70
|
+
# Simply return nil as CanCanCan doesn't provide such a feature.
|
65
71
|
# @param action [Symbol, String]
|
66
72
|
# @param subject [Object]
|
67
73
|
# @return [nil]
|
@@ -1,20 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Wallaby
|
4
|
-
# Default authorization provider
|
4
|
+
# Default authorization provider that whitelists everything.
|
5
5
|
class DefaultAuthorizationProvider < ModelAuthorizationProvider
|
6
|
-
#
|
7
|
-
# @param _context [ActionController::Base]
|
8
|
-
# @return [
|
6
|
+
# It returns false so that it can be used as the last resort.
|
7
|
+
# @param _context [ActionController::Base, ActionView::Base]
|
8
|
+
# @return [false]
|
9
9
|
def self.available?(_context)
|
10
|
-
|
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
|
-
{}
|
10
|
+
false
|
18
11
|
end
|
19
12
|
|
20
13
|
# Do nothing
|
@@ -47,7 +40,7 @@ module Wallaby
|
|
47
40
|
{}
|
48
41
|
end
|
49
42
|
|
50
|
-
# @note Please make sure to return nil when the authorization doesn't support this feature.
|
43
|
+
# @note Please make sure to return nil when the authorization provider doesn't support this feature.
|
51
44
|
# @param _action [Symbol, String]
|
52
45
|
# @param _subject [Object]
|
53
46
|
# @return [nil]
|