From 11b8336418634c9311e3f4010ac8267df47addad Mon Sep 17 00:00:00 2001 From: Daniel M Brasil Date: Mon, 29 May 2023 06:43:19 -0300 Subject: [PATCH 01/22] Add test coverage for `Mastodon::CLI::Accounts#create` (#25143) --- spec/lib/mastodon/cli/accounts_spec.rb | 155 +++++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/spec/lib/mastodon/cli/accounts_spec.rb b/spec/lib/mastodon/cli/accounts_spec.rb index 25f1311d40..c214d93ecd 100644 --- a/spec/lib/mastodon/cli/accounts_spec.rb +++ b/spec/lib/mastodon/cli/accounts_spec.rb @@ -4,9 +4,164 @@ require 'rails_helper' require 'mastodon/cli/accounts' describe Mastodon::CLI::Accounts 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 '#create' do + shared_examples 'a new user with given email address and username' do + it 'creates a new user with the specified email address' do + cli.invoke(:create, arguments, options) + + expect(User.find_by(email: options[:email])).to be_present + end + + it 'creates a new local account with the specified username' do + cli.invoke(:create, arguments, options) + + expect(Account.find_local('tootctl_username')).to be_present + end + + it 'returns "OK" and newly generated password' do + allow(SecureRandom).to receive(:hex).and_return('test_password') + + expect { cli.invoke(:create, arguments, options) }.to output( + a_string_including("OK\nNew password: test_password") + ).to_stdout + end + end + + context 'when required USERNAME and --email are provided' do + let(:arguments) { ['tootctl_username'] } + + context 'with USERNAME and --email only' do + let(:options) { { email: 'tootctl@example.com' } } + + it_behaves_like 'a new user with given email address and username' + + context 'with invalid --email value' do + let(:options) { { email: 'invalid' } } + + it 'exits with an error message' do + expect { cli.invoke(:create, arguments, options) }.to output( + a_string_including('Failure/Error: email') + ).to_stdout + .and raise_error(SystemExit) + end + end + end + + context 'with --confirmed option' do + let(:options) { { email: 'tootctl@example.com', confirmed: true } } + + it_behaves_like 'a new user with given email address and username' + + it 'creates a new user with confirmed status' do + cli.invoke(:create, arguments, options) + + user = User.find_by(email: options[:email]) + + expect(user.confirmed?).to be(true) + end + end + + context 'with --approve option' do + let(:options) { { email: 'tootctl@example.com', approve: true } } + + before do + Form::AdminSettings.new(registrations_mode: 'approved').save + end + + it_behaves_like 'a new user with given email address and username' + + it 'creates a new user with approved status' do + cli.invoke(:create, arguments, options) + + user = User.find_by(email: options[:email]) + + expect(user.approved?).to be(true) + end + end + + context 'with --role option' do + context 'when role exists' do + let(:default_role) { Fabricate(:user_role) } + let(:options) { { email: 'tootctl@example.com', role: default_role.name } } + + it_behaves_like 'a new user with given email address and username' + + it 'creates a new user and assigns the specified role' do + cli.invoke(:create, arguments, options) + + role = User.find_by(email: options[:email])&.role + + expect(role.name).to eq(default_role.name) + end + end + + context 'when role does not exist' do + let(:options) { { email: 'tootctl@example.com', role: '404' } } + + it 'exits with an error message indicating the role name was not found' do + expect { cli.invoke(:create, arguments, options) }.to output( + a_string_including('Cannot find user role with that name') + ).to_stdout + .and raise_error(SystemExit) + end + end + end + + context 'with --reattach option' do + context "when account's user is present" do + let(:options) { { email: 'tootctl_new@example.com', reattach: true } } + let(:user) { Fabricate.build(:user, email: 'tootctl@example.com') } + + before do + Fabricate(:account, username: 'tootctl_username', user: user) + end + + it 'returns an error message indicating the username is already taken' do + expect { cli.invoke(:create, arguments, options) }.to output( + a_string_including("The chosen username is currently in use\nUse --force to reattach it anyway and delete the other user") + ).to_stdout + end + + context 'with --force option' do + let(:options) { { email: 'tootctl_new@example.com', reattach: true, force: true } } + + it 'reattaches the account to the new user and deletes the previous user' do + cli.invoke(:create, arguments, options) + + user = Account.find_local('tootctl_username')&.user + + expect(user.email).to eq(options[:email]) + end + end + end + + context "when account's user is not present" do + let(:options) { { email: 'tootctl@example.com', reattach: true } } + + before do + Fabricate(:account, username: 'tootctl_username', user: nil) + end + + it_behaves_like 'a new user with given email address and username' + end + end + end + + context 'when required --email option is not provided' do + let(:arguments) { ['tootctl_username'] } + + it 'raises a required argument missing error (Thor::RequiredArgumentMissingError)' do + expect { cli.invoke(:create, arguments) } + .to raise_error(Thor::RequiredArgumentMissingError) + end + end + end end From 64b960b6b33086a20b3db8f442c7f2fd2f9b855b Mon Sep 17 00:00:00 2001 From: "y.takahashi" Date: Mon, 29 May 2023 18:55:16 +0900 Subject: [PATCH 02/22] Handle Surrogate Pairs in truncate() (#25148) --- app/javascript/mastodon/features/status/index.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/javascript/mastodon/features/status/index.jsx b/app/javascript/mastodon/features/status/index.jsx index 0ed94d34c0..195c6b5238 100644 --- a/app/javascript/mastodon/features/status/index.jsx +++ b/app/javascript/mastodon/features/status/index.jsx @@ -166,8 +166,9 @@ const makeMapStateToProps = () => { }; const truncate = (str, num) => { - if (str.length > num) { - return str.slice(0, num) + '…'; + const arr = Array.from(str); + if (arr.length > num) { + return arr.slice(0, num).join('') + '…'; } else { return str; } From bdc754865252c9ca9f9cbe847665e656cb6b8816 Mon Sep 17 00:00:00 2001 From: Daniel M Brasil Date: Mon, 29 May 2023 10:31:59 -0300 Subject: [PATCH 03/22] Add test coverage for `Mastodon::CLI::Accounts#modify` (#25145) --- spec/lib/mastodon/cli/accounts_spec.rb | 181 +++++++++++++++++++++++++ 1 file changed, 181 insertions(+) diff --git a/spec/lib/mastodon/cli/accounts_spec.rb b/spec/lib/mastodon/cli/accounts_spec.rb index c214d93ecd..fe2b4ec351 100644 --- a/spec/lib/mastodon/cli/accounts_spec.rb +++ b/spec/lib/mastodon/cli/accounts_spec.rb @@ -164,4 +164,185 @@ describe Mastodon::CLI::Accounts do end end end + + describe '#modify' do + context 'when the given username is not found' do + let(:arguments) { ['non_existent_username'] } + + it 'exits with an error message indicating the user was not found' do + expect { cli.invoke(:modify, arguments) }.to output( + a_string_including('No user with such username') + ).to_stdout + .and raise_error(SystemExit) + end + end + + context 'when the given username is found' do + let(:user) { Fabricate(:user) } + let(:arguments) { [user.account.username] } + + context 'when no option is provided' do + it 'returns a successful message' do + expect { cli.invoke(:modify, arguments) }.to output( + a_string_including('OK') + ).to_stdout + end + + it 'does not modify the user' do + cli.invoke(:modify, arguments) + + expect(user).to eq(user.reload) + end + end + + context 'with --role option' do + context 'when the given role is not found' do + let(:options) { { role: '404' } } + + it 'exits with an error message indicating the role was not found' do + expect { cli.invoke(:modify, arguments, options) }.to output( + a_string_including('Cannot find user role with that name') + ).to_stdout + .and raise_error(SystemExit) + end + end + + context 'when the given role is found' do + let(:default_role) { Fabricate(:user_role) } + let(:options) { { role: default_role.name } } + + it "updates the user's role to the specified role" do + cli.invoke(:modify, arguments, options) + + role = user.reload.role + + expect(role.name).to eq(default_role.name) + end + end + end + + context 'with --remove-role option' do + let(:options) { { remove_role: true } } + let(:role) { Fabricate(:user_role) } + let(:user) { Fabricate(:user, role: role) } + + it "removes the user's role successfully" do + cli.invoke(:modify, arguments, options) + + role = user.reload.role + + expect(role.name).to be_empty + end + end + + context 'with --email option' do + let(:user) { Fabricate(:user, email: 'old_email@email.com') } + let(:options) { { email: 'new_email@email.com' } } + + it "sets the user's unconfirmed email to the provided email address" do + cli.invoke(:modify, arguments, options) + + expect(user.reload.unconfirmed_email).to eq(options[:email]) + end + + it "does not update the user's original email address" do + cli.invoke(:modify, arguments, options) + + expect(user.reload.email).to eq('old_email@email.com') + end + + context 'with --confirm option' do + let(:user) { Fabricate(:user, email: 'old_email@email.com', confirmed_at: nil) } + let(:options) { { email: 'new_email@email.com', confirm: true } } + + it "updates the user's email address to the provided email" do + cli.invoke(:modify, arguments, options) + + expect(user.reload.email).to eq(options[:email]) + end + + it "sets the user's email address as confirmed" do + cli.invoke(:modify, arguments, options) + + expect(user.reload.confirmed?).to be(true) + end + end + end + + context 'with --confirm option' do + let(:user) { Fabricate(:user, confirmed_at: nil) } + let(:options) { { confirm: true } } + + it "confirms the user's email address" do + cli.invoke(:modify, arguments, options) + + expect(user.reload.confirmed?).to be(true) + end + end + + context 'with --approve option' do + let(:user) { Fabricate(:user, approved: false) } + let(:options) { { approve: true } } + + before do + Form::AdminSettings.new(registrations_mode: 'approved').save + end + + it 'approves the user' do + expect { cli.invoke(:modify, arguments, options) }.to change { user.reload.approved }.from(false).to(true) + end + end + + context 'with --disable option' do + let(:user) { Fabricate(:user, disabled: false) } + let(:options) { { disable: true } } + + it 'disables the user' do + expect { cli.invoke(:modify, arguments, options) }.to change { user.reload.disabled }.from(false).to(true) + end + end + + context 'with --enable option' do + let(:user) { Fabricate(:user, disabled: true) } + let(:options) { { enable: true } } + + it 'enables the user' do + expect { cli.invoke(:modify, arguments, options) }.to change { user.reload.disabled }.from(true).to(false) + end + end + + context 'with --reset-password option' do + let(:options) { { reset_password: true } } + + it 'returns a new password for the user' do + allow(SecureRandom).to receive(:hex).and_return('new_password') + + expect { cli.invoke(:modify, arguments, options) }.to output( + a_string_including('new_password') + ).to_stdout + end + end + + context 'with --disable-2fa option' do + let(:user) { Fabricate(:user, otp_required_for_login: true) } + let(:options) { { disable_2fa: true } } + + it 'disables the two-factor authentication for the user' do + expect { cli.invoke(:modify, arguments, options) }.to change { user.reload.otp_required_for_login }.from(true).to(false) + end + end + + context 'when provided data is invalid' do + let(:user) { Fabricate(:user) } + let(:options) { { email: 'invalid' } } + + it 'exits with an error message' do + expect { cli.invoke(:modify, arguments, options) }.to output( + a_string_including('Failure/Error: email') + ).to_stdout + .and raise_error(SystemExit) + end + end + end + end end From 8c183a98310fa74d89573d3920931d9f88cb7e6e Mon Sep 17 00:00:00 2001 From: "S.H" Date: Tue, 30 May 2023 16:28:01 +0900 Subject: [PATCH 04/22] Align argument type to keyword argument for private process method in FetchResourceService (#25189) --- app/services/fetch_resource_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/fetch_resource_service.rb b/app/services/fetch_resource_service.rb index a2000e5967..a3406e5a57 100644 --- a/app/services/fetch_resource_service.rb +++ b/app/services/fetch_resource_service.rb @@ -19,7 +19,7 @@ class FetchResourceService < BaseService private - def process(url, terminal = false) + def process(url, terminal: false) @url = url perform_request { |response| process_response(response, terminal) } From 37dc48c3a1ce7b320de02d63f88f3b36acb91fb1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 May 2023 09:28:39 +0200 Subject: [PATCH 05/22] Bump postcss from 8.4.23 to 8.4.24 (#25169) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 13720c56b4..e76f37583a 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "path-complete-extname": "^1.0.0", "pg": "^8.5.0", "pg-connection-string": "^2.6.0", - "postcss": "^8.4.23", + "postcss": "^8.4.24", "postcss-loader": "^4.3.0", "prop-types": "^15.8.1", "punycode": "^2.3.0", diff --git a/yarn.lock b/yarn.lock index ae89f81d37..d35149cb41 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9241,10 +9241,10 @@ postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8.2.15, postcss@^8.4.23: - version "8.4.23" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.23.tgz#df0aee9ac7c5e53e1075c24a3613496f9e6552ab" - integrity sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA== +postcss@^8.2.15, postcss@^8.4.23, postcss@^8.4.24: + version "8.4.24" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.24.tgz#f714dba9b2284be3cc07dbd2fc57ee4dc972d2df" + integrity sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg== dependencies: nanoid "^3.3.6" picocolors "^1.0.0" From b91aeeb94f91e95f40f19de1ea5a7388506ba29a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 May 2023 09:29:40 +0200 Subject: [PATCH 06/22] Bump sidekiq from 6.5.8 to 6.5.9 (#25176) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 85cc20e633..58368e72ac 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -642,7 +642,7 @@ GEM activerecord (>= 4.0.0) railties (>= 4.0.0) semantic_range (3.0.0) - sidekiq (6.5.8) + sidekiq (6.5.9) connection_pool (>= 2.2.5, < 3) rack (~> 2.0) redis (>= 4.5.0, < 5) From 8ff2d61adde4ab444676e2fb51689ad70e2af37f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 May 2023 09:33:21 +0200 Subject: [PATCH 07/22] Bump @types/lodash from 4.14.194 to 4.14.195 (#25184) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e76f37583a..d7dcc29962 100644 --- a/package.json +++ b/package.json @@ -149,7 +149,7 @@ "@types/intl": "^1.2.0", "@types/jest": "^29.5.1", "@types/js-yaml": "^4.0.5", - "@types/lodash": "^4.14.194", + "@types/lodash": "^4.14.195", "@types/npmlog": "^4.1.4", "@types/object-assign": "^4.0.30", "@types/pg": "^8.6.6", diff --git a/yarn.lock b/yarn.lock index d35149cb41..8bb3a98c1c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2087,10 +2087,10 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= -"@types/lodash@^4.14.194": - version "4.14.194" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.194.tgz#b71eb6f7a0ff11bff59fc987134a093029258a76" - integrity sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g== +"@types/lodash@^4.14.195": + version "4.14.195" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.195.tgz#bafc975b252eb6cea78882ce8a7b6bf22a6de632" + integrity sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg== "@types/mime@*": version "3.0.1" From 6d41cdcc6a897fb4114d18183b6c5853441a93c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 May 2023 09:34:59 +0200 Subject: [PATCH 08/22] Bump @typescript-eslint/eslint-plugin from 5.59.7 to 5.59.8 (#25182) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 74 ++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 55 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index d7dcc29962..2d06aecc6b 100644 --- a/package.json +++ b/package.json @@ -174,7 +174,7 @@ "@types/uuid": "^9.0.0", "@types/webpack": "^4.41.33", "@types/yargs": "^17.0.24", - "@typescript-eslint/eslint-plugin": "^5.59.7", + "@typescript-eslint/eslint-plugin": "^5.59.8", "@typescript-eslint/parser": "^5.59.7", "babel-jest": "^29.5.0", "eslint": "^8.41.0", diff --git a/yarn.lock b/yarn.lock index 8bb3a98c1c..887ba0021f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2434,15 +2434,15 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^5.59.7": - version "5.59.7" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.7.tgz#e470af414f05ecfdc05a23e9ce6ec8f91db56fe2" - integrity sha512-BL+jYxUFIbuYwy+4fF86k5vdT9lT0CNJ6HtwrIvGh0PhH8s0yy5rjaKH2fDCrz5ITHy07WCzVGNvAmjJh4IJFA== +"@typescript-eslint/eslint-plugin@^5.59.8": + version "5.59.8" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.8.tgz#1e7a3e5318ece22251dfbc5c9c6feeb4793cc509" + integrity sha512-JDMOmhXteJ4WVKOiHXGCoB96ADWg9q7efPWHRViT/f09bA8XOMLAVHHju3l0MkZnG1izaWXYmgvQcUjTRcpShQ== dependencies: "@eslint-community/regexpp" "^4.4.0" - "@typescript-eslint/scope-manager" "5.59.7" - "@typescript-eslint/type-utils" "5.59.7" - "@typescript-eslint/utils" "5.59.7" + "@typescript-eslint/scope-manager" "5.59.8" + "@typescript-eslint/type-utils" "5.59.8" + "@typescript-eslint/utils" "5.59.8" debug "^4.3.4" grapheme-splitter "^1.0.4" ignore "^5.2.0" @@ -2468,13 +2468,21 @@ "@typescript-eslint/types" "5.59.7" "@typescript-eslint/visitor-keys" "5.59.7" -"@typescript-eslint/type-utils@5.59.7": - version "5.59.7" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.7.tgz#89c97291371b59eb18a68039857c829776f1426d" - integrity sha512-ozuz/GILuYG7osdY5O5yg0QxXUAEoI4Go3Do5xeu+ERH9PorHBPSdvD3Tjp2NN2bNLh1NJQSsQu2TPu/Ly+HaQ== +"@typescript-eslint/scope-manager@5.59.8": + version "5.59.8" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.8.tgz#ff4ad4fec6433647b817c4a7d4b4165d18ea2fa8" + integrity sha512-/w08ndCYI8gxGf+9zKf1vtx/16y8MHrZs5/tnjHhMLNSixuNcJavSX4wAiPf4aS5x41Es9YPCn44MIe4cxIlig== dependencies: - "@typescript-eslint/typescript-estree" "5.59.7" - "@typescript-eslint/utils" "5.59.7" + "@typescript-eslint/types" "5.59.8" + "@typescript-eslint/visitor-keys" "5.59.8" + +"@typescript-eslint/type-utils@5.59.8": + version "5.59.8" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.8.tgz#aa6c029a9d7706d26bbd25eb4666398781df6ea2" + integrity sha512-+5M518uEIHFBy3FnyqZUF3BMP+AXnYn4oyH8RF012+e7/msMY98FhGL5SrN29NQ9xDgvqCgYnsOiKp1VjZ/fpA== + dependencies: + "@typescript-eslint/typescript-estree" "5.59.8" + "@typescript-eslint/utils" "5.59.8" debug "^4.3.4" tsutils "^3.21.0" @@ -2488,6 +2496,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.7.tgz#6f4857203fceee91d0034ccc30512d2939000742" integrity sha512-UnVS2MRRg6p7xOSATscWkKjlf/NDKuqo5TdbWck6rIRZbmKpVNTLALzNvcjIfHBE7736kZOFc/4Z3VcZwuOM/A== +"@typescript-eslint/types@5.59.8": + version "5.59.8" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.8.tgz#212e54414733618f5d0fd50b2da2717f630aebf8" + integrity sha512-+uWuOhBTj/L6awoWIg0BlWy0u9TyFpCHrAuQ5bNfxDaZ1Ppb3mx6tUigc74LHcbHpOHuOTOJrBoAnhdHdaea1w== + "@typescript-eslint/typescript-estree@5.59.0": version "5.59.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.0.tgz#8869156ee1dcfc5a95be3ed0e2809969ea28e965" @@ -2514,17 +2527,30 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@5.59.7": - version "5.59.7" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.7.tgz#7adf068b136deae54abd9a66ba5a8780d2d0f898" - integrity sha512-yCX9WpdQKaLufz5luG4aJbOpdXf/fjwGMcLFXZVPUz3QqLirG5QcwwnIHNf8cjLjxK4qtzTO8udUtMQSAToQnQ== +"@typescript-eslint/typescript-estree@5.59.8": + version "5.59.8" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.8.tgz#801a7b1766481629481b3b0878148bd7a1f345d7" + integrity sha512-Jy/lPSDJGNow14vYu6IrW790p7HIf/SOV1Bb6lZ7NUkLc2iB2Z9elESmsaUtLw8kVqogSbtLH9tut5GCX1RLDg== + dependencies: + "@typescript-eslint/types" "5.59.8" + "@typescript-eslint/visitor-keys" "5.59.8" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.59.8": + version "5.59.8" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.8.tgz#34d129f35a2134c67fdaf024941e8f96050dca2b" + integrity sha512-Tr65630KysnNn9f9G7ROF3w1b5/7f6QVCJ+WK9nhIocWmx9F+TmCAcglF26Vm7z8KCTwoKcNEBZrhlklla3CKg== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@types/json-schema" "^7.0.9" "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.59.7" - "@typescript-eslint/types" "5.59.7" - "@typescript-eslint/typescript-estree" "5.59.7" + "@typescript-eslint/scope-manager" "5.59.8" + "@typescript-eslint/types" "5.59.8" + "@typescript-eslint/typescript-estree" "5.59.8" eslint-scope "^5.1.1" semver "^7.3.7" @@ -2544,6 +2570,14 @@ "@typescript-eslint/types" "5.59.7" eslint-visitor-keys "^3.3.0" +"@typescript-eslint/visitor-keys@5.59.8": + version "5.59.8" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.8.tgz#aa6a7ef862add919401470c09e1609392ef3cc40" + integrity sha512-pJhi2ms0x0xgloT7xYabil3SGGlojNNKjK/q6dB3Ey0uJLMjK2UDGJvHieiyJVW/7C3KI+Z4Q3pEHkm4ejA+xQ== + dependencies: + "@typescript-eslint/types" "5.59.8" + eslint-visitor-keys "^3.3.0" + "@webassemblyjs/ast@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" From 5f1a03fdba79ed4b1d7000317e3f944649530cb4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 May 2023 09:38:42 +0200 Subject: [PATCH 09/22] Bump @typescript-eslint/parser from 5.59.7 to 5.59.8 (#25175) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 48 +++++++----------------------------------------- 2 files changed, 8 insertions(+), 42 deletions(-) diff --git a/package.json b/package.json index 2d06aecc6b..9a567fe0ae 100644 --- a/package.json +++ b/package.json @@ -175,7 +175,7 @@ "@types/webpack": "^4.41.33", "@types/yargs": "^17.0.24", "@typescript-eslint/eslint-plugin": "^5.59.8", - "@typescript-eslint/parser": "^5.59.7", + "@typescript-eslint/parser": "^5.59.8", "babel-jest": "^29.5.0", "eslint": "^8.41.0", "eslint-config-prettier": "^8.8.0", diff --git a/yarn.lock b/yarn.lock index 887ba0021f..de75c87402 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2450,24 +2450,16 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.59.7": - version "5.59.7" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.7.tgz#02682554d7c1028b89aa44a48bf598db33048caa" - integrity sha512-VhpsIEuq/8i5SF+mPg9jSdIwgMBBp0z9XqjiEay+81PYLJuroN+ET1hM5IhkiYMJd9MkTz8iJLt7aaGAgzWUbQ== +"@typescript-eslint/parser@^5.59.8": + version "5.59.8" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.8.tgz#60cbb00671d86cf746044ab797900b1448188567" + integrity sha512-AnR19RjJcpjoeGojmwZtCwBX/RidqDZtzcbG3xHrmz0aHHoOcbWnpDllenRDmDvsV0RQ6+tbb09/kyc+UT9Orw== dependencies: - "@typescript-eslint/scope-manager" "5.59.7" - "@typescript-eslint/types" "5.59.7" - "@typescript-eslint/typescript-estree" "5.59.7" + "@typescript-eslint/scope-manager" "5.59.8" + "@typescript-eslint/types" "5.59.8" + "@typescript-eslint/typescript-estree" "5.59.8" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.59.7": - version "5.59.7" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.7.tgz#0243f41f9066f3339d2f06d7f72d6c16a16769e2" - integrity sha512-FL6hkYWK9zBGdxT2wWEd2W8ocXMu3K94i3gvMrjXpx+koFYdYV7KprKfirpgY34vTGzEPPuKoERpP8kD5h7vZQ== - dependencies: - "@typescript-eslint/types" "5.59.7" - "@typescript-eslint/visitor-keys" "5.59.7" - "@typescript-eslint/scope-manager@5.59.8": version "5.59.8" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.8.tgz#ff4ad4fec6433647b817c4a7d4b4165d18ea2fa8" @@ -2491,11 +2483,6 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.0.tgz#3fcdac7dbf923ec5251545acdd9f1d42d7c4fe32" integrity sha512-yR2h1NotF23xFFYKHZs17QJnB51J/s+ud4PYU4MqdZbzeNxpgUr05+dNeCN/bb6raslHvGdd6BFCkVhpPk/ZeA== -"@typescript-eslint/types@5.59.7": - version "5.59.7" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.7.tgz#6f4857203fceee91d0034ccc30512d2939000742" - integrity sha512-UnVS2MRRg6p7xOSATscWkKjlf/NDKuqo5TdbWck6rIRZbmKpVNTLALzNvcjIfHBE7736kZOFc/4Z3VcZwuOM/A== - "@typescript-eslint/types@5.59.8": version "5.59.8" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.8.tgz#212e54414733618f5d0fd50b2da2717f630aebf8" @@ -2514,19 +2501,6 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.59.7": - version "5.59.7" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.7.tgz#b887acbd4b58e654829c94860dbff4ac55c5cff8" - integrity sha512-4A1NtZ1I3wMN2UGDkU9HMBL+TIQfbrh4uS0WDMMpf3xMRursDbqEf1ahh6vAAe3mObt8k3ZATnezwG4pdtWuUQ== - dependencies: - "@typescript-eslint/types" "5.59.7" - "@typescript-eslint/visitor-keys" "5.59.7" - debug "^4.3.4" - globby "^11.1.0" - is-glob "^4.0.3" - semver "^7.3.7" - tsutils "^3.21.0" - "@typescript-eslint/typescript-estree@5.59.8": version "5.59.8" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.8.tgz#801a7b1766481629481b3b0878148bd7a1f345d7" @@ -2562,14 +2536,6 @@ "@typescript-eslint/types" "5.59.0" eslint-visitor-keys "^3.3.0" -"@typescript-eslint/visitor-keys@5.59.7": - version "5.59.7" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.7.tgz#09c36eaf268086b4fbb5eb9dc5199391b6485fc5" - integrity sha512-tyN+X2jvMslUszIiYbF0ZleP+RqQsFVpGrKI6e0Eet1w8WmhsAtmzaqm8oM8WJQ1ysLwhnsK/4hYHJjOgJVfQQ== - dependencies: - "@typescript-eslint/types" "5.59.7" - eslint-visitor-keys "^3.3.0" - "@typescript-eslint/visitor-keys@5.59.8": version "5.59.8" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.8.tgz#aa6a7ef862add919401470c09e1609392ef3cc40" From 66c1ad8be971c93262b53692a441a68d8b440ced Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 May 2023 09:40:22 +0200 Subject: [PATCH 10/22] Bump @types/react-motion from 0.0.33 to 0.0.34 (#25185) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 9a567fe0ae..cd5a829b3b 100644 --- a/package.json +++ b/package.json @@ -160,7 +160,7 @@ "@types/react-helmet": "^6.1.6", "@types/react-immutable-proptypes": "^2.1.0", "@types/react-intl": "2.3.18", - "@types/react-motion": "^0.0.33", + "@types/react-motion": "^0.0.34", "@types/react-overlays": "^3.1.0", "@types/react-router-dom": "^5.3.3", "@types/react-select": "^5.0.1", diff --git a/yarn.lock b/yarn.lock index de75c87402..1059f06766 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2208,10 +2208,10 @@ resolved "https://registry.yarnpkg.com/@types/react-intl/-/react-intl-2.3.18.tgz#fd2d8b7f4d0a1dd05b5f1784ab0d7fe1786a690d" integrity sha512-DVNJs49zUxKRZng8VuILE886Yihdsf3yLr5vHk9zJrmF8SyRSK3sxNSvikAKxNkv9hX55XBTJShz6CkJnbNjgg== -"@types/react-motion@^0.0.33": - version "0.0.33" - resolved "https://registry.yarnpkg.com/@types/react-motion/-/react-motion-0.0.33.tgz#c156c400ace995584990344cc0239e41f411f425" - integrity sha512-R9grd4EwdDBcKKq7Zhszd8ukyy2BLKN6ooNI0V39nUl/sui+m7VI94cdebYemBteoPHmO7J7BZk+cIf+Xnk4TA== +"@types/react-motion@^0.0.34": + version "0.0.34" + resolved "https://registry.yarnpkg.com/@types/react-motion/-/react-motion-0.0.34.tgz#789ff2063e2f7fbb6085d291135c442e8b35291a" + integrity sha512-/rFI22Vg4Xzb47hXtS06WkzUGRu+Vb3yDleuxiqzGj0JbXYXQUCgwSa2ZU12K7ubKi4C8xsdIN3xt4Z4fjSdPw== dependencies: "@types/react" "*" From 05c2d4dab273a6fb05fd2d988da28e34c39b2819 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 May 2023 09:42:41 +0200 Subject: [PATCH 11/22] Bump nokogiri from 1.14.3 to 1.15.2 (#25177) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 6a444acd25..400afef4af 100644 --- a/Gemfile +++ b/Gemfile @@ -59,7 +59,7 @@ gem 'idn-ruby', require: 'idn' gem 'kaminari', '~> 1.2' gem 'link_header', '~> 0.0' gem 'mime-types', '~> 3.4.1', require: 'mime/types/columnar' -gem 'nokogiri', '~> 1.14' +gem 'nokogiri', '~> 1.15' gem 'nsa', '~> 0.2' gem 'oj', '~> 3.14' gem 'ox', '~> 2.14' diff --git a/Gemfile.lock b/Gemfile.lock index 58368e72ac..36f7d72012 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -439,8 +439,8 @@ GEM net-protocol net-ssh (7.1.0) nio4r (2.5.9) - nokogiri (1.14.3) - mini_portile2 (~> 2.8.0) + nokogiri (1.15.2) + mini_portile2 (~> 2.8.2) racc (~> 1.4) nsa (0.2.8) activesupport (>= 4.2, < 7) @@ -829,7 +829,7 @@ DEPENDENCIES mime-types (~> 3.4.1) net-http (~> 0.3.2) net-ldap (~> 0.18) - nokogiri (~> 1.14) + nokogiri (~> 1.15) nsa (~> 0.2) oj (~> 3.14) omniauth (~> 1.9) From 4869384fa0c5b9b106ef373d8294f7b114019736 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 May 2023 09:43:20 +0200 Subject: [PATCH 12/22] Bump jsdom from 22.0.0 to 22.1.0 (#25178) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index cd5a829b3b..9893d56ef3 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "intl-messageformat": "^2.2.0", "intl-relativeformat": "^6.4.3", "js-yaml": "^4.1.0", - "jsdom": "^22.0.0", + "jsdom": "^22.1.0", "lodash": "^4.17.21", "mark-loader": "^0.1.6", "marky": "^1.2.5", diff --git a/yarn.lock b/yarn.lock index 1059f06766..8f8f0a51bf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7460,10 +7460,10 @@ jsdom@^20.0.0: ws "^8.11.0" xml-name-validator "^4.0.0" -jsdom@^22.0.0: - version "22.0.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-22.0.0.tgz#3295c6992c70089c4b8f5cf060489fddf7ee9816" - integrity sha512-p5ZTEb5h+O+iU02t0GfEjAnkdYPrQSkfuTSMkMYyIoMvUNEHsbG0bHHbfXIcfTqD2UfvjQX7mmgiFsyRwGscVw== +jsdom@^22.1.0: + version "22.1.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-22.1.0.tgz#0fca6d1a37fbeb7f4aac93d1090d782c56b611c8" + integrity sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw== dependencies: abab "^2.0.6" cssstyle "^3.0.0" From 44eaa979d493e5903b28f93228a931379dd8f9bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 May 2023 09:58:55 +0200 Subject: [PATCH 13/22] Bump @types/react from 18.2.6 to 18.2.7 (#25166) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 15 +++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 9893d56ef3..f9b78b42b2 100644 --- a/package.json +++ b/package.json @@ -155,7 +155,7 @@ "@types/pg": "^8.6.6", "@types/prop-types": "^15.7.5", "@types/punycode": "^2.1.0", - "@types/react": "^18.0.26", + "@types/react": "^18.2.7", "@types/react-dom": "^18.2.4", "@types/react-helmet": "^6.1.6", "@types/react-immutable-proptypes": "^2.1.0", diff --git a/yarn.lock b/yarn.lock index 8f8f0a51bf..b2c4ced872 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2156,12 +2156,7 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.2.3.tgz#ef65165aea2924c9359205bf748865b8881753c0" integrity sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA== -"@types/prop-types@*": - version "15.7.3" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" - integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== - -"@types/prop-types@^15.7.5": +"@types/prop-types@*", "@types/prop-types@^15.7.5": version "15.7.5" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== @@ -2288,10 +2283,10 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@>=16.9.11", "@types/react@^18.0.26": - version "18.2.6" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.6.tgz#5cd53ee0d30ffc193b159d3516c8c8ad2f19d571" - integrity sha512-wRZClXn//zxCFW+ye/D2qY65UsYP1Fpex2YXorHc8awoNamkMZSvBxwxdYVInsHOZZd2Ppq8isnSzJL5Mpf8OA== +"@types/react@*", "@types/react@>=16.9.11", "@types/react@^18.0.26", "@types/react@^18.2.7": + version "18.2.7" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.7.tgz#dfb4518042a3117a045b8c222316f83414a783b3" + integrity sha512-ojrXpSH2XFCmHm7Jy3q44nXDyN54+EYKP2lBhJ2bqfyPj6cIUW/FZW/Csdia34NQgq7KYcAlHi5184m4X88+yw== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" From bbbcdc083fdbe43a07e76266717062bf56118f33 Mon Sep 17 00:00:00 2001 From: Daniel M Brasil Date: Tue, 30 May 2023 06:59:17 -0300 Subject: [PATCH 14/22] Add test coverage for `Mastodon::CLI::Accounts#delete` (#25146) --- spec/lib/mastodon/cli/accounts_spec.rb | 100 +++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/spec/lib/mastodon/cli/accounts_spec.rb b/spec/lib/mastodon/cli/accounts_spec.rb index fe2b4ec351..281b9fb351 100644 --- a/spec/lib/mastodon/cli/accounts_spec.rb +++ b/spec/lib/mastodon/cli/accounts_spec.rb @@ -345,4 +345,104 @@ describe Mastodon::CLI::Accounts do end end end + + describe '#delete' do + let(:account) { Fabricate(:account) } + let(:arguments) { [account.username] } + let(:options) { { email: account.user.email } } + let(:delete_account_service) { instance_double(DeleteAccountService) } + + before do + allow(DeleteAccountService).to receive(:new).and_return(delete_account_service) + allow(delete_account_service).to receive(:call) + end + + context 'when both username and --email are provided' do + it 'exits with an error message indicating that only one should be used' do + expect { cli.invoke(:delete, arguments, options) }.to output( + a_string_including('Use username or --email, not both') + ).to_stdout + .and raise_error(SystemExit) + end + end + + context 'when neither username nor --email are provided' do + it 'exits with an error message indicating that no username was provided' do + expect { cli.invoke(:delete) }.to output( + a_string_including('No username provided') + ).to_stdout + .and raise_error(SystemExit) + end + end + + context 'when username is provided' do + it 'deletes the specified user successfully' do + cli.invoke(:delete, arguments) + + expect(delete_account_service).to have_received(:call).with(account, reserve_email: false).once + end + + context 'with --dry-run option' do + let(:options) { { dry_run: true } } + + it 'does not delete the specified user' do + cli.invoke(:delete, arguments, options) + + expect(delete_account_service).to_not have_received(:call).with(account, reserve_email: false) + end + + it 'outputs a successful message in dry run mode' do + expect { cli.invoke(:delete, arguments, options) }.to output( + a_string_including('OK (DRY RUN)') + ).to_stdout + end + end + + context 'when the given username is not found' do + let(:arguments) { ['non_existent_username'] } + + it 'exits with an error message indicating that no user was found' do + expect { cli.invoke(:delete, arguments) }.to output( + a_string_including('No user with such username') + ).to_stdout + .and raise_error(SystemExit) + end + end + end + + context 'when --email is provided' do + it 'deletes the specified user successfully' do + cli.invoke(:delete, nil, options) + + expect(delete_account_service).to have_received(:call).with(account, reserve_email: false).once + end + + context 'with --dry-run option' do + let(:options) { { email: account.user.email, dry_run: true } } + + it 'does not delete the user' do + cli.invoke(:delete, nil, options) + + expect(delete_account_service).to_not have_received(:call).with(account, reserve_email: false) + end + + it 'outputs a successful message in dry run mode' do + expect { cli.invoke(:delete, nil, options) }.to output( + a_string_including('OK (DRY RUN)') + ).to_stdout + end + end + + context 'when the given email address is not found' do + let(:options) { { email: '404@example.com' } } + + it 'exits with an error message indicating that no user was found' do + expect { cli.invoke(:delete, nil, options) }.to output( + a_string_including('No user with such email') + ).to_stdout + .and raise_error(SystemExit) + end + end + end + end end From 3d253b9830db614faa19ef7da8ebf47a68c50dd2 Mon Sep 17 00:00:00 2001 From: Daniel M Brasil Date: Tue, 30 May 2023 10:00:21 -0300 Subject: [PATCH 15/22] Add test coverage for `Mastodon::CLI::Accounts#approve` (#25160) --- spec/lib/mastodon/cli/accounts_spec.rb | 87 ++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/spec/lib/mastodon/cli/accounts_spec.rb b/spec/lib/mastodon/cli/accounts_spec.rb index 281b9fb351..709400db31 100644 --- a/spec/lib/mastodon/cli/accounts_spec.rb +++ b/spec/lib/mastodon/cli/accounts_spec.rb @@ -445,4 +445,91 @@ describe Mastodon::CLI::Accounts do end end end + + describe '#approve' do + let(:total_users) { 10 } + + before do + Form::AdminSettings.new(registrations_mode: 'approved').save + Fabricate.times(total_users, :user) + end + + context 'with --all option' do + it 'approves all pending registrations' do + cli.invoke(:approve, nil, all: true) + + expect(User.pluck(:approved).all?(true)).to be(true) + end + end + + context 'with --number option' do + context 'when the number is positive' do + let(:options) { { number: 3 } } + + it 'approves the earliest n pending registrations' do + cli.invoke(:approve, nil, options) + + n_earliest_pending_registrations = User.order(created_at: :asc).first(options[:number]) + + expect(n_earliest_pending_registrations.all?(&:approved?)).to be(true) + end + + it 'does not approve the remaining pending registrations' do + cli.invoke(:approve, nil, options) + + pending_registrations = User.order(created_at: :asc).last(total_users - options[:number]) + + expect(pending_registrations.all?(&:approved?)).to be(false) + end + end + + context 'when the number is negative' do + it 'exits with an error message indicating that the number must be positive' do + expect { cli.invoke(:approve, nil, number: -1) }.to output( + a_string_including('Number must be positive') + ).to_stdout + .and raise_error(SystemExit) + end + end + + context 'when the given number is greater than the number of users' do + let(:options) { { number: total_users * 2 } } + + it 'approves all users' do + cli.invoke(:approve, nil, options) + + expect(User.pluck(:approved).all?(true)).to be(true) + end + + it 'does not raise any error' do + expect { cli.invoke(:approve, nil, options) } + .to_not raise_error + end + end + end + + context 'with username argument' do + context 'when the given username is found' do + let(:user) { User.last } + let(:arguments) { [user.account.username] } + + it 'approves the specified user successfully' do + cli.invoke(:approve, arguments) + + expect(user.reload.approved?).to be(true) + end + end + + context 'when the given username is not found' do + let(:arguments) { ['non_existent_username'] } + + it 'exits with an error message indicating that no such account was found' do + expect { cli.invoke(:approve, arguments) }.to output( + a_string_including('No such account') + ).to_stdout + .and raise_error(SystemExit) + end + end + end + end end From ec9bc7e6047686328df47c2af88d251a196b38b2 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 30 May 2023 10:07:44 -0400 Subject: [PATCH 16/22] Consistent usage of CLI `dry_run?` method (#25116) --- lib/mastodon/cli/accounts.rb | 30 ++++++++++++------------------ lib/mastodon/cli/domains.rb | 15 +++++++-------- lib/mastodon/cli/feeds.rb | 10 ++++------ lib/mastodon/cli/helper.rb | 4 ++++ lib/mastodon/cli/main.rb | 11 +++++------ lib/mastodon/cli/media.rb | 27 ++++++++++++--------------- lib/mastodon/cli/preview_cards.rb | 5 ++--- lib/mastodon/cli/upgrade.rb | 3 +-- 8 files changed, 47 insertions(+), 58 deletions(-) diff --git a/lib/mastodon/cli/accounts.rb b/lib/mastodon/cli/accounts.rb index 417f126ccd..fd8368565c 100644 --- a/lib/mastodon/cli/accounts.rb +++ b/lib/mastodon/cli/accounts.rb @@ -217,7 +217,6 @@ module Mastodon::CLI exit(1) end - dry_run = options[:dry_run] ? ' (DRY RUN)' : '' account = nil if username.present? @@ -234,9 +233,9 @@ module Mastodon::CLI end end - say("Deleting user with #{account.statuses_count} statuses, this might take a while...#{dry_run}") - DeleteAccountService.new.call(account, reserve_email: false) unless options[:dry_run] - say("OK#{dry_run}", :green) + say("Deleting user with #{account.statuses_count} statuses, this might take a while...#{dry_run_mode_suffix}") + DeleteAccountService.new.call(account, reserve_email: false) unless dry_run? + say("OK#{dry_run_mode_suffix}", :green) end option :force, type: :boolean, aliases: [:f], description: 'Override public key check' @@ -291,7 +290,7 @@ module Mastodon::CLI Account.remote.select(:uri, 'count(*)').group(:uri).having('count(*) > 1').pluck(:uri).each do |uri| say("Duplicates found for #{uri}") begin - ActivityPub::FetchRemoteAccountService.new.call(uri) unless options[:dry_run] + ActivityPub::FetchRemoteAccountService.new.call(uri) unless dry_run? rescue => e say("Error processing #{uri}: #{e}", :red) end @@ -332,7 +331,6 @@ module Mastodon::CLI LONG_DESC def cull(*domains) skip_threshold = 7.days.ago - dry_run = options[:dry_run] ? ' (DRY RUN)' : '' skip_domains = Concurrent::Set.new query = Account.remote.where(protocol: :activitypub) @@ -350,7 +348,7 @@ module Mastodon::CLI end if [404, 410].include?(code) - DeleteAccountService.new.call(account, reserve_username: false) unless options[:dry_run] + DeleteAccountService.new.call(account, reserve_username: false) unless dry_run? 1 else # Touch account even during dry run to avoid getting the account into the window again @@ -358,7 +356,7 @@ module Mastodon::CLI end end - say("Visited #{processed} accounts, removed #{culled}#{dry_run}", :green) + say("Visited #{processed} accounts, removed #{culled}#{dry_run_mode_suffix}", :green) unless skip_domains.empty? say('The following domains were not available during the check:', :yellow) @@ -381,21 +379,19 @@ module Mastodon::CLI specified with space-separated USERNAMES. LONG_DESC def refresh(*usernames) - dry_run = options[:dry_run] ? ' (DRY RUN)' : '' - if options[:domain] || options[:all] scope = Account.remote scope = scope.where(domain: options[:domain]) if options[:domain] processed, = parallelize_with_progress(scope) do |account| - next if options[:dry_run] + next if dry_run? account.reset_avatar! account.reset_header! account.save end - say("Refreshed #{processed} accounts#{dry_run}", :green, true) + say("Refreshed #{processed} accounts#{dry_run_mode_suffix}", :green, true) elsif !usernames.empty? usernames.each do |user| user, domain = user.split('@') @@ -406,7 +402,7 @@ module Mastodon::CLI exit(1) end - next if options[:dry_run] + next if dry_run? begin account.reset_avatar! @@ -417,7 +413,7 @@ module Mastodon::CLI end end - say("OK#{dry_run}", :green) + say("OK#{dry_run_mode_suffix}", :green) else say('No account(s) given', :red) exit(1) @@ -568,8 +564,6 @@ module Mastodon::CLI - not muted/blocked by us LONG_DESC def prune - dry_run = options[:dry_run] ? ' (dry run)' : '' - query = Account.remote.where.not(actor_type: %i(Application Service)) query = query.where('NOT EXISTS (SELECT 1 FROM mentions WHERE account_id = accounts.id)') query = query.where('NOT EXISTS (SELECT 1 FROM favourites WHERE account_id = accounts.id)') @@ -585,11 +579,11 @@ module Mastodon::CLI next if account.suspended? next if account.silenced? - account.destroy unless options[:dry_run] + account.destroy unless dry_run? 1 end - say("OK, pruned #{deleted} accounts#{dry_run}", :green) + say("OK, pruned #{deleted} accounts#{dry_run_mode_suffix}", :green) end option :force, type: :boolean diff --git a/lib/mastodon/cli/domains.rb b/lib/mastodon/cli/domains.rb index d885c95638..d17b253681 100644 --- a/lib/mastodon/cli/domains.rb +++ b/lib/mastodon/cli/domains.rb @@ -34,7 +34,6 @@ module Mastodon::CLI When the --purge-domain-blocks option is given, also purge matching domain blocks. LONG_DESC def purge(*domains) - dry_run = options[:dry_run] ? ' (DRY RUN)' : '' domains = domains.map { |domain| TagManager.instance.normalize_domain(domain) } account_scope = Account.none domain_block_scope = DomainBlock.none @@ -79,23 +78,23 @@ module Mastodon::CLI # Actually perform the deletions processed, = parallelize_with_progress(account_scope) do |account| - DeleteAccountService.new.call(account, reserve_username: false, skip_side_effects: true) unless options[:dry_run] + DeleteAccountService.new.call(account, reserve_username: false, skip_side_effects: true) unless dry_run? end - say("Removed #{processed} accounts#{dry_run}", :green) + say("Removed #{processed} accounts#{dry_run_mode_suffix}", :green) if options[:purge_domain_blocks] domain_block_count = domain_block_scope.count - domain_block_scope.in_batches.destroy_all unless options[:dry_run] - say("Removed #{domain_block_count} domain blocks#{dry_run}", :green) + domain_block_scope.in_batches.destroy_all unless dry_run? + say("Removed #{domain_block_count} domain blocks#{dry_run_mode_suffix}", :green) end custom_emojis_count = emoji_scope.count - emoji_scope.in_batches.destroy_all unless options[:dry_run] + emoji_scope.in_batches.destroy_all unless dry_run? - Instance.refresh unless options[:dry_run] + Instance.refresh unless dry_run? - say("Removed #{custom_emojis_count} custom emojis#{dry_run}", :green) + say("Removed #{custom_emojis_count} custom emojis#{dry_run_mode_suffix}", :green) end option :concurrency, type: :numeric, default: 50, aliases: [:c] diff --git a/lib/mastodon/cli/feeds.rb b/lib/mastodon/cli/feeds.rb index 342b550ca3..34617e7538 100644 --- a/lib/mastodon/cli/feeds.rb +++ b/lib/mastodon/cli/feeds.rb @@ -18,14 +18,12 @@ module Mastodon::CLI Otherwise, a single user specified by USERNAME. LONG_DESC def build(username = nil) - dry_run = options[:dry_run] ? '(DRY RUN)' : '' - if options[:all] || username.nil? processed, = parallelize_with_progress(Account.joins(:user).merge(User.active)) do |account| - PrecomputeFeedService.new.call(account) unless options[:dry_run] + PrecomputeFeedService.new.call(account) unless dry_run? end - say("Regenerated feeds for #{processed} accounts #{dry_run}", :green, true) + say("Regenerated feeds for #{processed} accounts #{dry_run_mode_suffix}", :green, true) elsif username.present? account = Account.find_local(username) @@ -34,9 +32,9 @@ module Mastodon::CLI exit(1) end - PrecomputeFeedService.new.call(account) unless options[:dry_run] + PrecomputeFeedService.new.call(account) unless dry_run? - say("OK #{dry_run}", :green, true) + say("OK #{dry_run_mode_suffix}", :green, true) else say('No account(s) given', :red) exit(1) diff --git a/lib/mastodon/cli/helper.rb b/lib/mastodon/cli/helper.rb index b277e16ebd..78931b9a22 100644 --- a/lib/mastodon/cli/helper.rb +++ b/lib/mastodon/cli/helper.rb @@ -15,6 +15,10 @@ module Mastodon::CLI options[:dry_run] end + def dry_run_mode_suffix + dry_run? ? ' (DRY RUN)' : '' + end + def create_progress_bar(total = nil) ProgressBar.create(total: total, format: '%c/%u |%b%i| %e') end diff --git a/lib/mastodon/cli/main.rb b/lib/mastodon/cli/main.rb index e61a6f9c46..1594eadce8 100644 --- a/lib/mastodon/cli/main.rb +++ b/lib/mastodon/cli/main.rb @@ -94,7 +94,7 @@ module Mastodon::CLI exit(1) unless prompt.ask('Type in the domain of the server to confirm:', required: true) == Rails.configuration.x.local_domain - unless options[:dry_run] + unless dry_run? prompt.warn('This operation WILL NOT be reversible. It can also take a long time.') prompt.warn('While the data won\'t be erased locally, the server will be in a BROKEN STATE afterwards.') prompt.warn('A running Sidekiq process is required. Do not shut it down until queues clear.') @@ -104,12 +104,11 @@ module Mastodon::CLI inboxes = Account.inboxes processed = 0 - dry_run = options[:dry_run] ? ' (DRY RUN)' : '' - Setting.registrations_mode = 'none' unless options[:dry_run] + Setting.registrations_mode = 'none' unless dry_run? if inboxes.empty? - Account.local.without_suspended.in_batches.update_all(suspended_at: Time.now.utc, suspension_origin: :local) unless options[:dry_run] + Account.local.without_suspended.in_batches.update_all(suspended_at: Time.now.utc, suspension_origin: :local) unless dry_run? prompt.ok('It seems like your server has not federated with anything') prompt.ok('You can shut it down and delete it any time') return @@ -126,7 +125,7 @@ module Mastodon::CLI json = Oj.dump(ActivityPub::LinkedDataSignature.new(payload).sign!(account)) - unless options[:dry_run] + unless dry_run? ActivityPub::DeliveryWorker.push_bulk(inboxes, limit: 1_000) do |inbox_url| [json, account.id, inbox_url] end @@ -140,7 +139,7 @@ module Mastodon::CLI Account.local.without_suspended.find_each { |account| delete_account.call(account) } Account.local.suspended.joins(:deletion_request).find_each { |account| delete_account.call(account) } - prompt.ok("Queued #{inboxes.size * processed} items into Sidekiq for #{processed} accounts#{dry_run}") + prompt.ok("Queued #{inboxes.size * processed} items into Sidekiq for #{processed} accounts#{dry_run_mode_suffix}") prompt.ok('Wait until Sidekiq processes all items, then you can shut everything down and delete the data') rescue TTY::Reader::InputInterrupt exit(1) diff --git a/lib/mastodon/cli/media.rb b/lib/mastodon/cli/media.rb index 045f6351ad..40b270ffb2 100644 --- a/lib/mastodon/cli/media.rb +++ b/lib/mastodon/cli/media.rb @@ -35,12 +35,12 @@ module Mastodon::CLI say('--prune-profiles and --remove-headers should not be specified simultaneously', :red, true) exit(1) end + if options[:include_follows] && !(options[:prune_profiles] || options[:remove_headers]) say('--include-follows can only be used with --prune-profiles or --remove-headers', :red, true) exit(1) end - time_ago = options[:days].days.ago - dry_run = options[:dry_run] ? ' (DRY RUN)' : '' + time_ago = options[:days].days.ago if options[:prune_profiles] || options[:remove_headers] processed, aggregate = parallelize_with_progress(Account.remote.where({ last_webfingered_at: ..time_ago, updated_at: ..time_ago })) do |account| @@ -51,7 +51,7 @@ module Mastodon::CLI size = (account.header_file_size || 0) size += (account.avatar_file_size || 0) if options[:prune_profiles] - unless options[:dry_run] + unless dry_run? account.header.destroy account.avatar.destroy if options[:prune_profiles] account.save! @@ -60,7 +60,7 @@ module Mastodon::CLI size end - say("Visited #{processed} accounts and removed profile media totaling #{number_to_human_size(aggregate)}#{dry_run}", :green, true) + say("Visited #{processed} accounts and removed profile media totaling #{number_to_human_size(aggregate)}#{dry_run_mode_suffix}", :green, true) end unless options[:prune_profiles] || options[:remove_headers] @@ -69,7 +69,7 @@ module Mastodon::CLI size = (media_attachment.file_file_size || 0) + (media_attachment.thumbnail_file_size || 0) - unless options[:dry_run] + unless dry_run? media_attachment.file.destroy media_attachment.thumbnail.destroy media_attachment.save @@ -78,7 +78,7 @@ module Mastodon::CLI size end - say("Removed #{processed} media attachments (approx. #{number_to_human_size(aggregate)})#{dry_run}", :green, true) + say("Removed #{processed} media attachments (approx. #{number_to_human_size(aggregate)})#{dry_run_mode_suffix}", :green, true) end end @@ -97,7 +97,6 @@ module Mastodon::CLI progress = create_progress_bar(nil) reclaimed_bytes = 0 removed = 0 - dry_run = options[:dry_run] ? ' (DRY RUN)' : '' prefix = options[:prefix] case Paperclip::Attachment.default_options[:storage] @@ -123,7 +122,7 @@ module Mastodon::CLI record_map = preload_records_from_mixed_objects(objects) objects.each do |object| - object.acl.put(acl: s3_permissions) if options[:fix_permissions] && !options[:dry_run] + object.acl.put(acl: s3_permissions) if options[:fix_permissions] && !dry_run? path_segments = object.key.split('/') path_segments.delete('cache') @@ -145,7 +144,7 @@ module Mastodon::CLI next unless attachment.blank? || !attachment.variant?(file_name) begin - object.delete unless options[:dry_run] + object.delete unless dry_run? reclaimed_bytes += object.size removed += 1 @@ -194,7 +193,7 @@ module Mastodon::CLI begin size = File.size(path) - unless options[:dry_run] + unless dry_run? File.delete(path) begin FileUtils.rmdir(File.dirname(path), parents: true) @@ -216,7 +215,7 @@ module Mastodon::CLI progress.total = progress.progress progress.finish - say("Removed #{removed} orphans (approx. #{number_to_human_size(reclaimed_bytes)})#{dry_run}", :green, true) + say("Removed #{removed} orphans (approx. #{number_to_human_size(reclaimed_bytes)})#{dry_run_mode_suffix}", :green, true) end option :account, type: :string @@ -246,8 +245,6 @@ module Mastodon::CLI not be re-downloaded. To force re-download of every URL, use --force. DESC def refresh - dry_run = options[:dry_run] ? ' (DRY RUN)' : '' - if options[:status] scope = MediaAttachment.where(status_id: options[:status]) elsif options[:account] @@ -274,7 +271,7 @@ module Mastodon::CLI next if media_attachment.remote_url.blank? || (!options[:force] && media_attachment.file_file_name.present?) next if DomainBlock.reject_media?(media_attachment.account.domain) - unless options[:dry_run] + unless dry_run? media_attachment.reset_file! media_attachment.reset_thumbnail! media_attachment.save @@ -283,7 +280,7 @@ module Mastodon::CLI media_attachment.file_file_size + (media_attachment.thumbnail_file_size || 0) end - say("Downloaded #{processed} media attachments (approx. #{number_to_human_size(aggregate)})#{dry_run}", :green, true) + say("Downloaded #{processed} media attachments (approx. #{number_to_human_size(aggregate)})#{dry_run_mode_suffix}", :green, true) end desc 'usage', 'Calculate disk space consumed by Mastodon' diff --git a/lib/mastodon/cli/preview_cards.rb b/lib/mastodon/cli/preview_cards.rb index c66bcb504a..2df3d095da 100644 --- a/lib/mastodon/cli/preview_cards.rb +++ b/lib/mastodon/cli/preview_cards.rb @@ -27,7 +27,6 @@ module Mastodon::CLI DESC def remove time_ago = options[:days].days.ago - dry_run = options[:dry_run] ? ' (DRY RUN)' : '' link = options[:link] ? 'link-type ' : '' scope = PreviewCard.cached scope = scope.where(type: :link) if options[:link] @@ -38,7 +37,7 @@ module Mastodon::CLI size = preview_card.image_file_size - unless options[:dry_run] + unless dry_run? preview_card.image.destroy preview_card.save end @@ -46,7 +45,7 @@ module Mastodon::CLI size end - say("Removed #{processed} #{link}preview cards (approx. #{number_to_human_size(aggregate)})#{dry_run}", :green, true) + say("Removed #{processed} #{link}preview cards (approx. #{number_to_human_size(aggregate)})#{dry_run_mode_suffix}", :green, true) end end end diff --git a/lib/mastodon/cli/upgrade.rb b/lib/mastodon/cli/upgrade.rb index e5c86b3d73..88390da5bf 100644 --- a/lib/mastodon/cli/upgrade.rb +++ b/lib/mastodon/cli/upgrade.rb @@ -17,7 +17,6 @@ module Mastodon::CLI LONG_DESC def storage_schema progress = create_progress_bar(nil) - dry_run = dry_run? ? ' (DRY RUN)' : '' records = 0 klasses = [ @@ -69,7 +68,7 @@ module Mastodon::CLI progress.total = progress.progress progress.finish - say("Upgraded storage schema of #{records} records#{dry_run}", :green, true) + say("Upgraded storage schema of #{records} records#{dry_run_mode_suffix}", :green, true) end private From 2cecb2dc9ef42f7425fd546b525f8ec9f5b55382 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 30 May 2023 10:08:47 -0400 Subject: [PATCH 17/22] Increment index which was previously not used in maintenance CLI loop (#25118) --- lib/mastodon/cli/maintenance.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/mastodon/cli/maintenance.rb b/lib/mastodon/cli/maintenance.rb index b107480359..a0d0547a01 100644 --- a/lib/mastodon/cli/maintenance.rb +++ b/lib/mastodon/cli/maintenance.rb @@ -225,9 +225,8 @@ module Mastodon::CLI @prompt.warn "e-mail will be disabled for the following accounts: #{user.map(&:account).map(&:acct).join(', ')}" @prompt.warn 'Please reach out to them and set another address with `tootctl account modify` or delete them.' - i = 0 - users.each do |user| - user.update!(email: "#{i} " + user.email) + users.each_with_index do |user, index| + user.update!(email: "#{index} " + user.email) end end From b7b96efd17bfcabad56730bdf48650fb93f34fc9 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 30 May 2023 10:09:15 -0400 Subject: [PATCH 18/22] Extract helper method for error report in cli/accounts command (#25119) --- lib/mastodon/cli/accounts.rb | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/mastodon/cli/accounts.rb b/lib/mastodon/cli/accounts.rb index fd8368565c..33520df25d 100644 --- a/lib/mastodon/cli/accounts.rb +++ b/lib/mastodon/cli/accounts.rb @@ -113,12 +113,7 @@ module Mastodon::CLI say('OK', :green) say("New password: #{password}") else - user.errors.each do |error| - say('Failure/Error: ', :red) - say(error.attribute) - say(" #{error.type}", :red) - end - + report_errors(user.errors) exit(1) end end @@ -189,12 +184,7 @@ module Mastodon::CLI say('OK', :green) say("New password: #{password}") if options[:reset_password] else - user.errors.each do |error| - say('Failure/Error: ', :red) - say(error.attribute) - say(" #{error.type}", :red) - end - + report_errors(user.errors) exit(1) end end @@ -661,6 +651,14 @@ module Mastodon::CLI private + def report_errors(errors) + errors.each do |error| + say('Failure/Error: ', :red) + say(error.attribute) + say(" #{error.type}", :red) + end + end + def rotate_keys_for_account(account, delay = 0) if account.nil? say('No such account', :red) From 80c7de998427d6c77b95ec297b84736eeecb6861 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 30 May 2023 10:09:57 -0400 Subject: [PATCH 19/22] Fix Rails/WhereExists cop in CLI (#25123) --- .rubocop_todo.yml | 1 - lib/mastodon/cli/email_domain_blocks.rb | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 3383a6b280..db65c1455d 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -890,7 +890,6 @@ Rails/WhereExists: - 'app/validators/vote_validator.rb' - 'app/workers/move_worker.rb' - 'db/migrate/20190529143559_preserve_old_layout_for_existing_users.rb' - - 'lib/mastodon/cli/email_domain_blocks.rb' - 'lib/tasks/tests.rake' - 'spec/controllers/api/v1/accounts/notes_controller_spec.rb' - 'spec/controllers/api/v1/tags_controller_spec.rb' diff --git a/lib/mastodon/cli/email_domain_blocks.rb b/lib/mastodon/cli/email_domain_blocks.rb index abbbdfe31c..88a84ecb42 100644 --- a/lib/mastodon/cli/email_domain_blocks.rb +++ b/lib/mastodon/cli/email_domain_blocks.rb @@ -39,7 +39,7 @@ module Mastodon::CLI processed = 0 domains.each do |domain| - if EmailDomainBlock.where(domain: domain).exists? + if EmailDomainBlock.exists?(domain: domain) say("#{domain} is already blocked.", :yellow) skipped += 1 next @@ -60,7 +60,7 @@ module Mastodon::CLI (email_domain_block.other_domains || []).uniq.each do |hostname| another_email_domain_block = EmailDomainBlock.new(domain: hostname, parent: email_domain_block) - if EmailDomainBlock.where(domain: hostname).exists? + if EmailDomainBlock.exists?(domain: hostname) say("#{hostname} is already blocked.", :yellow) skipped += 1 next From dbc44be0caaeadddb63002ba8f5b10392ef881a6 Mon Sep 17 00:00:00 2001 From: Daniel M Brasil Date: Tue, 30 May 2023 11:13:29 -0300 Subject: [PATCH 20/22] Add test coverage for `Mastodon::CLI::Accounts#follow` (#25161) --- spec/lib/mastodon/cli/accounts_spec.rb | 45 ++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/spec/lib/mastodon/cli/accounts_spec.rb b/spec/lib/mastodon/cli/accounts_spec.rb index 709400db31..bcb353aeee 100644 --- a/spec/lib/mastodon/cli/accounts_spec.rb +++ b/spec/lib/mastodon/cli/accounts_spec.rb @@ -532,4 +532,49 @@ describe Mastodon::CLI::Accounts do end end end + + describe '#follow' do + context 'when the given username is not found' do + let(:arguments) { ['non_existent_username'] } + + it 'exits with an error message indicating that no account with the given username was found' do + expect { cli.invoke(:follow, arguments) }.to output( + a_string_including('No such account') + ).to_stdout + .and raise_error(SystemExit) + end + end + + context 'when the given username is found' do + let!(:target_account) { Fabricate(:account) } + let!(:follower_bob) { Fabricate(:account, username: 'bob') } + let!(:follower_rony) { Fabricate(:account, username: 'rony') } + let!(:follower_charles) { Fabricate(:account, username: 'charles') } + let(:follow_service) { instance_double(FollowService, call: nil) } + let(:scope) { Account.local.without_suspended } + + before do + allow(cli).to receive(:parallelize_with_progress).and_yield(follower_bob) + .and_yield(follower_rony) + .and_yield(follower_charles) + .and_return([3, nil]) + allow(FollowService).to receive(:new).and_return(follow_service) + end + + it 'makes all local accounts follow the target account' do + cli.follow(target_account.username) + + expect(cli).to have_received(:parallelize_with_progress).with(scope).once + expect(follow_service).to have_received(:call).with(follower_bob, target_account, any_args).once + expect(follow_service).to have_received(:call).with(follower_rony, target_account, any_args).once + expect(follow_service).to have_received(:call).with(follower_charles, target_account, any_args).once + end + + it 'displays a successful message' do + expect { cli.follow(target_account.username) }.to output( + a_string_including('OK, followed target from 3 accounts') + ).to_stdout + end + end + end end From 1baf40077b53a850ffe58d60aa2781f0972cf52d Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 30 May 2023 10:21:53 -0400 Subject: [PATCH 21/22] Fix FormatStringToken cop in CLI (#25122) --- .rubocop_todo.yml | 1 - lib/mastodon/cli/maintenance.rb | 11 ++++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index db65c1455d..59186681c9 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -951,7 +951,6 @@ Style/FormatStringToken: Exclude: - 'app/models/privacy_policy.rb' - 'config/initializers/devise.rb' - - 'lib/mastodon/cli/maintenance.rb' - 'lib/paperclip/color_extractor.rb' # This cop supports unsafe autocorrection (--autocorrect-all). diff --git a/lib/mastodon/cli/maintenance.rb b/lib/mastodon/cli/maintenance.rb index a0d0547a01..d604973320 100644 --- a/lib/mastodon/cli/maintenance.rb +++ b/lib/mastodon/cli/maintenance.rb @@ -551,7 +551,16 @@ module Mastodon::CLI @prompt.warn 'All those accounts are distinct accounts but only the most recently-created one is fully-functional.' accounts.each_with_index do |account, idx| - @prompt.say format('%2d. %s: created at: %s; updated at: %s; last logged in at: %s; statuses: %5d; last status at: %s', idx, account.username, account.created_at, account.updated_at, account.user&.last_sign_in_at&.to_s || 'N/A', account.account_stat&.statuses_count || 0, account.account_stat&.last_status_at || 'N/A') + @prompt.say format( + '%2d. %s: created at: %s; updated at: %s; last logged in at: %s; statuses: %5d; last status at: %s', + index: idx, + username: account.username, + created_at: account.created_at, + updated_at: account.updated_at, + last_log_in_at: account.user&.last_sign_in_at&.to_s || 'N/A', + status_count: account.account_stat&.statuses_count || 0, + last_status_at: account.account_stat&.last_status_at || 'N/A' + ) end @prompt.say 'Please chose the one to keep unchanged, other ones will be automatically renamed.' From 14bb6bb29a49f151c8a6c379e5d2ddb663f8e923 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 30 May 2023 19:01:42 +0200 Subject: [PATCH 22/22] Fix `null` signUp URL in various places (#25190) --- app/javascript/mastodon/features/interaction_modal/index.jsx | 2 +- .../mastodon/features/ui/components/sign_in_banner.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/javascript/mastodon/features/interaction_modal/index.jsx b/app/javascript/mastodon/features/interaction_modal/index.jsx index be03b8f5fe..0f17a0896a 100644 --- a/app/javascript/mastodon/features/interaction_modal/index.jsx +++ b/app/javascript/mastodon/features/interaction_modal/index.jsx @@ -13,7 +13,7 @@ import { registrationsOpen } from 'mastodon/initial_state'; const mapStateToProps = (state, { accountId }) => ({ displayNameHtml: state.getIn(['accounts', accountId, 'display_name_html']), - signupUrl: state.getIn(['server', 'server', 'registrations', 'url'], '/auth/sign_up'), + signupUrl: state.getIn(['server', 'server', 'registrations', 'url'], null) || '/auth/sign_up', }); const mapDispatchToProps = (dispatch) => ({ diff --git a/app/javascript/mastodon/features/ui/components/sign_in_banner.jsx b/app/javascript/mastodon/features/ui/components/sign_in_banner.jsx index dad36134cf..abae34f7fd 100644 --- a/app/javascript/mastodon/features/ui/components/sign_in_banner.jsx +++ b/app/javascript/mastodon/features/ui/components/sign_in_banner.jsx @@ -17,7 +17,7 @@ const SignInBanner = () => { let signupButton; - const signupUrl = useAppSelector((state) => state.getIn(['server', 'server', 'registrations', 'url'], '/auth/sign_up')); + const signupUrl = useAppSelector((state) => state.getIn(['server', 'server', 'registrations', 'url'], null) || '/auth/sign_up'); if (registrationsOpen) { signupButton = (