diff --git a/app/models/category.rb b/app/models/category.rb index 92f0b751723..a120391f775 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -60,32 +60,21 @@ class Category < ActiveRecord::Base has_many :category_tag_groups, dependent: :destroy has_many :tag_groups, through: :category_tag_groups - scope :latest, ->{ order('topic_count desc') } + scope :latest, -> { order('topic_count DESC') } - scope :secured, ->(guardian = nil) { + scope :secured, -> (guardian = nil) { ids = guardian.secure_category_ids if guardian if ids.present? - where("NOT categories.read_restricted or categories.id in (:cats)", cats: ids).references(:categories) + where("NOT categories.read_restricted OR categories.id IN (:cats)", cats: ids).references(:categories) else where("NOT categories.read_restricted").references(:categories) end } - scope :topic_create_allowed, ->(guardian) { - if guardian.anonymous? - where("1=0") - else - scoped_to_permissions(guardian, [:full]) - end - } - - scope :post_create_allowed, ->(guardian) { - if guardian.anonymous? - where("1=0") - else - scoped_to_permissions(guardian, [:create_post, :full]) - end - } + TOPIC_CREATION_PERMISSIONS ||= [:full] + POST_CREATION_PERMISSIONS ||= [:create_post, :full] + scope :topic_create_allowed, -> (guardian) { scoped_to_permissions(guardian, TOPIC_CREATION_PERMISSIONS) } + scope :post_create_allowed, -> (guardian) { scoped_to_permissions(guardian, POST_CREATION_PERMISSIONS) } delegate :post_template, to: 'self.class' @@ -98,7 +87,7 @@ class Category < ActiveRecord::Base end def self.scoped_to_permissions(guardian, permission_types) - if guardian && guardian.is_admin? + if guardian.try(:is_admin?) all elsif !guardian || guardian.anonymous? if permission_types.include?(:readonly) @@ -107,28 +96,19 @@ class Category < ActiveRecord::Base where("1 = 0") end else - permission_types = permission_types.map{ |permission_type| - CategoryGroup.permission_types[permission_type] - } - where("categories.id in ( - SELECT cg.category_id FROM category_groups cg - WHERE permission_type in (:permissions) AND - ( - group_id IN ( - SELECT g.group_id FROM group_users g where g.user_id = :user_id - ) - ) - ) - OR - categories.id in ( - SELECT cg.category_id FROM category_groups cg - WHERE permission_type in (:permissions) AND group_id = :everyone - ) - OR - categories.id NOT in (SELECT cg.category_id FROM category_groups cg) - ", permissions: permission_types, - user_id: guardian.user.id, - everyone: Group[:everyone].id) + permissions = permission_types.map { |p| CategoryGroup.permission_types[p] } + where("(:staged AND LENGTH(COALESCE(email_in, '')) > 0 AND email_in_allow_strangers) + OR categories.id NOT IN (SELECT category_id FROM category_groups) + OR categories.id IN ( + SELECT category_id + FROM category_groups + WHERE permission_type IN (:permissions) + AND (group_id = :everyone OR group_id IN (SELECT group_id FROM group_users WHERE user_id = :user_id)) + )", + staged: guardian.is_staged?, + permissions: permissions, + user_id: guardian.user.id, + everyone: Group[:everyone].id) end end @@ -139,14 +119,13 @@ class Category < ActiveRecord::Base .group("topics.category_id") .visible.to_sql - Category.exec_sql < x.topic_count OR c.post_count <> x.post_count) - + SET topic_count = x.topic_count, + post_count = x.post_count + FROM (#{topics_with_post_count}) x + WHERE x.category_id = c.id + AND (c.topic_count <> x.topic_count OR c.post_count <> x.post_count) SQL # Yes, there are a lot of queries happening below. diff --git a/lib/guardian.rb b/lib/guardian.rb index 8f4593943c8..28235ed8024 100644 --- a/lib/guardian.rb +++ b/lib/guardian.rb @@ -78,6 +78,10 @@ class Guardian ) end + def is_staged? + @user.staged? + end + # Can the user see the object? def can_see?(obj) if obj diff --git a/lib/guardian/post_guardian.rb b/lib/guardian/post_guardian.rb index 2c883d15a16..7ff13bf0e43 100644 --- a/lib/guardian/post_guardian.rb +++ b/lib/guardian/post_guardian.rb @@ -76,7 +76,6 @@ module PostGuardian # Creating Method def can_create_post?(parent) - (!SpamRule::AutoBlock.block?(@user) || (!!parent.try(:private_message?) && parent.allowed_users.include?(@user))) && ( !parent || !parent.category || diff --git a/spec/components/email/receiver_spec.rb b/spec/components/email/receiver_spec.rb index 533eea27ec3..bd60b249b3b 100644 --- a/spec/components/email/receiver_spec.rb +++ b/spec/components/email/receiver_spec.rb @@ -107,8 +107,9 @@ describe Email::Receiver do context "reply" do let(:reply_key) { "4f97315cc828096c9cb34c6f1a0d6fe8" } + let(:category) { Fabricate(:category) } let(:user) { Fabricate(:user, email: "discourse@bar.com") } - let(:topic) { create_topic(user: user) } + let(:topic) { create_topic(category: category, user: user) } let(:post) { create_post(topic: topic, user: user) } let!(:email_log) { Fabricate(:email_log, reply_key: reply_key, user: user, topic: topic, post: post) } @@ -214,6 +215,17 @@ describe Email::Receiver do expect { process(:auto_generated_unblocked) }.to change { topic.posts.count } end + it "allows staged users to reply to a restricted category" do + user.update_columns(staged: true) + + category.email_in = "category@bar.com" + category.email_in_allow_strangers = true + category.set_permissions(Group[:trust_level_4] => :full) + category.save + + expect { process(:staged_reply_restricted) }.to change { topic.posts.count } + end + describe 'Unsubscribing via email' do let(:last_email) { ActionMailer::Base.deliveries.last } diff --git a/spec/fixtures/emails/staged_reply_restricted.eml b/spec/fixtures/emails/staged_reply_restricted.eml new file mode 100644 index 00000000000..6f753212db6 Binary files /dev/null and b/spec/fixtures/emails/staged_reply_restricted.eml differ