Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add: #600 NGルール #602

Merged
merged 24 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading