Class: Scimitar::Resources::Base
- Inherits:
-
Object
- Object
- Scimitar::Resources::Base
- Includes:
- ActiveModel::Model, Errors, Schema::DerivedAttributes
- Defined in:
- app/models/scimitar/resources/base.rb
Overview
The base class for all SCIM resources.
Instance Attribute Summary collapse
-
#errors ⇒ Object
readonly
Returns the value of attribute errors.
-
#externalId ⇒ Object
Returns the value of attribute externalId.
-
#id ⇒ Object
Returns the value of attribute id.
-
#meta ⇒ Object
Returns the value of attribute meta.
Class Method Summary collapse
- .all_attributes ⇒ Object
- .complex_scim_attributes ⇒ Object
-
.extend_schema(schema) ⇒ Object
Can be used to extend an existing resource type’s schema.
- .extended_schemas ⇒ Object
-
.find_attribute(*path) ⇒ Object
Calls to Scimitar::Schema::Base::find_attribute for each of the schemas in ::schemas, in order returned (so main schema would be first, then any extended schemas searched next).
- .resource_type(location) ⇒ Object
- .resource_type_id ⇒ Object
- .schemas ⇒ Object
Instance Method Summary collapse
-
#as_json(options = {}) ⇒ Object
Renders *in full* as JSON; typically used for write-based operations…
- #complex_type_from_hash(scim_attribute, attr_value) ⇒ Object
- #constantize_complex_types(hash) ⇒ Object
-
#flatten_extension_attributes(options) ⇒ Object
Scimitar has at present a general limitation in handling schema IDs, which just involves stripping them and requiring attributes across all extension schemas to be overall unique.
-
#initialize(options = {}) ⇒ Base
constructor
A new instance of Base.
- #validate_resource ⇒ Object
Methods included from Errors
Constructor Details
#initialize(options = {}) ⇒ Base
Returns a new instance of Base.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'app/models/scimitar/resources/base.rb', line 13 def initialize( = {}) flattened_attributes = flatten_extension_attributes() ci_all_attributes = Scimitar::Support::HashWithIndifferentCaseInsensitiveAccess.new camel_attributes = {} # Create a map where values are the schema-correct-case attribute names # and the values are set the same, but since the ci_all_attributes data # type is HashWithIndifferentCaseInsensitiveAccess, lookups in this are # case insensitive. Thus, arbitrary case input data can be mapped to # the case correctness required for ActiveModel's attribute accessors. # self.class.all_attributes.each { |attr| ci_all_attributes[attr] = attr } flattened_attributes.each do | key, value | if ci_all_attributes.key?(key) camel_attributes[ci_all_attributes[key]] = value end end super(camel_attributes) constantize_complex_types(camel_attributes) @errors = ActiveModel::Errors.new(self) end |
Instance Attribute Details
#errors ⇒ Object (readonly)
Returns the value of attribute errors.
10 11 12 |
# File 'app/models/scimitar/resources/base.rb', line 10 def errors @errors end |
#externalId ⇒ Object
Returns the value of attribute externalId.
9 10 11 |
# File 'app/models/scimitar/resources/base.rb', line 9 def externalId @externalId end |
#id ⇒ Object
Returns the value of attribute id.
9 10 11 |
# File 'app/models/scimitar/resources/base.rb', line 9 def id @id end |
#meta ⇒ Object
Returns the value of attribute meta.
9 10 11 |
# File 'app/models/scimitar/resources/base.rb', line 9 def @meta end |
Class Method Details
.all_attributes ⇒ Object
121 122 123 124 |
# File 'app/models/scimitar/resources/base.rb', line 121 def self.all_attributes scim_attributes = schemas.map(&:scim_attributes).flatten.map(&:name) scim_attributes + [:id, :externalId, :meta] end |
.complex_scim_attributes ⇒ Object
145 146 147 |
# File 'app/models/scimitar/resources/base.rb', line 145 def self.complex_scim_attributes schemas.flat_map(&:scim_attributes).select(&:complexType).group_by(&:name) end |
.extend_schema(schema) ⇒ Object
Can be used to extend an existing resource type’s schema. For example:
module Scim
module Schema
class MyExtension < Scimitar::Schema::Base
def initialize( = {})
super(name: 'ExtendedGroup',
id: self.class.id,
description: 'Represents extra info about a group',
scim_attributes: self.class.scim_attributes)
end
def self.id
'urn:ietf:params:scim:schemas:extension:extendedgroup:2.0:Group'
end
def self.scim_attributes
[Scimitar::Schema::Attribute.new(name: 'someAddedAttribute',
type: 'string',
required: true,
canonicalValues: ['FOO', 'BAR'])]
end
end
end
end
Scimitar::Resources::Group.extend_schema Scim::Schema::MyExtension
108 109 110 111 |
# File 'app/models/scimitar/resources/base.rb', line 108 def self.extend_schema(schema) derive_attributes_from_schema(schema) extended_schemas << schema end |
.extended_schemas ⇒ Object
113 114 115 |
# File 'app/models/scimitar/resources/base.rb', line 113 def self.extended_schemas @extended_schemas ||= [] end |
.find_attribute(*path) ⇒ Object
Calls to Scimitar::Schema::Base::find_attribute for each of the schemas in ::schemas, in order returned (so main schema would be first, then any extended schemas searched next). Returns the first match found, or nil
.
See Scimitar::Schema::Base::find_attribute for details on parameters, more about the return value and other general information.
134 135 136 137 138 139 140 141 142 143 |
# File 'app/models/scimitar/resources/base.rb', line 134 def self.find_attribute(*path) found_attribute = nil self.schemas.each do | schema | found_attribute = schema.find_attribute(*path) break unless found_attribute.nil? end return found_attribute end |
.resource_type(location) ⇒ Object
200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'app/models/scimitar/resources/base.rb', line 200 def self.resource_type(location) resource_type = ResourceType.new( endpoint: endpoint, schema: schema.id, id: resource_type_id, name: resource_type_id, schemaExtensions: extended_schemas.map(&:id) ) resource_type..location = location resource_type end |
.resource_type_id ⇒ Object
196 197 198 |
# File 'app/models/scimitar/resources/base.rb', line 196 def self.resource_type_id name.demodulize end |
.schemas ⇒ Object
117 118 119 |
# File 'app/models/scimitar/resources/base.rb', line 117 def self.schemas ([schema] + extended_schemas).flatten end |
Instance Method Details
#as_json(options = {}) ⇒ Object
Renders *in full* as JSON; typically used for write-based operations…
record = self.storage_class().new
record.from_scim!(scim_hash: scim_resource.as_json())
self.save!(record)
…so all fields, even those marked “returned: false”, are included. Use Scimitar::Resources::Mixin::to_scim to obtain a SCIM object with non-returnable fields omitted, rendering that as JSON via #to_json.
181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'app/models/scimitar/resources/base.rb', line 181 def as_json( = {}) self. = Meta.new unless self. && self..is_a?(Meta) self..resourceType = self.class.resource_type_id original_hash = super().except('errors') original_hash.merge!('schemas' => self.class.schemas.map(&:id)) self.class.extended_schemas.each do |extension_schema| extension_attributes = extension_schema.scim_attributes.map(&:name) original_hash.merge!(extension_schema.id => original_hash.extract!(*extension_attributes)) end original_hash end |
#complex_type_from_hash(scim_attribute, attr_value) ⇒ Object
149 150 151 152 153 154 155 |
# File 'app/models/scimitar/resources/base.rb', line 149 def complex_type_from_hash(scim_attribute, attr_value) if attr_value.is_a?(Hash) scim_attribute.complexType.new(attr_value) else attr_value end end |
#constantize_complex_types(hash) ⇒ Object
157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'app/models/scimitar/resources/base.rb', line 157 def constantize_complex_types(hash) hash.with_indifferent_access.each_pair do |attr_name, attr_value| scim_attribute = self.class.complex_scim_attributes[attr_name].try(:first) if scim_attribute&.complexType if scim_attribute.multiValued self.send("#{attr_name}=", attr_value&.map {|attr_for_each_item| complex_type_from_hash(scim_attribute, attr_for_each_item)}) else self.send("#{attr_name}=", complex_type_from_hash(scim_attribute, attr_value)) end end end end |
#flatten_extension_attributes(options) ⇒ Object
Scimitar has at present a general limitation in handling schema IDs, which just involves stripping them and requiring attributes across all extension schemas to be overall unique.
This method takes an options payload for the initializer and strips out recognised schema IDs, so that the resulting attribute data matches the resource attribute map.
attributes
-
Attributes to assign via initializer; typically a POST payload of attributes that has been run through Rails strong parameters for safety.
Returns a new object of the same class as options
with recognised schema IDs removed.
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'app/models/scimitar/resources/base.rb', line 53 def flatten_extension_attributes() flattened = .class.new lower_case_schema_ids = self.class.extended_schemas.map do | schema | schema.id.downcase() end .each do | key, value | path = Scimitar::Support::Utilities::path_str_to_array( self.class.extended_schemas, key ) if path.first.include?(':') && lower_case_schema_ids.include?(path.first.downcase) path.shift() end if path.empty? flattened.merge!(value) else flattened[path.join('.')] = value end end return flattened end |
#validate_resource ⇒ Object
213 214 215 216 217 218 |
# File 'app/models/scimitar/resources/base.rb', line 213 def validate_resource self.class.schema.valid?(self) self.class.extended_schemas.each do |extended_schema| extended_schema.valid?(self) end end |