FIX: Apply all watched words rules to user fields
Currently we only apply watched words of the `Block` type to custom user fields and user profile fields. This patch enables all rules to be applied such as `Censor` or `Replace`.
This commit is contained in:
parent
3b4ed134ba
commit
5a4c35f627
|
@ -146,6 +146,7 @@ class User < ActiveRecord::Base
|
|||
before_save :ensure_password_is_hashed
|
||||
before_save :match_primary_group_changes
|
||||
before_save :check_if_title_is_badged_granted
|
||||
before_save :apply_watched_words, unless: :custom_fields_clean?
|
||||
|
||||
after_save :expire_tokens_if_password_changed
|
||||
after_save :clear_global_notice_if_needed
|
||||
|
@ -1273,14 +1274,24 @@ class User < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def public_user_field_values
|
||||
@public_user_field_ids ||= UserField.public_fields.pluck(:id)
|
||||
user_fields(@public_user_field_ids).values.join(" ")
|
||||
public_user_fields.values.join(" ")
|
||||
end
|
||||
|
||||
def set_user_field(field_id, value)
|
||||
custom_fields["#{USER_FIELD_PREFIX}#{field_id}"] = value
|
||||
end
|
||||
|
||||
def apply_watched_words
|
||||
public_user_fields.each do |id, value|
|
||||
set_user_field(id, PrettyText.cook(value).gsub(/^<p>(.*)<\/p>$/, "\\1"))
|
||||
end
|
||||
end
|
||||
|
||||
def public_user_fields
|
||||
@public_user_field_ids ||= UserField.public_fields.pluck(:id)
|
||||
user_fields(@public_user_field_ids)
|
||||
end
|
||||
|
||||
def number_of_deleted_posts
|
||||
Post.with_deleted
|
||||
.where(user_id: self.id)
|
||||
|
|
|
@ -1,19 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class UserProfile < ActiveRecord::Base
|
||||
BAKED_VERSION = 1
|
||||
|
||||
belongs_to :user, inverse_of: :user_profile
|
||||
belongs_to :card_background_upload, class_name: "Upload"
|
||||
belongs_to :profile_background_upload, class_name: "Upload"
|
||||
belongs_to :granted_title_badge, class_name: "Badge"
|
||||
belongs_to :featured_topic, class_name: 'Topic'
|
||||
|
||||
has_many :upload_references, as: :target, dependent: :destroy
|
||||
has_many :user_profile_views, dependent: :destroy
|
||||
|
||||
validates :bio_raw, length: { maximum: 3000 }, watched_words: true
|
||||
validates :website, url: true, allow_blank: true, if: Proc.new { |c| c.new_record? || c.website_changed? }
|
||||
validates :website, url: true, allow_blank: true, if: :validate_website?
|
||||
validates :user, presence: true
|
||||
validates :location, watched_words: true
|
||||
|
||||
validate :website_domain_validator, if: :validate_website?
|
||||
|
||||
before_save :cook
|
||||
before_save :apply_watched_words, if: :location?
|
||||
|
||||
after_save :trigger_badges
|
||||
after_save :pull_hotlinked_image
|
||||
|
||||
|
@ -24,12 +32,6 @@ class UserProfile < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
validate :website_domain_validator, if: Proc.new { |c| c.new_record? || c.website_changed? }
|
||||
|
||||
has_many :user_profile_views, dependent: :destroy
|
||||
|
||||
BAKED_VERSION = 1
|
||||
|
||||
attr_accessor :skip_pull_hotlinked_image
|
||||
|
||||
def bio_excerpt(length = 350, opts = {})
|
||||
|
@ -138,6 +140,10 @@ class UserProfile < ActiveRecord::Base
|
|||
|
||||
private
|
||||
|
||||
def self.remove_featured_topic_from_all_profiles(topic)
|
||||
where(featured_topic_id: topic.id).update_all(featured_topic_id: nil)
|
||||
end
|
||||
|
||||
def cooked
|
||||
if self.bio_raw.present?
|
||||
PrettyText.cook(self.bio_raw, omit_nofollow: user.has_trust_level?(TrustLevel[3]) && !SiteSetting.tl3_links_no_follow)
|
||||
|
@ -157,6 +163,10 @@ class UserProfile < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def apply_watched_words
|
||||
self.location = PrettyText.cook(location).gsub(/^<p>(.*)<\/p>$/, "\\1")
|
||||
end
|
||||
|
||||
def website_domain_validator
|
||||
allowed_domains = SiteSetting.allowed_user_website_domains
|
||||
return if (allowed_domains.blank? || self.website.blank?)
|
||||
|
@ -168,8 +178,8 @@ class UserProfile < ActiveRecord::Base
|
|||
self.errors.add :base, (I18n.t('user.website.domain_not_allowed', domains: allowed_domains.split('|').join(", "))) unless allowed_domains.split('|').include?(domain)
|
||||
end
|
||||
|
||||
def self.remove_featured_topic_from_all_profiles(topic)
|
||||
where(featured_topic_id: topic.id).update_all(featured_topic_id: nil)
|
||||
def validate_website?
|
||||
new_record? || website_changed?
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -9,12 +9,36 @@ RSpec.describe UserProfile do
|
|||
|
||||
describe "#location" do
|
||||
context "when it contains watched words" do
|
||||
before { profile.location = "bad location" }
|
||||
before { profile.location = 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/)
|
||||
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
|
||||
|
||||
|
|
|
@ -153,20 +153,68 @@ RSpec.describe User do
|
|||
before { user.set_user_field(user_field.id, value) }
|
||||
|
||||
context "when user fields contain watched words" do
|
||||
let(:value) { "bad user field value" }
|
||||
let(:user_field_value) { user.reload.user_fields[user_field.id.to_s] }
|
||||
|
||||
context "when user field is public" do
|
||||
it "is not valid" do
|
||||
user.valid?
|
||||
expect(user.errors[:base].size).to eq(1)
|
||||
expect(user.errors.messages[:base]).to include(/you can't post the word/)
|
||||
context "when watched words are of type 'Block'" do
|
||||
let(:value) { "bad user field value" }
|
||||
|
||||
context "when user field is public" do
|
||||
it "is not valid" do
|
||||
user.valid?
|
||||
expect(user.errors[:base].size).to eq(1)
|
||||
expect(user.errors.messages[:base]).to include(/you can't post the word/)
|
||||
end
|
||||
end
|
||||
|
||||
context "when user field is private" do
|
||||
before { user_field.update(show_on_profile: false) }
|
||||
|
||||
it { is_expected.to be_valid }
|
||||
end
|
||||
end
|
||||
|
||||
context "when user field is private" do
|
||||
before { user_field.update(show_on_profile: false) }
|
||||
context "when watched words are of type 'Censor'" do
|
||||
let!(:censored_word) { Fabricate(:watched_word, word: "censored", action: WatchedWord.actions[:censor]) }
|
||||
let(:value) { "censored word" }
|
||||
|
||||
it { is_expected.to be_valid }
|
||||
context "when user field is public" do
|
||||
it "censors the words upon saving" do
|
||||
user.save!
|
||||
expect(user_field_value).to eq "■■■■■■■■ word"
|
||||
end
|
||||
end
|
||||
|
||||
context "when user field is private" do
|
||||
before { user_field.update(show_on_profile: false) }
|
||||
|
||||
it "does not censor anything" do
|
||||
user.save!
|
||||
expect(user_field_value).to eq "censored word"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when watched words are of type 'Replace'" do
|
||||
let(:value) { "word to replace" }
|
||||
let!(:replace_word) do
|
||||
Fabricate(:watched_word, word: "to replace", replacement: "replaced", action: WatchedWord.actions[:replace])
|
||||
end
|
||||
|
||||
context "when user field is public" do
|
||||
it "replaces the words upon saving" do
|
||||
user.save!
|
||||
expect(user_field_value).to eq "word replaced"
|
||||
end
|
||||
end
|
||||
|
||||
context "when user field is private" do
|
||||
before { user_field.update(show_on_profile: false) }
|
||||
|
||||
it "does not replace anything" do
|
||||
user.save!
|
||||
expect(user_field_value).to eq "word to replace"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue