Change: #647 NGワードの入力フォーム (#663)

* Change: #647 NGワードの入力フォーム

* Wip: 画面改造

* テストコード、画面

* Fix: 複数の問題
This commit is contained in:
KMY(雪あすか) 2024-03-26 08:44:16 +09:00 committed by GitHub
parent 0d2b415e26
commit 95ab1f729c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 526 additions and 172 deletions

View file

@ -4,20 +4,25 @@ class Admin::NgWord
class << self
def reject?(text, **options)
text = PlainTextFormatter.new(text, false).to_s if options[:uri].present?
hit_word = ng_words.detect { |word| include?(text, word) ? word : nil }
record!(:ng_words, text, hit_word, options) if hit_word.present?
hit_word.present?
if options.delete(:stranger)
::NgWord.caches.detect { |word| include?(text, word) ? word : nil }&.keyword.tap do |hit_word|
record!(:ng_words_for_stranger_mention, text, hit_word, options) if hit_word.present?
end.present?
else
::NgWord.caches.filter { |w| !w.stranger }.detect { |word| include?(text, word) ? word : nil }&.keyword.tap do |hit_word|
record!(:ng_words, text, hit_word, options) if hit_word.present?
end.present?
end
end
def stranger_mention_reject?(text, **options)
text = PlainTextFormatter.new(text, false).to_s if options[:uri].present?
hit_word = ng_words_for_stranger_mention.detect { |word| include?(text, word) ? word : nil }
record!(:ng_words_for_stranger_mention, text, hit_word, options) if hit_word.present?
hit_word.present?
opts = options.merge({ stranger: true })
reject?(text, **opts)
end
def reject_with_custom_words?(text, custom_ng_words)
custom_ng_words.any? { |word| include?(text, word) }
def reject_with_custom_word?(text, word)
include_with_regexp?(text, word)
end
def hashtag_reject?(hashtag_count, **options)
@ -53,19 +58,15 @@ class Admin::NgWord
private
def include?(text, word)
if word.start_with?('?') && word.size >= 2
text =~ /#{word[1..]}/i
if word.regexp
text =~ /#{word.keyword}/
else
text.include?(word)
text.include?(word.keyword)
end
end
def ng_words
Setting.ng_words || []
end
def ng_words_for_stranger_mention
Setting.ng_words_for_stranger_mention || []
def include_with_regexp?(text, word)
text =~ /#{word}/i
end
def post_hash_tags_max

View file

@ -44,8 +44,6 @@ class Form::AdminSettings
delete_content_cache_without_reaction
status_page_url
captcha_enabled
ng_words
ng_words_for_stranger_mention
stranger_mention_from_local_ng
hide_local_users_for_anonymous
post_hash_tags_max
@ -122,8 +120,6 @@ class Form::AdminSettings
}.freeze
STRING_ARRAY_KEYS = %i(
ng_words
ng_words_for_stranger_mention
emoji_reaction_disallow_domains
permit_new_account_domains
).freeze

87
app/models/ng_word.rb Normal file
View file

@ -0,0 +1,87 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: ng_words
#
# id :bigint(8) not null, primary key
# keyword :string not null
# regexp :boolean default(FALSE), not null
# stranger :boolean default(TRUE), not null
# created_at :datetime not null
# updated_at :datetime not null
#
class NgWord < ApplicationRecord
attr_accessor :keywords, :regexps, :strangers
validate :check_regexp
class << self
def caches
Rails.cache.fetch('ng_words') { NgWord.where.not(id: 0).order(:keyword).to_a }
end
def save_from_hashes(rows)
unmatched = caches
matched = []
NgWord.transaction do
rows.filter { |item| item[:keyword].present? }.each do |item|
exists = unmatched.find { |i| i.keyword == item[:keyword] }
if exists.present?
unmatched.delete(exists)
matched << exists
next if exists.regexp == item[:regexp] && exists.stranger == item[:stranger]
exists.update!(regexp: item[:regexp], stranger: item[:stranger])
elsif matched.none? { |i| i.keyword == item[:keyword] }
NgWord.create!(
keyword: item[:keyword],
regexp: item[:regexp],
stranger: item[:stranger]
)
end
end
NgWord.destroy(unmatched.map(&:id))
end
true
end
def save_from_raws(rows)
regexps = rows['regexps'] || []
strangers = rows['strangers'] || []
hashes = (rows['keywords'] || []).zip(rows['temporary_ids'] || []).map do |item|
temp_id = item[1]
{
keyword: item[0],
regexp: regexps.include?(temp_id),
stranger: strangers.include?(temp_id),
}
end
save_from_hashes(hashes)
end
end
private
def invalidate_cache!
Rails.cache.delete('ng_words')
end
def check_regexp
return if keyword.blank? || !regexp
begin
Admin::NgWord.reject_with_custom_word?('Sample text', keyword)
rescue
raise Mastodon::ValidationError, I18n.t('admin.ng_words.test_error')
end
end
end

View file

@ -16,6 +16,8 @@
class SensitiveWord < ApplicationRecord
attr_accessor :keywords, :regexps, :remotes, :spoilers
validate :check_regexp
class << self
def caches
Rails.cache.fetch('sensitive_words') { SensitiveWord.where.not(id: 0).order(:keyword).to_a }
@ -50,8 +52,6 @@ class SensitiveWord < ApplicationRecord
end
true
# rescue
# false
end
def save_from_raws(rows)
@ -78,4 +78,14 @@ class SensitiveWord < ApplicationRecord
def invalidate_cache!
Rails.cache.delete('sensitive_words')
end
def check_regexp
return if keyword.blank? || !regexp
begin
Admin::NgWord.reject_with_custom_word?('Sample text', keyword)
rescue
raise Mastodon::ValidationError, I18n.t('admin.ng_words.test_error')
end
end
end