2019-04-29 20:27:42 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2022-07-27 22:27:38 -04:00
|
|
|
RSpec.describe UserSerializer do
|
2020-09-10 22:23:35 -04:00
|
|
|
fab!(:user) { Fabricate(:user, trust_level: 0) }
|
2013-10-30 15:45:13 -04:00
|
|
|
|
2014-11-26 13:20:03 -05:00
|
|
|
context "with a TL0 user seen as anonymous" do
|
|
|
|
let(:serializer) { UserSerializer.new(user, scope: Guardian.new, root: false) }
|
|
|
|
let(:json) { serializer.as_json }
|
2017-06-04 08:58:36 -04:00
|
|
|
let(:untrusted_attributes) { %i{bio_raw bio_cooked bio_excerpt location website website_name profile_background card_background} }
|
2014-11-26 13:20:03 -05:00
|
|
|
|
|
|
|
it "doesn't serialize untrusted attributes" do
|
2014-12-31 09:55:03 -05:00
|
|
|
untrusted_attributes.each { |attr| expect(json).not_to have_key(attr) }
|
2014-11-26 13:20:03 -05:00
|
|
|
end
|
2020-06-15 20:43:06 -04:00
|
|
|
|
2020-09-10 22:23:35 -04:00
|
|
|
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)
|
2020-06-15 20:43:06 -04:00
|
|
|
end
|
2014-11-26 13:20:03 -05:00
|
|
|
end
|
|
|
|
|
2016-02-16 23:46:19 -05:00
|
|
|
context "as current user" do
|
|
|
|
it "serializes options correctly" do
|
|
|
|
# so we serialize more stuff
|
2016-02-18 00:57:22 -05:00
|
|
|
SiteSetting.default_other_auto_track_topics_after_msecs = 0
|
2016-09-30 12:36:43 -04:00
|
|
|
SiteSetting.default_other_notification_level_when_replying = 3
|
2016-02-18 00:57:22 -05:00
|
|
|
SiteSetting.default_other_new_topic_duration_minutes = 60 * 24
|
2016-02-16 23:46:19 -05:00
|
|
|
|
2022-10-25 03:29:09 -04:00
|
|
|
user = Fabricate(:user)
|
|
|
|
user.user_option.update(dynamic_favicon: true, skip_new_user_tips: true)
|
2016-02-16 23:46:19 -05:00
|
|
|
|
|
|
|
json = UserSerializer.new(user, scope: Guardian.new(user), root: false).as_json
|
|
|
|
|
2016-07-16 07:30:00 -04:00
|
|
|
expect(json[:user_option][:dynamic_favicon]).to eq(true)
|
2020-08-14 09:40:56 -04:00
|
|
|
expect(json[:user_option][:skip_new_user_tips]).to eq(true)
|
2016-02-18 00:57:22 -05:00
|
|
|
expect(json[:user_option][:new_topic_duration_minutes]).to eq(60 * 24)
|
|
|
|
expect(json[:user_option][:auto_track_topics_after_msecs]).to eq(0)
|
2016-09-30 12:36:43 -04:00
|
|
|
expect(json[:user_option][:notification_level_when_replying]).to eq(3)
|
2020-06-15 20:43:06 -04:00
|
|
|
expect(json[:group_users]).to eq([])
|
2020-09-10 22:23:35 -04:00
|
|
|
expect(json[:second_factor_enabled]).to eq(false)
|
2016-02-16 23:46:19 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-10-30 15:45:13 -04:00
|
|
|
context "with a user" do
|
2021-05-13 19:45:14 -04:00
|
|
|
let(:admin_user) { Fabricate(:admin) }
|
2019-11-08 00:11:53 -05:00
|
|
|
let(:scope) { Guardian.new }
|
2019-05-10 06:59:31 -04:00
|
|
|
fab!(:user) { Fabricate(:user) }
|
2019-11-08 00:11:53 -05:00
|
|
|
let(:serializer) { UserSerializer.new(user, scope: scope, root: false) }
|
2013-10-30 15:45:13 -04:00
|
|
|
let(:json) { serializer.as_json }
|
2019-05-10 06:59:31 -04:00
|
|
|
fab!(:upload) { Fabricate(:upload) }
|
|
|
|
fab!(:upload2) { Fabricate(:upload) }
|
2013-10-30 15:45:13 -04:00
|
|
|
|
2021-05-13 19:45:14 -04:00
|
|
|
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
|
|
|
|
|
2013-10-30 15:45:13 -04:00
|
|
|
context "with `enable_names` true" do
|
|
|
|
before do
|
2016-02-16 23:46:19 -05:00
|
|
|
SiteSetting.enable_names = true
|
2013-10-30 15:45:13 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "has a name" do
|
2014-12-31 09:55:03 -05:00
|
|
|
expect(json[:name]).to be_present
|
2013-10-30 15:45:13 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "with `enable_names` false" do
|
|
|
|
before do
|
2017-07-07 02:09:14 -04:00
|
|
|
SiteSetting.enable_names = false
|
2013-10-30 15:45:13 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "has a name" do
|
2014-12-31 09:55:03 -05:00
|
|
|
expect(json[:name]).to be_blank
|
2013-10-30 15:45:13 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-04-28 23:58:52 -04:00
|
|
|
context "with filled out backgrounds" do
|
2014-06-11 21:52:50 -04:00
|
|
|
before do
|
2019-04-28 23:58:52 -04:00
|
|
|
user.user_profile.upload_card_background(upload)
|
|
|
|
user.user_profile.upload_profile_background(upload2)
|
2014-06-11 21:52:50 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "has a profile background" do
|
2019-04-28 23:58:52 -04:00
|
|
|
expect(json[:card_background_upload_url]).to eq(upload.url)
|
|
|
|
expect(json[:profile_background_upload_url]).to eq(upload2.url)
|
2014-06-11 21:52:50 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-06-07 15:52:51 -04:00
|
|
|
context "with filled out website" do
|
2016-04-11 01:53:50 -04:00
|
|
|
context "when website has a path" do
|
|
|
|
before do
|
|
|
|
user.user_profile.website = 'http://example.com/user'
|
|
|
|
end
|
2013-10-30 15:45:13 -04:00
|
|
|
|
2016-04-11 01:53:50 -04:00
|
|
|
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
|
2015-08-10 04:07:53 -04:00
|
|
|
end
|
|
|
|
|
2016-04-11 01:53:50 -04:00
|
|
|
context "when website has a subdomain" do
|
|
|
|
before do
|
2016-04-11 10:13:33 -04:00
|
|
|
user.user_profile.website = 'http://subdomain.example.com/user'
|
2016-04-11 01:53:50 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "has a website with a subdomain" do
|
2016-04-11 10:13:33 -04:00
|
|
|
expect(json[:website]).to eq 'http://subdomain.example.com/user'
|
2016-04-11 01:53:50 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "returns website name with the subdomain" do
|
2016-04-11 10:13:33 -04:00
|
|
|
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'
|
2016-04-11 01:53:50 -04:00
|
|
|
end
|
2016-04-09 07:52:55 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
context "when website includes query parameters" do
|
|
|
|
before do
|
|
|
|
user.user_profile.website = 'http://example.com/user?ref=payme'
|
2015-08-10 04:07:53 -04:00
|
|
|
end
|
|
|
|
|
2016-04-09 07:52:55 -04:00
|
|
|
it "has a website with query params" do
|
|
|
|
expect(json[:website]).to eq 'http://example.com/user?ref=payme'
|
2015-08-10 04:07:53 -04:00
|
|
|
end
|
|
|
|
|
2016-04-09 07:52:55 -04:00
|
|
|
it "has a website name without query params" do
|
2015-08-10 04:07:53 -04:00
|
|
|
expect(json[:website_name]).to eq 'example.com/user'
|
|
|
|
end
|
2014-06-07 15:52:51 -04:00
|
|
|
end
|
2016-04-09 07:52:55 -04:00
|
|
|
|
|
|
|
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
|
2014-06-07 15:52:51 -04:00
|
|
|
end
|
2014-06-10 01:19:08 -04:00
|
|
|
|
|
|
|
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
|
2019-11-08 00:11:53 -05:00
|
|
|
|
|
|
|
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
|
2020-01-02 08:04:08 -05:00
|
|
|
|
|
|
|
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
|
2013-10-30 15:45:13 -04:00
|
|
|
end
|
2014-08-19 11:05:35 -04:00
|
|
|
|
|
|
|
context "with custom_fields" do
|
2019-05-06 23:12:20 -04:00
|
|
|
fab!(:user) { Fabricate(:user) }
|
2014-08-19 11:05:35 -04:00
|
|
|
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]
|
2014-12-31 09:55:03 -05:00
|
|
|
expect(json[:custom_fields]).to be_empty
|
2014-08-19 11:05:35 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "serializes the fields listed in public_user_custom_fields site setting" do
|
2017-07-07 02:09:14 -04:00
|
|
|
SiteSetting.public_user_custom_fields = 'public_field'
|
2014-12-31 09:55:03 -05:00
|
|
|
expect(json[:custom_fields]['public_field']).to eq(user.custom_fields['public_field'])
|
|
|
|
expect(json[:custom_fields]['secret_field']).to eq(nil)
|
2014-08-19 11:05:35 -04:00
|
|
|
end
|
2018-10-17 05:33:27 -04:00
|
|
|
|
2018-10-17 05:54:22 -04:00
|
|
|
context "with user custom field" do
|
|
|
|
before do
|
|
|
|
plugin = Plugin::Instance.new
|
2020-07-26 20:23:54 -04:00
|
|
|
plugin.allow_public_user_custom_field :public_field
|
2018-10-17 05:54:22 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
after do
|
2020-05-15 09:04:38 -04:00
|
|
|
DiscoursePluginRegistry.reset!
|
2018-10-17 05:54:22 -04:00
|
|
|
end
|
|
|
|
|
2020-05-15 09:04:38 -04:00
|
|
|
it "serializes the fields listed in public_user_custom_fields" do
|
2018-10-17 05:54:22 -04:00
|
|
|
expect(json[:custom_fields]['public_field']).to eq(user.custom_fields['public_field'])
|
|
|
|
expect(json[:custom_fields]['secret_field']).to eq(nil)
|
|
|
|
end
|
2018-10-17 05:33:27 -04:00
|
|
|
end
|
2014-08-19 11:05:35 -04:00
|
|
|
end
|
2018-12-07 05:57:28 -05:00
|
|
|
|
|
|
|
context "with user fields" do
|
2019-05-06 23:12:20 -04:00
|
|
|
fab!(:user) { Fabricate(:user) }
|
2018-12-07 05:57:28 -05:00
|
|
|
|
|
|
|
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
|
2018-08-22 17:19:01 -04:00
|
|
|
|
|
|
|
context "with user_api_keys" do
|
2019-05-06 23:12:20 -04:00
|
|
|
fab!(:user) { Fabricate(:user) }
|
2018-08-22 17:19:01 -04:00
|
|
|
|
|
|
|
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
|
2022-08-11 23:26:56 -04:00
|
|
|
|
2022-12-22 22:45:29 -05:00
|
|
|
context 'for user sidebar attributes' do
|
|
|
|
include_examples "User Sidebar Serializer Attributes", described_class
|
2022-08-11 23:26:56 -04:00
|
|
|
|
2022-12-22 22:45:29 -05:00
|
|
|
it "does not include attributes when scoped to user that cannot edit user" do
|
|
|
|
user2 = Fabricate(:user)
|
|
|
|
serializer = described_class.new(user, scope: Guardian.new(user2), root: false)
|
2022-08-11 23:26:56 -04:00
|
|
|
|
2022-12-22 22:45:29 -05:00
|
|
|
expect(serializer.as_json[:sidebar_category_ids]).to eq(nil)
|
|
|
|
expect(serializer.as_json[:sidebar_tags]).to eq(nil)
|
|
|
|
expect(serializer.as_json[:sidebar_list_destination]).to eq(nil)
|
|
|
|
expect(serializer.as_json[:display_sidebar_tags]).to eq(nil)
|
2022-08-11 23:26:56 -04:00
|
|
|
end
|
|
|
|
end
|
2013-10-30 15:45:13 -04:00
|
|
|
end
|