Class: Clickwrap::DocumentVersion
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- Clickwrap::DocumentVersion
- Defined in:
- lib/clickwrap/models/document_version.rb
Overview
An immutable published version of a document.
Once published_at is set, the bytes and their digest are frozen. There is
no supported way to edit them: a change is a new version, and the old row
stays exactly as it was because a receipt from last year points at it.
content_digest covers the original source bytes. rendered_content_digest
covers the representation actually offered when a source format was
transformed for display. Keeping both is what lets a receipt distinguish
"this Markdown file existed" from "the server offered this rendered HTML"
instead of letting one claim borrow the other's credibility.
Constant Summary collapse
- STORAGE_BACKENDS =
%w[database active_storage resolver].freeze
Instance Method Summary collapse
-
#content_bytes ⇒ Object
Reads the bytes for this version, from wherever the storage adapter put them, and verifies them against the recorded digest before returning.
- #prefixed_content_digest ⇒ Object
- #presentable_at?(moment = Clickwrap.now) ⇒ Boolean
- #published? ⇒ Boolean
- #rendered_bytes ⇒ Object
- #retire!(because:, at: Clickwrap.now) ⇒ Object
- #retired? ⇒ Boolean
- #to_s ⇒ Object
- #verify_content_digest ⇒ Object
- #verify_rendered_content_digest ⇒ Object
Instance Method Details
#content_bytes ⇒ Object
Reads the bytes for this version, from wherever the storage adapter put them, and verifies them against the recorded digest before returning. Verification is not optional: silently returning bytes that no longer match would turn this method into a way to launder edited content into an export.
57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/clickwrap/models/document_version.rb', line 57 def content_bytes bytes = read_bytes unless Digest.matches?(bytes, "#{content_digest_algorithm}:#{(content_digest)}") raise DocumentDigestMismatchError, "The stored bytes for document version #{self} no longer match the digest " \ "recorded when it was published. The evidence that references this version " \ "cannot be reproduced until that is explained. Recorded: #{content_digest}." end bytes end |
#prefixed_content_digest ⇒ Object
104 |
# File 'lib/clickwrap/models/document_version.rb', line 104 def prefixed_content_digest = content_digest |
#presentable_at?(moment = Clickwrap.now) ⇒ Boolean
46 47 48 49 50 |
# File 'lib/clickwrap/models/document_version.rb', line 46 def presentable_at?(moment = Clickwrap.now) published? && (effective_at.nil? || effective_at <= moment) && (retired_at.nil? || retired_at > moment) end |
#published? ⇒ Boolean
43 |
# File 'lib/clickwrap/models/document_version.rb', line 43 def published? = published_at.present? |
#rendered_bytes ⇒ Object
77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/clickwrap/models/document_version.rb', line 77 def rendered_bytes return content_bytes if rendered_content.nil? unless rendered_content_digest.present? && Digest.matches?(rendered_content, rendered_content_digest) raise DocumentDigestMismatchError, "The rendered bytes for document version #{self} no longer match the digest " \ "recorded when they were published." end rendered_content end |
#retire!(because:, at: Clickwrap.now) ⇒ Object
96 97 98 99 100 101 102 |
# File 'lib/clickwrap/models/document_version.rb', line 96 def retire!(because:, at: Clickwrap.now) raise DocumentVersionConflictError, "Retiring a document version needs a `because:`." if because.to_s.strip.empty? raise DocumentVersionConflictError, "Document version #{self} is already retired." if retired? update_columns(retired_at: at, retired_reason: because) self end |
#retired? ⇒ Boolean
44 |
# File 'lib/clickwrap/models/document_version.rb', line 44 def retired? = retired_at.present? |
#to_s ⇒ Object
106 |
# File 'lib/clickwrap/models/document_version.rb', line 106 def to_s = "#{document&.document_key} #{version_label} (#{locale})" |
#verify_content_digest ⇒ Object
70 71 72 73 74 75 |
# File 'lib/clickwrap/models/document_version.rb', line 70 def verify_content_digest content_bytes true rescue DocumentDigestMismatchError, DocumentNotPublishedError false end |
#verify_rendered_content_digest ⇒ Object
89 90 91 92 93 94 |
# File 'lib/clickwrap/models/document_version.rb', line 89 def verify_rendered_content_digest rendered_bytes true rescue DocumentDigestMismatchError, DocumentNotPublishedError false end |