|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
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
|