discourse/spec/serializers/site_serializer_spec.rb
Bianca Nenciu a24d110258
FIX: Preload parent categories for sidebar (#25726)
When "lazy load categories" is enabled, only the categories present in
the sidebar are preloaded. This is insufficient because the parent
categories are necessary too for the sidebar to be rendered properly.
2024-02-16 16:39:18 +02:00

429 lines
16 KiB
Ruby

# frozen_string_literal: true
RSpec.describe SiteSerializer do
let(:guardian) { Guardian.new }
let(:category) { Fabricate(:category) }
after { Site.clear_cache }
describe "#user_tips" do
it "is included if enable_user_tips" do
SiteSetting.enable_user_tips = true
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:user_tips]).to eq(User.user_tips)
end
it "is not included if enable_user_tips is disabled" do
SiteSetting.enable_user_tips = false
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:user_tips]).to eq(nil)
end
end
it "includes category custom fields only if its preloaded" do
category.custom_fields["enable_marketplace"] = true
category.save_custom_fields
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
c1 = serialized[:categories].find { |c| c[:id] == category.id }
expect(c1[:custom_fields]).to eq(nil)
Site.preloaded_category_custom_fields << "enable_marketplace"
Site.clear_cache
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
c1 = serialized[:categories].find { |c| c[:id] == category.id }
expect(c1[:custom_fields]["enable_marketplace"]).to eq("t")
ensure
Site.reset_preloaded_category_custom_fields
end
it "includes category tags" do
tag = Fabricate(:tag)
tag_group = Fabricate(:tag_group)
tag_group_2 = Fabricate(:tag_group)
category.tags << tag
category.tag_groups << tag_group
category.update!(
category_required_tag_groups: [
CategoryRequiredTagGroup.new(tag_group: tag_group_2, min_count: 1),
],
)
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
c1 = serialized[:categories].find { |c| c[:id] == category.id }
expect(c1[:allowed_tags]).to contain_exactly(tag.name)
expect(c1[:allowed_tag_groups]).to contain_exactly(tag_group.name)
expect(c1[:required_tag_groups]).to eq([{ name: tag_group_2.name, min_count: 1 }])
end
it "doesn't explode when category_required_tag_group is missing" do
tag = Fabricate(:tag)
tag_group = Fabricate(:tag_group)
crtg = CategoryRequiredTagGroup.new(tag_group: tag_group, min_count: 1)
category.update!(category_required_tag_groups: [crtg])
tag_group.delete # Bypassing hooks like this should never happen in the app
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
c1 = serialized[:categories].find { |c| c[:id] == category.id }
expect(c1[:required_tag_groups]).to eq([{ name: nil, min_count: 1 }])
end
it "returns correct notification level for categories" do
SiteSetting.mute_all_categories_by_default = true
SiteSetting.default_categories_normal = category.id.to_s
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
categories = serialized[:categories]
expect(categories[0][:notification_level]).to eq(0)
expect(categories[-1][:notification_level]).to eq(1)
end
it "includes user-selectable color schemes" do
# it includes seeded color schemes
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:user_color_schemes].count).to eq(6)
scheme_names = serialized[:user_color_schemes].map { |x| x[:name] }
expect(scheme_names).to include(I18n.t("color_schemes.dark"))
expect(scheme_names).to include(I18n.t("color_schemes.wcag"))
expect(scheme_names).to include(I18n.t("color_schemes.wcag_dark"))
expect(scheme_names).to include(I18n.t("color_schemes.solarized_light"))
expect(scheme_names).to include(I18n.t("color_schemes.solarized_dark"))
expect(scheme_names).to include(I18n.t("color_schemes.dracula"))
dark_scheme = ColorScheme.create_from_base(name: "AnotherDarkScheme", base_scheme_id: "Dark")
dark_scheme.user_selectable = true
dark_scheme.save!
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:user_color_schemes].count).to eq(7)
expect(serialized[:user_color_schemes][0][:is_dark]).to eq(true)
end
it "includes default dark mode scheme" do
scheme = ColorScheme.last
SiteSetting.default_dark_mode_color_scheme_id = scheme.id
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
default_dark_scheme = expect(serialized[:default_dark_color_scheme]["name"]).to eq(scheme.name)
SiteSetting.default_dark_mode_color_scheme_id = -1
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:default_dark_color_scheme]).to eq(nil)
end
it "does not include shared_drafts_category_id if the category is Uncategorized" do
admin = Fabricate(:admin)
admin_guardian = Guardian.new(admin)
SiteSetting.shared_drafts_category = SiteSetting.uncategorized_category_id
serialized =
described_class.new(Site.new(admin_guardian), scope: admin_guardian, root: false).as_json
expect(serialized[:shared_drafts_category_id]).to eq(nil)
end
context "with lazy loaded categories enabled" do
fab!(:user)
fab!(:category)
fab!(:sidebar) { Fabricate(:category_sidebar_section_link, linkable: category, user: user) }
before { SiteSetting.lazy_load_categories_groups = "#{Group::AUTO_GROUPS[:everyone]}" }
it "does not include any categories for anonymous users" do
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:categories]).to eq(nil)
end
it "includes preloaded categories for logged in users" do
guardian = Guardian.new(user)
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:categories].map { |c| c[:id] }).to contain_exactly(category.id)
end
end
describe "#anonymous_default_navigation_menu_tags" do
fab!(:user)
fab!(:tag) { Fabricate(:tag, name: "dev", description: "some description") }
fab!(:tag2) { Fabricate(:tag, name: "random") }
fab!(:hidden_tag) { Fabricate(:tag, name: "secret") }
fab!(:staff_tag_group) do
Fabricate(:tag_group, permissions: { "staff" => 1 }, tag_names: [hidden_tag.name])
end
before do
SiteSetting.navigation_menu = "sidebar"
SiteSetting.tagging_enabled = true
SiteSetting.default_navigation_menu_tags = "#{tag.name}|#{tag2.name}|#{hidden_tag.name}"
end
it "is not included in the serialised object when tagging is not enabled" do
SiteSetting.tagging_enabled = false
guardian = Guardian.new(user)
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:anonymous_default_navigation_menu_tags]).to eq(nil)
end
it "is not included in the serialised object when user is not anonymous" do
guardian = Guardian.new(user)
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:anonymous_default_navigation_menu_tags]).to eq(nil)
end
it "is not included in the serialisd object when default sidebar tags have not been configured" do
SiteSetting.default_navigation_menu_tags = ""
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:anonymous_default_navigation_menu_tags]).to eq(nil)
end
it "includes only tags user can see in the serialised object when user is anonymous" do
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:anonymous_default_navigation_menu_tags]).to eq(
[
{ name: "dev", description: "some description", pm_only: false },
{ name: "random", description: tag2.description, pm_only: false },
],
)
end
end
describe "#anonymous_sidebar_sections" do
fab!(:user)
fab!(:public_sidebar_section) do
Fabricate(:sidebar_section, title: "Public section", public: true)
end
fab!(:private_sidebar_section) do
Fabricate(:sidebar_section, title: "Private section", user: user, public: false)
end
it "is not included in the serialised object when user is not anonymous" do
guardian = Guardian.new(user)
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
end
it "includes only public sidebar sections serialised object when user is anonymous" do
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:anonymous_sidebar_sections].map(&:title)).to eq(
["Community", "Public section"],
)
end
it "eager loads sidebar_urls" do
public_section_link =
Fabricate(:custom_sidebar_section_link, user: user, sidebar_section: public_sidebar_section)
# warmup
described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
initial_count =
track_sql_queries do
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:anonymous_sidebar_sections].count).to eq(2)
expect(serialized[:anonymous_sidebar_sections].last.links.map { |link| link.id }).to eq(
[public_section_link.linkable.id],
)
end.count
public_section_link_2 =
Fabricate(:custom_sidebar_section_link, user: user, sidebar_section: public_sidebar_section)
public_section_link_3 =
Fabricate(:custom_sidebar_section_link, user: user, sidebar_section: public_sidebar_section)
final_count =
track_sql_queries do
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:anonymous_sidebar_sections].count).to eq(2)
expect(serialized[:anonymous_sidebar_sections].last.links.map { |link| link.id }).to eq(
[
public_section_link.linkable.id,
public_section_link_2.linkable.id,
public_section_link_3.linkable.id,
],
)
end.count
expect(final_count).to eq(initial_count)
end
end
describe "#top_tags" do
fab!(:tag)
describe "when tagging is not enabled" do
before { SiteSetting.tagging_enabled = false }
it "is not included in the serialised object" do
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:top_tags]).to eq(nil)
end
end
describe "when tagging is enabled" do
fab!(:tag2) { Fabricate(:tag) }
fab!(:tag3) { Fabricate(:tag) }
before { SiteSetting.tagging_enabled = true }
it "is not included in the serialised object when there are no tags" do
tag.destroy!
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:top_tags]).to eq([])
end
it "is included in the serialised object containing the top tags" do
tag2 = Fabricate(:tag)
tag2 = Fabricate(:tag)
SiteSetting.max_tags_in_filter_list = 1
CategoryTagStat.create!(
category_id: SiteSetting.uncategorized_category_id,
tag_id: tag2.id,
topic_count: 2,
)
CategoryTagStat.create!(
category_id: SiteSetting.uncategorized_category_id,
tag_id: tag.id,
topic_count: 1,
)
CategoryTagStat.create!(
category_id: SiteSetting.uncategorized_category_id,
tag_id: tag3.id,
topic_count: 5,
)
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:top_tags]).to eq([tag3.name, tag2.name])
end
end
end
describe "#navigation_menu_site_top_tags" do
fab!(:tag1) do
Fabricate(:tag, name: "tag 1").tap { |tag| Fabricate.times(2, :topic, tags: [tag]) }
end
fab!(:tag2) do
Fabricate(:tag, name: "tag 2").tap { |tag| Fabricate.times(1, :topic, tags: [tag]) }
end
fab!(:tag3) do
Fabricate(:tag, name: "tag 3").tap { |tag| Fabricate.times(3, :topic, tags: [tag]) }
end
fab!(:hidden_tag) do
Fabricate(:tag, name: "tag 4").tap { |tag| Fabricate.times(4, :topic, tags: [tag]) }
end
fab!(:staff_tag_group) do
Fabricate(:tag_group, permissions: { "staff" => 1 }, tag_names: [hidden_tag.name])
end
it "should return the site's top tags as the default tags for sidebar" do
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:navigation_menu_site_top_tags]).to eq(
[
{ name: tag3.name, description: tag2.description, pm_only: false },
{ name: tag1.name, description: tag1.description, pm_only: false },
{ name: tag2.name, description: tag3.description, pm_only: false },
],
)
end
it "should not be serialized if `tagging_enabled` site setting is set to false" do
SiteSetting.set(:tagging_enabled, false)
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:navigation_menu_site_top_tags]).to eq(nil)
end
it "should return an empty array if site has no top tags" do
Tag.delete_all
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
expect(serialized[:navigation_menu_site_top_tags]).to eq([])
end
end
describe "#whispers_allowed_groups_names" do
fab!(:admin)
fab!(:allowed_user) { Fabricate(:user) }
fab!(:not_allowed_user) { Fabricate(:user) }
fab!(:group1) { Fabricate(:group, name: "whisperers1", users: [allowed_user]) }
fab!(:group2) { Fabricate(:group, name: "whisperers2", users: [allowed_user]) }
it "returns correct group names for created groups" do
admin_guardian = Guardian.new(admin)
SiteSetting.whispers_allowed_groups = "#{group1.id}|#{group2.id}"
serialized =
described_class.new(Site.new(admin_guardian), scope: admin_guardian, root: false).as_json
expect(serialized[:whispers_allowed_groups_names]).to contain_exactly(
"whisperers1",
"whisperers2",
)
end
it "returns correct group names for automatic groups" do
admin_guardian = Guardian.new(admin)
SiteSetting.whispers_allowed_groups =
"#{Group::AUTO_GROUPS[:staff]}|#{Group::AUTO_GROUPS[:trust_level_4]}"
serialized =
described_class.new(Site.new(admin_guardian), scope: admin_guardian, root: false).as_json
expect(serialized[:whispers_allowed_groups_names]).to contain_exactly(
"trust_level_4",
"staff",
)
end
it "returns group names when user is allowed to whisper" do
user_guardian = Guardian.new(allowed_user)
SiteSetting.whispers_allowed_groups = "#{group1.id}|#{group2.id}"
serialized =
described_class.new(Site.new(user_guardian), scope: user_guardian, root: false).as_json
expect(serialized[:whispers_allowed_groups_names]).to contain_exactly(
"whisperers1",
"whisperers2",
)
end
it "returns nil when user is not allowed to whisper" do
user_guardian = Guardian.new(not_allowed_user)
SiteSetting.whispers_allowed_groups =
"#{Group::AUTO_GROUPS[:staff]}|#{Group::AUTO_GROUPS[:trust_level_4]}"
serialized =
described_class.new(Site.new(user_guardian), scope: user_guardian, root: false).as_json
expect(serialized[:whispers_allowed_groups_names]).to eq(nil)
end
end
end