mirror of
https://github.com/discourse/discourse.git
synced 2025-06-07 15:26:01 +08:00
FIX: Remove tags from experimental sidebar on notification level changed (#17083)
As part of this commit, a bug where updating a tag's notification level on the server side does not update the state of the user's tag notification levels on the client side is fixed too.
This commit is contained in:

committed by
GitHub

parent
47034d9ca0
commit
e7e23e8d9c
@ -181,14 +181,15 @@ export default DiscoverySortableController.extend(
|
|||||||
this.tagNotification
|
this.tagNotification
|
||||||
.update({ notification_level: notificationLevel })
|
.update({ notification_level: notificationLevel })
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
this.currentUser.set(
|
const payload = response.responseJson;
|
||||||
"muted_tag_ids",
|
|
||||||
this.currentUser.calculateMutedIds(
|
this.currentUser.setProperties({
|
||||||
notificationLevel,
|
watched_tags: payload.watched_tags,
|
||||||
response.responseJson.tag_id,
|
watching_first_post_tags: payload.watching_first_post_tags,
|
||||||
"muted_tag_ids"
|
tracked_tags: payload.tracked_tags,
|
||||||
)
|
muted_tags: payload.muted_tags,
|
||||||
);
|
regular_tags: payload.regular_tags,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -32,15 +32,15 @@ function isUnseen(topic) {
|
|||||||
return !topic.is_seen;
|
return !topic.is_seen;
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasMutedTags(topicTagIds, mutedTagIds, siteSettings) {
|
function hasMutedTags(topicTags, mutedTags, siteSettings) {
|
||||||
if (!mutedTagIds || !topicTagIds) {
|
if (!mutedTags || !topicTags) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
(siteSettings.remove_muted_tags_from_latest === "always" &&
|
(siteSettings.remove_muted_tags_from_latest === "always" &&
|
||||||
topicTagIds.any((tagId) => mutedTagIds.includes(tagId))) ||
|
topicTags.any((topicTag) => mutedTags.includes(topicTag))) ||
|
||||||
(siteSettings.remove_muted_tags_from_latest === "only_muted" &&
|
(siteSettings.remove_muted_tags_from_latest === "only_muted" &&
|
||||||
topicTagIds.every((tagId) => mutedTagIds.includes(tagId)))
|
topicTags.every((topicTag) => mutedTags.includes(topicTag)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -876,10 +876,9 @@ const TopicTrackingState = EmberObject.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (["new_topic", "latest"].includes(data.message_type)) {
|
if (["new_topic", "latest"].includes(data.message_type)) {
|
||||||
const mutedTagIds = User.currentProp("muted_tag_ids");
|
const mutedTags = User.currentProp("muted_tags");
|
||||||
if (
|
|
||||||
hasMutedTags(data.payload.topic_tag_ids, mutedTagIds, this.siteSettings)
|
if (hasMutedTags(data.payload.tags, mutedTags, this.siteSettings)) {
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ import {
|
|||||||
import { isLegacyEmber } from "discourse-common/config/environment";
|
import { isLegacyEmber } from "discourse-common/config/environment";
|
||||||
import discoveryFixture from "discourse/tests/fixtures/discovery-fixtures";
|
import discoveryFixture from "discourse/tests/fixtures/discovery-fixtures";
|
||||||
import { cloneJSON } from "discourse-common/lib/object";
|
import { cloneJSON } from "discourse-common/lib/object";
|
||||||
|
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||||
|
import { NotificationLevels } from "discourse/lib/notification-levels";
|
||||||
|
|
||||||
acceptance("Sidebar - Tags section - tagging disabled", function (needs) {
|
acceptance("Sidebar - Tags section - tagging disabled", function (needs) {
|
||||||
needs.settings({
|
needs.settings({
|
||||||
@ -62,6 +64,16 @@ acceptance("Sidebar - Tags section", function (needs) {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.put("/tag/:tagId/notifications", (request) => {
|
||||||
|
return helper.response({
|
||||||
|
watched_tags: [],
|
||||||
|
watching_first_post_tags: [],
|
||||||
|
regular_tags: [request.params.tagId],
|
||||||
|
tracked_tags: [],
|
||||||
|
muted_tags: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
conditionalTest(
|
conditionalTest(
|
||||||
@ -370,4 +382,25 @@ acceptance("Sidebar - Tags section", function (needs) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
conditionalTest(
|
||||||
|
"updating tags notification levels",
|
||||||
|
!isLegacyEmber(),
|
||||||
|
async function (assert) {
|
||||||
|
await visit(`/tag/tag1/l/unread`);
|
||||||
|
|
||||||
|
const notificationLevelsDropdown = selectKit(".notifications-button");
|
||||||
|
|
||||||
|
await notificationLevelsDropdown.expand();
|
||||||
|
|
||||||
|
await notificationLevelsDropdown.selectRowByValue(
|
||||||
|
NotificationLevels.REGULAR
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
!exists(".sidebar-section-tags .sidebar-section-link-tag1"),
|
||||||
|
"tag1 section link is removed from sidebar"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
@ -760,8 +760,10 @@ discourseModule("Unit | Model | topic-tracking-state", function (hooks) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("topics in muted tags do not get added to the state", function (assert) {
|
test("topics in muted tags do not get added to the state", function (assert) {
|
||||||
trackingState.currentUser.set("muted_tag_ids", [44]);
|
trackingState.currentUser.set("muted_tags", ["pending"]);
|
||||||
|
|
||||||
publishToMessageBus("/new", newTopicPayload);
|
publishToMessageBus("/new", newTopicPayload);
|
||||||
|
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
trackingState.findState(222),
|
trackingState.findState(222),
|
||||||
undefined,
|
undefined,
|
||||||
|
@ -301,7 +301,7 @@ class TagsController < ::ApplicationController
|
|||||||
raise Discourse::NotFound unless tag
|
raise Discourse::NotFound unless tag
|
||||||
level = params[:tag_notification][:notification_level].to_i
|
level = params[:tag_notification][:notification_level].to_i
|
||||||
TagUser.change(current_user.id, tag.id, level)
|
TagUser.change(current_user.id, tag.id, level)
|
||||||
render json: { notification_level: level, tag_id: tag.id }
|
render_serialized(current_user, UserTagNotificationsSerializer, root: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
def personal_messages
|
def personal_messages
|
||||||
|
@ -36,14 +36,4 @@ class BasicUserSerializer < ApplicationSerializer
|
|||||||
def category_user_notification_levels
|
def category_user_notification_levels
|
||||||
@category_user_notification_levels ||= CategoryUser.notification_levels_for(user)
|
@category_user_notification_levels ||= CategoryUser.notification_levels_for(user)
|
||||||
end
|
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(user)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
33
app/serializers/concerns/user_tag_notifications_mixin.rb
Normal file
33
app/serializers/concerns/user_tag_notifications_mixin.rb
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module UserTagNotificationsMixin
|
||||||
|
def muted_tags
|
||||||
|
tags_with_notification_level(:muted)
|
||||||
|
end
|
||||||
|
|
||||||
|
def tracked_tags
|
||||||
|
tags_with_notification_level(:tracking)
|
||||||
|
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 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(user)
|
||||||
|
end
|
||||||
|
end
|
@ -1,6 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class CurrentUserSerializer < BasicUserSerializer
|
class CurrentUserSerializer < BasicUserSerializer
|
||||||
|
include UserTagNotificationsMixin
|
||||||
|
|
||||||
attributes :name,
|
attributes :name,
|
||||||
:unread_notifications,
|
:unread_notifications,
|
||||||
@ -33,7 +34,6 @@ class CurrentUserSerializer < BasicUserSerializer
|
|||||||
:tracked_category_ids,
|
:tracked_category_ids,
|
||||||
:watched_first_post_category_ids,
|
:watched_first_post_category_ids,
|
||||||
:watched_category_ids,
|
:watched_category_ids,
|
||||||
:muted_tag_ids,
|
|
||||||
:watched_tags,
|
:watched_tags,
|
||||||
:watching_first_post_tags,
|
:watching_first_post_tags,
|
||||||
:tracked_tags,
|
:tracked_tags,
|
||||||
@ -230,32 +230,6 @@ class CurrentUserSerializer < BasicUserSerializer
|
|||||||
categories_with_notification_level(:watching_first_post)
|
categories_with_notification_level(:watching_first_post)
|
||||||
end
|
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(:tracking)
|
|
||||||
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
|
def ignored_users
|
||||||
IgnoredUser.where(user: object.id).joins(:ignored_user).pluck(:username)
|
IgnoredUser.where(user: object.id).joins(:ignored_user).pluck(:username)
|
||||||
end
|
end
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class UserSerializer < UserCardSerializer
|
class UserSerializer < UserCardSerializer
|
||||||
|
include UserTagNotificationsMixin
|
||||||
|
|
||||||
attributes :bio_raw,
|
attributes :bio_raw,
|
||||||
:bio_cooked,
|
:bio_cooked,
|
||||||
@ -211,22 +212,6 @@ class UserSerializer < UserCardSerializer
|
|||||||
###
|
###
|
||||||
### PRIVATE ATTRIBUTES
|
### PRIVATE ATTRIBUTES
|
||||||
###
|
###
|
||||||
def muted_tags
|
|
||||||
tags_with_notification_level(:muted)
|
|
||||||
end
|
|
||||||
|
|
||||||
def tracked_tags
|
|
||||||
tags_with_notification_level(:tracking)
|
|
||||||
end
|
|
||||||
|
|
||||||
def watching_first_post_tags
|
|
||||||
tags_with_notification_level(:watching_first_post)
|
|
||||||
end
|
|
||||||
|
|
||||||
def watched_tags
|
|
||||||
tags_with_notification_level(:watching)
|
|
||||||
end
|
|
||||||
|
|
||||||
def muted_category_ids
|
def muted_category_ids
|
||||||
categories_with_notification_level(:muted)
|
categories_with_notification_level(:muted)
|
||||||
end
|
end
|
||||||
|
15
app/serializers/user_tag_notifications_serializer.rb
Normal file
15
app/serializers/user_tag_notifications_serializer.rb
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class UserTagNotificationsSerializer < ApplicationSerializer
|
||||||
|
include UserTagNotificationsMixin
|
||||||
|
|
||||||
|
attributes :watched_tags,
|
||||||
|
:watching_first_post_tags,
|
||||||
|
:tracked_tags,
|
||||||
|
:muted_tags,
|
||||||
|
:regular_tags
|
||||||
|
|
||||||
|
def user
|
||||||
|
object
|
||||||
|
end
|
||||||
|
end
|
@ -1095,4 +1095,59 @@ describe TagsController do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#update_notifications' do
|
||||||
|
fab!(:tag) { Fabricate(:tag) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
sign_in(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns 404 when tag is not found' do
|
||||||
|
put "/tag/someinvalidtagname/notifications.json"
|
||||||
|
|
||||||
|
expect(response.status).to eq(404)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'updates the notification level of a tag for a user' do
|
||||||
|
tag_user = TagUser.change(user.id, tag.id, NotificationLevels.all[:muted])
|
||||||
|
|
||||||
|
put "/tag/#{tag.name}/notifications.json", params: {
|
||||||
|
tag_notification: {
|
||||||
|
notification_level: NotificationLevels.all[:tracking]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
expect(response.parsed_body["watched_tags"]).to eq([])
|
||||||
|
expect(response.parsed_body["watching_first_post_tags"]).to eq([])
|
||||||
|
expect(response.parsed_body["tracked_tags"]).to eq([tag.name])
|
||||||
|
expect(response.parsed_body["muted_tags"]).to eq([])
|
||||||
|
expect(response.parsed_body["regular_tags"]).to eq([])
|
||||||
|
|
||||||
|
expect(tag_user.reload.notification_level).to eq(NotificationLevels.all[:tracking])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sets the notification level of a tag for a user' do
|
||||||
|
expect do
|
||||||
|
put "/tag/#{tag.name}/notifications.json", params: {
|
||||||
|
tag_notification: {
|
||||||
|
notification_level: NotificationLevels.all[:muted]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
|
||||||
|
expect(response.parsed_body["watched_tags"]).to eq([])
|
||||||
|
expect(response.parsed_body["watching_first_post_tags"]).to eq([])
|
||||||
|
expect(response.parsed_body["tracked_tags"]).to eq([])
|
||||||
|
expect(response.parsed_body["muted_tags"]).to eq([tag.name])
|
||||||
|
expect(response.parsed_body["regular_tags"]).to eq([])
|
||||||
|
end.to change { user.tag_users.count }.by(1)
|
||||||
|
|
||||||
|
tag_user = user.tag_users.last
|
||||||
|
|
||||||
|
expect(tag_user.notification_level).to eq(NotificationLevels.all[:muted])
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -60,19 +60,21 @@ RSpec.describe CurrentUserSerializer do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "#muted_tag_ids" do
|
context "#muted_tag" do
|
||||||
fab!(:user) { Fabricate(:user) }
|
fab!(:user) { Fabricate(:user) }
|
||||||
fab!(:tag) { Fabricate(:tag) }
|
fab!(:tag) { Fabricate(:tag) }
|
||||||
|
|
||||||
let!(:tag_user) do
|
let!(:tag_user) do
|
||||||
TagUser.create!(user_id: user.id,
|
TagUser.create!(
|
||||||
notification_level: TagUser.notification_levels[:muted],
|
user_id: user.id,
|
||||||
tag_id: tag.id
|
notification_level: TagUser.notification_levels[:muted],
|
||||||
)
|
tag_id: tag.id
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'include muted tag ids' do
|
it 'includes muted tag names' do
|
||||||
payload = serializer.as_json
|
payload = serializer.as_json
|
||||||
expect(payload[:muted_tag_ids]).to eq([tag.id])
|
expect(payload[:muted_tags]).to eq([tag.name])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user