mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
Tag groups can belong to groups (#10854)
This commit is contained in:
@@ -23,31 +23,47 @@ module DiscourseTagging
|
||||
end
|
||||
end
|
||||
|
||||
# tags currently on the topic
|
||||
old_tag_names = topic.tags.pluck(:name) || []
|
||||
# tags we're trying to add to the topic
|
||||
new_tag_names = tag_names - old_tag_names
|
||||
# tag names being removed from the topic
|
||||
removed_tag_names = old_tag_names - tag_names
|
||||
|
||||
# Protect staff-only tags
|
||||
unless guardian.is_staff?
|
||||
all_staff_tags = DiscourseTagging.staff_tag_names
|
||||
hidden_tags = DiscourseTagging.hidden_tag_names
|
||||
# tag names which are visible, but not usable, by *some users*
|
||||
readonly_tags = DiscourseTagging.readonly_tag_names(guardian)
|
||||
# tags names which are not visibile or usuable by *some users*
|
||||
hidden_tags = DiscourseTagging.hidden_tag_names(guardian)
|
||||
|
||||
staff_tags = new_tag_names & all_staff_tags
|
||||
staff_tags += new_tag_names & hidden_tags
|
||||
if staff_tags.present?
|
||||
topic.errors.add(:base, I18n.t("tags.staff_tag_disallowed", tag: staff_tags.join(" ")))
|
||||
return false
|
||||
end
|
||||
# tag names which ARE permitted by *this user*
|
||||
permitted_tags = DiscourseTagging.permitted_tag_names(guardian)
|
||||
|
||||
staff_tags = removed_tag_names & all_staff_tags
|
||||
if staff_tags.present?
|
||||
topic.errors.add(:base, I18n.t("tags.staff_tag_remove_disallowed", tag: staff_tags.join(" ")))
|
||||
return false
|
||||
end
|
||||
|
||||
tag_names += removed_tag_names & hidden_tags
|
||||
# If this user has explicit permission to use certain tags,
|
||||
# we need to ensure those tags are removed from the list of
|
||||
# restricted tags
|
||||
if permitted_tags.present?
|
||||
readonly_tags = readonly_tags - permitted_tags
|
||||
hidden_tags = hidden_tags - permitted_tags
|
||||
end
|
||||
|
||||
# visible, but not usable, tags this user is trying to use
|
||||
disallowed_tags = new_tag_names & readonly_tags
|
||||
# hidden tags this user is trying to use
|
||||
disallowed_tags += new_tag_names & hidden_tags
|
||||
|
||||
if disallowed_tags.present?
|
||||
topic.errors.add(:base, I18n.t("tags.restricted_tag_disallowed", tag: disallowed_tags.join(" ")))
|
||||
return false
|
||||
end
|
||||
|
||||
removed_readonly_tags = removed_tag_names & readonly_tags
|
||||
if removed_readonly_tags.present?
|
||||
topic.errors.add(:base, I18n.t("tags.restricted_tag_remove_disallowed", tag: removed_readonly_tags.join(" ")))
|
||||
return false
|
||||
end
|
||||
|
||||
tag_names += removed_tag_names & hidden_tags
|
||||
|
||||
category = topic.category
|
||||
tag_names = tag_names + old_tag_names if append
|
||||
|
||||
@@ -182,8 +198,7 @@ module DiscourseTagging
|
||||
INNER JOIN tag_group_memberships tgm ON tgm.tag_id = t.id /*and_name_like*/
|
||||
INNER JOIN tag_groups tg ON tg.id = tgm.tag_group_id
|
||||
INNER JOIN tag_group_permissions tgp
|
||||
ON tg.id = tgp.tag_group_id
|
||||
AND tgp.group_id = #{Group::AUTO_GROUPS[:everyone]}
|
||||
ON tg.id = tgp.tag_group_id /*and_group_ids*/
|
||||
AND tgp.permission_type = #{TagGroupPermission.permission_types[:full]}
|
||||
)
|
||||
SQL
|
||||
@@ -217,6 +232,8 @@ module DiscourseTagging
|
||||
sql = +"WITH #{TAG_GROUP_RESTRICTIONS_SQL}, #{CATEGORY_RESTRICTIONS_SQL}"
|
||||
if (opts[:for_input] || opts[:for_topic]) && filter_for_non_staff
|
||||
sql << ", #{PERMITTED_TAGS_SQL} "
|
||||
builder_params[:group_ids] = permitted_group_ids(guardian)
|
||||
sql.gsub!("/*and_group_ids*/", "AND group_id IN (:group_ids)")
|
||||
end
|
||||
|
||||
outer_join = category.nil? || category.allow_global_tags || !category_has_restricted_tags
|
||||
@@ -296,12 +313,23 @@ module DiscourseTagging
|
||||
end
|
||||
|
||||
if filter_for_non_staff
|
||||
# remove hidden tags
|
||||
builder.where(<<~SQL, Group::AUTO_GROUPS[:everyone])
|
||||
group_ids = permitted_group_ids(guardian)
|
||||
|
||||
builder.where(<<~SQL, group_ids, group_ids)
|
||||
id NOT IN (
|
||||
SELECT tag_id
|
||||
FROM tag_group_memberships tgm
|
||||
WHERE tag_group_id NOT IN (SELECT tag_group_id FROM tag_group_permissions WHERE group_id = ?)
|
||||
(SELECT tgm.tag_id
|
||||
FROM tag_group_permissions tgp
|
||||
INNER JOIN tag_groups tg ON tgp.tag_group_id = tg.id
|
||||
INNER JOIN tag_group_memberships tgm ON tg.id = tgm.tag_group_id
|
||||
WHERE tgp.group_id NOT IN (?))
|
||||
|
||||
EXCEPT
|
||||
|
||||
(SELECT tgm.tag_id
|
||||
FROM tag_group_permissions tgp
|
||||
INNER JOIN tag_groups tg ON tgp.tag_group_id = tg.id
|
||||
INNER JOIN tag_group_memberships tgm ON tg.id = tgm.tag_group_id
|
||||
WHERE tgp.group_id IN (?))
|
||||
)
|
||||
SQL
|
||||
end
|
||||
@@ -348,16 +376,52 @@ module DiscourseTagging
|
||||
guardian&.is_staff? ? [] : hidden_tags_query.pluck(:name)
|
||||
end
|
||||
|
||||
# most restrictive level of tag groups
|
||||
def self.hidden_tags_query
|
||||
Tag.joins(:tag_groups)
|
||||
query = Tag.joins(:tag_groups)
|
||||
.where('tag_groups.id NOT IN (
|
||||
SELECT tag_group_id
|
||||
FROM tag_group_permissions
|
||||
WHERE group_id = ?)',
|
||||
Group::AUTO_GROUPS[:everyone]
|
||||
)
|
||||
|
||||
query
|
||||
end
|
||||
|
||||
def self.permitted_group_ids(guardian = nil)
|
||||
group_ids = [Group::AUTO_GROUPS[:everyone]]
|
||||
|
||||
if guardian.authenticated?
|
||||
group_ids.concat(guardian.user.groups.pluck(:id))
|
||||
end
|
||||
|
||||
group_ids
|
||||
end
|
||||
|
||||
# read-only tags for this user
|
||||
def self.readonly_tag_names(guardian = nil)
|
||||
return [] if guardian&.is_staff?
|
||||
|
||||
query = Tag.joins(tag_groups: :tag_group_permissions)
|
||||
.where('tag_group_permissions.permission_type = ?',
|
||||
TagGroupPermission.permission_types[:readonly])
|
||||
|
||||
query.pluck(:name)
|
||||
end
|
||||
|
||||
# explicit permissions to use these tags
|
||||
def self.permitted_tag_names(guardian = nil)
|
||||
query = Tag.joins(tag_groups: :tag_group_permissions)
|
||||
.where('tag_group_permissions.group_id IN (?) AND tag_group_permissions.permission_type = ?',
|
||||
permitted_group_ids(guardian),
|
||||
TagGroupPermission.permission_types[:full]
|
||||
)
|
||||
|
||||
query.pluck(:name).uniq
|
||||
end
|
||||
|
||||
# middle level of tag group restrictions
|
||||
def self.staff_tag_names
|
||||
tag_names = Discourse.cache.read(TAGS_STAFF_CACHE_KEY)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user