apiphobic-authorization 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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