Skip to content

Commit

Permalink
FEATURE: Allow group moderators to close/archive topics
Browse files Browse the repository at this point in the history
* FEATURE: Allow group moderators to close/archive topics
  • Loading branch information
jbrw committed Jul 14, 2020
1 parent cc6d722 commit 06073fe
Show file tree
Hide file tree
Showing 31 changed files with 215 additions and 38 deletions.
4 changes: 3 additions & 1 deletion app/assets/javascripts/discourse/app/lib/transform-post.js
Expand Up @@ -119,7 +119,9 @@ export default function transformPost(
postAtts.canManage = currentUser && currentUser.get("canManageTopic");
postAtts.canViewRawEmail =
currentUser && (currentUser.id === post.user_id || currentUser.staff);
postAtts.canReplyAsNewTopic = details.can_reply_as_new_topic;
postAtts.canArchiveTopic = !!details.can_archive_topic;
postAtts.canCloseTopic = !!details.can_close_topic;
postAtts.canReplyAsNewTopic = !!details.can_reply_as_new_topic;
postAtts.canReviewTopic = !!details.can_review_topic;
postAtts.canPublishPage =
!!details.can_publish_page && post.post_number === 1;
Expand Down
Expand Up @@ -81,7 +81,7 @@

<section>
<h3>{{i18n "category.settings_sections.moderation"}}</h3>
{{#if siteSettings.enable_category_group_review}}
{{#if siteSettings.enable_category_group_moderation}}
<section class="field">
<label for="reviewable-by-group">
{{i18n "category.reviewable_by_group"}}
Expand Down
Expand Up @@ -158,7 +158,9 @@ export default createWidget("topic-admin-menu", {
label: "actions.recover"
});
}
}

if (this.currentUser && details.get("can_close_topic")) {
if (topic.get("closed")) {
this.addActionButton({
className: "topic-admin-open",
Expand All @@ -176,7 +178,9 @@ export default createWidget("topic-admin-menu", {
label: "actions.close"
});
}
}

if (this.currentUser && this.currentUser.get("canManageTopic")) {
this.addActionButton({
className: "topic-admin-status-update",
buttonClass: "popup-menu-btn",
Expand Down Expand Up @@ -212,7 +216,9 @@ export default createWidget("topic-admin-menu", {
icon: "anchor",
label: "actions.reset_bump_date"
});
}

if (this.currentUser && details.get("can_archive_topic")) {
if (!isPrivateMessage) {
this.addActionButton({
className: "topic-admin-archive",
Expand All @@ -222,7 +228,9 @@ export default createWidget("topic-admin-menu", {
label: topic.get("archived") ? "actions.unarchive" : "actions.archive"
});
}
}

if (this.currentUser && this.currentUser.get("canManageTopic")) {
this.addActionButton({
className: "topic-admin-visible",
buttonClass: "popup-menu-btn",
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/categories_controller.rb
Expand Up @@ -335,7 +335,7 @@ def category_params
allowed_tags: [],
allowed_tag_groups: []
)
if SiteSetting.enable_category_group_review?
if SiteSetting.enable_category_group_moderation?
result[:reviewable_by_group_id] = Group.find_by(name: params[:reviewable_by_group_name])&.id
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/reviewable_claimed_topics_controller.rb
Expand Up @@ -40,7 +40,7 @@ def destroy
def notify_users(topic, claimed_by)
user_ids = User.staff.pluck(:id)

if SiteSetting.enable_category_group_review? && group_id = topic.category&.reviewable_by_group_id.presence
if SiteSetting.enable_category_group_moderation? && group_id = topic.category&.reviewable_by_group_id.presence
user_ids.concat(GroupUser.where(group_id: group_id).pluck(:user_id))
user_ids.uniq!
end
Expand Down
11 changes: 10 additions & 1 deletion app/controllers/topics_controller.rb
Expand Up @@ -412,7 +412,16 @@ def status

check_for_status_presence(:status, status)
@topic = Topic.find_by(id: topic_id)
guardian.ensure_can_moderate!(@topic)

case status
when 'closed'
guardian.ensure_can_close_topic!(@topic)
when 'archived'
guardian.ensure_can_archive_topic!(@topic)
else
guardian.ensure_can_moderate!(@topic)
end

@topic.update_status(status, enabled, current_user, until: params[:until])

render json: success_json.merge!(
Expand Down
2 changes: 1 addition & 1 deletion app/jobs/regular/notify_reviewable.rb
Expand Up @@ -10,7 +10,7 @@ def execute(args)

notify_admins
notify_moderators if reviewable.reviewable_by_moderator?
if SiteSetting.enable_category_group_review? && reviewable.reviewable_by_group.present?
if SiteSetting.enable_category_group_moderation? && reviewable.reviewable_by_group.present?
notify_group(reviewable.reviewable_by_group)
end
end
Expand Down
2 changes: 1 addition & 1 deletion app/jobs/regular/toggle_topic_closed.rb
Expand Up @@ -16,7 +16,7 @@ def execute(args)

user = topic_timer.user

if Guardian.new(user).can_close?(topic)
if Guardian.new(user).can_close_topic?(topic)
if state == false && topic.auto_close_threshold_reached?
topic.set_or_create_timer(
TopicTimer.types[:open],
Expand Down
2 changes: 1 addition & 1 deletion app/models/category.rb
Expand Up @@ -768,7 +768,7 @@ def index_search
end

def update_reviewables
if SiteSetting.enable_category_group_review? && saved_change_to_reviewable_by_group_id?
if SiteSetting.enable_category_group_moderation? && saved_change_to_reviewable_by_group_id?
Reviewable.where(category_id: id).update_all(reviewable_by_group_id: reviewable_by_group_id)
end
end
Expand Down
4 changes: 2 additions & 2 deletions app/models/reviewable.rb
Expand Up @@ -281,7 +281,7 @@ def log_history(reviewable_history_type, performed_by, edited: nil)
end

def apply_review_group
return unless SiteSetting.enable_category_group_review? &&
return unless SiteSetting.enable_category_group_moderation? &&
category.present? &&
category.reviewable_by_group_id

Expand Down Expand Up @@ -419,7 +419,7 @@ def self.viewable_by(user, order: nil, preload: true)
end
return result if user.admin?

group_ids = SiteSetting.enable_category_group_review? ? user.group_users.pluck(:group_id) : []
group_ids = SiteSetting.enable_category_group_moderation? ? user.group_users.pluck(:group_id) : []

result.where(
'(reviewables.reviewable_by_moderator AND :staff) OR (reviewables.reviewable_by_group_id IN (:group_ids))',
Expand Down
2 changes: 1 addition & 1 deletion app/models/reviewable_flagged_post.rb
Expand Up @@ -292,7 +292,7 @@ def unassign_topic(performed_by, post)

user_ids = User.staff.pluck(:id)

if SiteSetting.enable_category_group_review? && group_id = topic.category&.reviewable_by_group_id.presence
if SiteSetting.enable_category_group_moderation? && group_id = topic.category&.reviewable_by_group_id.presence
user_ids.concat(GroupUser.where(group_id: group_id).pluck(:user_id))
user_ids.uniq!
end
Expand Down
2 changes: 1 addition & 1 deletion app/serializers/category_serializer.rb
Expand Up @@ -26,7 +26,7 @@ def reviewable_by_group_name
end

def include_reviewable_by_group_name?
SiteSetting.enable_category_group_review? && object.reviewable_by_group_id.present?
SiteSetting.enable_category_group_moderation? && object.reviewable_by_group_id.present?
end

def group_permissions
Expand Down
12 changes: 11 additions & 1 deletion app/serializers/topic_view_details_serializer.rb
Expand Up @@ -16,7 +16,9 @@ def self.can_attributes
:can_convert_topic,
:can_review_topic,
:can_edit_tags,
:can_publish_page]
:can_publish_page,
:can_close_topic,
:can_archive_topic]
end

attributes(
Expand Down Expand Up @@ -134,6 +136,14 @@ def include_can_edit_tags?
!scope.can_edit?(object.topic) && scope.can_edit_tags?(object.topic)
end

def include_can_close_topic?
scope.can_close_topic?(object.topic)
end

def include_can_archive_topic?
scope.can_archive_topic?(object.topic)
end

def include_can_publish_page?
scope.can_publish_page?(object.topic)
end
Expand Down
2 changes: 1 addition & 1 deletion config/locales/client.en.yml
Expand Up @@ -2888,7 +2888,7 @@ en:
default_list_filter: "Default List Filter:"
allow_badges_label: "Allow badges to be awarded in this category"
edit_permissions: "Edit Permissions"
reviewable_by_group: "In addition to staff, posts and flags in this category can be also be reviewed by:"
reviewable_by_group: "In addition to staff, content in this category can be also be reviewed by:"
review_group_name: "group name"
require_topic_approval: "Require moderator approval of all new topics"
require_reply_approval: "Require moderator approval of all new replies"
Expand Down
2 changes: 1 addition & 1 deletion config/locales/server.en.yml
Expand Up @@ -2016,7 +2016,7 @@ en:
staff_user_custom_fields: "A list of user custom fields that can be retrieved for staff members with the API."
enable_user_directory: "Provide a directory of users for browsing"
enable_group_directory: "Provide a directory of groups for browsing"
enable_category_group_review: "Allow groups to review content in specific categories"
enable_category_group_moderation: "Allow groups to moderate content in specific categories"
group_in_subject: "Set %%{optional_pm} in email subject to name of first group in PM, see: <a href='https://meta.discourse.org/t/customize-subject-format-for-standard-emails/20801' target='_blank'>Customize subject format for standard emails</a>"
allow_anonymous_posting: "Allow users to switch to anonymous mode"
anonymous_posting_min_trust_level: "Minimum trust level required to enable anonymous posting"
Expand Down
2 changes: 1 addition & 1 deletion config/site_settings.yml
Expand Up @@ -600,7 +600,7 @@ groups:
default: true
group_in_subject:
default: false
enable_category_group_review:
enable_category_group_moderation:
client: true
default: false

Expand Down
@@ -0,0 +1,13 @@
# frozen_string_literal: true

class RenameCategoryGroupModerationSetting < ActiveRecord::Migration[6.0]
def up
execute "UPDATE site_settings SET name = 'enable_category_group_moderation' WHERE name = 'enable_category_group_review'"
execute "UPDATE user_histories SET subject = 'enable_category_group_moderation' WHERE subject = 'enable_category_group_review'"
end

def down
execute "UPDATE site_settings SET name = 'enable_category_group_review' WHERE name = 'enable_category_group_moderation'"
execute "UPDATE user_histories SET subject = 'enable_category_group_review' WHERE subject = 'enable_category_group_moderation'"
end
end
1 change: 0 additions & 1 deletion lib/guardian.rb
Expand Up @@ -165,7 +165,6 @@ def can_moderate?(obj)
end
alias :can_move_posts? :can_moderate?
alias :can_see_flags? :can_moderate?
alias :can_close? :can_moderate?

def can_tag?(topic)
return false if topic.blank?
Expand Down
16 changes: 15 additions & 1 deletion lib/guardian/topic_guardian.rb
Expand Up @@ -17,7 +17,7 @@ def can_review_topic?(topic)
return false if anonymous? || topic.nil?
return true if is_staff?

SiteSetting.enable_category_group_review? &&
SiteSetting.enable_category_group_moderation? &&
topic.category.present? &&
topic.category.reviewable_by_group_id.present? &&
GroupUser.where(group_id: topic.category.reviewable_by_group_id, user_id: user.id).exists?
Expand Down Expand Up @@ -203,4 +203,18 @@ def can_edit_tags?(topic)

false
end

def can_perform_action_available_to_group_moderators?(topic)
return false if anonymous? || topic.nil?
return true if is_staff?
return true if @user.has_trust_level?(TrustLevel[4])

SiteSetting.enable_category_group_moderation? &&
topic.category.present? &&
topic.category.reviewable_by_group_id.present? &&
GroupUser.where(group_id: topic.category.reviewable_by_group_id, user_id: @user.id).exists?
end
alias :can_archive_topic? :can_perform_action_available_to_group_moderators?
alias :can_close_topic? :can_perform_action_available_to_group_moderators?

end
2 changes: 1 addition & 1 deletion lib/guardian/user_guardian.rb
Expand Up @@ -147,7 +147,7 @@ def can_feature_topic?(user, topic)

def can_see_review_queue?
is_staff? || (
SiteSetting.enable_category_group_review &&
SiteSetting.enable_category_group_moderation &&
Reviewable
.where(reviewable_by_group_id: @user.group_users.pluck(:group_id))
.where('category_id IS NULL or category_id IN (?)', allowed_category_ids)
Expand Down
6 changes: 3 additions & 3 deletions spec/components/guardian/user_guardian_spec.rb
Expand Up @@ -380,7 +380,7 @@
group = Fabricate(:group)
group.add(user)
guardian = Guardian.new(user)
SiteSetting.enable_category_group_review = true
SiteSetting.enable_category_group_moderation = true

Fabricate(:reviewable_flagged_post, reviewable_by_group: group, category: nil)

Expand All @@ -391,7 +391,7 @@
group = Fabricate(:group)
group.add(user)
guardian = Guardian.new(user)
SiteSetting.enable_category_group_review = false
SiteSetting.enable_category_group_moderation = false

Fabricate(:reviewable_flagged_post, reviewable_by_group: group, category: nil)

Expand All @@ -402,7 +402,7 @@
group = Fabricate(:group)
group.add(user)
guardian = Guardian.new(user)
SiteSetting.enable_category_group_review = true
SiteSetting.enable_category_group_moderation = true
category = Fabricate(:category, read_restricted: true)

Fabricate(:reviewable_flagged_post, reviewable_by_group: group, category: category)
Expand Down
48 changes: 46 additions & 2 deletions spec/components/guardian_spec.rb
Expand Up @@ -1726,15 +1726,59 @@
expect(Guardian.new(user).can_review_topic?(topic)).to eq(false)
end

it 'returns false for a regular user' do
SiteSetting.enable_category_group_review = true
it 'returns true for a group member with reviewable status' do
SiteSetting.enable_category_group_moderation = true
group = Fabricate(:group)
GroupUser.create!(group_id: group.id, user_id: user.id)
topic.category.update!(reviewable_by_group_id: group.id)
expect(Guardian.new(user).can_review_topic?(topic)).to eq(true)
end
end

context "can_close_topic?" do
it 'returns false with a nil object' do
expect(Guardian.new(user).can_close_topic?(nil)).to eq(false)
end

it 'returns true for a staff user' do
expect(Guardian.new(moderator).can_close_topic?(topic)).to eq(true)
end

it 'returns false for a regular user' do
expect(Guardian.new(user).can_close_topic?(topic)).to eq(false)
end

it 'returns true for a group member with reviewable status' do
SiteSetting.enable_category_group_moderation = true
group = Fabricate(:group)
GroupUser.create!(group_id: group.id, user_id: user.id)
topic.category.update!(reviewable_by_group_id: group.id)
expect(Guardian.new(user).can_close_topic?(topic)).to eq(true)
end
end

context "can_archive_topic?" do
it 'returns false with a nil object' do
expect(Guardian.new(user).can_archive_topic?(nil)).to eq(false)
end

it 'returns true for a staff user' do
expect(Guardian.new(moderator).can_archive_topic?(topic)).to eq(true)
end

it 'returns false for a regular user' do
expect(Guardian.new(user).can_archive_topic?(topic)).to eq(false)
end

it 'returns true for a group member with reviewable status' do
SiteSetting.enable_category_group_moderation = true
group = Fabricate(:group)
GroupUser.create!(group_id: group.id, user_id: user.id)
topic.category.update!(reviewable_by_group_id: group.id)
expect(Guardian.new(user).can_archive_topic?(topic)).to eq(true)
end
end

context "can_create_topic?" do
it 'returns true for staff user' do
expect(Guardian.new(moderator).can_create_topic?(topic)).to eq(true)
Expand Down
6 changes: 3 additions & 3 deletions spec/jobs/notify_reviewable_spec.rb
Expand Up @@ -11,7 +11,7 @@
let(:group) { group_user.group }

it "will notify users of new reviewable content" do
SiteSetting.enable_category_group_review = true
SiteSetting.enable_category_group_moderation = true

GroupUser.create!(group_id: group.id, user_id: moderator.id)

Expand Down Expand Up @@ -52,7 +52,7 @@
end

it "won't notify a group when disabled" do
SiteSetting.enable_category_group_review = false
SiteSetting.enable_category_group_moderation = false

GroupUser.create!(group_id: group.id, user_id: moderator.id)
r3 = Fabricate(:reviewable, reviewable_by_moderator: true, reviewable_by_group: group)
Expand All @@ -64,7 +64,7 @@
end

it "respects visibility" do
SiteSetting.enable_category_group_review = true
SiteSetting.enable_category_group_moderation = true
Reviewable.set_priorities(medium: 2.0)
SiteSetting.reviewable_default_visibility = 'medium'

Expand Down

1 comment on commit 06073fe

@discoursebot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit has been mentioned on Discourse Meta. There might be relevant details there:

https://meta.discourse.org/t/category-group-review-moderation/116478/56

Please sign in to comment.