main
1# frozen_string_literal: true
2
3module Scim
4 module Kit
5 module V2
6 # Represents a SCIM Attribute
7 class Attribute
8 include ::ActiveModel::Validations
9 include Attributable
10 include Templatable
11 attr_reader :_type
12 attr_reader :_resource
13 attr_reader :_value
14
15 validate :presence_of_value, if: proc { |x| x._type.required }
16 validate :inclusion_of_value, if: proc { |x| x._type.canonical_values }
17 validate :validate_type, unless: proc { |x| x.complex? }
18 validate :validate_complex, if: proc { |x| x.complex? }
19 validate :multiple, if: proc { |x| x.multi_valued && !x.complex? }
20
21 delegate :complex?, :multi_valued, to: :_type
22
23 def initialize(resource:, type:, value: nil)
24 @_type = type
25 @_value = value || type.multi_valued ? [] : nil
26 @_resource = resource
27
28 define_attributes_for(resource, type.attributes)
29 end
30
31 def _assign(new_value, coerce: false)
32 @_value = coerce ? _type.coerce(new_value) : new_value
33 end
34
35 def _value=(new_value)
36 _assign(new_value, coerce: true)
37 end
38
39 def renderable?
40 return false if server_only?
41 return false if client_only?
42 return false if restricted?
43
44 true
45 end
46
47 def each_value(&block)
48 Array(_value).each(&block)
49 end
50
51 private
52
53 def server_only?
54 read_only? && _resource.mode?(:client)
55 end
56
57 def client_only?
58 write_only? && (_resource.mode?(:server) || _value.blank?)
59 end
60
61 def restricted?
62 _resource.mode?(:server) && _type.returned == Returned::NEVER
63 end
64
65 def presence_of_value
66 return unless _type.required && _value.blank?
67
68 errors.add(_type.name, I18n.t('errors.messages.blank'))
69 end
70
71 def inclusion_of_value
72 return if _type.canonical_values.include?(_value)
73
74 errors.add(_type.name, I18n.t('errors.messages.inclusion'))
75 end
76
77 def validate_type
78 return if _value.nil?
79 return if _type.valid?(_value)
80
81 errors.add(_type.name, I18n.t('errors.messages.invalid'))
82 end
83
84 def validate_complex
85 validates_with ComplexAttributeValidator
86 end
87
88 def multiple
89 return unless _value.respond_to?(:to_a)
90
91 duped_type = _type.dup
92 duped_type.multi_valued = false
93 _value.to_a.each do |x|
94 unless duped_type.valid?(x)
95 errors.add(duped_type.name, I18n.t('errors.messages.invalid'))
96 end
97 end
98 end
99
100 def read_only?
101 _type.mutability == Mutability::READ_ONLY
102 end
103
104 def write_only?
105 _type.mutability == Mutability::WRITE_ONLY
106 end
107 end
108 end
109 end
110end