Merge commit '391c089d0db58d731765dba730a5e1f2fe8570a6' into glitch-soc/merge-upstream

Conflicts:
- `.github/dependabot.yml`:
  We removed it from glitch-soc.
  Keep it deleted.
pull/62/head
Claire 2023-05-28 16:41:14 +02:00
commit 0e7466717f
56 changed files with 362 additions and 315 deletions

View File

@ -379,23 +379,6 @@ RSpec/EmptyExampleGroup:
RSpec/ExampleLength:
Max: 22
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle.
# SupportedStyles: method_call, block
RSpec/ExpectChange:
Exclude:
- 'spec/controllers/admin/account_moderation_notes_controller_spec.rb'
- 'spec/controllers/admin/custom_emojis_controller_spec.rb'
- 'spec/controllers/admin/invites_controller_spec.rb'
- 'spec/controllers/admin/report_notes_controller_spec.rb'
- 'spec/controllers/concerns/accountable_concern_spec.rb'
- 'spec/controllers/invites_controller_spec.rb'
- 'spec/controllers/settings/two_factor_authentication/webauthn_credentials_controller_spec.rb'
- 'spec/models/admin/account_action_spec.rb'
- 'spec/services/suspend_account_service_spec.rb'
- 'spec/services/unsuspend_account_service_spec.rb'
- 'spec/workers/scheduler/accounts_statuses_cleanup_scheduler_spec.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle.
# SupportedStyles: implicit, each, example

View File

@ -151,7 +151,7 @@ GEM
bundler-audit (0.9.1)
bundler (>= 1.2.0, < 3)
thor (~> 1.0)
capistrano (3.17.2)
capistrano (3.17.3)
airbrussh (>= 1.0.0)
i18n
rake (>= 10.0.0)
@ -269,7 +269,7 @@ GEM
faraday-rack (1.0.0)
faraday-retry (1.0.3)
fast_blank (1.0.1)
fastimage (2.2.6)
fastimage (2.2.7)
ffi (1.15.5)
ffi-compiler (1.0.1)
ffi (>= 1.0.0)

View File

@ -1,37 +0,0 @@
import PropTypes from 'prop-types';
import { PureComponent } from 'react';
import { injectIntl, defineMessages } from 'react-intl';
import { Icon } from 'mastodon/components/icon';
const messages = defineMessages({
load_more: { id: 'status.load_more', defaultMessage: 'Load more' },
});
class LoadGap extends PureComponent {
static propTypes = {
disabled: PropTypes.bool,
maxId: PropTypes.string,
onClick: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
};
handleClick = () => {
this.props.onClick(this.props.maxId);
};
render () {
const { disabled, intl } = this.props;
return (
<button className='load-more load-gap' disabled={disabled} onClick={this.handleClick} aria-label={intl.formatMessage(messages.load_more)}>
<Icon id='ellipsis-h' />
</button>
);
}
}
export default injectIntl(LoadGap);

View File

@ -0,0 +1,36 @@
import { useCallback } from 'react';
import type { InjectedIntl } from 'react-intl';
import { injectIntl, defineMessages } from 'react-intl';
import { Icon } from 'mastodon/components/icon';
const messages = defineMessages({
load_more: { id: 'status.load_more', defaultMessage: 'Load more' },
});
interface Props {
disabled: boolean;
maxId: string;
onClick: (maxId: string) => void;
intl: InjectedIntl;
}
export const LoadGap = injectIntl<Props>(
({ disabled, maxId, onClick, intl }) => {
const handleClick = useCallback(() => {
onClick(maxId);
}, [maxId, onClick]);
return (
<button
className='load-more load-gap'
disabled={disabled}
onClick={handleClick}
aria-label={intl.formatMessage(messages.load_more)}
>
<Icon id='ellipsis-h' />
</button>
);
}
);

View File

@ -114,7 +114,6 @@ class StatusActionBar extends ImmutablePureComponent {
handleShareClick = () => {
navigator.share({
text: this.props.status.get('search_index'),
url: this.props.status.get('url'),
}).catch((e) => {
if (e.name !== 'AbortError') console.error(e);
@ -256,6 +255,10 @@ class StatusActionBar extends ImmutablePureComponent {
menu.push({ text: intl.formatMessage(messages.copy), action: this.handleCopy });
if (publicStatus && 'share' in navigator) {
menu.push({ text: intl.formatMessage(messages.share), action: this.handleShareClick });
}
if (publicStatus) {
menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed });
}
@ -352,10 +355,6 @@ class StatusActionBar extends ImmutablePureComponent {
reblogTitle = intl.formatMessage(messages.cannot_reblog);
}
const shareButton = ('share' in navigator) && publicStatus && (
<IconButton className='status__action-bar__button' title={intl.formatMessage(messages.share)} icon='share-alt' onClick={this.handleShareClick} />
);
const filterButton = this.props.onFilter && (
<IconButton className='status__action-bar__button' title={intl.formatMessage(messages.hide)} icon='eye' onClick={this.handleHideClick} />
);
@ -367,8 +366,6 @@ class StatusActionBar extends ImmutablePureComponent {
<IconButton className='status__action-bar__button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} />
<IconButton className='status__action-bar__button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} />
{shareButton}
{filterButton}
<div className='status__action-bar__dropdown'>

View File

@ -9,7 +9,7 @@ import RegenerationIndicator from 'mastodon/components/regeneration_indicator';
import StatusContainer from '../containers/status_container';
import LoadGap from './load_gap';
import { LoadGap } from './load_gap';
import ScrollableList from './scrollable_list';
export default class StatusList extends ImmutablePureComponent {

View File

@ -165,7 +165,6 @@ class Header extends ImmutablePureComponent {
const { account } = this.props;
navigator.share({
text: `${titleFromAccount(account)}\n${account.get('note_plain')}`,
url: account.get('url'),
}).catch((e) => {
if (e.name !== 'AbortError') console.error(e);

View File

@ -28,7 +28,7 @@ import {
} from '../../actions/notifications';
import Column from '../../components/column';
import ColumnHeader from '../../components/column_header';
import LoadGap from '../../components/load_gap';
import { LoadGap } from '../../components/load_gap';
import ScrollableList from '../../components/scrollable_list';
import NotificationsPermissionBanner from './components/notifications_permission_banner';

View File

@ -169,7 +169,6 @@ class ActionBar extends PureComponent {
handleShare = () => {
navigator.share({
text: this.props.status.get('search_index'),
url: this.props.status.get('url'),
});
};
@ -202,6 +201,11 @@ class ActionBar extends PureComponent {
}
menu.push({ text: intl.formatMessage(messages.copy), action: this.handleCopy });
if ('share' in navigator) {
menu.push({ text: intl.formatMessage(messages.share), action: this.handleShare });
}
menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed });
menu.push(null);
}
@ -260,10 +264,6 @@ class ActionBar extends PureComponent {
}
}
const shareButton = ('share' in navigator) && publicStatus && (
<div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.share)} icon='share-alt' onClick={this.handleShare} /></div>
);
let replyIcon;
if (status.get('in_reply_to_id', null) === null) {
replyIcon = 'reply';
@ -287,12 +287,10 @@ class ActionBar extends PureComponent {
return (
<div className='detailed-status__action-bar'>
<div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} /></div>
<div className='detailed-status__button' ><IconButton className={classNames({ reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} /></div>
<div className='detailed-status__button'><IconButton className={classNames({ reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} /></div>
<div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} /></div>
<div className='detailed-status__button'><IconButton className='bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} /></div>
{shareButton}
<div className='detailed-status__action-bar-dropdown'>
<DropdownMenuContainer size={18} icon='ellipsis-h' disabled={!signedIn} status={status} items={menu} direction='left' title={intl.formatMessage(messages.more)} />
</div>

View File

@ -21,7 +21,7 @@ const Account = connect(state => ({
));
const mapStateToProps = (state) => ({
signupUrl: state.getIn(['server', 'server', 'registrations', 'url'], '/auth/sign_up'),
signupUrl: state.getIn(['server', 'server', 'registrations', 'url'], null) || '/auth/sign_up',
});
const mapDispatchToProps = (dispatch) => ({

View File

@ -1,18 +1,10 @@
# frozen_string_literal: true
require 'set'
require_relative '../../../config/boot'
require_relative '../../../config/environment'
require_relative 'helper'
require_relative 'base'
module Mastodon::CLI
class Accounts < Thor
include Helper
def self.exit_on_failure?
true
end
class Accounts < Base
option :all, type: :boolean
desc 'rotate [USERNAME]', 'Generate and broadcast new keys'
long_desc <<-LONG_DESC

19
lib/mastodon/cli/base.rb Normal file
View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
require_relative '../../../config/boot'
require_relative '../../../config/environment'
require 'thor'
require_relative 'helper'
module Mastodon
module CLI
class Base < Thor
include CLI::Helper
def self.exit_on_failure?
true
end
end
end
end

View File

@ -1,17 +1,9 @@
# frozen_string_literal: true
require_relative '../../../config/boot'
require_relative '../../../config/environment'
require_relative 'helper'
require_relative 'base'
module Mastodon::CLI
class Cache < Thor
include Helper
def self.exit_on_failure?
true
end
class Cache < Base
desc 'clear', 'Clear out the cache storage'
def clear
Rails.cache.clear

View File

@ -1,18 +1,10 @@
# frozen_string_literal: true
require 'concurrent'
require_relative '../../../config/boot'
require_relative '../../../config/environment'
require_relative 'helper'
require_relative 'base'
module Mastodon::CLI
class CanonicalEmailBlocks < Thor
include Helper
def self.exit_on_failure?
true
end
class CanonicalEmailBlocks < Base
desc 'find EMAIL', 'Find a given e-mail address in the canonical e-mail blocks'
long_desc <<-LONG_DESC
When suspending a local user, a hash of a "canonical" version of their e-mail

View File

@ -1,18 +1,10 @@
# frozen_string_literal: true
require 'concurrent'
require_relative '../../../config/boot'
require_relative '../../../config/environment'
require_relative 'helper'
require_relative 'base'
module Mastodon::CLI
class Domains < Thor
include Helper
def self.exit_on_failure?
true
end
class Domains < Base
option :concurrency, type: :numeric, default: 5, aliases: [:c]
option :verbose, type: :boolean, aliases: [:v]
option :dry_run, type: :boolean

View File

@ -1,18 +1,10 @@
# frozen_string_literal: true
require 'concurrent'
require_relative '../../../config/boot'
require_relative '../../../config/environment'
require_relative 'helper'
require_relative 'base'
module Mastodon::CLI
class EmailDomainBlocks < Thor
include Helper
def self.exit_on_failure?
true
end
class EmailDomainBlocks < Base
desc 'list', 'List blocked e-mail domains'
def list
EmailDomainBlock.where(parent_id: nil).order(id: 'DESC').find_each do |entry|

View File

@ -1,16 +1,10 @@
# frozen_string_literal: true
require 'rubygems/package'
require_relative '../../../config/boot'
require_relative '../../../config/environment'
require_relative 'helper'
require_relative 'base'
module Mastodon::CLI
class Emoji < Thor
def self.exit_on_failure?
true
end
class Emoji < Base
option :prefix
option :suffix
option :overwrite, type: :boolean

View File

@ -1,18 +1,11 @@
# frozen_string_literal: true
require_relative '../../../config/boot'
require_relative '../../../config/environment'
require_relative 'helper'
require_relative 'base'
module Mastodon::CLI
class Feeds < Thor
include Helper
class Feeds < Base
include Redisable
def self.exit_on_failure?
true
end
option :all, type: :boolean, default: false
option :concurrency, type: :numeric, default: 5, aliases: [:c]
option :verbose, type: :boolean, aliases: [:v]

View File

@ -1,16 +1,10 @@
# frozen_string_literal: true
require 'rubygems/package'
require_relative '../../../config/boot'
require_relative '../../../config/environment'
require_relative 'helper'
require_relative 'base'
module Mastodon::CLI
class IpBlocks < Thor
def self.exit_on_failure?
true
end
class IpBlocks < Base
option :severity, required: true, enum: %w(no_access sign_up_requires_approval sign_up_block), desc: 'Severity of the block'
option :comment, aliases: [:c], desc: 'Optional comment'
option :duration, aliases: [:d], type: :numeric, desc: 'Duration of the block in seconds'

View File

@ -1,29 +1,25 @@
# frozen_string_literal: true
require 'thor'
require_relative 'media'
require_relative 'emoji'
require_relative 'base'
require_relative 'accounts'
require_relative 'cache'
require_relative 'canonical_email_blocks'
require_relative 'domains'
require_relative 'email_domain_blocks'
require_relative 'emoji'
require_relative 'feeds'
require_relative 'ip_blocks'
require_relative 'maintenance'
require_relative 'media'
require_relative 'preview_cards'
require_relative 'search'
require_relative 'settings'
require_relative 'statuses'
require_relative 'domains'
require_relative 'preview_cards'
require_relative 'cache'
require_relative 'upgrade'
require_relative 'email_domain_blocks'
require_relative 'canonical_email_blocks'
require_relative 'ip_blocks'
require_relative 'maintenance'
require_relative '../version'
module Mastodon::CLI
class Main < Thor
def self.exit_on_failure?
true
end
class Main < Base
desc 'media SUBCOMMAND ...ARGS', 'Manage media files'
subcommand 'media', Media

View File

@ -1,18 +1,10 @@
# frozen_string_literal: true
require 'tty-prompt'
require_relative '../../../config/boot'
require_relative '../../../config/environment'
require_relative 'helper'
require_relative 'base'
module Mastodon::CLI
class Maintenance < Thor
include Helper
def self.exit_on_failure?
true
end
class Maintenance < Base
MIN_SUPPORTED_VERSION = 2019_10_01_213028
MAX_SUPPORTED_VERSION = 2022_11_04_133904

View File

@ -1,20 +1,13 @@
# frozen_string_literal: true
require_relative '../../../config/boot'
require_relative '../../../config/environment'
require_relative 'helper'
require_relative 'base'
module Mastodon::CLI
class Media < Thor
class Media < Base
include ActionView::Helpers::NumberHelper
include Helper
VALID_PATH_SEGMENTS_SIZE = [7, 10].freeze
def self.exit_on_failure?
true
end
option :days, type: :numeric, default: 7, aliases: [:d]
option :prune_profiles, type: :boolean, default: false
option :remove_headers, type: :boolean, default: false

View File

@ -1,18 +1,11 @@
# frozen_string_literal: true
require 'tty-prompt'
require_relative '../../../config/boot'
require_relative '../../../config/environment'
require_relative 'helper'
require_relative 'base'
module Mastodon::CLI
class PreviewCards < Thor
class PreviewCards < Base
include ActionView::Helpers::NumberHelper
include Helper
def self.exit_on_failure?
true
end
option :days, type: :numeric, default: 180
option :concurrency, type: :numeric, default: 5, aliases: [:c]

View File

@ -1,13 +1,9 @@
# frozen_string_literal: true
require_relative '../../../config/boot'
require_relative '../../../config/environment'
require_relative 'helper'
require_relative 'base'
module Mastodon::CLI
class Search < Thor
include Helper
class Search < Base
# Indices are sorted by amount of data to be expected in each, so that
# smaller indices can go online sooner
INDICES = [

View File

@ -1,15 +1,9 @@
# frozen_string_literal: true
require_relative '../../../config/boot'
require_relative '../../../config/environment'
require_relative 'helper'
require_relative 'base'
module Mastodon::CLI
class Registrations < Thor
def self.exit_on_failure?
true
end
class Registrations < Base
desc 'open', 'Open registrations'
def open
Setting.registrations_mode = 'open'
@ -37,7 +31,7 @@ module Mastodon::CLI
end
end
class Settings < Thor
class Settings < Base
desc 'registrations SUBCOMMAND ...ARGS', 'Manage state of registrations'
subcommand 'registrations', Registrations
end

View File

@ -1,18 +1,11 @@
# frozen_string_literal: true
require_relative '../../../config/boot'
require_relative '../../../config/environment'
require_relative 'helper'
require_relative 'base'
module Mastodon::CLI
class Statuses < Thor
include Helper
class Statuses < Base
include ActionView::Helpers::NumberHelper
def self.exit_on_failure?
true
end
option :days, type: :numeric, default: 90
option :batch_size, type: :numeric, default: 1_000, aliases: [:b], desc: 'Number of records in each batch'
option :continue, type: :boolean, default: false, desc: 'If remove is not completed, execute from the previous continuation'

View File

@ -1,17 +1,9 @@
# frozen_string_literal: true
require_relative '../../../config/boot'
require_relative '../../../config/environment'
require_relative 'helper'
require_relative 'base'
module Mastodon::CLI
class Upgrade < Thor
include Helper
def self.exit_on_failure?
true
end
class Upgrade < Base
CURRENT_STORAGE_SCHEMA_VERSION = 1
option :dry_run, type: :boolean, default: false

View File

@ -100,7 +100,7 @@
"react-motion": "^0.5.2",
"react-notification": "^6.8.5",
"react-overlays": "^5.2.1",
"react-redux": "^7.2.9",
"react-redux": "^8.0.4",
"react-redux-loading-bar": "^5.0.4",
"react-router-dom": "^4.1.1",
"react-router-scroll-4": "^1.0.0-beta.1",
@ -165,7 +165,6 @@
"@types/react-intl": "2.3.18",
"@types/react-motion": "^0.0.33",
"@types/react-overlays": "^3.1.0",
"@types/react-redux": "^7.1.25",
"@types/react-router-dom": "^5.3.3",
"@types/react-select": "^5.0.1",
"@types/react-sparklines": "^1.7.2",
@ -181,12 +180,12 @@
"@typescript-eslint/eslint-plugin": "^5.59.7",
"@typescript-eslint/parser": "^5.59.7",
"babel-jest": "^29.5.0",
"eslint": "^8.40.0",
"eslint": "^8.41.0",
"eslint-config-prettier": "^8.8.0",
"eslint-import-resolver-typescript": "^3.5.5",
"eslint-plugin-formatjs": "^4.10.1",
"eslint-plugin-import": "~2.27.5",
"eslint-plugin-jsdoc": "^44.2.4",
"eslint-plugin-jsdoc": "^44.2.5",
"eslint-plugin-jsx-a11y": "~6.7.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-promise": "~6.1.1",

View File

@ -19,7 +19,7 @@ RSpec.describe Admin::AccountModerationNotesController do
let(:params) { { account_moderation_note: { target_account_id: target_account.id, content: 'test content' } } }
it 'successfully creates a note' do
expect { subject }.to change { AccountModerationNote.count }.by(1)
expect { subject }.to change(AccountModerationNote, :count).by(1)
expect(subject).to redirect_to admin_account_path(target_account.id)
end
end
@ -28,7 +28,7 @@ RSpec.describe Admin::AccountModerationNotesController do
let(:params) { { account_moderation_note: { target_account_id: target_account.id, content: '' } } }
it 'falls to create a note' do
expect { subject }.to_not change { AccountModerationNote.count }
expect { subject }.to_not change(AccountModerationNote, :count)
expect(subject).to render_template 'admin/accounts/show'
end
end
@ -41,7 +41,7 @@ RSpec.describe Admin::AccountModerationNotesController do
let(:account) { Fabricate(:account) }
it 'destroys note' do
expect { subject }.to change { AccountModerationNote.count }.by(-1)
expect { subject }.to change(AccountModerationNote, :count).by(-1)
expect(subject).to redirect_to admin_account_path(target_account.id)
end
end

View File

@ -42,7 +42,7 @@ describe Admin::CustomEmojisController do
let(:params) { { shortcode: 'test', image: image } }
it 'creates custom emoji' do
expect { subject }.to change { CustomEmoji.count }.by(1)
expect { subject }.to change(CustomEmoji, :count).by(1)
end
end

View File

@ -26,7 +26,7 @@ describe Admin::InvitesController do
subject { post :create, params: { invite: { max_uses: '10', expires_in: 1800 } } }
it 'succeeds to create a invite' do
expect { subject }.to change { Invite.count }.by(1)
expect { subject }.to change(Invite, :count).by(1)
expect(subject).to redirect_to admin_invites_path
expect(Invite.last).to have_attributes(user_id: user.id, max_uses: 10)
end

View File

@ -25,7 +25,7 @@ describe Admin::ReportNotesController do
let(:params) { { report_note: { content: 'test content', report_id: report.id }, create_and_resolve: nil } }
it 'creates a report note and resolves report' do
expect { subject }.to change { ReportNote.count }.by(1)
expect { subject }.to change(ReportNote, :count).by(1)
expect(report.reload).to be_action_taken
expect(subject).to redirect_to admin_reports_path
end
@ -35,7 +35,7 @@ describe Admin::ReportNotesController do
let(:params) { { report_note: { content: 'test content', report_id: report.id } } }
it 'creates a report note and does not resolve report' do
expect { subject }.to change { ReportNote.count }.by(1)
expect { subject }.to change(ReportNote, :count).by(1)
expect(report.reload).to_not be_action_taken
expect(subject).to redirect_to admin_report_path(report)
end
@ -50,7 +50,7 @@ describe Admin::ReportNotesController do
let(:params) { { report_note: { content: 'test content', report_id: report.id }, create_and_unresolve: nil } }
it 'creates a report note and unresolves report' do
expect { subject }.to change { ReportNote.count }.by(1)
expect { subject }.to change(ReportNote, :count).by(1)
expect(report.reload).to_not be_action_taken
expect(subject).to redirect_to admin_report_path(report)
end
@ -60,7 +60,7 @@ describe Admin::ReportNotesController do
let(:params) { { report_note: { content: 'test content', report_id: report.id } } }
it 'creates a report note and does not unresolve report' do
expect { subject }.to change { ReportNote.count }.by(1)
expect { subject }.to change(ReportNote, :count).by(1)
expect(report.reload).to be_action_taken
expect(subject).to redirect_to admin_report_path(report)
end
@ -85,7 +85,7 @@ describe Admin::ReportNotesController do
let!(:report_note) { Fabricate(:report_note) }
it 'deletes note' do
expect { subject }.to change { ReportNote.count }.by(-1)
expect { subject }.to change(ReportNote, :count).by(-1)
expect(subject).to redirect_to admin_report_path(report_note.report)
end
end

View File

@ -22,7 +22,7 @@ RSpec.describe AccountableConcern do
it 'creates Admin::ActionLog' do
expect do
hoge.log_action(:create, target)
end.to change { Admin::ActionLog.count }.by(1)
end.to change(Admin::ActionLog, :count).by(1)
end
end
end

View File

@ -52,7 +52,7 @@ describe InvitesController do
end
it 'succeeds to create a invite' do
expect { subject }.to change { Invite.count }.by(1)
expect { subject }.to change(Invite, :count).by(1)
expect(subject).to redirect_to invites_path
expect(Invite.last).to have_attributes(user_id: user.id, max_uses: 10)
end

View File

@ -134,7 +134,7 @@ describe Settings::TwoFactorAuthentication::WebauthnCredentialsController do
end
it 'does not change webauthn_id' do
expect { get :options }.to_not change { user.webauthn_id }
expect { get :options }.to_not change(user, :webauthn_id)
end
it 'includes existing credentials in list of excluded credentials' do
@ -238,7 +238,7 @@ describe Settings::TwoFactorAuthentication::WebauthnCredentialsController do
expect do
post :create, params: { credential: new_webauthn_credential, nickname: nickname }
end.to_not change { user.webauthn_id }
end.to_not change(user, :webauthn_id)
end
end

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
require 'rails_helper'
require 'mastodon/cli/accounts'
describe Mastodon::CLI::Accounts do
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
end

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
require 'rails_helper'
require 'mastodon/cli/cache'
describe Mastodon::CLI::Cache do
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
end

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
require 'rails_helper'
require 'mastodon/cli/canonical_email_blocks'
describe Mastodon::CLI::CanonicalEmailBlocks do
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
end

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
require 'rails_helper'
require 'mastodon/cli/domains'
describe Mastodon::CLI::Domains do
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
end

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
require 'rails_helper'
require 'mastodon/cli/email_domain_blocks'
describe Mastodon::CLI::EmailDomainBlocks do
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
end

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
require 'rails_helper'
require 'mastodon/cli/emoji'
describe Mastodon::CLI::Emoji do
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
end

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
require 'rails_helper'
require 'mastodon/cli/feeds'
describe Mastodon::CLI::Feeds do
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
end

View File

@ -3,9 +3,15 @@
require 'rails_helper'
require 'mastodon/cli/ip_blocks'
RSpec.describe Mastodon::CLI::IpBlocks do
describe Mastodon::CLI::IpBlocks do
let(:cli) { described_class.new }
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
describe '#add' do
let(:ip_list) do
[

View File

@ -4,6 +4,12 @@ require 'rails_helper'
require 'mastodon/cli/main'
describe Mastodon::CLI::Main do
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
describe 'version' do
it 'returns the Mastodon version' do
expect { described_class.new.invoke(:version) }.to output(

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
require 'rails_helper'
require 'mastodon/cli/maintenance'
describe Mastodon::CLI::Maintenance do
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
end

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
require 'rails_helper'
require 'mastodon/cli/media'
describe Mastodon::CLI::Media do
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
end

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
require 'rails_helper'
require 'mastodon/cli/preview_cards'
describe Mastodon::CLI::PreviewCards do
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
end

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
require 'rails_helper'
require 'mastodon/cli/search'
describe Mastodon::CLI::Search do
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
end

View File

@ -3,7 +3,13 @@
require 'rails_helper'
require 'mastodon/cli/settings'
RSpec.describe Mastodon::CLI::Settings do
describe Mastodon::CLI::Settings do
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
describe 'subcommand "registrations"' do
let(:cli) { Mastodon::CLI::Registrations.new }

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
require 'rails_helper'
require 'mastodon/cli/statuses'
describe Mastodon::CLI::Statuses do
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
end

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
require 'rails_helper'
require 'mastodon/cli/upgrade'
describe Mastodon::CLI::Upgrade do
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
end

View File

@ -58,7 +58,7 @@ RSpec.describe Admin::AccountAction do
it 'creates Admin::ActionLog' do
expect do
subject
end.to change { Admin::ActionLog.count }.by 1
end.to change(Admin::ActionLog, :count).by 1
end
it 'calls process_email!' do

View File

@ -26,7 +26,7 @@ RSpec.describe SuspendAccountService, type: :service do
end
it 'does not change the “suspended” flag' do
expect { subject }.to_not change { account.suspended? }
expect { subject }.to_not change(account, :suspended?)
end
end

View File

@ -33,7 +33,7 @@ RSpec.describe UnsuspendAccountService, type: :service do
end
it 'does not change the “suspended” flag' do
expect { subject }.to_not change { account.suspended? }
expect { subject }.to_not change(account, :suspended?)
end
include_examples 'with common context' do
@ -86,7 +86,7 @@ RSpec.describe UnsuspendAccountService, type: :service do
end
it 'does not change the “suspended” flag' do
expect { subject }.to_not change { account.suspended? }
expect { subject }.to_not change(account, :suspended?)
end
end
@ -110,7 +110,7 @@ RSpec.describe UnsuspendAccountService, type: :service do
end
it 'marks account as suspended' do
expect { subject }.to change { account.suspended? }.from(false).to(true)
expect { subject }.to change(account, :suspended?).from(false).to(true)
end
end

View File

@ -103,7 +103,7 @@ describe Scheduler::AccountsStatusesCleanupScheduler do
describe '#perform' do
context 'when the budget is lower than the number of toots to delete' do
it 'deletes as many statuses as the given budget' do
expect { subject.perform }.to change { Status.count }.by(-subject.compute_budget)
expect { subject.perform }.to change(Status, :count).by(-subject.compute_budget)
end
it 'does not delete from accounts with no cleanup policy' do
@ -117,7 +117,7 @@ describe Scheduler::AccountsStatusesCleanupScheduler do
it 'eventually deletes every deletable toot given enough runs' do
stub_const 'Scheduler::AccountsStatusesCleanupScheduler::MAX_BUDGET', 4
expect { 10.times { subject.perform } }.to change { Status.count }.by(-30)
expect { 10.times { subject.perform } }.to change(Status, :count).by(-30)
end
it 'correctly round-trips between users across several runs' do
@ -125,7 +125,7 @@ describe Scheduler::AccountsStatusesCleanupScheduler do
stub_const 'Scheduler::AccountsStatusesCleanupScheduler::PER_ACCOUNT_BUDGET', 2
expect { 3.times { subject.perform } }
.to change { Status.count }.by(-3 * 3)
.to change(Status, :count).by(-3 * 3)
.and change { account1.statuses.count }
.and change { account3.statuses.count }
.and change { account5.statuses.count }
@ -140,7 +140,7 @@ describe Scheduler::AccountsStatusesCleanupScheduler do
it 'correctly handles looping in a single run' do
expect(subject.compute_budget).to eq(400)
expect { subject.perform }.to change { Status.count }.by(-30)
expect { subject.perform }.to change(Status, :count).by(-30)
end
end
@ -154,7 +154,7 @@ describe Scheduler::AccountsStatusesCleanupScheduler do
it 'does not get stuck' do
expect(subject.compute_budget).to eq(400)
expect { subject.perform }.to_not change { Status.count }
expect { subject.perform }.to_not change(Status, :count)
end
end
end

103
yarn.lock
View File

@ -1062,7 +1062,7 @@
dependencies:
regenerator-runtime "^0.12.0"
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.13.8", "@babel/runtime@^7.15.4", "@babel/runtime@^7.2.0", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.5", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.13.8", "@babel/runtime@^7.2.0", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.5", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
version "7.21.5"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.5.tgz#8492dddda9644ae3bda3b45eabe87382caee7200"
integrity sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==
@ -1216,10 +1216,10 @@
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==
"@es-joy/jsdoccomment@~0.39.3":
version "0.39.3"
resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.39.3.tgz#76b55203bf447d608e4e299ecb62d7ef14db72bb"
integrity sha512-q6pObzaS+aTA96kl4DF91QILNpSiDE8S89cQdJnhIc7hWzwIHPnfBnsiBVa0Z/R9pLHdZTnXEMnggGMmCq7HmA==
"@es-joy/jsdoccomment@~0.39.4":
version "0.39.4"
resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.39.4.tgz#6b8a62e9b3077027837728818d3c4389a898b392"
integrity sha512-Jvw915fjqQct445+yron7Dufix9A+m9j1fCJYlCo1FWlRvTxa3pjJelxdSTdaLWcTwRU6vbL+NYjO4YuNIS5Qg==
dependencies:
comment-parser "1.3.1"
esquery "^1.5.0"
@ -1252,10 +1252,10 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
"@eslint/js@8.40.0":
version "8.40.0"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.40.0.tgz#3ba73359e11f5a7bd3e407f70b3528abfae69cec"
integrity sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==
"@eslint/js@8.41.0":
version "8.41.0"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.41.0.tgz#080321c3b68253522f7646b55b577dd99d2950b3"
integrity sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==