Skip to content

Commit

Permalink
Change: #647 NGワードの入力フォーム (#663)
Browse files Browse the repository at this point in the history
* Change: #647 NGワードの入力フォーム

* Wip: 画面改造

* テストコード、画面

* Fix: 複数の問題
  • Loading branch information
kmycode authored Mar 25, 2024
1 parent 0d2b415 commit 95ab1f7
Show file tree
Hide file tree
Showing 33 changed files with 526 additions and 172 deletions.
1 change: 1 addition & 0 deletions .haml-lint_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ linters:
exclude:
- 'app/views/application/_sidebar.html.haml'
- 'app/views/admin/ng_rules/_ng_rule_fields.html.haml'
- 'app/views/admin/ng_words/keywords/_ng_word.html.haml'
- 'app/views/admin/sensitive_words/_sensitive_word.html.haml'
30 changes: 30 additions & 0 deletions app/controllers/admin/ng_words/keywords_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true

module Admin
class NgWords::KeywordsController < NgWordsController
def show
super
@ng_words = ::NgWord.caches.presence || [::NgWord.new]
end

protected

def validate
begin
::NgWord.save_from_raws(settings_params_test)
return true
rescue
flash[:alert] = I18n.t('admin.ng_words.test_error')
redirect_to after_update_redirect_path
end

false
end

private

def after_update_redirect_path
admin_ng_words_keywords_path
end
end
end
11 changes: 11 additions & 0 deletions app/controllers/admin/ng_words/settings_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

module Admin
class NgWords::SettingsController < NgWordsController
protected

def after_update_redirect_path
admin_ng_words_settings_path
end
end
end
11 changes: 11 additions & 0 deletions app/controllers/admin/ng_words/white_list_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

module Admin
class NgWords::WhiteListController < NgWordsController
protected

def after_update_redirect_path
admin_ng_words_white_list_path
end
end
end
21 changes: 10 additions & 11 deletions app/controllers/admin/ng_words_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,7 @@ def show
def create
authorize :ng_words, :create?

begin
test_words
rescue
flash[:alert] = I18n.t('admin.ng_words.test_error')
redirect_to after_update_redirect_path
return
end
return unless validate

@admin_settings = Form::AdminSettings.new(settings_params)

Expand All @@ -29,19 +23,24 @@ def create
end
end

private
protected

def test_words
ng_words = "#{settings_params['ng_words']}\n#{settings_params['ng_words_for_stranger_mention']}".split(/\r\n|\r|\n/).filter(&:present?)
Admin::NgWord.reject_with_custom_words?('Sample text', ng_words)
def validate
true
end

def after_update_redirect_path
admin_ng_words_path
end

private

def settings_params
params.require(:form_admin_settings).permit(*Form::AdminSettings::KEYS)
end

def settings_params_test
params.require(:form_admin_settings)[:ng_words_test]
end
end
end
9 changes: 2 additions & 7 deletions app/controllers/admin/sensitive_words_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def create
authorize :sensitive_words, :create?

begin
test_words
::SensitiveWord.save_from_raws(settings_params_test)
rescue
flash[:alert] = I18n.t('admin.ng_words.test_error')
redirect_to after_update_redirect_path
Expand All @@ -22,7 +22,7 @@ def create

@admin_settings = Form::AdminSettings.new(settings_params)

if @admin_settings.save && ::SensitiveWord.save_from_raws(settings_params_test)
if @admin_settings.save
flash[:notice] = I18n.t('generic.changes_saved_msg')
redirect_to after_update_redirect_path
else
Expand All @@ -32,11 +32,6 @@ def create

private

def test_words
sensitive_words = settings_params_test['keywords'].compact.uniq
Admin::NgWord.reject_with_custom_words?('Sample text', sensitive_words)
end

def after_update_redirect_path
admin_sensitive_words_path
end
Expand Down
23 changes: 20 additions & 3 deletions app/javascript/packs/admin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,8 @@ Rails.delegate(
document,
'#sensitive-words-table .add-row-button',
'click',
() => {
(ev) => {
ev.preventDefault();
addTableRow('sensitive-words-table');
},
);
Expand All @@ -329,8 +330,24 @@ Rails.delegate(
document,
'#sensitive-words-table .delete-row-button',
'click',
({ target }) => {
removeTableRow(target, 'sensitive-words-table');
(ev) => {
ev.preventDefault();
removeTableRow(ev.target, 'sensitive-words-table');
},
);

Rails.delegate(document, '#ng-words-table .add-row-button', 'click', (ev) => {
ev.preventDefault();
addTableRow('ng-words-table');
});

Rails.delegate(
document,
'#ng-words-table .delete-row-button',
'click',
(ev) => {
ev.preventDefault();
removeTableRow(ev.target, 'ng-words-table');
},
);

Expand Down
3 changes: 1 addition & 2 deletions app/lib/activitypub/activity/create.rb
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,10 @@ def process_sensitive_words
def valid_status?
valid = true
valid = false if valid && !valid_status_for_ng_rule?
valid = !Admin::NgWord.reject?("#{@params[:spoiler_text]}\n#{@params[:text]}", uri: @params[:uri], target_type: :status, public: @status_parser.distributable_visibility?) if valid
valid = !Admin::NgWord.reject?("#{@params[:spoiler_text]}\n#{@params[:text]}", uri: @params[:uri], target_type: :status, public: @status_parser.distributable_visibility?, stranger: mention_to_local_stranger? || reference_to_local_stranger?) if valid
valid = !Admin::NgWord.hashtag_reject?(@tags.size, uri: @params[:uri], target_type: :status, public: @status_parser.distributable_visibility?, text: "#{@params[:spoiler_text]}\n#{@params[:text]}") if valid
valid = !Admin::NgWord.mention_reject?(@raw_mention_uris.size, uri: @params[:uri], target_type: :status, public: @status_parser.distributable_visibility?, text: "#{@params[:spoiler_text]}\n#{@params[:text]}") if valid
valid = !Admin::NgWord.stranger_mention_reject_with_count?(@raw_mention_uris.size, uri: @params[:uri], target_type: :status, public: @status_parser.distributable_visibility?, text: "#{@params[:spoiler_text]}\n#{@params[:text]}") if valid && (mention_to_local_stranger? || reference_to_local_stranger?)
valid = !Admin::NgWord.stranger_mention_reject?("#{@params[:spoiler_text]}\n#{@params[:text]}", uri: @params[:uri], target_type: :status, public: @status_parser.distributable_visibility?) if valid && (mention_to_local_stranger? || reference_to_local_stranger?)
valid = false if valid && Setting.block_unfollow_account_mention && (mention_to_local_stranger? || reference_to_local_stranger?) && !local_following_sender?

valid
Expand Down
37 changes: 19 additions & 18 deletions app/models/admin/ng_word.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -53,19 +58,15 @@ def stranger_mention_reject_with_extractor?(text)
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
Expand Down
4 changes: 0 additions & 4 deletions app/models/form/admin_settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
87 changes: 87 additions & 0 deletions app/models/ng_word.rb
Original file line number Diff line number Diff line change
@@ -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
14 changes: 12 additions & 2 deletions app/models/sensitive_word.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down Expand Up @@ -50,8 +52,6 @@ def save_from_hashes(rows)
end

true
# rescue
# false
end

def save_from_raws(rows)
Expand All @@ -78,4 +78,14 @@ def save_from_raws(rows)
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
3 changes: 1 addition & 2 deletions app/services/activitypub/process_status_update_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,9 @@ def update_poll!(allow_significant_changes: true)
end

def valid_status?
valid = !Admin::NgWord.reject?("#{@status_parser.spoiler_text}\n#{@status_parser.text}", uri: @status.uri, target_type: :status)
valid = !Admin::NgWord.reject?("#{@status_parser.spoiler_text}\n#{@status_parser.text}", uri: @status.uri, target_type: :status, stranger: mention_to_local_stranger? || reference_to_local_stranger?)
valid = !Admin::NgWord.hashtag_reject?(@raw_tags.size) if valid
valid = false if valid && Admin::NgWord.mention_reject?(@raw_mentions.size, uri: @status.uri, target_type: :status, text: "#{@status_parser.spoiler_text}\n#{@status_parser.text}")
valid = false if valid && (mention_to_local_stranger? || reference_to_local_stranger?) && Admin::NgWord.stranger_mention_reject?("#{@status_parser.spoiler_text}\n#{@status_parser.text}", uri: @status.uri, target_type: :status)
valid = false if valid && (mention_to_local_stranger? || reference_to_local_stranger?) && Admin::NgWord.stranger_mention_reject_with_count?(@raw_mentions.size, uri: @status.uri, target_type: :status, text: "#{@status_parser.spoiler_text}\n#{@status_parser.text}")
valid = false if valid && (mention_to_local_stranger? || reference_to_local_stranger?) && reject_reply_exclude_followers?

Expand Down
Loading

0 comments on commit 95ab1f7

Please sign in to comment.