scimitar 1.8.1 → 2.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.
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