diff --git a/app/models/theme.rb b/app/models/theme.rb index de06a767bfc..2fcd7c62417 100644 --- a/app/models/theme.rb +++ b/app/models/theme.rb @@ -241,6 +241,19 @@ class Theme < ActiveRecord::Base end end + def self.enabled_theme_and_component_ids + get_set_cache "enabled_theme_and_component_ids" do + theme_ids = Theme.user_selectable.where(enabled: true).pluck(:id) + component_ids = + ChildTheme + .where(parent_theme_id: theme_ids) + .joins(:child_theme) + .where(themes: { enabled: true }) + .pluck(:child_theme_id) + (theme_ids | component_ids) + end + end + def self.allowed_remote_theme_ids return nil if GlobalSetting.allowed_theme_repos.blank? diff --git a/app/serializers/user_serializer.rb b/app/serializers/user_serializer.rb index dba348d7a2d..ca7734f7e3d 100644 --- a/app/serializers/user_serializer.rb +++ b/app/serializers/user_serializer.rb @@ -324,7 +324,7 @@ class UserSerializer < UserCardSerializer end def can_pick_theme_with_custom_homepage - ThemeModifierHelper.new(theme_ids: Theme.user_theme_ids).custom_homepage + ThemeModifierHelper.new(theme_ids: Theme.enabled_theme_and_component_ids).custom_homepage end private diff --git a/spec/models/theme_spec.rb b/spec/models/theme_spec.rb index d3a561537c0..9d77da0e167 100644 --- a/spec/models/theme_spec.rb +++ b/spec/models/theme_spec.rb @@ -466,6 +466,47 @@ HTML expect(Theme.user_theme_ids).to eq([]) end + it "correctly caches enabled_theme_and_component_ids" do + Theme.destroy_all + + theme2 = Fabricate(:theme) + + expect(Theme.enabled_theme_and_component_ids).to eq([]) + + theme2.update!(user_selectable: true) + + expect(Theme.enabled_theme_and_component_ids).to contain_exactly(theme2.id) + + theme2.update!(user_selectable: false) + theme2.set_default! + expect(Theme.enabled_theme_and_component_ids).to contain_exactly(theme2.id) + + child2 = Fabricate(:theme, component: true) + theme2.add_relative_theme!(:child, child2) + expect(Theme.enabled_theme_and_component_ids).to contain_exactly(theme2.id, child2.id) + + child2.update!(enabled: false) + expect(Theme.enabled_theme_and_component_ids).to contain_exactly(theme2.id) + + theme3 = Fabricate(:theme, user_selectable: true) + child2.update!(enabled: true) + + expect(Theme.enabled_theme_and_component_ids).to contain_exactly( + theme2.id, + child2.id, + theme3.id, + ) + + theme3.update!(enabled: false) + + expect(Theme.enabled_theme_and_component_ids).to contain_exactly(theme2.id, child2.id) + + theme2.destroy + theme3.destroy + + expect(Theme.enabled_theme_and_component_ids).to eq([]) + end + it "correctly caches user_themes template" do Theme.destroy_all diff --git a/spec/system/homepage_spec.rb b/spec/system/homepage_spec.rb index 56c851c5dda..f38d3dc3626 100644 --- a/spec/system/homepage_spec.rb +++ b/spec/system/homepage_spec.rb @@ -5,7 +5,7 @@ describe "Homepage", type: :system do fab!(:user) fab!(:topics) { Fabricate.times(5, :post).map(&:topic) } let(:discovery) { PageObjects::Pages::Discovery.new } - let!(:theme) { Fabricate(:theme) } + fab!(:theme) before do # A workaround to avoid the global notice from interfering with the tests @@ -76,23 +76,8 @@ describe "Homepage", type: :system do expect(page).to have_css(".alert-info") end - context "when the theme adds content to the [custom-homepage] connector" do - let!(:basic_html_field) do - Fabricate( - :theme_field, - theme: theme, - type_id: ThemeField.types[:html], - target_id: Theme.targets[:common], - name: "head_tag", - value: <<~HTML, - - HTML - ) - end - - it "shows the custom homepage from the theme on the homepage" do + shared_examples "a custom homepage" do + it "shows the custom homepage component" do visit "/" expect(page).to have_css(".new-home", text: "Hi friends!") @@ -148,5 +133,46 @@ describe "Homepage", type: :system do expect(page).to have_css(".new-home", text: "Hi friends!") end end + + context "when the theme adds content to the [custom-homepage] connector" do + let!(:basic_html_field) do + Fabricate( + :theme_field, + theme: theme, + type_id: ThemeField.types[:html], + target_id: Theme.targets[:common], + name: "head_tag", + value: <<~HTML, + + HTML + ) + end + + include_examples "a custom homepage" + end + + context "when a theme component adds content to the [custom-homepage] connector" do + let!(:component) { Fabricate(:theme, component: true) } + let!(:component_html_field) do + Fabricate( + :theme_field, + theme: component, + type_id: ThemeField.types[:html], + target_id: Theme.targets[:common], + name: "head_tag", + value: <<~HTML, + + HTML + ) + end + + before { theme.add_relative_theme!(:child, component) } + + include_examples "a custom homepage" + end end end