diff --git a/app/models/topic.rb b/app/models/topic.rb index b99b9c7015c..208b639d505 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -74,6 +74,7 @@ class Topic < ActiveRecord::Base presence: true, topic_title_length: true, censored_words: true, + watched_words: true, quality_title: { unless: :private_message? }, max_emojis: true, unique_among: { unless: Proc.new { |t| (SiteSetting.allow_duplicate_topic_titles? || t.private_message?) }, diff --git a/lib/validators/post_validator.rb b/lib/validators/post_validator.rb index 09c564b3b19..dc391b63bf5 100644 --- a/lib/validators/post_validator.rb +++ b/lib/validators/post_validator.rb @@ -36,7 +36,7 @@ class Validators::PostValidator < ActiveModel::Validator return if options[:skip_post_body] || post.topic&.pm_with_non_human_user? stripped_length(post) raw_quality(post) - watched_words(post) + WatchedWordsValidator.new(attributes: [:raw]).validate(post) if !post.acting_user&.staged end def stripped_length(post) @@ -59,19 +59,6 @@ class Validators::PostValidator < ActiveModel::Validator post.errors.add(:raw, I18n.t(:is_invalid)) unless sentinel.valid? end - def watched_words(post) - if !post.acting_user&.staged && matches = WordWatcher.new(post.raw).should_block?.presence - if matches.size == 1 - key = 'contains_blocked_word' - translation_args = { word: matches[0] } - else - key = 'contains_blocked_words' - translation_args = { words: matches.join(', ') } - end - post.errors.add(:base, I18n.t(key, translation_args)) - end - end - # Ensure maximum amount of mentions in a post def max_mention_validator(post) return if post.acting_user.try(:staff?) diff --git a/lib/validators/watched_words_validator.rb b/lib/validators/watched_words_validator.rb new file mode 100644 index 00000000000..cfa7e5a6b66 --- /dev/null +++ b/lib/validators/watched_words_validator.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class WatchedWordsValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + if matches = WordWatcher.new(value).should_block?.presence + if matches.size == 1 + key = 'contains_blocked_word' + translation_args = { word: matches[0] } + else + key = 'contains_blocked_words' + translation_args = { words: matches.join(', ') } + end + record.errors.add(:base, I18n.t(key, translation_args)) + end + end +end diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb index e9da4a7c639..0c3f6383531 100644 --- a/spec/models/topic_spec.rb +++ b/spec/models/topic_spec.rb @@ -86,6 +86,22 @@ describe Topic do end end end + + describe 'blocked words' do + describe 'when title contains watched words' do + it 'should not be valid' do + Fabricate(:watched_word, word: 'pineapple', action: WatchedWord.actions[:block]) + + topic.title = 'pen PinEapple apple pen is a complete sentence' + + expect(topic).to_not be_valid + + expect(topic.errors.full_messages.first).to include(I18n.t( + 'contains_blocked_word', word: 'PinEapple' + )) + end + end + end end end