Skip to content

Commit

Permalink
Add: #600 NGルール (#602)
Browse files Browse the repository at this point in the history
* Wip

* Wip

* Wip: History

* Wip: テストコード作成

* Fix test

* Wip

* Wip

* Wip

* Fix test

* Wip

* Wip

* Wip

* Wip

* なんとか完成、これから動作確認

* spell miss

* Change ng rule timings

* Fix test

* Wip

* Fix test

* Wip

* Fix form

* 表示まわりの改善
  • Loading branch information
kmycode authored Feb 26, 2024
1 parent 0779c74 commit 7d96d58
Show file tree
Hide file tree
Showing 56 changed files with 2,061 additions and 41 deletions.
3 changes: 3 additions & 0 deletions .haml-lint_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ linters:
# Offense count: 1
LineLength:
exclude:
- 'app/views/admin/ng_rules/_ng_rule_fields.html.haml'
- 'app/views/admin/roles/_form.html.haml'

# Offense count: 9
Expand All @@ -20,9 +21,11 @@ linters:
ViewLength:
exclude:
- 'app/views/admin/instances/show.html.haml'
- 'app/views/admin/ng_rules/_ng_rule_fields.html.haml'
- 'app/views/settings/preferences/appearance/show.html.haml'
- 'app/views/settings/preferences/other/show.html.haml'

InstanceVariables:
exclude:
- 'app/views/application/_sidebar.html.haml'
- 'app/views/admin/ng_rules/_ng_rule_fields.html.haml'
24 changes: 24 additions & 0 deletions app/controllers/admin/ng_rule_histories_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

module Admin
class NgRuleHistoriesController < BaseController
before_action :set_ng_rule
before_action :set_histories

PER_PAGE = 20

def show
authorize :ng_words, :show?
end

private

def set_ng_rule
@ng_rule = ::NgRule.find(params[:id])
end

def set_histories
@histories = NgRuleHistory.where(ng_rule_id: params[:id]).order(id: :desc).page(params[:page]).per(PER_PAGE)
end
end
end
115 changes: 115 additions & 0 deletions app/controllers/admin/ng_rules_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# frozen_string_literal: true

module Admin
class NgRulesController < BaseController
before_action :set_ng_rule, only: [:edit, :update, :destroy, :duplicate]

def index
authorize :ng_words, :show?

@ng_rules = ::NgRule.order(id: :asc)
end

def new
authorize :ng_words, :show?

@ng_rule = ::NgRule.build
end

def edit
authorize :ng_words, :show?
end

def create
authorize :ng_words, :create?

begin
test_words!
rescue
flash[:alert] = I18n.t('admin.ng_rules.test_error')
redirect_to new_admin_ng_rule_path
return
end

@ng_rule = ::NgRule.build(resource_params)

if @ng_rule.save
redirect_to admin_ng_rules_path
else
render :new
end
end

def update
authorize :ng_words, :create?

begin
test_words!
rescue
flash[:alert] = I18n.t('admin.ng_rules.test_error')
redirect_to edit_admin_ng_rule_path(id: @ng_rule.id)
return
end

if @ng_rule.update(resource_params)
redirect_to admin_ng_rules_path
else
render :edit
end
end

def duplicate
authorize :ng_words, :create?

@ng_rule = @ng_rule.copy!

flash[:alert] = I18n.t('admin.ng_rules.copy_error') unless @ng_rule.save

redirect_to admin_ng_rules_path
end

def destroy
authorize :ng_words, :create?

@ng_rule.destroy
redirect_to admin_ng_rules_path
end

private

def set_ng_rule
@ng_rule = ::NgRule.find(params[:id])
end

def resource_params
params.require(:ng_rule).permit(:title, :expires_in, :available, :account_domain, :account_username, :account_display_name,
:account_note, :account_field_name, :account_field_value, :account_avatar_state,
:account_header_state, :account_include_local, :status_spoiler_text, :status_text, :status_tag,
:status_sensitive_state, :status_cw_state, :status_media_state, :status_poll_state,
:status_mention_state, :status_reference_state,
:status_quote_state, :status_reply_state, :status_media_threshold, :status_poll_threshold,
:status_mention_threshold, :status_allow_follower_mention,
:reaction_allow_follower, :emoji_reaction_name, :emoji_reaction_origin_domain,
:status_reference_threshold, :account_allow_followed_by_local, :record_history_also_local,
status_visibility: [], status_searchability: [], reaction_type: [])
end

def test_words!
arr = [
resource_params[:account_domain],
resource_params[:account_username],
resource_params[:account_display_name],
resource_params[:account_note],
resource_params[:account_field_name],
resource_params[:account_field_value],
resource_params[:status_spoiler_text],
resource_params[:status_text],
resource_params[:status_tag],
resource_params[:emoji_reaction_name],
resource_params[:emoji_reaction_origin_domain],
].compact_blank.join("\n")

Admin::NgRule.extract_test!(arr) if arr.present?
end
end
end
28 changes: 28 additions & 0 deletions app/helpers/ng_rule_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

module NgRuleHelper
def check_invalid_status_for_ng_rule!(account, **options)
(check_for_ng_rule!(account, **options) { |rule| !rule.check_status_or_record! }).none?
end

def check_invalid_reaction_for_ng_rule!(account, **options)
(check_for_ng_rule!(account, **options) { |rule| !rule.check_reaction_or_record! }).none?
end

private

def check_for_ng_rule!(account, **options, &block)
NgRule.cached_rules
.map { |raw_rule| Admin::NgRule.new(raw_rule, account, **options) }
.filter(&block)
end

def do_account_action_for_rule!(account, action)
case action
when :silence
account.silence!
when :suspend
account.suspend!
end
end
end
3 changes: 3 additions & 0 deletions app/lib/activitypub/activity/announce.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# frozen_string_literal: true

class ActivityPub::Activity::Announce < ActivityPub::Activity
include NgRuleHelper

def perform
return reject_payload! if delete_arrived_first?(@json['id']) || !related_to_local_activity?

Expand All @@ -9,6 +11,7 @@ def perform

return reject_payload! if original_status.nil? || !announceable?(original_status)
return if requested_through_relay?
return unless check_invalid_reaction_for_ng_rule! @account, uri: @json['id'], reaction_type: 'reblog', recipient: original_status.account, target_status: original_status

@status = Status.find_by(account: @account, reblog: original_status)

Expand Down
29 changes: 27 additions & 2 deletions app/lib/activitypub/activity/create.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

class ActivityPub::Activity::Create < ActivityPub::Activity
include FormattingHelper
include NgRuleHelper

def perform
@account.schedule_refresh_if_stale!
Expand Down Expand Up @@ -144,7 +145,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?)
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.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?)
Expand All @@ -154,6 +157,26 @@ def valid_status?
valid
end

def valid_status_for_ng_rule?
check_invalid_status_for_ng_rule! @account,
reaction_type: 'create',
uri: @params[:uri],
url: @params[:url],
spoiler_text: @params[:spoiler_text],
text: @params[:text],
tag_names: @tags.map(&:name),
visibility: @params[:visibility].to_s,
searchability: @params[:searchability]&.to_s,
sensitive: @params[:sensitive],
media_count: @params[:media_attachment_ids]&.size,
poll_count: @params[:poll]&.options&.size || 0,
quote: quote,
reply: in_reply_to_uri.present?,
mention_count: mentioned_accounts.count,
reference_count: reference_uris.size,
mention_to_following: !(mention_to_local_stranger? || reference_to_local_stranger?)
end

def accounts_in_audience
return @accounts_in_audience if @accounts_in_audience

Expand Down Expand Up @@ -353,6 +376,8 @@ def process_poll
def poll_vote?
return false if replied_to_status.nil? || replied_to_status.preloadable_poll.nil? || !replied_to_status.local? || !replied_to_status.preloadable_poll.options.include?(@object['name'])

return true unless check_invalid_reaction_for_ng_rule! @account, uri: @json['id'], reaction_type: 'vote', recipient: replied_to_status.account, target_status: replied_to_status

poll_vote! unless replied_to_status.preloadable_poll.expired?

true
Expand Down Expand Up @@ -552,7 +577,7 @@ def reference_uris
return @reference_uris if defined?(@reference_uris)

@reference_uris = @object['references'].nil? ? [] : (ActivityPub::FetchReferencesService.new.call(@account, @object['references']) || []).uniq
@reference_uris += ProcessReferencesService.extract_uris(@object['content'] || '')
@reference_uris += ProcessReferencesService.extract_uris(@object['content'] || '', remote: true)
end

def local_referred_accounts
Expand Down
2 changes: 2 additions & 0 deletions app/lib/activitypub/activity/follow.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
class ActivityPub::Activity::Follow < ActivityPub::Activity
include Payloadable
include FollowHelper
include NgRuleHelper

def perform
return request_follow_for_friend if friend_follow?

target_account = account_from_uri(object_uri)

return if target_account.nil? || !target_account.local? || delete_arrived_first?(@json['id'])
return unless check_invalid_reaction_for_ng_rule! @account, uri: @json['id'], reaction_type: 'follow', recipient: target_account

# Update id of already-existing follow requests
existing_follow_request = ::FollowRequest.find_by(account: @account, target_account: target_account) || PendingFollowRequest.find_by(account: @account, target_account: target_account)
Expand Down
4 changes: 4 additions & 0 deletions app/lib/activitypub/activity/like.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ class ActivityPub::Activity::Like < ActivityPub::Activity
include Redisable
include Lockable
include JsonLdHelper
include NgRuleHelper

def perform
@original_status = status_from_uri(object_uri)
Expand All @@ -25,6 +26,7 @@ def reject_favourite?

def process_favourite
return if @account.favourited?(@original_status)
return unless check_invalid_reaction_for_ng_rule! @account, uri: @json['id'], reaction_type: 'favourite', recipient: @original_status.account, target_status: @original_status

favourite = @original_status.favourites.create!(account: @account, uri: @json['id'])

Expand All @@ -43,6 +45,8 @@ def process_emoji_reaction
return if emoji.nil?
end

return unless check_invalid_reaction_for_ng_rule! @account, uri: @json['id'], reaction_type: 'emoji_reaction', emoji_reaction_name: emoji&.shortcode || shortcode, emoji_reaction_origin_domain: emoji&.domain, recipient: @original_status.account, target_status: @original_status

reaction = nil

with_redis_lock("emoji_reaction:#{@original_status.id}") do
Expand Down
17 changes: 17 additions & 0 deletions app/lib/vacuum/ng_histories_vacuum.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

class Vacuum::NgHistoriesVacuum
include Redisable

HISTORY_LIFE_DURATION = 7.days.freeze

def perform
vacuum_histories!
end

private

def vacuum_histories!
NgRuleHistory.where('created_at < ?', HISTORY_LIFE_DURATION.ago).in_batches.destroy_all
end
end
Loading

0 comments on commit 7d96d58

Please sign in to comment.