FEATURE: whispers available for groups (#17170)
Before, whispers were only available for staff members. Config has been changed to allow to configure privileged groups with access to whispers. Post migration was added to move from the old setting into the new one. I considered having a boolean column `whisperer` on user model similar to `admin/moderator` for performance reason. Finally, I decided to keep looking for groups as queries are only done for current user and didn't notice any N+1 queries.
This commit is contained in:
parent
f44eb13236
commit
09932738e5
|
@ -233,6 +233,7 @@ export default Controller.extend({
|
|||
},
|
||||
|
||||
isStaffUser: reads("currentUser.staff"),
|
||||
whisperer: reads("currentUser.whisperer"),
|
||||
|
||||
canUnlistTopic: and("model.creatingTopic", "isStaffUser"),
|
||||
|
||||
|
@ -289,12 +290,12 @@ export default Controller.extend({
|
|||
return SAVE_LABELS[modelAction];
|
||||
},
|
||||
|
||||
@discourseComputed("isStaffUser", "model.action")
|
||||
canWhisper(isStaffUser, modelAction) {
|
||||
@discourseComputed("whisperer", "model.action")
|
||||
canWhisper(whisperer, modelAction) {
|
||||
return (
|
||||
this.siteSettings.enable_whispers &&
|
||||
isStaffUser &&
|
||||
Composer.REPLY === modelAction
|
||||
Composer.REPLY === modelAction &&
|
||||
whisperer
|
||||
);
|
||||
},
|
||||
|
||||
|
|
|
@ -19,7 +19,11 @@ import userFixtures from "discourse/tests/fixtures/user-fixtures";
|
|||
import { cloneJSON } from "discourse-common/lib/object";
|
||||
|
||||
acceptance("Composer Actions", function (needs) {
|
||||
needs.user();
|
||||
needs.user({
|
||||
id: 5,
|
||||
username: "kris",
|
||||
whisperer: true,
|
||||
});
|
||||
needs.settings({
|
||||
prioritize_username_in_ux: true,
|
||||
display_name_on_post: false,
|
||||
|
@ -78,7 +82,8 @@ acceptance("Composer Actions", function (needs) {
|
|||
);
|
||||
});
|
||||
|
||||
test("replying to post - toggle_whisper", async function (assert) {
|
||||
test("replying to post - toggle_whisper for whisperers", async function (assert) {
|
||||
updateCurrentUser({ admin: false, moderator: false });
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
|
||||
await visit("/t/internationalization-localization/280");
|
||||
|
@ -346,7 +351,13 @@ acceptance("Composer Actions", function (needs) {
|
|||
test("replying to post as TL3 user", async function (assert) {
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
|
||||
updateCurrentUser({ moderator: false, admin: false, trust_level: 3 });
|
||||
updateCurrentUser({
|
||||
moderator: false,
|
||||
admin: false,
|
||||
trust_level: 3,
|
||||
whisperer: false,
|
||||
groups: [{ id: 13, name: "tl3_group" }],
|
||||
});
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("article#post_3 button.reply");
|
||||
await composerActions.expand();
|
||||
|
@ -364,7 +375,13 @@ acceptance("Composer Actions", function (needs) {
|
|||
test("replying to post as TL4 user", async function (assert) {
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
|
||||
updateCurrentUser({ moderator: false, admin: false, trust_level: 4 });
|
||||
updateCurrentUser({
|
||||
moderator: false,
|
||||
admin: false,
|
||||
trust_level: 4,
|
||||
whisperer: false,
|
||||
groups: [{ id: 13, name: "tl4_group" }],
|
||||
});
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("article#post_3 button.reply");
|
||||
await composerActions.expand();
|
||||
|
|
|
@ -26,8 +26,14 @@ import { Promise } from "rsvp";
|
|||
import sinon from "sinon";
|
||||
|
||||
acceptance("Composer", function (needs) {
|
||||
needs.user();
|
||||
needs.settings({ enable_whispers: true });
|
||||
needs.user({
|
||||
id: 5,
|
||||
username: "kris",
|
||||
whisperer: true,
|
||||
});
|
||||
needs.settings({
|
||||
enable_whispers: true,
|
||||
});
|
||||
needs.site({ can_tag_topics: true });
|
||||
needs.pretender((server, helper) => {
|
||||
server.post("/uploads/lookup-urls", () => {
|
||||
|
@ -455,7 +461,7 @@ acceptance("Composer", function (needs) {
|
|||
);
|
||||
});
|
||||
|
||||
test("Composer can toggle whispers", async function (assert) {
|
||||
test("Composer can toggle whispers when whisperer user", async function (assert) {
|
||||
const menu = selectKit(".toolbar-popup-menu-options");
|
||||
|
||||
await visit("/t/this-is-a-test-topic/9");
|
||||
|
|
|
@ -1257,7 +1257,7 @@ class TopicsController < ApplicationController
|
|||
topic_query.options[:limit] = false
|
||||
topics = topic_query.filter_private_messages_unread(current_user, filter)
|
||||
else
|
||||
topics = TopicQuery.unread_filter(topic_query.joined_topic_user, staff: guardian.is_staff?).listable_topics
|
||||
topics = TopicQuery.unread_filter(topic_query.joined_topic_user, whisperer: guardian.is_whisperer?).listable_topics
|
||||
topics = TopicQuery.tracked_filter(topics, current_user.id) if params[:tracked].to_s == "true"
|
||||
|
||||
if params[:category_id]
|
||||
|
|
|
@ -18,6 +18,17 @@ module Roleable
|
|||
!staff?
|
||||
end
|
||||
|
||||
def whisperer?
|
||||
@whisperer ||= begin
|
||||
return false if !SiteSetting.enable_whispers?
|
||||
return true if staff?
|
||||
whispers_allowed_group_ids = SiteSetting.whispers_allowed_group_ids
|
||||
return false if whispers_allowed_group_ids.blank?
|
||||
return true if whispers_allowed_group_ids.include?(primary_group_id)
|
||||
group_users&.exists?(group_id: whispers_allowed_group_ids)
|
||||
end
|
||||
end
|
||||
|
||||
def grant_moderation!
|
||||
return if moderator
|
||||
set_permission('moderator', true)
|
||||
|
@ -61,6 +72,11 @@ module Roleable
|
|||
end
|
||||
end
|
||||
|
||||
def reload(options = nil)
|
||||
@whisperer = nil
|
||||
super(options)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def auto_approve_user
|
||||
|
|
|
@ -12,7 +12,7 @@ module TopicTrackingStatePublishable
|
|||
notification_level: nil)
|
||||
|
||||
highest_post_number = DB.query_single(
|
||||
"SELECT #{user.staff? ? "highest_staff_post_number" : "highest_post_number"} FROM topics WHERE id = ?",
|
||||
"SELECT #{user.whisperer? ? "highest_staff_post_number" : "highest_post_number"} FROM topics WHERE id = ?",
|
||||
topic_id
|
||||
).first
|
||||
|
||||
|
|
|
@ -24,7 +24,9 @@ class GroupUser < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def self.update_first_unread_pm(last_seen, limit: 10_000)
|
||||
DB.exec(<<~SQL, archetype: Archetype.private_message, last_seen: last_seen, limit: limit, now: 10.minutes.ago)
|
||||
whisperers_group_ids = SiteSetting.whispers_allowed_group_ids
|
||||
|
||||
DB.exec(<<~SQL, archetype: Archetype.private_message, last_seen: last_seen, limit: limit, now: 10.minutes.ago, whisperers_group_ids: whisperers_group_ids)
|
||||
UPDATE group_users gu
|
||||
SET first_unread_pm_at = Y.min_date
|
||||
FROM (
|
||||
|
@ -51,7 +53,7 @@ class GroupUser < ActiveRecord::Base
|
|||
WHERE t.deleted_at IS NULL
|
||||
AND t.archetype = :archetype
|
||||
AND tu.last_read_post_number < CASE
|
||||
WHEN u.admin OR u.moderator
|
||||
WHEN u.admin OR u.moderator #{whisperers_group_ids.present? ? 'OR gu2.group_id IN (:whisperers_group_ids)' : ''}
|
||||
THEN t.highest_staff_post_number
|
||||
ELSE t.highest_post_number
|
||||
END
|
||||
|
|
|
@ -60,7 +60,7 @@ class PostTiming < ActiveRecord::Base
|
|||
|
||||
def self.destroy_last_for(user, topic_id: nil, topic: nil)
|
||||
topic ||= Topic.find(topic_id)
|
||||
post_number = user.staff? ? topic.highest_staff_post_number : topic.highest_post_number
|
||||
post_number = user.whisperer? ? topic.highest_staff_post_number : topic.highest_post_number
|
||||
|
||||
last_read = post_number - 1
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ class PrivateMessageTopicTrackingState
|
|||
SQL
|
||||
|
||||
<<~SQL
|
||||
#{TopicTrackingState.unread_filter_sql(staff: user.staff?)}
|
||||
#{TopicTrackingState.unread_filter_sql(whisperer: user.whisperer?)}
|
||||
#{first_unread_pm_at ? "AND topics.updated_at > '#{first_unread_pm_at}'" : ""}
|
||||
SQL
|
||||
end
|
||||
|
@ -79,7 +79,7 @@ class PrivateMessageTopicTrackingState
|
|||
u.id AS user_id,
|
||||
last_read_post_number,
|
||||
tu.notification_level,
|
||||
#{TopicTrackingState.highest_post_number_column_select(user.staff?)},
|
||||
#{TopicTrackingState.highest_post_number_column_select(user.whisperer?)},
|
||||
ARRAY(SELECT group_id FROM topic_allowed_groups WHERE topic_allowed_groups.topic_id = topics.id) AS group_ids
|
||||
FROM topics
|
||||
JOIN users u on u.id = #{user.id.to_i}
|
||||
|
|
|
@ -191,6 +191,14 @@ class SiteSetting < ActiveRecord::Base
|
|||
SiteSetting::Upload
|
||||
end
|
||||
|
||||
def self.whispers_allowed_group_ids
|
||||
if SiteSetting.enable_whispers && SiteSetting.whispers_allowed_groups.present?
|
||||
SiteSetting.whispers_allowed_groups.split("|").map(&:to_i)
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def self.require_invite_code
|
||||
invite_code.present?
|
||||
end
|
||||
|
|
|
@ -404,7 +404,7 @@ class Topic < ActiveRecord::Base
|
|||
types = Post.types
|
||||
result = [types[:regular]]
|
||||
result += [types[:moderator_action], types[:small_action]] if include_moderator_actions
|
||||
result << types[:whisper] if viewed_by&.staff?
|
||||
result << types[:whisper] if viewed_by&.whisperer?
|
||||
result
|
||||
end
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ class TopicTrackingState
|
|||
publish_read(topic.id, 1, topic.user)
|
||||
end
|
||||
|
||||
def self.publish_latest(topic, staff_only = false)
|
||||
def self.publish_latest(topic, whisper = false)
|
||||
return unless topic.regular?
|
||||
|
||||
tag_ids, tags = nil
|
||||
|
@ -89,8 +89,8 @@ class TopicTrackingState
|
|||
end
|
||||
|
||||
group_ids =
|
||||
if staff_only
|
||||
[Group::AUTO_GROUPS[:staff]]
|
||||
if whisper
|
||||
[Group::AUTO_GROUPS[:staff], *SiteSetting.whispers_allowed_group_ids]
|
||||
else
|
||||
topic.category && topic.category.secure_group_ids
|
||||
end
|
||||
|
@ -151,7 +151,7 @@ class TopicTrackingState
|
|||
|
||||
group_ids =
|
||||
if post.post_type == Post.types[:whisper]
|
||||
[Group::AUTO_GROUPS[:staff]]
|
||||
[Group::AUTO_GROUPS[:staff], *SiteSetting.whispers_allowed_group_ids]
|
||||
else
|
||||
post.topic.category && post.topic.category.secure_group_ids
|
||||
end
|
||||
|
@ -253,8 +253,8 @@ class TopicTrackingState
|
|||
" AND dismissed_topic_users.id IS NULL"
|
||||
end
|
||||
|
||||
def self.unread_filter_sql(staff: false)
|
||||
TopicQuery.unread_filter(Topic, staff: staff).where_clause.ast.to_sql
|
||||
def self.unread_filter_sql(whisperer: false)
|
||||
TopicQuery.unread_filter(Topic, whisperer: whisperer).where_clause.ast.to_sql
|
||||
end
|
||||
|
||||
def self.treat_as_new_topic_clause
|
||||
|
@ -319,6 +319,7 @@ class TopicTrackingState
|
|||
skip_order: true,
|
||||
staff: user.staff?,
|
||||
admin: user.admin?,
|
||||
whisperer: user.whisperer?,
|
||||
user: user,
|
||||
muted_tag_ids: tag_ids
|
||||
)
|
||||
|
@ -332,6 +333,7 @@ class TopicTrackingState
|
|||
staff: user.staff?,
|
||||
filter_old_unread: true,
|
||||
admin: user.admin?,
|
||||
whisperer: user.whisperer?,
|
||||
user: user,
|
||||
muted_tag_ids: tag_ids
|
||||
)
|
||||
|
@ -369,6 +371,7 @@ class TopicTrackingState
|
|||
skip_order: false,
|
||||
staff: false,
|
||||
admin: false,
|
||||
whisperer: false,
|
||||
select: nil,
|
||||
custom_state_filter: nil,
|
||||
additional_join_sql: nil
|
||||
|
@ -377,7 +380,7 @@ class TopicTrackingState
|
|||
if skip_unread
|
||||
"1=0"
|
||||
else
|
||||
unread_filter_sql(staff: staff)
|
||||
unread_filter_sql(whisperer: whisperer)
|
||||
end
|
||||
|
||||
filter_old_unread_sql =
|
||||
|
@ -399,7 +402,7 @@ class TopicTrackingState
|
|||
u.id as user_id,
|
||||
topics.created_at,
|
||||
topics.updated_at,
|
||||
#{highest_post_number_column_select(staff)},
|
||||
#{highest_post_number_column_select(whisperer)},
|
||||
last_read_post_number,
|
||||
c.id as category_id,
|
||||
tu.notification_level,
|
||||
|
@ -497,8 +500,8 @@ class TopicTrackingState
|
|||
sql
|
||||
end
|
||||
|
||||
def self.highest_post_number_column_select(staff)
|
||||
"#{staff ? "topics.highest_staff_post_number AS highest_post_number" : "topics.highest_post_number"}"
|
||||
def self.highest_post_number_column_select(whisperer)
|
||||
"#{whisperer ? "topics.highest_staff_post_number AS highest_post_number" : "topics.highest_post_number"}"
|
||||
end
|
||||
|
||||
def self.publish_read_indicator_on_write(topic_id, last_read_post_number, user_id)
|
||||
|
|
|
@ -19,7 +19,9 @@ class UserStat < ActiveRecord::Base
|
|||
UPDATE_UNREAD_USERS_LIMIT = 10_000
|
||||
|
||||
def self.update_first_unread_pm(last_seen, limit: UPDATE_UNREAD_USERS_LIMIT)
|
||||
DB.exec(<<~SQL, archetype: Archetype.private_message, now: UPDATE_UNREAD_MINUTES_AGO.minutes.ago, last_seen: last_seen, limit: limit)
|
||||
whisperers_group_ids = SiteSetting.whispers_allowed_group_ids
|
||||
|
||||
DB.exec(<<~SQL, archetype: Archetype.private_message, now: UPDATE_UNREAD_MINUTES_AGO.minutes.ago, last_seen: last_seen, limit: limit, whisperers_group_ids: whisperers_group_ids)
|
||||
UPDATE user_stats us
|
||||
SET first_unread_pm_at = COALESCE(Z.min_date, :now)
|
||||
FROM (
|
||||
|
@ -35,10 +37,11 @@ class UserStat < ActiveRecord::Base
|
|||
INNER JOIN topics t ON t.id = tau.topic_id
|
||||
INNER JOIN users u ON u.id = tau.user_id
|
||||
LEFT JOIN topic_users tu ON t.id = tu.topic_id AND tu.user_id = tau.user_id
|
||||
#{whisperers_group_ids.present? ? 'LEFT JOIN group_users gu ON gu.group_id IN (:whisperers_group_ids) AND gu.user_id = u.id' : ''}
|
||||
WHERE t.deleted_at IS NULL
|
||||
AND t.archetype = :archetype
|
||||
AND tu.last_read_post_number < CASE
|
||||
WHEN u.admin OR u.moderator
|
||||
WHEN u.admin OR u.moderator #{whisperers_group_ids.present? ? 'OR gu.id IS NOT NULL' : ''}
|
||||
THEN t.highest_staff_post_number
|
||||
ELSE t.highest_post_number
|
||||
END
|
||||
|
|
|
@ -12,6 +12,7 @@ class CurrentUserSerializer < BasicUserSerializer
|
|||
:notification_channel_position,
|
||||
:moderator?,
|
||||
:staff?,
|
||||
:whisperer?,
|
||||
:title,
|
||||
:any_posts,
|
||||
:enable_quoting,
|
||||
|
|
|
@ -54,7 +54,7 @@ class ListableTopicSerializer < BasicTopicSerializer
|
|||
end
|
||||
|
||||
def highest_post_number
|
||||
(scope.is_staff? && object.highest_staff_post_number) || object.highest_post_number
|
||||
(scope.is_whisperer? && object.highest_staff_post_number) || object.highest_post_number
|
||||
end
|
||||
|
||||
def liked
|
||||
|
|
|
@ -48,7 +48,7 @@ class UserPostTopicBookmarkBaseSerializer < UserBookmarkBaseSerializer
|
|||
end
|
||||
|
||||
def highest_post_number
|
||||
scope.is_staff? ? topic.highest_staff_post_number : topic.highest_post_number
|
||||
scope.is_whisperer? ? topic.highest_staff_post_number : topic.highest_post_number
|
||||
end
|
||||
|
||||
def last_read_post_number
|
||||
|
|
|
@ -1683,6 +1683,7 @@ en:
|
|||
enable_badges: "Enable the badge system"
|
||||
max_favorite_badges: "Maximum number of badges that user can select"
|
||||
enable_whispers: "Allow staff private communication within topics."
|
||||
whispers_allowed_groups: "Allow private communication within topics for members of specified groups."
|
||||
|
||||
allow_index_in_robots_txt: "Specify in robots.txt that this site is allowed to be indexed by web search engines. In exceptional cases you can permanently <a href='%{base_path}/admin/customize/robots'>override robots.txt</a>."
|
||||
blocked_email_domains: "A pipe-delimited list of email domains that users are not allowed to register accounts with. Example: mailinator.com|trashmail.net"
|
||||
|
|
|
@ -323,6 +323,13 @@ basic:
|
|||
enable_whispers:
|
||||
client: true
|
||||
default: false
|
||||
whispers_allowed_groups:
|
||||
client: true
|
||||
type: group_list
|
||||
list_type: compact
|
||||
default: ""
|
||||
allow_any: false
|
||||
refresh: true
|
||||
enable_bookmarks_with_reminders:
|
||||
client: true
|
||||
default: true
|
||||
|
|
|
@ -56,6 +56,9 @@ class Guardian
|
|||
def topic_create_allowed_category_ids
|
||||
[]
|
||||
end
|
||||
def groups
|
||||
[]
|
||||
end
|
||||
def has_trust_level?(level)
|
||||
false
|
||||
end
|
||||
|
@ -65,6 +68,9 @@ class Guardian
|
|||
def email
|
||||
nil
|
||||
end
|
||||
def whisperer?
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :request
|
||||
|
@ -99,6 +105,10 @@ class Guardian
|
|||
@user.moderator?
|
||||
end
|
||||
|
||||
def is_whisperer?
|
||||
@user.whisperer?
|
||||
end
|
||||
|
||||
def is_category_group_moderator?(category)
|
||||
return false unless category
|
||||
return false unless authenticated?
|
||||
|
|
|
@ -36,11 +36,11 @@ module TopicGuardian
|
|||
end
|
||||
|
||||
def can_create_whisper?
|
||||
is_staff? && SiteSetting.enable_whispers?
|
||||
@user.whisperer?
|
||||
end
|
||||
|
||||
def can_see_whispers?(_topic)
|
||||
is_staff?
|
||||
def can_see_whispers?(_topic = nil)
|
||||
@user.whisperer?
|
||||
end
|
||||
|
||||
def can_publish_topic?(topic, category)
|
||||
|
|
|
@ -336,8 +336,8 @@ class TopicQuery
|
|||
.where("COALESCE(tu.notification_level, :tracking) >= :tracking", tracking: TopicUser.notification_levels[:tracking])
|
||||
end
|
||||
|
||||
def self.unread_filter(list, staff: false)
|
||||
col_name = staff ? "highest_staff_post_number" : "highest_post_number"
|
||||
def self.unread_filter(list, whisperer: false)
|
||||
col_name = whisperer ? "highest_staff_post_number" : "highest_post_number"
|
||||
|
||||
list
|
||||
.where("tu.last_read_post_number < topics.#{col_name}")
|
||||
|
@ -474,7 +474,7 @@ class TopicQuery
|
|||
|
||||
def unseen_results(options = {})
|
||||
result = default_results(options)
|
||||
result = unseen_filter(result, @user.first_seen_at, @user.staff?) if @user
|
||||
result = unseen_filter(result, @user.first_seen_at, @user.whisperer?) if @user
|
||||
result = remove_muted(result, @user, options)
|
||||
result = apply_shared_drafts(result, get_category_id(options[:category]), options)
|
||||
|
||||
|
@ -489,7 +489,7 @@ class TopicQuery
|
|||
def unread_results(options = {})
|
||||
result = TopicQuery.unread_filter(
|
||||
default_results(options.reverse_merge(unordered: true)),
|
||||
staff: @user&.staff?)
|
||||
whisperer: @user&.whisperer?)
|
||||
.order('CASE WHEN topics.user_id = tu.user_id THEN 1 ELSE 2 END')
|
||||
|
||||
if @user
|
||||
|
@ -948,7 +948,7 @@ class TopicQuery
|
|||
def unread_messages(params)
|
||||
query = TopicQuery.unread_filter(
|
||||
messages_for_groups_or_user(params[:my_group_ids]),
|
||||
staff: @user.staff?
|
||||
whisperer: @user.whisperer?
|
||||
)
|
||||
|
||||
first_unread_pm_at =
|
||||
|
@ -1084,10 +1084,10 @@ class TopicQuery
|
|||
|
||||
private
|
||||
|
||||
def unseen_filter(list, user_first_seen_at, staff)
|
||||
def unseen_filter(list, user_first_seen_at, whisperer)
|
||||
list = list.where("topics.bumped_at >= ?", user_first_seen_at)
|
||||
|
||||
col_name = staff ? "highest_staff_post_number" : "highest_post_number"
|
||||
col_name = whisperer ? "highest_staff_post_number" : "highest_post_number"
|
||||
list.where("tu.last_read_post_number IS NULL OR tu.last_read_post_number < topics.#{col_name}")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -165,7 +165,7 @@ class TopicQuery
|
|||
def filter_private_messages_unread(user, type)
|
||||
list = TopicQuery.unread_filter(
|
||||
private_messages_for(user, type),
|
||||
staff: user.staff?
|
||||
whisperer: user.whisperer?
|
||||
)
|
||||
|
||||
first_unread_pm_at =
|
||||
|
|
|
@ -69,7 +69,7 @@ class TopicsBulkAction
|
|||
end
|
||||
|
||||
def dismiss_posts
|
||||
highest_number_source_column = @user.staff? ? 'highest_staff_post_number' : 'highest_post_number'
|
||||
highest_number_source_column = @user.whisperer? ? 'highest_staff_post_number' : 'highest_post_number'
|
||||
sql = <<~SQL
|
||||
UPDATE topic_users tu
|
||||
SET last_read_post_number = t.#{highest_number_source_column}
|
||||
|
|
|
@ -14,7 +14,7 @@ class Unread
|
|||
return 0 if @topic_user.last_read_post_number.blank?
|
||||
return 0 if do_not_notify?(@topic_user.notification_level)
|
||||
|
||||
highest_post_number = @guardian.is_staff? ? @topic.highest_staff_post_number : @topic.highest_post_number
|
||||
highest_post_number = @guardian.is_whisperer? ? @topic.highest_staff_post_number : @topic.highest_post_number
|
||||
|
||||
return 0 if @topic_user.last_read_post_number > highest_post_number
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ export default Component.extend({
|
|||
|
||||
@discourseComputed("model.topic.id", "isReply", "isWhisper")
|
||||
whisperChannelName(topicId, isReply, isWhisper) {
|
||||
if (topicId && this.currentUser.staff && (isReply || isWhisper)) {
|
||||
if (topicId && this.currentUser.whisperer && (isReply || isWhisper)) {
|
||||
return `/discourse-presence/whisper/${topicId}`;
|
||||
}
|
||||
},
|
||||
|
|
|
@ -15,7 +15,7 @@ import User from "discourse/models/user";
|
|||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
|
||||
acceptance("Discourse Presence Plugin", function (needs) {
|
||||
needs.user();
|
||||
needs.user({ whisperer: true });
|
||||
needs.settings({ enable_whispers: true });
|
||||
|
||||
test("Doesn't break topic creation", async function (assert) {
|
||||
|
|
|
@ -119,7 +119,10 @@ RSpec.describe BookmarkQuery do
|
|||
context "for a whispered post" do
|
||||
before do
|
||||
post_bookmark.bookmarkable.update(post_type: Post.types[:whisper])
|
||||
SiteSetting.enable_whispers = true
|
||||
end
|
||||
fab!(:whisperers_group) { Fabricate(:group) }
|
||||
|
||||
context "when the user is moderator" do
|
||||
it "does return the whispered post" do
|
||||
user.update!(moderator: true)
|
||||
|
@ -132,6 +135,13 @@ RSpec.describe BookmarkQuery do
|
|||
expect(bookmark_query.list_all.count).to eq(3)
|
||||
end
|
||||
end
|
||||
context "when the user is a member of whisperers group" do
|
||||
it "returns the whispered post" do
|
||||
SiteSetting.whispers_allowed_groups = "#{whisperers_group.id}"
|
||||
user.update!(groups: [whisperers_group])
|
||||
expect(bookmark_query.list_all.count).to eq(3)
|
||||
end
|
||||
end
|
||||
context "when the user is not staff" do
|
||||
it "does not return the whispered post" do
|
||||
expect(bookmark_query.list_all.count).to eq(2)
|
||||
|
|
|
@ -893,6 +893,8 @@ describe Guardian do
|
|||
end
|
||||
|
||||
it 'respects whispers' do
|
||||
SiteSetting.enable_whispers = true
|
||||
SiteSetting.whispers_allowed_groups = "#{group.id}"
|
||||
regular_post = post
|
||||
whisper_post = Fabricate.build(:post, post_type: Post.types[:whisper])
|
||||
|
||||
|
@ -916,6 +918,10 @@ describe Guardian do
|
|||
admin_guardian = Guardian.new(Fabricate.build(:admin))
|
||||
expect(admin_guardian.can_see?(regular_post)).to eq(true)
|
||||
expect(admin_guardian.can_see?(whisper_post)).to eq(true)
|
||||
|
||||
whisperer_guardian = Guardian.new(Fabricate(:user, groups: [group]))
|
||||
expect(whisperer_guardian.can_see?(regular_post)).to eq(true)
|
||||
expect(whisperer_guardian.can_see?(whisper_post)).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -656,7 +656,7 @@ describe PostDestroyer do
|
|||
|
||||
it 'should not set Topic#last_post_user_id to a whisperer' do
|
||||
post_1 = create_post(topic: post.topic, user: moderator)
|
||||
whisper_1 = create_post(topic: post.topic, user: Fabricate(:user), post_type: Post.types[:whisper])
|
||||
create_post(topic: post.topic, user: Fabricate(:user), post_type: Post.types[:whisper])
|
||||
whisper_2 = create_post(topic: post.topic, user: Fabricate(:user), post_type: Post.types[:whisper])
|
||||
|
||||
PostDestroyer.new(admin, whisper_2).destroy
|
||||
|
|
|
@ -910,7 +910,12 @@ describe Search do
|
|||
])
|
||||
end
|
||||
|
||||
it 'allows staff to search for whispers' do
|
||||
it 'allows staff and members of whisperers group to search for whispers' do
|
||||
whisperers_group = Fabricate(:group)
|
||||
user = Fabricate(:user)
|
||||
SiteSetting.enable_whispers = true
|
||||
SiteSetting.whispers_allowed_groups = "#{whisperers_group.id}"
|
||||
|
||||
post.update!(post_type: Post.types[:whisper], raw: 'this is a tiger')
|
||||
|
||||
results = Search.execute('tiger')
|
||||
|
@ -920,6 +925,13 @@ describe Search do
|
|||
results = Search.execute('tiger', guardian: Guardian.new(admin))
|
||||
|
||||
expect(results.posts).to eq([post])
|
||||
|
||||
results = Search.execute('tiger', guardian: Guardian.new(user))
|
||||
expect(results.posts).to eq([])
|
||||
|
||||
user.groups << whisperers_group
|
||||
results = Search.execute('tiger', guardian: Guardian.new(user))
|
||||
expect(results.posts).to eq([post])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -834,6 +834,9 @@ describe TopicQuery do
|
|||
end
|
||||
|
||||
context 'with whispers' do
|
||||
before do
|
||||
SiteSetting.enable_whispers = true
|
||||
end
|
||||
|
||||
it 'correctly shows up in unread for staff' do
|
||||
|
||||
|
|
|
@ -343,6 +343,7 @@ RSpec.describe TopicView do
|
|||
|
||||
context '.post_counts_by_user' do
|
||||
it 'returns the two posters with their appropriate counts' do
|
||||
SiteSetting.enable_whispers = true
|
||||
Fabricate(:post, topic: topic, user: evil_trout, post_type: Post.types[:whisper])
|
||||
# Should not be counted
|
||||
Fabricate(:post, topic: topic, user: evil_trout, post_type: Post.types[:whisper], action_code: 'assign')
|
||||
|
@ -480,6 +481,7 @@ RSpec.describe TopicView do
|
|||
|
||||
context 'whispers' do
|
||||
it "handles their visibility properly" do
|
||||
SiteSetting.enable_whispers = true
|
||||
p1 = Fabricate(:post, topic: topic, user: evil_trout)
|
||||
p2 = Fabricate(:post, topic: topic, user: evil_trout, post_type: Post.types[:whisper])
|
||||
p3 = Fabricate(:post, topic: topic, user: evil_trout)
|
||||
|
|
|
@ -95,6 +95,7 @@ describe TopicsBulkAction do
|
|||
|
||||
context "when the highest_staff_post_number is > highest_post_number for a topic (e.g. whisper is last post)" do
|
||||
it "dismisses posts" do
|
||||
SiteSetting.enable_whispers = true
|
||||
post1 = create_post(user: user)
|
||||
p = create_post(topic_id: post1.topic_id)
|
||||
create_post(topic_id: post1.topic_id)
|
||||
|
|
|
@ -4,8 +4,9 @@ require 'unread'
|
|||
|
||||
describe Unread do
|
||||
|
||||
let (:user) { Fabricate.build(:user, id: 1) }
|
||||
let (:topic) do
|
||||
let(:whisperers_group) { Fabricate(:group) }
|
||||
let(:user) { Fabricate(:user, id: 1, groups: [whisperers_group]) }
|
||||
let(:topic) do
|
||||
Fabricate.build(:topic,
|
||||
posts_count: 13,
|
||||
highest_staff_post_number: 15,
|
||||
|
@ -26,6 +27,7 @@ describe Unread do
|
|||
|
||||
describe 'staff counts' do
|
||||
it 'should correctly return based on staff post number' do
|
||||
SiteSetting.enable_whispers = true
|
||||
user.admin = true
|
||||
|
||||
topic_user.last_read_post_number = 13
|
||||
|
@ -46,11 +48,20 @@ describe Unread do
|
|||
end
|
||||
|
||||
it 'returns the right unread posts for a staff user' do
|
||||
SiteSetting.enable_whispers = true
|
||||
SiteSetting.whispers_allowed_groups = ""
|
||||
user.admin = true
|
||||
topic_user.last_read_post_number = 10
|
||||
expect(unread.unread_posts).to eq(5)
|
||||
end
|
||||
|
||||
it 'returns the right unread posts for a whisperer user' do
|
||||
SiteSetting.enable_whispers = true
|
||||
SiteSetting.whispers_allowed_groups = "#{whisperers_group.id}"
|
||||
topic_user.last_read_post_number = 10
|
||||
expect(unread.unread_posts).to eq(5)
|
||||
end
|
||||
|
||||
it 'should have 0 unread posts if the user has read more posts than exist (deleted)' do
|
||||
topic_user.last_read_post_number = 14
|
||||
expect(unread.unread_posts).to eq(0)
|
||||
|
|
|
@ -65,6 +65,7 @@ describe PrivateMessageTopicTrackingState do
|
|||
end
|
||||
|
||||
it 'returns the right tracking state when topics contain whispers' do
|
||||
SiteSetting.enable_whispers = true
|
||||
TopicUser.find_by(user: user_2, topic: private_message).update!(
|
||||
last_read_post_number: 1
|
||||
)
|
||||
|
|
|
@ -5,7 +5,8 @@ describe Topic do
|
|||
let(:now) { Time.zone.local(2013, 11, 20, 8, 0) }
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
fab!(:user1) { Fabricate(:user) }
|
||||
fab!(:user2) { Fabricate(:user) }
|
||||
fab!(:whisperers_group) { Fabricate(:group) }
|
||||
fab!(:user2) { Fabricate(:user, groups: [whisperers_group]) }
|
||||
fab!(:moderator) { Fabricate(:moderator) }
|
||||
fab!(:coding_horror) { Fabricate(:coding_horror) }
|
||||
fab!(:evil_trout) { Fabricate(:evil_trout) }
|
||||
|
@ -167,6 +168,11 @@ describe Topic do
|
|||
context '#visible_post_types' do
|
||||
let(:types) { Post.types }
|
||||
|
||||
before do
|
||||
SiteSetting.enable_whispers = true
|
||||
SiteSetting.whispers_allowed_groups = "#{whisperers_group.id}"
|
||||
end
|
||||
|
||||
it "returns the appropriate types for anonymous users" do
|
||||
post_types = Topic.visible_post_types
|
||||
|
||||
|
@ -186,7 +192,16 @@ describe Topic do
|
|||
end
|
||||
|
||||
it "returns the appropriate types for staff users" do
|
||||
post_types = Topic.visible_post_types(Fabricate.build(:moderator))
|
||||
post_types = Topic.visible_post_types(moderator)
|
||||
|
||||
expect(post_types).to include(types[:regular])
|
||||
expect(post_types).to include(types[:moderator_action])
|
||||
expect(post_types).to include(types[:small_action])
|
||||
expect(post_types).to include(types[:whisper])
|
||||
end
|
||||
|
||||
it "returns the appropriate types for whisperer users" do
|
||||
post_types = Topic.visible_post_types(user2)
|
||||
|
||||
expect(post_types).to include(types[:regular])
|
||||
expect(post_types).to include(types[:moderator_action])
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
describe TopicTrackingState do
|
||||
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
fab!(:whisperers_group) { Fabricate(:group) }
|
||||
|
||||
let(:post) do
|
||||
create_post
|
||||
|
@ -25,6 +26,21 @@ describe TopicTrackingState do
|
|||
expect(data["payload"]["archetype"]).to eq(Archetype.default)
|
||||
end
|
||||
|
||||
it "publishes whisper post to staff users and members of whisperers group" do
|
||||
whisperers_group = Fabricate(:group)
|
||||
Fabricate(:user, groups: [whisperers_group])
|
||||
Fabricate(:topic_user_watching, topic: topic, user: user)
|
||||
SiteSetting.enable_whispers = true
|
||||
SiteSetting.whispers_allowed_groups = "#{whisperers_group.id}"
|
||||
post.update!(post_type: Post.types[:whisper])
|
||||
|
||||
message = MessageBus.track_publish("/latest") do
|
||||
TopicTrackingState.publish_latest(post.topic, true)
|
||||
end.first
|
||||
|
||||
expect(message.group_ids).to contain_exactly(whisperers_group.id, Group::AUTO_GROUPS[:staff])
|
||||
end
|
||||
|
||||
describe 'private message' do
|
||||
it 'should not publish any message' do
|
||||
messages = MessageBus.track_publish do
|
||||
|
@ -54,6 +70,7 @@ describe TopicTrackingState do
|
|||
end
|
||||
|
||||
it 'correctly publish read for staff' do
|
||||
SiteSetting.enable_whispers = true
|
||||
create_post(
|
||||
raw: "this is a test post",
|
||||
topic: post.topic,
|
||||
|
@ -118,7 +135,32 @@ describe TopicTrackingState do
|
|||
expect(message.user_ids).to contain_exactly(other_user.id)
|
||||
end
|
||||
|
||||
it "publishes whisper post to staff users and members of whisperers group" do
|
||||
whisperers_group = Fabricate(:group)
|
||||
Fabricate(:topic_user_watching, topic: topic, user: user)
|
||||
SiteSetting.enable_whispers = true
|
||||
SiteSetting.whispers_allowed_groups = "#{whisperers_group.id}"
|
||||
post.update!(post_type: Post.types[:whisper])
|
||||
|
||||
messages = MessageBus.track_publish("/unread") do
|
||||
TopicTrackingState.publish_unread(post)
|
||||
end
|
||||
|
||||
expect(messages).to eq([])
|
||||
|
||||
user.groups << whisperers_group
|
||||
other_user.grant_admin!
|
||||
|
||||
message = MessageBus.track_publish("/unread") do
|
||||
TopicTrackingState.publish_unread(post)
|
||||
end.first
|
||||
|
||||
expect(message.user_ids).to contain_exactly(user.id, other_user.id)
|
||||
expect(message.group_ids).to eq(nil)
|
||||
end
|
||||
|
||||
it "does not publish whisper post to non-staff users" do
|
||||
SiteSetting.enable_whispers = true
|
||||
post.update!(post_type: Post.types[:whisper])
|
||||
|
||||
messages = MessageBus.track_publish("/unread") do
|
||||
|
@ -632,6 +674,7 @@ describe TopicTrackingState do
|
|||
|
||||
describe ".report" do
|
||||
it "correctly reports topics with staff posts" do
|
||||
SiteSetting.enable_whispers = true
|
||||
create_post(
|
||||
raw: "this is a test post",
|
||||
topic: topic,
|
||||
|
|
|
@ -2645,4 +2645,37 @@ RSpec.describe User do
|
|||
expect(result).to be(true)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#whisperer?" do
|
||||
before do
|
||||
SiteSetting.enable_whispers = true
|
||||
end
|
||||
|
||||
it 'returns true for an admin user' do
|
||||
admin = Fabricate.create(:admin)
|
||||
expect(admin.whisperer?).to eq(true)
|
||||
end
|
||||
|
||||
it 'returns false for an admin user when whispers are not enabled' do
|
||||
SiteSetting.enable_whispers = false
|
||||
|
||||
admin = Fabricate.create(:admin)
|
||||
expect(admin.whisperer?).to eq(false)
|
||||
end
|
||||
|
||||
it 'returns true for user belonging to whisperers groups' do
|
||||
group = Fabricate(:group)
|
||||
whisperer = Fabricate(:user)
|
||||
user = Fabricate(:user)
|
||||
SiteSetting.whispers_allowed_groups = "#{group.id}"
|
||||
|
||||
expect(whisperer.whisperer?).to eq(false)
|
||||
expect(user.whisperer?).to eq(false)
|
||||
|
||||
group.add(whisperer)
|
||||
|
||||
expect(whisperer.whisperer?).to eq(true)
|
||||
expect(user.whisperer?).to eq(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3890,6 +3890,7 @@ describe UsersController do
|
|||
end
|
||||
|
||||
it "includes all post types for staff members" do
|
||||
SiteSetting.enable_whispers = true
|
||||
sign_in(admin)
|
||||
|
||||
get "/u/#{admin.username}.json", params: { include_post_count_for: topic.id }
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.describe UserPostBookmarkSerializer do
|
||||
let(:whisperers_group) { Fabricate(:group) }
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:post) { Fabricate(:post, user: user, topic: topic) }
|
||||
let(:topic) { Fabricate(:topic) }
|
||||
let!(:bookmark) { Fabricate(:bookmark, name: 'Test', user: user, bookmarkable: post) }
|
||||
|
||||
it "uses the correct highest_post_number column based on whether the user is staff" do
|
||||
before do
|
||||
SiteSetting.enable_whispers = true
|
||||
SiteSetting.whispers_allowed_groups = "#{whisperers_group.id}"
|
||||
end
|
||||
|
||||
it "uses the correct highest_post_number column based on whether the user is whisperer" do
|
||||
Fabricate(:post, topic: topic)
|
||||
Fabricate(:post, topic: topic)
|
||||
Fabricate(:whisper, topic: topic)
|
||||
|
@ -16,7 +22,7 @@ RSpec.describe UserPostBookmarkSerializer do
|
|||
|
||||
expect(serializer.highest_post_number).to eq(3)
|
||||
|
||||
user.update!(admin: true)
|
||||
user.groups << whisperers_group
|
||||
|
||||
expect(serializer.highest_post_number).to eq(4)
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue