Skip to content

Commit

Permalink
Add: メンション数上限 (#565)
Browse files Browse the repository at this point in the history
* Add: メンション数上限

* Fix test
  • Loading branch information
kmycode authored Feb 17, 2024
1 parent 5424567 commit 7411941
Show file tree
Hide file tree
Showing 11 changed files with 94 additions and 5 deletions.
5 changes: 3 additions & 2 deletions app/lib/activitypub/activity/create.rb
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,9 @@ def process_status_params
end

def valid_status?
valid = !Admin::NgWord.reject?("#{@params[:spoiler_text]}\n#{@params[:text]}", uri: @params[:uri], target_type: :status, public: @status_parser.distributable_visibility?) && !Admin::NgWord.hashtag_reject?(@tags.size)

valid = !Admin::NgWord.reject?("#{@params[:spoiler_text]}\n#{@params[:text]}", uri: @params[:uri], target_type: :status, public: @status_parser.distributable_visibility?)
valid = !Admin::NgWord.hashtag_reject?(@tags.size) if valid
valid = !Admin::NgWord.mention_reject?(@mentions.count { |m| !m.silent }) if valid
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
Expand Down
13 changes: 13 additions & 0 deletions app/models/admin/ng_word.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ def hashtag_reject_with_extractor?(text)
hashtag_reject?(Extractor.extract_hashtags(text)&.size || 0)
end

def mention_reject?(mention_count)
post_mentions_max.positive? && post_mentions_max < mention_count
end

def mention_reject_with_extractor?(text)
mention_reject?(text.gsub(Account::MENTION_RE)&.count || 0)
end

private

def include?(text, word)
Expand All @@ -49,6 +57,11 @@ def post_hash_tags_max
value.is_a?(Integer) && value.positive? ? value : 0
end

def post_mentions_max
value = Setting.post_mentions_max
value.is_a?(Integer) && value.positive? ? value : 0
end

def record!(type, text, keyword, options)
return unless options[:uri] && options[:target_type]
return if options.key?(:public) && !options.delete(:public)
Expand Down
2 changes: 2 additions & 0 deletions app/models/form/admin_settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class Form::AdminSettings
stranger_mention_from_local_ng
hide_local_users_for_anonymous
post_hash_tags_max
post_mentions_max
sensitive_words
sensitive_words_for_full
authorized_fetch
Expand All @@ -69,6 +70,7 @@ class Form::AdminSettings
content_cache_retention_period
backups_retention_period
post_hash_tags_max
post_mentions_max
registrations_limit
registrations_limit_per_day
registrations_start_hour
Expand Down
2 changes: 1 addition & 1 deletion app/services/activitypub/process_status_update_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def update_poll!(allow_significant_changes: true)
end

def valid_status?
!Admin::NgWord.reject?("#{@status_parser.spoiler_text}\n#{@status_parser.text}", uri: @status.uri, target_type: :status) && !Admin::NgWord.hashtag_reject?(@raw_tags.size)
!Admin::NgWord.reject?("#{@status_parser.spoiler_text}\n#{@status_parser.text}", uri: @status.uri, target_type: :status) && !Admin::NgWord.hashtag_reject?(@raw_tags.size) && !Admin::NgWord.mention_reject?(@raw_mentions.size)
end

def validate_status_mentions!
Expand Down
3 changes: 2 additions & 1 deletion app/services/post_status_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,8 @@ def postprocess_status!

def validate_status!
raise Mastodon::ValidationError, I18n.t('statuses.contains_ng_words') if Admin::NgWord.reject?("#{@options[:spoiler_text]}\n#{@options[:text]}")
raise Mastodon::ValidationError, I18n.t('statuses.too_many_hashtags') if Admin::NgWord.hashtag_reject_with_extractor?(@options[:text])
raise Mastodon::ValidationError, I18n.t('statuses.too_many_hashtags') if Admin::NgWord.hashtag_reject_with_extractor?(@text)
raise Mastodon::ValidationError, I18n.t('statuses.too_many_mentions') if Admin::NgWord.mention_reject_with_extractor?(@text)
end

def validate_status_mentions!
Expand Down
3 changes: 2 additions & 1 deletion app/services/update_status_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ def update_media_attachments!

def validate_status!
raise Mastodon::ValidationError, I18n.t('statuses.contains_ng_words') if Admin::NgWord.reject?("#{@options[:spoiler_text]}\n#{@options[:text]}")
raise Mastodon::ValidationError, I18n.t('statuses.too_many_hashtags') if Admin::NgWord.hashtag_reject_with_extractor?(@options[:text])
raise Mastodon::ValidationError, I18n.t('statuses.too_many_hashtags') if Admin::NgWord.hashtag_reject_with_extractor?(@options[:text] || '')
raise Mastodon::ValidationError, I18n.t('statuses.too_many_mentions') if Admin::NgWord.mention_reject_with_extractor?(@options[:text] || '')
end

def validate_status_mentions!
Expand Down
3 changes: 3 additions & 0 deletions app/views/admin/ng_words/show.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
.fields-group
= f.input :post_hash_tags_max, wrapper: :with_label, as: :integer, label: t('admin.ng_words.post_hash_tags_max')

.fields-group
= f.input :post_mentions_max, wrapper: :with_label, as: :integer, label: t('admin.ng_words.post_mentions_max')

.fields-group
= f.input :hide_local_users_for_anonymous, wrapper: :with_label, as: :boolean, label: t('admin.ng_words.hide_local_users_for_anonymous')

Expand Down
2 changes: 2 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,7 @@ en:
keywords_for_stranger_mention_hint: This words are checked posts from other servers only.
keywords_hint: The first character of the line is "?". to use regular expressions
post_hash_tags_max: Hash tags max for posts
post_mentions_max: Mentions max for posts
stranger_mention_from_local_ng: フォローしていないアカウントへのメンションのNGワードを、ローカルユーザーによる投稿にも適用する
stranger_mention_from_local_ng_hint: サーバーの登録が承認制でない場合、あなたのサーバーにもスパムが入り込む可能性があります
test_error: Testing is returned any errors
Expand Down Expand Up @@ -1941,6 +1942,7 @@ en:
show_thread: Show thread
title: '%{name}: "%{quote}"'
too_many_hashtags: Too many hashtags
too_many_mentions: Too many mentions
visibilities:
direct: Direct
login: Login only
Expand Down
2 changes: 2 additions & 0 deletions config/locales/ja.yml
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,7 @@ ja:
keywords_for_stranger_mention_hint: フォローしていないアカウントへのメンション、参照、引用にのみ適用されます
keywords_hint: 行を「?」で始めると、正規表現が使えます
post_hash_tags_max: 投稿に設定可能なハッシュタグの最大数
post_mentions_max: 投稿に設定可能なメンションの最大数
stranger_mention_from_local_ng: フォローしていないアカウントへのメンションのNGワードを、ローカルユーザーによる投稿にも適用する
stranger_mention_from_local_ng_hint: サーバーの登録が承認制でない場合、あなたのサーバーにもスパムが入り込む可能性があります
test_error: NGワードのテストに失敗しました。正規表現のミスが含まれているかもしれません
Expand Down Expand Up @@ -1914,6 +1915,7 @@ ja:
show_thread: スレッドを表示
title: '%{name}: "%{quote}"'
too_many_hashtags: ハッシュタグが多すぎます
too_many_mentions: メンションが多すぎます
visibilities:
direct: ダイレクト
login: ログインユーザーのみ
Expand Down
41 changes: 41 additions & 0 deletions spec/lib/activitypub/activity/create_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2066,6 +2066,47 @@ def activity_for_object(json)
end
end
end

context 'when mentions limit is set' do
let(:post_mentions_max) { 2 }
let(:custom_before) { true }
let(:object_json) do
{
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
type: 'Note',
content: 'Lorem ipsum',
tag: [
{
type: 'Mention',
href: ActivityPub::TagManager.instance.uri_for(Fabricate(:account)),
},
{
type: 'Mention',
href: ActivityPub::TagManager.instance.uri_for(Fabricate(:account)),
},
],
}
end

before do
Form::AdminSettings.new(post_mentions_max: post_mentions_max).save
subject.perform
end

context 'when limit is enough' do
it 'creates status' do
expect(sender.statuses.first).to_not be_nil
end
end

context 'when limit is over' do
let(:post_mentions_max) { 1 }

it 'creates status' do
expect(sender.statuses.first).to be_nil
end
end
end
end

context 'when object URI uses bearcaps' do
Expand Down
23 changes: 23 additions & 0 deletions spec/services/post_status_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,29 @@

expect { subject.call(account, text: text) }.to raise_error Mastodon::ValidationError
end

it 'using mentions under limit' do
Fabricate(:account, username: 'a')
Fabricate(:account, username: 'b')
account = Fabricate(:account)
text = '@a @b'
Form::AdminSettings.new(post_mentions_max: 2).save

status = subject.call(account, text: text)

expect(status).to be_persisted
expect(status.text).to eq text
end

it 'using mentions over limit' do
Fabricate(:account, username: 'a')
Fabricate(:account, username: 'b')
account = Fabricate(:account)
text = '@a @b'
Form::AdminSettings.new(post_mentions_max: 1).save

expect { subject.call(account, text: text) }.to raise_error Mastodon::ValidationError
end
end

def create_status_with_options(**options)
Expand Down

0 comments on commit 7411941

Please sign in to comment.