alchemy_cms 8.1.10 → 8.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +12 -1
- data/app/assets/builds/alchemy/admin.css +1 -1
- data/app/assets/builds/alchemy/alchemy_admin.min.js +1 -1
- data/app/assets/builds/alchemy/alchemy_admin.min.js.map +1 -1
- data/app/assets/builds/alchemy/dark-theme.css +1 -1
- data/app/assets/builds/alchemy/light-theme.css +1 -1
- data/app/assets/builds/alchemy/theme.css +1 -1
- data/app/assets/builds/alchemy/welcome.css +1 -1
- data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css +1 -1
- data/app/assets/builds/tinymce/skins/content/alchemy-dark/content.min.css +1 -1
- data/app/assets/images/alchemy/icons-sprite.svg +1 -1
- data/app/components/alchemy/admin/current_user_name.rb +34 -0
- data/app/components/alchemy/admin/locale_select.rb +12 -8
- data/app/components/alchemy/admin/page_node.html.erb +3 -2
- data/app/components/alchemy/admin/picture_thumbnail.rb +1 -1
- data/app/components/alchemy/admin/preview_time_select.rb +55 -0
- data/app/components/alchemy/admin/publish_element_button.html.erb +41 -0
- data/app/components/alchemy/admin/publish_element_button.rb +13 -0
- data/app/components/alchemy/admin/timezone_select.rb +47 -0
- data/app/components/alchemy/ingredients/select_editor.rb +6 -1
- data/app/controllers/alchemy/admin/base_controller.rb +1 -0
- data/app/controllers/alchemy/admin/elements_controller.rb +54 -34
- data/app/controllers/alchemy/admin/pages_controller.rb +1 -0
- data/app/controllers/alchemy/admin/resources_controller.rb +11 -6
- data/app/controllers/alchemy/pages_controller.rb +1 -2
- data/app/helpers/alchemy/admin/base_helper.rb +4 -7
- data/app/helpers/alchemy/url_helper.rb +2 -10
- data/app/javascript/alchemy_admin/components/element_editor/publish_element_button.js +28 -27
- data/app/javascript/alchemy_admin/components/element_editor.js +11 -2
- data/app/javascript/alchemy_admin/components/message.js +5 -1
- data/app/javascript/alchemy_admin/components/picture_thumbnail.js +1 -0
- data/app/javascript/alchemy_admin/components/uploader/file_upload.js +5 -5
- data/app/javascript/alchemy_admin/image_cropper.js +10 -6
- data/app/javascript/alchemy_admin/initializer.js +6 -33
- data/app/javascript/alchemy_admin/shoelace_theme.js +6 -2
- data/app/javascript/alchemy_admin/templates/compiled.js +1 -1
- data/app/javascript/alchemy_admin.js +12 -2
- data/app/models/alchemy/attachment.rb +1 -1
- data/app/models/alchemy/current.rb +5 -1
- data/app/models/alchemy/element/element_ingredients.rb +11 -3
- data/app/models/alchemy/element.rb +10 -0
- data/app/models/alchemy/ingredient.rb +2 -0
- data/app/models/alchemy/ingredients/select.rb +1 -2
- data/app/models/alchemy/page/etag_generator.rb +21 -0
- data/app/models/alchemy/page/url_path.rb +11 -2
- data/app/models/alchemy/page.rb +12 -2
- data/app/models/alchemy/page_version.rb +5 -5
- data/app/models/alchemy/picture.rb +19 -2
- data/app/models/alchemy/storage_adapter/active_storage.rb +9 -0
- data/app/models/alchemy/storage_adapter/dragonfly.rb +9 -0
- data/app/models/alchemy/storage_adapter.rb +1 -0
- data/app/models/concerns/alchemy/publishable.rb +20 -12
- data/app/models/concerns/alchemy/relatable_resource.rb +16 -2
- data/app/models/concerns/alchemy/touch_elements.rb +3 -3
- data/app/services/alchemy/element_preloader.rb +107 -0
- data/app/stylesheets/alchemy/_custom-properties.scss +1 -0
- data/app/stylesheets/alchemy/_mixins.scss +1 -1
- data/app/stylesheets/alchemy/_themes.scss +2 -0
- data/app/stylesheets/alchemy/admin/archive.scss +2 -2
- data/app/stylesheets/alchemy/admin/base.scss +2 -1
- data/app/stylesheets/alchemy/admin/elements.scss +22 -19
- data/app/stylesheets/alchemy/admin/form_fields.scss +3 -0
- data/app/stylesheets/alchemy/admin/forms.scss +14 -1
- data/app/stylesheets/alchemy/admin/frame.scss +9 -8
- data/app/stylesheets/alchemy/admin/images.scss +2 -2
- data/app/stylesheets/alchemy/admin/notices.scss +1 -1
- data/app/stylesheets/alchemy/admin/popover.scss +37 -0
- data/app/stylesheets/alchemy/admin/selects.scss +4 -0
- data/app/stylesheets/alchemy/admin/shoelace.scss +16 -4
- data/app/stylesheets/alchemy/admin/toolbar.scss +8 -0
- data/app/stylesheets/alchemy/admin.scss +1 -0
- data/app/views/alchemy/admin/_header.html.erb +4 -0
- data/app/views/alchemy/admin/_left_menu.html.erb +24 -0
- data/app/views/alchemy/admin/_main_navi.html.erb +6 -0
- data/app/views/alchemy/admin/_top_menu.html.erb +6 -0
- data/app/views/alchemy/admin/_user_info.html.erb +5 -0
- data/app/views/alchemy/admin/crop.html.erb +6 -11
- data/app/views/alchemy/admin/elements/_header.html.erb +16 -6
- data/app/views/alchemy/admin/elements/_schedule.html.erb +62 -0
- data/app/views/alchemy/admin/elements/_toolbar.html.erb +1 -15
- data/app/views/alchemy/admin/elements/publish.turbo_stream.erb +28 -0
- data/app/views/alchemy/admin/nodes/index.html.erb +1 -1
- data/app/views/alchemy/admin/pages/_locked_pages.html.erb +5 -0
- data/app/views/alchemy/admin/pages/_publication_fields.html.erb +4 -4
- data/app/views/alchemy/admin/pages/_table.html.erb +1 -1
- data/app/views/alchemy/admin/pages/edit.html.erb +6 -2
- data/app/views/alchemy/admin/partials/_language_tree_select.html.erb +10 -10
- data/app/views/alchemy/admin/partials/_site_select.html.erb +6 -3
- data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +3 -3
- data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +1 -1
- data/app/views/alchemy/admin/pictures/index.html.erb +2 -2
- data/app/views/alchemy/admin/tinymce/_setup.html.erb +9 -16
- data/app/views/alchemy/admin/uploader/_setup.html.erb +1 -6
- data/app/views/alchemy/language_links/_language.html.erb +1 -2
- data/app/views/layouts/alchemy/admin.html.erb +2 -45
- data/config/importmap.rb +7 -2
- data/config/locales/alchemy.en.yml +35 -5
- data/lib/alchemy/admin/preview_time.rb +23 -0
- data/lib/alchemy/admin/preview_url.rb +13 -2
- data/lib/alchemy/admin/timezone.rb +56 -0
- data/lib/alchemy/configurations/main.rb +13 -1
- data/lib/alchemy/test_support/factories/element_factory.rb +2 -2
- data/lib/alchemy/test_support/relatable_resource_examples.rb +2 -2
- data/lib/alchemy/test_support/shared_publishable_examples.rb +44 -2
- data/lib/alchemy/upgrader.rb +3 -1
- data/lib/alchemy/version.rb +1 -1
- data/lib/alchemy_cms.rb +2 -0
- data/lib/generators/alchemy/install/install_generator.rb +2 -1
- data/vendor/javascript/handlebars.min.js +4 -4
- data/vendor/javascript/shoelace.min.js +1419 -1323
- data/vendor/javascript/sortable.min.js +2 -2
- data/vendor/javascript/tinymce.min.js +1 -1
- metadata +33 -1
|
@@ -233,6 +233,15 @@ en:
|
|
|
233
233
|
elements:
|
|
234
234
|
toolbar:
|
|
235
235
|
hide: Hide
|
|
236
|
+
schedule:
|
|
237
|
+
visibility_status:
|
|
238
|
+
public_html: This element is <b>currently visible</b>.
|
|
239
|
+
hidden_html: This element is <b>currently hidden</b>.
|
|
240
|
+
public_no_schedule: Set a "visible until" date to automatically hide it.
|
|
241
|
+
public_scheduled_html: It will be hidden on <b>%{public_until}</b>.
|
|
242
|
+
hidden_no_schedule: Change dates to make it visible again.
|
|
243
|
+
hidden_scheduled_html: It will be visible from <b>%{public_on}</b>.
|
|
244
|
+
hidden_window_html: It will be visible from <b>%{public_on}</b> until <b>%{public_until}</b>.
|
|
236
245
|
pictures:
|
|
237
246
|
sorting_select:
|
|
238
247
|
label: "Sorting"
|
|
@@ -390,6 +399,7 @@ en:
|
|
|
390
399
|
cannot_visit_unpublic_page: "Publish page before visiting it."
|
|
391
400
|
choose_file_to_link: "Please choose a file to link"
|
|
392
401
|
"clear clipboard": "clear clipboard"
|
|
402
|
+
clear_schedule: Clear Schedule
|
|
393
403
|
click_to_show_all: "Click to show all again."
|
|
394
404
|
confirm_to_delete_element: "Do you really want to delete this element? It cannot be restored!"
|
|
395
405
|
confirm_to_delete_file: "Do you really want to delete this file from the server?"
|
|
@@ -446,6 +456,9 @@ en:
|
|
|
446
456
|
element_hidden: "Hidden"
|
|
447
457
|
element_of_type: "Element"
|
|
448
458
|
element_saved: "Saved element."
|
|
459
|
+
element_scheduled:
|
|
460
|
+
public_on: "visible from %{public_on}"
|
|
461
|
+
public_until: "visible until %{public_until}"
|
|
449
462
|
enter_external_link: "Please enter the URL you want to link with"
|
|
450
463
|
explain_cropping: '<p>Move the frame and change its size with the mouse or arrow keys to adjust the image mask. Click on "apply" when you are satisfied with your selection.</p><p>If you want to return to the original centered image mask like it was defined in the layout, click "reset" and "apply" afterwards.</p>'
|
|
451
464
|
explain_publishing: "Publish current page content"
|
|
@@ -596,7 +609,9 @@ en:
|
|
|
596
609
|
"1024": "iPad Landscape (1024px)"
|
|
597
610
|
"1280": "Laptop (1280px)"
|
|
598
611
|
"1440": "Desktop (1440px)"
|
|
612
|
+
preview_time: "Preview Time"
|
|
599
613
|
preview_url: Preview
|
|
614
|
+
now: "Now"
|
|
600
615
|
publish_page_language_not_public: Cannot publish page if language is not public
|
|
601
616
|
publish_page_not_allowed: You have not the permission to publish this page
|
|
602
617
|
recently_uploaded_only: "Recently uploaded only"
|
|
@@ -625,6 +640,7 @@ en:
|
|
|
625
640
|
fulltext_search: "Fulltext search"
|
|
626
641
|
select_element: "Select element"
|
|
627
642
|
seperate_tags_with_comma: "Seperate tags with comma"
|
|
643
|
+
schedule_element: Schedule visibility
|
|
628
644
|
show_element_content: "Show content of this element."
|
|
629
645
|
show_eq: "Show EQ"
|
|
630
646
|
show_navigation: "Show in navigation"
|
|
@@ -635,6 +651,7 @@ en:
|
|
|
635
651
|
successfully_added_element: "Successfully added new element."
|
|
636
652
|
successfully_deleted_tag: "Successfully deleted tag"
|
|
637
653
|
successfully_saved_element_position: "Element position updated successfully."
|
|
654
|
+
successfully_scheduled_element: "Successfully scheduled element."
|
|
638
655
|
successfully_updated_tag: "Successfully updated tag"
|
|
639
656
|
swap_image: "Change image"
|
|
640
657
|
insert_image: "Insert image"
|
|
@@ -672,6 +689,7 @@ en:
|
|
|
672
689
|
width: "Width"
|
|
673
690
|
without_tag: "Without tag"
|
|
674
691
|
you_can_rename_this_tag: "You can rename this tag"
|
|
692
|
+
timezone: "Timezone"
|
|
675
693
|
zoom_image: "Zoom this image"
|
|
676
694
|
"Leave Alchemy": "Leave Alchemy"
|
|
677
695
|
leave: "Leave"
|
|
@@ -712,7 +730,7 @@ en:
|
|
|
712
730
|
text: "required"
|
|
713
731
|
mark: "*"
|
|
714
732
|
error_notification:
|
|
715
|
-
default_message: "Please review the problems below
|
|
733
|
+
default_message: "Please review the problems below."
|
|
716
734
|
|
|
717
735
|
# Alchemy date formats
|
|
718
736
|
date:
|
|
@@ -724,14 +742,18 @@ en:
|
|
|
724
742
|
time:
|
|
725
743
|
formats:
|
|
726
744
|
alchemy:
|
|
727
|
-
default: "%
|
|
745
|
+
default: "%d-%m-%Y %I:%M%P"
|
|
728
746
|
ingredient_date: "%Y-%m-%d"
|
|
729
|
-
page_status: "%
|
|
730
|
-
short_datetime: "%d %b %
|
|
731
|
-
time: "%
|
|
747
|
+
page_status: "%d %b %Y, %I:%M%P"
|
|
748
|
+
short_datetime: "%d %b %I:%M%P"
|
|
749
|
+
time: "%I:%M%P"
|
|
750
|
+
element_date: "%d %b %Y, %I:%M%P"
|
|
732
751
|
|
|
733
752
|
# Translations for error messages.
|
|
734
753
|
errors:
|
|
754
|
+
attributes:
|
|
755
|
+
public_until:
|
|
756
|
+
must_be_after_public_on: "must be after visible from date"
|
|
735
757
|
models:
|
|
736
758
|
alchemy/element:
|
|
737
759
|
attributes:
|
|
@@ -812,6 +834,12 @@ en:
|
|
|
812
834
|
base:
|
|
813
835
|
restrict_dependent_destroy:
|
|
814
836
|
has_many: "There are still %{record} attached to this page. Please remove them first."
|
|
837
|
+
descendants:
|
|
838
|
+
still_attached_to_nodes: "The following descendant pages are still attached to menu nodes: %{page_names}. Please remove them first."
|
|
839
|
+
alchemy/element:
|
|
840
|
+
attributes:
|
|
841
|
+
page_version_id:
|
|
842
|
+
must_match_parent: "must be the same as the parent element's page version"
|
|
815
843
|
models:
|
|
816
844
|
gutentag/tag:
|
|
817
845
|
one: Tag
|
|
@@ -867,6 +895,8 @@ en:
|
|
|
867
895
|
name: "Name"
|
|
868
896
|
public: "visible"
|
|
869
897
|
tag_list: Tags
|
|
898
|
+
public_on: Visible from
|
|
899
|
+
public_until: Visible until
|
|
870
900
|
alchemy/ingredient:
|
|
871
901
|
dom_id: Anchor
|
|
872
902
|
alchemy/ingredients/file:
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Alchemy
|
|
4
|
+
module Admin
|
|
5
|
+
module PreviewTime
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
included do
|
|
9
|
+
before_action :set_preview_time, if: :should_set_preview_time?
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def set_preview_time
|
|
15
|
+
Current.preview_time = Time.zone.parse(params[:alchemy_preview_time])
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def should_set_preview_time?
|
|
19
|
+
params[:alchemy_preview_time].present? && can?(:edit_content, Alchemy::Page)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -47,10 +47,13 @@ module Alchemy
|
|
|
47
47
|
port: uri.port,
|
|
48
48
|
path: page.url_path,
|
|
49
49
|
userinfo: userinfo,
|
|
50
|
-
query: {
|
|
50
|
+
query: {
|
|
51
|
+
alchemy_preview_mode: true,
|
|
52
|
+
alchemy_preview_time: preview_time
|
|
53
|
+
}.compact.to_param
|
|
51
54
|
).to_s
|
|
52
55
|
else
|
|
53
|
-
routes.admin_page_path(page)
|
|
56
|
+
routes.admin_page_path(page, alchemy_preview_time: preview_time)
|
|
54
57
|
end
|
|
55
58
|
end
|
|
56
59
|
|
|
@@ -79,6 +82,14 @@ module Alchemy
|
|
|
79
82
|
end
|
|
80
83
|
end
|
|
81
84
|
|
|
85
|
+
# Returns the preview time as ISO 8601 string if explicitly set.
|
|
86
|
+
# We use Current.attributes instead of Current.preview_time because
|
|
87
|
+
# the getter falls back to Time.current, which would freeze a stale
|
|
88
|
+
# timestamp into the preview URL and hide elements created after page load.
|
|
89
|
+
def preview_time
|
|
90
|
+
Current.attributes[:preview_time]&.iso8601
|
|
91
|
+
end
|
|
92
|
+
|
|
82
93
|
def userinfo
|
|
83
94
|
auth = @preview_config.auth
|
|
84
95
|
auth.username ? "#{auth["username"]}:#{auth["password"]}" : nil
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Alchemy
|
|
4
|
+
module Admin
|
|
5
|
+
module Timezone
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
included do
|
|
9
|
+
around_action :set_timezone, if: -> { can?(:edit_content, Alchemy::Page) }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
# Sets the timezone for the current request.
|
|
15
|
+
#
|
|
16
|
+
# Uses the most preferred timezone or falls back to the server default.
|
|
17
|
+
#
|
|
18
|
+
# It respects the server's configured timezone from +config/application.rb+.
|
|
19
|
+
#
|
|
20
|
+
def set_timezone(&action)
|
|
21
|
+
timezone = if timezone_change_needed?
|
|
22
|
+
resolved_timezone || Time.zone.name
|
|
23
|
+
else
|
|
24
|
+
session[:alchemy_timezone]
|
|
25
|
+
end
|
|
26
|
+
session[:alchemy_timezone] = timezone
|
|
27
|
+
Time.use_zone(timezone, &action)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Checks if we need to change the timezone or not.
|
|
31
|
+
def timezone_change_needed?
|
|
32
|
+
params[:admin_timezone].present? || session[:alchemy_timezone].blank?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Returns the first valid timezone from the priority chain, or nil.
|
|
36
|
+
#
|
|
37
|
+
# The priority order is:
|
|
38
|
+
#
|
|
39
|
+
# * the passed parameter: +params[:admin_timezone]+
|
|
40
|
+
# * the user's timezone preference
|
|
41
|
+
#
|
|
42
|
+
def resolved_timezone
|
|
43
|
+
candidates = [params[:admin_timezone], timezone_from_user].compact
|
|
44
|
+
candidates.detect { |tz| ActiveSupport::TimeZone[tz].present? }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Try to get the timezone from user settings.
|
|
48
|
+
def timezone_from_user
|
|
49
|
+
return if !current_alchemy_user
|
|
50
|
+
return if !current_alchemy_user.respond_to?(:timezone)
|
|
51
|
+
|
|
52
|
+
current_alchemy_user.timezone.presence
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -218,7 +218,7 @@ module Alchemy
|
|
|
218
218
|
|
|
219
219
|
# The storage adapter for Pictures and Attachments
|
|
220
220
|
#
|
|
221
|
-
option :storage_adapter, :string, default: "
|
|
221
|
+
option :storage_adapter, :string, default: "active_storage"
|
|
222
222
|
|
|
223
223
|
# Define page preview sources
|
|
224
224
|
#
|
|
@@ -434,6 +434,18 @@ module Alchemy
|
|
|
434
434
|
# The path to the page showing the user they're unauthorized
|
|
435
435
|
option :unauthorized_path, :string, default: "/"
|
|
436
436
|
|
|
437
|
+
# === Edit User Path
|
|
438
|
+
#
|
|
439
|
+
# The path to the edit user form.
|
|
440
|
+
#
|
|
441
|
+
# == Example
|
|
442
|
+
#
|
|
443
|
+
# "/admin/users/:id/edit"
|
|
444
|
+
#
|
|
445
|
+
# NOTE: The :id placeholder will be replaced with the current_alchemy_user's id.
|
|
446
|
+
#
|
|
447
|
+
option :edit_user_path, :string
|
|
448
|
+
|
|
437
449
|
# === CanCan abilities
|
|
438
450
|
#
|
|
439
451
|
# If your app or your engine has own CanCan abilities you must register them.
|
|
@@ -4,7 +4,7 @@ FactoryBot.define do
|
|
|
4
4
|
factory :alchemy_element, class: "Alchemy::Element" do
|
|
5
5
|
name { "article" }
|
|
6
6
|
autogenerate_ingredients { false }
|
|
7
|
-
|
|
7
|
+
page_version { parent_element&.page_version || association(:alchemy_page_version) }
|
|
8
8
|
|
|
9
9
|
trait :fixed do
|
|
10
10
|
fixed { true }
|
|
@@ -21,7 +21,7 @@ FactoryBot.define do
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
trait :nested do
|
|
24
|
-
parent_element {
|
|
24
|
+
parent_element { association(:alchemy_element, name: "slider") }
|
|
25
25
|
name { "slide" }
|
|
26
26
|
end
|
|
27
27
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
RSpec.shared_examples_for "a relatable resource" do |args|
|
|
2
2
|
it { is_expected.to have_many(:related_ingredients) }
|
|
3
|
-
it { is_expected.to have_many(:
|
|
4
|
-
it { is_expected.to have_many(:
|
|
3
|
+
it { is_expected.to have_many(:related_elements).through(:related_ingredients) }
|
|
4
|
+
it { is_expected.to have_many(:related_pages).through(:related_elements) }
|
|
5
5
|
|
|
6
6
|
describe ".deletable" do
|
|
7
7
|
subject { described_class.deletable }
|
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
RSpec.shared_examples_for "being publishable" do |factory_name|
|
|
4
|
+
describe "validations" do
|
|
5
|
+
context "when public_until is older than public_on" do
|
|
6
|
+
let(:record) do
|
|
7
|
+
build(
|
|
8
|
+
factory_name,
|
|
9
|
+
public_on: Time.current,
|
|
10
|
+
public_until: Time.current - 1.day
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "is not valid" do
|
|
15
|
+
expect(record).not_to be_valid
|
|
16
|
+
expect(record.errors[:public_until]).to include(
|
|
17
|
+
I18n.t("errors.attributes.public_until.must_be_after_public_on")
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
4
23
|
describe ".draft" do
|
|
5
24
|
let!(:draft_versions) { create_list(factory_name, 2, public_on: nil) }
|
|
6
25
|
|
|
@@ -75,7 +94,7 @@ RSpec.shared_examples_for "being publishable" do |factory_name|
|
|
|
75
94
|
context "and public_until is nil" do
|
|
76
95
|
let(:public_until) { nil }
|
|
77
96
|
|
|
78
|
-
it { expect(subject).to
|
|
97
|
+
it { expect(subject).to be(false) }
|
|
79
98
|
end
|
|
80
99
|
|
|
81
100
|
context "and public_until is in the past" do
|
|
@@ -101,7 +120,7 @@ RSpec.shared_examples_for "being publishable" do |factory_name|
|
|
|
101
120
|
context "and public_until is nil" do
|
|
102
121
|
let(:public_until) { nil }
|
|
103
122
|
|
|
104
|
-
it { expect(subject).to
|
|
123
|
+
it { expect(subject).to be(false) }
|
|
105
124
|
end
|
|
106
125
|
|
|
107
126
|
context "and public_until is in the future" do
|
|
@@ -169,5 +188,28 @@ RSpec.shared_examples_for "being publishable" do |factory_name|
|
|
|
169
188
|
|
|
170
189
|
it { is_expected.to be(false) }
|
|
171
190
|
end
|
|
191
|
+
|
|
192
|
+
context "when Current.preview_time is set" do
|
|
193
|
+
let(:page_version) do
|
|
194
|
+
build(factory_name,
|
|
195
|
+
public_on: Time.zone.parse("2025-06-01 00:00:00"),
|
|
196
|
+
public_until: Time.zone.parse("2025-06-30 23:59:59"))
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
it "uses preview_time to determine visibility" do
|
|
200
|
+
Alchemy::Current.preview_time = Time.zone.parse("2025-06-15 12:00:00")
|
|
201
|
+
expect(page_version.public?).to be(true)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
it "returns false when preview_time is outside the public range" do
|
|
205
|
+
Alchemy::Current.preview_time = Time.zone.parse("2025-07-15 12:00:00")
|
|
206
|
+
expect(page_version.public?).to be(false)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
it "returns false when preview_time is before public_on" do
|
|
210
|
+
Alchemy::Current.preview_time = Time.zone.parse("2025-05-15 12:00:00")
|
|
211
|
+
expect(page_version.public?).to be(false)
|
|
212
|
+
end
|
|
213
|
+
end
|
|
172
214
|
end
|
|
173
215
|
end
|
data/lib/alchemy/upgrader.rb
CHANGED
|
@@ -32,7 +32,9 @@ module Alchemy
|
|
|
32
32
|
|
|
33
33
|
def update_config
|
|
34
34
|
desc "Copy configuration file."
|
|
35
|
-
@default_config = Alchemy::Configurations::Main.new
|
|
35
|
+
@default_config = Alchemy::Configurations::Main.new(
|
|
36
|
+
storage_adapter: "dragonfly"
|
|
37
|
+
)
|
|
36
38
|
template("templates/alchemy.rb.tt", "config/initializers/alchemy.rb")
|
|
37
39
|
end
|
|
38
40
|
|
data/lib/alchemy/version.rb
CHANGED
data/lib/alchemy_cms.rb
CHANGED
|
@@ -23,6 +23,8 @@ require "view_component"
|
|
|
23
23
|
# Require globally used Alchemy mixins
|
|
24
24
|
require_relative "alchemy/ability_helper"
|
|
25
25
|
require_relative "alchemy/admin/locale"
|
|
26
|
+
require_relative "alchemy/admin/timezone"
|
|
27
|
+
require_relative "alchemy/admin/preview_time"
|
|
26
28
|
require_relative "alchemy/admin/preview_url"
|
|
27
29
|
require_relative "alchemy/auth_accessors"
|
|
28
30
|
require_relative "alchemy/cache_digests/template_tracker"
|
|
@@ -69,7 +69,8 @@ module Alchemy
|
|
|
69
69
|
default_language: {
|
|
70
70
|
name: @default_language[:name],
|
|
71
71
|
code: @default_language[:code]
|
|
72
|
-
}
|
|
72
|
+
},
|
|
73
|
+
storage_adapter: "active_storage"
|
|
73
74
|
)
|
|
74
75
|
template "#{__dir__}/templates/alchemy.rb.tt", app_config_path.join("initializers", "alchemy.rb")
|
|
75
76
|
end
|