FEATURE: topic title is validated for blocked words (#8127)
Currently, the topic is only validated for censored words and should be validated for blocked words as well. Blocked word validation is now used by both Post and Topic. To avoid code duplication, I extracted blocked words validation code into separate Validator, and use it in both places. The only downside is that even if the topic contains blocked words validation message is saying "Your post contains a word that's not allowed: tomato" but I think this is descriptive enough.
This commit is contained in:
parent
0b93f1239b
commit
f331b5eab2
|
@ -74,6 +74,7 @@ class Topic < ActiveRecord::Base
|
||||||
presence: true,
|
presence: true,
|
||||||
topic_title_length: true,
|
topic_title_length: true,
|
||||||
censored_words: true,
|
censored_words: true,
|
||||||
|
watched_words: true,
|
||||||
quality_title: { unless: :private_message? },
|
quality_title: { unless: :private_message? },
|
||||||
max_emojis: true,
|
max_emojis: true,
|
||||||
unique_among: { unless: Proc.new { |t| (SiteSetting.allow_duplicate_topic_titles? || t.private_message?) },
|
unique_among: { unless: Proc.new { |t| (SiteSetting.allow_duplicate_topic_titles? || t.private_message?) },
|
||||||
|
|
|
@ -36,7 +36,7 @@ class Validators::PostValidator < ActiveModel::Validator
|
||||||
return if options[:skip_post_body] || post.topic&.pm_with_non_human_user?
|
return if options[:skip_post_body] || post.topic&.pm_with_non_human_user?
|
||||||
stripped_length(post)
|
stripped_length(post)
|
||||||
raw_quality(post)
|
raw_quality(post)
|
||||||
watched_words(post)
|
WatchedWordsValidator.new(attributes: [:raw]).validate(post) if !post.acting_user&.staged
|
||||||
end
|
end
|
||||||
|
|
||||||
def stripped_length(post)
|
def stripped_length(post)
|
||||||
|
@ -59,19 +59,6 @@ class Validators::PostValidator < ActiveModel::Validator
|
||||||
post.errors.add(:raw, I18n.t(:is_invalid)) unless sentinel.valid?
|
post.errors.add(:raw, I18n.t(:is_invalid)) unless sentinel.valid?
|
||||||
end
|
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
|
# Ensure maximum amount of mentions in a post
|
||||||
def max_mention_validator(post)
|
def max_mention_validator(post)
|
||||||
return if post.acting_user.try(:staff?)
|
return if post.acting_user.try(:staff?)
|
||||||
|
|
|
@ -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
|
|
@ -86,6 +86,22 @@ describe Topic do
|
||||||
end
|
end
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue