FEATURE: set notification levels when added to a group (#10378)
* FEATURE: set notification levels when added to a group This feature allows admins and group owners to define default category and tag tracking levels that will be applied to user preferences automatically at the time when users are added to the group. Users are free to change those preferences afterwards. When removed from a group, the user's notification preferences aren't changed.
This commit is contained in:
parent
cd4f251891
commit
1ca81fbb95
|
@ -0,0 +1,14 @@
|
|||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import Controller from "@ember/controller";
|
||||
|
||||
export default Controller.extend({
|
||||
@discourseComputed(
|
||||
"model.watchingCategories.[]",
|
||||
"model.watchingFirstPostCategories.[]",
|
||||
"model.trackingCategories.[]",
|
||||
"model.mutedCategories.[]"
|
||||
)
|
||||
selectedCategories(watching, watchingFirst, tracking, muted) {
|
||||
return [].concat(watching, watchingFirst, tracking, muted).filter(t => t);
|
||||
}
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import Controller from "@ember/controller";
|
||||
|
||||
export default Controller.extend({
|
||||
@discourseComputed(
|
||||
"model.watching_tags.[]",
|
||||
"model.watching_first_post_tags.[]",
|
||||
"model.tracking_tags.[]",
|
||||
"model.muted_tags.[]"
|
||||
)
|
||||
selectedTags(watching, watchingFirst, tracking, muted) {
|
||||
return [].concat(watching, watchingFirst, tracking, muted).filter(t => t);
|
||||
}
|
||||
});
|
|
@ -13,6 +13,14 @@ export default Controller.extend({
|
|||
route: "group.manage.interaction",
|
||||
title: "groups.manage.interaction.title"
|
||||
},
|
||||
{
|
||||
route: "group.manage.categories",
|
||||
title: "groups.manage.categories.title"
|
||||
},
|
||||
{
|
||||
route: "group.manage.tags",
|
||||
title: "groups.manage.tags.title"
|
||||
},
|
||||
|
||||
{ route: "group.manage.logs", title: "groups.manage.logs.title" }
|
||||
];
|
||||
|
|
|
@ -176,6 +176,35 @@ const Group = RestModel.extend({
|
|||
}
|
||||
},
|
||||
|
||||
@observes("watching_category_ids")
|
||||
_updateWatchingCategories() {
|
||||
this.set(
|
||||
"watchingCategories",
|
||||
Category.findByIds(this.watching_category_ids)
|
||||
);
|
||||
},
|
||||
|
||||
@observes("tracking_category_ids")
|
||||
_updateTrackingCategories() {
|
||||
this.set(
|
||||
"trackingCategories",
|
||||
Category.findByIds(this.tracking_category_ids)
|
||||
);
|
||||
},
|
||||
|
||||
@observes("watching_first_post_category_ids")
|
||||
_updateWatchingFirstPostCategories() {
|
||||
this.set(
|
||||
"watchingFirstPostCategories",
|
||||
Category.findByIds(this.watching_first_post_category_ids)
|
||||
);
|
||||
},
|
||||
|
||||
@observes("muted_category_ids")
|
||||
_updateMutedCategories() {
|
||||
this.set("mutedCategories", Category.findByIds(this.muted_category_ids));
|
||||
},
|
||||
|
||||
asJSON() {
|
||||
const attrs = {
|
||||
name: this.name,
|
||||
|
@ -211,6 +240,26 @@ const Group = RestModel.extend({
|
|||
publish_read_state: this.publish_read_state
|
||||
};
|
||||
|
||||
["muted", "watching", "tracking", "watching_first_post"].forEach(s => {
|
||||
let prop =
|
||||
s === "watching_first_post"
|
||||
? "watchingFirstPostCategories"
|
||||
: s + "Categories";
|
||||
|
||||
let categories = this.get(prop);
|
||||
|
||||
if (categories) {
|
||||
attrs[s + "_category_ids"] =
|
||||
categories.length > 0 ? categories.map(c => c.get("id")) : [-1];
|
||||
}
|
||||
|
||||
let tags = this.get(s + "_tags");
|
||||
|
||||
if (tags) {
|
||||
attrs[s + "_tags"] = tags.length > 0 ? tags : [""];
|
||||
}
|
||||
});
|
||||
|
||||
if (this.flair_type === "icon") {
|
||||
attrs["flair_icon"] = this.flair_icon;
|
||||
} else if (this.flair_type === "image") {
|
||||
|
|
|
@ -94,6 +94,8 @@ export default function() {
|
|||
this.route("interaction");
|
||||
this.route("email");
|
||||
this.route("members");
|
||||
this.route("categories");
|
||||
this.route("tags");
|
||||
this.route("logs");
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
import I18n from "I18n";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
showFooter: true,
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("groups.manage.categories.title");
|
||||
}
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
import I18n from "I18n";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
showFooter: true,
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("groups.manage.tags.title");
|
||||
}
|
||||
});
|
|
@ -0,0 +1,64 @@
|
|||
<form class="groups-form form-vertical groups-notifications-form">
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{i18n "groups.manage.categories.long_title"}}</label>
|
||||
<div>{{i18n "groups.manage.categories.description"}}</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>{{d-icon "d-watching"}} {{i18n "user.watched_categories"}}</label>
|
||||
|
||||
{{category-selector
|
||||
categories=model.watchingCategories
|
||||
blacklist=selectedCategories
|
||||
onChange=(action (mut model.watchingCategories))
|
||||
}}
|
||||
|
||||
<div class="control-instructions">
|
||||
{{i18n "groups.manage.categories.watched_categories_instructions"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>{{d-icon "d-tracking"}} {{i18n "user.tracked_categories"}}</label>
|
||||
|
||||
{{category-selector
|
||||
categories=model.trackingCategories
|
||||
blacklist=selectedCategories
|
||||
onChange=(action (mut model.trackingCategories))
|
||||
}}
|
||||
|
||||
<div class="control-instructions">
|
||||
{{i18n "groups.manage.categories.tracked_categories_instructions"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>{{d-icon "d-watching-first"}} {{i18n "user.watched_first_post_categories"}}</label>
|
||||
|
||||
{{category-selector
|
||||
categories=model.watchingFirstPostCategories
|
||||
blacklist=selectedCategories
|
||||
onChange=(action (mut model.watchingFirstPostCategories))
|
||||
}}
|
||||
|
||||
<div class="control-instructions">
|
||||
{{i18n "groups.manage.categories.watching_first_post_categories_instructions"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>{{d-icon "d-muted"}} {{i18n "user.muted_categories"}}</label>
|
||||
|
||||
{{category-selector
|
||||
categories=model.mutedCategories
|
||||
blacklist=selectedCategories
|
||||
onChange=(action (mut model.mutedCategories))
|
||||
}}
|
||||
|
||||
<div class="control-instructions">
|
||||
{{i18n "groups.manage.categories.muted_categories_instructions"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{group-manage-save-button model=model}}
|
||||
</form>
|
|
@ -0,0 +1,72 @@
|
|||
<form class="groups-form form-vertical groups-notifications-form">
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{i18n "groups.manage.tags.long_title"}}</label>
|
||||
<div>{{i18n "groups.manage.tags.description"}}</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>{{d-icon "d-watching"}} {{i18n "user.watched_tags"}}</label>
|
||||
|
||||
{{tag-chooser
|
||||
tags=model.watching_tags
|
||||
blacklist=selectedTags
|
||||
allowCreate=false
|
||||
everyTag=true
|
||||
unlimitedTagCount=true
|
||||
}}
|
||||
|
||||
<div class="control-instructions">
|
||||
{{i18n "groups.manage.tags.watched_tags_instructions"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>{{d-icon "d-tracking"}} {{i18n "user.tracked_tags"}}</label>
|
||||
|
||||
{{tag-chooser
|
||||
tags=model.tracking_tags
|
||||
blacklist=selectedTags
|
||||
allowCreate=false
|
||||
everyTag=true
|
||||
unlimitedTagCount=true
|
||||
}}
|
||||
|
||||
<div class="control-instructions">
|
||||
{{i18n "groups.manage.tags.tracked_tags_instructions"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>{{d-icon "d-watching-first"}} {{i18n "user.watched_first_post_tags"}}</label>
|
||||
|
||||
{{tag-chooser
|
||||
tags=model.watching_first_post_tags
|
||||
blacklist=selectedTags
|
||||
allowCreate=false
|
||||
everyTag=true
|
||||
unlimitedTagCount=true
|
||||
}}
|
||||
|
||||
<div class="control-instructions">
|
||||
{{i18n "groups.manage.tags.watching_first_post_tags_instructions"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>{{d-icon "d-muted"}} {{i18n "user.muted_tags"}}</label>
|
||||
|
||||
{{tag-chooser
|
||||
tags=model.muted_tags
|
||||
blacklist=selectedTags
|
||||
allowCreate=false
|
||||
everyTag=true
|
||||
unlimitedTagCount=true
|
||||
}}
|
||||
|
||||
<div class="control-instructions">
|
||||
{{i18n "groups.manage.tags.muted_tags_instructions"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{group-manage-save-button model=model}}
|
||||
</form>
|
|
@ -146,4 +146,17 @@
|
|||
.control-group-inline {
|
||||
display: inline;
|
||||
}
|
||||
&.groups-notifications-form {
|
||||
.control-instructions {
|
||||
color: $primary-medium;
|
||||
margin-bottom: 10px;
|
||||
font-size: $font-down-1;
|
||||
line-height: $line-height-large;
|
||||
}
|
||||
|
||||
.category-selector,
|
||||
.tag-chooser {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,3 +50,8 @@
|
|||
top: 20px;
|
||||
right: 20px;
|
||||
}
|
||||
|
||||
.groups-form.groups-notifications-form {
|
||||
width: 500px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
|
|
@ -604,6 +604,13 @@ class GroupsController < ApplicationController
|
|||
default_params
|
||||
end
|
||||
|
||||
if !automatic || current_user.admin
|
||||
[:muted, :tracking, :watching, :watching_first_post].each do |level|
|
||||
permitted_params << { "#{level}_category_ids" => [] }
|
||||
permitted_params << { "#{level}_tags" => [] }
|
||||
end
|
||||
end
|
||||
|
||||
params.require(:group).permit(*permitted_params)
|
||||
end
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ module Roleable
|
|||
set_permission('moderator', true)
|
||||
auto_approve_user
|
||||
enqueue_staff_welcome_message(:moderator)
|
||||
set_default_notification_levels(:moderators)
|
||||
end
|
||||
|
||||
def revoke_moderation!
|
||||
|
@ -34,6 +35,7 @@ module Roleable
|
|||
set_permission('admin', true)
|
||||
auto_approve_user
|
||||
enqueue_staff_welcome_message(:admin)
|
||||
set_default_notification_levels(:admins)
|
||||
end
|
||||
|
||||
def revoke_admin!
|
||||
|
@ -52,6 +54,13 @@ module Roleable
|
|||
save_and_refresh_staff_groups!
|
||||
end
|
||||
|
||||
def set_default_notification_levels(group_name)
|
||||
Group.set_category_and_tag_default_notification_levels!(self, group_name)
|
||||
if group_name == :admins || group_name == :moderators
|
||||
Group.set_category_and_tag_default_notification_levels!(self, :staff)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def auto_approve_user
|
||||
|
|
|
@ -29,6 +29,8 @@ class Group < ActiveRecord::Base
|
|||
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
|
||||
|
||||
belongs_to :flair_upload, class_name: 'Upload'
|
||||
|
||||
|
@ -51,6 +53,7 @@ class Group < ActiveRecord::Base
|
|||
after_commit :trigger_group_created_event, on: :create
|
||||
after_commit :trigger_group_updated_event, on: :update
|
||||
after_commit :trigger_group_destroyed_event, on: :destroy
|
||||
after_commit :set_default_notifications, on: [:create, :update]
|
||||
|
||||
def expire_cache
|
||||
ApplicationSerializer.expire_cache_fragment!("group_names")
|
||||
|
@ -382,6 +385,13 @@ class Group < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def self.set_category_and_tag_default_notification_levels!(user, group_name)
|
||||
if group = lookup_group(group_name)
|
||||
GroupUser.set_category_notifications(group, user)
|
||||
GroupUser.set_tag_notifications(group, user)
|
||||
end
|
||||
end
|
||||
|
||||
def self.refresh_automatic_group!(name)
|
||||
return unless id = AUTO_GROUPS[name]
|
||||
|
||||
|
@ -755,6 +765,32 @@ class Group < ActiveRecord::Base
|
|||
flair_icon.presence || flair_upload&.short_path
|
||||
end
|
||||
|
||||
[:muted, :tracking, :watching, :watching_first_post].each do |level|
|
||||
define_method("#{level}_category_ids=") do |category_ids|
|
||||
@category_notifications ||= {}
|
||||
@category_notifications[level] = category_ids
|
||||
end
|
||||
|
||||
define_method("#{level}_tags=") do |tag_names|
|
||||
@tag_notifications ||= {}
|
||||
@tag_notifications[level] = tag_names
|
||||
end
|
||||
end
|
||||
|
||||
def set_default_notifications
|
||||
if @category_notifications
|
||||
@category_notifications.each do |level, category_ids|
|
||||
GroupCategoryNotificationDefault.batch_set(self, level, category_ids)
|
||||
end
|
||||
end
|
||||
|
||||
if @tag_notifications
|
||||
@tag_notifications.each do |level, tag_names|
|
||||
GroupTagNotificationDefault.batch_set(self, level, tag_names)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def imap_mailboxes
|
||||
return [] if self.imap_server.blank? ||
|
||||
self.email_username.blank? ||
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class GroupCategoryNotificationDefault < ActiveRecord::Base
|
||||
belongs_to :group
|
||||
belongs_to :category
|
||||
|
||||
def self.notification_levels
|
||||
NotificationLevels.all
|
||||
end
|
||||
|
||||
def self.lookup(group, level)
|
||||
self.where(group: group, notification_level: notification_levels[level])
|
||||
end
|
||||
|
||||
def self.batch_set(group, level, category_ids)
|
||||
level_num = notification_levels[level]
|
||||
category_ids = Category.where(id: category_ids).pluck(:id)
|
||||
|
||||
changed = false
|
||||
|
||||
# Update pre-existing
|
||||
if category_ids.present? && GroupCategoryNotificationDefault
|
||||
.where(group_id: group.id, category_id: category_ids)
|
||||
.where.not(notification_level: level_num)
|
||||
.update_all(notification_level: level_num) > 0
|
||||
|
||||
changed = true
|
||||
end
|
||||
|
||||
# Remove extraneous category users
|
||||
if GroupCategoryNotificationDefault
|
||||
.where(group_id: group.id, notification_level: level_num)
|
||||
.where.not(category_id: category_ids)
|
||||
.delete_all > 0
|
||||
|
||||
changed = true
|
||||
end
|
||||
|
||||
if category_ids.present?
|
||||
params = {
|
||||
group_id: group.id,
|
||||
level_num: level_num,
|
||||
}
|
||||
|
||||
sql = <<~SQL
|
||||
INSERT INTO group_category_notification_defaults (group_id, category_id, notification_level)
|
||||
SELECT :group_id, :category_id, :level_num
|
||||
ON CONFLICT DO NOTHING
|
||||
SQL
|
||||
|
||||
# we could use VALUES here but it would introduce a string
|
||||
# into the query, plus it is a bit of a micro optimisation
|
||||
category_ids.each do |category_id|
|
||||
params[:category_id] = category_id
|
||||
if DB.exec(sql, params) > 0
|
||||
changed = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
changed
|
||||
end
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: group_category_notification_defaults
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# group_id :integer not null
|
||||
# category_id :integer not null
|
||||
# notification_level :integer not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# idx_group_category_notification_defaults_unique (group_id,category_id) UNIQUE
|
||||
#
|
|
@ -0,0 +1,57 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class GroupTagNotificationDefault < ActiveRecord::Base
|
||||
belongs_to :group
|
||||
belongs_to :tag
|
||||
|
||||
def self.notification_levels
|
||||
NotificationLevels.all
|
||||
end
|
||||
|
||||
def self.lookup(group, level)
|
||||
self.where(group: group, notification_level: notification_levels[level])
|
||||
end
|
||||
|
||||
def self.batch_set(group, level, tag_names)
|
||||
tag_names ||= []
|
||||
changed = false
|
||||
|
||||
records = self.where(group: group, notification_level: notification_levels[level])
|
||||
old_ids = records.pluck(:tag_id)
|
||||
|
||||
tag_ids = tag_names.empty? ? [] : Tag.where_name(tag_names).pluck(:id)
|
||||
|
||||
Tag.where_name(tag_names).joins(:target_tag).each do |tag|
|
||||
tag_ids[tag_ids.index(tag.id)] = tag.target_tag_id
|
||||
end
|
||||
|
||||
tag_ids.uniq!
|
||||
|
||||
remove = (old_ids - tag_ids)
|
||||
if remove.present?
|
||||
records.where('tag_id in (?)', remove).destroy_all
|
||||
changed = true
|
||||
end
|
||||
|
||||
(tag_ids - old_ids).each do |id|
|
||||
self.create!(group: group, tag_id: id, notification_level: notification_levels[level])
|
||||
changed = true
|
||||
end
|
||||
|
||||
changed
|
||||
end
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: group_tag_notification_defaults
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# group_id :integer not null
|
||||
# tag_id :integer not null
|
||||
# notification_level :integer not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# idx_group_tag_notification_defaults_unique (group_id,tag_id) UNIQUE
|
||||
#
|
|
@ -12,6 +12,8 @@ class GroupUser < ActiveRecord::Base
|
|||
|
||||
before_create :set_notification_level
|
||||
after_save :grant_trust_level
|
||||
after_save :set_category_notifications
|
||||
after_save :set_tag_notifications
|
||||
|
||||
def self.notification_levels
|
||||
NotificationLevels.all
|
||||
|
@ -64,6 +66,70 @@ class GroupUser < ActiveRecord::Base
|
|||
|
||||
Promotion.recalculate(user)
|
||||
end
|
||||
|
||||
def set_category_notifications
|
||||
self.class.set_category_notifications(group, user)
|
||||
end
|
||||
|
||||
def self.set_category_notifications(group, user)
|
||||
group_levels = group.group_category_notification_defaults.each_with_object({}) do |r, h|
|
||||
h[r.notification_level] ||= []
|
||||
h[r.notification_level] << r.category_id
|
||||
end
|
||||
|
||||
return if group_levels.empty?
|
||||
|
||||
user_levels = CategoryUser.where(user_id: user.id).each_with_object({}) do |r, h|
|
||||
h[r.notification_level] ||= []
|
||||
h[r.notification_level] << r.category_id
|
||||
end
|
||||
|
||||
higher_level_category_ids = user_levels.values.flatten
|
||||
|
||||
[:muted, :tracking, :watching_first_post, :watching].each do |level|
|
||||
level_num = NotificationLevels.all[level]
|
||||
higher_level_category_ids -= (user_levels[level_num] || [])
|
||||
if group_category_ids = group_levels[level_num]
|
||||
CategoryUser.batch_set(
|
||||
user,
|
||||
level,
|
||||
group_category_ids + (user_levels[level_num] || []) - higher_level_category_ids
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def set_tag_notifications
|
||||
self.class.set_tag_notifications(group, user)
|
||||
end
|
||||
|
||||
def self.set_tag_notifications(group, user)
|
||||
group_levels = group.group_tag_notification_defaults.each_with_object({}) do |r, h|
|
||||
h[r.notification_level] ||= []
|
||||
h[r.notification_level] << r.tag_id
|
||||
end
|
||||
|
||||
return if group_levels.empty?
|
||||
|
||||
user_levels = TagUser.where(user_id: user.id).each_with_object({}) do |r, h|
|
||||
h[r.notification_level] ||= []
|
||||
h[r.notification_level] << r.tag_id
|
||||
end
|
||||
|
||||
higher_level_tag_ids = user_levels.values.flatten
|
||||
|
||||
[:muted, :tracking, :watching_first_post, :watching].each do |level|
|
||||
level_num = NotificationLevels.all[level]
|
||||
higher_level_tag_ids -= (user_levels[level_num] || [])
|
||||
if group_tag_ids = group_levels[level_num]
|
||||
TagUser.batch_set(
|
||||
user,
|
||||
level,
|
||||
group_tag_ids + (user_levels[level_num] || []) - higher_level_tag_ids
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
|
|
|
@ -19,23 +19,50 @@ class TagUser < ActiveRecord::Base
|
|||
records = TagUser.where(user: user, notification_level: notification_levels[level])
|
||||
old_ids = records.pluck(:tag_id)
|
||||
|
||||
tag_ids = tags.empty? ? [] : Tag.where_name(tags).pluck(:id)
|
||||
tag_ids = if tags.empty?
|
||||
[]
|
||||
elsif tags.first&.is_a?(String)
|
||||
Tag.where_name(tags).pluck(:id)
|
||||
else
|
||||
tags
|
||||
end
|
||||
|
||||
Tag.where_name(tags).joins(:target_tag).each do |tag|
|
||||
Tag.where(id: tag_ids).joins(:target_tag).each do |tag|
|
||||
tag_ids[tag_ids.index(tag.id)] = tag.target_tag_id
|
||||
end
|
||||
|
||||
tag_ids.uniq!
|
||||
|
||||
if tag_ids.present? &&
|
||||
TagUser.where(user_id: user.id, tag_id: tag_ids)
|
||||
.where
|
||||
.not(notification_level: notification_levels[level])
|
||||
.update_all(notification_level: notification_levels[level]) > 0
|
||||
|
||||
changed = true
|
||||
end
|
||||
|
||||
remove = (old_ids - tag_ids)
|
||||
if remove.present?
|
||||
records.where('tag_id in (?)', remove).destroy_all
|
||||
changed = true
|
||||
end
|
||||
|
||||
(tag_ids - old_ids).each do |id|
|
||||
TagUser.create!(user: user, tag_id: id, notification_level: notification_levels[level])
|
||||
changed = true
|
||||
now = Time.zone.now
|
||||
|
||||
new_records_attrs = (tag_ids - old_ids).map do |tag_id|
|
||||
{
|
||||
user_id: user.id,
|
||||
tag_id: tag_id,
|
||||
notification_level: notification_levels[level],
|
||||
created_at: now,
|
||||
updated_at: now
|
||||
}
|
||||
end
|
||||
|
||||
unless new_records_attrs.empty?
|
||||
result = TagUser.insert_all(new_records_attrs)
|
||||
changed = true if result.rows.length > 0
|
||||
end
|
||||
|
||||
if changed
|
||||
|
|
|
@ -57,6 +57,24 @@ class BasicGroupSerializer < ApplicationSerializer
|
|||
:imap_old_emails,
|
||||
:imap_new_emails
|
||||
|
||||
def self.admin_or_owner_attributes(*attrs)
|
||||
attributes(*attrs)
|
||||
attrs.each do |attr|
|
||||
define_method "include_#{attr}?" do
|
||||
scope.is_admin? || (include_is_group_owner? && is_group_owner)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
admin_or_owner_attributes :watching_category_ids,
|
||||
:tracking_category_ids,
|
||||
:watching_first_post_category_ids,
|
||||
:muted_category_ids,
|
||||
:watching_tags,
|
||||
:watching_first_post_tags,
|
||||
:tracking_tags,
|
||||
:muted_tags
|
||||
|
||||
def include_display_name?
|
||||
object.automatic
|
||||
end
|
||||
|
@ -103,6 +121,16 @@ class BasicGroupSerializer < ApplicationSerializer
|
|||
scope.can_see_group_members?(object)
|
||||
end
|
||||
|
||||
[:watching, :tracking, :watching_first_post, :muted].each do |level|
|
||||
define_method("#{level}_category_ids") do
|
||||
GroupCategoryNotificationDefault.lookup(object, level).pluck(:category_id)
|
||||
end
|
||||
|
||||
define_method("#{level}_tags") do
|
||||
GroupTagNotificationDefault.lookup(object, level).joins(:tag).pluck('tags.name')
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def staff?
|
||||
|
|
|
@ -656,6 +656,22 @@ en:
|
|||
membership:
|
||||
title: Membership
|
||||
access: Access
|
||||
categories:
|
||||
title: Categories
|
||||
long_title: "Category default notifications"
|
||||
description: "When users are added to this group, their category notification settings will be set to these defaults. Afterwards, they can change them."
|
||||
watched_categories_instructions: "Automatically watch all topics in these categories. Group members will be notified of all new posts and topics, and a count of new posts will also appear next to the topic."
|
||||
tracked_categories_instructions: "Automatically track all topics in these categories. A count of new posts will appear next to the topic."
|
||||
watching_first_post_categories_instructions: "Users will be notified of the first post in each new topic in these categories."
|
||||
muted_categories_instructions: "Users will not be notified of anything about new topics in these categories, and they will not appear on the categories or latest topics pages."
|
||||
tags:
|
||||
title: Tags
|
||||
long_title: "Tags default notifications"
|
||||
description: "When users are added to this group, their tag notification settings will be set to these defaults. Afterwards, they can change them."
|
||||
watched_tags_instructions: "Automatically watch all topics with these tags. Group members will be notified of all new posts and topics, and a count of new posts will also appear next to the topic."
|
||||
tracked_tags_instructions: "Automatically track all topics with these tags. A count of new posts will appear next to the topic."
|
||||
watching_first_post_tags_instructions: "Users will be notified of the first post in each new topic with these tags."
|
||||
muted_tags_instructions: "Users will not be notified of anything about new topics with these tags, and they will not appear in latest."
|
||||
logs:
|
||||
title: "Logs"
|
||||
when: "When"
|
||||
|
|
|
@ -577,6 +577,8 @@ Discourse::Application.routes.draw do
|
|||
manage/membership
|
||||
manage/interaction
|
||||
manage/email
|
||||
manage/categories
|
||||
manage/tags
|
||||
manage/logs
|
||||
}.each do |path|
|
||||
get path => 'groups#show'
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreateGroupDefaultTracking < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
create_table :group_category_notification_defaults do |t|
|
||||
t.integer :group_id, null: false
|
||||
t.integer :category_id, null: false
|
||||
t.integer :notification_level, null: false
|
||||
end
|
||||
|
||||
add_index :group_category_notification_defaults,
|
||||
[:group_id, :category_id],
|
||||
unique: true,
|
||||
name: :idx_group_category_notification_defaults_unique
|
||||
|
||||
create_table :group_tag_notification_defaults do |t|
|
||||
t.integer :group_id, null: false
|
||||
t.integer :tag_id, null: false
|
||||
t.integer :notification_level, null: false
|
||||
end
|
||||
|
||||
add_index :group_tag_notification_defaults,
|
||||
[:group_id, :tag_id],
|
||||
unique: true,
|
||||
name: :idx_group_tag_notification_defaults_unique
|
||||
end
|
||||
end
|
|
@ -1054,4 +1054,121 @@ describe Group do
|
|||
expect(group.name).to eq("Bücherwurm") # NFC
|
||||
end
|
||||
end
|
||||
|
||||
describe "default notifications" do
|
||||
let(:category1) { Fabricate(:category) }
|
||||
let(:category2) { Fabricate(:category) }
|
||||
let(:category3) { Fabricate(:category) }
|
||||
let(:tag1) { Fabricate(:tag) }
|
||||
let(:tag2) { Fabricate(:tag) }
|
||||
let(:tag3) { Fabricate(:tag) }
|
||||
let(:synonym1) { Fabricate(:tag, target_tag: tag1) }
|
||||
let(:synonym2) { Fabricate(:tag, target_tag: tag2) }
|
||||
|
||||
it "can set category notifications" do
|
||||
group.watching_category_ids = [category1.id, category2.id]
|
||||
group.tracking_category_ids = [category3.id]
|
||||
group.save!
|
||||
expect(GroupCategoryNotificationDefault.lookup(group, :watching).pluck(:category_id)).to contain_exactly(category1.id, category2.id)
|
||||
expect(GroupCategoryNotificationDefault.lookup(group, :tracking).pluck(:category_id)).to eq([category3.id])
|
||||
|
||||
new_group = Fabricate.build(:group)
|
||||
new_group.watching_category_ids = [category1.id, category2.id]
|
||||
new_group.save!
|
||||
expect(GroupCategoryNotificationDefault.lookup(new_group, :watching).pluck(:category_id)).to contain_exactly(category1.id, category2.id)
|
||||
end
|
||||
|
||||
it "can remove categories" do
|
||||
[category1, category2].each do |category|
|
||||
GroupCategoryNotificationDefault.create!(
|
||||
group: group,
|
||||
category: category,
|
||||
notification_level: GroupCategoryNotificationDefault.notification_levels[:watching]
|
||||
)
|
||||
end
|
||||
|
||||
group.watching_category_ids = [category2.id]
|
||||
group.save!
|
||||
expect(GroupCategoryNotificationDefault.lookup(group, :watching).pluck(:category_id)).to eq([category2.id])
|
||||
|
||||
group.watching_category_ids = []
|
||||
group.save!
|
||||
expect(GroupCategoryNotificationDefault.lookup(group, :watching).pluck(:category_id)).to be_empty
|
||||
end
|
||||
|
||||
it "can set tag notifications" do
|
||||
group.watching_tags = [tag1.name, tag2.name]
|
||||
group.tracking_tags = [tag3.name]
|
||||
group.save!
|
||||
expect(GroupTagNotificationDefault.lookup(group, :watching).pluck(:tag_id)).to contain_exactly(tag1.id, tag2.id)
|
||||
expect(GroupTagNotificationDefault.lookup(group, :tracking).pluck(:tag_id)).to eq([tag3.id])
|
||||
|
||||
new_group = Fabricate.build(:group)
|
||||
new_group.watching_first_post_tags = [tag1.name, tag3.name]
|
||||
new_group.save!
|
||||
expect(GroupTagNotificationDefault.lookup(new_group, :watching_first_post).pluck(:tag_id)).to contain_exactly(tag1.id, tag3.id)
|
||||
end
|
||||
|
||||
it "can take tag synonyms" do
|
||||
group.tracking_tags = [synonym1.name, synonym2.name, tag3.name]
|
||||
group.save!
|
||||
expect(GroupTagNotificationDefault.lookup(group, :tracking).pluck(:tag_id)).to contain_exactly(tag1.id, tag2.id, tag3.id)
|
||||
|
||||
group.tracking_tags = [synonym1.name, synonym2.name, tag1.name, tag2.name, tag3.name]
|
||||
group.save!
|
||||
expect(GroupTagNotificationDefault.lookup(group, :tracking).pluck(:tag_id)).to contain_exactly(tag1.id, tag2.id, tag3.id)
|
||||
end
|
||||
|
||||
it "can remove tags" do
|
||||
[tag1, tag2].each do |tag|
|
||||
GroupTagNotificationDefault.create!(
|
||||
group: group,
|
||||
tag: tag,
|
||||
notification_level: GroupTagNotificationDefault.notification_levels[:watching]
|
||||
)
|
||||
end
|
||||
|
||||
group.watching_tags = [tag2.name]
|
||||
group.save!
|
||||
expect(GroupTagNotificationDefault.lookup(group, :watching).pluck(:tag_id)).to eq([tag2.id])
|
||||
|
||||
group.watching_tags = []
|
||||
group.save!
|
||||
expect(GroupTagNotificationDefault.lookup(group, :watching)).to be_empty
|
||||
end
|
||||
|
||||
it "can apply default notifications for admins group" do
|
||||
group = Group.find(Group::AUTO_GROUPS[:admins])
|
||||
group.tracking_category_ids = [category1.id]
|
||||
group.tracking_tags = [tag1.name]
|
||||
group.save!
|
||||
user.grant_admin!
|
||||
expect(CategoryUser.lookup(user, :tracking).pluck(:category_id)).to eq([category1.id])
|
||||
expect(TagUser.lookup(user, :tracking).pluck(:tag_id)).to eq([tag1.id])
|
||||
end
|
||||
|
||||
it "can apply default notifications for staff group" do
|
||||
group = Group.find(Group::AUTO_GROUPS[:staff])
|
||||
group.tracking_category_ids = [category1.id]
|
||||
group.tracking_tags = [tag1.name]
|
||||
group.save!
|
||||
user.grant_admin!
|
||||
expect(CategoryUser.lookup(user, :tracking).pluck(:category_id)).to eq([category1.id])
|
||||
expect(TagUser.lookup(user, :tracking).pluck(:tag_id)).to eq([tag1.id])
|
||||
end
|
||||
|
||||
it "can apply default notifications from two automatic groups" do
|
||||
staff = Group.find(Group::AUTO_GROUPS[:staff])
|
||||
staff.tracking_category_ids = [category1.id]
|
||||
staff.tracking_tags = [tag1.name]
|
||||
staff.save!
|
||||
admins = Group.find(Group::AUTO_GROUPS[:admins])
|
||||
admins.tracking_category_ids = [category2.id]
|
||||
admins.tracking_tags = [tag2.name]
|
||||
admins.save!
|
||||
user.grant_admin!
|
||||
expect(CategoryUser.lookup(user, :tracking).pluck(:category_id)).to contain_exactly(category1.id, category2.id)
|
||||
expect(TagUser.lookup(user, :tracking).pluck(:tag_id)).to contain_exactly(tag1.id, tag2.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -32,4 +32,123 @@ describe GroupUser do
|
|||
expect(gu.notification_level).to eq(NotificationLevels.all[:regular])
|
||||
end
|
||||
|
||||
describe "default category notifications" do
|
||||
let(:group) { Fabricate(:group) }
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:category1) { Fabricate(:category) }
|
||||
let(:category2) { Fabricate(:category) }
|
||||
let(:category3) { Fabricate(:category) }
|
||||
let(:category4) { Fabricate(:category) }
|
||||
|
||||
def levels
|
||||
CategoryUser.notification_levels
|
||||
end
|
||||
|
||||
it "doesn't change anything with no configured defaults" do
|
||||
expect { group.add(user) }.to_not change { CategoryUser.count }
|
||||
end
|
||||
|
||||
it "adds new category notifications" do
|
||||
group.muted_category_ids = [category1.id]
|
||||
group.tracking_category_ids = [category2.id]
|
||||
group.watching_category_ids = [category3.id]
|
||||
group.watching_first_post_category_ids = [category4.id]
|
||||
group.save!
|
||||
expect { group.add(user) }.to change { CategoryUser.count }.by(4)
|
||||
h = CategoryUser.notification_levels_for(Guardian.new(user))
|
||||
expect(h[category1.id]).to eq(levels[:muted])
|
||||
expect(h[category2.id]).to eq(levels[:tracking])
|
||||
expect(h[category3.id]).to eq(levels[:watching])
|
||||
expect(h[category4.id]).to eq(levels[:watching_first_post])
|
||||
end
|
||||
|
||||
it "only upgrades notifications" do
|
||||
CategoryUser.create!(user: user, category_id: category1.id, notification_level: levels[:muted])
|
||||
CategoryUser.create!(user: user, category_id: category2.id, notification_level: levels[:tracking])
|
||||
CategoryUser.create!(user: user, category_id: category3.id, notification_level: levels[:watching_first_post])
|
||||
CategoryUser.create!(user: user, category_id: category4.id, notification_level: levels[:watching])
|
||||
group.watching_first_post_category_ids = [category1.id, category2.id, category3.id, category4.id]
|
||||
group.save!
|
||||
group.add(user)
|
||||
h = CategoryUser.notification_levels_for(Guardian.new(user))
|
||||
expect(h[category1.id]).to eq(levels[:watching_first_post])
|
||||
expect(h[category2.id]).to eq(levels[:watching_first_post])
|
||||
expect(h[category3.id]).to eq(levels[:watching_first_post])
|
||||
expect(h[category4.id]).to eq(levels[:watching])
|
||||
end
|
||||
|
||||
it "merges notifications" do
|
||||
CategoryUser.create!(user: user, category_id: category1.id, notification_level: CategoryUser.notification_levels[:tracking])
|
||||
CategoryUser.create!(user: user, category_id: category2.id, notification_level: CategoryUser.notification_levels[:watching])
|
||||
CategoryUser.create!(user: user, category_id: category4.id, notification_level: CategoryUser.notification_levels[:watching_first_post])
|
||||
group.muted_category_ids = [category3.id]
|
||||
group.tracking_category_ids = [category4.id]
|
||||
group.save!
|
||||
group.add(user)
|
||||
h = CategoryUser.notification_levels_for(Guardian.new(user))
|
||||
expect(h[category1.id]).to eq(levels[:tracking])
|
||||
expect(h[category2.id]).to eq(levels[:watching])
|
||||
expect(h[category3.id]).to eq(levels[:muted])
|
||||
expect(h[category4.id]).to eq(levels[:watching_first_post])
|
||||
end
|
||||
end
|
||||
|
||||
describe "default tag notifications" do
|
||||
let(:group) { Fabricate(:group) }
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:tag1) { Fabricate(:tag) }
|
||||
let(:tag2) { Fabricate(:tag) }
|
||||
let(:tag3) { Fabricate(:tag) }
|
||||
let(:tag4) { Fabricate(:tag) }
|
||||
let(:synonym1) { Fabricate(:tag, target_tag: tag1) }
|
||||
|
||||
def levels
|
||||
TagUser.notification_levels
|
||||
end
|
||||
|
||||
it "doesn't change anything with no configured defaults" do
|
||||
expect { group.add(user) }.to_not change { TagUser.count }
|
||||
end
|
||||
|
||||
it "adds new tag notifications" do
|
||||
group.muted_tags = [synonym1.name]
|
||||
group.tracking_tags = [tag2.name]
|
||||
group.watching_tags = [tag3.name]
|
||||
group.watching_first_post_tags = [tag4.name]
|
||||
group.save!
|
||||
expect { group.add(user) }.to change { TagUser.count }.by(4)
|
||||
expect(TagUser.lookup(user, :muted).pluck(:tag_id)).to eq([tag1.id])
|
||||
expect(TagUser.lookup(user, :tracking).pluck(:tag_id)).to eq([tag2.id])
|
||||
expect(TagUser.lookup(user, :watching).pluck(:tag_id)).to eq([tag3.id])
|
||||
expect(TagUser.lookup(user, :watching_first_post).pluck(:tag_id)).to eq([tag4.id])
|
||||
end
|
||||
|
||||
it "only upgrades notifications" do
|
||||
TagUser.create!(user: user, tag_id: tag1.id, notification_level: levels[:muted])
|
||||
TagUser.create!(user: user, tag_id: tag2.id, notification_level: levels[:tracking])
|
||||
TagUser.create!(user: user, tag_id: tag3.id, notification_level: levels[:watching_first_post])
|
||||
TagUser.create!(user: user, tag_id: tag4.id, notification_level: levels[:watching])
|
||||
group.watching_first_post_tags = [tag1.name, tag2.name, tag3.name, tag4.name]
|
||||
group.save!
|
||||
group.add(user)
|
||||
expect(TagUser.lookup(user, :muted).pluck(:tag_id)).to be_empty
|
||||
expect(TagUser.lookup(user, :tracking).pluck(:tag_id)).to be_empty
|
||||
expect(TagUser.lookup(user, :watching).pluck(:tag_id)).to eq([tag4.id])
|
||||
expect(TagUser.lookup(user, :watching_first_post).pluck(:tag_id)).to contain_exactly(tag1.id, tag2.id, tag3.id)
|
||||
end
|
||||
|
||||
it "merges notifications" do
|
||||
TagUser.create!(user: user, tag_id: tag1.id, notification_level: levels[:tracking])
|
||||
TagUser.create!(user: user, tag_id: tag2.id, notification_level: levels[:watching])
|
||||
TagUser.create!(user: user, tag_id: tag4.id, notification_level: levels[:watching_first_post])
|
||||
group.muted_tags = [tag3.name]
|
||||
group.tracking_tags = [tag2.name]
|
||||
group.save!
|
||||
group.add(user)
|
||||
expect(TagUser.lookup(user, :muted).pluck(:tag_id)).to eq([tag3.id])
|
||||
expect(TagUser.lookup(user, :tracking).pluck(:tag_id)).to eq([tag1.id])
|
||||
expect(TagUser.lookup(user, :watching).pluck(:tag_id)).to eq([tag2.id])
|
||||
expect(TagUser.lookup(user, :watching_first_post).pluck(:tag_id)).to eq([tag4.id])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -615,6 +615,8 @@ describe GroupsController do
|
|||
public_exit: false
|
||||
)
|
||||
end
|
||||
let(:category) { Fabricate(:category) }
|
||||
let(:tag) { Fabricate(:tag) }
|
||||
|
||||
context "custom_fields" do
|
||||
before do
|
||||
|
@ -688,7 +690,9 @@ describe GroupsController do
|
|||
allow_membership_requests: true,
|
||||
membership_request_template: 'testing',
|
||||
default_notification_level: 1,
|
||||
name: 'testing'
|
||||
name: 'testing',
|
||||
tracking_category_ids: [category.id],
|
||||
tracking_tags: [tag.name]
|
||||
}
|
||||
}
|
||||
end.to change { GroupHistory.count }.by(13)
|
||||
|
@ -716,6 +720,8 @@ describe GroupsController do
|
|||
expect(group.primary_group).to eq(false)
|
||||
expect(group.incoming_email).to eq(nil)
|
||||
expect(group.grant_trust_level).to eq(0)
|
||||
expect(group.group_category_notification_defaults.first&.category).to eq(category)
|
||||
expect(group.group_tag_notification_defaults.first&.tag).to eq(tag)
|
||||
end
|
||||
|
||||
it 'should not be allowed to update automatic groups' do
|
||||
|
@ -753,7 +759,9 @@ describe GroupsController do
|
|||
automatic_membership_email_domains: 'test.org',
|
||||
grant_trust_level: 2,
|
||||
visibility_level: 1,
|
||||
members_visibility_level: 3
|
||||
members_visibility_level: 3,
|
||||
tracking_category_ids: [category.id],
|
||||
tracking_tags: [tag.name]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -768,6 +776,8 @@ describe GroupsController do
|
|||
expect(group.members_visibility_level).to eq(3)
|
||||
expect(group.automatic_membership_email_domains).to eq('test.org')
|
||||
expect(group.grant_trust_level).to eq(2)
|
||||
expect(group.group_category_notification_defaults.first&.category).to eq(category)
|
||||
expect(group.group_tag_notification_defaults.first&.tag).to eq(tag)
|
||||
|
||||
expect(Jobs::AutomaticGroupMembership.jobs.first["args"].first["group_id"])
|
||||
.to eq(group.id)
|
||||
|
@ -790,7 +800,9 @@ describe GroupsController do
|
|||
visibility_level: 1,
|
||||
mentionable_level: 1,
|
||||
messageable_level: 1,
|
||||
default_notification_level: 1
|
||||
default_notification_level: 1,
|
||||
tracking_category_ids: [category.id],
|
||||
tracking_tags: [tag.name]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -803,6 +815,8 @@ describe GroupsController do
|
|||
expect(group.mentionable_level).to eq(1)
|
||||
expect(group.messageable_level).to eq(1)
|
||||
expect(group.default_notification_level).to eq(1)
|
||||
expect(group.group_category_notification_defaults.first&.category).to eq(category)
|
||||
expect(group.group_tag_notification_defaults.first&.tag).to eq(tag)
|
||||
end
|
||||
|
||||
it 'triggers a extensibility event' do
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import { acceptance, updateCurrentUser } from "helpers/qunit-helpers";
|
||||
|
||||
acceptance("Managing Group Category Notification Defaults");
|
||||
QUnit.test("As an anonymous user", async assert => {
|
||||
await visit("/g/discourse/manage/categories");
|
||||
|
||||
assert.ok(
|
||||
count(".group-members tr") > 0,
|
||||
"it should redirect to members page for an anonymous user"
|
||||
);
|
||||
});
|
||||
|
||||
acceptance("Managing Group Category Notification Defaults", { loggedIn: true });
|
||||
|
||||
QUnit.test("As an admin", async assert => {
|
||||
await visit("/g/discourse/manage/categories");
|
||||
|
||||
assert.ok(
|
||||
find(".groups-notifications-form .category-selector").length === 4,
|
||||
"it should display category inputs"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("As a group owner", async assert => {
|
||||
updateCurrentUser({ moderator: false, admin: false });
|
||||
|
||||
await visit("/g/discourse/manage/categories");
|
||||
|
||||
assert.ok(
|
||||
find(".groups-notifications-form .category-selector").length === 4,
|
||||
"it should display category inputs"
|
||||
);
|
||||
});
|
|
@ -0,0 +1,33 @@
|
|||
import { acceptance, updateCurrentUser } from "helpers/qunit-helpers";
|
||||
|
||||
acceptance("Managing Group Tag Notification Defaults");
|
||||
QUnit.test("As an anonymous user", async assert => {
|
||||
await visit("/g/discourse/manage/tags");
|
||||
|
||||
assert.ok(
|
||||
count(".group-members tr") > 0,
|
||||
"it should redirect to members page for an anonymous user"
|
||||
);
|
||||
});
|
||||
|
||||
acceptance("Managing Group Tag Notification Defaults", { loggedIn: true });
|
||||
|
||||
QUnit.test("As an admin", async assert => {
|
||||
await visit("/g/discourse/manage/tags");
|
||||
|
||||
assert.ok(
|
||||
find(".groups-notifications-form .tag-chooser").length === 4,
|
||||
"it should display tag inputs"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("As a group owner", async assert => {
|
||||
updateCurrentUser({ moderator: false, admin: false });
|
||||
|
||||
await visit("/g/discourse/manage/tags");
|
||||
|
||||
assert.ok(
|
||||
find(".groups-notifications-form .tag-chooser").length === 4,
|
||||
"it should display tag inputs"
|
||||
);
|
||||
});
|
Loading…
Reference in New Issue