mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-07 02:22:49 +08:00
In a previous PR I had to work with TopicGuardian#can_delete_topic? and I had to whip out pen and paper to untangle the single conditional that governs it. Now that that task is done, I'm going back to it to clear it up. Commit by commit: 1. Move the tests to topic_guardian_spec.rb. 2. Add missing test cases for trashed- and category topics. 3. Break the conditional into individual code paths using guard clauses.
375 lines
14 KiB
Ruby
375 lines
14 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
RSpec.describe TopicGuardian do
|
|
fab!(:user) { Fabricate(:user, refresh_auto_groups: true) }
|
|
fab!(:admin)
|
|
fab!(:tl3_user, :trust_level_3)
|
|
fab!(:tl4_user, :trust_level_4)
|
|
fab!(:moderator)
|
|
fab!(:category)
|
|
fab!(:group)
|
|
fab!(:private_category) { Fabricate(:private_category, group: group) }
|
|
fab!(:topic) { Fabricate(:topic, category: category) }
|
|
fab!(:private_topic) { Fabricate(:topic, category: private_category) }
|
|
fab!(:private_message_topic)
|
|
|
|
before { Guardian.enable_topic_can_see_consistency_check }
|
|
|
|
after { Guardian.disable_topic_can_see_consistency_check }
|
|
|
|
describe "#can_create_shared_draft?" do
|
|
it "when shared_drafts are disabled" do
|
|
SiteSetting.shared_drafts_allowed_groups = Group::AUTO_GROUPS[:admins]
|
|
|
|
expect(Guardian.new(admin).can_create_shared_draft?).to eq(false)
|
|
end
|
|
|
|
it "when user is a moderator and access is set to admin" do
|
|
SiteSetting.shared_drafts_category = category.id
|
|
SiteSetting.shared_drafts_allowed_groups = Group::AUTO_GROUPS[:admins]
|
|
|
|
expect(Guardian.new(moderator).can_create_shared_draft?).to eq(false)
|
|
end
|
|
|
|
it "when user is a moderator and access is set to staff" do
|
|
SiteSetting.shared_drafts_category = category.id
|
|
SiteSetting.shared_drafts_allowed_groups = Group::AUTO_GROUPS[:staff]
|
|
|
|
expect(Guardian.new(moderator).can_create_shared_draft?).to eq(true)
|
|
end
|
|
|
|
it "when user is TL3 and access is set to TL2" do
|
|
SiteSetting.shared_drafts_category = category.id
|
|
SiteSetting.shared_drafts_allowed_groups = Group::AUTO_GROUPS[:trust_level_2]
|
|
|
|
expect(Guardian.new(tl3_user).can_create_shared_draft?).to eq(true)
|
|
end
|
|
end
|
|
|
|
describe "#can_see_shared_draft?" do
|
|
it "when shared_drafts are disabled (existing shared drafts)" do
|
|
SiteSetting.shared_drafts_allowed_groups = Group::AUTO_GROUPS[:admins]
|
|
|
|
expect(Guardian.new(admin).can_see_shared_draft?).to eq(true)
|
|
end
|
|
|
|
it "when user is a moderator and access is set to admin" do
|
|
SiteSetting.shared_drafts_category = category.id
|
|
SiteSetting.shared_drafts_allowed_groups = Group::AUTO_GROUPS[:admins]
|
|
|
|
expect(Guardian.new(moderator).can_see_shared_draft?).to eq(false)
|
|
end
|
|
|
|
it "when user is a moderator and access is set to staff" do
|
|
SiteSetting.shared_drafts_category = category.id
|
|
SiteSetting.shared_drafts_allowed_groups = Group::AUTO_GROUPS[:staff]
|
|
|
|
expect(Guardian.new(moderator).can_see_shared_draft?).to eq(true)
|
|
end
|
|
|
|
it "when user is TL3 and access is set to TL2" do
|
|
SiteSetting.shared_drafts_category = category.id
|
|
SiteSetting.shared_drafts_allowed_groups = Group::AUTO_GROUPS[:trust_level_2]
|
|
|
|
expect(Guardian.new(tl3_user).can_see_shared_draft?).to eq(true)
|
|
end
|
|
end
|
|
|
|
describe "#can_see_deleted_topics?" do
|
|
it "returns true for staff" do
|
|
expect(Guardian.new(admin).can_see_deleted_topics?(topic.category)).to eq(true)
|
|
end
|
|
|
|
it "returns true for group moderator" do
|
|
SiteSetting.enable_category_group_moderation = true
|
|
expect(Guardian.new(user).can_see_deleted_topics?(topic.category)).to eq(false)
|
|
Fabricate(:category_moderation_group, category:, group:)
|
|
group.add(user)
|
|
topic.update!(category: category)
|
|
expect(Guardian.new(user).can_see_deleted_topics?(topic.category)).to eq(true)
|
|
end
|
|
|
|
it "returns true when tl4 can delete posts and topics" do
|
|
expect(Guardian.new(tl4_user).can_see_deleted_topics?(topic.category)).to eq(false)
|
|
SiteSetting.delete_all_posts_and_topics_allowed_groups = Group::AUTO_GROUPS[:trust_level_4]
|
|
expect(Guardian.new(tl4_user).can_see_deleted_topics?(topic.category)).to eq(true)
|
|
end
|
|
|
|
it "returns false for anonymous user" do
|
|
SiteSetting.delete_all_posts_and_topics_allowed_groups = Group::AUTO_GROUPS[:trust_level_4]
|
|
expect(Guardian.new.can_see_deleted_topics?(topic.category)).to be_falsey
|
|
end
|
|
end
|
|
|
|
describe "#can_recover_topic?" do
|
|
fab!(:deleted_topic) { Fabricate(:topic, category: category, deleted_at: 1.day.ago) }
|
|
it "returns true for staff" do
|
|
expect(Guardian.new(admin).can_recover_topic?(Topic.with_deleted.last)).to eq(true)
|
|
end
|
|
|
|
it "returns true for group moderator" do
|
|
SiteSetting.enable_category_group_moderation = true
|
|
expect(Guardian.new(user).can_recover_topic?(Topic.with_deleted.last)).to eq(false)
|
|
Fabricate(:category_moderation_group, category:, group:)
|
|
group.add(user)
|
|
topic.update!(category: category)
|
|
expect(Guardian.new(user).can_recover_topic?(Topic.with_deleted.last)).to eq(true)
|
|
end
|
|
|
|
it "returns true when tl4 can delete posts and topics" do
|
|
expect(Guardian.new(tl4_user).can_recover_topic?(Topic.with_deleted.last)).to eq(false)
|
|
SiteSetting.delete_all_posts_and_topics_allowed_groups = Group::AUTO_GROUPS[:trust_level_4]
|
|
expect(Guardian.new(tl4_user).can_recover_topic?(Topic.with_deleted.last)).to eq(true)
|
|
end
|
|
|
|
it "returns false for anonymous user" do
|
|
SiteSetting.delete_all_posts_and_topics_allowed_groups = Group::AUTO_GROUPS[:trust_level_4]
|
|
expect(Guardian.new.can_recover_topic?(Topic.with_deleted.last)).to eq(false)
|
|
end
|
|
end
|
|
|
|
describe "#can_edit_topic?" do
|
|
context "when the topic is a shared draft" do
|
|
let(:tl2_user) { Fabricate(:user, trust_level: TrustLevel[2]) }
|
|
|
|
before do
|
|
SiteSetting.shared_drafts_category = category.id
|
|
SiteSetting.shared_drafts_allowed_groups = Group::AUTO_GROUPS[:trust_level_2]
|
|
end
|
|
|
|
it "returns false if the topic is a PM" do
|
|
pm_with_draft = Fabricate(:private_message_topic, category: category)
|
|
Fabricate(:shared_draft, topic: pm_with_draft)
|
|
|
|
expect(Guardian.new(tl2_user).can_edit_topic?(pm_with_draft)).to eq(false)
|
|
end
|
|
|
|
it "returns false if the topic is archived" do
|
|
archived_topic = Fabricate(:topic, archived: true, category: category)
|
|
Fabricate(:shared_draft, topic: archived_topic)
|
|
|
|
expect(Guardian.new(tl2_user).can_edit_topic?(archived_topic)).to eq(false)
|
|
end
|
|
|
|
it "returns true if a shared draft exists" do
|
|
Fabricate(:shared_draft, topic: topic)
|
|
|
|
expect(Guardian.new(tl2_user).can_edit_topic?(topic)).to eq(true)
|
|
end
|
|
|
|
it "returns false if the user has a lower trust level" do
|
|
tl1_user = Fabricate(:user, trust_level: TrustLevel[1])
|
|
Fabricate(:shared_draft, topic: topic)
|
|
|
|
expect(Guardian.new(tl1_user).can_edit_topic?(topic)).to eq(false)
|
|
end
|
|
|
|
it "returns true if the shared_draft is from a different category" do
|
|
topic = Fabricate(:topic, category: Fabricate(:category))
|
|
Fabricate(:shared_draft, topic: topic)
|
|
|
|
expect(Guardian.new(tl2_user).can_edit_topic?(topic)).to eq(false)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#can_delete_topic?" do
|
|
it "returns false for an unauthenticated user" do
|
|
expect(Guardian.new.can_delete_topic?(topic)).to be_falsey
|
|
end
|
|
|
|
it "returns false for a regular user" do
|
|
expect(Guardian.new(Fabricate(:user)).can_delete_topic?(topic)).to be_falsey
|
|
end
|
|
|
|
it "returns true for a moderator" do
|
|
expect(Guardian.new(moderator).can_delete_topic?(topic)).to be_truthy
|
|
end
|
|
|
|
it "returns true for an admin" do
|
|
expect(Guardian.new(admin).can_delete_topic?(topic)).to be_truthy
|
|
end
|
|
|
|
it "returns false for static doc topics" do
|
|
tos_topic = Fabricate(:topic, user: Discourse.system_user)
|
|
SiteSetting.tos_topic_id = tos_topic.id
|
|
expect(Guardian.new(admin).can_delete_topic?(tos_topic)).to be_falsey
|
|
end
|
|
|
|
it "returns false when topic is trashed" do
|
|
topic.stubs(:trashed?).returns(true)
|
|
expect(Guardian.new(admin).can_delete_topic?(topic)).to be_falsey
|
|
end
|
|
|
|
it "returns false when topic is category topic" do
|
|
topic.stubs(:is_category_topic?).returns(true)
|
|
expect(Guardian.new(admin).can_delete_topic?(topic)).to be_falsey
|
|
end
|
|
|
|
it "returns true for own topic with no replies" do
|
|
topic.update_attribute(:posts_count, 1)
|
|
topic.update_attribute(:created_at, Time.zone.now)
|
|
expect(Guardian.new(topic.user).can_delete_topic?(topic)).to be_truthy
|
|
end
|
|
|
|
it "returns false for own topic with replies" do
|
|
topic.update!(posts_count: 2, created_at: Time.zone.now)
|
|
expect(Guardian.new(topic.user).can_delete_topic?(topic)).to be_falsey
|
|
end
|
|
|
|
it "returns false for own topic within cooldown period" do
|
|
topic.update!(posts_count: 1, created_at: 48.hours.ago)
|
|
expect(Guardian.new(topic.user).can_delete_topic?(topic)).to be_falsey
|
|
end
|
|
|
|
it "returns true for user in allowed groups" do
|
|
SiteSetting.delete_all_posts_and_topics_allowed_groups = Group::AUTO_GROUPS[:trust_level_4]
|
|
expect(Guardian.new(tl4_user).can_delete_topic?(topic)).to be_truthy
|
|
end
|
|
|
|
it "returns false for user not in allowed groups" do
|
|
SiteSetting.delete_all_posts_and_topics_allowed_groups = Group::AUTO_GROUPS[:trust_level_4]
|
|
expect(Guardian.new(tl3_user).can_delete_topic?(topic)).to be_falsey
|
|
end
|
|
|
|
context "when category group moderation is enabled" do
|
|
fab!(:group_user)
|
|
|
|
before { SiteSetting.enable_category_group_moderation = true }
|
|
|
|
it "returns false if user is not a member of the appropriate group" do
|
|
expect(Guardian.new(group_user.user).can_delete_topic?(topic)).to be_falsey
|
|
end
|
|
|
|
it "returns true if user is a member of the appropriate group" do
|
|
Fabricate(:category_moderation_group, category: topic.category, group: group_user.group)
|
|
|
|
expect(Guardian.new(group_user.user).can_delete_topic?(topic)).to be_truthy
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#is_in_edit_topic_groups?" do
|
|
it "returns true if the user is in edit_all_topic_groups" do
|
|
group.add(user)
|
|
SiteSetting.edit_all_topic_groups = group.id.to_s
|
|
|
|
expect(Guardian.new(user).is_in_edit_topic_groups?).to eq(true)
|
|
end
|
|
|
|
it "returns false if the user is not in edit_all_topic_groups" do
|
|
SiteSetting.edit_all_topic_groups = Group::AUTO_GROUPS[:trust_level_4]
|
|
|
|
expect(Guardian.new(tl3_user).is_in_edit_topic_groups?).to eq(false)
|
|
end
|
|
|
|
it "returns false if the edit_all_topic_groups is empty" do
|
|
SiteSetting.edit_all_topic_groups = nil
|
|
|
|
expect(Guardian.new(user).is_in_edit_topic_groups?).to eq(false)
|
|
end
|
|
end
|
|
|
|
describe "#can_review_topic?" do
|
|
it "returns false for TL4 users" do
|
|
topic = Fabricate(:topic)
|
|
|
|
expect(Guardian.new(tl4_user).can_review_topic?(topic)).to eq(false)
|
|
end
|
|
end
|
|
|
|
describe "#can_create_unlisted_topic?" do
|
|
it "returns true for moderators" do
|
|
expect(Guardian.new(moderator).can_create_unlisted_topic?(topic)).to eq(true)
|
|
end
|
|
|
|
it "returns true for TL4 users" do
|
|
expect(Guardian.new(tl4_user).can_create_unlisted_topic?(topic)).to eq(true)
|
|
end
|
|
|
|
it "returns false for regular users" do
|
|
expect(Guardian.new(user).can_create_unlisted_topic?(topic)).to eq(false)
|
|
end
|
|
end
|
|
|
|
describe "#can_see_unlisted_topics?" do
|
|
it "is allowed for staff users" do
|
|
expect(Guardian.new(moderator).can_see_unlisted_topics?).to eq(true)
|
|
end
|
|
|
|
it "is allowed for TL4 users" do
|
|
expect(Guardian.new(tl4_user).can_see_unlisted_topics?).to eq(true)
|
|
end
|
|
|
|
it "is not allowed for lower level users" do
|
|
expect(Guardian.new(tl3_user).can_see_unlisted_topics?).to eq(false)
|
|
end
|
|
end
|
|
|
|
# The test cases here are intentionally kept brief because majority of the cases are already handled by
|
|
# `TopicGuardianCanSeeConsistencyCheck` which we run to ensure that the implementation between `TopicGuardian#can_see_topic_ids`
|
|
# and `TopicGuardian#can_see_topic?` is consistent.
|
|
describe "#can_see_topic_ids" do
|
|
it "returns the topic ids for the topics which a user is allowed to see" do
|
|
expect(
|
|
Guardian.new.can_see_topic_ids(topic_ids: [topic.id, private_message_topic.id]),
|
|
).to contain_exactly(topic.id)
|
|
|
|
expect(
|
|
Guardian.new(user).can_see_topic_ids(topic_ids: [topic.id, private_message_topic.id]),
|
|
).to contain_exactly(topic.id)
|
|
|
|
expect(
|
|
Guardian.new(moderator).can_see_topic_ids(topic_ids: [topic.id, private_message_topic.id]),
|
|
).to contain_exactly(topic.id)
|
|
|
|
expect(
|
|
Guardian.new(admin).can_see_topic_ids(topic_ids: [topic.id, private_message_topic.id]),
|
|
).to contain_exactly(topic.id, private_message_topic.id)
|
|
end
|
|
|
|
it "returns the topic ids for topics which are deleted but user is a category moderator of" do
|
|
SiteSetting.enable_category_group_moderation = true
|
|
|
|
Fabricate(:category_moderation_group, category:, group:)
|
|
group.add(user)
|
|
topic.update!(category: category)
|
|
topic.trash!(admin)
|
|
|
|
topic2 = Fabricate(:topic)
|
|
user2 = Fabricate(:user)
|
|
|
|
expect(
|
|
Guardian.new(user).can_see_topic_ids(topic_ids: [topic.id, topic2.id]),
|
|
).to contain_exactly(topic.id, topic2.id)
|
|
|
|
expect(
|
|
Guardian.new(user2).can_see_topic_ids(topic_ids: [topic.id, topic2.id]),
|
|
).to contain_exactly(topic2.id)
|
|
end
|
|
end
|
|
|
|
describe "#filter_allowed_categories" do
|
|
it "allows admin access to categories without explicit access" do
|
|
guardian = Guardian.new(admin)
|
|
list = Topic.where(id: private_topic.id)
|
|
list = guardian.filter_allowed_categories(list)
|
|
|
|
expect(list.count).to eq(1)
|
|
end
|
|
|
|
context "when SiteSetting.suppress_secured_categories_from_admin is true" do
|
|
before { SiteSetting.suppress_secured_categories_from_admin = true }
|
|
|
|
it "does not allow admin access to categories without explicit access" do
|
|
guardian = Guardian.new(admin)
|
|
list = Topic.where(id: private_topic.id)
|
|
list = guardian.filter_allowed_categories(list)
|
|
|
|
expect(list.count).to eq(0)
|
|
|
|
expect(guardian.can_see?(private_topic)).to eq(false)
|
|
end
|
|
end
|
|
end
|
|
end
|