mirror of
https://github.com/discourse/discourse.git
synced 2024-11-27 02:13:38 +08:00
3deabb00d4
Previously, PM only tags were being routed to the public topic list with the tag added as a filter. However, the public topic list does not fetch PMs and hence PM only tags did not provide any value when added to the Sidebar. This commit changes that by allowing the client to differentiate PM only tag and thus routes the link to the PM tags show route. Counts for PM only tags section links are not supported as of this commit and will be added in a follow up commit.
428 lines
15 KiB
Ruby
428 lines
15 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
RSpec.describe UserSerializer do
|
|
fab!(:user) { Fabricate(:user, trust_level: 0) }
|
|
|
|
context "with a TL0 user seen as anonymous" do
|
|
let(:serializer) { UserSerializer.new(user, scope: Guardian.new, root: false) }
|
|
let(:json) { serializer.as_json }
|
|
let(:untrusted_attributes) { %i{bio_raw bio_cooked bio_excerpt location website website_name profile_background card_background} }
|
|
|
|
it "doesn't serialize untrusted attributes" do
|
|
untrusted_attributes.each { |attr| expect(json).not_to have_key(attr) }
|
|
end
|
|
|
|
it "serializes correctly" do
|
|
expect(json[:group_users]).to eq(nil)
|
|
expect(json[:second_factor_enabled]).to eq(nil)
|
|
end
|
|
end
|
|
|
|
context "as moderator" do
|
|
it "serializes correctly" do
|
|
json = UserSerializer.new(
|
|
user,
|
|
scope: Guardian.new(Fabricate(:moderator)),
|
|
root: false
|
|
).as_json
|
|
|
|
expect(json[:group_users]).to eq(nil)
|
|
expect(json[:second_factor_enabled]).to eq(nil)
|
|
end
|
|
end
|
|
|
|
context "as current user" do
|
|
it "serializes options correctly" do
|
|
# so we serialize more stuff
|
|
SiteSetting.default_other_auto_track_topics_after_msecs = 0
|
|
SiteSetting.default_other_notification_level_when_replying = 3
|
|
SiteSetting.default_other_new_topic_duration_minutes = 60 * 24
|
|
|
|
user = Fabricate.build(:user,
|
|
id: 1,
|
|
user_profile: Fabricate.build(:user_profile),
|
|
user_option: UserOption.new(dynamic_favicon: true, skip_new_user_tips: true),
|
|
user_stat: UserStat.new,
|
|
created_at: Time.zone.now
|
|
)
|
|
|
|
json = UserSerializer.new(user, scope: Guardian.new(user), root: false).as_json
|
|
|
|
expect(json[:user_option][:dynamic_favicon]).to eq(true)
|
|
expect(json[:user_option][:skip_new_user_tips]).to eq(true)
|
|
expect(json[:user_option][:new_topic_duration_minutes]).to eq(60 * 24)
|
|
expect(json[:user_option][:auto_track_topics_after_msecs]).to eq(0)
|
|
expect(json[:user_option][:notification_level_when_replying]).to eq(3)
|
|
expect(json[:group_users]).to eq([])
|
|
expect(json[:second_factor_enabled]).to eq(false)
|
|
end
|
|
end
|
|
|
|
context "with a user" do
|
|
let(:admin_user) { Fabricate(:admin) }
|
|
let(:scope) { Guardian.new }
|
|
fab!(:user) { Fabricate(:user) }
|
|
let(:serializer) { UserSerializer.new(user, scope: scope, root: false) }
|
|
let(:json) { serializer.as_json }
|
|
fab!(:upload) { 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
|
|
before do
|
|
SiteSetting.enable_names = true
|
|
end
|
|
|
|
it "has a name" do
|
|
expect(json[:name]).to be_present
|
|
end
|
|
end
|
|
|
|
context "with `enable_names` false" do
|
|
before do
|
|
SiteSetting.enable_names = false
|
|
end
|
|
|
|
it "has a name" do
|
|
expect(json[:name]).to be_blank
|
|
end
|
|
end
|
|
|
|
context "with filled out backgrounds" do
|
|
before do
|
|
user.user_profile.upload_card_background(upload)
|
|
user.user_profile.upload_profile_background(upload2)
|
|
end
|
|
|
|
it "has a profile background" do
|
|
expect(json[:card_background_upload_url]).to eq(upload.url)
|
|
expect(json[:profile_background_upload_url]).to eq(upload2.url)
|
|
end
|
|
end
|
|
|
|
context "with filled out website" do
|
|
context "when website has a path" do
|
|
before do
|
|
user.user_profile.website = 'http://example.com/user'
|
|
end
|
|
|
|
it "has a website with a path" do
|
|
expect(json[:website]).to eq 'http://example.com/user'
|
|
end
|
|
|
|
it "returns complete website name with path" do
|
|
expect(json[:website_name]).to eq 'example.com/user'
|
|
end
|
|
end
|
|
|
|
context "when website has a subdomain" do
|
|
before do
|
|
user.user_profile.website = 'http://subdomain.example.com/user'
|
|
end
|
|
|
|
it "has a website with a subdomain" do
|
|
expect(json[:website]).to eq 'http://subdomain.example.com/user'
|
|
end
|
|
|
|
it "returns website name with the subdomain" do
|
|
expect(json[:website_name]).to eq 'subdomain.example.com/user'
|
|
end
|
|
end
|
|
|
|
context "when website has www" do
|
|
before do
|
|
user.user_profile.website = 'http://www.example.com/user'
|
|
end
|
|
|
|
it "has a website with the www" do
|
|
expect(json[:website]).to eq 'http://www.example.com/user'
|
|
end
|
|
|
|
it "returns website name without the www" do
|
|
expect(json[:website_name]).to eq 'example.com/user'
|
|
end
|
|
end
|
|
|
|
context "when website includes query parameters" do
|
|
before do
|
|
user.user_profile.website = 'http://example.com/user?ref=payme'
|
|
end
|
|
|
|
it "has a website with query params" do
|
|
expect(json[:website]).to eq 'http://example.com/user?ref=payme'
|
|
end
|
|
|
|
it "has a website name without query params" do
|
|
expect(json[:website_name]).to eq 'example.com/user'
|
|
end
|
|
end
|
|
|
|
context "when website is not a valid url" do
|
|
before do
|
|
user.user_profile.website = 'invalid-url'
|
|
end
|
|
|
|
it "has a website with the invalid url" do
|
|
expect(json[:website]).to eq 'invalid-url'
|
|
end
|
|
|
|
it "has a nil website name" do
|
|
expect(json[:website_name]).to eq nil
|
|
end
|
|
end
|
|
end
|
|
|
|
context "with filled out bio" do
|
|
before do
|
|
user.user_profile.bio_raw = 'my raw bio'
|
|
user.user_profile.bio_cooked = 'my cooked bio'
|
|
end
|
|
|
|
it "has a bio" do
|
|
expect(json[:bio_raw]).to eq 'my raw bio'
|
|
end
|
|
|
|
it "has a cooked bio" do
|
|
expect(json[:bio_cooked]).to eq 'my cooked bio'
|
|
end
|
|
end
|
|
|
|
describe "second_factor_enabled" do
|
|
let(:scope) { Guardian.new(user) }
|
|
it "is false by default" do
|
|
expect(json[:second_factor_enabled]).to eq(false)
|
|
end
|
|
|
|
context "when totp enabled" do
|
|
before do
|
|
User.any_instance.stubs(:totp_enabled?).returns(true)
|
|
end
|
|
|
|
it "is true" do
|
|
expect(json[:second_factor_enabled]).to eq(true)
|
|
end
|
|
end
|
|
|
|
context "when security_keys enabled" do
|
|
before do
|
|
User.any_instance.stubs(:security_keys_enabled?).returns(true)
|
|
end
|
|
|
|
it "is true" do
|
|
expect(json[:second_factor_enabled]).to eq(true)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "ignored and muted" do
|
|
fab!(:viewing_user) { Fabricate(:user) }
|
|
let(:scope) { Guardian.new(viewing_user) }
|
|
|
|
it 'returns false values for muted and ignored' do
|
|
expect(json[:ignored]).to eq(false)
|
|
expect(json[:muted]).to eq(false)
|
|
end
|
|
|
|
context 'when ignored' do
|
|
before do
|
|
Fabricate(:ignored_user, user: viewing_user, ignored_user: user)
|
|
viewing_user.reload
|
|
end
|
|
|
|
it 'returns true for ignored' do
|
|
expect(json[:ignored]).to eq(true)
|
|
expect(json[:muted]).to eq(false)
|
|
end
|
|
end
|
|
|
|
context 'when muted' do
|
|
before do
|
|
Fabricate(:muted_user, user: viewing_user, muted_user: user)
|
|
viewing_user.reload
|
|
end
|
|
|
|
it 'returns true for muted' do
|
|
expect(json[:muted]).to eq(true)
|
|
expect(json[:ignored]).to eq(false)
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
context "with custom_fields" do
|
|
fab!(:user) { Fabricate(:user) }
|
|
let(:json) { UserSerializer.new(user, scope: Guardian.new, root: false).as_json }
|
|
|
|
before do
|
|
user.custom_fields['secret_field'] = 'Only for me to know'
|
|
user.custom_fields['public_field'] = 'Everyone look here'
|
|
user.save
|
|
end
|
|
|
|
it "doesn't serialize the fields by default" do
|
|
json[:custom_fields]
|
|
expect(json[:custom_fields]).to be_empty
|
|
end
|
|
|
|
it "serializes the fields listed in public_user_custom_fields site setting" do
|
|
SiteSetting.public_user_custom_fields = 'public_field'
|
|
expect(json[:custom_fields]['public_field']).to eq(user.custom_fields['public_field'])
|
|
expect(json[:custom_fields]['secret_field']).to eq(nil)
|
|
end
|
|
|
|
context "with user custom field" do
|
|
before do
|
|
plugin = Plugin::Instance.new
|
|
plugin.allow_public_user_custom_field :public_field
|
|
end
|
|
|
|
after do
|
|
DiscoursePluginRegistry.reset!
|
|
end
|
|
|
|
it "serializes the fields listed in public_user_custom_fields" do
|
|
expect(json[:custom_fields]['public_field']).to eq(user.custom_fields['public_field'])
|
|
expect(json[:custom_fields]['secret_field']).to eq(nil)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "with user fields" do
|
|
fab!(:user) { Fabricate(:user) }
|
|
|
|
let! :fields do
|
|
[
|
|
Fabricate(:user_field),
|
|
Fabricate(:user_field),
|
|
Fabricate(:user_field, show_on_profile: true),
|
|
Fabricate(:user_field, show_on_user_card: true),
|
|
Fabricate(:user_field, show_on_user_card: true, show_on_profile: true)
|
|
]
|
|
end
|
|
|
|
let(:other_user_json) { UserSerializer.new(user, scope: Guardian.new(Fabricate(:user)), root: false).as_json }
|
|
let(:self_json) { UserSerializer.new(user, scope: Guardian.new(user), root: false).as_json }
|
|
let(:admin_json) { UserSerializer.new(user, scope: Guardian.new(Fabricate(:admin)), root: false).as_json }
|
|
|
|
it "includes the correct fields for each audience" do
|
|
expect(admin_json[:user_fields].keys).to contain_exactly(*fields.map { |f| f.id.to_s })
|
|
expect(other_user_json[:user_fields].keys).to contain_exactly(*fields[2..5].map { |f| f.id.to_s })
|
|
expect(self_json[:user_fields].keys).to contain_exactly(*fields.map { |f| f.id.to_s })
|
|
end
|
|
|
|
end
|
|
|
|
context "with user_api_keys" do
|
|
fab!(:user) { Fabricate(:user) }
|
|
|
|
it "sorts keys by last used time" do
|
|
freeze_time
|
|
|
|
user_api_key_0 = Fabricate(:readonly_user_api_key, user: user, last_used_at: 2.days.ago, revoked_at: Time.zone.now)
|
|
user_api_key_1 = Fabricate(:readonly_user_api_key, user: user, last_used_at: 7.days.ago)
|
|
user_api_key_2 = Fabricate(:readonly_user_api_key, user: user, last_used_at: 1.days.ago)
|
|
user_api_key_3 = Fabricate(:readonly_user_api_key, user: user, last_used_at: 4.days.ago, revoked_at: Time.zone.now)
|
|
user_api_key_4 = Fabricate(:readonly_user_api_key, user: user, last_used_at: 3.days.ago)
|
|
|
|
json = UserSerializer.new(user, scope: Guardian.new(user), root: false).as_json
|
|
|
|
expect(json[:user_api_keys].size).to eq(3)
|
|
expect(json[:user_api_keys][0][:id]).to eq(user_api_key_1.id)
|
|
expect(json[:user_api_keys][1][:id]).to eq(user_api_key_4.id)
|
|
expect(json[:user_api_keys][2][:id]).to eq(user_api_key_2.id)
|
|
end
|
|
end
|
|
|
|
describe '#sidebar_tags' do
|
|
fab!(:tag_sidebar_section_link) { Fabricate(:tag_sidebar_section_link, user: user) }
|
|
fab!(:tag_sidebar_section_link_2) { Fabricate(:tag_sidebar_section_link, user: user) }
|
|
|
|
context 'when viewing self' do
|
|
subject(:json) { UserSerializer.new(user, scope: Guardian.new(user), root: false).as_json }
|
|
|
|
it "is not included when SiteSeting.enable_experimental_sidebar_hamburger is false" do
|
|
SiteSetting.enable_experimental_sidebar_hamburger = false
|
|
SiteSetting.tagging_enabled = true
|
|
|
|
expect(json[:sidebar_tags]).to eq(nil)
|
|
end
|
|
|
|
it "is not included when SiteSeting.tagging_enabled is false" do
|
|
SiteSetting.enable_experimental_sidebar_hamburger = true
|
|
SiteSetting.tagging_enabled = false
|
|
|
|
expect(json[:sidebar_tags]).to eq(nil)
|
|
end
|
|
|
|
it "is present when experimental sidebar and tagging has been enabled" do
|
|
SiteSetting.enable_experimental_sidebar_hamburger = true
|
|
SiteSetting.tagging_enabled = true
|
|
|
|
tag_sidebar_section_link_2.linkable.update!(pm_topic_count: 5, topic_count: 0)
|
|
|
|
expect(json[:sidebar_tags]).to contain_exactly(
|
|
{ name: tag_sidebar_section_link.linkable.name, pm_only: false },
|
|
{ name: tag_sidebar_section_link_2.linkable.name, pm_only: true }
|
|
)
|
|
end
|
|
end
|
|
|
|
context 'when viewing another user' do
|
|
fab!(:user2) { Fabricate(:user) }
|
|
|
|
subject(:json) { UserSerializer.new(user, scope: Guardian.new(user2), root: false).as_json }
|
|
|
|
it "is not present even when experimental sidebar and tagging has been enabled" do
|
|
SiteSetting.enable_experimental_sidebar_hamburger = true
|
|
SiteSetting.tagging_enabled = true
|
|
|
|
expect(json[:sidebar_tags]).to eq(nil)
|
|
end
|
|
end
|
|
end
|
|
end
|