scimitar 1.8.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/scimitar/active_record_backed_resources_controller.rb +20 -94
  3. data/app/controllers/scimitar/application_controller.rb +13 -41
  4. data/app/controllers/scimitar/schemas_controller.rb +0 -5
  5. data/app/models/scimitar/complex_types/address.rb +6 -0
  6. data/app/models/scimitar/engine_configuration.rb +5 -13
  7. data/app/models/scimitar/error_response.rb +0 -12
  8. data/app/models/scimitar/lists/query_parser.rb +10 -25
  9. data/app/models/scimitar/resource_invalid_error.rb +1 -1
  10. data/app/models/scimitar/resources/base.rb +4 -14
  11. data/app/models/scimitar/resources/mixin.rb +13 -140
  12. data/app/models/scimitar/schema/address.rb +0 -1
  13. data/app/models/scimitar/schema/attribute.rb +5 -14
  14. data/app/models/scimitar/schema/base.rb +1 -1
  15. data/app/models/scimitar/schema/vdtp.rb +1 -1
  16. data/app/models/scimitar/service_provider_configuration.rb +3 -14
  17. data/config/initializers/scimitar.rb +3 -28
  18. data/lib/scimitar/version.rb +2 -2
  19. data/lib/scimitar.rb +2 -7
  20. data/spec/apps/dummy/app/controllers/mock_groups_controller.rb +1 -1
  21. data/spec/apps/dummy/app/models/mock_group.rb +1 -1
  22. data/spec/apps/dummy/app/models/mock_user.rb +8 -36
  23. data/spec/apps/dummy/config/application.rb +1 -0
  24. data/spec/apps/dummy/config/environments/test.rb +28 -5
  25. data/spec/apps/dummy/config/initializers/scimitar.rb +10 -61
  26. data/spec/apps/dummy/config/routes.rb +7 -28
  27. data/spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb +1 -10
  28. data/spec/apps/dummy/db/migrate/20210308044214_create_join_table_mock_groups_mock_users.rb +3 -8
  29. data/spec/apps/dummy/db/schema.rb +4 -11
  30. data/spec/controllers/scimitar/application_controller_spec.rb +3 -126
  31. data/spec/controllers/scimitar/resource_types_controller_spec.rb +2 -2
  32. data/spec/controllers/scimitar/schemas_controller_spec.rb +2 -10
  33. data/spec/models/scimitar/complex_types/address_spec.rb +4 -3
  34. data/spec/models/scimitar/complex_types/email_spec.rb +2 -0
  35. data/spec/models/scimitar/lists/query_parser_spec.rb +9 -76
  36. data/spec/models/scimitar/resources/base_spec.rb +70 -208
  37. data/spec/models/scimitar/resources/base_validation_spec.rb +2 -27
  38. data/spec/models/scimitar/resources/mixin_spec.rb +43 -790
  39. data/spec/models/scimitar/schema/attribute_spec.rb +3 -22
  40. data/spec/models/scimitar/schema/base_spec.rb +1 -1
  41. data/spec/models/scimitar/schema/user_spec.rb +0 -10
  42. data/spec/requests/active_record_backed_resources_controller_spec.rb +66 -709
  43. data/spec/requests/application_controller_spec.rb +3 -16
  44. data/spec/spec_helper.rb +0 -8
  45. metadata +14 -25
  46. data/LICENSE.txt +0 -21
  47. data/README.md +0 -710
  48. data/lib/scimitar/support/utilities.rb +0 -51
  49. data/spec/apps/dummy/app/controllers/custom_create_mock_users_controller.rb +0 -25
  50. data/spec/apps/dummy/app/controllers/custom_replace_mock_users_controller.rb +0 -25
  51. data/spec/apps/dummy/app/controllers/custom_save_mock_users_controller.rb +0 -24
  52. data/spec/apps/dummy/app/controllers/custom_update_mock_users_controller.rb +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed2a0e01326248966fb009845e4fa05f4cae800b79bc3d85497960c833869f24
4
- data.tar.gz: c7f92d402444abf8b4df77d8b404c85ff90b06e113126ebafe75c8935608f869
3
+ metadata.gz: 95a2166cc921a400959f9d8d4398f6bf8ecb772f8d7a0a0a73950892e85d808a
4
+ data.tar.gz: cdf5aab3812f10f69c96304e738a150f4208850267527b66d36eeb99548d7b1f
5
5
  SHA512:
6
- metadata.gz: 834cbc912ea8cdf996cb74a57d4f24495b3e0b005924635829ddb5ab99025ca17bdec5aef58c79353af189bb3304c4560017b31c9089614af4cf4b00832909b9
7
- data.tar.gz: 71398ecaa9a879cd37fe41867526a824b9cc4db32efd8c3a23012e086a5509a95db66140f7e0c623bc3bde4ac648f5eca5f51bd99e5a7b2322b65d326ff7ea4d
6
+ metadata.gz: f0925517599b107e44fd93db9be142aebe608892c2c5069c50d22b353c51238290710474b062a002fdb010be3d783c4dea3b314f72f47b4aca3c2385a8fc1377
7
+ data.tar.gz: eef6eebfc64bb2d4adabfca110f26e3a6c9e227f47387da6fb384925899ddf0ae260cf68176f24040a6bb356cf34f6576c920bd44264d4a1fee415aeadc237e6
@@ -21,8 +21,6 @@ module Scimitar
21
21
 
22
22
  rescue_from ActiveRecord::RecordNotFound, with: :handle_resource_not_found # See Scimitar::ApplicationController
23
23
 
24
- before_action :obtain_id_column_name_from_attribute_map
25
-
26
24
  # GET (list)
27
25
  #
28
26
  def index
@@ -39,13 +37,12 @@ module Scimitar
39
37
  pagination_info = scim_pagination_info(query.count())
40
38
 
41
39
  page_of_results = query
42
- .order(@id_column => :asc)
43
40
  .offset(pagination_info.offset)
44
41
  .limit(pagination_info.limit)
45
42
  .to_a()
46
43
 
47
44
  super(pagination_info, page_of_results) do | record |
48
- record_to_scim(record)
45
+ record.to_scim(location: url_for(action: :show, id: record.id))
49
46
  end
50
47
  end
51
48
 
@@ -54,61 +51,45 @@ module Scimitar
54
51
  def show
55
52
  super do |record_id|
56
53
  record = self.find_record(record_id)
57
- record_to_scim(record)
54
+ record.to_scim(location: url_for(action: :show, id: record_id))
58
55
  end
59
56
  end
60
57
 
61
58
  # POST (create)
62
59
  #
63
- # Calls #save! on the new record if no block is given, else invokes the
64
- # block, passing it the new ActiveRecord model instance to be saved. It
65
- # is up to the block to make any further changes and persist the record.
66
- #
67
- # Blocks are invoked from within a wrapping database transaction.
68
- # ActiveRecord::RecordInvalid exceptions are handled for you, rendering
69
- # an appropriate SCIM error.
70
- #
71
- def create(&block)
60
+ def create
72
61
  super do |scim_resource|
73
62
  self.storage_class().transaction do
74
63
  record = self.storage_class().new
75
64
  record.from_scim!(scim_hash: scim_resource.as_json())
76
- self.save!(record, &block)
77
- record_to_scim(record)
65
+ self.save!(record)
66
+ record.to_scim(location: url_for(action: :show, id: record.id))
78
67
  end
79
68
  end
80
69
  end
81
70
 
82
71
  # PUT (replace)
83
72
  #
84
- # Calls #save! on the updated record if no block is given, else invokes the
85
- # block, passing the updated record which the block must persist, with the
86
- # same rules as for #create.
87
- #
88
- def replace(&block)
73
+ def replace
89
74
  super do |record_id, scim_resource|
90
75
  self.storage_class().transaction do
91
76
  record = self.find_record(record_id)
92
77
  record.from_scim!(scim_hash: scim_resource.as_json())
93
- self.save!(record, &block)
94
- record_to_scim(record)
78
+ self.save!(record)
79
+ record.to_scim(location: url_for(action: :show, id: record.id))
95
80
  end
96
81
  end
97
82
  end
98
83
 
99
84
  # PATCH (update)
100
85
  #
101
- # Calls #save! on the updated record if no block is given, else invokes the
102
- # block, passing the updated record which the block must persist, with the
103
- # same rules as for #create.
104
- #
105
- def update(&block)
86
+ def update
106
87
  super do |record_id, patch_hash|
107
88
  self.storage_class().transaction do
108
89
  record = self.find_record(record_id)
109
90
  record.from_scim_patch!(patch_hash: patch_hash)
110
- self.save!(record, &block)
111
- record_to_scim(record)
91
+ self.save!(record)
92
+ record.to_scim(location: url_for(action: :show, id: record.id))
112
93
  end
113
94
  end
114
95
  end
@@ -150,43 +131,19 @@ module Scimitar
150
131
  raise NotImplementedError
151
132
  end
152
133
 
153
- # Return an Array of exceptions that #save! can rescue and handle with a
154
- # SCIM error automatically.
155
- #
156
- def scimitar_rescuable_exceptions
157
- [
158
- ActiveRecord::RecordInvalid,
159
- ActiveRecord::RecordNotSaved,
160
- ActiveRecord::RecordNotUnique,
161
- ]
162
- end
163
-
164
134
  # Find a record by ID. Subclasses can override this if they need special
165
135
  # lookup behaviour.
166
136
  #
167
137
  # +record_id+:: Record ID (SCIM schema 'id' value - "our" ID).
168
138
  #
169
139
  def find_record(record_id)
170
- self.storage_scope().find_by!(@id_column => record_id)
171
- end
172
-
173
- # DRY up controller actions - pass a record; returns the SCIM
174
- # representation, with a "show" location specified via #url_for.
175
- #
176
- def record_to_scim(record)
177
- record.to_scim(location: url_for(action: :show, id: record.send(@id_column)))
140
+ self.storage_scope().find(record_id)
178
141
  end
179
142
 
180
143
  # Save a record, dealing with validation exceptions by raising SCIM
181
144
  # errors.
182
145
  #
183
- # +record+:: ActiveRecord subclass to save.
184
- #
185
- # If you just let this superclass handle things, it'll call the standard
186
- # +#save!+ method on the record. If you pass a block, then this block is
187
- # invoked and passed the ActiveRecord model instance to be saved. You can
188
- # then do things like calling a different method, using a service object
189
- # of some kind, perform audit-related operations and so-on.
146
+ # +record+:: ActiveRecord subclass to save (via #save!).
190
147
  #
191
148
  # The return value is not used internally, making life easier for
192
149
  # overriding subclasses to "do the right thing" / avoid mistakes (instead
@@ -194,31 +151,11 @@ module Scimitar
194
151
  # and relying upon this to generate correct response payloads - an early
195
152
  # version of the gem did this and it caused a confusing subclass bug).
196
153
  #
197
- def save!(record, &block)
198
- if block_given?
199
- yield(record)
200
- else
201
- record.save!
202
- end
203
- rescue *self.scimitar_rescuable_exceptions() => exception
204
- handle_on_save_exception(record, exception)
205
- end
154
+ def save!(record)
155
+ record.save!
206
156
 
207
- # Deal with exceptions related to errors upon saving, by responding with
208
- # an appropriate SCIM error. This is most effective if the record has
209
- # validation errors defined, but falls back to the provided exception's
210
- # message otherwise.
211
- #
212
- # +record+:: The record that provoked the exception. Mandatory.
213
- # +exception+:: The exception that was raised. If omitted, a default of
214
- # 'Unknown', in English with no I18n, is used.
215
- #
216
- def handle_on_save_exception(record, exception = RuntimeError.new('Unknown'))
217
- details = if record.errors.present?
218
- record.errors.full_messages.join('; ')
219
- else
220
- exception.message
221
- end
157
+ rescue ActiveRecord::RecordInvalid => exception
158
+ joined_errors = record.errors.full_messages.join('; ')
222
159
 
223
160
  # https://tools.ietf.org/html/rfc7644#page-12
224
161
  #
@@ -228,27 +165,16 @@ module Scimitar
228
165
  # status code 409 (Conflict) with a "scimType" error code of
229
166
  # "uniqueness"
230
167
  #
231
- if exception.is_a?(ActiveRecord::RecordNotUnique) || record.errors.any? { | e | e.type == :taken }
168
+ if record.errors.any? { | e | e.type == :taken }
232
169
  raise Scimitar::ErrorResponse.new(
233
170
  status: 409,
234
171
  scimType: 'uniqueness',
235
- detail: "Operation failed due to a uniqueness constraint: #{details}"
172
+ detail: joined_errors
236
173
  )
237
174
  else
238
- raise Scimitar::ResourceInvalidError.new(details)
175
+ raise Scimitar::ResourceInvalidError.new(joined_errors)
239
176
  end
240
177
  end
241
178
 
242
- # Called via +before_action+ - stores in @id_column the name of whatever
243
- # model column is used to store the record ID, via
244
- # Scimitar::Resources::Mixin::scim_attributes_map.
245
- #
246
- # Default is <tt>:id</tt>.
247
- #
248
- def obtain_id_column_name_from_attribute_map
249
- attrs = storage_class().scim_attributes_map() || {}
250
- @id_column = attrs[:id] || :id
251
- end
252
-
253
179
  end
254
180
  end
@@ -25,11 +25,10 @@ module Scimitar
25
25
  #
26
26
  # ...to "globally" invoke this handler if you wish.
27
27
  #
28
- # +exception+:: Exception instance, used for a configured error reporter
29
- # via #handle_scim_error (if present).
28
+ # +_exception+:: Exception instance (currently unused).
30
29
  #
31
- def handle_resource_not_found(exception)
32
- handle_scim_error(NotFoundError.new(params[:id]), exception)
30
+ def handle_resource_not_found(_exception)
31
+ handle_scim_error(NotFoundError.new(params[:id]))
33
32
  end
34
33
 
35
34
  # This base controller uses:
@@ -39,22 +38,9 @@ module Scimitar
39
38
  # ...to "globally" invoke this handler for all Scimitar errors (including
40
39
  # subclasses).
41
40
  #
42
- # Mandatory parameters are:
43
- #
44
41
  # +error_response+:: Scimitar::ErrorResponse (or subclass) instance.
45
42
  #
46
- # Optional parameters are:
47
- #
48
- # *exception+:: If a Ruby exception was the reason this method is being
49
- # called, pass it here. Any configured exception reporting
50
- # mechanism will be invokved with the given parameter.
51
- # Otherwise, the +error_response+ value is reported.
52
- #
53
- def handle_scim_error(error_response, exception = error_response)
54
- unless Scimitar.engine_configuration.exception_reporter.nil?
55
- Scimitar.engine_configuration.exception_reporter.call(exception)
56
- end
57
-
43
+ def handle_scim_error(error_response)
58
44
  render json: error_response, status: error_response.status
59
45
  end
60
46
 
@@ -69,7 +55,7 @@ module Scimitar
69
55
  # +exception+:: Exception instance.
70
56
  #
71
57
  def handle_bad_json_error(exception)
72
- handle_scim_error(ErrorResponse.new(status: 400, detail: "Invalid JSON - #{exception.message}"), exception)
58
+ handle_scim_error(ErrorResponse.new(status: 400, detail: "Invalid JSON - #{exception.message}"))
73
59
  end
74
60
 
75
61
  # This base controller uses:
@@ -82,7 +68,7 @@ module Scimitar
82
68
  #
83
69
  def handle_unexpected_error(exception)
84
70
  Rails.logger.error("#{exception.message}\n#{exception.backtrace}")
85
- handle_scim_error(ErrorResponse.new(status: 500, detail: exception.message), exception)
71
+ handle_scim_error(ErrorResponse.new(status: 500, detail: exception.message))
86
72
  end
87
73
 
88
74
  # =========================================================================
@@ -96,17 +82,12 @@ module Scimitar
96
82
  # request and subclass processing.
97
83
  #
98
84
  def require_scim
99
- scim_mime_type = Mime::Type.lookup_by_extension(:scim).to_s
100
-
101
- if request.media_type.nil? || request.media_type.empty?
102
- request.format = :scim
103
- request.headers['CONTENT_TYPE'] = scim_mime_type
104
- elsif request.media_type.downcase == scim_mime_type
85
+ if request.content_type&.downcase == Mime::Type.lookup_by_extension(:scim).to_s
105
86
  request.format = :scim
106
87
  elsif request.format == :scim
107
- request.headers['CONTENT_TYPE'] = scim_mime_type
88
+ request.headers['CONTENT_TYPE'] = Mime::Type.lookup_by_extension(:scim).to_s
108
89
  else
109
- handle_scim_error(ErrorResponse.new(status: 406, detail: "Only #{scim_mime_type} type is accepted."))
90
+ handle_scim_error(ErrorResponse.new(status: 406, detail: "Only #{Mime::Type.lookup_by_extension(:scim)} type is accepted."))
110
91
  end
111
92
  end
112
93
 
@@ -124,13 +105,8 @@ module Scimitar
124
105
  #
125
106
  # https://stackoverflow.com/questions/10239970/what-is-the-delimiter-for-www-authenticate-for-multiple-schemes
126
107
  #
127
- response.set_header('WWW-Authenticate', 'Basic' ) if Scimitar.engine_configuration.basic_authenticator.present?
128
- response.set_header('WWW-Authenticate', 'Bearer') if Scimitar.engine_configuration.token_authenticator.present?
129
-
130
- # No matter what a caller might request via headers, the only content
131
- # type we can ever respond with is JSON-for-SCIM.
132
- #
133
- response.set_header('Content-Type', "#{Mime::Type.lookup_by_extension(:scim)}; charset=utf-8")
108
+ response.set_header('WWW_AUTHENTICATE', 'Basic' ) if Scimitar.engine_configuration.basic_authenticator.present?
109
+ response.set_header('WWW_AUTHENTICATE', 'Bearer') if Scimitar.engine_configuration.token_authenticator.present?
134
110
  end
135
111
 
136
112
  def authenticate
@@ -139,15 +115,11 @@ module Scimitar
139
115
 
140
116
  def authenticated?
141
117
  result = if Scimitar.engine_configuration.basic_authenticator.present?
142
- authenticate_with_http_basic do |username, password|
143
- instance_exec(username, password, &Scimitar.engine_configuration.basic_authenticator)
144
- end
118
+ authenticate_with_http_basic(&Scimitar.engine_configuration.basic_authenticator)
145
119
  end
146
120
 
147
121
  result ||= if Scimitar.engine_configuration.token_authenticator.present?
148
- authenticate_with_http_token do |token, options|
149
- instance_exec(token, options, &Scimitar.engine_configuration.token_authenticator)
150
- end
122
+ authenticate_with_http_token(&Scimitar.engine_configuration.token_authenticator)
151
123
  end
152
124
 
153
125
  return result
@@ -4,11 +4,6 @@ module Scimitar
4
4
  class SchemasController < ApplicationController
5
5
  def index
6
6
  schemas = Scimitar::Engine.schemas
7
-
8
- schemas.each do |schema|
9
- schema.meta.location = scim_schemas_url(name: schema.id)
10
- end
11
-
12
7
  schemas_by_id = schemas.reduce({}) do |hash, schema|
13
8
  hash[schema.id] = schema
14
9
  hash
@@ -7,6 +7,12 @@ module Scimitar
7
7
  #
8
8
  class Address < Base
9
9
  set_schema Scimitar::Schema::Address
10
+
11
+ # Returns the JSON representation of an Address.
12
+ #
13
+ def as_json(options = {})
14
+ {'type' => 'work'}.merge(super(options))
15
+ end
10
16
  end
11
17
  end
12
18
  end
@@ -7,23 +7,15 @@ module Scimitar
7
7
  class EngineConfiguration
8
8
  include ActiveModel::Model
9
9
 
10
- attr_accessor(
11
- :uses_defaults,
12
- :basic_authenticator,
13
- :token_authenticator,
14
- :application_controller_mixin,
15
- :exception_reporter,
16
- :optional_value_fields_required,
17
- )
10
+ attr_accessor :basic_authenticator,
11
+ :token_authenticator,
12
+ :application_controller_mixin
18
13
 
19
14
  def initialize(attributes = {})
20
- @uses_defaults = attributes.empty?
21
15
 
22
- # Set defaults that may be overridden by the initializer.
16
+ # No defaults yet - reserved for future use.
23
17
  #
24
- defaults = {
25
- optional_value_fields_required: true
26
- }
18
+ defaults = {}
27
19
 
28
20
  super(defaults.merge(attributes))
29
21
  end
@@ -16,17 +16,5 @@ module Scimitar
16
16
  data['scimType'] = scimType if scimType
17
17
  data
18
18
  end
19
-
20
- # Originally Scimitar used attribute "detail" for exception text; it was
21
- # only for JSON responses at the time, but in hindsight was a bad choice.
22
- # It should have been "message" given inheritance from StandardError, which
23
- # then works properly with e.g. error reporting services.
24
- #
25
- # The "detail" attribute is still present, for backwards compatibility with
26
- # any client code that might be using this class.
27
- #
28
- def message
29
- self.detail
30
- end
31
19
  end
32
20
  end
@@ -78,7 +78,7 @@ module Scimitar
78
78
  # method's return value here.
79
79
  #
80
80
  def initialize(attribute_map)
81
- @attribute_map = attribute_map.with_indifferent_case_insensitive_access()
81
+ @attribute_map = attribute_map
82
82
  end
83
83
 
84
84
  # Parse SCIM filter query into RPN stack
@@ -192,7 +192,7 @@ module Scimitar
192
192
 
193
193
  ast.push(self.start_group? ? self.parse_group() : self.pop())
194
194
 
195
- if ast.last.is_a?(String) && !UNARY_OPERATORS.include?(ast.last.downcase) || ast.last.is_a?(Array)
195
+ unless ! ast.last.is_a?(String) || UNARY_OPERATORS.include?(ast.last.downcase)
196
196
  expect_op ^= true
197
197
  end
198
198
  end
@@ -601,27 +601,12 @@ module Scimitar
601
601
  column_names = self.activerecord_columns(scim_attribute)
602
602
  value = self.activerecord_parameter(scim_parameter)
603
603
  value_for_like = self.sql_modified_value(scim_operator, value)
604
- arel_columns = column_names.map do |column|
605
- if base_scope.model.column_names.include?(column.to_s)
606
- arel_table[column]
607
- elsif column.is_a?(Arel::Attribute)
608
- column
609
- end
610
- end
611
-
612
- raise Scimitar::FilterError unless arel_columns.all?
604
+ all_supported = column_names.all? { | column_name | base_scope.model.column_names.include?(column_name.to_s) }
613
605
 
614
- unless case_sensitive
615
- lc_scim_attribute = scim_attribute.downcase()
616
-
617
- case_sensitive = (
618
- lc_scim_attribute == 'id' ||
619
- lc_scim_attribute == 'externalid' ||
620
- lc_scim_attribute.start_with?('meta.')
621
- )
622
- end
606
+ raise Scimitar::FilterError unless all_supported
623
607
 
624
- arel_columns.each.with_index do | arel_column, index |
608
+ column_names.each.with_index do | column_name, index |
609
+ arel_column = arel_table[column_name]
625
610
  arel_operation = case scim_operator
626
611
  when 'eq'
627
612
  if case_sensitive
@@ -646,9 +631,9 @@ module Scimitar
646
631
  when 'co', 'sw', 'ew'
647
632
  arel_column.matches(value_for_like, nil, case_sensitive)
648
633
  when 'pr'
649
- arel_column.relation.grouping(arel_column.not_eq_all(['', nil]))
634
+ arel_table.grouping(arel_column.not_eq_all(['', nil]))
650
635
  else
651
- raise Scimitar::FilterError.new("Unsupported operator: '#{scim_operator}'")
636
+ raise Scimitar::FilterError
652
637
  end
653
638
 
654
639
  if index == 0
@@ -671,10 +656,10 @@ module Scimitar
671
656
  # +scim_attribute+:: SCIM attribute from a filter string.
672
657
  #
673
658
  def activerecord_columns(scim_attribute)
674
- raise Scimitar::FilterError.new("No scim_attribute provided") if scim_attribute.blank?
659
+ raise Scimitar::FilterError if scim_attribute.blank?
675
660
 
676
661
  mapped_attribute = self.attribute_map()[scim_attribute]
677
- raise Scimitar::FilterError.new("Unable to find domain attribute from SCIM attribute: '#{scim_attribute}'") if mapped_attribute.blank?
662
+ raise Scimitar::FilterError if mapped_attribute.blank?
678
663
 
679
664
  if mapped_attribute[:ignore]
680
665
  return []
@@ -2,7 +2,7 @@ module Scimitar
2
2
  class ResourceInvalidError < ErrorResponse
3
3
 
4
4
  def initialize(error_message)
5
- super(status: 400, scimType: 'invalidValue', detail: "Operation failed since record has become invalid: #{error_message}")
5
+ super(status: 400, scimType: 'invalidValue', detail:"Operation failed since record has become invalid: #{error_message}")
6
6
  end
7
7
 
8
8
  end
@@ -112,7 +112,7 @@ module Scimitar
112
112
  end
113
113
 
114
114
  def self.complex_scim_attributes
115
- schemas.flat_map(&:scim_attributes).select(&:complexType).group_by(&:name)
115
+ schema.scim_attributes.select(&:complexType).group_by(&:name)
116
116
  end
117
117
 
118
118
  def complex_type_from_hash(scim_attribute, attr_value)
@@ -138,24 +138,14 @@ module Scimitar
138
138
  end
139
139
 
140
140
  def as_json(options = {})
141
- self.meta = Meta.new unless self.meta && self.meta.is_a?(Meta)
142
- self.meta.resourceType = self.class.resource_type_id
143
-
144
- non_returnable_attributes = self.class
145
- .schemas
146
- .flat_map(&:scim_attributes)
147
- .filter_map { |attribute| attribute.name if attribute.returned == 'never' }
148
-
149
- non_returnable_attributes << 'errors'
150
-
151
- original_hash = super(options).except(*non_returnable_attributes)
141
+ self.meta = Meta.new unless self.meta
142
+ meta.resourceType = self.class.resource_type_id
143
+ original_hash = super(options).except('errors')
152
144
  original_hash.merge!('schemas' => self.class.schemas.map(&:id))
153
-
154
145
  self.class.extended_schemas.each do |extension_schema|
155
146
  extension_attributes = extension_schema.scim_attributes.map(&:name)
156
147
  original_hash.merge!(extension_schema.id => original_hash.extract!(*extension_attributes))
157
148
  end
158
-
159
149
  original_hash
160
150
  end
161
151