wallaby-core 0.1.2 → 0.2.3

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.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +60 -13
  3. data/app/controllers/wallaby/resources_controller.rb +15 -374
  4. data/app/security/ability.rb +1 -1
  5. data/config/locales/wallaby.en.yml +92 -128
  6. data/config/locales/wallaby_class.en.yml +2 -23
  7. data/lib/adaptors/wallaby/custom/default_provider.rb +1 -1
  8. data/lib/adaptors/wallaby/custom/model_decorator.rb +8 -7
  9. data/lib/adaptors/wallaby/custom/model_finder.rb +3 -2
  10. data/lib/adaptors/wallaby/custom/model_pagination_provider.rb +1 -1
  11. data/lib/adaptors/wallaby/custom/model_service_provider.rb +1 -40
  12. data/lib/authorizers/wallaby/cancancan_authorization_provider.rb +30 -24
  13. data/lib/authorizers/wallaby/default_authorization_provider.rb +6 -13
  14. data/lib/authorizers/wallaby/model_authorizer.rb +43 -67
  15. data/lib/authorizers/wallaby/pundit_authorization_provider.rb +21 -30
  16. data/lib/concerns/wallaby/application_concern.rb +110 -0
  17. data/lib/concerns/wallaby/authentication_concern.rb +162 -0
  18. data/lib/concerns/wallaby/authorizable.rb +8 -14
  19. data/lib/concerns/wallaby/baseable.rb +91 -10
  20. data/lib/concerns/wallaby/decoratable.rb +3 -3
  21. data/lib/concerns/wallaby/engineable.rb +1 -1
  22. data/lib/concerns/wallaby/fieldable.rb +4 -4
  23. data/lib/concerns/wallaby/paginatable.rb +3 -3
  24. data/lib/concerns/wallaby/prefixable.rb +21 -0
  25. data/lib/concerns/wallaby/resourcable.rb +4 -35
  26. data/lib/concerns/wallaby/resources_concern.rb +434 -0
  27. data/lib/concerns/wallaby/servicable.rb +4 -10
  28. data/lib/decorators/wallaby/resource_decorator.rb +53 -80
  29. data/lib/errors/wallaby/{cell_handling.rb → class_not_found.rb} +1 -1
  30. data/lib/errors/wallaby/model_not_found.rb +3 -1
  31. data/lib/errors/wallaby/resource_not_found.rb +1 -1
  32. data/lib/helpers/wallaby/application_helper.rb +6 -9
  33. data/lib/helpers/wallaby/form_helper.rb +2 -9
  34. data/lib/helpers/wallaby/index_helper.rb +2 -14
  35. data/lib/helpers/wallaby/links_helper.rb +5 -5
  36. data/lib/helpers/wallaby/resources_helper.rb +3 -7
  37. data/lib/helpers/wallaby/secure_helper.rb +3 -3
  38. data/lib/helpers/wallaby/styling_helper.rb +17 -3
  39. data/lib/interfaces/wallaby/mode.rb +5 -5
  40. data/lib/interfaces/wallaby/model_authorization_provider.rb +15 -13
  41. data/lib/interfaces/wallaby/model_decorator.rb +15 -3
  42. data/lib/paginators/wallaby/model_paginator.rb +14 -45
  43. data/lib/parsers/wallaby/parser.rb +49 -14
  44. data/lib/routes/wallaby/resources_router.rb +1 -1
  45. data/lib/servicers/wallaby/model_servicer.rb +32 -62
  46. data/lib/services/wallaby/map/mode_mapper.rb +14 -14
  47. data/lib/services/wallaby/map/model_class_collector.rb +2 -2
  48. data/lib/services/wallaby/map/model_class_mapper.rb +7 -26
  49. data/lib/services/wallaby/prefixes_builder.rb +15 -49
  50. data/lib/services/wallaby/type_renderer.rb +3 -13
  51. data/lib/utils/wallaby/locale.rb +53 -0
  52. data/lib/utils/wallaby/model_utils.rb +4 -3
  53. data/lib/utils/wallaby/module_utils.rb +1 -1
  54. data/lib/utils/wallaby/utils.rb +10 -15
  55. data/lib/wallaby/class_array.rb +75 -0
  56. data/lib/wallaby/class_hash.rb +94 -0
  57. data/lib/wallaby/classifier.rb +29 -0
  58. data/lib/wallaby/configuration/mapping.rb +33 -27
  59. data/lib/wallaby/configuration/metadata.rb +1 -1
  60. data/lib/wallaby/configuration/models.rb +5 -9
  61. data/lib/wallaby/configuration/security.rb +6 -3
  62. data/lib/wallaby/configuration/sorting.rb +1 -1
  63. data/lib/wallaby/configuration.rb +31 -2
  64. data/lib/wallaby/constants.rb +10 -8
  65. data/lib/wallaby/core/version.rb +1 -1
  66. data/lib/wallaby/core.rb +21 -16
  67. data/lib/wallaby/engine.rb +9 -20
  68. data/lib/wallaby/logger.rb +35 -0
  69. data/lib/wallaby/map.rb +20 -17
  70. data/lib/wallaby/preloader.rb +77 -0
  71. metadata +48 -22
  72. data/app/controllers/wallaby/application_controller.rb +0 -84
  73. data/app/controllers/wallaby/secure_controller.rb +0 -81
  74. data/lib/concerns/wallaby/rails_overridden_methods.rb +0 -42
  75. data/lib/concerns/wallaby/themeable.rb +0 -40
  76. data/lib/paginators/wallaby/resource_paginator.rb +0 -12
  77. data/lib/renderers/wallaby/cell.rb +0 -137
  78. data/lib/renderers/wallaby/cell_resolver.rb +0 -89
  79. data/lib/renderers/wallaby/custom_lookup_context.rb +0 -64
  80. data/lib/renderers/wallaby/custom_partial_renderer.rb +0 -33
  81. data/lib/renderers/wallaby/custom_renderer.rb +0 -16
  82. data/lib/utils/wallaby/cell_utils.rb +0 -34
  83. 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
- labels:
24
- count: 'Count: '
25
- auto_select_hint: 'Type to select...'
26
- upload: 'Upload'
27
- empty: 'null'
28
- na: 'n/a'
29
- edit: 'Edit # %{id}'
30
- create: 'Create a %{model}'
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
- buttons:
33
- save: 'Save'
12
+ buttons:
13
+ save: 'Save'
34
14
 
35
- links:
36
- new: 'Create %{model}'
37
- show: 'Show'
38
- edit: 'Edit'
39
- delete: 'Delete'
40
- cancel: 'Cancel'
41
- confirm:
42
- delete: 'Please confirm to delete'
43
- export: 'Export as %{ext}'
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
- http_errors:
46
- report_error_html: 'And report the error <a href="https://github.com/reinteractive/wallaby/issues/new" target="_blank">here</a>.'
47
- not_implemented: 'Not implemented.'
48
- internal_server_error: 'Hope you feel better.'
49
- bad_request: 'Your request is not supported.'
50
- not_found: 'Not found.'
51
- unprocessable_entity: 'Your request cannot be processed.'
52
- unauthorized: 'You need to sign in to access this page.'
53
- forbidden: 'You need permission to access this page.'
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
- json_errors:
56
- not_implemented: 'Not implemented.'
57
- internal_server_error: 'Internal server error.'
58
- bad_request: 'Your request is not supported.'
59
- not_found: 'Not found.'
60
- unprocessable_entity: 'Your request cannot be processed.'
61
- unauthorized: 'You need to sign in to access this page.'
62
- forbidden: 'You need permission to access this page.'
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
- errors:
65
- invalid:
66
- models: '%{models} are invalid models.'
67
- inheritance: '%{klass} does not inherit from %{parent}.'
68
- type_required: 'Type is required for %{field_name}.'
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
- scope_policy: 'Cannot find scope policy for %{scope}.'
81
- attributes_for: 'Cannot find attributes for %{subject}.'
82
- activerecord:
83
- paginatable: '%{collection} is not paginatable.'
84
- required: '%{subject} is required.'
85
- not_implemented:
86
- model_servicer: 'Custom model servicer method `%{method_name}` is not implemented'
87
-
88
- pagination:
89
- prev: 'Prev'
90
- next: 'Next'
91
- from_to: '%{from} to %{to}'
92
- of: ' of '
93
- total_count: '%{total}'
94
- pers: 'Page Size'
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
- filters:
98
- title: 'Filters'
99
- all: 'All'
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
- search:
102
- hint: 'Press enter to search.'
75
+ filters:
76
+ title: 'Filters'
77
+ all: 'All'
103
78
 
104
- hints:
105
- 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.'
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
- deprecation:
118
- authorizer: "[DEPRECATION] `authorizer` will be removed from 5.3.*. Please use `current_authorizer` instead.\n(called from %{from})"
119
- current_model_service: "[DEPRECATION] `current_model_service` will be removed from 5.3.*. Please use `current_servicer` instead.\n(called from %{from})"
120
- 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})"
121
- form_type_partial_render: "[DEPRECATION] `form_type_partial_render` will be removed from 5.3.*. Please use `type_render` instead.\n(called from %{from})"
122
- index_params: "[DEPRECATION] `index_params` will be removed from 5.3.*.\n(called from %{from})"
123
- paginator_of: "[DEPRECATION] `paginator_of` will be removed from 5.3.*. Please use `current_paginator` instead.\n(called from %{from})"
124
- resource_paginator_inheirtance: "[DEPRECATION] `Wallaby::ResourcePaginator` will be removed from 5.3.*. Please inherit from `Wallaby::ModelPaginator` instead.\n(called from %{from})"
125
- resource_paginator=: "[DEPRECATION] `resource_paginator=` will be removed from 5.3.*. Please use `model_paginator=` instead.\n(called from %{from})"
126
- type_partial_render: "[DEPRECATION] `type_partial_render` will be removed from 5.3.*. Please use `type_render` instead.\n(called from %{from})"
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
- fa:
129
- # map fa 5's icon name to version 4
130
- # @see this fa migration document https://fontawesome.com/how-to-use/on-the-web/setup/upgrading-from-version-4
131
- v4:
132
- clock: 'clock-o'
133
- bars: 'navicon'
134
- calendar: 'calendar-o'
135
- check-square: 'check-square-o'
136
- square: 'square-o'
137
- link: 'chain'
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: "[WALLABY] Don't know how to handle this model %{model}."
4
+ missing_mode_for_model_class: "Don't know how to handle this model %{model}."
26
5
  model_class_mapper:
27
- missing_model_class: "[WALLABY] Please define self.model_class for %{model} or set it as global.\n @see Wallaby.configuration.mapping"
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
- # Default provider for custom mode
5
+ # Default authorization provider for {Wallaby::Custom} mode that whitelists everything.
6
6
  class DefaultProvider < DefaultAuthorizationProvider
7
7
  end
8
8
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Wallaby
4
4
  class Custom
5
- # Custom modal decorator
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] primary key name
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
- field_name = FieldUtils.first_field_by({ name: /name|title|subject/ }, fields)
67
- ModuleUtils.try_to resource, field_name
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 [Array<Class>] a list of classes
8
+ # @return [Wallaby::ClashArray] a list of classes
8
9
  def all
9
10
  Wallaby.configuration.custom_models.presence
10
11
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Wallaby
4
4
  class Custom
5
- # Model pagination provider
5
+ # Model pagination provider for {Wallaby::Custom} mode
6
6
  class ModelPaginationProvider < ::Wallaby::ModelPaginationProvider
7
7
  # By default, it doesn't support pagination
8
8
  # @return [false]
@@ -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
- # Cancancan base authorization provider
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 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.
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) && defined?(Ability) && context.respond_to?(:current_ability)
14
+ defined?(CanCanCan) && context.respond_to?(:current_ability)
12
15
  end
13
16
 
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
17
+ # @!attribute [w] ability
18
+ attr_writer :ability
20
19
 
21
20
  # @!attribute [r] ability
22
- # @return [Ability]
23
- attr_reader :ability
24
-
25
- def initialize(ability:, user: nil)
26
- @ability = ability
27
- @user = user
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
- # This method will be used in controller.
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
- Rails.logger.info I18n.t('errors.unauthorized', user: user, action: action, subject: subject)
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 [Boolean]
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
- ModuleUtils.try_to(scope, :accessible_by, ability, action) || scope
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
- # Just return nil
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
- # Always available.
7
- # @param _context [ActionController::Base]
8
- # @return [true]
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
- 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
- {}
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]