mirror of
https://github.com/discourse/discourse.git
synced 2024-11-22 15:25:35 +08:00
FIX: Base topic details message on current category and tag tracking state (#12937)
The user may have changed their category or tag tracking settings since a topic was tracked/watched based on those settings in the past. In that case we need to alter the reason message we show them otherwise it is very confusing for the end user to be told they are tracking a topic because of a category, when they are no longer tracking that category. For example: "You will see a count of new replies because you are tracking this category." becomes: "You will see a count of new replies because you were tracking this category in the past." To do this, it was necessary to add tag and category tracking info to current user serializer. I improved the serializer code so it only does 3 SQL queries instead of 9 to get the tracking information for tags and categories for the current user.
This commit is contained in:
parent
c792c2b5fe
commit
72648dd576
|
@ -1,6 +1,4 @@
|
|||
import EmberObject from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
import { NotificationLevels } from "discourse/lib/notification-levels";
|
||||
import RestModel from "discourse/models/rest";
|
||||
import User from "discourse/models/user";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
|
@ -9,8 +7,6 @@ import { ajax } from "discourse/lib/ajax";
|
|||
A model representing a Topic's details that aren't always present, such as a list of participants.
|
||||
When showing topics in lists and such this information should not be required.
|
||||
**/
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
|
||||
const TopicDetails = RestModel.extend({
|
||||
loaded: false,
|
||||
|
@ -35,34 +31,6 @@ const TopicDetails = RestModel.extend({
|
|||
this.set("loaded", true);
|
||||
},
|
||||
|
||||
@discourseComputed("notification_level", "notifications_reason_id")
|
||||
notificationReasonText(level, reason) {
|
||||
if (typeof level !== "number") {
|
||||
level = 1;
|
||||
}
|
||||
|
||||
let localeString = `topic.notifications.reasons.${level}`;
|
||||
if (typeof reason === "number") {
|
||||
const tmp = localeString + "_" + reason;
|
||||
// some sane protection for missing translations of edge cases
|
||||
if (I18n.lookup(tmp, { locale: "en" })) {
|
||||
localeString = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
User.currentProp("mailing_list_mode") &&
|
||||
level > NotificationLevels.MUTED
|
||||
) {
|
||||
return I18n.t("topic.notifications.reasons.mailing_list_mode");
|
||||
} else {
|
||||
return I18n.t(localeString, {
|
||||
username: User.currentProp("username_lower"),
|
||||
basePath: getURL(""),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
updateNotifications(level) {
|
||||
return ajax(`/t/${this.get("topic.id")}/notifications`, {
|
||||
type: "POST",
|
||||
|
|
|
@ -3,19 +3,25 @@ import componentTest, {
|
|||
} from "discourse/tests/helpers/component-test";
|
||||
import I18n from "I18n";
|
||||
import Topic from "discourse/models/topic";
|
||||
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
|
||||
import {
|
||||
discourseModule,
|
||||
queryAll,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import hbs from "htmlbars-inline-precompile";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
|
||||
const buildTopic = function (level, archetype = "regular") {
|
||||
const buildTopic = function (opts) {
|
||||
return Topic.create({
|
||||
id: 4563,
|
||||
}).updateFromJson({
|
||||
title: "Qunit Test Topic",
|
||||
details: {
|
||||
notification_level: level,
|
||||
notification_level: opts.level,
|
||||
notifications_reason_id: opts.reason || null,
|
||||
},
|
||||
archetype,
|
||||
archetype: opts.archetype || "regular",
|
||||
category_id: opts.category_id || null,
|
||||
tags: opts.tags || [],
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -40,7 +46,7 @@ discourseModule(
|
|||
`,
|
||||
|
||||
beforeEach() {
|
||||
this.set("topic", buildTopic(1));
|
||||
this.set("topic", buildTopic({ level: 1 }));
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
|
@ -50,7 +56,7 @@ discourseModule(
|
|||
"it has the correct label"
|
||||
);
|
||||
|
||||
await this.set("topic", buildTopic(2));
|
||||
await this.set("topic", buildTopic({ level: 2 }));
|
||||
|
||||
assert.equal(
|
||||
selectKit().header().label(),
|
||||
|
@ -70,7 +76,10 @@ discourseModule(
|
|||
|
||||
beforeEach() {
|
||||
I18n.translations.en.js.topic.notifications.tracking_pm.title = `${originalTranslation} PM`;
|
||||
this.set("topic", buildTopic(2, "private_message"));
|
||||
this.set(
|
||||
"topic",
|
||||
buildTopic({ level: 2, archetype: "private_message" })
|
||||
);
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
|
@ -81,5 +90,194 @@ discourseModule(
|
|||
);
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("notification reason text - user mailing list mode", {
|
||||
template: hbs`
|
||||
{{topic-notifications-button
|
||||
notificationLevel=topic.details.notification_level
|
||||
topic=topic
|
||||
}}
|
||||
`,
|
||||
|
||||
beforeEach() {
|
||||
this.currentUser.set("mailing_list_mode", true);
|
||||
this.set("topic", buildTopic({ level: 2 }));
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
assert.equal(
|
||||
queryAll(".topic-notifications-button .text").text(),
|
||||
I18n.t("topic.notifications.reasons.mailing_list_mode"),
|
||||
"mailing_list_mode enabled for the user shows unique text"
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("notification reason text - bad notification reason", {
|
||||
template: hbs`
|
||||
{{topic-notifications-button
|
||||
notificationLevel=topic.details.notification_level
|
||||
topic=topic
|
||||
}}
|
||||
`,
|
||||
|
||||
beforeEach() {
|
||||
this.set("topic", buildTopic({ level: 2 }));
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
this.set("topic", buildTopic({ level: 3, reason: 999 }));
|
||||
|
||||
assert.equal(
|
||||
queryAll(".topic-notifications-button .text").text(),
|
||||
I18n.t("topic.notifications.reasons.3"),
|
||||
"fallback to regular level translation if reason does not exist"
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("notification reason text - user tracking category", {
|
||||
template: hbs`
|
||||
{{topic-notifications-button
|
||||
notificationLevel=topic.details.notification_level
|
||||
topic=topic
|
||||
}}
|
||||
`,
|
||||
|
||||
beforeEach() {
|
||||
this.currentUser.set("tracked_category_ids", [88]);
|
||||
this.set("topic", buildTopic({ level: 2, reason: 8, category_id: 88 }));
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
assert.equal(
|
||||
queryAll(".topic-notifications-button .text").text(),
|
||||
I18n.t("topic.notifications.reasons.2_8"),
|
||||
"use 2_8 notification if user is still tracking category"
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
componentTest(
|
||||
"notification reason text - user no longer tracking category",
|
||||
{
|
||||
template: hbs`
|
||||
{{topic-notifications-button
|
||||
notificationLevel=topic.details.notification_level
|
||||
topic=topic
|
||||
}}
|
||||
`,
|
||||
|
||||
beforeEach() {
|
||||
this.currentUser.set("tracked_category_ids", []);
|
||||
this.set(
|
||||
"topic",
|
||||
buildTopic({ level: 2, reason: 8, category_id: 88 })
|
||||
);
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
assert.equal(
|
||||
queryAll(".topic-notifications-button .text").text(),
|
||||
I18n.t("topic.notifications.reasons.2_8_stale"),
|
||||
"use _stale notification if user is no longer tracking category"
|
||||
);
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
componentTest("notification reason text - user watching category", {
|
||||
template: hbs`
|
||||
{{topic-notifications-button
|
||||
notificationLevel=topic.details.notification_level
|
||||
topic=topic
|
||||
}}
|
||||
`,
|
||||
|
||||
beforeEach() {
|
||||
this.currentUser.set("watched_category_ids", [88]);
|
||||
this.set("topic", buildTopic({ level: 3, reason: 6, category_id: 88 }));
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
assert.equal(
|
||||
queryAll(".topic-notifications-button .text").text(),
|
||||
I18n.t("topic.notifications.reasons.3_6"),
|
||||
"use 3_6 notification if user is still watching category"
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
componentTest(
|
||||
"notification reason text - user no longer watching category",
|
||||
{
|
||||
template: hbs`
|
||||
{{topic-notifications-button
|
||||
notificationLevel=topic.details.notification_level
|
||||
topic=topic
|
||||
}}
|
||||
`,
|
||||
|
||||
beforeEach() {
|
||||
this.currentUser.set("watched_category_ids", []);
|
||||
this.set(
|
||||
"topic",
|
||||
buildTopic({ level: 3, reason: 6, category_id: 88 })
|
||||
);
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
assert.equal(
|
||||
queryAll(".topic-notifications-button .text").text(),
|
||||
I18n.t("topic.notifications.reasons.3_6_stale"),
|
||||
"use _stale notification if user is no longer watching category"
|
||||
);
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
componentTest("notification reason text - user watching tag", {
|
||||
template: hbs`
|
||||
{{topic-notifications-button
|
||||
notificationLevel=topic.details.notification_level
|
||||
topic=topic
|
||||
}}
|
||||
`,
|
||||
|
||||
beforeEach() {
|
||||
this.currentUser.set("watched_tags", ["test"]);
|
||||
this.set("topic", buildTopic({ level: 3, reason: 10, tags: ["test"] }));
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
assert.equal(
|
||||
queryAll(".topic-notifications-button .text").text(),
|
||||
I18n.t("topic.notifications.reasons.3_10"),
|
||||
"use 3_10 notification if user is still watching tag"
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("notification reason text - user no longer watching tag", {
|
||||
template: hbs`
|
||||
{{topic-notifications-button
|
||||
notificationLevel=topic.details.notification_level
|
||||
topic=topic
|
||||
}}
|
||||
`,
|
||||
|
||||
beforeEach() {
|
||||
this.currentUser.set("watched_tags", []);
|
||||
this.set("topic", buildTopic({ level: 3, reason: 10, tags: ["test"] }));
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
assert.equal(
|
||||
queryAll(".topic-notifications-button .text").text(),
|
||||
I18n.t("topic.notifications.reasons.3_10_stale"),
|
||||
"use _stale notification if user is no longer watching tag"
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
@ -2,8 +2,8 @@ import { module, test } from "qunit";
|
|||
import Topic from "discourse/models/topic";
|
||||
import User from "discourse/models/user";
|
||||
|
||||
function buildDetails(id) {
|
||||
const topic = Topic.create({ id: id });
|
||||
function buildDetails(id, topicParams = {}) {
|
||||
const topic = Topic.create(Object.assign({ id }, topicParams));
|
||||
return topic.get("details");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
import { action, computed } from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { NotificationLevels } from "discourse/lib/notification-levels";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
import Component from "@ember/component";
|
||||
import layout from "select-kit/templates/components/topic-notifications-button";
|
||||
|
||||
|
@ -25,4 +30,85 @@ export default Component.extend({
|
|||
.finally(() => this.set("isLoading", false));
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("topic", "topic.details")
|
||||
notificationReasonText(topic, topicDetails) {
|
||||
let level = topicDetails.notification_level;
|
||||
let reason = topicDetails.notifications_reason_id;
|
||||
|
||||
if (typeof level !== "number") {
|
||||
level = 1;
|
||||
}
|
||||
|
||||
let localeString = `topic.notifications.reasons.${level}`;
|
||||
if (typeof reason === "number") {
|
||||
let localeStringWithReason = localeString + "_" + reason;
|
||||
|
||||
if (
|
||||
this._notificationReasonStale(level, reason, topic, this.currentUser)
|
||||
) {
|
||||
localeStringWithReason += "_stale";
|
||||
}
|
||||
|
||||
// some sane protection for missing translations of edge cases
|
||||
if (I18n.lookup(localeStringWithReason, { locale: "en" })) {
|
||||
localeString = localeStringWithReason;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
this.currentUser &&
|
||||
this.currentUser.mailing_list_mode &&
|
||||
level > NotificationLevels.MUTED
|
||||
) {
|
||||
return I18n.t("topic.notifications.reasons.mailing_list_mode");
|
||||
} else {
|
||||
return I18n.t(localeString, {
|
||||
username: this.currentUser && this.currentUser.username_lower,
|
||||
basePath: getURL(""),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// The user may have changed their category or tag tracking settings
|
||||
// since this topic was tracked/watched based on those settings in the
|
||||
// past. In that case we need to alter the reason message we show them
|
||||
// otherwise it is very confusing for the end user to be told they are
|
||||
// tracking a topic because of a category, when they are no longer tracking
|
||||
// that category.
|
||||
_notificationReasonStale(level, reason, topic, currentUser) {
|
||||
if (!currentUser) {
|
||||
return;
|
||||
}
|
||||
|
||||
let categoryId = topic.category_id;
|
||||
let tags = topic.tags;
|
||||
let watchedCategoryIds = currentUser.watched_category_ids || [];
|
||||
let trackedCategoryIds = currentUser.tracked_category_ids || [];
|
||||
let watchedTags = currentUser.watched_tags || [];
|
||||
|
||||
// 2_8 tracking category
|
||||
if (categoryId) {
|
||||
if (level === 2 && reason === 8) {
|
||||
if (!trackedCategoryIds.includes(categoryId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 3_6 watching category
|
||||
} else if (level === 3 && reason === 6) {
|
||||
if (!watchedCategoryIds.includes(categoryId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (!isEmpty(tags)) {
|
||||
// 3_10 watching tag
|
||||
if (level === 3 && reason === 10) {
|
||||
if (!tags.some((tag) => watchedTags.includes(tag))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
});
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
showCaret=showCaret
|
||||
)
|
||||
}}
|
||||
<span class="text">{{html-safe topic.details.notificationReasonText}}</span>
|
||||
<span class="text">{{html-safe notificationReasonText}}</span>
|
||||
</p>
|
||||
{{else}}
|
||||
{{topic-notifications-options
|
||||
|
|
|
@ -202,15 +202,21 @@ class CategoryUser < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def self.notification_levels_for(guardian)
|
||||
# Anonymous users have all default categories set to regular tracking,
|
||||
# except for default muted categories which stay muted.
|
||||
if guardian.anonymous?
|
||||
notification_levels = [
|
||||
SiteSetting.default_categories_watching.split("|"),
|
||||
SiteSetting.default_categories_tracking.split("|"),
|
||||
SiteSetting.default_categories_watching_first_post.split("|"),
|
||||
SiteSetting.default_categories_regular.split("|")
|
||||
].flatten.map { |id| [id.to_i, self.notification_levels[:regular]] }
|
||||
].flatten.map do |id|
|
||||
[id.to_i, self.notification_levels[:regular]]
|
||||
end
|
||||
|
||||
notification_levels += SiteSetting.default_categories_muted.split("|").map { |id| [id.to_i, self.notification_levels[:muted]] }
|
||||
notification_levels += SiteSetting.default_categories_muted.split("|").map do |id|
|
||||
[id.to_i, self.notification_levels[:muted]]
|
||||
end
|
||||
else
|
||||
notification_levels = CategoryUser.where(user: guardian.user).pluck(:category_id, :notification_level)
|
||||
end
|
||||
|
|
|
@ -192,6 +192,28 @@ class TagUser < ActiveRecord::Base
|
|||
auto_track_tag: TopicUser.notification_reasons[:auto_track_tag])
|
||||
end
|
||||
|
||||
def self.notification_levels_for(guardian)
|
||||
# Anonymous users have all default tags set to regular tracking,
|
||||
# except for default muted tags which stay muted.
|
||||
if guardian.anonymous?
|
||||
notification_levels = [
|
||||
SiteSetting.default_tags_watching_first_post.split("|"),
|
||||
SiteSetting.default_tags_watching.split("|"),
|
||||
SiteSetting.default_tags_tracking.split("|")
|
||||
].flatten.map do |name|
|
||||
[name, self.notification_levels[:regular]]
|
||||
end
|
||||
|
||||
notification_levels += SiteSetting.default_tags_muted.split("|").map do |name|
|
||||
[name, self.notification_levels[:muted]]
|
||||
end
|
||||
else
|
||||
notification_levels = TagUser.where(user: guardian.user).joins(:tag).pluck("tags.name", :notification_level)
|
||||
end
|
||||
|
||||
Hash[*notification_levels.flatten]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
|
|
|
@ -1546,17 +1546,27 @@ class User < ActiveRecord::Base
|
|||
|
||||
values = []
|
||||
|
||||
%w{watching watching_first_post tracking regular muted}.each do |s|
|
||||
category_ids = SiteSetting.get("default_categories_#{s}").split("|").map(&:to_i)
|
||||
# The following site settings are used to pre-populate default category
|
||||
# tracking settings for a user:
|
||||
#
|
||||
# * default_categories_watching
|
||||
# * default_categories_tracking
|
||||
# * default_categories_watching_first_post
|
||||
# * default_categories_regular
|
||||
# * default_categories_muted
|
||||
%w{watching watching_first_post tracking regular muted}.each do |setting|
|
||||
category_ids = SiteSetting.get("default_categories_#{setting}").split("|").map(&:to_i)
|
||||
category_ids.each do |category_id|
|
||||
next if category_id == 0
|
||||
values << "(#{self.id}, #{category_id}, #{CategoryUser.notification_levels[s.to_sym]})"
|
||||
values << {
|
||||
user_id: self.id,
|
||||
category_id: category_id,
|
||||
notification_level: CategoryUser.notification_levels[setting.to_sym]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
if values.present?
|
||||
DB.exec("INSERT INTO category_users (user_id, category_id, notification_level) VALUES #{values.join(",")}")
|
||||
end
|
||||
CategoryUser.insert_all!(values) if values.present?
|
||||
end
|
||||
|
||||
def set_default_tags_preferences
|
||||
|
@ -1564,12 +1574,25 @@ class User < ActiveRecord::Base
|
|||
|
||||
values = []
|
||||
|
||||
%w{watching watching_first_post tracking muted}.each do |s|
|
||||
tag_names = SiteSetting.get("default_tags_#{s}").split("|")
|
||||
# The following site settings are used to pre-populate default tag
|
||||
# tracking settings for a user:
|
||||
#
|
||||
# * default_tags_watching
|
||||
# * default_tags_tracking
|
||||
# * default_tags_watching_first_post
|
||||
# * default_tags_muted
|
||||
%w{watching watching_first_post tracking muted}.each do |setting|
|
||||
tag_names = SiteSetting.get("default_tags_#{setting}").split("|")
|
||||
now = Time.zone.now
|
||||
|
||||
Tag.where(name: tag_names).pluck(:id).each do |tag_id|
|
||||
values << { user_id: self.id, tag_id: tag_id, notification_level: TagUser.notification_levels[s.to_sym], created_at: now, updated_at: now }
|
||||
values << {
|
||||
user_id: self.id,
|
||||
tag_id: tag_id,
|
||||
notification_level: TagUser.notification_levels[setting.to_sym],
|
||||
created_at: now,
|
||||
updated_at: now
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -22,4 +22,24 @@ class BasicUserSerializer < ApplicationSerializer
|
|||
def user
|
||||
object[:user] || object.try(:user) || object
|
||||
end
|
||||
|
||||
def categories_with_notification_level(lookup_level)
|
||||
category_user_notification_levels.select do |id, level|
|
||||
level == CategoryUser.notification_levels[lookup_level]
|
||||
end.keys
|
||||
end
|
||||
|
||||
def category_user_notification_levels
|
||||
@category_user_notification_levels ||= CategoryUser.notification_levels_for(scope)
|
||||
end
|
||||
|
||||
def tags_with_notification_level(lookup_level)
|
||||
tag_user_notification_levels.select do |id, level|
|
||||
level == TagUser.notification_levels[lookup_level]
|
||||
end.keys
|
||||
end
|
||||
|
||||
def tag_user_notification_levels
|
||||
@tag_user_notification_levels ||= TagUser.notification_levels_for(scope)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -28,7 +28,16 @@ class CurrentUserSerializer < BasicUserSerializer
|
|||
:redirected_to_top,
|
||||
:custom_fields,
|
||||
:muted_category_ids,
|
||||
:regular_category_ids,
|
||||
:tracked_category_ids,
|
||||
:watched_first_post_category_ids,
|
||||
:watched_category_ids,
|
||||
:muted_tag_ids,
|
||||
:watched_tags,
|
||||
:watching_first_post_tags,
|
||||
:tracked_tags,
|
||||
:muted_tags,
|
||||
:regular_tags,
|
||||
:dismissed_banner_key,
|
||||
:is_anonymous,
|
||||
:reviewable_count,
|
||||
|
@ -53,7 +62,7 @@ class CurrentUserSerializer < BasicUserSerializer
|
|||
:skip_new_user_tips,
|
||||
:do_not_disturb_until,
|
||||
:has_topic_draft,
|
||||
:can_review
|
||||
:can_review,
|
||||
|
||||
def groups
|
||||
object.visible_groups.pluck(:id, :name).map { |id, name| { id: id, name: name } }
|
||||
|
@ -181,13 +190,51 @@ class CurrentUserSerializer < BasicUserSerializer
|
|||
end
|
||||
|
||||
def muted_category_ids
|
||||
CategoryUser.lookup(object, :muted).pluck(:category_id)
|
||||
categories_with_notification_level(:muted)
|
||||
end
|
||||
|
||||
def regular_category_ids
|
||||
categories_with_notification_level(:regular)
|
||||
end
|
||||
|
||||
def tracked_category_ids
|
||||
categories_with_notification_level(:tracking)
|
||||
end
|
||||
|
||||
def watched_category_ids
|
||||
categories_with_notification_level(:watching)
|
||||
end
|
||||
|
||||
def watched_first_post_category_ids
|
||||
categories_with_notification_level(:watching_first_post)
|
||||
end
|
||||
|
||||
# this is a weird outlier that is used for topic tracking state which
|
||||
# needs the actual ids, which is why it is duplicated with muted_tags
|
||||
def muted_tag_ids
|
||||
TagUser.lookup(object, :muted).pluck(:tag_id)
|
||||
end
|
||||
|
||||
def muted_tags
|
||||
tags_with_notification_level(:muted)
|
||||
end
|
||||
|
||||
def tracked_tags
|
||||
tags_with_notification_level(:tracked)
|
||||
end
|
||||
|
||||
def watching_first_post_tags
|
||||
tags_with_notification_level(:watching_first_post)
|
||||
end
|
||||
|
||||
def watched_tags
|
||||
tags_with_notification_level(:watching)
|
||||
end
|
||||
|
||||
def regular_tags
|
||||
tags_with_notification_level(:regular)
|
||||
end
|
||||
|
||||
def ignored_users
|
||||
IgnoredUser.where(user: object.id).joins(:ignored_user).pluck(:username)
|
||||
end
|
||||
|
|
|
@ -207,39 +207,39 @@ class UserSerializer < UserCardSerializer
|
|||
### PRIVATE ATTRIBUTES
|
||||
###
|
||||
def muted_tags
|
||||
TagUser.lookup(object, :muted).joins(:tag).pluck('tags.name')
|
||||
tags_with_notification_level(:muted)
|
||||
end
|
||||
|
||||
def tracked_tags
|
||||
TagUser.lookup(object, :tracking).joins(:tag).pluck('tags.name')
|
||||
tags_with_notification_level(:tracked)
|
||||
end
|
||||
|
||||
def watching_first_post_tags
|
||||
TagUser.lookup(object, :watching_first_post).joins(:tag).pluck('tags.name')
|
||||
tags_with_notification_level(:watching_first_post)
|
||||
end
|
||||
|
||||
def watched_tags
|
||||
TagUser.lookup(object, :watching).joins(:tag).pluck('tags.name')
|
||||
tags_with_notification_level(:watching)
|
||||
end
|
||||
|
||||
def muted_category_ids
|
||||
CategoryUser.lookup(object, :muted).pluck(:category_id)
|
||||
categories_with_notification_level(:muted)
|
||||
end
|
||||
|
||||
def regular_category_ids
|
||||
CategoryUser.lookup(object, :regular).pluck(:category_id)
|
||||
categories_with_notification_level(:regular)
|
||||
end
|
||||
|
||||
def tracked_category_ids
|
||||
CategoryUser.lookup(object, :tracking).pluck(:category_id)
|
||||
categories_with_notification_level(:tracking)
|
||||
end
|
||||
|
||||
def watched_category_ids
|
||||
CategoryUser.lookup(object, :watching).pluck(:category_id)
|
||||
categories_with_notification_level(:watching)
|
||||
end
|
||||
|
||||
def watched_first_post_category_ids
|
||||
CategoryUser.lookup(object, :watching_first_post).pluck(:category_id)
|
||||
categories_with_notification_level(:watching_first_post)
|
||||
end
|
||||
|
||||
def muted_usernames
|
||||
|
|
|
@ -2595,12 +2595,15 @@ en:
|
|||
reasons:
|
||||
mailing_list_mode: "You have mailing list mode enabled, so you will be notified of replies to this topic via email."
|
||||
"3_10": "You will receive notifications because you are watching a tag on this topic."
|
||||
"3_10_stale": "You will receive notifications because you were watching a tag on this topic in the past."
|
||||
"3_6": "You will receive notifications because you are watching this category."
|
||||
"3_6_stale": "You will receive notifications because you were watching this category in the past."
|
||||
"3_5": "You will receive notifications because you started watching this topic automatically."
|
||||
"3_2": "You will receive notifications because you are watching this topic."
|
||||
"3_1": "You will receive notifications because you created this topic."
|
||||
"3": "You will receive notifications because you are watching this topic."
|
||||
"2_8": "You will see a count of new replies because you are tracking this category."
|
||||
"2_8_stale": "You will see a count of new replies because you were tracking this category in the past."
|
||||
"2_4": "You will see a count of new replies because you posted a reply to this topic."
|
||||
"2_2": "You will see a count of new replies because you are tracking this topic."
|
||||
"2": 'You will see a count of new replies because you <a href="%{basePath}/u/%{username}/preferences/notifications">read this topic</a>.'
|
||||
|
|
|
@ -219,6 +219,54 @@ describe CategoryUser do
|
|||
|
||||
expect(CategoryUser.where(user_id: user.id).count).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#notification_levels_for" do
|
||||
let(:guardian) { Guardian.new(user) }
|
||||
let!(:category1) { Fabricate(:category) }
|
||||
let!(:category2) { Fabricate(:category) }
|
||||
let!(:category3) { Fabricate(:category) }
|
||||
let!(:category4) { Fabricate(:category) }
|
||||
let!(:category5) { Fabricate(:category) }
|
||||
|
||||
context "for anon" do
|
||||
let(:user) { nil }
|
||||
before do
|
||||
SiteSetting.default_categories_watching = category1.id.to_s
|
||||
SiteSetting.default_categories_tracking = category2.id.to_s
|
||||
SiteSetting.default_categories_watching_first_post = category3.id.to_s
|
||||
SiteSetting.default_categories_regular = category4.id.to_s
|
||||
SiteSetting.default_categories_muted = category5.id.to_s
|
||||
end
|
||||
it "every category from the default_categories_* site settings get overridden to regular, except for muted" do
|
||||
levels = CategoryUser.notification_levels_for(guardian)
|
||||
expect(levels[category1.id]).to eq(CategoryUser.notification_levels[:regular])
|
||||
expect(levels[category2.id]).to eq(CategoryUser.notification_levels[:regular])
|
||||
expect(levels[category3.id]).to eq(CategoryUser.notification_levels[:regular])
|
||||
expect(levels[category4.id]).to eq(CategoryUser.notification_levels[:regular])
|
||||
expect(levels[category5.id]).to eq(CategoryUser.notification_levels[:muted])
|
||||
end
|
||||
end
|
||||
|
||||
context "for a user" do
|
||||
before do
|
||||
CategoryUser.create(user: user, category: category1, notification_level: CategoryUser.notification_levels[:watching])
|
||||
CategoryUser.create(user: user, category: category2, notification_level: CategoryUser.notification_levels[:tracking])
|
||||
CategoryUser.create(user: user, category: category3, notification_level: CategoryUser.notification_levels[:watching_first_post])
|
||||
CategoryUser.create(user: user, category: category4, notification_level: CategoryUser.notification_levels[:regular])
|
||||
CategoryUser.create(user: user, category: category5, notification_level: CategoryUser.notification_levels[:muted])
|
||||
end
|
||||
it "gets the category_user notification levels for all categories the user is tracking and does not
|
||||
include categories the user is not tracking at all" do
|
||||
category6 = Fabricate(:category)
|
||||
levels = CategoryUser.notification_levels_for(guardian)
|
||||
expect(levels[category1.id]).to eq(CategoryUser.notification_levels[:watching])
|
||||
expect(levels[category2.id]).to eq(CategoryUser.notification_levels[:tracking])
|
||||
expect(levels[category3.id]).to eq(CategoryUser.notification_levels[:watching_first_post])
|
||||
expect(levels[category4.id]).to eq(CategoryUser.notification_levels[:regular])
|
||||
expect(levels[category5.id]).to eq(CategoryUser.notification_levels[:muted])
|
||||
expect(levels.key?(category6.id)).to eq(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -232,4 +232,49 @@ describe TagUser do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#notification_levels_for" do
|
||||
let(:guardian) { Guardian.new(user) }
|
||||
let!(:tag1) { Fabricate(:tag) }
|
||||
let!(:tag2) { Fabricate(:tag) }
|
||||
let!(:tag3) { Fabricate(:tag) }
|
||||
let!(:tag4) { Fabricate(:tag) }
|
||||
|
||||
context "for anon" do
|
||||
let(:user) { nil }
|
||||
before do
|
||||
SiteSetting.default_tags_watching = tag1.name
|
||||
SiteSetting.default_tags_tracking = tag2.name
|
||||
SiteSetting.default_tags_watching_first_post = tag3.name
|
||||
SiteSetting.default_tags_muted = tag4.name
|
||||
end
|
||||
it "every tag from the default_tags_* site settings get overridden to watching_first_post, except for muted" do
|
||||
levels = TagUser.notification_levels_for(guardian)
|
||||
expect(levels[tag1.name]).to eq(TagUser.notification_levels[:regular])
|
||||
expect(levels[tag2.name]).to eq(TagUser.notification_levels[:regular])
|
||||
expect(levels[tag3.name]).to eq(TagUser.notification_levels[:regular])
|
||||
expect(levels[tag4.name]).to eq(TagUser.notification_levels[:muted])
|
||||
end
|
||||
end
|
||||
|
||||
context "for a user" do
|
||||
let(:user) { Fabricate(:user) }
|
||||
before do
|
||||
TagUser.create(user: user, tag: tag1, notification_level: TagUser.notification_levels[:watching])
|
||||
TagUser.create(user: user, tag: tag2, notification_level: TagUser.notification_levels[:tracking])
|
||||
TagUser.create(user: user, tag: tag3, notification_level: TagUser.notification_levels[:watching_first_post])
|
||||
TagUser.create(user: user, tag: tag4, notification_level: TagUser.notification_levels[:muted])
|
||||
end
|
||||
it "gets the tag_user notification levels for all tags the user is tracking and does not
|
||||
include tags the user is not tracking at all" do
|
||||
tag5 = Fabricate(:tag)
|
||||
levels = TagUser.notification_levels_for(guardian)
|
||||
expect(levels[tag1.name]).to eq(TagUser.notification_levels[:watching])
|
||||
expect(levels[tag2.name]).to eq(TagUser.notification_levels[:tracking])
|
||||
expect(levels[tag3.name]).to eq(TagUser.notification_levels[:watching_first_post])
|
||||
expect(levels[tag4.name]).to eq(TagUser.notification_levels[:muted])
|
||||
expect(levels.key?(tag5.name)).to eq(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue
Block a user