FEATURE: Support designating multiple groups as mods on category (#28655)
Currently, categories support designating only 1 group as a moderation group on the category. This commit removes the one group limitation and makes it possible to designate multiple groups as mods on a category. Internal topic: t/124648.
This commit is contained in:
parent
7092d88ee4
commit
280adda09c
|
@ -120,11 +120,10 @@
|
|||
{{#if this.siteSettings.enable_category_group_moderation}}
|
||||
<section class="field reviewable-by-group">
|
||||
<label>{{i18n "category.reviewable_by_group"}}</label>
|
||||
<GroupSelector
|
||||
@groupFinder={{this.groupFinder}}
|
||||
@single="true"
|
||||
@groupNames={{this.category.reviewable_by_group_name}}
|
||||
@placeholderKey="category.review_group_name"
|
||||
<GroupChooser
|
||||
@content={{this.site.groups}}
|
||||
@value={{this.category.moderating_group_ids}}
|
||||
@onChange={{this.onCategoryModeratingGroupsChange}}
|
||||
/>
|
||||
</section>
|
||||
{{/if}}
|
||||
|
|
|
@ -3,7 +3,6 @@ import { and, empty } from "@ember/object/computed";
|
|||
import { buildCategoryPanel } from "discourse/components/edit-category-panel";
|
||||
import { setting } from "discourse/lib/computed";
|
||||
import { SEARCH_PRIORITIES } from "discourse/lib/constants";
|
||||
import Group from "discourse/models/group";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
|
@ -50,10 +49,6 @@ export default class EditCategorySettings extends buildCategoryPanel(
|
|||
];
|
||||
}
|
||||
|
||||
groupFinder(term) {
|
||||
return Group.findAll({ term, ignore_automatic: true });
|
||||
}
|
||||
|
||||
@discourseComputed
|
||||
availableViews() {
|
||||
return [
|
||||
|
@ -146,4 +141,9 @@ export default class EditCategorySettings extends buildCategoryPanel(
|
|||
let seconds = minutes ? minutes * 60 : null;
|
||||
this.set("category.default_slow_mode_seconds", seconds);
|
||||
}
|
||||
|
||||
@action
|
||||
onCategoryModeratingGroupsChange(groupIds) {
|
||||
this.set("category.moderating_group_ids", groupIds);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -761,7 +761,7 @@ export default class Category extends RestModel {
|
|||
"navigate_to_first_post_after_read"
|
||||
),
|
||||
search_priority: this.search_priority,
|
||||
reviewable_by_group_name: this.reviewable_by_group_name,
|
||||
moderating_group_ids: this.moderating_group_ids,
|
||||
read_only_banner: this.read_only_banner,
|
||||
default_list_filter: this.default_list_filter,
|
||||
}),
|
||||
|
|
|
@ -751,8 +751,8 @@ export default class Topic extends RestModel {
|
|||
if (
|
||||
opts.force_destroy ||
|
||||
(!deleted_by.staff &&
|
||||
!deleted_by.groups.some(
|
||||
(group) => group.name === this.category?.reviewable_by_group_name
|
||||
!deleted_by.groups.some((group) =>
|
||||
this.category?.moderating_group_ids?.includes(group.id)
|
||||
) &&
|
||||
!deleted_by.can_delete_all_posts_and_topics)
|
||||
) {
|
||||
|
|
|
@ -578,10 +578,9 @@ class CategoriesController < ApplicationController
|
|||
]
|
||||
end
|
||||
|
||||
conditional_param_keys = []
|
||||
if SiteSetting.enable_category_group_moderation?
|
||||
params[:reviewable_by_group_id] = Group.where(
|
||||
name: params[:reviewable_by_group_name],
|
||||
).pick(:id) if params[:reviewable_by_group_name]
|
||||
conditional_param_keys << { moderating_group_ids: [] }
|
||||
end
|
||||
|
||||
result =
|
||||
|
@ -621,7 +620,7 @@ class CategoriesController < ApplicationController
|
|||
:allow_global_tags,
|
||||
:read_only_banner,
|
||||
:default_list_filter,
|
||||
:reviewable_by_group_id,
|
||||
*conditional_param_keys,
|
||||
category_setting_attributes: %i[
|
||||
auto_bump_cooldown_days
|
||||
num_auto_bump_daily
|
||||
|
|
|
@ -36,9 +36,8 @@ class ReviewableClaimedTopicsController < ApplicationController
|
|||
def notify_users(topic, claimed_by)
|
||||
group_ids = Set.new([Group::AUTO_GROUPS[:staff]])
|
||||
|
||||
if SiteSetting.enable_category_group_moderation? &&
|
||||
group_id = topic.category&.reviewable_by_group_id.presence
|
||||
group_ids.add(group_id)
|
||||
if SiteSetting.enable_category_group_moderation? && topic.category
|
||||
group_ids.merge(topic.category.moderating_group_ids)
|
||||
end
|
||||
|
||||
if claimed_by.present?
|
||||
|
|
|
@ -20,23 +20,18 @@ class Jobs::NotifyReviewable < ::Jobs::Base
|
|||
|
||||
all_updates[:admins][r.id] = payload
|
||||
all_updates[:moderators][r.id] = payload if r.reviewable_by_moderator?
|
||||
all_updates[r.reviewable_by_group_id][r.id] = payload if r.reviewable_by_group_id
|
||||
|
||||
if SiteSetting.enable_category_group_moderation? && r.category.present?
|
||||
r
|
||||
.category
|
||||
.moderating_groups
|
||||
.pluck(:id)
|
||||
.each { |group_id| all_updates[group_id][r.id] = payload }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
DistributedMutex.synchronize("notify_reviewable_job", validity: 120) do
|
||||
counts = Hash.new(0)
|
||||
Reviewable
|
||||
.default_visible
|
||||
.pending
|
||||
.group(:reviewable_by_moderator, :reviewable_by_group_id)
|
||||
.pluck(:reviewable_by_moderator, :reviewable_by_group_id, "count(*)")
|
||||
.each do |reviewable_by_moderator, reviewable_by_group_id, count|
|
||||
counts[:admins] += count
|
||||
counts[:moderators] += count if reviewable_by_moderator
|
||||
counts[reviewable_by_group_id] += count if reviewable_by_group_id
|
||||
end
|
||||
|
||||
notify_users(User.real.admins, all_updates[:admins])
|
||||
|
||||
if reviewable.reviewable_by_moderator?
|
||||
|
@ -46,16 +41,21 @@ class Jobs::NotifyReviewable < ::Jobs::Base
|
|||
)
|
||||
end
|
||||
|
||||
if SiteSetting.enable_category_group_moderation? && (group = reviewable.reviewable_by_group)
|
||||
users = group.users.includes(:group_users).where("users.id NOT IN (?)", @contacted)
|
||||
if SiteSetting.enable_category_group_moderation? && reviewable.category.present?
|
||||
users =
|
||||
User
|
||||
.includes(:group_users)
|
||||
.joins(:group_users)
|
||||
.joins(
|
||||
"INNER JOIN category_moderation_groups ON category_moderation_groups.group_id = group_users.group_id",
|
||||
)
|
||||
.where("category_moderation_groups.category_id": reviewable.category.id)
|
||||
.where("users.id NOT IN (?)", @contacted)
|
||||
.distinct
|
||||
|
||||
users.find_each do |user|
|
||||
count = 0
|
||||
updates = {}
|
||||
user.group_users.each do |gu|
|
||||
updates.merge!(all_updates[gu.group_id])
|
||||
count += counts[gu.group_id]
|
||||
end
|
||||
user.group_users.each { |gu| updates.merge!(all_updates[gu.group_id]) }
|
||||
|
||||
notify_user(user, updates)
|
||||
end
|
||||
|
|
|
@ -88,7 +88,7 @@ class About
|
|||
allowed_cats = Guardian.new(@user).allowed_category_ids
|
||||
return [] if allowed_cats.blank?
|
||||
|
||||
cats_with_mods = Category.where.not(reviewable_by_group_id: nil).pluck(:id)
|
||||
cats_with_mods = Category.joins(:category_moderation_groups).distinct.pluck(:id)
|
||||
|
||||
category_ids = cats_with_mods & allowed_cats
|
||||
return [] if category_ids.blank?
|
||||
|
@ -96,15 +96,32 @@ class About
|
|||
per_cat_limit = category_mods_limit / category_ids.size
|
||||
per_cat_limit = 1 if per_cat_limit < 1
|
||||
|
||||
results = DB.query(<<~SQL, category_ids: category_ids)
|
||||
SELECT c.id category_id
|
||||
, (ARRAY_AGG(u.id ORDER BY u.last_seen_at DESC))[:#{per_cat_limit}] user_ids
|
||||
FROM categories c
|
||||
JOIN group_users gu ON gu.group_id = c.reviewable_by_group_id
|
||||
JOIN users u ON u.id = gu.user_id
|
||||
WHERE c.id IN (:category_ids)
|
||||
GROUP BY c.id
|
||||
ORDER BY c.position
|
||||
results = DB.query(<<~SQL, category_ids:)
|
||||
WITH moderator_users AS (
|
||||
SELECT
|
||||
cmg.category_id AS category_id,
|
||||
u.id AS user_id,
|
||||
u.last_seen_at,
|
||||
ROW_NUMBER() OVER (PARTITION BY cmg.category_id, u.id ORDER BY u.last_seen_at DESC) as rn
|
||||
FROM category_moderation_groups cmg
|
||||
INNER JOIN group_users gu
|
||||
ON cmg.group_id = gu.group_id
|
||||
INNER JOIN users u
|
||||
ON gu.user_id = u.id
|
||||
WHERE cmg.category_id IN (:category_ids)
|
||||
)
|
||||
SELECT id AS category_id, user_ids
|
||||
FROM categories
|
||||
INNER JOIN (
|
||||
SELECT
|
||||
category_id,
|
||||
(ARRAY_AGG(user_id ORDER BY last_seen_at DESC))[:#{per_cat_limit}] AS user_ids
|
||||
FROM moderator_users
|
||||
WHERE rn = 1
|
||||
GROUP BY category_id
|
||||
) X
|
||||
ON X.category_id = id
|
||||
ORDER BY position
|
||||
SQL
|
||||
|
||||
cats = Category.where(id: results.map(&:category_id)).index_by(&:id)
|
||||
|
|
|
@ -7,6 +7,7 @@ class Category < ActiveRecord::Base
|
|||
:suppress_from_latest, # TODO: Remove when 20240212034010_drop_deprecated_columns has been promoted to pre-deploy
|
||||
:required_tag_group_id, # TODO: Remove when 20240212034010_drop_deprecated_columns has been promoted to pre-deploy
|
||||
:min_tags_from_required_group, # TODO: Remove when 20240212034010_drop_deprecated_columns has been promoted to pre-deploy
|
||||
:reviewable_by_group_id,
|
||||
]
|
||||
|
||||
include Searchable
|
||||
|
@ -37,7 +38,9 @@ class Category < ActiveRecord::Base
|
|||
has_many :featured_topics, through: :category_featured_topics, source: :topic
|
||||
|
||||
has_many :category_groups, dependent: :destroy
|
||||
has_many :category_moderation_groups, dependent: :destroy
|
||||
has_many :groups, through: :category_groups
|
||||
has_many :moderating_groups, through: :category_moderation_groups, source: :group
|
||||
has_many :topic_timers, dependent: :destroy
|
||||
has_many :upload_references, as: :target, dependent: :destroy
|
||||
|
||||
|
@ -110,7 +113,6 @@ class Category < ActiveRecord::Base
|
|||
after_save :reset_topic_ids_cache
|
||||
after_save :clear_subcategory_ids
|
||||
after_save :clear_url_cache
|
||||
after_save :update_reviewables
|
||||
after_save :publish_discourse_stylesheet
|
||||
after_save :publish_category
|
||||
|
||||
|
@ -163,8 +165,6 @@ class Category < ActiveRecord::Base
|
|||
has_many :category_form_templates, dependent: :destroy
|
||||
has_many :form_templates, through: :category_form_templates
|
||||
|
||||
belongs_to :reviewable_by_group, class_name: "Group"
|
||||
|
||||
scope :latest, -> { order("topic_count DESC") }
|
||||
|
||||
scope :secured,
|
||||
|
@ -1113,10 +1113,8 @@ class Category < ActiveRecord::Base
|
|||
)
|
||||
end
|
||||
|
||||
def update_reviewables
|
||||
if should_update_reviewables?
|
||||
Reviewable.where(category_id: id).update_all(reviewable_by_group_id: reviewable_by_group_id)
|
||||
end
|
||||
def moderating_group_ids
|
||||
category_moderation_groups.pluck(:group_id)
|
||||
end
|
||||
|
||||
def self.find_by_slug_path(slug_path)
|
||||
|
@ -1278,10 +1276,6 @@ class Category < ActiveRecord::Base
|
|||
self.build_category_setting if self.category_setting.blank?
|
||||
end
|
||||
|
||||
def should_update_reviewables?
|
||||
SiteSetting.enable_category_group_moderation? && saved_change_to_reviewable_by_group_id?
|
||||
end
|
||||
|
||||
def check_permissions_compatibility(parent_permissions, child_permissions)
|
||||
parent_groups = parent_permissions.map(&:first)
|
||||
|
||||
|
@ -1381,7 +1375,6 @@ end
|
|||
# navigate_to_first_post_after_read :boolean default(FALSE), not null
|
||||
# search_priority :integer default(0)
|
||||
# allow_global_tags :boolean default(FALSE), not null
|
||||
# reviewable_by_group_id :integer
|
||||
# read_only_banner :string
|
||||
# default_list_filter :string(20) default("all")
|
||||
# allow_unlimited_owner_edits_on_first_post :boolean default(FALSE), not null
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CategoryModerationGroup < ActiveRecord::Base
|
||||
belongs_to :category
|
||||
belongs_to :group
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: category_moderation_groups
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# category_id :integer
|
||||
# group_id :integer
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_category_moderation_groups_on_category_id_and_group_id (category_id,group_id) UNIQUE
|
||||
#
|
|
@ -16,6 +16,7 @@ class Group < ActiveRecord::Base
|
|||
self.preloaded_custom_field_names = Set.new
|
||||
|
||||
has_many :category_groups, dependent: :destroy
|
||||
has_many :category_moderation_groups, dependent: :destroy
|
||||
has_many :group_users, dependent: :destroy
|
||||
has_many :group_requests, dependent: :destroy
|
||||
has_many :group_mentions, dependent: :destroy
|
||||
|
@ -24,15 +25,11 @@ class Group < ActiveRecord::Base
|
|||
has_many :group_archived_messages, dependent: :destroy
|
||||
|
||||
has_many :categories, through: :category_groups
|
||||
has_many :moderation_categories, through: :category_moderation_groups, source: :category
|
||||
has_many :users, through: :group_users
|
||||
has_many :human_users, -> { human_users }, through: :group_users, source: :user
|
||||
has_many :requesters, through: :group_requests, source: :user
|
||||
has_many :group_histories, dependent: :destroy
|
||||
has_many :category_reviews,
|
||||
class_name: "Category",
|
||||
foreign_key: :reviewable_by_group_id,
|
||||
dependent: :nullify
|
||||
has_many :reviewables, foreign_key: :reviewable_by_group_id, dependent: :nullify
|
||||
has_many :group_category_notification_defaults, dependent: :destroy
|
||||
has_many :group_tag_notification_defaults, dependent: :destroy
|
||||
has_many :associated_groups, through: :group_associated_groups, dependent: :destroy
|
||||
|
@ -81,10 +78,6 @@ class Group < ActiveRecord::Base
|
|||
Discourse.cache.delete("group_imap_mailboxes_#{self.id}")
|
||||
end
|
||||
|
||||
def remove_review_groups
|
||||
Category.where(review_group_id: self.id).update_all(review_group_id: nil)
|
||||
end
|
||||
|
||||
validate :name_format_validator
|
||||
validates :name, presence: true
|
||||
validate :automatic_membership_email_domains_format_validator
|
||||
|
|
|
@ -7,6 +7,8 @@ class Reviewable < ActiveRecord::Base
|
|||
ReviewableUser: BasicReviewableUserSerializer,
|
||||
}
|
||||
|
||||
self.ignored_columns = [:reviewable_by_group_id]
|
||||
|
||||
class UpdateConflict < StandardError
|
||||
end
|
||||
|
||||
|
@ -17,13 +19,11 @@ class Reviewable < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
before_save :apply_review_group
|
||||
attr_accessor :created_new
|
||||
validates_presence_of :type, :status, :created_by_id
|
||||
belongs_to :target, polymorphic: true
|
||||
belongs_to :created_by, class_name: "User"
|
||||
belongs_to :target_created_by, class_name: "User"
|
||||
belongs_to :reviewable_by_group, class_name: "Group"
|
||||
|
||||
# Optional, for filtering
|
||||
belongs_to :topic
|
||||
|
@ -264,15 +264,6 @@ class Reviewable < ActiveRecord::Base
|
|||
)
|
||||
end
|
||||
|
||||
def apply_review_group
|
||||
unless SiteSetting.enable_category_group_moderation? && category.present? &&
|
||||
category.reviewable_by_group_id
|
||||
return
|
||||
end
|
||||
|
||||
self.reviewable_by_group_id = category.reviewable_by_group_id
|
||||
end
|
||||
|
||||
def actions_for(guardian, args = nil)
|
||||
args ||= {}
|
||||
|
||||
|
@ -408,14 +399,17 @@ class Reviewable < ActiveRecord::Base
|
|||
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))",
|
||||
staff: user.staff?,
|
||||
group_ids: group_ids,
|
||||
).where(
|
||||
"reviewables.category_id IS NULL OR reviewables.category_id IN (?)",
|
||||
Guardian.new(user).allowed_category_ids,
|
||||
)
|
||||
result
|
||||
.left_joins(category: :category_moderation_groups)
|
||||
.where(
|
||||
"(reviewables.reviewable_by_moderator AND :moderator) OR (category_moderation_groups.group_id IN (:group_ids))",
|
||||
moderator: user.moderator?,
|
||||
group_ids: group_ids,
|
||||
)
|
||||
.where(
|
||||
"reviewables.category_id IS NULL OR reviewables.category_id IN (?)",
|
||||
Guardian.new(user).allowed_category_ids,
|
||||
)
|
||||
end
|
||||
|
||||
def self.pending_count(user)
|
||||
|
@ -768,7 +762,6 @@ end
|
|||
# status :integer default("pending"), not null
|
||||
# created_by_id :integer not null
|
||||
# reviewable_by_moderator :boolean default(FALSE), not null
|
||||
# reviewable_by_group_id :integer
|
||||
# category_id :integer
|
||||
# topic_id :integer
|
||||
# score :float default(0.0), not null
|
||||
|
|
|
@ -337,9 +337,16 @@ class ReviewableFlaggedPost < Reviewable
|
|||
|
||||
user_ids = User.staff.pluck(:id)
|
||||
|
||||
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))
|
||||
if SiteSetting.enable_category_group_moderation? && topic.category
|
||||
user_ids.concat(
|
||||
GroupUser
|
||||
.joins(
|
||||
"INNER JOIN category_moderation_groups ON category_moderation_groups.group_id = group_users.group_id",
|
||||
)
|
||||
.where("category_moderation_groups.category_id": topic.category.id)
|
||||
.distinct
|
||||
.pluck(:user_id),
|
||||
)
|
||||
user_ids.uniq!
|
||||
end
|
||||
|
||||
|
@ -388,7 +395,6 @@ end
|
|||
# status :integer default("pending"), not null
|
||||
# created_by_id :integer not null
|
||||
# reviewable_by_moderator :boolean default(FALSE), not null
|
||||
# reviewable_by_group_id :integer
|
||||
# category_id :integer
|
||||
# topic_id :integer
|
||||
# score :float default(0.0), not null
|
||||
|
|
|
@ -141,7 +141,6 @@ end
|
|||
# status :integer default("pending"), not null
|
||||
# created_by_id :integer not null
|
||||
# reviewable_by_moderator :boolean default(FALSE), not null
|
||||
# reviewable_by_group_id :integer
|
||||
# category_id :integer
|
||||
# topic_id :integer
|
||||
# score :float default(0.0), not null
|
||||
|
|
|
@ -241,7 +241,6 @@ end
|
|||
# status :integer default("pending"), not null
|
||||
# created_by_id :integer not null
|
||||
# reviewable_by_moderator :boolean default(FALSE), not null
|
||||
# reviewable_by_group_id :integer
|
||||
# category_id :integer
|
||||
# topic_id :integer
|
||||
# score :float default(0.0), not null
|
||||
|
|
|
@ -105,7 +105,6 @@ end
|
|||
# status :integer default("pending"), not null
|
||||
# created_by_id :integer not null
|
||||
# reviewable_by_moderator :boolean default(FALSE), not null
|
||||
# reviewable_by_group_id :integer
|
||||
# category_id :integer
|
||||
# topic_id :integer
|
||||
# score :float default(0.0), not null
|
||||
|
|
|
@ -26,17 +26,13 @@ class CategorySerializer < SiteCategorySerializer
|
|||
:custom_fields,
|
||||
:topic_featured_link_allowed,
|
||||
:search_priority,
|
||||
:reviewable_by_group_name,
|
||||
:moderating_group_ids,
|
||||
:default_slow_mode_seconds
|
||||
|
||||
has_one :category_setting, serializer: CategorySettingSerializer, embed: :objects
|
||||
|
||||
def reviewable_by_group_name
|
||||
object.reviewable_by_group.name
|
||||
end
|
||||
|
||||
def include_reviewable_by_group_name?
|
||||
SiteSetting.enable_category_group_moderation? && object.reviewable_by_group_id.present?
|
||||
def include_moderating_group_ids?
|
||||
SiteSetting.enable_category_group_moderation?
|
||||
end
|
||||
|
||||
def include_category_setting?
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreateCategoryModerationGroups < ActiveRecord::Migration[7.1]
|
||||
def change
|
||||
create_table :category_moderation_groups do |t|
|
||||
t.integer :category_id
|
||||
t.integer :group_id
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
add_index :category_moderation_groups, %i[category_id group_id], unique: true
|
||||
|
||||
execute <<~SQL
|
||||
INSERT INTO category_moderation_groups (category_id, group_id, created_at, updated_at)
|
||||
SELECT id, reviewable_by_group_id, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP
|
||||
FROM categories
|
||||
WHERE reviewable_by_group_id IS NOT NULL
|
||||
SQL
|
||||
end
|
||||
end
|
|
@ -136,17 +136,14 @@ class Guardian
|
|||
return false if !category
|
||||
return false if !category_group_moderation_allowed?
|
||||
|
||||
reviewable_by_group_id = category.reviewable_by_group_id
|
||||
return false if reviewable_by_group_id.blank?
|
||||
@group_moderator_categories ||= {}
|
||||
|
||||
@category_group_moderator_groups ||= {}
|
||||
|
||||
if @category_group_moderator_groups.key?(reviewable_by_group_id)
|
||||
@category_group_moderator_groups[reviewable_by_group_id]
|
||||
if @group_moderator_categories.key?(category.id)
|
||||
@group_moderator_categories[category.id]
|
||||
else
|
||||
@category_group_moderator_groups[
|
||||
reviewable_by_group_id
|
||||
] = category_group_moderator_scope.exists?("categories.id": category.id)
|
||||
@group_moderator_categories[category.id] = category_group_moderator_scope.exists?(
|
||||
id: category.id,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -692,8 +689,9 @@ class Guardian
|
|||
end
|
||||
|
||||
def category_group_moderator_scope
|
||||
Category.joins(
|
||||
"INNER JOIN group_users ON group_users.group_id = categories.reviewable_by_group_id",
|
||||
).where("group_users.user_id = ?", user.id)
|
||||
Category
|
||||
.joins(:category_moderation_groups)
|
||||
.joins("INNER JOIN group_users ON group_users.group_id = category_moderation_groups.group_id")
|
||||
.where("group_users.user_id": user.id)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -171,8 +171,13 @@ module UserGuardian
|
|||
(
|
||||
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)
|
||||
.joins(
|
||||
"INNER JOIN category_moderation_groups ON category_moderation_groups.category_id = reviewables.category_id",
|
||||
)
|
||||
.where(
|
||||
category_id: allowed_category_ids,
|
||||
"category_moderation_groups.group_id": @user.group_users.pluck(:group_id),
|
||||
)
|
||||
.exists?
|
||||
)
|
||||
end
|
||||
|
|
|
@ -364,9 +364,13 @@ class PostActionCreator
|
|||
create_args[:subtype] = TopicSubtype.notify_moderators
|
||||
create_args[:target_group_names] = [Group[:moderators].name]
|
||||
|
||||
if SiteSetting.enable_category_group_moderation? &&
|
||||
@post.topic&.category&.reviewable_by_group_id?
|
||||
create_args[:target_group_names] << @post.topic.category.reviewable_by_group.name
|
||||
if SiteSetting.enable_category_group_moderation? && @post.topic&.category
|
||||
create_args[:target_group_names].push(
|
||||
*Group
|
||||
.joins(:category_moderation_groups)
|
||||
.where("category_moderation_groups.category_id": @post.topic.category.id)
|
||||
.pluck(:name),
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -535,16 +535,19 @@ class TopicView
|
|||
def category_group_moderator_user_ids
|
||||
@category_group_moderator_user_ids ||=
|
||||
begin
|
||||
if SiteSetting.enable_category_group_moderation? &&
|
||||
@topic.category&.reviewable_by_group.present?
|
||||
if SiteSetting.enable_category_group_moderation? && @topic.category.present?
|
||||
posts_user_ids = Set.new(@posts.map(&:user_id))
|
||||
Set.new(
|
||||
@topic
|
||||
.category
|
||||
.reviewable_by_group
|
||||
.group_users
|
||||
.where(user_id: posts_user_ids)
|
||||
.pluck("distinct user_id"),
|
||||
GroupUser
|
||||
.joins(
|
||||
"INNER JOIN category_moderation_groups ON category_moderation_groups.group_id = group_users.group_id",
|
||||
)
|
||||
.where(
|
||||
"category_moderation_groups.category_id": @topic.category.id,
|
||||
user_id: posts_user_ids,
|
||||
)
|
||||
.distinct
|
||||
.pluck(:user_id),
|
||||
)
|
||||
else
|
||||
Set.new
|
||||
|
|
|
@ -354,11 +354,11 @@ RSpec.describe Chat::GuardianExtensions do
|
|||
context "when enable_category_group_moderation is true" do
|
||||
before { SiteSetting.enable_category_group_moderation = true }
|
||||
|
||||
it "returns true if the regular user is part of the reviewable_by_group for the category" do
|
||||
it "returns true if the regular user is part of the reviewable groups for the category" do
|
||||
moderator = Fabricate(:user)
|
||||
mods = Fabricate(:group)
|
||||
mods.add(moderator)
|
||||
category.update!(reviewable_by_group: mods)
|
||||
Fabricate(:category_moderation_group, category:, group: mods)
|
||||
expect(Guardian.new(Fabricate(:admin)).can_moderate_chat?(channel.chatable)).to eq(true)
|
||||
expect(Guardian.new(moderator).can_moderate_chat?(channel.chatable)).to eq(true)
|
||||
end
|
||||
|
@ -443,7 +443,7 @@ RSpec.describe Chat::GuardianExtensions do
|
|||
moderator = Fabricate(:user)
|
||||
mods = Fabricate(:group)
|
||||
mods.add(moderator)
|
||||
chatable.update!(reviewable_by_group: mods)
|
||||
Fabricate(:category_moderation_group, category: chatable, group: mods)
|
||||
expect(Guardian.new(moderator).can_restore_chat?(message, chatable)).to eq(true)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -28,12 +28,14 @@ RSpec.describe "Move message to channel", type: :system do
|
|||
fab!(:group_1) { Fabricate(:group) }
|
||||
fab!(:channel_1) { Fabricate(:private_category_channel, group: group_1) }
|
||||
fab!(:message_1) { Fabricate(:chat_message, chat_channel: channel_1, user: current_user) }
|
||||
fab!(:category_moderation_group) do
|
||||
Fabricate(:category_moderation_group, category: channel_1.category, group: group_1)
|
||||
end
|
||||
|
||||
before do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
group_1.add(current_user)
|
||||
channel_1.add(current_user)
|
||||
channel_1.chatable.update!(reviewable_by_group_id: group_1.id)
|
||||
end
|
||||
|
||||
it "is available" do
|
||||
|
|
|
@ -59,9 +59,8 @@ after_initialize do
|
|||
config.allowed_group_ids += SiteSetting.edit_all_post_groups.split("|").map(&:to_i)
|
||||
end
|
||||
|
||||
if SiteSetting.enable_category_group_moderation? &&
|
||||
group_id = topic.category&.reviewable_by_group_id
|
||||
config.allowed_group_ids << group_id
|
||||
if SiteSetting.enable_category_group_moderation? && topic.category
|
||||
config.allowed_group_ids.push(*topic.category.moderating_groups.pluck(:id))
|
||||
end
|
||||
|
||||
config
|
||||
|
|
|
@ -73,7 +73,7 @@ RSpec.describe "discourse-presence" do
|
|||
expect(c.config.allowed_group_ids).to contain_exactly(Group::AUTO_GROUPS[:staff])
|
||||
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
category.update(reviewable_by_group_id: group.id)
|
||||
Fabricate(:category_moderation_group, category:, group:)
|
||||
|
||||
c = PresenceChannel.new("/discourse-presence/edit/#{p.id}", use_cache: false)
|
||||
expect(c.config.allowed_group_ids).to contain_exactly(Group::AUTO_GROUPS[:staff], group.id)
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Fabricator(:category_moderation_group) do
|
||||
category
|
||||
group
|
||||
end
|
|
@ -54,8 +54,9 @@ RSpec.describe Jobs::NotifyReviewable do
|
|||
moderator.update!(last_seen_reviewable_id: moderator_reviewable.id)
|
||||
|
||||
# Content for a group
|
||||
group_reviewable =
|
||||
Fabricate(:reviewable, reviewable_by_moderator: true, reviewable_by_group: group)
|
||||
category = Fabricate(:category)
|
||||
Fabricate(:category_moderation_group, category:, group:)
|
||||
group_reviewable = Fabricate(:reviewable, reviewable_by_moderator: true, category:)
|
||||
|
||||
messages =
|
||||
MessageBus.track_publish { described_class.new.execute(reviewable_id: group_reviewable.id) }
|
||||
|
@ -85,7 +86,9 @@ RSpec.describe Jobs::NotifyReviewable do
|
|||
SiteSetting.enable_category_group_moderation = false
|
||||
|
||||
GroupUser.create!(group_id: group.id, user_id: moderator.id)
|
||||
reviewable = Fabricate(:reviewable, reviewable_by_moderator: true, reviewable_by_group: group)
|
||||
category = Fabricate(:category)
|
||||
Fabricate(:category_moderation_group, category:, group:)
|
||||
reviewable = Fabricate(:reviewable, reviewable_by_moderator: true, category:)
|
||||
|
||||
messages =
|
||||
MessageBus.track_publish("/reviewable_counts") do
|
||||
|
|
|
@ -5,20 +5,16 @@ RSpec.describe Jobs::RefreshUsersReviewableCounts do
|
|||
fab!(:moderator)
|
||||
fab!(:user)
|
||||
|
||||
fab!(:group)
|
||||
fab!(:topic)
|
||||
fab!(:reviewable1) do
|
||||
Fabricate(:reviewable, reviewable_by_group: group, reviewable_by_moderator: true, topic: topic)
|
||||
end
|
||||
fab!(:group) { Fabricate(:group, users: [user]) }
|
||||
fab!(:category)
|
||||
fab!(:topic) { Fabricate(:topic, category:) }
|
||||
fab!(:category_moderation_group) { Fabricate(:category_moderation_group, category:, group:) }
|
||||
fab!(:reviewable1) { Fabricate(:reviewable, reviewable_by_moderator: true, topic:, category:) }
|
||||
|
||||
fab!(:reviewable2) { Fabricate(:reviewable, reviewable_by_moderator: false) }
|
||||
fab!(:reviewable3) { Fabricate(:reviewable, reviewable_by_moderator: true) }
|
||||
|
||||
before do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
group.add(user)
|
||||
topic.category.update!(reviewable_by_group: group)
|
||||
end
|
||||
before { SiteSetting.enable_category_group_moderation = true }
|
||||
|
||||
describe "#execute" do
|
||||
it "publishes reviewable counts for the members of the specified groups" do
|
||||
|
|
|
@ -83,7 +83,7 @@ RSpec.describe TopicGuardian do
|
|||
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)
|
||||
category.update!(reviewable_by_group_id: group.id)
|
||||
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)
|
||||
|
@ -110,7 +110,7 @@ RSpec.describe TopicGuardian do
|
|||
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)
|
||||
category.update!(reviewable_by_group_id: group.id)
|
||||
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)
|
||||
|
@ -255,7 +255,7 @@ RSpec.describe TopicGuardian do
|
|||
it "returns the topic ids for topics which are deleted but user is a category moderator of" do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
|
||||
category.update!(reviewable_by_group_id: group.id)
|
||||
Fabricate(:category_moderation_group, category:, group:)
|
||||
group.add(user)
|
||||
topic.update!(category: category)
|
||||
topic.trash!(admin)
|
||||
|
|
|
@ -415,8 +415,10 @@ RSpec.describe UserGuardian do
|
|||
group.add(user)
|
||||
guardian = Guardian.new(user)
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
category = Fabricate(:category)
|
||||
Fabricate(:category_moderation_group, category:, group:)
|
||||
|
||||
Fabricate(:reviewable_flagged_post, reviewable_by_group: group, category: nil)
|
||||
Fabricate(:reviewable_flagged_post, category:)
|
||||
|
||||
expect(guardian.can_see_review_queue?).to eq(true)
|
||||
end
|
||||
|
@ -426,8 +428,10 @@ RSpec.describe UserGuardian do
|
|||
group.add(user)
|
||||
guardian = Guardian.new(user)
|
||||
SiteSetting.enable_category_group_moderation = false
|
||||
category = Fabricate(:category)
|
||||
Fabricate(:category_moderation_group, category:, group:)
|
||||
|
||||
Fabricate(:reviewable_flagged_post, reviewable_by_group: group, category: nil)
|
||||
Fabricate(:reviewable_flagged_post, category:)
|
||||
|
||||
expect(guardian.can_see_review_queue?).to eq(false)
|
||||
end
|
||||
|
@ -438,8 +442,9 @@ RSpec.describe UserGuardian do
|
|||
guardian = Guardian.new(user)
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
category = Fabricate(:category, read_restricted: true)
|
||||
Fabricate(:category_moderation_group, category:, group:)
|
||||
|
||||
Fabricate(:reviewable_flagged_post, reviewable_by_group: group, category: category)
|
||||
Fabricate(:reviewable_flagged_post, category: category)
|
||||
|
||||
expect(guardian.can_see_review_queue?).to eq(false)
|
||||
end
|
||||
|
|
|
@ -1072,7 +1072,8 @@ RSpec.describe Guardian do
|
|||
|
||||
expect(Guardian.new(user_gm).can_see?(topic)).to be_falsey
|
||||
|
||||
topic.category.update!(reviewable_by_group_id: group.id, topic_id: post.topic.id)
|
||||
topic.category.update!(topic_id: post.topic.id)
|
||||
Fabricate(:category_moderation_group, category: topic.category, group:)
|
||||
|
||||
expect(Guardian.new(user_gm).can_see?(topic)).to be_truthy
|
||||
end
|
||||
|
@ -1130,7 +1131,8 @@ RSpec.describe Guardian do
|
|||
|
||||
expect(Guardian.new(user_gm).can_see?(post)).to be_falsey
|
||||
|
||||
post.topic.category.update!(reviewable_by_group_id: group.id, topic_id: post.topic.id)
|
||||
post.topic.category.update!(topic_id: post.topic.id)
|
||||
Fabricate(:category_moderation_group, category: post.topic.category, group:)
|
||||
expect(Guardian.new(user_gm).can_see?(post)).to be_truthy
|
||||
end
|
||||
|
||||
|
@ -1504,7 +1506,7 @@ RSpec.describe Guardian do
|
|||
end
|
||||
|
||||
it "returns true if user is a member of the appropriate group" do
|
||||
topic.category.update!(reviewable_by_group_id: group_user.group.id)
|
||||
Fabricate(:category_moderation_group, category: topic.category, group: group_user.group)
|
||||
|
||||
expect(Guardian.new(group_user.user).can_recover_topic?(topic)).to be_truthy
|
||||
end
|
||||
|
@ -1787,7 +1789,7 @@ RSpec.describe Guardian do
|
|||
before do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
GroupUser.create!(group_id: group.id, user_id: cat_mod_user.id)
|
||||
post.topic.category.update!(reviewable_by_group_id: group.id)
|
||||
Fabricate(:category_moderation_group, category: post.topic.category, group:)
|
||||
end
|
||||
|
||||
it "returns true as a category group moderator user" do
|
||||
|
@ -2161,7 +2163,7 @@ RSpec.describe Guardian do
|
|||
it "returns true for a group member with reviewable status" do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
GroupUser.create!(group_id: group.id, user_id: user.id)
|
||||
topic.category.update!(reviewable_by_group_id: group.id)
|
||||
Fabricate(:category_moderation_group, category: topic.category, group:)
|
||||
expect(Guardian.new(user).can_review_topic?(topic)).to eq(true)
|
||||
end
|
||||
end
|
||||
|
@ -2182,7 +2184,7 @@ RSpec.describe Guardian do
|
|||
it "returns true for a group member with reviewable status" do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
GroupUser.create!(group_id: group.id, user_id: user.id)
|
||||
topic.category.update!(reviewable_by_group_id: group.id)
|
||||
Fabricate(:category_moderation_group, category: topic.category, group:)
|
||||
expect(Guardian.new(user).can_close_topic?(topic)).to eq(true)
|
||||
end
|
||||
end
|
||||
|
@ -2203,7 +2205,7 @@ RSpec.describe Guardian do
|
|||
it "returns true for a group member with reviewable status" do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
GroupUser.create!(group_id: group.id, user_id: user.id)
|
||||
topic.category.update!(reviewable_by_group_id: group.id)
|
||||
Fabricate(:category_moderation_group, category: topic.category, group:)
|
||||
expect(Guardian.new(user).can_archive_topic?(topic)).to eq(true)
|
||||
end
|
||||
end
|
||||
|
@ -2224,7 +2226,7 @@ RSpec.describe Guardian do
|
|||
it "returns true for a group member with reviewable status" do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
GroupUser.create!(group_id: group.id, user_id: user.id)
|
||||
topic.category.update!(reviewable_by_group_id: group.id)
|
||||
Fabricate(:category_moderation_group, category: topic.category, group:)
|
||||
expect(Guardian.new(user).can_edit_staff_notes?(topic)).to eq(true)
|
||||
end
|
||||
end
|
||||
|
@ -2348,7 +2350,7 @@ RSpec.describe Guardian do
|
|||
end
|
||||
|
||||
it "returns true if user is a member of the appropriate group" do
|
||||
topic.category.update!(reviewable_by_group_id: group_user.group.id)
|
||||
Fabricate(:category_moderation_group, category: topic.category, group: group_user.group)
|
||||
|
||||
expect(Guardian.new(group_user.user).can_delete?(topic)).to be_truthy
|
||||
end
|
||||
|
@ -2411,8 +2413,9 @@ RSpec.describe Guardian do
|
|||
it "returns true for category moderators" do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
GroupUser.create(group: group, user: user)
|
||||
category = Fabricate(:category, reviewable_by_group_id: group.id)
|
||||
category = Fabricate(:category)
|
||||
post.topic.update!(category: category)
|
||||
Fabricate(:category_moderation_group, category:, group:)
|
||||
|
||||
expect(Guardian.new(user).can_delete?(post)).to eq(true)
|
||||
end
|
||||
|
@ -4399,7 +4402,7 @@ RSpec.describe Guardian do
|
|||
|
||||
it "should correctly detect category moderation" do
|
||||
group.add(user)
|
||||
category.update!(reviewable_by_group_id: group.id)
|
||||
Fabricate(:category_moderation_group, category:, group:)
|
||||
guardian = Guardian.new(user)
|
||||
|
||||
# implementation detail, ensure memoization is good (hence testing twice)
|
||||
|
|
|
@ -490,9 +490,12 @@ RSpec.describe NewPostManager do
|
|||
end
|
||||
|
||||
context "when posting in the category requires approval" do
|
||||
let!(:user) { Fabricate(:user, refresh_auto_groups: true) }
|
||||
let!(:review_group) { Fabricate(:group) }
|
||||
let!(:category) { Fabricate(:category, reviewable_by_group_id: review_group.id) }
|
||||
fab!(:user) { Fabricate(:user, refresh_auto_groups: true) }
|
||||
fab!(:review_group) { Fabricate(:group) }
|
||||
fab!(:category)
|
||||
fab!(:category_moderation_group) do
|
||||
Fabricate(:category_moderation_group, category:, group: review_group)
|
||||
end
|
||||
|
||||
context "when new topics require approval" do
|
||||
before do
|
||||
|
|
|
@ -306,7 +306,8 @@ RSpec.describe PostDestroyer do
|
|||
before do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
review_group = Fabricate(:group)
|
||||
review_category = Fabricate(:category, reviewable_by_group_id: review_group.id)
|
||||
review_category = Fabricate(:category)
|
||||
Fabricate(:category_moderation_group, category: review_category, group: review_group)
|
||||
@reply.topic.update!(category: review_category)
|
||||
review_group.users << review_user
|
||||
end
|
||||
|
@ -552,7 +553,8 @@ RSpec.describe PostDestroyer do
|
|||
before do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
review_group = Fabricate(:group)
|
||||
review_category = Fabricate(:category, reviewable_by_group_id: review_group.id)
|
||||
review_category = Fabricate(:category)
|
||||
Fabricate(:category_moderation_group, category: review_category, group: review_group)
|
||||
post.topic.update!(category: review_category)
|
||||
review_group.users << review_user
|
||||
end
|
||||
|
|
|
@ -1091,8 +1091,9 @@ RSpec.describe PostRevisor do
|
|||
|
||||
context "when logging group moderator edits" do
|
||||
fab!(:group_user)
|
||||
fab!(:category) do
|
||||
Fabricate(:category, reviewable_by_group_id: group_user.group.id, topic: topic)
|
||||
fab!(:category) { Fabricate(:category, topic: topic) }
|
||||
fab!(:category_moderation_group) do
|
||||
Fabricate(:category_moderation_group, category:, group: group_user.group)
|
||||
end
|
||||
|
||||
before do
|
||||
|
|
|
@ -308,7 +308,8 @@ RSpec.describe TopicQuery do
|
|||
group_moderator = Fabricate(:user)
|
||||
group = Fabricate(:group)
|
||||
group.add(group_moderator)
|
||||
category = Fabricate(:category, reviewable_by_group: group)
|
||||
category = Fabricate(:category)
|
||||
Fabricate(:category_moderation_group, category:, group:)
|
||||
_topic = Fabricate(:topic, category: category, deleted_at: 1.year.ago)
|
||||
|
||||
expect(TopicQuery.new(admin, status: "deleted").list_latest.topics.size).to eq(1)
|
||||
|
|
|
@ -386,7 +386,8 @@ RSpec.describe PostValidator do
|
|||
SiteSetting.enable_category_group_moderation = true
|
||||
group = Fabricate(:group)
|
||||
GroupUser.create(group: group, user: user)
|
||||
category = Fabricate(:category, reviewable_by_group_id: group.id)
|
||||
category = Fabricate(:category)
|
||||
Fabricate(:category_moderation_group, category:, group:)
|
||||
topic.update!(category: category)
|
||||
|
||||
Post.create!(user: other_user, topic: topic, raw: "post number 1", post_number: 1)
|
||||
|
|
|
@ -67,31 +67,28 @@ RSpec.describe About do
|
|||
end
|
||||
|
||||
describe "#category_moderators" do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:public_cat_moderator) { Fabricate(:user, last_seen_at: 1.month.ago) }
|
||||
let(:private_cat_moderator) { Fabricate(:user, last_seen_at: 2.month.ago) }
|
||||
let(:common_moderator) { Fabricate(:user, last_seen_at: 3.month.ago) }
|
||||
let(:common_moderator_2) { Fabricate(:user, last_seen_at: 4.month.ago) }
|
||||
fab!(:user)
|
||||
fab!(:public_cat_moderator) { Fabricate(:user, last_seen_at: 1.month.ago) }
|
||||
fab!(:private_cat_moderator) { Fabricate(:user, last_seen_at: 2.month.ago) }
|
||||
fab!(:common_moderator) { Fabricate(:user, last_seen_at: 3.month.ago) }
|
||||
fab!(:common_moderator_2) { Fabricate(:user, last_seen_at: 4.month.ago) }
|
||||
|
||||
let(:public_group) do
|
||||
group = Fabricate(:public_group)
|
||||
group.add(public_cat_moderator)
|
||||
group.add(common_moderator)
|
||||
group.add(common_moderator_2)
|
||||
group
|
||||
fab!(:public_group) do
|
||||
Fabricate(:public_group, users: [public_cat_moderator, common_moderator, common_moderator_2])
|
||||
end
|
||||
|
||||
let(:private_group) do
|
||||
group = Fabricate(:group)
|
||||
group.add(private_cat_moderator)
|
||||
group.add(common_moderator)
|
||||
group.add(common_moderator_2)
|
||||
group
|
||||
fab!(:private_group) do
|
||||
Fabricate(:group, users: [private_cat_moderator, common_moderator, common_moderator_2])
|
||||
end
|
||||
|
||||
let!(:public_cat) { Fabricate(:category, reviewable_by_group: public_group) }
|
||||
let!(:private_cat) do
|
||||
Fabricate(:private_category, group: private_group, reviewable_by_group: private_group)
|
||||
fab!(:public_cat) { Fabricate(:category) }
|
||||
fab!(:public_category_moderation_group) do
|
||||
Fabricate(:category_moderation_group, category: public_cat, group: public_group)
|
||||
end
|
||||
|
||||
fab!(:private_cat) { Fabricate(:private_category, group: private_group) }
|
||||
fab!(:private_category_moderation_group) do
|
||||
Fabricate(:category_moderation_group, category: private_cat, group: private_group)
|
||||
end
|
||||
|
||||
it "lists moderators of the category that the current user can see" do
|
||||
|
@ -120,6 +117,19 @@ RSpec.describe About do
|
|||
expect(results.size).to eq(2)
|
||||
results.each { |res| expect(res.moderators.size).to eq(2) }
|
||||
end
|
||||
|
||||
it "doesn't list the same user twice as a category mod if the user is member of multiple groups" do
|
||||
Fabricate(:category_moderation_group, category: public_cat, group: private_group)
|
||||
|
||||
results = About.new(nil).category_moderators
|
||||
mods = results.find { |r| r.category.id == public_cat.id }.moderators
|
||||
expect(mods.map(&:id)).to contain_exactly(
|
||||
public_cat_moderator.id,
|
||||
common_moderator.id,
|
||||
common_moderator_2.id,
|
||||
private_cat_moderator.id,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#admins" do
|
||||
|
|
|
@ -82,51 +82,19 @@ RSpec.describe Category do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#review_group_id" do
|
||||
describe "#category_moderation_groups" do
|
||||
fab!(:group)
|
||||
fab!(:category) { Fabricate(:category_with_definition, reviewable_by_group: group) }
|
||||
fab!(:category) { Fabricate(:category_with_definition) }
|
||||
fab!(:topic) { Fabricate(:topic, category: category) }
|
||||
fab!(:post) { Fabricate(:post, topic: topic) }
|
||||
fab!(:category_moderation_group) { Fabricate(:category_moderation_group, category:, group:) }
|
||||
fab!(:user) { Fabricate(:user, refresh_auto_groups: true) }
|
||||
|
||||
it "will add the group to the reviewable" do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
reviewable = PostActionCreator.spam(user, post).reviewable
|
||||
expect(reviewable.reviewable_by_group_id).to eq(group.id)
|
||||
end
|
||||
|
||||
it "will add the group to the reviewable even if created manually" do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
reviewable =
|
||||
ReviewableFlaggedPost.create!(
|
||||
created_by: user,
|
||||
payload: {
|
||||
raw: "test raw",
|
||||
},
|
||||
category: category,
|
||||
)
|
||||
expect(reviewable.reviewable_by_group_id).to eq(group.id)
|
||||
end
|
||||
|
||||
it "will not add add the group to the reviewable" do
|
||||
SiteSetting.enable_category_group_moderation = false
|
||||
reviewable = PostActionCreator.spam(user, post).reviewable
|
||||
expect(reviewable.reviewable_by_group_id).to be_nil
|
||||
end
|
||||
|
||||
it "will nullify the group_id if destroyed" do
|
||||
it "is destroyed if the group is destroyed" do
|
||||
expect(category.category_moderation_groups).to contain_exactly(category_moderation_group)
|
||||
reviewable = PostActionCreator.spam(user, post).reviewable
|
||||
group.destroy
|
||||
expect(category.reload.reviewable_by_group).to be_blank
|
||||
expect(reviewable.reload.reviewable_by_group_id).to be_blank
|
||||
end
|
||||
|
||||
it "will remove the reviewable_by_group if the category is updated" do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
reviewable = PostActionCreator.spam(user, post).reviewable
|
||||
category.reviewable_by_group_id = nil
|
||||
category.save!
|
||||
expect(reviewable.reload.reviewable_by_group_id).to be_nil
|
||||
expect(category.reload.category_moderation_groups).to be_blank
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ RSpec.describe PostAction do
|
|||
before do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
group.update!(messageable_level: Group::ALIAS_LEVELS[:nobody])
|
||||
post.topic.category.update!(reviewable_by_group_id: group.id)
|
||||
Fabricate(:category_moderation_group, category: post.topic.category, group:)
|
||||
end
|
||||
|
||||
it "notifies via pm" do
|
||||
|
|
|
@ -131,7 +131,9 @@ RSpec.describe Reviewable, type: :model do
|
|||
it "works with the reviewable by group" do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
group = Fabricate(:group)
|
||||
reviewable.reviewable_by_group_id = group.id
|
||||
category = Fabricate(:category)
|
||||
Fabricate(:category_moderation_group, category:, group:)
|
||||
reviewable.category_id = category.id
|
||||
reviewable.save!
|
||||
|
||||
expect(Reviewable.list_for(user, status: :pending)).to be_empty
|
||||
|
@ -147,7 +149,9 @@ RSpec.describe Reviewable, type: :model do
|
|||
it "doesn't allow review by group when disabled" do
|
||||
SiteSetting.enable_category_group_moderation = false
|
||||
group = Fabricate(:group)
|
||||
reviewable.reviewable_by_group_id = group.id
|
||||
category = Fabricate(:category)
|
||||
Fabricate(:category_moderation_group, category:, group:)
|
||||
reviewable.category_id = category.id
|
||||
reviewable.save!
|
||||
|
||||
GroupUser.create!(group_id: group.id, user_id: user.id)
|
||||
|
@ -266,12 +270,12 @@ RSpec.describe Reviewable, type: :model do
|
|||
fab!(:admin)
|
||||
fab!(:moderator)
|
||||
fab!(:group)
|
||||
fab!(:category)
|
||||
fab!(:user) { Fabricate(:user, groups: [group]) }
|
||||
fab!(:admin_reviewable) { Fabricate(:reviewable, reviewable_by_moderator: false) }
|
||||
fab!(:mod_reviewable) { Fabricate(:reviewable, reviewable_by_moderator: true) }
|
||||
fab!(:group_reviewable) do
|
||||
Fabricate(:reviewable, reviewable_by_group: group, reviewable_by_moderator: false)
|
||||
end
|
||||
fab!(:category_moderation_group) { Fabricate(:category_moderation_group, category:, group:) }
|
||||
fab!(:group_reviewable) { Fabricate(:reviewable, reviewable_by_moderator: false, category:) }
|
||||
|
||||
context "for admins" do
|
||||
it "returns a list of pending reviewables that haven't been seen by the user" do
|
||||
|
@ -638,12 +642,12 @@ RSpec.describe Reviewable, type: :model do
|
|||
|
||||
describe ".unseen_reviewable_count" do
|
||||
fab!(:group)
|
||||
fab!(:category)
|
||||
fab!(:user)
|
||||
fab!(:admin_reviewable) { Fabricate(:reviewable, reviewable_by_moderator: false) }
|
||||
fab!(:mod_reviewable) { Fabricate(:reviewable, reviewable_by_moderator: true) }
|
||||
fab!(:group_reviewable) do
|
||||
Fabricate(:reviewable, reviewable_by_moderator: false, reviewable_by_group: group)
|
||||
end
|
||||
fab!(:category_moderation_group) { Fabricate(:category_moderation_group, category:, group:) }
|
||||
fab!(:group_reviewable) { Fabricate(:reviewable, reviewable_by_moderator: false, category:) }
|
||||
|
||||
it "doesn't include reviewables that can't be seen by the user" do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
|
|
|
@ -3407,8 +3407,9 @@ RSpec.describe User do
|
|||
user.update!(groups: [group])
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
|
||||
group_reviewable =
|
||||
Fabricate(:reviewable, reviewable_by_moderator: false, reviewable_by_group: group)
|
||||
category = Fabricate(:category)
|
||||
Fabricate(:category_moderation_group, category:, group:)
|
||||
group_reviewable = Fabricate(:reviewable, reviewable_by_moderator: false, category:)
|
||||
mod_reviewable = Fabricate(:reviewable, reviewable_by_moderator: true)
|
||||
admin_reviewable = Fabricate(:reviewable, reviewable_by_moderator: false)
|
||||
|
||||
|
|
|
@ -517,7 +517,7 @@ RSpec.describe CategoriesController do
|
|||
slug: "hello-cat",
|
||||
auto_close_hours: 72,
|
||||
search_priority: Searchable::PRIORITIES[:ignore],
|
||||
reviewable_by_group_name: group.name,
|
||||
moderating_group_ids: [group.id],
|
||||
permissions: {
|
||||
"everyone" => readonly,
|
||||
"staff" => create_post,
|
||||
|
@ -527,7 +527,7 @@ RSpec.describe CategoriesController do
|
|||
expect(response.status).to eq(200)
|
||||
cat_json = response.parsed_body["category"]
|
||||
expect(cat_json).to be_present
|
||||
expect(cat_json["reviewable_by_group_name"]).to eq(group.name)
|
||||
expect(cat_json["moderating_group_ids"]).to eq([group.id])
|
||||
expect(cat_json["name"]).to eq("hello")
|
||||
expect(cat_json["slug"]).to eq("hello-cat")
|
||||
expect(cat_json["color"]).to eq("ff0")
|
||||
|
@ -634,6 +634,10 @@ RSpec.describe CategoriesController do
|
|||
end
|
||||
|
||||
describe "#update" do
|
||||
fab!(:mod_group_1) { Fabricate(:group) }
|
||||
fab!(:mod_group_2) { Fabricate(:group) }
|
||||
fab!(:mod_group_3) { Fabricate(:group) }
|
||||
|
||||
before { Jobs.run_immediately! }
|
||||
|
||||
it "requires the user to be logged in" do
|
||||
|
@ -871,6 +875,47 @@ RSpec.describe CategoriesController do
|
|||
expect(category.custom_fields).to eq({ "field_1" => "hi" })
|
||||
expect(category.form_template_ids.count).to eq(0)
|
||||
end
|
||||
|
||||
it "doesn't set category moderation groups if the enable_category_group_moderation setting is false" do
|
||||
SiteSetting.enable_category_group_moderation = false
|
||||
|
||||
put "/categories/#{category.id}.json", params: { moderating_group_ids: [mod_group_1.id] }
|
||||
expect(response.status).to eq(200)
|
||||
expect(category.reload.moderating_groups).to be_blank
|
||||
end
|
||||
|
||||
it "sets category moderation groups if the enable_category_group_moderation setting is true" do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
|
||||
put "/categories/#{category.id}.json", params: { moderating_group_ids: [mod_group_1.id] }
|
||||
expect(response.status).to eq(200)
|
||||
expect(category.reload.moderating_groups).to contain_exactly(mod_group_1)
|
||||
end
|
||||
|
||||
it "removes category moderation groups and adds groups according to the moderating_group_ids param" do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
|
||||
category.update!(moderating_group_ids: [mod_group_2.id])
|
||||
expect(category.reload.moderating_groups).to contain_exactly(mod_group_2)
|
||||
|
||||
put "/categories/#{category.id}.json",
|
||||
params: {
|
||||
moderating_group_ids: [mod_group_1.id, mod_group_3.id],
|
||||
}
|
||||
expect(response.status).to eq(200)
|
||||
expect(category.reload.moderating_groups).to contain_exactly(mod_group_1, mod_group_3)
|
||||
end
|
||||
|
||||
it "can remove all category moderation groups" do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
|
||||
category.update!(moderating_group_ids: [mod_group_2.id, mod_group_1.id])
|
||||
expect(category.reload.moderating_groups).to contain_exactly(mod_group_2, mod_group_1)
|
||||
|
||||
put "/categories/#{category.id}.json", params: { moderating_group_ids: [] }
|
||||
expect(response.status).to eq(200)
|
||||
expect(category.reload.moderating_groups).to be_blank
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -59,7 +59,8 @@ RSpec.shared_examples "finding and showing post" do
|
|||
end
|
||||
|
||||
it "can find posts in the allowed category" do
|
||||
post.topic.category.update!(reviewable_by_group_id: group.id, topic_id: topic.id)
|
||||
post.topic.category.update!(topic_id: topic.id)
|
||||
Fabricate(:category_moderation_group, category: post.topic.category, group:)
|
||||
get url
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
|
@ -602,7 +603,8 @@ RSpec.describe PostsController do
|
|||
|
||||
before do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
post.topic.category.update!(reviewable_by_group_id: group.id, topic_id: topic.id)
|
||||
Fabricate(:category_moderation_group, category: post.topic.category, group:)
|
||||
post.topic.category.update!(topic_id: topic.id)
|
||||
sign_in(user_gm)
|
||||
end
|
||||
|
||||
|
@ -2880,7 +2882,7 @@ RSpec.describe PostsController do
|
|||
|
||||
before do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
topic.category.update!(reviewable_by_group_id: group.id)
|
||||
Fabricate(:category_moderation_group, category: topic.category, group:)
|
||||
|
||||
sign_in(user)
|
||||
end
|
||||
|
@ -2903,8 +2905,7 @@ RSpec.describe PostsController do
|
|||
end
|
||||
|
||||
it "prevents a group moderator from altering notes outside of their category" do
|
||||
moderatable_group = Fabricate(:group)
|
||||
topic.category.update!(reviewable_by_group_id: moderatable_group.id)
|
||||
topic.category.category_moderation_groups.where(group:).delete_all
|
||||
|
||||
put "/posts/#{public_post.id}/notice.json", params: { notice: "Hello" }
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ RSpec.describe ReviewableClaimedTopicsController do
|
|||
SiteSetting.reviewable_claiming = "optional"
|
||||
|
||||
group = Fabricate(:group)
|
||||
topic.category.update!(reviewable_by_group: group)
|
||||
Fabricate(:category_moderation_group, category: topic.category, group:)
|
||||
|
||||
messages =
|
||||
MessageBus.track_publish("/reviewable_claimed") do
|
||||
|
@ -106,8 +106,7 @@ RSpec.describe ReviewableClaimedTopicsController do
|
|||
not_notified = Fabricate(:user)
|
||||
|
||||
group = Fabricate(:group)
|
||||
topic.category.update!(reviewable_by_group: group)
|
||||
reviewable.update!(reviewable_by_group: group)
|
||||
Fabricate(:category_moderation_group, category: topic.category, group:)
|
||||
|
||||
notified = Fabricate(:user)
|
||||
group.add(notified)
|
||||
|
@ -190,8 +189,7 @@ RSpec.describe ReviewableClaimedTopicsController do
|
|||
not_notified = Fabricate(:user)
|
||||
|
||||
group = Fabricate(:group)
|
||||
topic.category.update!(reviewable_by_group: group)
|
||||
reviewable.update!(reviewable_by_group: group)
|
||||
Fabricate(:category_moderation_group, category: topic.category, group:)
|
||||
|
||||
notified = Fabricate(:user)
|
||||
group.add(notified)
|
||||
|
|
|
@ -233,7 +233,10 @@ RSpec.describe TopicsController do
|
|||
end
|
||||
|
||||
describe "moving to a new topic as a group moderator" do
|
||||
fab!(:category) { Fabricate(:category, reviewable_by_group: group_user.group) }
|
||||
fab!(:category)
|
||||
fab!(:category_moderation_group) do
|
||||
Fabricate(:category_moderation_group, category:, group: group_user.group)
|
||||
end
|
||||
fab!(:topic) { Fabricate(:topic, category: category) }
|
||||
fab!(:p1) { Fabricate(:post, user: group_user.user, post_number: 1, topic: topic) }
|
||||
fab!(:p2) { Fabricate(:post, user: group_user.user, post_number: 2, topic: topic) }
|
||||
|
@ -388,7 +391,10 @@ RSpec.describe TopicsController do
|
|||
end
|
||||
|
||||
describe "moving to an existing topic as a group moderator" do
|
||||
fab!(:category) { Fabricate(:category, reviewable_by_group: group_user.group) }
|
||||
fab!(:category)
|
||||
fab!(:category_moderation_group) do
|
||||
Fabricate(:category_moderation_group, category:, group: group_user.group)
|
||||
end
|
||||
fab!(:topic) { Fabricate(:topic, category: category) }
|
||||
fab!(:p1) { Fabricate(:post, user: group_user.user, post_number: 1, topic: topic) }
|
||||
fab!(:p2) { Fabricate(:post, user: group_user.user, post_number: 2, topic: topic) }
|
||||
|
@ -439,7 +445,10 @@ RSpec.describe TopicsController do
|
|||
end
|
||||
|
||||
describe "moving chronologically to an existing topic as a group moderator" do
|
||||
fab!(:category) { Fabricate(:category, reviewable_by_group: group_user.group) }
|
||||
fab!(:category)
|
||||
fab!(:category_moderation_group) do
|
||||
Fabricate(:category_moderation_group, category:, group: group_user.group)
|
||||
end
|
||||
fab!(:topic) { Fabricate(:topic, category: category) }
|
||||
fab!(:p1) do
|
||||
Fabricate(
|
||||
|
@ -715,7 +724,10 @@ RSpec.describe TopicsController do
|
|||
end
|
||||
|
||||
describe "merging into another topic as a group moderator" do
|
||||
fab!(:category) { Fabricate(:category, reviewable_by_group: group_user.group) }
|
||||
fab!(:category)
|
||||
fab!(:category_moderation_group) do
|
||||
Fabricate(:category_moderation_group, category:, group: group_user.group)
|
||||
end
|
||||
fab!(:topic) { Fabricate(:topic, category: category) }
|
||||
fab!(:p1) { Fabricate(:post, user: post_author1, post_number: 1, topic: topic) }
|
||||
fab!(:p2) { Fabricate(:post, user: post_author2, post_number: 2, topic: topic) }
|
||||
|
@ -752,7 +764,10 @@ RSpec.describe TopicsController do
|
|||
end
|
||||
|
||||
describe "merging chronologically into another topic as a group moderator" do
|
||||
fab!(:category) { Fabricate(:category, reviewable_by_group: group_user.group) }
|
||||
fab!(:category)
|
||||
fab!(:category_moderation_group) do
|
||||
Fabricate(:category_moderation_group, category:, group: group_user.group)
|
||||
end
|
||||
fab!(:topic) { Fabricate(:topic, category: category) }
|
||||
fab!(:p1) do
|
||||
Fabricate(
|
||||
|
@ -1152,7 +1167,10 @@ RSpec.describe TopicsController do
|
|||
end
|
||||
|
||||
describe "when logged in as a group member with reviewable status" do
|
||||
fab!(:category) { Fabricate(:category, reviewable_by_group: group_user.group) }
|
||||
fab!(:category)
|
||||
fab!(:category_moderation_group) do
|
||||
Fabricate(:category_moderation_group, category:, group: group_user.group)
|
||||
end
|
||||
fab!(:topic) { Fabricate(:topic, category: category) }
|
||||
|
||||
before do
|
||||
|
@ -4970,7 +4988,7 @@ RSpec.describe TopicsController do
|
|||
it "allows a category moderator to create a delete timer" do
|
||||
user.update!(trust_level: TrustLevel[4])
|
||||
Group.user_trust_level_change!(user.id, user.trust_level)
|
||||
topic.category.update!(reviewable_by_group: user.groups.first)
|
||||
Fabricate(:category_moderation_group, category: topic.category, group: user.groups.first)
|
||||
|
||||
sign_in(user)
|
||||
|
||||
|
|
|
@ -4,18 +4,19 @@ RSpec.describe CategorySerializer do
|
|||
fab!(:user)
|
||||
fab!(:admin)
|
||||
fab!(:group)
|
||||
fab!(:category) { Fabricate(:category, reviewable_by_group_id: group.id) }
|
||||
fab!(:category)
|
||||
fab!(:category_moderation_group) { Fabricate(:category_moderation_group, category:, group:) }
|
||||
|
||||
it "includes the reviewable by group name if enabled" do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
json = described_class.new(category, scope: Guardian.new, root: false).as_json
|
||||
expect(json[:reviewable_by_group_name]).to eq(group.name)
|
||||
expect(json[:moderating_group_ids]).to eq([group.id])
|
||||
end
|
||||
|
||||
it "doesn't include the reviewable by group name if disabled" do
|
||||
SiteSetting.enable_category_group_moderation = false
|
||||
json = described_class.new(category, scope: Guardian.new, root: false).as_json
|
||||
expect(json[:reviewable_by_group_name]).to be_blank
|
||||
expect(json[:moderating_group_ids]).to be_blank
|
||||
end
|
||||
|
||||
it "includes custom fields" do
|
||||
|
|
|
@ -284,12 +284,12 @@ RSpec.describe PostSerializer do
|
|||
fab!(:topic)
|
||||
fab!(:group_user)
|
||||
fab!(:post) { Fabricate(:post, topic: topic) }
|
||||
|
||||
before do
|
||||
SiteSetting.enable_category_group_moderation = true
|
||||
topic.category.update!(reviewable_by_group_id: group_user.group.id)
|
||||
fab!(:category_moderation_group) do
|
||||
Fabricate(:category_moderation_group, category: topic.category, group: group_user.group)
|
||||
end
|
||||
|
||||
before { SiteSetting.enable_category_group_moderation = true }
|
||||
|
||||
it "does nothing for regular users" do
|
||||
expect(serialized_post_for_user(nil)[:group_moderator]).to eq(nil)
|
||||
end
|
||||
|
|
|
@ -454,7 +454,10 @@ RSpec.describe TopicViewSerializer do
|
|||
|
||||
context "with can_edit" do
|
||||
fab!(:group_user)
|
||||
fab!(:category) { Fabricate(:category, reviewable_by_group: group_user.group) }
|
||||
fab!(:category)
|
||||
fab!(:category_moderation_group) do
|
||||
Fabricate(:category_moderation_group, category:, group: group_user.group)
|
||||
end
|
||||
fab!(:topic) { Fabricate(:topic, category: category) }
|
||||
let(:user) { group_user.user }
|
||||
|
||||
|
|
Loading…
Reference in New Issue