From 8e7b45e206d7f7c994d4b5a4a90919604c761683 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Tue, 23 Jan 2024 21:27:04 +0100 Subject: [PATCH] Add upgrader for active storage --- alchemy_cms.gemspec | 2 + app/models/alchemy/attachment.rb | 13 +++ app/models/alchemy/picture.rb | 16 ++++ ...23080918_rename_alchemy_attachment_file.rb | 13 +++ ...80918_rename_alchemy_picture_image_file.rb | 16 ++++ lib/alchemy/upgrader/seven_point_one.rb | 91 +++++++++++++++++++ lib/alchemy_cms.rb | 2 + lib/tasks/alchemy/upgrade.rake | 28 +++++- 8 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20240123080918_rename_alchemy_attachment_file.rb create mode 100644 db/migrate/20240123080918_rename_alchemy_picture_image_file.rb create mode 100644 lib/alchemy/upgrader/seven_point_one.rb diff --git a/alchemy_cms.gemspec b/alchemy_cms.gemspec index 743bfb673a..5ce219e836 100644 --- a/alchemy_cms.gemspec +++ b/alchemy_cms.gemspec @@ -38,6 +38,8 @@ Gem::Specification.new do |gem| gem.add_runtime_dependency "awesome_nested_set", ["~> 3.1"] gem.add_runtime_dependency "cancancan", [">= 2.1", "< 4.0"] gem.add_runtime_dependency "coffee-rails", [">= 4.0", "< 6.0"] + gem.add_runtime_dependency "dragonfly", ["~> 1.4"] + gem.add_runtime_dependency "dragonfly_svg", ["~> 0.0.4"] gem.add_runtime_dependency "gutentag", ["~> 2.2", ">= 2.2.1"] gem.add_runtime_dependency "handlebars_assets", ["~> 0.23"] gem.add_runtime_dependency "image_processing", [">= 1.2"] diff --git a/app/models/alchemy/attachment.rb b/app/models/alchemy/attachment.rb index 6f0f4a2945..6931961a6a 100644 --- a/app/models/alchemy/attachment.rb +++ b/app/models/alchemy/attachment.rb @@ -24,6 +24,19 @@ class Attachment < BaseRecord include Alchemy::Taggable include Alchemy::TouchElements + # Legacy Dragonfly file attachments + extend Dragonfly::Model + dragonfly_accessor :legacy_file, app: :alchemy_attachments + DEPRECATED_COLUMNS = %i[ + legacy_file + legacy_file_name + legacy_file_size + legacy_file_uid + ].each do |column| + deprecate column, deprecator: Alchemy::Deprecation + deprecate :"#{column}=", deprecator: Alchemy::Deprecation + end + # Use ActiveStorage file attachments has_one_attached :file, service: :alchemy_cms diff --git a/app/models/alchemy/picture.rb b/app/models/alchemy/picture.rb index 8cfc042579..9db1626ba0 100644 --- a/app/models/alchemy/picture.rb +++ b/app/models/alchemy/picture.rb @@ -79,6 +79,22 @@ def self.preprocessor_class=(klass) @_preprocessor_class = klass end + # Legacy Dragonfly image attachments + extend Dragonfly::Model + dragonfly_accessor :legacy_image_file, app: :alchemy_pictures + DEPRECATED_COLUMNS = %i[ + legacy_image_file + legacy_image_file_format + legacy_image_file_height + legacy_image_file_name + legacy_image_file_size + legacy_image_file_uid + legacy_image_file_width + ].each do |column| + deprecate column, deprecator: Alchemy::Deprecation + deprecate :"#{column}=", deprecator: Alchemy::Deprecation + end + # Use ActiveStorage image processing has_one_attached :image_file, service: :alchemy_cms diff --git a/db/migrate/20240123080918_rename_alchemy_attachment_file.rb b/db/migrate/20240123080918_rename_alchemy_attachment_file.rb new file mode 100644 index 0000000000..caf952940c --- /dev/null +++ b/db/migrate/20240123080918_rename_alchemy_attachment_file.rb @@ -0,0 +1,13 @@ +class RenameAlchemyAttachmentFile < ActiveRecord::Migration[7.0] + COLUMNS = %i[ + file_name + file_size + file_uid + ] + + def change + COLUMNS.each do |column| + rename_column :alchemy_attachments, column, :"legacy_#{column}" + end + end +end diff --git a/db/migrate/20240123080918_rename_alchemy_picture_image_file.rb b/db/migrate/20240123080918_rename_alchemy_picture_image_file.rb new file mode 100644 index 0000000000..00b21693ee --- /dev/null +++ b/db/migrate/20240123080918_rename_alchemy_picture_image_file.rb @@ -0,0 +1,16 @@ +class RenameAlchemyPictureImageFile < ActiveRecord::Migration[7.0] + COLUMNS = %i[ + image_file_format + image_file_height + image_file_name + image_file_size + image_file_uid + image_file_width + ] + + def change + COLUMNS.each do |column| + rename_column :alchemy_pictures, column, :"legacy_#{column}" + end + end +end diff --git a/lib/alchemy/upgrader/seven_point_one.rb b/lib/alchemy/upgrader/seven_point_one.rb new file mode 100644 index 0000000000..63e3c96a00 --- /dev/null +++ b/lib/alchemy/upgrader/seven_point_one.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +require "alchemy/shell" +require "benchmark" + +module Alchemy + class Upgrader::SevenPointOne < Upgrader + extend Alchemy::Shell + DEFAULT_CONTENT_TYPE = "application/octet-stream" + SERVICE_NAME = :alchemy_cms + + # Prevents (down)loading the original file + METADATA = { + identified: true, # Skip identifying file type + analyzed: true, # Skip analyze job + composed: true # Skip checksum check + } + + class << self + def migrate_pictures_to_active_storage + pictures_without_as_attachment = Alchemy::Picture.where.missing(:image_file_attachment) + count = pictures_without_as_attachment.count + if count > 0 + log "Migrating #{count} Dragonfly image file(s) to ActiveStorage." + realtime = Benchmark.realtime do + pictures_without_as_attachment.find_each do |picture| + content_type = Mime::Type.lookup_by_extension(picture.legacy_image_file_format) || DEFAULT_CONTENT_TYPE + Alchemy::Picture.transaction do + blob = Alchemy::Deprecation.silence do + ActiveStorage::Blob.create!( + key: picture.legacy_image_file_uid, + filename: picture.legacy_image_file_name, + byte_size: picture.legacy_image_file_size, + content_type: content_type, + metadata: METADATA.merge( + width: picture.legacy_image_file_width, + height: picture.legacy_image_file_height + ), + service_name: SERVICE_NAME + ) + end + picture.create_image_file_attachment!( + name: :image_file, + record: picture, + blob: blob + ) + end + print "." + end + end + puts "\nDone in #{realtime.round(2)}s!" + else + log "No Dragonfly image files for migration found.", :skip + end + end + + def migrate_attachments_to_active_storage + attachments_without_as_attachment = Alchemy::Attachment.where.missing(:file_attachment) + count = attachments_without_as_attachment.count + if count > 0 + log "Migrating #{count} Dragonfly attachment file(s) to ActiveStorage." + realtime = Benchmark.realtime do + attachments_without_as_attachment.find_each do |attachment| + Alchemy::Attachment.transaction do + blob = Alchemy::Deprecation.silence do + ActiveStorage::Blob.create!( + key: attachment.legacy_file_uid, + filename: attachment.legacy_file_name, + byte_size: attachment.legacy_file_size, + content_type: attachment.file_mime_type.presence || DEFAULT_CONTENT_TYPE, + metadata: METADATA, + service_name: SERVICE_NAME + ) + end + attachment.create_file_attachment!( + record: attachment, + name: :file, + blob: blob + ) + end + print "." + end + end + puts "\nDone in #{realtime.round(2)}s!" + else + log "No Dragonfly attachment files for migration found.", :skip + end + end + end + end +end diff --git a/lib/alchemy_cms.rb b/lib/alchemy_cms.rb index d205a03e9a..74bf405166 100644 --- a/lib/alchemy_cms.rb +++ b/lib/alchemy_cms.rb @@ -9,6 +9,8 @@ require "active_model_serializers" require "awesome_nested_set" require "cancan" +require "dragonfly" +require "dragonfly_svg" require "gutentag" require "handlebars_assets" require "importmap-rails" diff --git a/lib/tasks/alchemy/upgrade.rake b/lib/tasks/alchemy/upgrade.rake index d0fd71ad65..f397945d44 100644 --- a/lib/tasks/alchemy/upgrade.rake +++ b/lib/tasks/alchemy/upgrade.rake @@ -7,7 +7,8 @@ namespace :alchemy do desc "Upgrades your app to AlchemyCMS v#{Alchemy::VERSION}." task upgrade: [ "alchemy:upgrade:prepare", - "alchemy:upgrade:7.0:run" + "alchemy:upgrade:7.0:run", + "alchemy:upgrade:7.1:run" ] do Alchemy::Upgrader.display_todos end @@ -49,5 +50,30 @@ namespace :alchemy do Alchemy::Upgrader::SevenPointZero.remove_admin_entrypoint end end + + desc "Upgrade Alchemy to v7.1" + task "7.1" => [ + "alchemy:upgrade:prepare", + "alchemy:upgrade:7.1:run" + ] do + Alchemy::Upgrader.display_todos + end + + namespace "7.1" do + task "run" => [ + "alchemy:upgrade:7.1:migrate_pictures_to_active_storage", + "alchemy:upgrade:7.1:migrate_attachments_to_active_storage" + ] + + desc "Migrate pictures to active_storage" + task migrate_pictures_to_active_storage: [:environment] do + Alchemy::Upgrader::SevenPointOne.migrate_pictures_to_active_storage + end + + desc "Migrate attachments to active_storage" + task migrate_attachments_to_active_storage: [:environment] do + Alchemy::Upgrader::SevenPointOne.migrate_attachments_to_active_storage + end + end end end