Merge branch 'main' into mobile/bridge-components
* main: (22 commits) Disable card column buttons when active Prevent comment content from overlapping with reaction button Delete pins belonging to cards in a board with revoked access Update development dependencies in SAAS lockfile Update runtime dependencies Update development dependencies Balance magic link instructions Add `.txt-balance` utility Move handleDesktop inside restoreColumnsDisablingTransitions Adjust border radius Clean up blank slates Add dialog manager to events page More sturated mini bubbles in light mode Brighten mini bubbles in dark mode Use separate cache namespaces for each beta instance Bump boost size up a tick on mobile Move Undo form inside closure message element Phrasing tweak for exceeding storage limit Keep strong tags words on same line Allow ActionText embed reuse and safe purge (#2346) ...
This commit is contained in:
+1
-1
@@ -1,7 +1,7 @@
|
||||
default_options: &default_options
|
||||
store_options:
|
||||
max_age: <%= 60.days.to_i %>
|
||||
namespace: <%= Rails.env %>
|
||||
namespace: <%= "#{Rails.env}#{"-#{ENV["CACHE_NAMESPACE"]}" if ENV["CACHE_NAMESPACE"]}" %>
|
||||
|
||||
default_connection: &default_connection
|
||||
database: cache
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
# attached to an untracked type (avatar/export) could theoretically be reused in a tracked
|
||||
# context. This is acceptable - user-accessible blob IDs from untracked contexts are
|
||||
# basically nonexistent in practice.
|
||||
#
|
||||
# Exception: ActionText embeds are allowed to reuse blobs to support copy/paste.
|
||||
|
||||
ActiveSupport.on_load(:active_storage_attachment) do
|
||||
validate :blob_account_matches_record, on: :create
|
||||
@@ -29,30 +31,31 @@ ActiveSupport.on_load(:active_storage_attachment) do
|
||||
# bypass tenancy checks via try(:account) returning nil - this is intentional as
|
||||
# these classes don't participate in storage tracking.
|
||||
def blob_account_matches_record
|
||||
return unless record&.try(:account).present?
|
||||
return if whitelisted_for_cross_account?
|
||||
|
||||
unless blob&.account_id == record.account.id
|
||||
errors.add(:blob_id, "blob account must match record account")
|
||||
if record&.try(:account).present? && !whitelisted_for_cross_account?
|
||||
unless blob&.account_id == record.account.id
|
||||
errors.add(:blob_id, "blob account must match record account")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Ledger integrity: blob can only have one tracked attachment
|
||||
def no_tracked_blob_reuse
|
||||
tracked_record = record&.try(:storage_tracked_record)
|
||||
return unless tracked_record.present?
|
||||
return if whitelisted_for_cross_account?
|
||||
if tracked_record.present? &&
|
||||
!whitelisted_for_cross_account? &&
|
||||
!(record_type == "ActionText::RichText" && name == "embeds")
|
||||
|
||||
# Check for existing attachment of this blob in tracked contexts
|
||||
# Uses Storage::TRACKED_RECORD_TYPES constant to stay generic
|
||||
existing = ActiveStorage::Attachment
|
||||
.where(blob_id: blob_id)
|
||||
.where(record_type: Storage::TRACKED_RECORD_TYPES)
|
||||
.where.not(id: id)
|
||||
.exists?
|
||||
# Check for existing attachment of this blob in tracked contexts
|
||||
# Uses Storage::TRACKED_RECORD_TYPES constant to stay generic
|
||||
existing = ActiveStorage::Attachment
|
||||
.where(blob_id: blob_id)
|
||||
.where(record_type: Storage::TRACKED_RECORD_TYPES)
|
||||
.where.not(id: id)
|
||||
.exists?
|
||||
|
||||
if existing
|
||||
errors.add(:blob_id, "cannot reuse blob in tracked storage context")
|
||||
if existing
|
||||
errors.add(:blob_id, "cannot reuse blob in tracked storage context")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# Fizzy-specific override: ActiveStorage's default purge path uses `delete`,
|
||||
# which skips attachment callbacks. We need `destroy` so storage ledger detaches
|
||||
# are recorded and reused blobs (ActionText embeds) aren't purged until the
|
||||
# last attachment is gone. Keep this local to Fizzy; it's not a Rails default.
|
||||
module ActiveStorage
|
||||
module PurgeOnLastAttachment
|
||||
def purge
|
||||
@purge_mode = :purge
|
||||
destroy
|
||||
purge_blob_if_last(:purge) if destroyed?
|
||||
ensure
|
||||
@purge_mode = nil
|
||||
end
|
||||
|
||||
def purge_later
|
||||
@purge_mode = :purge_later
|
||||
destroy
|
||||
purge_blob_if_last(:purge_later) if destroyed?
|
||||
ensure
|
||||
@purge_mode = nil
|
||||
end
|
||||
|
||||
private
|
||||
def purge_dependent_blob_later
|
||||
if dependent == :purge_later && !@purge_mode
|
||||
purge_blob_if_last(:purge_later)
|
||||
end
|
||||
end
|
||||
|
||||
def purge_blob_if_last(mode)
|
||||
if blob && !blob.attachments.exists?
|
||||
mode == :purge ? blob.purge : blob.purge_later
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ActiveSupport.on_load(:active_storage_attachment) do
|
||||
prepend ActiveStorage::PurgeOnLastAttachment
|
||||
end
|
||||
Reference in New Issue
Block a user