Class: Masks::Check
- Inherits:
-
ApplicationModel
- Object
- ApplicationModel
- Masks::Check
- Defined in:
- app/models/masks/check.rb
Overview
Checks track attempts to verify one attribute of a session, like the actor or their password.
Every session contains a list of checks that can be manipulated while it is masked. Credentials associated with the session are typical consumers of checks, but direct manipulation is possible as well.
Once a check’s consumers have reported their status (approved, denied, or skipped) it will report an overall status based on the results, either:
-
passed?
- true if attempts were made and all were approved, not skipped, or the check is optional -
failed?
- true if attempts were made and any were denied
Note: Checks can exist in a middle state, neither passed or failed, in the case that no attempts were made.
Instance Method Summary collapse
-
#approve!(id, **opts) ⇒ Object
Approves an attempt.
-
#attempt_approved?(id) ⇒ Boolean
Returns true if a specific attempt was approved.
-
#attempt_skipped?(id) ⇒ Boolean
Returns true if a specific attempt was skipped.
-
#attempts ⇒ Hash
Returns a hash of attempts for the check.
-
#clear!(id) ⇒ Datetime
Clears all data for attempts by the given
id
. -
#deny!(id, **opts) ⇒ Object
Denies an attempt.
-
#optional? ⇒ Boolean
Whether or not the check is optional.
-
#passed? ⇒ Boolean
Whether or not the check passed.
-
#passed_at ⇒ Datetime
Returns the time the check passed, if it did.
-
#skip!(id, **opts) ⇒ Object
Skips an attempt.
-
#to_session ⇒ Hash
Returns a version of the check intended for the rails session.
Instance Method Details
#approve!(id, **opts) ⇒ Object
Approves an attempt.
Additional metadata can be passed as keyword arguments, and it will be saved alongside the attempt data.
106 107 108 109 110 111 112 113 |
# File 'app/models/masks/check.rb', line 106 def approve!(id, **opts) self.approved = true merge_attempt( id, opts.merge(approved_at: Time.current.iso8601, skipped_at: nil) ) end |
#attempt_approved?(id) ⇒ Boolean
Returns true if a specific attempt was approved.
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'app/models/masks/check.rb', line 67 def attempt_approved?(id) opts = attempts.fetch(id.to_s, {}) return approved unless lifetime return false if opts["skipped_at"] time = case opts["approved_at"] when nil return false when String Time.try(:parse, opts["approved_at"]) else time end if time time + ActiveSupport::Duration.parse(lifetime) > Time.current else false end end |
#attempt_skipped?(id) ⇒ Boolean
Returns true if a specific attempt was skipped.
93 94 95 96 |
# File 'app/models/masks/check.rb', line 93 def attempt_skipped?(id) opts = attempts.fetch(id.to_s, {}) opts["skipped_at"] && optional end |
#attempts ⇒ Hash
Returns a hash of attempts for the check.
Each key in the hash is the name of a specific attemptee, like a class or credential. The value is a hash of data about the attempt (like when it was attempted, approved, denied, and/or skipped).
37 38 39 |
# File 'app/models/masks/check.rb', line 37 def attempts attempted.deep_merge(@attempts || {}).deep_stringify_keys end |
#clear!(id) ⇒ Datetime
Clears all data for attempts by the given id
.
163 164 165 166 |
# File 'app/models/masks/check.rb', line 163 def clear!(id) @attempts&.except!(id) attempted.except!(id) end |
#deny!(id, **opts) ⇒ Object
Denies an attempt.
Additional metadata can be passed as keyword arguments, and it will be saved alongside the attempt data.
140 141 142 143 144 |
# File 'app/models/masks/check.rb', line 140 def deny!(id, **opts) self.denied = true merge_attempt(id, opts.merge(approved_at: nil, skipped_at: nil)) end |
#optional? ⇒ Boolean
Whether or not the check is optional.
Optional checks always return true
for passed?
.
46 47 48 |
# File 'app/models/masks/check.rb', line 46 def optional? optional end |
#passed? ⇒ Boolean
Whether or not the check passed.
true
if attempts were made and all were approved, not skipped, or the check is optional
55 56 57 58 59 60 61 62 |
# File 'app/models/masks/check.rb', line 55 def passed? return true if optional? && !failed? return false if attempts.keys.empty? attempts.all? do |id, _opts| attempt_approved?(id) || attempt_skipped?(id) end end |
#passed_at ⇒ Datetime
Returns the time the check passed, if it did.
148 149 150 151 152 153 154 155 156 157 158 |
# File 'app/models/masks/check.rb', line 148 def passed_at return unless passed? attempts .map do |_id, opts| time = opts["approved_at"] || opts["skipped_at"] Time.try(:parse, time) if time end .compact .max end |
#skip!(id, **opts) ⇒ Object
Skips an attempt. Skips count as approvals.
Additional metadata can be passed as keyword arguments, and it will be saved alongside the attempt data.
123 124 125 126 127 128 129 130 |
# File 'app/models/masks/check.rb', line 123 def skip!(id, **opts) self.skipped = true merge_attempt( id, opts.merge(approved_at: nil, skipped_at: Time.current.iso8601) ) end |
#to_session ⇒ Hash
Returns a version of the check intended for the rails session.
170 171 172 173 174 |
# File 'app/models/masks/check.rb', line 170 def to_session return { optional:, attempted: } unless lifetime { optional:, attempted: attempts } end |