Class: RailsMarkup::Annotation
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- RailsMarkup::Annotation
- Defined in:
- app/models/rails_markup/annotation.rb
Constant Summary collapse
- INTENTS =
%w[fix change question approve].freeze
- SEVERITIES =
%w[suggestion important blocking].freeze
- STATUSES =
%w[pending acknowledged resolved dismissed].freeze
- BROWSER_ATTRIBUTES =
%w[content intent severity selected_text target page_url].freeze
- BROWSER_METADATA_KEYS =
%w[tool url localId sessionId screenshot].freeze
- CLIENT_UUID_PATTERN =
/\A[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\z/- CLIENT_UUID_INPUT_PATTERN =
/\A[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\z/i- LEGACY_SESSION_PATTERN =
/\Arm-[0-9a-f]{16}\z/i- LEGACY_CLIENT_ID_LIMIT =
256- LEGACY_UUID_NAMESPACE =
"265e7cf0-8be6-5e21-8f31-a582cfde8646"
Class Method Summary collapse
- .distinct_authors ⇒ Object
- .legacy_client_uuid(session_id:, legacy_client_id:) ⇒ Object
- .normalize_client_uuid(value) ⇒ Object
- .valid_client_uuid?(value) ⇒ Boolean
Instance Method Summary collapse
- #acknowledge! ⇒ Object
- #add_reply!(message:, role: "agent") ⇒ Object
- #apply_browser_state(attributes, dirty_fields: []) ⇒ Object
- #as_api_json ⇒ Object
- #author_name ⇒ Object
- #dismiss!(reason: nil) ⇒ Object
- #resolve!(summary: nil) ⇒ Object
Class Method Details
.distinct_authors ⇒ Object
90 91 92 93 94 95 96 |
# File 'app/models/rails_markup/annotation.rb', line 90 def self. if connection.adapter_name.downcase.include?("postgres") where("metadata->>'author' IS NOT NULL").distinct.pluck(Arel.sql("metadata->>'author'")).compact.sort else all.filter_map(&:author_name).uniq.sort end end |
.legacy_client_uuid(session_id:, legacy_client_id:) ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'app/models/rails_markup/annotation.rb', line 48 def self.legacy_client_uuid(session_id:, legacy_client_id:) session_id = session_id.to_s legacy_client_id = legacy_client_id.to_s unless LEGACY_SESSION_PATTERN.match?(session_id) && legacy_client_id.present? && legacy_client_id.bytesize <= LEGACY_CLIENT_ID_LIMIT raise ArgumentError, "legacy client identity requires a valid session and client id" end namespace = [LEGACY_UUID_NAMESPACE.delete("-")].pack("H*") bytes = Digest::SHA1.digest(namespace + "#{session_id}\0#{legacy_client_id}").bytes.first(16) bytes[6] = (bytes[6] & 0x0f) | 0x50 bytes[8] = (bytes[8] & 0x3f) | 0x80 hex = bytes.pack("C*").unpack1("H*") "#{hex[0, 8]}-#{hex[8, 4]}-#{hex[12, 4]}-#{hex[16, 4]}-#{hex[20, 12]}" end |
.normalize_client_uuid(value) ⇒ Object
44 45 46 |
# File 'app/models/rails_markup/annotation.rb', line 44 def self.normalize_client_uuid(value) value.downcase if value.is_a?(String) && CLIENT_UUID_INPUT_PATTERN.match?(value) end |
.valid_client_uuid?(value) ⇒ Boolean
40 41 42 |
# File 'app/models/rails_markup/annotation.rb', line 40 def self.valid_client_uuid?(value) value.is_a?(String) && CLIENT_UUID_PATTERN.match?(value) end |
Instance Method Details
#acknowledge! ⇒ Object
109 110 111 112 113 |
# File 'app/models/rails_markup/annotation.rb', line 109 def acknowledge! raise "Cannot acknowledge a #{status} annotation" unless status == "pending" update!(status: "acknowledged") end |
#add_reply!(message:, role: "agent") ⇒ Object
133 134 135 136 |
# File 'app/models/rails_markup/annotation.rb', line 133 def add_reply!(message:, role: "agent") add_thread_entry(role: role, message: ) save! end |
#apply_browser_state(attributes, dirty_fields: []) ⇒ Object
102 103 104 105 106 107 |
# File 'app/models/rails_markup/annotation.rb', line 102 def apply_browser_state(attributes, dirty_fields: []) assign_attributes(attributes.slice(*BROWSER_ATTRIBUTES)) self. = ( || {}).merge(attributes.fetch("metadata", {}).slice(*BROWSER_METADATA_KEYS)) self.status = attributes["status"] if dirty_fields.include?("status") self end |
#as_api_json ⇒ Object
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'app/models/rails_markup/annotation.rb', line 138 def as_api_json { id: id.to_s, clientId: client_uuid, userId: user_id, authorName: , content: content, intent: intent, severity: severity, status: status, selectedText: selected_text, pageUrl: page_url, target: target, metadata: , thread: thread, createdAt: created_at&.iso8601, updatedAt: updated_at&.iso8601 } end |
#author_name ⇒ Object
98 99 100 |
# File 'app/models/rails_markup/annotation.rb', line 98 def &.dig("author") end |
#dismiss!(reason: nil) ⇒ Object
124 125 126 127 128 129 130 131 |
# File 'app/models/rails_markup/annotation.rb', line 124 def dismiss!(reason: nil) raise "Cannot dismiss a #{status} annotation" unless status.in?(%w[pending acknowledged]) transaction do add_thread_entry(role: "agent", message: reason) if reason.present? update!(status: "dismissed") end end |
#resolve!(summary: nil) ⇒ Object
115 116 117 118 119 120 121 122 |
# File 'app/models/rails_markup/annotation.rb', line 115 def resolve!(summary: nil) raise "Cannot resolve a #{status} annotation" unless status.in?(%w[pending acknowledged]) transaction do add_thread_entry(role: "agent", message: summary) if summary.present? update!(status: "resolved") end end |