FIX: Wrong scope used for notification levels user serializer (#13039)
This is a recent regression introduced by https://github.com/discourse/discourse/pull/12937 which makes it so that when looking at a user profile that is not your own, specifically the category and tag notification settings, you would see your own settings instead of the target user. This is only a problem for admins because regular users cannot see these details for other users. The issue was that we were using `scope` in the serializer, which refers to the current user, rather than using a scope for the target user via `Guardian.new(user)`. However, on further inspection the `notification_levels_for` method for `TagUser` and `CategoryUser` did not actually need to be accepting an instance of Guardian, all that it was using it for was to check guardian.anonymous? which is just a fancy way of saying user.blank?. Changed this method to just accept a user instead and send the user in from the serializer.
This commit is contained in:
parent
19182b1386
commit
38742bc208
|
@ -100,7 +100,7 @@ class CategoryList
|
||||||
|
|
||||||
@categories = @categories.to_a
|
@categories = @categories.to_a
|
||||||
|
|
||||||
notification_levels = CategoryUser.notification_levels_for(@guardian)
|
notification_levels = CategoryUser.notification_levels_for(@guardian.user)
|
||||||
default_notification_level = CategoryUser.default_notification_level
|
default_notification_level = CategoryUser.default_notification_level
|
||||||
|
|
||||||
allowed_topic_create = Set.new(Category.topic_create_allowed(@guardian).pluck(:id))
|
allowed_topic_create = Set.new(Category.topic_create_allowed(@guardian).pluck(:id))
|
||||||
|
|
|
@ -201,10 +201,10 @@ class CategoryUser < ActiveRecord::Base
|
||||||
SiteSetting.mute_all_categories_by_default ? notification_levels[:muted] : notification_levels[:regular]
|
SiteSetting.mute_all_categories_by_default ? notification_levels[:muted] : notification_levels[:regular]
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.notification_levels_for(guardian)
|
def self.notification_levels_for(user)
|
||||||
# Anonymous users have all default categories set to regular tracking,
|
# Anonymous users have all default categories set to regular tracking,
|
||||||
# except for default muted categories which stay muted.
|
# except for default muted categories which stay muted.
|
||||||
if guardian.anonymous?
|
if user.blank?
|
||||||
notification_levels = [
|
notification_levels = [
|
||||||
SiteSetting.default_categories_watching.split("|"),
|
SiteSetting.default_categories_watching.split("|"),
|
||||||
SiteSetting.default_categories_tracking.split("|"),
|
SiteSetting.default_categories_tracking.split("|"),
|
||||||
|
@ -218,7 +218,7 @@ class CategoryUser < ActiveRecord::Base
|
||||||
[id.to_i, self.notification_levels[:muted]]
|
[id.to_i, self.notification_levels[:muted]]
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
notification_levels = CategoryUser.where(user: guardian.user).pluck(:category_id, :notification_level)
|
notification_levels = CategoryUser.where(user: user).pluck(:category_id, :notification_level)
|
||||||
end
|
end
|
||||||
|
|
||||||
Hash[*notification_levels.flatten]
|
Hash[*notification_levels.flatten]
|
||||||
|
|
|
@ -55,7 +55,7 @@ class Site
|
||||||
|
|
||||||
by_id = {}
|
by_id = {}
|
||||||
|
|
||||||
notification_levels = CategoryUser.notification_levels_for(@guardian)
|
notification_levels = CategoryUser.notification_levels_for(@guardian.user)
|
||||||
default_notification_level = CategoryUser.default_notification_level
|
default_notification_level = CategoryUser.default_notification_level
|
||||||
|
|
||||||
categories.each do |category|
|
categories.each do |category|
|
||||||
|
|
|
@ -192,10 +192,10 @@ class TagUser < ActiveRecord::Base
|
||||||
auto_track_tag: TopicUser.notification_reasons[:auto_track_tag])
|
auto_track_tag: TopicUser.notification_reasons[:auto_track_tag])
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.notification_levels_for(guardian)
|
def self.notification_levels_for(user)
|
||||||
# Anonymous users have all default tags set to regular tracking,
|
# Anonymous users have all default tags set to regular tracking,
|
||||||
# except for default muted tags which stay muted.
|
# except for default muted tags which stay muted.
|
||||||
if guardian.anonymous?
|
if user.blank?
|
||||||
notification_levels = [
|
notification_levels = [
|
||||||
SiteSetting.default_tags_watching_first_post.split("|"),
|
SiteSetting.default_tags_watching_first_post.split("|"),
|
||||||
SiteSetting.default_tags_watching.split("|"),
|
SiteSetting.default_tags_watching.split("|"),
|
||||||
|
@ -208,7 +208,7 @@ class TagUser < ActiveRecord::Base
|
||||||
[name, self.notification_levels[:muted]]
|
[name, self.notification_levels[:muted]]
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
notification_levels = TagUser.where(user: guardian.user).joins(:tag).pluck("tags.name", :notification_level)
|
notification_levels = TagUser.where(user: user).joins(:tag).pluck("tags.name", :notification_level)
|
||||||
end
|
end
|
||||||
|
|
||||||
Hash[*notification_levels.flatten]
|
Hash[*notification_levels.flatten]
|
||||||
|
|
|
@ -23,6 +23,10 @@ class BasicUserSerializer < ApplicationSerializer
|
||||||
object[:user] || object.try(:user) || object
|
object[:user] || object.try(:user) || object
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def user_is_current_user
|
||||||
|
object.id == scope.user&.id
|
||||||
|
end
|
||||||
|
|
||||||
def categories_with_notification_level(lookup_level)
|
def categories_with_notification_level(lookup_level)
|
||||||
category_user_notification_levels.select do |id, level|
|
category_user_notification_levels.select do |id, level|
|
||||||
level == CategoryUser.notification_levels[lookup_level]
|
level == CategoryUser.notification_levels[lookup_level]
|
||||||
|
@ -30,7 +34,7 @@ class BasicUserSerializer < ApplicationSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def category_user_notification_levels
|
def category_user_notification_levels
|
||||||
@category_user_notification_levels ||= CategoryUser.notification_levels_for(scope)
|
@category_user_notification_levels ||= CategoryUser.notification_levels_for(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
def tags_with_notification_level(lookup_level)
|
def tags_with_notification_level(lookup_level)
|
||||||
|
@ -40,6 +44,6 @@ class BasicUserSerializer < ApplicationSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def tag_user_notification_levels
|
def tag_user_notification_levels
|
||||||
@tag_user_notification_levels ||= TagUser.notification_levels_for(scope)
|
@tag_user_notification_levels ||= TagUser.notification_levels_for(user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -225,7 +225,7 @@ class CurrentUserSerializer < BasicUserSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def tracked_tags
|
def tracked_tags
|
||||||
tags_with_notification_level(:tracked)
|
tags_with_notification_level(:tracking)
|
||||||
end
|
end
|
||||||
|
|
||||||
def watching_first_post_tags
|
def watching_first_post_tags
|
||||||
|
|
|
@ -89,15 +89,15 @@ class UserSerializer < UserCardSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def include_group_users?
|
def include_group_users?
|
||||||
(object.id && object.id == scope.user.try(:id)) || scope.is_admin?
|
user_is_current_user || scope.is_admin?
|
||||||
end
|
end
|
||||||
|
|
||||||
def include_associated_accounts?
|
def include_associated_accounts?
|
||||||
(object.id && object.id == scope.user.try(:id))
|
user_is_current_user
|
||||||
end
|
end
|
||||||
|
|
||||||
def include_second_factor_enabled?
|
def include_second_factor_enabled?
|
||||||
(object&.id == scope.user&.id) || scope.is_admin?
|
user_is_current_user || scope.is_admin?
|
||||||
end
|
end
|
||||||
|
|
||||||
def second_factor_enabled
|
def second_factor_enabled
|
||||||
|
@ -105,7 +105,7 @@ class UserSerializer < UserCardSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def include_second_factor_backup_enabled?
|
def include_second_factor_backup_enabled?
|
||||||
object&.id == scope.user&.id
|
user_is_current_user
|
||||||
end
|
end
|
||||||
|
|
||||||
def second_factor_backup_enabled
|
def second_factor_backup_enabled
|
||||||
|
@ -113,7 +113,7 @@ class UserSerializer < UserCardSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def include_second_factor_remaining_backup_codes?
|
def include_second_factor_remaining_backup_codes?
|
||||||
(object&.id == scope.user&.id) && object.backup_codes_enabled?
|
user_is_current_user && object.backup_codes_enabled?
|
||||||
end
|
end
|
||||||
|
|
||||||
def second_factor_remaining_backup_codes
|
def second_factor_remaining_backup_codes
|
||||||
|
@ -211,7 +211,7 @@ class UserSerializer < UserCardSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def tracked_tags
|
def tracked_tags
|
||||||
tags_with_notification_level(:tracked)
|
tags_with_notification_level(:tracking)
|
||||||
end
|
end
|
||||||
|
|
||||||
def watching_first_post_tags
|
def watching_first_post_tags
|
||||||
|
|
|
@ -222,7 +222,6 @@ describe CategoryUser do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#notification_levels_for" do
|
describe "#notification_levels_for" do
|
||||||
let(:guardian) { Guardian.new(user) }
|
|
||||||
let!(:category1) { Fabricate(:category) }
|
let!(:category1) { Fabricate(:category) }
|
||||||
let!(:category2) { Fabricate(:category) }
|
let!(:category2) { Fabricate(:category) }
|
||||||
let!(:category3) { Fabricate(:category) }
|
let!(:category3) { Fabricate(:category) }
|
||||||
|
@ -239,7 +238,7 @@ describe CategoryUser do
|
||||||
SiteSetting.default_categories_muted = category5.id.to_s
|
SiteSetting.default_categories_muted = category5.id.to_s
|
||||||
end
|
end
|
||||||
it "every category from the default_categories_* site settings get overridden to regular, except for muted" do
|
it "every category from the default_categories_* site settings get overridden to regular, except for muted" do
|
||||||
levels = CategoryUser.notification_levels_for(guardian)
|
levels = CategoryUser.notification_levels_for(user)
|
||||||
expect(levels[category1.id]).to eq(CategoryUser.notification_levels[:regular])
|
expect(levels[category1.id]).to eq(CategoryUser.notification_levels[:regular])
|
||||||
expect(levels[category2.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[category3.id]).to eq(CategoryUser.notification_levels[:regular])
|
||||||
|
@ -259,7 +258,7 @@ describe CategoryUser do
|
||||||
it "gets the category_user notification levels for all categories the user is tracking and does not
|
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
|
include categories the user is not tracking at all" do
|
||||||
category6 = Fabricate(:category)
|
category6 = Fabricate(:category)
|
||||||
levels = CategoryUser.notification_levels_for(guardian)
|
levels = CategoryUser.notification_levels_for(user)
|
||||||
expect(levels[category1.id]).to eq(CategoryUser.notification_levels[:watching])
|
expect(levels[category1.id]).to eq(CategoryUser.notification_levels[:watching])
|
||||||
expect(levels[category2.id]).to eq(CategoryUser.notification_levels[:tracking])
|
expect(levels[category2.id]).to eq(CategoryUser.notification_levels[:tracking])
|
||||||
expect(levels[category3.id]).to eq(CategoryUser.notification_levels[:watching_first_post])
|
expect(levels[category3.id]).to eq(CategoryUser.notification_levels[:watching_first_post])
|
||||||
|
|
|
@ -57,7 +57,7 @@ describe GroupUser do
|
||||||
group.watching_first_post_category_ids = [category5.id]
|
group.watching_first_post_category_ids = [category5.id]
|
||||||
group.save!
|
group.save!
|
||||||
expect { group.add(user) }.to change { CategoryUser.count }.by(5)
|
expect { group.add(user) }.to change { CategoryUser.count }.by(5)
|
||||||
h = CategoryUser.notification_levels_for(Guardian.new(user))
|
h = CategoryUser.notification_levels_for(user)
|
||||||
expect(h[category1.id]).to eq(levels[:muted])
|
expect(h[category1.id]).to eq(levels[:muted])
|
||||||
expect(h[category2.id]).to eq(levels[:regular])
|
expect(h[category2.id]).to eq(levels[:regular])
|
||||||
expect(h[category3.id]).to eq(levels[:tracking])
|
expect(h[category3.id]).to eq(levels[:tracking])
|
||||||
|
@ -74,7 +74,7 @@ describe GroupUser do
|
||||||
group.watching_first_post_category_ids = [category2.id, category3.id, category4.id]
|
group.watching_first_post_category_ids = [category2.id, category3.id, category4.id]
|
||||||
group.save!
|
group.save!
|
||||||
group.add(user)
|
group.add(user)
|
||||||
h = CategoryUser.notification_levels_for(Guardian.new(user))
|
h = CategoryUser.notification_levels_for(user)
|
||||||
expect(h[category1.id]).to eq(levels[:regular])
|
expect(h[category1.id]).to eq(levels[:regular])
|
||||||
expect(h[category2.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[category3.id]).to eq(levels[:watching_first_post])
|
||||||
|
@ -89,7 +89,7 @@ describe GroupUser do
|
||||||
group.tracking_category_ids = [category4.id]
|
group.tracking_category_ids = [category4.id]
|
||||||
group.save!
|
group.save!
|
||||||
group.add(user)
|
group.add(user)
|
||||||
h = CategoryUser.notification_levels_for(Guardian.new(user))
|
h = CategoryUser.notification_levels_for(user)
|
||||||
expect(h[category1.id]).to eq(levels[:tracking])
|
expect(h[category1.id]).to eq(levels[:tracking])
|
||||||
expect(h[category2.id]).to eq(levels[:watching])
|
expect(h[category2.id]).to eq(levels[:watching])
|
||||||
expect(h[category3.id]).to eq(levels[:muted])
|
expect(h[category3.id]).to eq(levels[:muted])
|
||||||
|
|
|
@ -234,7 +234,6 @@ describe TagUser do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#notification_levels_for" do
|
describe "#notification_levels_for" do
|
||||||
let(:guardian) { Guardian.new(user) }
|
|
||||||
let!(:tag1) { Fabricate(:tag) }
|
let!(:tag1) { Fabricate(:tag) }
|
||||||
let!(:tag2) { Fabricate(:tag) }
|
let!(:tag2) { Fabricate(:tag) }
|
||||||
let!(:tag3) { Fabricate(:tag) }
|
let!(:tag3) { Fabricate(:tag) }
|
||||||
|
@ -249,7 +248,7 @@ describe TagUser do
|
||||||
SiteSetting.default_tags_muted = tag4.name
|
SiteSetting.default_tags_muted = tag4.name
|
||||||
end
|
end
|
||||||
it "every tag from the default_tags_* site settings get overridden to watching_first_post, except for muted" do
|
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)
|
levels = TagUser.notification_levels_for(user)
|
||||||
expect(levels[tag1.name]).to eq(TagUser.notification_levels[:regular])
|
expect(levels[tag1.name]).to eq(TagUser.notification_levels[:regular])
|
||||||
expect(levels[tag2.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[tag3.name]).to eq(TagUser.notification_levels[:regular])
|
||||||
|
@ -268,7 +267,7 @@ describe TagUser do
|
||||||
it "gets the tag_user notification levels for all tags the user is tracking and does not
|
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
|
include tags the user is not tracking at all" do
|
||||||
tag5 = Fabricate(:tag)
|
tag5 = Fabricate(:tag)
|
||||||
levels = TagUser.notification_levels_for(guardian)
|
levels = TagUser.notification_levels_for(user)
|
||||||
expect(levels[tag1.name]).to eq(TagUser.notification_levels[:watching])
|
expect(levels[tag1.name]).to eq(TagUser.notification_levels[:watching])
|
||||||
expect(levels[tag2.name]).to eq(TagUser.notification_levels[:tracking])
|
expect(levels[tag2.name]).to eq(TagUser.notification_levels[:tracking])
|
||||||
expect(levels[tag3.name]).to eq(TagUser.notification_levels[:watching_first_post])
|
expect(levels[tag3.name]).to eq(TagUser.notification_levels[:watching_first_post])
|
||||||
|
|
|
@ -60,6 +60,7 @@ describe UserSerializer do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with a user" do
|
context "with a user" do
|
||||||
|
let(:admin_user) { Fabricate(:admin) }
|
||||||
let(:scope) { Guardian.new }
|
let(:scope) { Guardian.new }
|
||||||
fab!(:user) { Fabricate(:user) }
|
fab!(:user) { Fabricate(:user) }
|
||||||
let(:serializer) { UserSerializer.new(user, scope: scope, root: false) }
|
let(:serializer) { UserSerializer.new(user, scope: scope, root: false) }
|
||||||
|
@ -67,6 +68,50 @@ describe UserSerializer do
|
||||||
fab!(:upload) { Fabricate(:upload) }
|
fab!(:upload) { Fabricate(:upload) }
|
||||||
fab!(:upload2) { Fabricate(:upload) }
|
fab!(:upload2) { Fabricate(:upload) }
|
||||||
|
|
||||||
|
context "when the scope user is admin" do
|
||||||
|
let(:scope) { Guardian.new(admin_user) }
|
||||||
|
|
||||||
|
it "returns the user's category notification levels, not the scope user's" do
|
||||||
|
category1 = Fabricate(:category)
|
||||||
|
category2 = Fabricate(:category)
|
||||||
|
category3 = Fabricate(:category)
|
||||||
|
category4 = Fabricate(:category)
|
||||||
|
CategoryUser.create(category: category1, user: user, notification_level: CategoryUser.notification_levels[:muted])
|
||||||
|
CategoryUser.create(category: Fabricate(:category), user: admin_user, notification_level: CategoryUser.notification_levels[:muted])
|
||||||
|
CategoryUser.create(category: category2, user: user, notification_level: CategoryUser.notification_levels[:tracking])
|
||||||
|
CategoryUser.create(category: Fabricate(:category), user: admin_user, notification_level: CategoryUser.notification_levels[:tracking])
|
||||||
|
CategoryUser.create(category: category3, user: user, notification_level: CategoryUser.notification_levels[:watching])
|
||||||
|
CategoryUser.create(category: Fabricate(:category), user: admin_user, notification_level: CategoryUser.notification_levels[:watching])
|
||||||
|
CategoryUser.create(category: category4, user: user, notification_level: CategoryUser.notification_levels[:regular])
|
||||||
|
CategoryUser.create(category: Fabricate(:category), user: admin_user, notification_level: CategoryUser.notification_levels[:regular])
|
||||||
|
|
||||||
|
expect(json[:muted_category_ids]).to eq([category1.id])
|
||||||
|
expect(json[:tracked_category_ids]).to eq([category2.id])
|
||||||
|
expect(json[:watched_category_ids]).to eq([category3.id])
|
||||||
|
expect(json[:regular_category_ids]).to eq([category4.id])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the user's tag notification levels, not the scope user's" do
|
||||||
|
tag1 = Fabricate(:tag)
|
||||||
|
tag2 = Fabricate(:tag)
|
||||||
|
tag3 = Fabricate(:tag)
|
||||||
|
tag4 = Fabricate(:tag)
|
||||||
|
TagUser.create(tag: tag1, user: user, notification_level: TagUser.notification_levels[:muted])
|
||||||
|
TagUser.create(tag: Fabricate(:tag), user: admin_user, notification_level: TagUser.notification_levels[:muted])
|
||||||
|
TagUser.create(tag: tag2, user: user, notification_level: TagUser.notification_levels[:tracking])
|
||||||
|
TagUser.create(tag: Fabricate(:tag), user: admin_user, notification_level: TagUser.notification_levels[:tracking])
|
||||||
|
TagUser.create(tag: tag3, user: user, notification_level: TagUser.notification_levels[:watching])
|
||||||
|
TagUser.create(tag: Fabricate(:tag), user: admin_user, notification_level: TagUser.notification_levels[:watching])
|
||||||
|
TagUser.create(tag: tag4, user: user, notification_level: TagUser.notification_levels[:watching_first_post])
|
||||||
|
TagUser.create(tag: Fabricate(:tag), user: admin_user, notification_level: TagUser.notification_levels[:watching_first_post])
|
||||||
|
|
||||||
|
expect(json[:muted_tags]).to eq([tag1.name])
|
||||||
|
expect(json[:tracked_tags]).to eq([tag2.name])
|
||||||
|
expect(json[:watched_tags]).to eq([tag3.name])
|
||||||
|
expect(json[:watching_first_post_tags]).to eq([tag4.name])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "with `enable_names` true" do
|
context "with `enable_names` true" do
|
||||||
before do
|
before do
|
||||||
SiteSetting.enable_names = true
|
SiteSetting.enable_names = true
|
||||||
|
|
Loading…
Reference in New Issue