* 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 * 表示まわりの改善
This commit is contained in:
parent
0779c748a6
commit
7d96d5828e
56 changed files with 2062 additions and 42 deletions
7
spec/fabricators/ng_rule_fabricator.rb
Normal file
7
spec/fabricators/ng_rule_fabricator.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Fabricator(:ng_rule) do
|
||||
status_visibility %w(public)
|
||||
status_searchability %w(direct unset)
|
||||
reaction_type %w(favourite)
|
||||
end
|
8
spec/fabricators/ng_rule_history_fabricator.rb
Normal file
8
spec/fabricators/ng_rule_history_fabricator.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Fabricator(:ng_rule_history) do
|
||||
ng_rule { Fabricate.build(:ng_rule) }
|
||||
account { Fabricate.build(:account) }
|
||||
reason 0
|
||||
reason_action 0
|
||||
end
|
|
@ -111,6 +111,38 @@ RSpec.describe ActivityPub::Activity::Announce do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when ng rule is existing' do
|
||||
context 'when ng rule is match' do
|
||||
before do
|
||||
Fabricate(:ng_rule, account_domain: 'example.com', reaction_type: ['reblog'])
|
||||
subject.perform
|
||||
end
|
||||
|
||||
let(:object_json) do
|
||||
ActivityPub::TagManager.instance.uri_for(status)
|
||||
end
|
||||
|
||||
it 'does not create a reblog by sender of status' do
|
||||
expect(sender.reblogged?(status)).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ng rule is not match' do
|
||||
before do
|
||||
Fabricate(:ng_rule, account_domain: 'foo.bar', reaction_type: ['reblog'])
|
||||
subject.perform
|
||||
end
|
||||
|
||||
let(:object_json) do
|
||||
ActivityPub::TagManager.instance.uri_for(status)
|
||||
end
|
||||
|
||||
it 'creates a reblog by sender of status' do
|
||||
expect(sender.reblogged?(status)).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the sender is relayed' do
|
||||
subject { described_class.new(json, sender, relayed_through_actor: relay_account) }
|
||||
|
||||
|
|
|
@ -1560,6 +1560,32 @@ RSpec.describe ActivityPub::Activity::Create do
|
|||
expect(vote.uri).to eq object_json[:id]
|
||||
expect(poll.reload.cached_tallies).to eq [1, 0]
|
||||
end
|
||||
|
||||
context 'when ng rule is existing' do
|
||||
let(:custom_before) { true }
|
||||
|
||||
context 'when ng rule is match' do
|
||||
before do
|
||||
Fabricate(:ng_rule, account_domain: 'example.com', reaction_type: ['vote'])
|
||||
subject.perform
|
||||
end
|
||||
|
||||
it 'does not create a reblog by sender of status' do
|
||||
expect(poll.votes.first).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ng rule is not match' do
|
||||
before do
|
||||
Fabricate(:ng_rule, account_domain: 'foo.bar', reaction_type: ['vote'])
|
||||
subject.perform
|
||||
end
|
||||
|
||||
it 'creates a reblog by sender of status' do
|
||||
expect(poll.votes.first).to_not be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a vote to an expired local poll' do
|
||||
|
@ -2024,6 +2050,43 @@ RSpec.describe ActivityPub::Activity::Create do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when ng rule is set' do
|
||||
let(:custom_before) { true }
|
||||
let(:content) { 'Lorem ipsum' }
|
||||
let(:object_json) do
|
||||
{
|
||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||
type: 'Note',
|
||||
content: content,
|
||||
to: 'https://www.w3.org/ns/activitystreams#Public',
|
||||
}
|
||||
end
|
||||
|
||||
context 'when rule hits' do
|
||||
before do
|
||||
Fabricate(:ng_rule, status_text: 'ipsum', status_allow_follower_mention: false)
|
||||
subject.perform
|
||||
end
|
||||
|
||||
it 'creates status' do
|
||||
status = sender.statuses.first
|
||||
expect(status).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when rule does not hit' do
|
||||
before do
|
||||
Fabricate(:ng_rule, status_text: 'amely', status_allow_follower_mention: false)
|
||||
subject.perform
|
||||
end
|
||||
|
||||
it 'creates status' do
|
||||
status = sender.statuses.first
|
||||
expect(status).to_not be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when hashtags limit is set' do
|
||||
let(:post_hash_tags_max) { 2 }
|
||||
let(:custom_before) { true }
|
||||
|
|
|
@ -244,6 +244,33 @@ RSpec.describe ActivityPub::Activity::Follow do
|
|||
expect(sender.requested?(recipient)).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ng rule is existing' do
|
||||
context 'when ng rule is match' do
|
||||
before do
|
||||
Fabricate(:ng_rule, account_domain: 'example.com', reaction_type: ['follow'])
|
||||
stub_request(:post, 'https://example.com/inbox').to_return(status: 200, body: '', headers: {})
|
||||
subject.perform
|
||||
end
|
||||
|
||||
it 'does not create a reblog by sender of status' do
|
||||
expect(sender.following?(recipient)).to be false
|
||||
expect(sender.requested?(recipient)).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ng rule is not match' do
|
||||
before do
|
||||
Fabricate(:ng_rule, account_domain: 'foo.bar', reaction_type: ['follow'])
|
||||
subject.perform
|
||||
end
|
||||
|
||||
it 'creates a reblog by sender of status' do
|
||||
expect(sender.following?(recipient)).to be true
|
||||
expect(sender.requested?(recipient)).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a follow relationship already exists' do
|
||||
|
|
|
@ -55,6 +55,32 @@ RSpec.describe ActivityPub::Activity::Like do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when ng rule is existing' do
|
||||
subject { described_class.new(json, sender) }
|
||||
|
||||
context 'when ng rule is match' do
|
||||
before do
|
||||
Fabricate(:ng_rule, account_domain: 'example.com', reaction_type: ['favourite'])
|
||||
subject.perform
|
||||
end
|
||||
|
||||
it 'does not create a reblog by sender of status' do
|
||||
expect(sender.favourited?(status)).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ng rule is not match' do
|
||||
before do
|
||||
Fabricate(:ng_rule, account_domain: 'foo.bar', reaction_type: ['favourite'])
|
||||
subject.perform
|
||||
end
|
||||
|
||||
it 'creates a reblog by sender of status' do
|
||||
expect(sender.favourited?(status)).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#perform when receive emoji reaction' do
|
||||
subject do
|
||||
described_class.new(json, sender).perform
|
||||
|
@ -592,6 +618,30 @@ RSpec.describe ActivityPub::Activity::Like do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ng rule is existing' do
|
||||
let(:content) { '😀' }
|
||||
|
||||
context 'when ng rule is match' do
|
||||
before do
|
||||
Fabricate(:ng_rule, account_domain: 'example.com', reaction_type: ['emoji_reaction'])
|
||||
end
|
||||
|
||||
it 'does not create a reblog by sender of status' do
|
||||
expect(subject.count).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ng rule is not match' do
|
||||
before do
|
||||
Fabricate(:ng_rule, account_domain: 'foo.bar', reaction_type: ['emoji_reaction'])
|
||||
end
|
||||
|
||||
it 'creates a reblog by sender of status' do
|
||||
expect(subject.count).to eq 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#perform when rejecting favourite domain block' do
|
||||
|
|
24
spec/lib/vacuum/ng_histories_vacuum_spec.rb
Normal file
24
spec/lib/vacuum/ng_histories_vacuum_spec.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Vacuum::NgHistoriesVacuum do
|
||||
subject { described_class.new }
|
||||
|
||||
describe '#perform' do
|
||||
let!(:rule_history_old) { Fabricate(:ng_rule_history, created_at: 30.days.ago) }
|
||||
let!(:rule_history_recent) { Fabricate(:ng_rule_history, created_at: 2.days.ago) }
|
||||
|
||||
before do
|
||||
subject.perform
|
||||
end
|
||||
|
||||
it 'deletes old history' do
|
||||
expect { rule_history_old.reload }.to raise_error ActiveRecord::RecordNotFound
|
||||
end
|
||||
|
||||
it 'does not delete recent history' do
|
||||
expect { rule_history_recent.reload }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
282
spec/models/admin/ng_rule_spec.rb
Normal file
282
spec/models/admin/ng_rule_spec.rb
Normal file
|
@ -0,0 +1,282 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Admin::NgRule do
|
||||
shared_examples 'matches rule' do |reason|
|
||||
it 'matches and history is added' do
|
||||
expect(subject).to be false
|
||||
|
||||
history = NgRuleHistory.order(id: :desc).find_by(ng_rule: ng_rule)
|
||||
expect(history).to_not be_nil
|
||||
expect(history.account_id).to eq account.id
|
||||
expect(history.reason).to eq reason
|
||||
expect(history.uri).to eq uri
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'does not match rule' do
|
||||
it 'does not match and history is not added' do
|
||||
expect(subject).to be true
|
||||
|
||||
history = NgRuleHistory.order(id: :desc).find_by(ng_rule: ng_rule)
|
||||
expect(history).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'check all states' do |reason, results|
|
||||
context 'when rule state is optional' do
|
||||
let(:state) { :optional }
|
||||
|
||||
it_behaves_like results[0] ? 'does not match rule' : 'matches rule', reason
|
||||
end
|
||||
|
||||
context 'when rule state is needed' do
|
||||
let(:state) { :needed }
|
||||
|
||||
it_behaves_like results[1] ? 'does not match rule' : 'matches rule', reason
|
||||
end
|
||||
|
||||
context 'when rule state is no_needed' do
|
||||
let(:state) { :no_needed }
|
||||
|
||||
it_behaves_like results[2] ? 'does not match rule' : 'matches rule', reason
|
||||
end
|
||||
end
|
||||
|
||||
let(:uri) { 'https://example.com/operation' }
|
||||
|
||||
describe '#check_account_or_record!' do
|
||||
subject { described_class.new(ng_rule, account).check_account_or_record! }
|
||||
|
||||
context 'when unmatch rule' do
|
||||
let(:ng_rule) { Fabricate(:ng_rule, account_note: 'assur', account_include_local: true) }
|
||||
let(:account) { Fabricate(:account, domain: 'example.com', uri: uri) }
|
||||
|
||||
it_behaves_like 'does not match rule'
|
||||
end
|
||||
|
||||
context 'with domain rule' do
|
||||
let(:account) { Fabricate(:account, domain: 'example.com', uri: uri) }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, account_domain: '?example\..*') }
|
||||
|
||||
it_behaves_like 'matches rule', 'account'
|
||||
end
|
||||
|
||||
context 'with note rule' do
|
||||
let(:uri) { '' }
|
||||
let(:account) { Fabricate(:account, note: 'ohagi is good') }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, account_note: 'ohagi', account_include_local: true) }
|
||||
|
||||
it_behaves_like 'matches rule', 'account'
|
||||
end
|
||||
|
||||
context 'with display name rule' do
|
||||
let(:uri) { '' }
|
||||
let(:account) { Fabricate(:account, display_name: '') }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, account_display_name: "?^$\r\n?[a-z0-9]{10}", account_include_local: true) }
|
||||
|
||||
it_behaves_like 'matches rule', 'account'
|
||||
end
|
||||
|
||||
context 'with field name rule' do
|
||||
let(:account) { Fabricate(:account, fields_attributes: { '0' => { name: 'Name', value: 'Value' } }, domain: 'example.com', uri: uri) }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, account_field_name: 'Name') }
|
||||
|
||||
it_behaves_like 'matches rule', 'account'
|
||||
end
|
||||
|
||||
context 'with field value rule' do
|
||||
let(:account) { Fabricate(:account, fields_attributes: { '0' => { name: 'Name', value: 'Value' } }, domain: 'example.com', uri: uri) }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, account_field_value: 'Value') }
|
||||
|
||||
it_behaves_like 'matches rule', 'account'
|
||||
end
|
||||
|
||||
context 'with avatar rule' do
|
||||
context 'when avatar is not set' do
|
||||
let(:account) { Fabricate(:account, domain: 'example.com', uri: uri) }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, account_avatar_state: state) }
|
||||
|
||||
it_behaves_like 'check all states', 'account', [false, true, false]
|
||||
end
|
||||
|
||||
context 'when avatar is set' do
|
||||
let(:account) { Fabricate(:account, avatar: fixture_file_upload('avatar.gif', 'image/gif'), domain: 'example.com', uri: uri) }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, account_avatar_state: state) }
|
||||
|
||||
it_behaves_like 'check all states', 'account', [false, false, true]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#check_status_or_record!' do
|
||||
subject do
|
||||
opts = { reaction_type: 'create' }.merge(options)
|
||||
described_class.new(ng_rule, account, **opts).check_status_or_record!
|
||||
end
|
||||
|
||||
context 'when status matches but account does not match' do
|
||||
let(:account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/actor') }
|
||||
let(:options) { { uri: uri, text: 'this is a spam' } }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, account_domain: 'ohagi.jp', status_text: 'spam') }
|
||||
|
||||
it_behaves_like 'does not match rule'
|
||||
end
|
||||
|
||||
context 'when account matches but status does not match' do
|
||||
let(:account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/actor') }
|
||||
let(:options) { { uri: uri, text: 'this is a spam' } }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, account_domain: 'example.com', status_text: 'span') }
|
||||
|
||||
it_behaves_like 'does not match rule'
|
||||
end
|
||||
|
||||
context 'with text rule' do
|
||||
let(:account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/actor') }
|
||||
let(:options) { { uri: uri, text: 'this is a spam' } }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, status_text: 'spam') }
|
||||
|
||||
it_behaves_like 'matches rule', 'status'
|
||||
|
||||
it 'records as public' do
|
||||
subject
|
||||
|
||||
history = NgRuleHistory.order(id: :desc).find_by(ng_rule: ng_rule)
|
||||
expect(history.hidden).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'with visibility rule' do
|
||||
let(:account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/actor') }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, status_visibility: ['public', 'public_unlisted']) }
|
||||
|
||||
context 'with public visibility' do
|
||||
let(:options) { { uri: uri, visibility: 'public' } }
|
||||
|
||||
it_behaves_like 'matches rule', 'status'
|
||||
end
|
||||
|
||||
context 'with unlisted visibility' do
|
||||
let(:options) { { uri: uri, visibility: 'unlisted' } }
|
||||
|
||||
it_behaves_like 'does not match rule', 'status'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with searchability rule' do
|
||||
let(:account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/actor') }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, status_searchability: ['public', 'public_unlisted']) }
|
||||
|
||||
context 'with public searchability' do
|
||||
let(:options) { { uri: uri, searchability: 'public' } }
|
||||
|
||||
it_behaves_like 'matches rule', 'status'
|
||||
end
|
||||
|
||||
context 'with private searchability' do
|
||||
let(:options) { { uri: uri, searchability: 'private' } }
|
||||
|
||||
it_behaves_like 'does not match rule', 'status'
|
||||
end
|
||||
|
||||
context 'with unset' do
|
||||
let(:options) { { uri: uri, searchability: nil } }
|
||||
|
||||
it_behaves_like 'does not match rule', 'status'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with reply rule' do
|
||||
let(:account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/actor') }
|
||||
let(:options) { { uri: uri, reply: false } }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, status_reply_state: :no_needed) }
|
||||
|
||||
it_behaves_like 'matches rule', 'status'
|
||||
end
|
||||
|
||||
context 'with media size rule' do
|
||||
let(:account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/actor') }
|
||||
let(:options) { { uri: uri, media_count: 5 } }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, status_media_threshold: 4) }
|
||||
|
||||
it_behaves_like 'matches rule', 'status'
|
||||
end
|
||||
|
||||
context 'with mention size rule' do
|
||||
let(:account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/actor') }
|
||||
let(:options) { { uri: uri, mention_count: 5 } }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, status_mention_threshold: 4, status_allow_follower_mention: false) }
|
||||
|
||||
it_behaves_like 'matches rule', 'status'
|
||||
|
||||
context 'when mention to stranger' do
|
||||
let(:options) { { uri: uri, mention_count: 5, mention_to_following: false } }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, status_mention_threshold: 4, status_allow_follower_mention: true) }
|
||||
|
||||
it_behaves_like 'matches rule', 'status'
|
||||
end
|
||||
|
||||
context 'when mention to follower' do
|
||||
let(:options) { { uri: uri, mention_count: 5, mention_to_following: true } }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, status_mention_threshold: 4, status_allow_follower_mention: true) }
|
||||
|
||||
it_behaves_like 'does not match rule', 'status'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with private privacy' do
|
||||
let(:account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/actor') }
|
||||
let(:options) { { uri: uri, text: 'this is a spam', visibility: 'private' } }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, status_text: 'spam', status_visibility: %w(private)) }
|
||||
|
||||
it 'records as hidden' do
|
||||
expect(subject).to be false
|
||||
|
||||
history = NgRuleHistory.order(id: :desc).find_by(ng_rule: ng_rule)
|
||||
expect(history).to_not be_nil
|
||||
expect(history.account_id).to eq account.id
|
||||
expect(history.reason).to eq 'status'
|
||||
expect(history.uri).to be_nil
|
||||
expect(history.hidden).to be true
|
||||
expect(history.text).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#check_reaction_or_record!' do
|
||||
subject do
|
||||
described_class.new(ng_rule, account, **options).check_reaction_or_record!
|
||||
end
|
||||
|
||||
context 'when account matches but reaction does not match' do
|
||||
let(:account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/actor') }
|
||||
let(:options) { { uri: uri, recipient: Fabricate(:account), reaction_type: 'favourite' } }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, account_domain: 'example.com', status_text: 'span', reaction_type: ['reblog']) }
|
||||
|
||||
it_behaves_like 'does not match rule'
|
||||
end
|
||||
|
||||
context 'with reaction type rule' do
|
||||
let(:account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/actor') }
|
||||
let(:options) { { uri: uri, recipient: Fabricate(:account), reaction_type: 'favourite' } }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, reaction_type: ['favourite', 'follow']) }
|
||||
|
||||
it_behaves_like 'matches rule', 'reaction'
|
||||
|
||||
context 'when reblog' do
|
||||
let(:options) { { uri: uri, recipient: Fabricate(:account), reaction_type: 'reblog' } }
|
||||
|
||||
it_behaves_like 'does not match rule'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with emoji reaction shortcode rule' do
|
||||
let(:account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/actor') }
|
||||
let(:options) { { uri: uri, recipient: Fabricate(:account), reaction_type: 'emoji_reaction', emoji_reaction_name: 'ohagi' } }
|
||||
let(:ng_rule) { Fabricate(:ng_rule, reaction_type: ['emoji_reaction'], emoji_reaction_name: 'ohagi') }
|
||||
|
||||
it_behaves_like 'matches rule', 'reaction'
|
||||
end
|
||||
end
|
||||
end
|
29
spec/models/ng_rule_spec.rb
Normal file
29
spec/models/ng_rule_spec.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe NgRule do
|
||||
describe '#copy!' do
|
||||
let(:original) { Fabricate(:ng_rule, account_domain: 'foo.bar', account_avatar_state: :needed, status_text: 'ohagi', status_mention_threshold: 5, status_allow_follower_mention: false) }
|
||||
let(:copied) { original.copy! }
|
||||
|
||||
it 'saves safely' do
|
||||
expect { copied.save! }.to_not raise_error
|
||||
expect(copied.reload.id).to_not eq original.id
|
||||
end
|
||||
|
||||
it 'saves specified rules' do
|
||||
expect(copied.account_domain).to eq 'foo.bar'
|
||||
expect(copied.account_avatar_state.to_sym).to eq :needed
|
||||
expect(copied.status_text).to eq 'ohagi'
|
||||
expect(copied.status_mention_threshold).to eq 5
|
||||
expect(copied.status_allow_follower_mention).to be false
|
||||
end
|
||||
|
||||
it 'saves default rules' do
|
||||
expect(copied.account_header_state.to_sym).to eq :optional
|
||||
expect(copied.status_spoiler_text).to eq ''
|
||||
expect(copied.status_reference_threshold).to eq(-1)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -681,5 +681,31 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ng rule is existing' do
|
||||
context 'when ng rule is match' do
|
||||
before do
|
||||
Fabricate(:ng_rule, account_domain: 'example.com', status_text: 'universe')
|
||||
subject.call(status, json, json)
|
||||
end
|
||||
|
||||
it 'does not update text' do
|
||||
expect(status.reload.text).to eq 'Hello world'
|
||||
expect(status.edits.reload.map(&:text)).to eq []
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ng rule is not match' do
|
||||
before do
|
||||
Fabricate(:ng_rule, account_domain: 'foo.bar', status_text: 'universe')
|
||||
subject.call(status, json, json)
|
||||
end
|
||||
|
||||
it 'updates text' do
|
||||
expect(status.reload.text).to eq 'Hello universe'
|
||||
expect(status.edits.reload.map(&:text)).to eq ['Hello world', 'Hello universe']
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -47,6 +47,8 @@ RSpec.describe DeleteAccountService, type: :service do
|
|||
|
||||
let!(:account_note) { Fabricate(:account_note, account: account) }
|
||||
|
||||
let!(:ng_rule_history) { Fabricate(:ng_rule_history, account: account) }
|
||||
|
||||
it 'deletes associated owned and target records and target notifications' do
|
||||
subject
|
||||
|
||||
|
@ -68,6 +70,7 @@ RSpec.describe DeleteAccountService, type: :service do
|
|||
expect { bookmark_category_status.status.reload }.to_not raise_error
|
||||
expect { antenna_account.account.reload }.to_not raise_error
|
||||
expect { circle_account.account.reload }.to_not raise_error
|
||||
expect { ng_rule_history.reload }.to_not raise_error
|
||||
expect { list.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
expect { list_account.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
expect { antenna_account.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
|
|
|
@ -113,6 +113,33 @@ RSpec.describe EmojiReactService, type: :service do
|
|||
end
|
||||
end
|
||||
|
||||
context 'with ng rule' do
|
||||
let(:name) { 'ohagi' }
|
||||
|
||||
context 'when rule hits' do
|
||||
before do
|
||||
Fabricate(:custom_emoji, shortcode: 'ohagi')
|
||||
Fabricate(:ng_rule, reaction_type: ['emoji_reaction'])
|
||||
end
|
||||
|
||||
it 'react with emoji' do
|
||||
expect { subject }.to raise_error Mastodon::ValidationError
|
||||
end
|
||||
end
|
||||
|
||||
context 'when rule does not hit' do
|
||||
before do
|
||||
Fabricate(:custom_emoji, shortcode: 'ohagi')
|
||||
Fabricate(:ng_rule, reaction_type: ['emoji_reaction'], emoji_reaction_name: 'aaa')
|
||||
end
|
||||
|
||||
it 'react with emoji' do
|
||||
expect { subject }.to_not raise_error
|
||||
expect(subject.count).to eq 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with custom emoji of remote' do
|
||||
let(:name) { 'ohagi@foo.bar' }
|
||||
let!(:custom_emoji) { Fabricate(:custom_emoji, shortcode: 'ohagi', domain: 'foo.bar', uri: 'https://foo.bar/emoji/ohagi') }
|
||||
|
|
|
@ -37,4 +37,31 @@ RSpec.describe FavouriteService, type: :service do
|
|||
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once
|
||||
end
|
||||
end
|
||||
|
||||
context 'with ng rule' do
|
||||
let(:status) { Fabricate(:status) }
|
||||
let(:sender) { Fabricate(:account) }
|
||||
|
||||
context 'when rule matches' do
|
||||
before do
|
||||
Fabricate(:ng_rule, reaction_type: ['favourite'])
|
||||
end
|
||||
|
||||
it 'does not favourite' do
|
||||
expect { subject.call(sender, status) }.to raise_error Mastodon::ValidationError
|
||||
expect(sender.favourited?(status)).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when rule does not match' do
|
||||
before do
|
||||
Fabricate(:ng_rule, account_display_name: 'else', reaction_type: ['favourite'])
|
||||
end
|
||||
|
||||
it 'favourites' do
|
||||
expect { subject.call(sender, status) }.to_not raise_error
|
||||
expect(sender.favourited?(status)).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -154,4 +154,30 @@ RSpec.describe FollowService, type: :service do
|
|||
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once
|
||||
end
|
||||
end
|
||||
|
||||
context 'with ng rule' do
|
||||
let(:bob) { Fabricate(:account) }
|
||||
|
||||
context 'when rule matches' do
|
||||
before do
|
||||
Fabricate(:ng_rule, reaction_type: ['follow'])
|
||||
end
|
||||
|
||||
it 'does not favourite' do
|
||||
expect { subject.call(sender, bob) }.to raise_error Mastodon::ValidationError
|
||||
expect(sender.following?(bob)).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when rule does not match' do
|
||||
before do
|
||||
Fabricate(:ng_rule, account_display_name: 'else', reaction_type: ['follow'])
|
||||
end
|
||||
|
||||
it 'favourites' do
|
||||
expect { subject.call(sender, bob) }.to_not raise_error
|
||||
expect(sender.following?(bob)).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -820,6 +820,27 @@ RSpec.describe PostStatusService, type: :service do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'ng rule is set' do
|
||||
it 'creates a new status when no rule matches' do
|
||||
Fabricate(:ng_rule, account_username: 'ohagi', status_allow_follower_mention: false)
|
||||
account = Fabricate(:account)
|
||||
text = 'test status update'
|
||||
|
||||
status = subject.call(account, text: text)
|
||||
|
||||
expect(status).to be_persisted
|
||||
expect(status.text).to eq text
|
||||
end
|
||||
|
||||
it 'does not create a new status when a rule matches' do
|
||||
Fabricate(:ng_rule, status_text: 'test', status_allow_follower_mention: false)
|
||||
account = Fabricate(:account)
|
||||
text = 'test status update'
|
||||
|
||||
expect { subject.call(account, text: text) }.to raise_error Mastodon::ValidationError
|
||||
end
|
||||
end
|
||||
|
||||
def create_status_with_options(**options)
|
||||
subject.call(Fabricate(:account), options.merge(text: 'test'))
|
||||
end
|
||||
|
|
|
@ -68,6 +68,35 @@ RSpec.describe ReblogService, type: :service do
|
|||
end
|
||||
end
|
||||
|
||||
context 'with ng rule' do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:status) { Fabricate(:status, account: alice, visibility: :public) }
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
context 'when rule matches' do
|
||||
before do
|
||||
Fabricate(:ng_rule, reaction_type: ['reblog'])
|
||||
end
|
||||
|
||||
it 'does not reblog' do
|
||||
expect { subject.call(account, status) }.to raise_error Mastodon::ValidationError
|
||||
expect(account.reblogged?(status)).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when rule does not match' do
|
||||
before do
|
||||
Fabricate(:ng_rule, account_display_name: 'else', reaction_type: ['reblog'])
|
||||
end
|
||||
|
||||
it 'reblogs' do
|
||||
expect { subject.call(account, status) }.to_not raise_error
|
||||
expect(account.reblogged?(status)).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the reblogged status is discarded in the meantime' do
|
||||
let(:status) { Fabricate(:status, account: alice, visibility: :public, text: 'discard-status-text') }
|
||||
|
||||
|
|
|
@ -401,4 +401,32 @@ RSpec.describe UpdateStatusService, type: :service do
|
|||
expect(status.text).to_not eq text
|
||||
end
|
||||
end
|
||||
|
||||
describe 'ng rule is set' do
|
||||
let(:status) { Fabricate(:status, text: 'Foo') }
|
||||
|
||||
context 'when rule hits' do
|
||||
before do
|
||||
Fabricate(:ng_rule, status_text: 'Bar', status_allow_follower_mention: false)
|
||||
end
|
||||
|
||||
it 'does not update text' do
|
||||
expect { subject.call(status, status.account_id, text: 'Bar') }.to raise_error Mastodon::ValidationError
|
||||
expect(status.reload.text).to_not eq 'Bar'
|
||||
expect(status.edits.pluck(:text)).to eq %w()
|
||||
end
|
||||
end
|
||||
|
||||
context 'when rule does not hit' do
|
||||
before do
|
||||
Fabricate(:ng_rule, status_text: 'aar', status_allow_follower_mention: false)
|
||||
end
|
||||
|
||||
it 'does not update text' do
|
||||
expect { subject.call(status, status.account_id, text: 'Bar') }.to_not raise_error
|
||||
expect(status.reload.text).to eq 'Bar'
|
||||
expect(status.edits.pluck(:text)).to eq %w(Foo Bar)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue