apiphobic-authorization 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b495a30be17fcd8a76aac415fcbf6d98e56f074c782fb8b97da5485ef5c87117
4
+ data.tar.gz: 4540fba22161f2ca8169e8daad77c4c868911e33a1792d58fb1bf66df66d1e35
5
+ SHA512:
6
+ metadata.gz: 3fdbe8d14d7a0cc433d73c71a2292470ff50a13182681a0f56d18959944393a8884027367ef19518027c843daa66cf9344ec22e5648d64d8f2526a9b71d1090d
7
+ data.tar.gz: 2c9a91ca38d27f3b78ee561481c12c4aeed6f920e77e19ac96b8e348f37575f93e362a4cbb1285e4adb0dc7a50bc634fc6a1b74b31d17b6120b06ff41afab952
checksums.yaml.gz.sig ADDED
Binary file
data.tar.gz.sig ADDED
Binary file
data/LICENSE.txt ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010-2016 The Kompanee, Ltd
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Authorization
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/authorization`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'authorization'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install authorization
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/jfelchner/authorization.
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'apiphobic/authorization/version'
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'apple_core/action_controller/resource_naming'
4
+ require 'apiphobic/resource/model'
5
+
6
+ module Apiphobic
7
+ module Authorization
8
+ module Resource
9
+ RESOURCE_COLLECTION_ACTIONS = %w{index}.freeze
10
+
11
+ module ClassMethods
12
+ def authorizer_class
13
+ @authorizer_class ||= Object.const_get(authorizer_class_name)
14
+ end
15
+
16
+ def authorizer_parameters_class
17
+ @authorizer_parameters_class ||= \
18
+ Object.const_get(authorizer_class_name('Parameters'))
19
+ end
20
+
21
+ def authorizer_scope_class
22
+ @authorizer_scope_class ||= Object.const_get(authorizer_class_name('Scope'))
23
+ end
24
+
25
+ def authorized_scope_root_class
26
+ @authorized_scope_root_class ||= Object.const_get(singular_resource_class_name)
27
+ end
28
+
29
+ def authorizer_class_components(type = nil)
30
+ [
31
+ name_components['root_module'],
32
+ 'Authorizers',
33
+ resource_name,
34
+ type,
35
+ ]
36
+ .compact
37
+ end
38
+
39
+ def authorizer_class_name(type = nil)
40
+ authorizer_class_components(type).join('::')
41
+ end
42
+ end
43
+
44
+ def self.included(base)
45
+ base.include AppleCore::ActionController::ResourceNaming
46
+ base.extend ClassMethods
47
+
48
+ base.before_action :authorize
49
+ end
50
+
51
+ private
52
+
53
+ def authorize
54
+ return if authorizer.public_send(authorization_query)
55
+
56
+ Erratum.fail(
57
+ 'ForbiddenError',
58
+ resource_name: self.class.singular_resource_name,
59
+ resource_id: [params[:id]],
60
+ action: action_name,
61
+ )
62
+ end
63
+
64
+ def authorized_parameters
65
+ @authorized_parameters ||= authorizer_parameters_class
66
+ .new(action: action_name,
67
+ token: token,
68
+ user: authorized_user,
69
+ issuer: authorized_issuer,
70
+ parameters: params)
71
+ .call
72
+ end
73
+
74
+ def authorized_scope
75
+ @authorized_scope ||= self
76
+ .class
77
+ .authorizer_scope_class
78
+ .new(action: action_name,
79
+ token: token,
80
+ user: authorized_user,
81
+ issuer: authorized_issuer,
82
+ parameters: authorized_parameters,
83
+ scope_root: authorized_scope_root_class)
84
+ .call
85
+ end
86
+
87
+ def authorized_attributes
88
+ @authorized_attributes ||= Authorization::Transformers::JsonApiToRailsAttributes
89
+ .new(parameters: authorized_parameters.slice(:data))
90
+ .call
91
+ end
92
+
93
+ def authorizer
94
+ @authorizer ||= self
95
+ .class
96
+ .authorizer_class
97
+ .new(action: action_name,
98
+ token: token,
99
+ user: authorized_user,
100
+ issuer: authorized_issuer,
101
+ parameters: authorized_parameters,
102
+ resource: authorized_resource)
103
+ end
104
+
105
+ def authorized_resource
106
+ return if RESOURCE_COLLECTION_ACTIONS.include?(action_name)
107
+
108
+ @authorized_resource ||= public_send(self.class.singular_resource_name)
109
+ end
110
+
111
+ def authorized_collection
112
+ return unless RESOURCE_COLLECTION_ACTIONS.include?(action_name)
113
+
114
+ @authorized_collection ||= \
115
+ Resource::Model
116
+ .new(resource: public_send(self.class.plural_resource_name),
117
+ parameters: authorized_parameters)
118
+ end
119
+
120
+ def authorized_user
121
+ current_user
122
+ end
123
+
124
+ def authorized_issuer
125
+ current_issuer
126
+ end
127
+
128
+ def authorization_query
129
+ @authorization_query ||= "able_to_#{action_name}?"
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Apiphobic
4
+ module Authorization
5
+ class Authorizer
6
+ attr_accessor :action,
7
+ :token,
8
+ :user,
9
+ :params,
10
+ :resource
11
+
12
+ # rubocop:disable Metrics/ParameterLists
13
+ def initialize(action:, token:, user:, issuer:, params:, resource:, **other)
14
+ self.action = action
15
+ self.token = token
16
+ self.user = user
17
+ self.params = params
18
+ self.resource = resource
19
+
20
+ other.each do |name, value|
21
+ public_send("#{name}=", value)
22
+ end
23
+ end
24
+ # rubocop:enable Metrics/ParameterLists
25
+
26
+ def able_to_index?
27
+ false
28
+ end
29
+
30
+ def able_to_show?
31
+ false
32
+ end
33
+
34
+ def able_to_create?
35
+ false
36
+ end
37
+
38
+ def able_to_update?
39
+ false
40
+ end
41
+
42
+ def able_to_destroy?
43
+ false
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,282 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'apiphobic/errors/unpermitted_inclusions'
4
+ require 'apiphobic/errors/unpermitted_sorts'
5
+
6
+ # rubocop:disable Metrics/ClassLength
7
+ module Apiphobic
8
+ module Authorization
9
+ module Authorizers
10
+ class Parameters
11
+ JSON_API_PARAMETERS = %i{include sort page data filter}.freeze
12
+
13
+ attr_accessor :action,
14
+ :token,
15
+ :user,
16
+ :raw_parameters
17
+
18
+ attr_writer :authorized_attributes,
19
+ :authorized_filters,
20
+ :authorized_inclusions,
21
+ :authorized_relationships,
22
+ :authorized_sorts
23
+
24
+ # rubocop:disable Metrics/ParameterLists
25
+ def initialize(action:, token:, user:, issuer:, parameters:, **other)
26
+ self.action = action
27
+ self.token = token
28
+ self.user = user
29
+ self.raw_parameters = parameters.slice(*JSON_API_PARAMETERS)
30
+
31
+ other.each do |name, value|
32
+ public_send("#{name}=", value)
33
+ end
34
+ end
35
+ # rubocop:enable Metrics/ParameterLists
36
+
37
+ def authorized_attributes
38
+ @authorized_attributes || []
39
+ end
40
+
41
+ def authorized_filters
42
+ @authorized_filters || []
43
+ end
44
+
45
+ def authorized_inclusions
46
+ @authorized_inclusions || []
47
+ end
48
+
49
+ def authorized_relationships
50
+ @authorized_relationships || []
51
+ end
52
+
53
+ def authorized_sorts
54
+ @authorized_sorts || []
55
+ end
56
+
57
+ def call
58
+ authorized_attributes.each do |attribute|
59
+ attribute = { name: attribute } unless attribute.is_a?(::Hash)
60
+
61
+ authorize_attribute(**attribute)
62
+ end
63
+
64
+ authorized_filters.each do |filter|
65
+ filter = { name: filter } unless filter.is_a?(::Hash)
66
+
67
+ authorize_filter(**filter)
68
+ end
69
+
70
+ authorized_relationships.each do |name|
71
+ name = { name: name } unless name.is_a?(::Hash)
72
+
73
+ authorize_relationship(**name)
74
+ end
75
+
76
+ authorize_inclusions(names: authorized_inclusions)
77
+ authorize_sorts(names: authorized_sorts)
78
+
79
+ raw_parameters.permit(*authorized_parameters)
80
+ end
81
+
82
+ private
83
+
84
+ def authorized_parameters
85
+ @authorized_parameters ||= [
86
+ {
87
+ data: [
88
+ :type,
89
+ :id,
90
+ {
91
+ attributes: nil,
92
+ relationships: nil,
93
+ },
94
+ ],
95
+ filter: nil,
96
+ page: %i{
97
+ number
98
+ size
99
+ offset
100
+ limit
101
+ cursor
102
+ },
103
+ },
104
+ ]
105
+ end
106
+
107
+ def authorize_attribute(**args)
108
+ authorize_parameter(value: raw_parameter_attribute_value(args[:name]),
109
+ authorized_parameters: authorized_parameter_attributes,
110
+ raw_parameters: raw_parameter_attributes,
111
+ **args)
112
+ end
113
+
114
+ def authorize_filter(**args)
115
+ authorize_parameter(value: raw_parameter_filter_value(args[:name]),
116
+ authorized_parameters: authorized_parameter_filters,
117
+ raw_parameters: raw_parameter_filters,
118
+ **args)
119
+ end
120
+
121
+ def authorize_inclusions(names:)
122
+ return if names.empty?
123
+
124
+ all_requested_inclusions_authorized = raw_parameter_inclusions
125
+ .to_s
126
+ .split(',')
127
+ .all? do |inclusion|
128
+ names.map(&:to_s).include?(inclusion.to_s)
129
+ end
130
+
131
+ fail Errors::UnpermittedInclusions.new(inclusions: raw_parameter_inclusions) \
132
+ unless all_requested_inclusions_authorized
133
+
134
+ authorized_parameters << :include
135
+ end
136
+
137
+ def authorize_sorts(names:)
138
+ return if names.empty?
139
+
140
+ all_requested_sorts_authorized = raw_parameter_sorts
141
+ .to_s
142
+ .delete('-')
143
+ .split(',')
144
+ .all? do |sort|
145
+ names.map(&:to_s).include?(sort.to_s)
146
+ end
147
+
148
+ fail Errors::UnpermittedSorts.new(sorts: raw_parameter_sorts) \
149
+ unless all_requested_sorts_authorized
150
+
151
+ authorized_parameters << :sort
152
+ end
153
+
154
+ def authorize_parameter(name:,
155
+ value:,
156
+ authorized_parameters:,
157
+ raw_parameters:,
158
+ override: { with: nil, if_admin: false, if_blank: false })
159
+
160
+ value = override_parameter(name: name,
161
+ value: value,
162
+ hash: raw_parameters,
163
+ override: override)
164
+
165
+ if value.class == ::Array
166
+ authorized_parameters[0][name] = []
167
+ else
168
+ authorized_parameters << name
169
+ end
170
+ end
171
+
172
+ def authorize_relationship(name:, embedded_attributes: [])
173
+ relationship_data = raw_parameter_relationship_data(name)
174
+ to_many_relation = relationship_data.is_a?(::Array)
175
+ first_relation = if to_many_relation
176
+ relationship_data[0]
177
+ else
178
+ relationship_data || {}
179
+ end
180
+ embedded_relation = first_relation[:attributes]
181
+
182
+ authorized_parameter_relationships[name] = if relationship_data.nil?
183
+ [:data]
184
+ elsif embedded_relation
185
+ {
186
+ data: [
187
+ :id,
188
+ :type,
189
+ {
190
+ attributes: %i{__id__} +
191
+ embedded_attributes,
192
+ },
193
+ ],
194
+ }
195
+ else
196
+ { data: %i{type id} }
197
+ end
198
+ end
199
+
200
+ def override_parameter(name:, value:, hash:, override:)
201
+ return value unless override[:with] &&
202
+ (!token.admin? || override[:if_admin]) &&
203
+ (!value.nil? || override[:if_blank])
204
+
205
+ hash[name] = override[:with]
206
+
207
+ override[:with]
208
+ end
209
+
210
+ def authorized_data_parameter
211
+ authorized_parameters[0][:data][2]
212
+ end
213
+
214
+ def authorized_parameter_attributes
215
+ authorized_data_parameter[:attributes] ||= [{}]
216
+ end
217
+
218
+ def authorized_parameter_relationships
219
+ authorized_data_parameter[:relationships] ||= {}
220
+ end
221
+
222
+ def authorized_parameter_filters
223
+ authorized_parameters[0][:filter] ||= [{}]
224
+ end
225
+
226
+ def authorized_parameter_inclusions
227
+ authorized_parameters[0][:include] ||= ''
228
+ end
229
+
230
+ def authorized_parameter_sorts
231
+ authorized_parameters[0][:sort] ||= ''
232
+ end
233
+
234
+ # rubocop:disable Layout/ExtraSpacing
235
+ def raw_parameter_attributes
236
+ @raw_parameter_attributes ||= begin
237
+ raw_parameters[:data] ||= {}
238
+ raw_parameters[:data][:attributes] ||= {}
239
+
240
+ raw_parameters[:data][:attributes]
241
+ end
242
+ end
243
+ # rubocop:enable Layout/ExtraSpacing
244
+
245
+ def raw_parameter_filters
246
+ @raw_parameter_filters ||= raw_parameters[:filter] ||= {}
247
+ end
248
+
249
+ def raw_parameter_inclusions
250
+ @raw_parameter_inclusions ||= raw_parameters[:include] ||= ''
251
+ end
252
+
253
+ def raw_parameter_relationships
254
+ @raw_parameter_relationships ||= raw_parameters
255
+ .fetch(:data, {})
256
+ .fetch(:relationships, {})
257
+ end
258
+
259
+ def raw_parameter_sorts
260
+ @raw_parameter_sorts ||= raw_parameters[:sort] ||= ''
261
+ end
262
+
263
+ def raw_parameter_attribute_value(name)
264
+ raw_parameter_attributes[name]
265
+ end
266
+
267
+ def raw_parameter_filter_value(name)
268
+ raw_parameter_filters[name]
269
+ end
270
+
271
+ def raw_parameter_relationship(name)
272
+ raw_parameter_relationships.fetch(name, {})
273
+ end
274
+
275
+ def raw_parameter_relationship_data(name)
276
+ raw_parameter_relationship(name).fetch(:data, nil)
277
+ end
278
+ end
279
+ end
280
+ end
281
+ end
282
+ # rubocop:enable Metrics/ClassLength
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'apple_core/refinements/string'
4
+
5
+ module Apiphobic
6
+ module Authorization
7
+ module Authorizers
8
+ class Scope
9
+ using ::AppleCore::Refinements::String
10
+
11
+ attr_accessor :action,
12
+ :token,
13
+ :user,
14
+ :raw_parameters,
15
+ :scope_root
16
+
17
+ # rubocop:disable Metrics/ParameterLists
18
+ def initialize(action:, token:, user:, issuer:, parameters:, scope_root:, **other)
19
+ self.action = action
20
+ self.token = token
21
+ self.user = user
22
+ self.raw_parameters = parameters
23
+ self.scope_root = scope_root
24
+
25
+ other.each do |name, value|
26
+ public_send("#{name}=", value)
27
+ end
28
+ end
29
+ # rubocop:enable Metrics/ParameterLists
30
+
31
+ def user_scope
32
+ scope_root.public_send("for_#{user_underscored_class_name}", scope_user_id)
33
+ end
34
+
35
+ def public_scope
36
+ scope_root.none
37
+ end
38
+
39
+ def call
40
+ if scope_user_id
41
+ user_scope
42
+ else
43
+ public_scope
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def scope_user_id
50
+ @scope_user_id ||= raw_parameters
51
+ .fetch(:filter, {})
52
+ .fetch(user_underscored_class_name, nil)
53
+ end
54
+
55
+ def user_underscored_class_name
56
+ @user_underscored_class_name ||= begin
57
+ base_user_class_name = user.class.name[/([^:]+)\z/, 1]
58
+
59
+ base_user_class_name.underscore.downcase
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'apiphobic/json_api/relationship'
4
+
5
+ module Apiphobic
6
+ module Authorization
7
+ module Transformers
8
+ class JsonApiToRailsAttributes
9
+ attr_accessor :parameters
10
+
11
+ def initialize(parameters:)
12
+ self.parameters = parameters
13
+ end
14
+
15
+ def call
16
+ attributes.merge(relationship_attributes)
17
+ end
18
+
19
+ private
20
+
21
+ def attributes
22
+ @attributes = parameters
23
+ .fetch(:data, {})
24
+ .fetch(:attributes, parameters_class.new)
25
+ end
26
+
27
+ def relationships
28
+ @relationships = parameters
29
+ .fetch(:data, {})
30
+ .fetch(:relationships, parameters_class.new)
31
+ end
32
+
33
+ def relationship_attributes
34
+ parameters_class.new.tap do |relationship_attributes|
35
+ relationships.each_pair do |name, relationship|
36
+ relationship_attributes.merge!(JsonApi::Relationship
37
+ .new(name: name, data: relationship)
38
+ .to_rails_attributes)
39
+ end
40
+
41
+ relationship_attributes.permit! if relationship_attributes.respond_to?(:permit!)
42
+ end
43
+ end
44
+
45
+ def parameters_class
46
+ parameters.class
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Apiphobic
4
+ module Authorization
5
+ VERSION = '1.0.0'
6
+ end
7
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'erratum/error'
4
+
5
+ module Apiphobic
6
+ module Errors
7
+ class UnpermittedInclusions < RuntimeError
8
+ include Erratum::Error
9
+
10
+ attr_accessor :inclusions
11
+
12
+ def http_status
13
+ 422
14
+ end
15
+
16
+ def title
17
+ 'Unpermitted Inclusion'
18
+ end
19
+
20
+ def detail
21
+ 'One or more of the inclusions you attempted to pass via the "include" parameter ' \
22
+ 'are either not available or not authorized.'
23
+ end
24
+
25
+ def source
26
+ { inclusions: inclusions }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'erratum/error'
4
+
5
+ module Apiphobic
6
+ module Errors
7
+ class UnpermittedSorts < RuntimeError
8
+ include Erratum::Error
9
+
10
+ attr_accessor :sorts
11
+
12
+ def http_status
13
+ 422
14
+ end
15
+
16
+ def title
17
+ 'Unpermitted Sort'
18
+ end
19
+
20
+ def detail
21
+ <<~HEREDOC.chomp.tr("\n", ' ')
22
+ One or more of the sorts you attempted to pass via the "sort" parameter
23
+ are either not available or not authorized.
24
+ HEREDOC
25
+ end
26
+
27
+ def source
28
+ { sorts: sorts }
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'apple_core/refinements/string'
4
+
5
+ module Apiphobic
6
+ module JsonApi
7
+ class Relationship
8
+ using ::AppleCore::Refinements::String
9
+
10
+ attr_accessor :name,
11
+ :raw_relationship,
12
+ :data_class
13
+
14
+ def initialize(name:, data:, data_class: nil)
15
+ self.name = name
16
+ self.raw_relationship = data
17
+ self.data_class = data_class || data.class
18
+ end
19
+
20
+ def to_rails_attributes
21
+ __send__("#{embedded}_#{type}_to_rails_attributes")
22
+ end
23
+
24
+ private
25
+
26
+ def embedded_has_one_to_rails_attributes
27
+ attribute = "#{name.singularize}_attributes".to_sym
28
+
29
+ with_data_class(attribute, relationship_attributes_to_rails_attributes(data))
30
+ end
31
+
32
+ def referenced_has_one_to_rails_attributes
33
+ attribute = "#{name.singularize}_id".to_sym
34
+
35
+ with_data_class(attribute, data[:id])
36
+ end
37
+
38
+ def embedded_has_many_to_rails_attributes
39
+ attribute = "#{name.pluralize}_attributes".to_sym
40
+
41
+ has_many_attributes = data.map do |datum|
42
+ relationship_attributes_to_rails_attributes(datum)
43
+ end
44
+
45
+ with_data_class(attribute, has_many_attributes)
46
+ end
47
+
48
+ def referenced_has_many_to_rails_attributes
49
+ attribute = "#{name.singularize}_ids".to_sym
50
+
51
+ has_many_attributes = data.map { |d| d[:id] }
52
+
53
+ with_data_class(attribute, has_many_attributes)
54
+ end
55
+
56
+ def empty_empty_to_rails_attributes
57
+ attribute = name.to_sym
58
+
59
+ with_data_class(attribute, nil)
60
+ end
61
+
62
+ def empty_has_many_to_rails_attributes
63
+ attribute = "#{name.singularize}_ids".to_sym
64
+
65
+ with_data_class(attribute, [])
66
+ end
67
+
68
+ def relationship_attributes_to_rails_attributes(other)
69
+ other[:attributes].dup.tap do |attrs|
70
+ attrs.delete(:__id__)
71
+ attrs[:id] = other[:id] if other[:id]
72
+ end
73
+ end
74
+
75
+ def type
76
+ return 'has_many' if has_many?
77
+ return 'has_one' if has_one?
78
+ return 'empty' unless has_data?
79
+ end
80
+
81
+ def embedded
82
+ if referenced?
83
+ 'referenced'
84
+ elsif embedded?
85
+ 'embedded'
86
+ elsif !has_data?
87
+ 'empty'
88
+ end
89
+ end
90
+
91
+ def has_many?
92
+ data.is_a?(::Array)
93
+ end
94
+
95
+ def has_one?
96
+ data.is_a?(::Hash) || data.is_a?(::ActionController::Parameters)
97
+ rescue NameError
98
+ false
99
+ end
100
+
101
+ def referenced?
102
+ return false unless has_data?
103
+
104
+ !Array(data)[0][:attributes]
105
+ end
106
+
107
+ def embedded?
108
+ return false unless has_data?
109
+
110
+ Array(data)[0][:attributes]
111
+ end
112
+
113
+ def has_data?
114
+ @has_data ||= Array(data).compact.any?
115
+ end
116
+
117
+ def data
118
+ raw_relationship[:data]
119
+ end
120
+
121
+ def with_data_class(key, value)
122
+ if data_class == ::Hash
123
+ { key => value }
124
+ elsif data_class == ::ActionController::Parameters
125
+ ::ActionController::Parameters.new(key => value).tap(&:permit!)
126
+ end
127
+ rescue NameError
128
+ { key => value }
129
+ end
130
+ end
131
+ end
132
+ end
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: apiphobic-authorization
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - thegranddesign
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDqjCCApKgAwIBAgIBATANBgkqhkiG9w0BAQUFADBNMREwDwYDVQQDDAhydWJ5
14
+ Z2VtczEjMCEGCgmSJomT8ixkARkWE2xpdmluZ2hpZ2hvbnRoZWJsb2cxEzARBgoJ
15
+ kiaJk/IsZAEZFgNjb20wHhcNMTcwODAyMjI1OTM1WhcNMTgwODAyMjI1OTM1WjBN
16
+ MREwDwYDVQQDDAhydWJ5Z2VtczEjMCEGCgmSJomT8ixkARkWE2xpdmluZ2hpZ2hv
17
+ bnRoZWJsb2cxEzARBgoJkiaJk/IsZAEZFgNjb20wggEiMA0GCSqGSIb3DQEBAQUA
18
+ A4IBDwAwggEKAoIBAQDtLa7+7p49gW15OgOyRZad/F92iZcMdDjZ2kAxZlviXgVe
19
+ PCtjfdURobH+YMdt++6eRkE25utIFqHyN51Shxfdc21T3fPQe/ZEoMyiJK4tYzbh
20
+ 7VjNJG4ldvKKpS1p7iVz9imnyTxNwb0JaIOsOFCA04T0u6aCQi2acNvAPLviXk0q
21
+ xJ/CKjI4QUTZKVrBt8Q1Egrp2yzmEnSNftDuTbBb8m4vDR+w325CwbKCgycHJ1/g
22
+ YZ3FO76TzJuRVbsYS/bU5XKHVEpkeFmWBqEXsk4DuUIWLa6WZEJcoZf+YP+1pycG
23
+ 7YqSbydpINtEdopD+EEI+g+zNJ4nSI8/eQcQyEjBAgMBAAGjgZQwgZEwCQYDVR0T
24
+ BAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFDWuVrg4ve0vLu71kqiGdyBnzJGV
25
+ MCsGA1UdEQQkMCKBIHJ1YnlnZW1zQGxpdmluZ2hpZ2hvbnRoZWJsb2cuY29tMCsG
26
+ A1UdEgQkMCKBIHJ1YnlnZW1zQGxpdmluZ2hpZ2hvbnRoZWJsb2cuY29tMA0GCSqG
27
+ SIb3DQEBBQUAA4IBAQDJIpHjbBPGiaY4wOHcXlltQ+BMmhWQNh+1fZtyajQd+7Ay
28
+ fv23mO7Mf25Q38gopQlpaODkfxq54Jt8FvQbr5RYRS4j+JEKb75NgrAtehd8USUd
29
+ CiJJGH+yvGNWug9IGZCGX91HIbTsLQ5IUUWQasC5jGP8nxXufUr9xgAJZZenewny
30
+ B2qKu8q1A/kj6cw62RCY7yBmUXxlcJBj8g+JKYAFbYYKUdQSzf50k9IiWLWunJM+
31
+ Y2GAoHKstmfIVhc4XHOPpmTd2o/C29O9oaRgjrkfQEhF/KvJ/PhoV5hvokzsCyI5
32
+ iUeXPfvrGD/itYIBCgk+fnzyQQ4QtE5hTQaWQ3o2
33
+ -----END CERTIFICATE-----
34
+ date: 2018-05-01 00:00:00.000000000 Z
35
+ dependencies:
36
+ - !ruby/object:Gem::Dependency
37
+ name: apple_core
38
+ requirement: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - "~>"
41
+ - !ruby/object:Gem::Version
42
+ version: '1.1'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '1.1'
50
+ - !ruby/object:Gem::Dependency
51
+ name: erratum
52
+ requirement: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: '3.1'
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - "~>"
62
+ - !ruby/object:Gem::Version
63
+ version: '3.1'
64
+ - !ruby/object:Gem::Dependency
65
+ name: actionpack
66
+ requirement: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - "~>"
69
+ - !ruby/object:Gem::Version
70
+ version: '5.0'
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - "~>"
76
+ - !ruby/object:Gem::Version
77
+ version: '5.0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rspec
80
+ requirement: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - "~>"
83
+ - !ruby/object:Gem::Version
84
+ version: '3.7'
85
+ type: :development
86
+ prerelease: false
87
+ version_requirements: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - "~>"
90
+ - !ruby/object:Gem::Version
91
+ version: '3.7'
92
+ - !ruby/object:Gem::Dependency
93
+ name: rspeckled
94
+ requirement: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - "~>"
97
+ - !ruby/object:Gem::Version
98
+ version: '0.0'
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - "~>"
104
+ - !ruby/object:Gem::Version
105
+ version: '0.0'
106
+ - !ruby/object:Gem::Dependency
107
+ name: timecop
108
+ requirement: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - "~>"
111
+ - !ruby/object:Gem::Version
112
+ version: 0.9.0
113
+ type: :development
114
+ prerelease: false
115
+ version_requirements: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - "~>"
118
+ - !ruby/object:Gem::Version
119
+ version: 0.9.0
120
+ description: ''
121
+ email:
122
+ - rubygems@livinghighontheblog.com
123
+ executables: []
124
+ extensions: []
125
+ extra_rdoc_files: []
126
+ files:
127
+ - LICENSE.txt
128
+ - README.md
129
+ - lib/apiphobic-authorization.rb
130
+ - lib/apiphobic/authorization/authorizable_resource.rb
131
+ - lib/apiphobic/authorization/authorizer.rb
132
+ - lib/apiphobic/authorization/authorizers/parameters.rb
133
+ - lib/apiphobic/authorization/authorizers/scope.rb
134
+ - lib/apiphobic/authorization/transformers/json_api_to_rails_attributes.rb
135
+ - lib/apiphobic/authorization/version.rb
136
+ - lib/apiphobic/errors/unpermitted_inclusions.rb
137
+ - lib/apiphobic/errors/unpermitted_sorts.rb
138
+ - lib/apiphobic/json_api/relationship.rb
139
+ homepage: ''
140
+ licenses:
141
+ - MIT
142
+ metadata:
143
+ allowed_push_host: https://rubygems.org
144
+ post_install_message:
145
+ rdoc_options: []
146
+ require_paths:
147
+ - lib
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 2.7.6
161
+ signing_key:
162
+ specification_version: 4
163
+ summary: Authorization for API Requests
164
+ test_files: []
metadata.gz.sig ADDED
Binary file