Module: Labimotion::ProfileAiSettings
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/labimotion/models/concerns/profile_ai_settings.rb
Overview
Per-user LabIMotion AI settings, stored on the host's profile record.
The model, an optional personal API key and an optional provider endpoint of
one's own live under one key in the host's data jsonb. They sit on the
profile rather than in a table of ours because the credential belongs to the
person, not to LabIMotion — but the shape of the value is ours, so reading
and writing it belongs here rather than in each host.
The API key is stored ENCRYPTED and never returned to a client: only whether
one is set. Encryption stays the HOST's — key management is a deployment
concern and a gem has no business inventing one. Chemotion supplies it as an
Encryptor concern, which is pulled in below when present, so a host there
includes this one alone:
class Profile < ApplicationRecord
include Labimotion::ProfileAiSettings
end
A host that names its encryption differently just defines encrypt_value
and decrypt_value on the model itself.
Constant Summary collapse
- DATA_KEY =
'labimotion_ai'
Instance Method Summary collapse
-
#labimotion_ai_api_key ⇒ Object
Decrypted personal API key, or nil when none is stored.
- #labimotion_ai_api_key? ⇒ Boolean
- #labimotion_ai_api_path ⇒ Object
-
#labimotion_ai_base_url ⇒ Object
Personal provider endpoint (BYO-Provider).
- #labimotion_ai_model ⇒ Object
- #labimotion_ai_settings ⇒ Object
-
#update_labimotion_ai(model: nil, api_key: nil, base_url: nil, api_path: nil) ⇒ Object
Persist the settings.
Instance Method Details
#labimotion_ai_api_key ⇒ Object
Decrypted personal API key, or nil when none is stored.
72 73 74 75 76 77 |
# File 'lib/labimotion/models/concerns/profile_ai_settings.rb', line 72 def labimotion_ai_api_key enc = labimotion_ai_settings['api_key'] return nil if enc.blank? decrypt_value(enc).presence end |
#labimotion_ai_api_key? ⇒ Boolean
67 68 69 |
# File 'lib/labimotion/models/concerns/profile_ai_settings.rb', line 67 def labimotion_ai_api_key? labimotion_ai_settings['api_key'].present? end |
#labimotion_ai_api_path ⇒ Object
63 64 65 |
# File 'lib/labimotion/models/concerns/profile_ai_settings.rb', line 63 def labimotion_ai_api_path labimotion_ai_settings['api_path'].presence end |
#labimotion_ai_base_url ⇒ Object
Personal provider endpoint (BYO-Provider). Honored only alongside a personal key, and SSRF-validated by Labimotion::AiEgressGuard before any request is made.
59 60 61 |
# File 'lib/labimotion/models/concerns/profile_ai_settings.rb', line 59 def labimotion_ai_base_url labimotion_ai_settings['base_url'].presence end |
#labimotion_ai_model ⇒ Object
52 53 54 |
# File 'lib/labimotion/models/concerns/profile_ai_settings.rb', line 52 def labimotion_ai_model labimotion_ai_settings['model'].presence end |
#labimotion_ai_settings ⇒ Object
48 49 50 |
# File 'lib/labimotion/models/concerns/profile_ai_settings.rb', line 48 def labimotion_ai_settings (data || {})[DATA_KEY] || {} end |
#update_labimotion_ai(model: nil, api_key: nil, base_url: nil, api_path: nil) ⇒ Object
Persist the settings. For every field: nil leaves it unchanged, a blank string clears it, anything else is stored (the api_key encrypted). Returns the safe summary — never the key itself.
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/labimotion/models/concerns/profile_ai_settings.rb', line 82 def update_labimotion_ai(model: nil, api_key: nil, base_url: nil, api_path: nil) ai = labimotion_ai_settings.dup ai['model'] = model.to_s if model unless api_key.nil? if api_key.to_s.strip.blank? ai.delete('api_key') else ai['api_key'] = encrypt_value(api_key.to_s.strip) end end set_or_clear_labimotion_ai(ai, 'base_url', base_url) set_or_clear_labimotion_ai(ai, 'api_path', api_path) # Reassign the whole `data` hash rather than mutating in place, so the # jsonb column is reliably marked dirty and actually persisted. self.data = (data || {}).merge(DATA_KEY => ai) save! { model: ai['model'], api_key_set: ai['api_key'].present?, base_url: ai['base_url'], api_path: ai['api_path'] } end |