mirror of
https://github.com/discourse/discourse.git
synced 2025-02-24 06:28:52 +00:00
The previous method for reused the PrettyText logic which applied the watched word logic, but had the unwanted effect of cooking the text too. This meant that regular text values were converted to HTML. Follow up to commit 5a4c35f62714d2d72bc0ee57a10e08116bdc476a.
297 lines
11 KiB
Ruby
297 lines
11 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
RSpec.describe UserProfile do
|
|
describe "Validations" do
|
|
subject(:profile) { user.user_profile }
|
|
|
|
fab!(:user) { Fabricate(:user) }
|
|
fab!(:watched_word) { Fabricate(:watched_word, word: "bad") }
|
|
|
|
describe "#location" do
|
|
context "when it contains watched words" do
|
|
before { profile.location = location }
|
|
|
|
context "when watched words are of type 'Block'" do
|
|
let(:location) { "bad location" }
|
|
|
|
it "is not valid" do
|
|
profile.valid?
|
|
expect(profile.errors[:base].size).to eq(1)
|
|
expect(profile.errors.messages[:base]).to include(/you can't post the word/)
|
|
end
|
|
end
|
|
|
|
context "when watched words are of type 'Censor'" do
|
|
let!(:censored_word) { Fabricate(:watched_word, word: "censored", action: WatchedWord.actions[:censor]) }
|
|
let(:location) { "censored location" }
|
|
|
|
it "censors the words upon saving" do
|
|
expect { profile.save! }.to change { profile.location }.to eq "■■■■■■■■ location"
|
|
end
|
|
end
|
|
|
|
context "when watched words are of type 'Replace'" do
|
|
let(:location) { "word to replace" }
|
|
let!(:replace_word) do
|
|
Fabricate(:watched_word, word: "to replace", replacement: "replaced", action: WatchedWord.actions[:replace])
|
|
end
|
|
|
|
it "replaces the words upon saving" do
|
|
expect { profile.save! }.to change { profile.location }.to eq "word replaced"
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when it does not contain watched words" do
|
|
it { is_expected.to be_valid }
|
|
end
|
|
|
|
it "is not cooked" do
|
|
profile.location = "https://discourse.org"
|
|
expect { profile.save! }.not_to change { profile.location }
|
|
end
|
|
end
|
|
|
|
describe "#bio_raw" do
|
|
context "when it contains watched words" do
|
|
before { profile.bio_raw = "bad bio" }
|
|
|
|
it "is not valid" do
|
|
profile.valid?
|
|
expect(profile.errors[:base].size).to eq(1)
|
|
expect(profile.errors.messages[:base]).to include(/you can't post the word/)
|
|
end
|
|
end
|
|
|
|
context "when it does not contain watched words" do
|
|
it { is_expected.to be_valid }
|
|
end
|
|
end
|
|
end
|
|
|
|
it 'is created automatically when a user is created' do
|
|
user = Fabricate(:evil_trout)
|
|
expect(user.user_profile).to be_present
|
|
end
|
|
|
|
describe 'rebaking' do
|
|
it 'correctly rebakes bio' do
|
|
user_profile = Fabricate(:evil_trout).user_profile
|
|
user_profile.update_columns(bio_raw: "test", bio_cooked: "broken", bio_cooked_version: nil)
|
|
|
|
problems = UserProfile.rebake_old(10)
|
|
expect(problems.length).to eq(0)
|
|
|
|
user_profile.reload
|
|
expect(user_profile.bio_cooked).to eq("<p>test</p>")
|
|
expect(user_profile.bio_cooked_version).to eq(UserProfile::BAKED_VERSION)
|
|
end
|
|
end
|
|
|
|
describe 'new' do
|
|
let(:user_profile) { UserProfile.new(bio_raw: "test") }
|
|
|
|
it 'is not valid without user' do
|
|
expect(user_profile.valid?).to be false
|
|
end
|
|
|
|
it 'is is valid with user' do
|
|
user_profile.user = Fabricate.build(:user)
|
|
expect(user_profile.valid?).to be true
|
|
end
|
|
|
|
it "doesn't support really long bios" do
|
|
user_profile = Fabricate.build(:user_profile_long)
|
|
expect(user_profile).not_to be_valid
|
|
end
|
|
|
|
context "website validation" do
|
|
let(:user_profile) { Fabricate.build(:user_profile, user: Fabricate(:user)) }
|
|
|
|
it "should not allow invalid URLs" do
|
|
user_profile.website = "http://https://google.com"
|
|
expect(user_profile).to_not be_valid
|
|
end
|
|
|
|
it "validates website domain if allowed_user_website_domains setting is present" do
|
|
SiteSetting.allowed_user_website_domains = "discourse.org"
|
|
|
|
user_profile.website = "https://google.com"
|
|
expect(user_profile).not_to be_valid
|
|
|
|
user_profile.website = "http://discourse.org"
|
|
expect(user_profile).to be_valid
|
|
end
|
|
|
|
it "doesn't blow up with an invalid URI" do
|
|
SiteSetting.allowed_user_website_domains = "discourse.org"
|
|
|
|
user_profile.website = 'user - https://forum.example.com/user'
|
|
expect { user_profile.save! }.to raise_error(ActiveRecord::RecordInvalid)
|
|
end
|
|
end
|
|
|
|
describe 'after save' do
|
|
fab!(:user) { Fabricate(:user) }
|
|
|
|
before do
|
|
user.user_profile.bio_raw = 'my bio'
|
|
user.user_profile.save
|
|
end
|
|
|
|
it 'has cooked bio' do
|
|
expect(user.user_profile.bio_cooked).to be_present
|
|
end
|
|
|
|
it 'has bio summary' do
|
|
expect(user.user_profile.bio_summary).to be_present
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'changing bio' do
|
|
fab!(:user) { Fabricate(:user) }
|
|
|
|
before do
|
|
user.user_profile.bio_raw = "**turtle power!**"
|
|
user.user_profile.save
|
|
user.user_profile.reload
|
|
end
|
|
|
|
it 'should markdown the raw_bio and put it in cooked_bio' do
|
|
expect(user.user_profile.bio_cooked).to eq("<p><strong>turtle power!</strong></p>")
|
|
end
|
|
end
|
|
|
|
describe 'bio excerpt emojis' do
|
|
fab!(:user) { Fabricate(:user) }
|
|
fab!(:upload) { Fabricate(:upload) }
|
|
|
|
before do
|
|
CustomEmoji.create!(name: 'test', upload: upload)
|
|
Emoji.clear_cache
|
|
|
|
user.user_profile.update!(
|
|
bio_raw: "hello :test: :woman_scientist:t5: 🤔"
|
|
)
|
|
end
|
|
|
|
it 'supports emoji images' do
|
|
expect(user.user_profile.bio_excerpt(500, keep_emoji_images: true)).to eq("hello <img src=\"#{upload.url}?v=#{Emoji::EMOJI_VERSION}\" title=\":test:\" class=\"emoji emoji-custom\" alt=\":test:\" loading=\"lazy\" width=\"20\" height=\"20\"> <img src=\"/images/emoji/twitter/woman_scientist/5.png?v=#{Emoji::EMOJI_VERSION}\" title=\":woman_scientist:t5:\" class=\"emoji\" alt=\":woman_scientist:t5:\" loading=\"lazy\" width=\"20\" height=\"20\"> <img src=\"/images/emoji/twitter/thinking.png?v=#{Emoji::EMOJI_VERSION}\" title=\":thinking:\" class=\"emoji\" alt=\":thinking:\" loading=\"lazy\" width=\"20\" height=\"20\">")
|
|
end
|
|
end
|
|
|
|
describe 'bio link stripping' do
|
|
|
|
it 'returns an empty string with no bio' do
|
|
expect(Fabricate.build(:user_profile).bio_excerpt).to be_blank
|
|
end
|
|
|
|
context 'with a user that has a link in their bio' do
|
|
let(:user_profile) { Fabricate.build(:user_profile, bio_raw: "I love http://discourse.org") }
|
|
let(:user) do
|
|
user = Fabricate.build(:user, user_profile: user_profile)
|
|
user_profile.user = user
|
|
user
|
|
end
|
|
|
|
fab!(:created_user) do
|
|
user = Fabricate(:user)
|
|
user.user_profile.bio_raw = 'I love http://discourse.org'
|
|
user.user_profile.save!
|
|
user
|
|
end
|
|
|
|
it 'includes the link as nofollow if the user is not new' do
|
|
user.user_profile.send(:cook)
|
|
expect(user_profile.bio_excerpt).to match_html("I love <a href='http://discourse.org' rel='noopener nofollow ugc'>http://discourse.org</a>")
|
|
expect(user_profile.bio_processed).to match_html("<p>I love <a href=\"http://discourse.org\" rel=\"noopener nofollow ugc\">http://discourse.org</a></p>")
|
|
end
|
|
|
|
it 'removes the link if the user is new' do
|
|
user.trust_level = TrustLevel[0]
|
|
user_profile.send(:cook)
|
|
expect(user_profile.bio_excerpt).to match_html("I love http://discourse.org")
|
|
expect(user_profile.bio_processed).to eq("<p>I love http://discourse.org</p>")
|
|
end
|
|
|
|
it 'removes the link if the user is suspended' do
|
|
user.suspended_till = 1.month.from_now
|
|
user_profile.send(:cook)
|
|
expect(user_profile.bio_excerpt).to match_html("I love http://discourse.org")
|
|
expect(user_profile.bio_processed).to eq("<p>I love http://discourse.org</p>")
|
|
end
|
|
|
|
context 'tl3_links_no_follow is false' do
|
|
before { SiteSetting.tl3_links_no_follow = false }
|
|
|
|
it 'includes the link without nofollow if the user is trust level 3 or higher' do
|
|
user.trust_level = TrustLevel[3]
|
|
user_profile.send(:cook)
|
|
expect(user_profile.bio_excerpt).to match_html("I love <a href='http://discourse.org'>http://discourse.org</a>")
|
|
expect(user_profile.bio_processed).to match_html("<p>I love <a href=\"http://discourse.org\">http://discourse.org</a></p>")
|
|
end
|
|
|
|
it 'removes nofollow from links in bio when trust level is increased' do
|
|
created_user.change_trust_level!(TrustLevel[3])
|
|
expect(created_user.user_profile.bio_excerpt).to match_html("I love <a href='http://discourse.org'>http://discourse.org</a>")
|
|
expect(created_user.user_profile.bio_processed).to match_html("<p>I love <a href=\"http://discourse.org\">http://discourse.org</a></p>")
|
|
end
|
|
|
|
it 'adds nofollow to links in bio when trust level is decreased' do
|
|
created_user.trust_level = TrustLevel[3]
|
|
created_user.save
|
|
created_user.reload
|
|
created_user.change_trust_level!(TrustLevel[2])
|
|
expect(created_user.user_profile.bio_excerpt).to match_html("I love <a href='http://discourse.org' rel='noopener nofollow ugc'>http://discourse.org</a>")
|
|
expect(created_user.user_profile.bio_processed).to match_html("<p>I love <a href=\"http://discourse.org\" rel=\"noopener nofollow ugc\">http://discourse.org</a></p>")
|
|
end
|
|
end
|
|
|
|
context 'tl3_links_no_follow is true' do
|
|
before { SiteSetting.tl3_links_no_follow = true }
|
|
|
|
it 'includes the link with nofollow if the user is trust level 3 or higher' do
|
|
user.trust_level = TrustLevel[3]
|
|
user_profile.send(:cook)
|
|
expect(user_profile.bio_excerpt).to match_html("I love <a href='http://discourse.org' rel='noopener nofollow ugc'>http://discourse.org</a>")
|
|
expect(user_profile.bio_processed).to match_html("<p>I love <a href=\"http://discourse.org\" rel=\"noopener nofollow ugc\">http://discourse.org</a></p>")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context '.import_url_for_user' do
|
|
fab!(:user) { Fabricate(:user) }
|
|
|
|
before do
|
|
stub_request(:any, "thisfakesomething.something.com")
|
|
.to_return(body: "abc", status: 404, headers: { 'Content-Length' => 3 })
|
|
end
|
|
|
|
describe 'when profile_background_url returns an invalid status code' do
|
|
it 'should not do anything' do
|
|
url = "http://thisfakesomething.something.com/"
|
|
|
|
UserProfile.import_url_for_user(url, user, is_card_background: false)
|
|
|
|
user.reload
|
|
|
|
expect(user.profile_background_upload).to eq(nil)
|
|
end
|
|
end
|
|
|
|
describe 'when card_background_url returns an invalid status code' do
|
|
it 'should not do anything' do
|
|
url = "http://thisfakesomething.something.com/"
|
|
|
|
UserProfile.import_url_for_user(url, user, is_card_background: true)
|
|
|
|
user.reload
|
|
|
|
expect(user.card_background_upload).to eq(nil)
|
|
end
|
|
end
|
|
end
|
|
end
|