diff --git a/app/services/word_watcher.rb b/app/services/word_watcher.rb index 5dbf7a732d1..b9b48761ae3 100644 --- a/app/services/word_watcher.rb +++ b/app/services/word_watcher.rb @@ -15,14 +15,22 @@ class WordWatcher def self.word_matcher_regexp(action) s = Discourse.cache.fetch(word_matcher_regexp_key(action), expires_in: 1.day) do words = words_for_action(action) - words.empty? ? nil : '\b(' + words.map { |w| word_to_regexp(w) }.join('|'.freeze) + ')\b' + if words.empty? + nil + else + regexp = '(' + words.map { |w| word_to_regexp(w) }.join('|'.freeze) + ')' + SiteSetting.watched_words_regular_expressions? ? regexp : "(#{regexp})" + end end - s.present? ? Regexp.new(s, Regexp::IGNORECASE) : nil end def self.word_to_regexp(word) - return word if SiteSetting.watched_words_regular_expressions? + if SiteSetting.watched_words_regular_expressions? + # Strip ruby regexp format if present, we're going to make the whole thing + # case insensitive anyway + return word.start_with?("(?-mix:") ? word[7..-2] : word + end Regexp.escape(word).gsub("\\*", '\S*') end diff --git a/spec/services/word_watcher_spec.rb b/spec/services/word_watcher_spec.rb index ba42f79bc6b..334446502c8 100644 --- a/spec/services/word_watcher_spec.rb +++ b/spec/services/word_watcher_spec.rb @@ -48,20 +48,36 @@ describe WordWatcher do expect(m[1]).to eq("acknowledge") end - it "supports regular expressions as a site setting" do - SiteSetting.watched_words_regular_expressions = true - Fabricate( - :watched_word, - word: "tro[uo]+t", - action: WatchedWord.actions[:require_approval] - ) - m = WordWatcher.new("Evil Trout is cool").word_matches_for_action?(:require_approval) - expect(m[1]).to eq("Trout") - m = WordWatcher.new("Evil Troot is cool").word_matches_for_action?(:require_approval) - expect(m[1]).to eq("Troot") - m = WordWatcher.new("trooooooooot").word_matches_for_action?(:require_approval) - expect(m[1]).to eq("trooooooooot") + context "regular expressions" do + before do + SiteSetting.watched_words_regular_expressions = true + end + + it "supports regular expressions on word boundaries" do + Fabricate( + :watched_word, + word: /\btest\b/, + action: WatchedWord.actions[:block] + ) + m = WordWatcher.new("this is not a test.").word_matches_for_action?(:block) + expect(m[1]).to eq("test") + end + + it "supports regular expressions as a site setting" do + Fabricate( + :watched_word, + word: /tro[uo]+t/, + action: WatchedWord.actions[:require_approval] + ) + m = WordWatcher.new("Evil Trout is cool").word_matches_for_action?(:require_approval) + expect(m[1]).to eq("Trout") + m = WordWatcher.new("Evil Troot is cool").word_matches_for_action?(:require_approval) + expect(m[1]).to eq("Troot") + m = WordWatcher.new("trooooooooot").word_matches_for_action?(:require_approval) + expect(m[1]).to eq("trooooooooot") + end end + end end