Merge commit '2ce0b666a139726dc406e6c1887728553b947e59' into glitch-soc/merge-upstream

Conflicts:
- `config/webpack/generateLocalePacks.js`:
  A dependency update changed how functions are imported.
  Also, some linting fixes not applicable to glitch-soc.
This commit is contained in:
Claire
2023-05-25 20:43:25 +02:00
128 changed files with 1393 additions and 560 deletions

View File

@@ -14,9 +14,7 @@ RSpec.describe ActivityPub::FollowersSynchronizationsController do
follower_2.follow!(account)
follower_3.follow!(account)
follower_4.follow!(account)
end
before do
allow(controller).to receive(:signed_request_actor).and_return(remote_account)
end

View File

@@ -27,9 +27,7 @@ RSpec.describe ActivityPub::OutboxesController do
Fabricate(:status, account: account, visibility: :private)
Fabricate(:status, account: account, visibility: :direct)
Fabricate(:status, account: account, visibility: :limited)
end
before do
allow(controller).to receive(:signed_request_actor).and_return(remote_account)
end

View File

@@ -5,16 +5,16 @@ require 'rails_helper'
RSpec.describe Admin::Disputes::AppealsController do
render_views
before { sign_in current_user, scope: :user }
before do
sign_in current_user, scope: :user
target_account.suspend!
end
let(:target_account) { Fabricate(:account) }
let(:strike) { Fabricate(:account_warning, target_account: target_account, action: :suspend) }
let(:appeal) { Fabricate(:appeal, strike: strike, account: target_account) }
before do
target_account.suspend!
end
describe 'POST #approve' do
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }

View File

@@ -146,13 +146,13 @@ describe Admin::Reports::ActionsController do
end
end
context 'with Action as submit button' do
context 'with action as submit button' do
subject { post :create, params: common_params.merge({ action => '' }) }
it_behaves_like 'all action types'
end
context 'with Action as submit button' do
context 'with moderation action as an extra field' do
subject { post :create, params: common_params.merge({ moderation_action: action }) }
it_behaves_like 'all action types'

View File

@@ -20,4 +20,52 @@ describe Api::V1::Admin::CanonicalEmailBlocksController do
expect(response).to have_http_status(200)
end
end
describe 'POST #test' do
context 'when required email is not provided' do
it 'returns http bad request' do
post :test
expect(response).to have_http_status(400)
end
end
context 'when required email is provided' do
let(:params) { { email: 'example@email.com' } }
context 'when there is a matching canonical email block' do
let!(:canonical_email_block) { CanonicalEmailBlock.create(params) }
it 'returns http success' do
post :test, params: params
expect(response).to have_http_status(200)
end
it 'returns expected canonical email hash' do
post :test, params: params
json = body_as_json
expect(json[0][:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash)
end
end
context 'when there is no matching canonical email block' do
it 'returns http success' do
post :test, params: params
expect(response).to have_http_status(200)
end
it 'returns an empty list' do
post :test, params: params
json = body_as_json
expect(json).to be_empty
end
end
end
end
end

View File

@@ -97,10 +97,12 @@ RSpec.describe Auth::RegistrationsController do
end
describe 'POST #create' do
let(:accept_language) { Rails.application.config.i18n.available_locales.sample.to_s }
let(:accept_language) { 'de' }
before do
session[:registration_form_time] = 5.seconds.ago
request.env['devise.mapping'] = Devise.mappings[:user]
end
around do |example|
@@ -109,8 +111,6 @@ RSpec.describe Auth::RegistrationsController do
end
end
before { request.env['devise.mapping'] = Devise.mappings[:user] }
context do
subject do
Setting.registrations_mode = 'open'

View File

@@ -1,6 +1,6 @@
# frozen_string_literal: true
Fabricator(:notification) do
activity fabricator: [:mention, :status, :follow, :follow_request, :favourite].sample
activity fabricator: :status
account
end

View File

@@ -0,0 +1,53 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe AccountReachFinder do
let(:account) { Fabricate(:account) }
let(:follower1) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-1') }
let(:follower2) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-2') }
let(:follower3) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://foo.bar/users/a/inbox', shared_inbox_url: 'https://foo.bar/inbox') }
let(:mentioned1) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://foo.bar/users/b/inbox', shared_inbox_url: 'https://foo.bar/inbox') }
let(:mentioned2) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-3') }
let(:mentioned3) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-4') }
let(:unrelated_account) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/unrelated-inbox') }
before do
follower1.follow!(account)
follower2.follow!(account)
follower3.follow!(account)
Fabricate(:status, account: account).tap do |status|
status.mentions << Mention.new(account: follower1)
status.mentions << Mention.new(account: mentioned1)
end
Fabricate(:status, account: account)
Fabricate(:status, account: account).tap do |status|
status.mentions << Mention.new(account: mentioned2)
status.mentions << Mention.new(account: mentioned3)
end
Fabricate(:status).tap do |status|
status.mentions << Mention.new(account: unrelated_account)
end
end
describe '#inboxes' do
it 'includes the preferred inbox URL of followers' do
expect(described_class.new(account).inboxes).to include(*[follower1, follower2, follower3].map(&:preferred_inbox_url))
end
it 'includes the preferred inbox URL of recently-mentioned accounts' do
expect(described_class.new(account).inboxes).to include(*[mentioned1, mentioned2, mentioned3].map(&:preferred_inbox_url))
end
it 'does not include the inbox of unrelated users' do
expect(described_class.new(account).inboxes).to_not include(unrelated_account.preferred_inbox_url)
end
end
end

View File

@@ -0,0 +1,292 @@
# frozen_string_literal: true
require 'rails_helper'
require 'mastodon/ip_blocks_cli'
RSpec.describe Mastodon::IpBlocksCLI do
let(:cli) { described_class.new }
describe '#add' do
let(:ip_list) do
[
'192.0.2.1',
'172.16.0.1',
'192.0.2.0/24',
'172.16.0.0/16',
'10.0.0.0/8',
'2001:0db8:85a3:0000:0000:8a2e:0370:7334',
'fe80::1',
'::1',
'2001:0db8::/32',
'fe80::/10',
'::/128',
]
end
let(:options) { { severity: 'no_access' } }
shared_examples 'ip address blocking' do
it 'blocks all specified IP addresses' do
cli.invoke(:add, ip_list, options)
blocked_ip_addresses = IpBlock.where(ip: ip_list).pluck(:ip)
expected_ip_addresses = ip_list.map { |ip| IPAddr.new(ip) }
expect(blocked_ip_addresses).to match_array(expected_ip_addresses)
end
it 'sets the severity for all blocked IP addresses' do
cli.invoke(:add, ip_list, options)
blocked_ips_severity = IpBlock.where(ip: ip_list).pluck(:severity).all?(options[:severity])
expect(blocked_ips_severity).to be(true)
end
it 'displays a success message with a summary' do
expect { cli.invoke(:add, ip_list, options) }.to output(
a_string_including("Added #{ip_list.size}, skipped 0, failed 0")
).to_stdout
end
end
context 'with valid IP addresses' do
include_examples 'ip address blocking'
end
context 'when a specified IP address is already blocked' do
let!(:blocked_ip) { IpBlock.create(ip: ip_list.last, severity: options[:severity]) }
it 'skips the already blocked IP address' do
allow(IpBlock).to receive(:new).and_call_original
cli.invoke(:add, ip_list, options)
expect(IpBlock).to_not have_received(:new).with(ip: ip_list.last)
end
it 'displays the correct summary' do
expect { cli.invoke(:add, ip_list, options) }.to output(
a_string_including("#{ip_list.last} is already blocked\nAdded #{ip_list.size - 1}, skipped 1, failed 0")
).to_stdout
end
context 'with --force option' do
let!(:blocked_ip) { IpBlock.create(ip: ip_list.last, severity: 'no_access') }
let(:options) { { severity: 'sign_up_requires_approval', force: true } }
it 'overwrites the existing IP block record' do
expect { cli.invoke(:add, ip_list, options) }
.to change { blocked_ip.reload.severity }
.from('no_access')
.to('sign_up_requires_approval')
end
include_examples 'ip address blocking'
end
end
context 'when a specified IP address is invalid' do
let(:ip_list) { ['320.15.175.0', '9.5.105.255', '0.0.0.0'] }
it 'displays the correct summary' do
expect { cli.invoke(:add, ip_list, options) }.to output(
a_string_including("#{ip_list.first} is invalid\nAdded #{ip_list.size - 1}, skipped 0, failed 1")
).to_stdout
end
end
context 'with --comment option' do
let(:options) { { severity: 'no_access', comment: 'Spam' } }
include_examples 'ip address blocking'
end
context 'with --duration option' do
let(:options) { { severity: 'no_access', duration: 10.days } }
include_examples 'ip address blocking'
end
context 'with "sign_up_requires_approval" severity' do
let(:options) { { severity: 'sign_up_requires_approval' } }
include_examples 'ip address blocking'
end
context 'with "sign_up_block" severity' do
let(:options) { { severity: 'sign_up_block' } }
include_examples 'ip address blocking'
end
context 'when a specified IP address fails to be blocked' do
let(:ip_address) { '127.0.0.1' }
let(:ip_block) { instance_double(IpBlock, ip: ip_address, save: false) }
before do
allow(IpBlock).to receive(:new).and_return(ip_block)
allow(ip_block).to receive(:severity=)
allow(ip_block).to receive(:expires_in=)
end
it 'displays an error message' do
expect { cli.invoke(:add, [ip_address], options) }
.to output(
a_string_including("#{ip_address} could not be saved")
).to_stdout
end
end
context 'when no IP address is provided' do
it 'exits with an error message' do
expect { cli.add }.to output(
a_string_including('No IP(s) given')
).to_stdout
.and raise_error(SystemExit)
end
end
end
describe '#remove' do
context 'when removing exact matches' do
let(:ip_list) do
[
'192.0.2.1',
'172.16.0.1',
'192.0.2.0/24',
'172.16.0.0/16',
'10.0.0.0/8',
'2001:0db8:85a3:0000:0000:8a2e:0370:7334',
'fe80::1',
'::1',
'2001:0db8::/32',
'fe80::/10',
'::/128',
]
end
before do
ip_list.each { |ip| IpBlock.create(ip: ip, severity: :no_access) }
end
it 'removes exact IP blocks' do
cli.invoke(:remove, ip_list)
expect(IpBlock.where(ip: ip_list)).to_not exist
end
it 'displays success message with a summary' do
expect { cli.invoke(:remove, ip_list) }.to output(
a_string_including("Removed #{ip_list.size}, skipped 0")
).to_stdout
end
end
context 'with --force option' do
let!(:block1) { IpBlock.create(ip: '192.168.0.0/24', severity: :no_access) }
let!(:block2) { IpBlock.create(ip: '10.0.0.0/16', severity: :no_access) }
let!(:block3) { IpBlock.create(ip: '172.16.0.0/20', severity: :no_access) }
let(:arguments) { ['192.168.0.5', '10.0.1.50'] }
let(:options) { { force: true } }
it 'removes blocks for IP ranges that cover given IP(s)' do
cli.invoke(:remove, arguments, options)
expect(IpBlock.where(id: [block1.id, block2.id])).to_not exist
end
it 'does not remove other IP ranges' do
cli.invoke(:remove, arguments, options)
expect(IpBlock.where(id: block3.id)).to exist
end
end
context 'when a specified IP address is not blocked' do
let(:unblocked_ip) { '192.0.2.1' }
it 'skips the IP address' do
expect { cli.invoke(:remove, [unblocked_ip]) }.to output(
a_string_including("#{unblocked_ip} is not yet blocked")
).to_stdout
end
it 'displays the summary correctly' do
expect { cli.invoke(:remove, [unblocked_ip]) }.to output(
a_string_including('Removed 0, skipped 1')
).to_stdout
end
end
context 'when a specified IP address is invalid' do
let(:invalid_ip) { '320.15.175.0' }
it 'skips the invalid IP address' do
expect { cli.invoke(:remove, [invalid_ip]) }.to output(
a_string_including("#{invalid_ip} is invalid")
).to_stdout
end
it 'displays the summary correctly' do
expect { cli.invoke(:remove, [invalid_ip]) }.to output(
a_string_including('Removed 0, skipped 1')
).to_stdout
end
end
context 'when no IP address is provided' do
it 'exits with an error message' do
expect { cli.remove }.to output(
a_string_including('No IP(s) given')
).to_stdout
.and raise_error(SystemExit)
end
end
end
describe '#export' do
let(:block1) { IpBlock.create(ip: '192.168.0.0/24', severity: :no_access) }
let(:block2) { IpBlock.create(ip: '10.0.0.0/16', severity: :no_access) }
let(:block3) { IpBlock.create(ip: '127.0.0.1', severity: :sign_up_block) }
context 'when --format option is set to "plain"' do
let(:options) { { format: 'plain' } }
it 'exports blocked IPs with "no_access" severity in plain format' do
expect { cli.invoke(:export, nil, options) }.to output(
a_string_including("#{block1.ip}/#{block1.ip.prefix}\n#{block2.ip}/#{block2.ip.prefix}")
).to_stdout
end
it 'does not export bloked IPs with different severities' do
expect { cli.invoke(:export, nil, options) }.to_not output(
a_string_including("#{block3.ip}/#{block1.ip.prefix}")
).to_stdout
end
end
context 'when --format option is set to "nginx"' do
let(:options) { { format: 'nginx' } }
it 'exports blocked IPs with "no_access" severity in plain format' do
expect { cli.invoke(:export, nil, options) }.to output(
a_string_including("deny #{block1.ip}/#{block1.ip.prefix};\ndeny #{block2.ip}/#{block2.ip.prefix};")
).to_stdout
end
it 'does not export bloked IPs with different severities' do
expect { cli.invoke(:export, nil, options) }.to_not output(
a_string_including("deny #{block3.ip}/#{block1.ip.prefix};")
).to_stdout
end
end
context 'when --format option is not provided' do
it 'exports blocked IPs in plain format by default' do
expect { cli.export }.to output(
a_string_including("#{block1.ip}/#{block1.ip.prefix}\n#{block2.ip}/#{block2.ip.prefix}")
).to_stdout
end
end
end
end

View File

@@ -7,9 +7,11 @@ RSpec.describe Vacuum::AccessTokensVacuum do
describe '#perform' do
let!(:revoked_access_token) { Fabricate(:access_token, revoked_at: 1.minute.ago) }
let!(:expired_access_token) { Fabricate(:access_token, expires_in: 59.minutes.to_i, created_at: 1.hour.ago) }
let!(:active_access_token) { Fabricate(:access_token) }
let!(:revoked_access_grant) { Fabricate(:access_grant, revoked_at: 1.minute.ago) }
let!(:expired_access_grant) { Fabricate(:access_grant, expires_in: 59.minutes.to_i, created_at: 1.hour.ago) }
let!(:active_access_grant) { Fabricate(:access_grant) }
before do
@@ -20,10 +22,18 @@ RSpec.describe Vacuum::AccessTokensVacuum do
expect { revoked_access_token.reload }.to raise_error ActiveRecord::RecordNotFound
end
it 'deletes expired access tokens' do
expect { expired_access_token.reload }.to raise_error ActiveRecord::RecordNotFound
end
it 'deletes revoked access grants' do
expect { revoked_access_grant.reload }.to raise_error ActiveRecord::RecordNotFound
end
it 'deletes expired access grants' do
expect { expired_access_grant.reload }.to raise_error ActiveRecord::RecordNotFound
end
it 'does not delete active access tokens' do
expect { active_access_token.reload }.to_not raise_error
end

35
spec/locales/i18n_spec.rb Normal file
View File

@@ -0,0 +1,35 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'I18n' do
describe 'Pluralizing locale translations' do
subject { I18n.t('generic.validation_errors', count: 1) }
context 'with the `en` locale which has `one` and `other` plural values' do
around do |example|
I18n.with_locale(:en) do
example.run
end
end
it 'translates to `en` correctly and without error' do
expect { subject }.to_not raise_error
expect(subject).to match(/the error below/)
end
end
context 'with the `my` locale which has only `other` plural value' do
around do |example|
I18n.with_locale(:my) do
example.run
end
end
it 'translates to `my` correctly and without error' do
expect { subject }.to_not raise_error
expect(subject).to match(/1/)
end
end
end
end

View File

@@ -10,7 +10,7 @@ RSpec.describe NotificationMailer do
shared_examples 'localized subject' do |*args, **kwrest|
it 'renders subject localized for the locale of the receiver' do
locale = %i(de en).sample
locale = :de
receiver.update!(locale: locale)
expect(mail.subject).to eq I18n.t(*args, **kwrest.merge(locale: locale))
end

View File

@@ -7,7 +7,7 @@ describe UserMailer do
shared_examples 'localized subject' do |*args, **kwrest|
it 'renders subject localized for the locale of the receiver' do
locale = I18n.available_locales.sample
locale = :de
receiver.update!(locale: locale)
expect(mail.subject).to eq I18n.t(*args, **kwrest.merge(locale: locale))
end

View File

@@ -0,0 +1,63 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Form::AccountBatch do
let(:account_batch) { described_class.new }
describe '#save' do
subject { account_batch.save }
let(:account) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
let(:account_ids) { [] }
let(:query) { Account.none }
before do
account_batch.assign_attributes(
action: action,
current_account: account,
account_ids: account_ids,
query: query,
select_all_matching: select_all_matching
)
end
context 'when action is "suspend"' do
let(:action) { 'suspend' }
let(:target_account) { Fabricate(:account) }
let(:target_account2) { Fabricate(:account) }
before do
Fabricate(:report, target_account: target_account)
Fabricate(:report, target_account: target_account2)
end
context 'when accounts are passed as account_ids' do
let(:select_all_matching) { '0' }
let(:account_ids) { [target_account.id, target_account2.id] }
it 'suspends the expected users' do
expect { subject }.to change { [target_account.reload.suspended?, target_account2.reload.suspended?] }.from([false, false]).to([true, true])
end
it 'closes open reports targeting the suspended users' do
expect { subject }.to change { Report.unresolved.where(target_account: [target_account, target_account2]).count }.from(2).to(0)
end
end
context 'when accounts are passed as a query' do
let(:select_all_matching) { '1' }
let(:query) { Account.where(id: [target_account.id, target_account2.id]) }
it 'suspends the expected users' do
expect { subject }.to change { [target_account.reload.suspended?, target_account2.reload.suspended?] }.from([false, false]).to([true, true])
end
it 'closes open reports targeting the suspended users' do
expect { subject }.to change { Report.unresolved.where(target_account: [target_account, target_account2]).count }.from(2).to(0)
end
end
end
end
end

View File

@@ -30,19 +30,17 @@ RSpec.describe ReportNotePolicy do
end
end
context 'when admin?' do
context 'when owner?' do
it 'permit' do
report_note = Fabricate(:report_note, account: john)
expect(subject).to permit(john, report_note)
end
context 'when owner?' do
it 'permit' do
report_note = Fabricate(:report_note, account: john)
expect(subject).to permit(john, report_note)
end
end
context 'with !owner?' do
it 'denies' do
report_note = Fabricate(:report_note)
expect(subject).to_not permit(john, report_note)
end
context 'with !owner?' do
it 'denies' do
report_note = Fabricate(:report_note)
expect(subject).to_not permit(john, report_note)
end
end
end

View File

@@ -139,10 +139,6 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do
end
context 'when Accounts referencing other accounts' do
before do
stub_const 'ActivityPub::ProcessAccountService::DISCOVERIES_PER_REQUEST', 5
end
let(:payload) do
{
'@context': ['https://www.w3.org/ns/activitystreams'],
@@ -155,6 +151,8 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do
end
before do
stub_const 'ActivityPub::ProcessAccountService::DISCOVERIES_PER_REQUEST', 5
8.times do |i|
actor_json = {
'@context': ['https://www.w3.org/ns/activitystreams'],

View File

@@ -3,7 +3,7 @@
require 'rails_helper'
RSpec.describe UnsuspendAccountService, type: :service do
shared_examples 'common behavior' do
shared_context 'with common context' do
subject { described_class.new.call(account) }
let!(:local_follower) { Fabricate(:user, current_sign_in_at: 1.hour.ago).account }
@@ -36,7 +36,7 @@ RSpec.describe UnsuspendAccountService, type: :service do
expect { subject }.to_not change { account.suspended? }
end
include_examples 'common behavior' do
include_examples 'with common context' do
let!(:account) { Fabricate(:account) }
let!(:remote_follower) { Fabricate(:account, uri: 'https://alice.com', inbox_url: 'https://alice.com/inbox', protocol: :activitypub) }
let!(:remote_reporter) { Fabricate(:account, uri: 'https://bob.com', inbox_url: 'https://bob.com/inbox', protocol: :activitypub) }
@@ -61,7 +61,7 @@ RSpec.describe UnsuspendAccountService, type: :service do
end
describe 'unsuspending a remote account' do
include_examples 'common behavior' do
include_examples 'with common context' do
let!(:account) { Fabricate(:account, domain: 'bob.com', uri: 'https://bob.com', inbox_url: 'https://bob.com/inbox', protocol: :activitypub) }
let!(:resolve_account_service) { double }