0
0
Fork 0

Add customizable user roles (#18641)

* Add customizable user roles

* Various fixes and improvements

* Add migration for old settings and fix tootctl role management
This commit is contained in:
Eugen Rochko 2022-07-05 02:41:40 +02:00 committed by GitHub
parent 1b4054256f
commit 44b2ee3485
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
187 changed files with 1945 additions and 1032 deletions

View file

@ -445,7 +445,7 @@ RSpec.describe Account, type: :model do
it 'accepts arbitrary limits' do
2.times.each { Fabricate(:account, display_name: "Display Name") }
results = Account.search_for("display", 1)
results = Account.search_for("display", limit: 1)
expect(results.size).to eq 1
end
@ -473,7 +473,7 @@ RSpec.describe Account, type: :model do
)
account.follow!(match)
results = Account.advanced_search_for('A?l\i:c e', account, 10, true)
results = Account.advanced_search_for('A?l\i:c e', account, limit: 10, following: true)
expect(results).to eq [match]
end
@ -485,7 +485,7 @@ RSpec.describe Account, type: :model do
domain: 'example.com'
)
results = Account.advanced_search_for('A?l\i:c e', account, 10, true)
results = Account.advanced_search_for('A?l\i:c e', account, limit: 10, following: true)
expect(results).to eq []
end
@ -498,7 +498,7 @@ RSpec.describe Account, type: :model do
suspended: true
)
results = Account.advanced_search_for('username', account, 10, true)
results = Account.advanced_search_for('username', account, limit: 10, following: true)
expect(results).to eq []
end
@ -511,7 +511,7 @@ RSpec.describe Account, type: :model do
match.user.update(approved: false)
results = Account.advanced_search_for('username', account, 10, true)
results = Account.advanced_search_for('username', account, limit: 10, following: true)
expect(results).to eq []
end
@ -524,7 +524,7 @@ RSpec.describe Account, type: :model do
match.user.update(confirmed_at: nil)
results = Account.advanced_search_for('username', account, 10, true)
results = Account.advanced_search_for('username', account, limit: 10, following: true)
expect(results).to eq []
end
end
@ -588,7 +588,7 @@ RSpec.describe Account, type: :model do
it 'accepts arbitrary limits' do
2.times { Fabricate(:account, display_name: "Display Name") }
results = Account.advanced_search_for("display", account, 1)
results = Account.advanced_search_for("display", account, limit: 1)
expect(results.size).to eq 1
end

View file

@ -5,7 +5,7 @@ RSpec.describe Admin::AccountAction, type: :model do
describe '#save!' do
subject { account_action.save! }
let(:account) { Fabricate(:user, admin: true).account }
let(:account) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
let(:target_account) { Fabricate(:account) }
let(:type) { 'disable' }

View file

@ -0,0 +1,189 @@
require 'rails_helper'
RSpec.describe UserRole, type: :model do
subject { described_class.create(name: 'Foo', position: 1) }
describe '#can?' do
context 'with a single flag' do
it 'returns true if any of them are present' do
subject.permissions = UserRole::FLAGS[:manage_reports]
expect(subject.can?(:manage_reports)).to be true
end
it 'returns false if it is not set' do
expect(subject.can?(:manage_reports)).to be false
end
end
context 'with multiple flags' do
it 'returns true if any of them are present' do
subject.permissions = UserRole::FLAGS[:manage_users]
expect(subject.can?(:manage_reports, :manage_users)).to be true
end
it 'returns false if none of them are present' do
expect(subject.can?(:manage_reports, :manage_users)).to be false
end
end
context 'with an unknown flag' do
it 'raises an error' do
expect { subject.can?(:foo) }.to raise_error ArgumentError
end
end
end
describe '#overrides?' do
it 'returns true if other role has lower position' do
expect(subject.overrides?(described_class.new(position: subject.position - 1))).to be true
end
it 'returns true if other role is nil' do
expect(subject.overrides?(nil)).to be true
end
it 'returns false if other role has higher position' do
expect(subject.overrides?(described_class.new(position: subject.position + 1))).to be false
end
end
describe '#permissions_as_keys' do
before do
subject.permissions = UserRole::FLAGS[:invite_users] | UserRole::FLAGS[:view_dashboard] | UserRole::FLAGS[:manage_reports]
end
it 'returns an array' do
expect(subject.permissions_as_keys).to match_array %w(invite_users view_dashboard manage_reports)
end
end
describe '#permissions_as_keys=' do
let(:input) { }
before do
subject.permissions_as_keys = input
end
context 'with a single value' do
let(:input) { %w(manage_users) }
it 'sets permission flags' do
expect(subject.permissions).to eq UserRole::FLAGS[:manage_users]
end
end
context 'with multiple values' do
let(:input) { %w(manage_users manage_reports) }
it 'sets permission flags' do
expect(subject.permissions).to eq UserRole::FLAGS[:manage_users] | UserRole::FLAGS[:manage_reports]
end
end
context 'with an unknown value' do
let(:input) { %w(foo) }
it 'does not set permission flags' do
expect(subject.permissions).to eq UserRole::Flags::NONE
end
end
end
describe '#computed_permissions' do
context 'when the role is nobody' do
let(:subject) { described_class.nobody }
it 'returns none' do
expect(subject.computed_permissions).to eq UserRole::Flags::NONE
end
end
context 'when the role is everyone' do
let(:subject) { described_class.everyone }
it 'returns permissions' do
expect(subject.computed_permissions).to eq subject.permissions
end
end
context 'when role has the administrator flag' do
before do
subject.permissions = UserRole::FLAGS[:administrator]
end
it 'returns all permissions' do
expect(subject.computed_permissions).to eq UserRole::Flags::ALL
end
end
context do
it 'returns permissions combined with the everyone role' do
expect(subject.computed_permissions).to eq described_class.everyone.permissions
end
end
end
describe '.everyone' do
subject { described_class.everyone }
it 'returns a role' do
expect(subject).to be_kind_of(described_class)
end
it 'is identified as the everyone role' do
expect(subject.everyone?).to be true
end
it 'has default permissions' do
expect(subject.permissions).to eq UserRole::FLAGS[:invite_users]
end
it 'has negative position' do
expect(subject.position).to eq -1
end
end
describe '.nobody' do
subject { described_class.nobody }
it 'returns a role' do
expect(subject).to be_kind_of(described_class)
end
it 'is identified as the nobody role' do
expect(subject.nobody?).to be true
end
it 'has no permissions' do
expect(subject.permissions).to eq UserRole::Flags::NONE
end
it 'has negative position' do
expect(subject.position).to eq -1
end
end
describe '#everyone?' do
it 'returns true when id is -99' do
subject.id = -99
expect(subject.everyone?).to be true
end
it 'returns false when id is not -99' do
subject.id = 123
expect(subject.everyone?).to be false
end
end
describe '#nobody?' do
it 'returns true when id is nil' do
subject.id = nil
expect(subject.nobody?).to be true
end
it 'returns false when id is not nil' do
subject.id = 123
expect(subject.nobody?).to be false
end
end
end

View file

@ -56,14 +56,6 @@ RSpec.describe User, type: :model do
end
end
describe 'admins' do
it 'returns an array of users who are admin' do
user_1 = Fabricate(:user, admin: false)
user_2 = Fabricate(:user, admin: true)
expect(User.admins).to match_array([user_2])
end
end
describe 'confirmed' do
it 'returns an array of users who are confirmed' do
user_1 = Fabricate(:user, confirmed_at: nil)
@ -289,49 +281,6 @@ RSpec.describe User, type: :model do
end
end
describe '#role' do
it 'returns admin for admin' do
user = User.new(admin: true)
expect(user.role).to eq 'admin'
end
it 'returns moderator for moderator' do
user = User.new(moderator: true)
expect(user.role).to eq 'moderator'
end
it 'returns user otherwise' do
user = User.new
expect(user.role).to eq 'user'
end
end
describe '#role?' do
it 'returns false when invalid role requested' do
user = User.new(admin: true)
expect(user.role?('disabled')).to be false
end
it 'returns true when exact role match' do
user = User.new
mod = User.new(moderator: true)
admin = User.new(admin: true)
expect(user.role?('user')).to be true
expect(mod.role?('moderator')).to be true
expect(admin.role?('admin')).to be true
end
it 'returns true when role higher than needed' do
mod = User.new(moderator: true)
admin = User.new(admin: true)
expect(mod.role?('user')).to be true
expect(admin.role?('user')).to be true
expect(admin.role?('moderator')).to be true
end
end
describe '#disable!' do
subject(:user) { Fabricate(:user, disabled: false, current_sign_in_at: current_sign_in_at, last_sign_in_at: nil) }
let(:current_sign_in_at) { Time.zone.now }
@ -420,110 +369,6 @@ RSpec.describe User, type: :model do
end
end
describe '#promote!' do
subject(:user) { Fabricate(:user, admin: is_admin, moderator: is_moderator) }
before do
user.promote!
end
context 'when user is an admin' do
let(:is_admin) { true }
context 'when user is a moderator' do
let(:is_moderator) { true }
it 'changes moderator filed false' do
expect(user).to be_admin
expect(user).not_to be_moderator
end
end
context 'when user is not a moderator' do
let(:is_moderator) { false }
it 'does not change status' do
expect(user).to be_admin
expect(user).not_to be_moderator
end
end
end
context 'when user is not admin' do
let(:is_admin) { false }
context 'when user is a moderator' do
let(:is_moderator) { true }
it 'changes user into an admin' do
expect(user).to be_admin
expect(user).not_to be_moderator
end
end
context 'when user is not a moderator' do
let(:is_moderator) { false }
it 'changes user into a moderator' do
expect(user).not_to be_admin
expect(user).to be_moderator
end
end
end
end
describe '#demote!' do
subject(:user) { Fabricate(:user, admin: admin, moderator: moderator) }
before do
user.demote!
end
context 'when user is an admin' do
let(:admin) { true }
context 'when user is a moderator' do
let(:moderator) { true }
it 'changes user into a moderator' do
expect(user).not_to be_admin
expect(user).to be_moderator
end
end
context 'when user is not a moderator' do
let(:moderator) { false }
it 'changes user into a moderator' do
expect(user).not_to be_admin
expect(user).to be_moderator
end
end
end
context 'when user is not an admin' do
let(:admin) { false }
context 'when user is a moderator' do
let(:moderator) { true }
it 'changes user into a plain user' do
expect(user).not_to be_admin
expect(user).not_to be_moderator
end
end
context 'when user is not a moderator' do
let(:moderator) { false }
it 'does not change any fields' do
expect(user).not_to be_admin
expect(user).not_to be_moderator
end
end
end
end
describe '#active_for_authentication?' do
subject { user.active_for_authentication? }
let(:user) { Fabricate(:user, disabled: disabled, confirmed_at: confirmed_at) }
@ -560,4 +405,8 @@ RSpec.describe User, type: :model do
end
end
end
describe '.those_who_can' do
pending
end
end