mirror of
https://github.com/discourse/discourse.git
synced 2026-08-06 13:08:40 +08:00
With the ACL changes that are ongoing, regular users need to be able to see the pseudogroups in certain situations, like the ACL group selection dropdown. Pseudogroups are the everyone, logged_in_users, and anonymous_users groups. They are currently limited to staff only, but this change will allow all logged on users to see them as well. This commit also does some minor fixes related to granular_anonymous_and_logged_in_groups_permissions upcoming change. If this is enabled, the everyone group should not be selectable in Site.groups in the UI, that will just lead to confusion in the long term especially because this upcoming change will eventually remove the everyone group.
467 lines
16 KiB
Ruby
Vendored
467 lines
16 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
RSpec.describe Site do
|
|
after { Site.clear_cache }
|
|
|
|
def expect_correct_themes(guardian)
|
|
json = Site.json_for(guardian)
|
|
parsed = JSON.parse(json)
|
|
|
|
expected =
|
|
Theme
|
|
.where("id = :default OR user_selectable", default: SiteSetting.default_theme_id)
|
|
.order(:name)
|
|
.pluck(:id, :name, :color_scheme_id, :dark_color_scheme_id)
|
|
.map do |id, name, color_scheme_id, dark_color_scheme_id|
|
|
{
|
|
"theme_id" => id,
|
|
"name" => name,
|
|
"default" => id == SiteSetting.default_theme_id,
|
|
"color_scheme_id" => color_scheme_id,
|
|
"dark_color_scheme_id" => dark_color_scheme_id,
|
|
"only_theme_color_schemes" => false,
|
|
}
|
|
end
|
|
|
|
expect(parsed["user_themes"]).to eq(expected)
|
|
end
|
|
|
|
it "includes user themes and expires them as needed" do
|
|
default_theme = Fabricate(:theme)
|
|
SiteSetting.default_theme_id = default_theme.id
|
|
user_theme = Fabricate(:theme, user_selectable: true)
|
|
second_user_theme = Fabricate(:theme, user_selectable: true)
|
|
color_scheme = Fabricate(:color_scheme)
|
|
|
|
anon_guardian = Guardian.new
|
|
user_guardian = Fabricate(:user).guardian
|
|
|
|
expect_correct_themes(anon_guardian)
|
|
expect_correct_themes(user_guardian)
|
|
|
|
Theme.clear_default!
|
|
|
|
expect_correct_themes(anon_guardian)
|
|
expect_correct_themes(user_guardian)
|
|
|
|
user_theme.user_selectable = false
|
|
user_theme.save!
|
|
|
|
expect_correct_themes(anon_guardian)
|
|
expect_correct_themes(user_guardian)
|
|
|
|
second_user_theme.color_scheme_id = color_scheme.id
|
|
second_user_theme.save!
|
|
|
|
expect_correct_themes(anon_guardian)
|
|
expect_correct_themes(user_guardian)
|
|
end
|
|
|
|
it "returns correct notification level for categories" do
|
|
category = Fabricate(:category)
|
|
guardian = Guardian.new
|
|
expect(Site.new(guardian).categories.last[:notification_level]).to eq(1)
|
|
SiteSetting.mute_all_categories_by_default = true
|
|
expect(Site.new(guardian).categories.last[:notification_level]).to eq(0)
|
|
SiteSetting.default_categories_tracking = category.id.to_s
|
|
expect(Site.new(guardian).categories.last[:notification_level]).to eq(1)
|
|
end
|
|
|
|
describe "#categories" do
|
|
fab!(:category)
|
|
fab!(:user)
|
|
let(:guardian) { user.guardian }
|
|
|
|
it "omits read restricted categories" do
|
|
expect(Site.new(guardian).categories.map { |c| c[:id] }).to contain_exactly(
|
|
SiteSetting.uncategorized_category_id,
|
|
category.id,
|
|
)
|
|
|
|
category.update!(read_restricted: true)
|
|
|
|
expect(Site.new(guardian).categories.map { |c| c[:id] }).to contain_exactly(
|
|
SiteSetting.uncategorized_category_id,
|
|
)
|
|
end
|
|
|
|
it "includes categories that a user's group can see" do
|
|
group = Fabricate(:group)
|
|
category.update!(read_restricted: true)
|
|
category.groups << group
|
|
|
|
expect(Site.new(guardian).categories.map { |c| c[:id] }).to contain_exactly(
|
|
SiteSetting.uncategorized_category_id,
|
|
)
|
|
|
|
group.add(user)
|
|
|
|
expect(Site.new(user.guardian).categories.map { |c| c[:id] }).to contain_exactly(
|
|
SiteSetting.uncategorized_category_id,
|
|
category.id,
|
|
)
|
|
end
|
|
|
|
it "omits categories users can not write to from the category list" do
|
|
expect(Site.new(guardian).categories.count).to eq(2)
|
|
|
|
category.set_permissions(everyone: :create_post)
|
|
category.save!
|
|
|
|
guardian = user.guardian
|
|
|
|
expect(
|
|
Site.new(guardian).categories.keep_if { |c| c[:name] == category.name }.first[:permission],
|
|
).not_to eq(CategoryGroup.permission_types[:full])
|
|
|
|
# If a parent category is not visible, the child categories should not be returned
|
|
category.set_permissions(staff: :full)
|
|
category.save!
|
|
|
|
sub_category = Fabricate(:category, parent_category_id: category.id)
|
|
expect(Site.new(guardian).categories).not_to include(sub_category)
|
|
end
|
|
|
|
it "should clear the cache when custom fields are updated" do
|
|
Site.preloaded_category_custom_fields << "enable_marketplace"
|
|
categories = Site.new(Guardian.new).categories
|
|
|
|
expect(categories.last[:custom_fields]["enable_marketplace"]).to eq(nil)
|
|
|
|
category.custom_fields["enable_marketplace"] = true
|
|
category.save_custom_fields
|
|
|
|
categories = Site.new(Guardian.new).categories
|
|
|
|
expect(categories.last[:custom_fields]["enable_marketplace"]).to eq("t")
|
|
|
|
category.upsert_custom_fields(enable_marketplace: false)
|
|
|
|
categories = Site.new(Guardian.new).categories
|
|
|
|
expect(categories.last[:custom_fields]["enable_marketplace"]).to eq("f")
|
|
ensure
|
|
Site.reset_preloaded_category_custom_fields
|
|
end
|
|
|
|
it "sets the can_edit field for categories correctly" do
|
|
categories = Site.new(Guardian.new).categories
|
|
|
|
expect(categories.map { |c| c[:can_edit] }).to contain_exactly(false, false)
|
|
|
|
site = Site.new(Fabricate(:moderator).guardian)
|
|
|
|
expect(site.categories.map { |c| c[:can_edit] }).to contain_exactly(false, false)
|
|
|
|
SiteSetting.moderators_manage_categories = true
|
|
|
|
site = Site.new(Fabricate(:moderator).guardian)
|
|
|
|
expect(site.categories.map { |c| c[:can_edit] }).to contain_exactly(true, true)
|
|
end
|
|
|
|
describe "site_all_categories_cache_query modifier" do
|
|
fab!(:cool_category) { Fabricate(:category, name: "Cool category") }
|
|
fab!(:boring_category) { Fabricate(:category, name: "Boring category") }
|
|
|
|
it "allows changing the query" do
|
|
prefetched_categories = Site.new(user.guardian).categories.map { |c| c[:id] }
|
|
expect(prefetched_categories).to include(cool_category.id, boring_category.id)
|
|
|
|
# we need to clear the cache to ensure that the categories list will be updated
|
|
Site.clear_cache
|
|
|
|
plugin_instance = Plugin::Instance.new
|
|
modifier_block = Proc.new { |query| query.where("categories.name LIKE 'Cool%'") }
|
|
plugin_instance.register_modifier(:site_all_categories_cache_query, &modifier_block)
|
|
|
|
prefetched_categories = Site.new(user.guardian).categories.map { |c| c[:id] }
|
|
|
|
expect(prefetched_categories).to include(cool_category.id)
|
|
expect(prefetched_categories).not_to include(boring_category.id)
|
|
ensure
|
|
DiscoursePluginRegistry.unregister_modifier(
|
|
plugin_instance,
|
|
:site_all_categories_cache_query,
|
|
&modifier_block
|
|
)
|
|
end
|
|
end
|
|
|
|
context "with lazy loaded categories enabled" do
|
|
fab!(:user)
|
|
|
|
before { SiteSetting.lazy_load_categories_groups = "#{Group::AUTO_GROUPS[:logged_in_users]}" }
|
|
|
|
it "returns all categories for anonymous users" do
|
|
site = Site.new(Guardian.new)
|
|
|
|
expect(site.categories.map { |c| c[:id] }).to include(category.id)
|
|
end
|
|
|
|
it "returns only sidebar categories and their ancestors" do
|
|
SiteSetting.max_category_nesting = 3
|
|
grandfather_category = Fabricate(:category)
|
|
parent_category = Fabricate(:category, parent_category: grandfather_category)
|
|
category.update!(parent_category: parent_category)
|
|
Fabricate(:category_sidebar_section_link, linkable: category, user: user)
|
|
|
|
site = Site.new(user.guardian)
|
|
|
|
expect(site.categories.map { |c| c[:id] }).to contain_exactly(
|
|
grandfather_category.id,
|
|
parent_category.id,
|
|
category.id,
|
|
)
|
|
end
|
|
|
|
it "returns only visible sidebar categories" do
|
|
Fabricate(:category_sidebar_section_link, linkable: category, user: user)
|
|
category.update!(read_restricted: true)
|
|
|
|
site = Site.new(user.guardian)
|
|
|
|
expect(site.categories).to eq([])
|
|
end
|
|
end
|
|
end
|
|
|
|
it "omits groups user can not see" do
|
|
user = Fabricate(:user)
|
|
site = Site.new(user.guardian)
|
|
|
|
staff_group = Fabricate(:group, visibility_level: Group.visibility_levels[:staff])
|
|
expect(site.groups.pluck(:name)).not_to include(staff_group.name)
|
|
|
|
public_group = Fabricate(:group)
|
|
expect(site.groups.pluck(:name)).to include(public_group.name)
|
|
|
|
admin = Fabricate(:admin)
|
|
site = Site.new(admin.guardian)
|
|
expect(site.groups.pluck(:name)).to include(
|
|
staff_group.name,
|
|
public_group.name,
|
|
"logged_in_users",
|
|
"anonymous_users",
|
|
)
|
|
end
|
|
|
|
describe "site_groups_query modifier" do
|
|
fab!(:user)
|
|
fab!(:cool_group) { Fabricate(:group, name: "cool-group") }
|
|
fab!(:boring_group) { Fabricate(:group, name: "boring-group") }
|
|
|
|
it "allows changing the query" do
|
|
prefetched_groups = Site.new(user.guardian).groups.map { |c| c[:id] }
|
|
expect(prefetched_groups).to include(cool_group.id, boring_group.id)
|
|
|
|
# we need to clear the cache to ensure that the groups list will be updated
|
|
Site.clear_cache
|
|
|
|
plugin_instance = Plugin::Instance.new
|
|
modifier_block = Proc.new { |query| query.where("groups.name LIKE 'cool%'") }
|
|
plugin_instance.register_modifier(:site_groups_query, &modifier_block)
|
|
|
|
prefetched_groups = Site.new(user.guardian).groups.map { |c| c[:id] }
|
|
|
|
expect(prefetched_groups).to include(cool_group.id)
|
|
expect(prefetched_groups).not_to include(boring_group.id)
|
|
ensure
|
|
DiscoursePluginRegistry.unregister_modifier(
|
|
plugin_instance,
|
|
:site_groups_query,
|
|
&modifier_block
|
|
)
|
|
end
|
|
end
|
|
|
|
it "includes all enabled authentication providers" do
|
|
SiteSetting.enable_twitter_logins = true
|
|
SiteSetting.enable_facebook_logins = true
|
|
data = JSON.parse(Site.json_for(Guardian.new))
|
|
expect(data["auth_providers"].map { |a| a["name"] }).to contain_exactly("facebook", "twitter")
|
|
end
|
|
|
|
it "includes all enabled authentication providers for anon when login_required" do
|
|
SiteSetting.login_required = true
|
|
SiteSetting.enable_twitter_logins = true
|
|
SiteSetting.enable_facebook_logins = true
|
|
data = JSON.parse(Site.json_for(Guardian.new))
|
|
expect(data["auth_providers"].map { |a| a["name"] }).to contain_exactly("facebook", "twitter")
|
|
end
|
|
|
|
it "includes tos_url and privacy_policy_url when login_required" do
|
|
SiteSetting.login_required = true
|
|
SiteSetting.tos_url = "https://discourse.org"
|
|
SiteSetting.privacy_policy_url = "https://discourse.org/privacy"
|
|
|
|
data = JSON.parse(Site.json_for(Guardian.new))
|
|
|
|
expect(data["tos_url"]).to eq(SiteSetting.tos_url)
|
|
expect(data["privacy_policy_url"]).to eq(SiteSetting.privacy_policy_url)
|
|
end
|
|
|
|
describe ".all_categories_cache" do
|
|
fab!(:category)
|
|
fab!(:category2, :category)
|
|
|
|
it "returns cached categories" do
|
|
categories_data = Site.all_categories_cache
|
|
expect(categories_data.map { |c| c[:id] }).to contain_exactly(
|
|
SiteSetting.uncategorized_category_id,
|
|
category.id,
|
|
category2.id,
|
|
)
|
|
end
|
|
|
|
it "caches the result" do
|
|
Site.all_categories_cache
|
|
|
|
category2.update_columns(name: "derp")
|
|
|
|
# The cached result should not contain
|
|
# the updated name that skipped validations
|
|
cached_names = Site.all_categories_cache.map { |c| c[:name] }
|
|
expect(cached_names).not_to include("derp")
|
|
|
|
Site.clear_cache
|
|
refreshed_names = Site.all_categories_cache.map { |c| c[:name] }
|
|
expect(refreshed_names).to include("derp")
|
|
end
|
|
|
|
it "includes preloaded custom fields" do
|
|
Site.reset_preloaded_category_custom_fields
|
|
Site.preloaded_category_custom_fields << "test_field"
|
|
|
|
category.custom_fields["test_field"] = "test_value"
|
|
category.save_custom_fields
|
|
|
|
categories_data = Site.all_categories_cache
|
|
category_data = categories_data.find { |c| c[:id] == category.id }
|
|
|
|
expect(category_data[:custom_fields]["test_field"]).to eq("test_value")
|
|
ensure
|
|
Site.reset_preloaded_category_custom_fields
|
|
end
|
|
|
|
it "applies plugin modifiers to the query" do
|
|
plugin_instance = Plugin::Instance.new
|
|
modifier_block =
|
|
Proc.new { |query| query.where("categories.name LIKE ?", "#{category.name}%") }
|
|
|
|
plugin_instance.register_modifier(:site_all_categories_cache_query, &modifier_block)
|
|
|
|
Site.clear_cache
|
|
categories_data = Site.all_categories_cache
|
|
|
|
expect(categories_data.map { |c| c[:id] }).to contain_exactly(category.id)
|
|
ensure
|
|
DiscoursePluginRegistry.unregister_modifier(
|
|
plugin_instance,
|
|
:site_all_categories_cache_query,
|
|
&modifier_block
|
|
)
|
|
end
|
|
|
|
describe "content_localization_enabled" do
|
|
it "returns localized category names when enabled" do
|
|
SiteSetting.content_localization_enabled = true
|
|
|
|
category = Fabricate(:category, locale: "en")
|
|
localization = Fabricate(:category_localization, category:)
|
|
locale = localization.locale.to_sym
|
|
|
|
I18n.locale = locale
|
|
|
|
all_categories_cache = Site.all_categories_cache
|
|
cached_category = all_categories_cache.find { |c| c[:id] == category.id }
|
|
expect(cached_category[:name]).to eq(localization.name)
|
|
expect(cached_category[:description]).to eq(localization.description)
|
|
end
|
|
|
|
it "returns original names when enabled" do
|
|
SiteSetting.content_localization_enabled = true
|
|
|
|
category = Fabricate(:category, name: "derp", description: "derp derp")
|
|
|
|
all_categories_cache = Site.all_categories_cache
|
|
cached_category = all_categories_cache.find { |c| c[:id] == category.id }
|
|
expect(cached_category[:name]).to eq(category.name)
|
|
expect(cached_category[:description]).to eq(category.description)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when there are anonymous users with different locales" do
|
|
let(:anon_guardian) { Guardian.new }
|
|
let(:original_locale) { I18n.locale }
|
|
|
|
before do
|
|
SiteSetting.login_required = false
|
|
Discourse.redis.flushdb
|
|
I18n.available_locales = %i[en ja]
|
|
I18n.locale = :en
|
|
end
|
|
|
|
after do
|
|
I18n.available_locales = nil
|
|
I18n.locale = original_locale
|
|
end
|
|
|
|
context "when content_localization_enabled is disabled" do
|
|
before { SiteSetting.content_localization_enabled = false }
|
|
|
|
it "caches anon site json with a global key (not locale scoped)" do
|
|
expect(Discourse.redis.get("site_json")).to be_nil
|
|
|
|
json = Site.json_for(anon_guardian)
|
|
|
|
expect(Discourse.redis.get("site_json")).to eq(json)
|
|
|
|
I18n.locale = :ja
|
|
json_ja = Site.json_for(anon_guardian)
|
|
expect(Discourse.redis.get("site_json")).to eq(json_ja)
|
|
|
|
# always overwritten, not per locale
|
|
I18n.locale = :en
|
|
expect(Discourse.redis.get("site_json")).to eq(json)
|
|
end
|
|
end
|
|
|
|
context "when content_localization_enabled is enabled" do
|
|
before { SiteSetting.content_localization_enabled = true }
|
|
|
|
it "caches anon site json separately for each locale" do
|
|
expect(Discourse.redis.get("site_json_en")).to be_nil
|
|
expect(Discourse.redis.get("site_json_ja")).to be_nil
|
|
|
|
json_en = Site.json_for(anon_guardian)
|
|
expect(Discourse.redis.get("site_json_en")).to eq(json_en)
|
|
|
|
I18n.locale = :ja
|
|
json_ja = Site.json_for(anon_guardian)
|
|
expect(Discourse.redis.get("site_json_ja")).to eq(json_ja)
|
|
|
|
expect(json_en).not_to eq(json_ja)
|
|
end
|
|
|
|
it "returns localized tag names for anonymous users based on locale" do
|
|
SiteSetting.tagging_enabled = true
|
|
tag = Fabricate(:tag, name: "cats", locale: "en")
|
|
Fabricate(:tag_localization, tag:, locale: "ja", name: "猫")
|
|
Fabricate(:topic, tags: [tag])
|
|
|
|
I18n.locale = :en
|
|
Discourse.redis.flushdb
|
|
json_en = Site.json_for(anon_guardian)
|
|
|
|
I18n.locale = :ja
|
|
json_ja = Site.json_for(anon_guardian)
|
|
|
|
expect(json_en).to include("cats")
|
|
expect(json_en).not_to include("猫")
|
|
expect(json_ja).to include("猫")
|
|
end
|
|
end
|
|
end
|
|
end
|