128 lines
3.3 KiB
Ruby
128 lines
3.3 KiB
Ruby
#!/usr/bin/env ruby
|
|
|
|
# Rollback script: Convert relative attachment URLs back to absolute URLs.
|
|
# Use this if you need to rollback the relative URL changes and want to
|
|
# convert rich texts created during the rollout back to absolute URLs.
|
|
#
|
|
# Run locally:
|
|
# bin/rails runner script/migrations/convert-relative-attachment-urls-to-absolute.rb --help
|
|
#
|
|
# Run via Kamal:
|
|
# kamal app exec -d <stage> -p --reuse "bin/rails runner script/migrations/convert-relative-attachment-urls-to-absolute.rb --help"
|
|
|
|
class ConvertRelativeAttachmentUrlsToAbsolute
|
|
# Match relative URLs pointing to Active Storage routes (with account slug)
|
|
RELATIVE_URL_PATTERN = %r{\A(/\d+/rails/active_storage/[^"']+)\z}
|
|
|
|
attr_reader :host, :since
|
|
|
|
def initialize(host:, since:)
|
|
@host = host
|
|
@since = since
|
|
end
|
|
|
|
def run
|
|
puts "Converting relative attachment URLs to absolute URLs"
|
|
puts "Host: #{host}"
|
|
puts "Processing rich texts created since: #{since}"
|
|
|
|
puts "\nPress ENTER to continue running or CTRL-C to bail..."
|
|
gets
|
|
|
|
puts "\nRunning..."
|
|
|
|
seconds = Benchmark.realtime do
|
|
suppressing_turbo_broadcasts do
|
|
convert_urls
|
|
end
|
|
end
|
|
|
|
puts "\n\n"
|
|
puts "Finished in %.2f seconds." % seconds
|
|
end
|
|
|
|
private
|
|
def suppressing_turbo_broadcasts
|
|
Board.suppressing_turbo_broadcasts do
|
|
Card.suppressing_turbo_broadcasts do
|
|
yield
|
|
end
|
|
end
|
|
end
|
|
|
|
def convert_urls
|
|
scanned = 0
|
|
fixed = 0
|
|
urls_converted = 0
|
|
|
|
action_texts_scope.find_each do |rich_text|
|
|
scanned += 1
|
|
|
|
body = rich_text.body
|
|
|
|
edited = false
|
|
conversions = 0
|
|
|
|
body.send(:attachment_nodes).each do |node|
|
|
url = node["url"]
|
|
next unless url
|
|
|
|
if url.match?(RELATIVE_URL_PATTERN)
|
|
node["url"] = "#{host}#{url}"
|
|
edited = true
|
|
conversions += 1
|
|
end
|
|
end
|
|
|
|
if edited
|
|
record = rich_text.record
|
|
puts " - modifying #{record.class.name} #{record.to_param} (account: #{record.account&.external_account_id}) - #{conversions} URL(s)"
|
|
|
|
rich_text.update! body: body.fragment.to_html
|
|
|
|
fixed += 1
|
|
urls_converted += conversions
|
|
end
|
|
end
|
|
|
|
puts "\n\nConversion complete!"
|
|
puts " Rich texts examined: #{scanned}"
|
|
puts " Rich texts modified: #{fixed}"
|
|
puts " URLs converted: #{urls_converted}"
|
|
end
|
|
|
|
def action_texts_scope
|
|
ActionText::RichText.joins(:embeds_attachments).where("action_text_rich_texts.created_at >= ?", since)
|
|
end
|
|
end
|
|
|
|
require "optparse"
|
|
require "time"
|
|
|
|
options = {}
|
|
|
|
OptionParser.new do |opts|
|
|
opts.banner = "Usage: bin/rails runner #{__FILE__} [options]"
|
|
|
|
opts.on("--host HOST", "Host to prepend (e.g., https://app.fizzy.do)") do |host|
|
|
options[:host] = host
|
|
end
|
|
|
|
opts.on("--since TIME", "Process rich texts created since this time (ISO 8601 format)") do |time|
|
|
options[:since] = Time.parse(time)
|
|
end
|
|
|
|
opts.on("-h", "--help", "Show this help message") do
|
|
puts opts
|
|
exit
|
|
end
|
|
end.parse!
|
|
|
|
if options[:host].nil? || options[:since].nil?
|
|
puts "Error: --host and --since are required"
|
|
puts "Example: bin/rails runner #{__FILE__} --host https://app.fizzy.do --since 2026-01-14T10:00:00Z"
|
|
exit 1
|
|
end
|
|
|
|
ConvertRelativeAttachmentUrlsToAbsolute.new(**options).run
|