diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a114306..83da08c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,18 +12,12 @@ jobs: fail-fast: false matrix: include: - - alchemy_cms: "7.4" + - alchemy_cms: "8.2" rails: "7.2" ruby: "3.3" - - alchemy_cms: "7.4" - rails: "8.0" - ruby: "3.4" - - alchemy_cms: "8.0" + - alchemy_cms: "8.2" rails: "8.0" ruby: "3.4" - - alchemy_cms: "8.1" - rails: "8.1" - ruby: "3.4" - alchemy_cms: "8.2" rails: "8.1" ruby: "3.4" diff --git a/Gemfile b/Gemfile index 40dab72..636730e 100644 --- a/Gemfile +++ b/Gemfile @@ -2,15 +2,12 @@ source "https://rubygems.org" gem "puma" gem "sqlite3" +gem "propshaft" -alchemy_cms_version = ENV.fetch("ALCHEMY_CMS_VERSION", "8.0") -if alchemy_cms_version.start_with?("8.") - gem "propshaft" -end +alchemy_cms_version = ENV.fetch("ALCHEMY_CMS_VERSION", "8.2") gem "alchemy_cms", "~> #{alchemy_cms_version}" -devise_version = (Gem::Version.new(alchemy_cms_version) >= Gem::Version.new("8.0")) ? "8.0" : alchemy_cms_version -gem "alchemy-devise", "~> #{devise_version}" +gem "alchemy-devise", "~> #{alchemy_cms_version}" # Specify your gem's dependencies in alchemy-solid_errors.gemspec. gemspec diff --git a/alchemy-solid_errors.gemspec b/alchemy-solid_errors.gemspec index 692c308..acac3bf 100644 --- a/alchemy-solid_errors.gemspec +++ b/alchemy-solid_errors.gemspec @@ -22,7 +22,7 @@ Gem::Specification.new do |spec| end spec.add_dependency "rails", ">= 7.2.0", "< 9.0" - spec.add_dependency "alchemy_cms", ">= 7.4.0", "< 9.0" + spec.add_dependency "alchemy_cms", ">= 8.2.0", "< 9.0" spec.add_dependency "solid_errors", ">= 0.7", "< 1.0" spec.add_development_dependency "capybara", ["~> 3.0"] diff --git a/spec/dummy/config/initializers/alchemy.rb b/spec/dummy/config/initializers/alchemy.rb index c9931ad..29e8350 100644 --- a/spec/dummy/config/initializers/alchemy.rb +++ b/spec/dummy/config/initializers/alchemy.rb @@ -1,5 +1,3 @@ -return unless Alchemy::VERSION.start_with?("8.") - Alchemy.configure do |config| # == This is the global Alchemy configuration file # @@ -51,8 +49,8 @@ # config.preview = { # host: https://www.my-static-site.com # auth: - # username: <%= ENV["BASIC_AUTH_USERNAME"] %%> - # password: <%= ENV["BASIC_AUTH_PASSWORD"] %%> + # username: <%= ENV["BASIC_AUTH_USERNAME"] %> + # password: <%= ENV["BASIC_AUTH_PASSWORD"] %> # } # Preview config per site is supported as well. # @@ -60,8 +58,8 @@ # My site name: # host: https://www.my-static-site.com # auth: - # username: <%= ENV["BASIC_AUTH_USERNAME"] %%> - # password: <%= ENV["BASIC_AUTH_PASSWORD"] %%> + # username: <%= ENV["BASIC_AUTH_USERNAME"] %> + # password: <%= ENV["BASIC_AUTH_PASSWORD"] %> # } # === Picture rendering settings diff --git a/spec/dummy/config/initializers/devise.rb b/spec/dummy/config/initializers/devise.rb index 8dabbc5..dc71ce9 100644 --- a/spec/dummy/config/initializers/devise.rb +++ b/spec/dummy/config/initializers/devise.rb @@ -14,7 +14,7 @@ # confirmation, reset password and unlock tokens in the database. # Devise will use the `secret_key_base` as its `secret_key` # by default. You can change it below and use your own secret key. - # config.secret_key = 'ae1026cf46a6d966db7905354bcf688870b1a81baf29ac316383bd9e10968ec08c6b22df66f4a856613e9961184c028221a78e5b9315c7f93b99695ca2a168a2' + # config.secret_key = '97c0164b69e9a67f2e51cb4709d1144c74e3ec50acab7a1eff7d72beceb83e4a7882bfe919e8e278412ad360261e57033ae95b54b8afcfb8593ad1052bbf6545' # ==> Controller configuration # Configure the parent class to the devise controllers. @@ -24,8 +24,7 @@ # Configure the e-mail address which will be shown in Devise::Mailer, # note that it will be overwritten if you use your own mailer class # with default "from" parameter. - alchemy_config = Alchemy::VERSION.start_with?("8.") ? Alchemy.config : Alchemy::Config - config.mailer_sender = alchemy_config.get(:mailer)["mail_from"] + config.mailer_sender = Alchemy.config.mailer.mail_from # Configure the class responsible to send e-mails. config.mailer = "Alchemy::Notifications" @@ -91,7 +90,7 @@ # It will change confirmation, password recovery and other workflows # to behave the same regardless if the e-mail provided was right or wrong. # Does not affect registerable. - # config.paranoid = true + config.paranoid = true # By default Devise will store the user in session. You can skip storage for # particular strategies by setting this option. @@ -127,7 +126,7 @@ config.stretches = Rails.env.test? ? 1 : 12 # Set up a pepper to generate the hashed password. - # config.pepper = '396758d90aba93d3f5f9cdad801782194211a3c77e24c36e24c00308e29853739f675c34f05a8a99e6f79292af8f9bf43a02e0af549e2ea3be53a3ca61c49a45' + # config.pepper = 'd04079d1f21db3f5e441a507c61666698da7d090e21dcc414e72e4998509e08cdc954690ffc964f83afffda313b09dd0ba04751d15d5de8d96aa97ce26a44161' # Send a notification to the original email when the user's email is changed. # config.send_email_changed_notification = false @@ -189,7 +188,7 @@ # ==> Configuration for :timeoutable # The time you want to timeout the user session without activity. After this # time the user will be asked for credentials again. Default is 30 minutes. - config.timeout_in = Rails.env.development? ? nil : alchemy_config.get(:auto_logout_time).minutes + config.timeout_in = Rails.env.development? ? nil : Alchemy.config.auto_logout_time.minutes # ==> Configuration for :lockable # Defines which strategy will be used to lock an account. @@ -303,7 +302,7 @@ # apps is `200 OK` and `302 Found` respectively, but new apps are generated with # these new defaults that match Hotwire/Turbo behavior. # Note: These might become the new default in future versions of Devise. - config.responder.error_status = :unprocessable_entity + config.responder.error_status = :unprocessable_content config.responder.redirect_status = :see_other # ==> Configuration for :registerable diff --git a/spec/dummy/db/migrate/20260510133828_add_rememberable_column.alchemy_devise.rb b/spec/dummy/db/migrate/20260510133828_add_rememberable_column.alchemy_devise.rb new file mode 100644 index 0000000..161b064 --- /dev/null +++ b/spec/dummy/db/migrate/20260510133828_add_rememberable_column.alchemy_devise.rb @@ -0,0 +1,6 @@ +# This migration comes from alchemy_devise (originally 20251127170649) +class AddRememberableColumn < ActiveRecord::Migration[7.1] + def change + add_column :alchemy_users, :remember_created_at, :datetime, if_not_exists: true + end +end diff --git a/spec/dummy/db/migrate/20260510133829_add_timezone_to_alchemy_users.alchemy_devise.rb b/spec/dummy/db/migrate/20260510133829_add_timezone_to_alchemy_users.alchemy_devise.rb new file mode 100644 index 0000000..7583d81 --- /dev/null +++ b/spec/dummy/db/migrate/20260510133829_add_timezone_to_alchemy_users.alchemy_devise.rb @@ -0,0 +1,7 @@ +# This migration comes from alchemy_devise (originally 20260410115756) +class AddTimezoneToAlchemyUsers < ActiveRecord::Migration[7.2] + def change + add_column :alchemy_users, :timezone, :string, if_not_exists: true, + comment: "The timezone of the user, used for displaying dates in the user's timezone" + end +end diff --git a/spec/dummy/db/migrate/20260510133910_convert_select_value_for_multiple.alchemy.rb b/spec/dummy/db/migrate/20260510133910_convert_select_value_for_multiple.alchemy.rb new file mode 100644 index 0000000..837c8f8 --- /dev/null +++ b/spec/dummy/db/migrate/20260510133910_convert_select_value_for_multiple.alchemy.rb @@ -0,0 +1,12 @@ +# This migration comes from alchemy (originally 20251106150010) +class ConvertSelectValueForMultiple < ActiveRecord::Migration[7.1] + def up + say_with_time "Converting Alchemy::Ingredients::Select values to multiple" do + update <<-SQL.squish + UPDATE alchemy_ingredients + SET value = '["' || value || '"]' + WHERE type = 'Alchemy::Ingredients::Select' AND value NOT LIKE '["%"]'; + SQL + end + end +end diff --git a/spec/dummy/db/migrate/20260510133911_add_metadata_to_page_versions.alchemy.rb b/spec/dummy/db/migrate/20260510133911_add_metadata_to_page_versions.alchemy.rb new file mode 100644 index 0000000..9adc6ce --- /dev/null +++ b/spec/dummy/db/migrate/20260510133911_add_metadata_to_page_versions.alchemy.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# This migration comes from alchemy (originally 20260102121232) +class AddMetadataToPageVersions < ActiveRecord::Migration[7.2] + def change + add_column :alchemy_page_versions, :title, :string + add_column :alchemy_page_versions, :meta_description, :text + add_column :alchemy_page_versions, :meta_keywords, :text + end +end diff --git a/spec/dummy/db/migrate/20260510133912_add_publication_timestamps_to_alchemy_elements.alchemy.rb b/spec/dummy/db/migrate/20260510133912_add_publication_timestamps_to_alchemy_elements.alchemy.rb new file mode 100644 index 0000000..0967e8e --- /dev/null +++ b/spec/dummy/db/migrate/20260510133912_add_publication_timestamps_to_alchemy_elements.alchemy.rb @@ -0,0 +1,31 @@ +# This migration comes from alchemy (originally 20260115164704) +class AddPublicationTimestampsToAlchemyElements < ActiveRecord::Migration[7.2] + def up + add_column :alchemy_elements, :public_on, :datetime + add_column :alchemy_elements, :public_until, :datetime + + say_with_time "Populating publication dates" do + update <<-SQL.squish + UPDATE alchemy_elements + SET public_on = created_at + WHERE public = #{connection.quoted_true} + SQL + end + end + + def down + say_with_time "Reverting publication dates" do + update <<-SQL.squish + UPDATE alchemy_elements + SET public = CASE + WHEN public_on IS NOT NULL AND public_on <= CURRENT_TIMESTAMP + THEN #{connection.quoted_true} + ELSE #{connection.quoted_false} + END + SQL + end + + remove_column :alchemy_elements, :public_until + remove_column :alchemy_elements, :public_on + end +end diff --git a/spec/dummy/db/migrate/20260510133913_add_index_to_element_publication_timestamps.alchemy.rb b/spec/dummy/db/migrate/20260510133913_add_index_to_element_publication_timestamps.alchemy.rb new file mode 100644 index 0000000..988cb36 --- /dev/null +++ b/spec/dummy/db/migrate/20260510133913_add_index_to_element_publication_timestamps.alchemy.rb @@ -0,0 +1,14 @@ +# This migration comes from alchemy (originally 20260115164705) +class AddIndexToElementPublicationTimestamps < ActiveRecord::Migration[7.2] + disable_ddl_transaction! if connection.adapter_name.match?(/postgres/i) + + def change + add_index :alchemy_elements, [:public_on, :public_until], algorithm: algorithm + end + + private + + def algorithm + connection.adapter_name.match?(/postgres/i) ? :concurrently : nil + end +end diff --git a/spec/dummy/db/schema.rb b/spec/dummy/db/schema.rb index 94463f7..6413105 100644 --- a/spec/dummy/db/schema.rb +++ b/spec/dummy/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.2].define(version: 2025_11_15_150241) do +ActiveRecord::Schema[7.2].define(version: 2026_05_10_133913) do create_table "alchemy_attachments", force: :cascade do |t| t.string "name" t.string "file_name" @@ -40,11 +40,14 @@ t.integer "parent_element_id" t.boolean "fixed", default: false, null: false t.integer "page_version_id", null: false + t.datetime "public_on" + t.datetime "public_until" t.index ["creator_id"], name: "index_alchemy_elements_on_creator_id" t.index ["fixed"], name: "index_alchemy_elements_on_fixed" t.index ["page_version_id", "parent_element_id"], name: "idx_alchemy_elements_on_page_version_id_and_parent_element_id" t.index ["page_version_id", "position"], name: "idx_alchemy_elements_on_page_version_id_and_position" t.index ["page_version_id"], name: "index_alchemy_elements_on_page_version_id" + t.index ["public_on", "public_until"], name: "index_alchemy_elements_on_public_on_and_public_until" t.index ["updater_id"], name: "index_alchemy_elements_on_updater_id" end @@ -147,6 +150,9 @@ t.datetime "public_until", precision: nil t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.string "title" + t.text "meta_description" + t.text "meta_keywords" t.index ["page_id"], name: "index_alchemy_page_versions_on_page_id" t.index ["public_on", "public_until"], name: "index_alchemy_page_versions_on_public_on_and_public_until" end @@ -261,6 +267,8 @@ t.string "reset_password_token" t.datetime "reset_password_sent_at", precision: nil t.string "alchemy_roles", default: "member" + t.datetime "remember_created_at" + t.string "timezone" t.index ["alchemy_roles"], name: "index_alchemy_users_on_alchemy_roles" t.index ["email"], name: "index_alchemy_users_on_email", unique: true t.index ["firstname"], name: "index_alchemy_users_on_firstname"