123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865 |
- require 'rails_helper'
- require 'models/concerns/has_groups_examples'
- require 'models/concerns/has_roles_examples'
- require 'models/concerns/has_groups_permissions_examples'
- require 'models/concerns/can_lookup_examples'
- RSpec.describe User do
- let(:subject) { create(:user, user_attrs || {}) }
- let(:group_access_instance) { create(:agent_user) }
- let(:new_group_access_instance) { build(:agent_user) }
- let(:group_access_no_permission_instance) { build(:user) }
- include_examples 'HasGroups'
- include_examples 'HasRoles'
- include_examples 'HasGroups and Permissions'
- include_examples 'CanLookup'
- let(:new_password) { 'N3W54V3PW!' }
- context 'password' do
- it 'resets login_failed on password change' do
- failed_logins = (Setting.get('password_max_login_failed').to_i || 10) + 1
- user = create(:user, login_failed: failed_logins)
- expect do
- user.password = new_password
- user.save
- end.to change { user.login_failed }.to(0)
- end
- end
- context '#out_of_office_agent' do
- it 'responds to out_of_office_agent' do
- user = create(:user)
- expect(user).to respond_to(:out_of_office_agent)
- end
- context 'replacement' do
- it 'finds assigned' do
- user_replacement = create(:user)
- user_ooo = create(:user,
- out_of_office: true,
- out_of_office_start_at: Time.zone.yesterday,
- out_of_office_end_at: Time.zone.tomorrow,
- out_of_office_replacement_id: user_replacement.id,)
- expect(user_ooo.out_of_office_agent).to eq user_replacement
- end
- it 'finds none for available users' do
- user = create(:user)
- expect(user.out_of_office_agent).to be nil
- end
- end
- end
- context '#max_login_failed?' do
- it 'responds to max_login_failed?' do
- user = create(:user)
- expect(user).to respond_to(:max_login_failed?)
- end
- it 'checks if a user has reached the maximum of failed logins' do
- user = create(:user)
- expect(user.max_login_failed?).to be false
- user.login_failed = 999
- user.save
- expect(user.max_login_failed?).to be true
- end
- end
- context '.identify' do
- it 'returns users found by login' do
- user = create(:user)
- found_user = User.identify(user.login)
- expect(found_user).to be_an(User)
- expect(found_user.id).to eq user.id
- end
- it 'returns users found by email' do
- user = create(:user)
- found_user = User.identify(user.email)
- expect(found_user).to be_an(User)
- expect(found_user.id).to eq user.id
- end
- end
- context '.authenticate' do
- it 'authenticates by username and password' do
- password = 'zammad'
- user = create(:user, password: password)
- result = described_class.authenticate(user.login, password)
- expect(result).to be_an(User)
- end
- context 'failure' do
- it 'increases login_failed on failed logins' do
- user = create(:user)
- expect do
- described_class.authenticate(user.login, 'wrongpw')
- user.reload
- end
- .to change { user.login_failed }.by(1)
- end
- it 'fails for unknown users' do
- result = described_class.authenticate('john.doe', 'zammad')
- expect(result).to be nil
- end
- it 'fails for inactive users' do
- user = create(:user, active: false)
- result = described_class.authenticate(user.login, 'zammad')
- expect(result).to be nil
- end
- it 'fails for users with too many failed logins' do
- user = create(:user, login_failed: 999)
- result = described_class.authenticate(user.login, 'zammad')
- expect(result).to be nil
- end
- it 'fails for wrong passwords' do
- user = create(:user)
- result = described_class.authenticate(user.login, 'wrongpw')
- expect(result).to be nil
- end
- it 'fails for empty username parameter' do
- result = described_class.authenticate('', 'zammad')
- expect(result).to be nil
- end
- it 'fails for empty password parameter' do
- result = described_class.authenticate('username', '')
- expect(result).to be nil
- end
- end
- end
- context '#by_reset_token' do
- it 'returns a User instance for existing tokens' do
- token = create(:token_password_reset)
- expect(described_class.by_reset_token(token.name)).to be_instance_of(described_class)
- end
- it 'returns nil for not existing tokens' do
- expect(described_class.by_reset_token('not-existing')).to be nil
- end
- end
- context '#password_reset_via_token' do
- it 'changes the password of the token user and destroys the token' do
- token = create(:token_password_reset)
- user = User.find(token.user_id)
- expect do
- described_class.password_reset_via_token(token.name, new_password)
- user.reload
- end.to change {
- user.password
- }.and change {
- Token.count
- }.by(-1)
- end
- end
- context 'import' do
- it "doesn't change imported passwords" do
- # mock settings calls
- expect(Setting).to receive(:get).with('import_mode').and_return(true)
- allow(Setting).to receive(:get)
- user = build(:user, password: '{sha2}dd9c764fa7ea18cd992c8600006d3dc3ac983d1ba22e9ba2d71f6207456be0ba') # zammad
- expect do
- user.save
- end.to_not change {
- user.password
- }
- end
- end
- context '.access?' do
- let(:role_with_admin_user_permissions) do
- create(:role).tap do |role|
- role.permission_grant('admin.user')
- end
- end
- let(:admin_with_admin_user_permissions) { create(:user, roles: [role_with_admin_user_permissions]) }
- let(:role_without_admin_user_permissions) do
- create(:role).tap do |role|
- role.permission_grant('admin.tag')
- end
- end
- let(:admin_without_admin_user_permissions) { create(:user, roles: [role_without_admin_user_permissions]) }
- context 'read' do
- context 'admin' do
- let(:requested) { create(:admin_user) }
- it 'is possible for admin.user' do
- requester = admin_with_admin_user_permissions
- access = requested.access?(requester, 'read')
- expect(access).to be(true)
- end
- it 'is possible for sub admin without admin.user' do
- requester = admin_without_admin_user_permissions
- access = requested.access?(requester, 'read')
- expect(access).to be(true)
- end
- it 'is possible for agent' do
- requester = create(:agent_user)
- access = requested.access?(requester, 'read')
- expect(access).to be(true)
- end
- it 'is not possible for customer' do
- requester = create(:customer_user)
- access = requested.access?(requester, 'read')
- expect(access).to be(false)
- end
- end
- context 'agent' do
- let(:requested) { create(:agent_user) }
- it 'is possible for admin.user' do
- requester = admin_with_admin_user_permissions
- access = requested.access?(requester, 'read')
- expect(access).to be(true)
- end
- it 'is possible for sub admin without admin.user' do
- requester = admin_without_admin_user_permissions
- access = requested.access?(requester, 'read')
- expect(access).to be(true)
- end
- it 'is possible for agent' do
- requester = create(:agent_user)
- access = requested.access?(requester, 'read')
- expect(access).to be(true)
- end
- it 'is not possible for customer' do
- requester = create(:customer_user)
- access = requested.access?(requester, 'read')
- expect(access).to be(false)
- end
- end
- context 'customer' do
- let(:requested) { create(:customer_user) }
- it 'is possible for admin.user' do
- requester = admin_with_admin_user_permissions
- access = requested.access?(requester, 'read')
- expect(access).to be(true)
- end
- it 'is possible for sub admin without admin.user' do
- requester = admin_without_admin_user_permissions
- access = requested.access?(requester, 'read')
- expect(access).to be(true)
- end
- it 'is possible for agent' do
- requester = create(:agent_user)
- access = requested.access?(requester, 'read')
- expect(access).to be(true)
- end
- it 'is possible for same customer' do
- access = requested.access?(requested, 'read')
- expect(access).to be(true)
- end
- it 'is possible for same organization' do
- organization = create(:organization)
- requester = create(:customer_user, organization: organization)
- requested.update!(organization: organization)
- access = requested.access?(requester, 'read')
- expect(access).to be(true)
- end
- it 'is not possible for different customer' do
- requester = create(:customer_user)
- access = requested.access?(requester, 'read')
- expect(access).to be(false)
- end
- end
- end
- context 'change' do
- context 'admin' do
- let(:requested) { create(:admin_user) }
- it 'is possible for admin.user' do
- requester = admin_with_admin_user_permissions
- access = requested.access?(requester, 'change')
- expect(access).to be(true)
- end
- it 'is not possible for sub admin without admin.user' do
- requester = admin_without_admin_user_permissions
- access = requested.access?(requester, 'change')
- expect(access).to be(false)
- end
- it 'is not possible for same for sub admin without admin.user' do
- access = admin_without_admin_user_permissions.access?(admin_without_admin_user_permissions, 'change')
- expect(access).to be(false)
- end
- it 'is not possible for agent' do
- requester = create(:agent_user)
- access = requested.access?(requester, 'change')
- expect(access).to be(false)
- end
- it 'is not possible for customer' do
- requester = create(:customer_user)
- access = requested.access?(requester, 'change')
- expect(access).to be(false)
- end
- end
- context 'agent' do
- let(:requested) { create(:agent_user) }
- it 'is possible for admin.user' do
- requester = admin_with_admin_user_permissions
- access = requested.access?(requester, 'change')
- expect(access).to be(true)
- end
- it 'is not possible for sub admin without admin.user' do
- requester = admin_without_admin_user_permissions
- access = requested.access?(requester, 'change')
- expect(access).to be(false)
- end
- it 'is not possible for same agent' do
- access = requested.access?(requested, 'change')
- expect(access).to be(false)
- end
- it 'is not possible for other agent' do
- requester = create(:agent_user)
- access = requested.access?(requester, 'change')
- expect(access).to be(false)
- end
- it 'is not possible for customer' do
- requester = create(:customer_user)
- access = requested.access?(requester, 'change')
- expect(access).to be(false)
- end
- end
- context 'customer' do
- let(:requested) { create(:customer_user) }
- it 'is possible for admin.user' do
- requester = admin_with_admin_user_permissions
- access = requested.access?(requester, 'change')
- expect(access).to be(true)
- end
- it 'is not possible for sub admin without admin.user' do
- requester = admin_without_admin_user_permissions
- access = requested.access?(requester, 'change')
- expect(access).to be(false)
- end
- it 'is possible for agent' do
- requester = create(:agent_user)
- access = requested.access?(requester, 'change')
- expect(access).to be(true)
- end
- it 'is not possible for same customer' do
- access = requested.access?(requested, 'change')
- expect(access).to be(false)
- end
- it 'is not possible for same organization' do
- organization = create(:organization)
- requester = create(:customer_user, organization: organization)
- requested.update!(organization: organization)
- access = requested.access?(requester, 'change')
- expect(access).to be(false)
- end
- it 'is not possible for different customer' do
- requester = create(:customer_user)
- access = requested.access?(requester, 'change')
- expect(access).to be(false)
- end
- end
- end
- context 'delete' do
- context 'admin' do
- let(:requested) { create(:admin_user) }
- it 'is possible for admin.user' do
- requester = admin_with_admin_user_permissions
- access = requested.access?(requester, 'delete')
- expect(access).to be(true)
- end
- it 'is not possible for sub admin without admin.user' do
- requester = admin_without_admin_user_permissions
- access = requested.access?(requester, 'delete')
- expect(access).to be(false)
- end
- it 'is not possible for agent' do
- requester = create(:agent_user)
- access = requested.access?(requester, 'delete')
- expect(access).to be(false)
- end
- it 'is not possible for customer' do
- requester = create(:customer_user)
- access = requested.access?(requester, 'delete')
- expect(access).to be(false)
- end
- end
- context 'agent' do
- let(:requested) { create(:agent_user) }
- it 'is possible for admin.user' do
- requester = admin_with_admin_user_permissions
- access = requested.access?(requester, 'delete')
- expect(access).to be(true)
- end
- it 'is not possible for sub admin without admin.user' do
- requester = admin_without_admin_user_permissions
- access = requested.access?(requester, 'delete')
- expect(access).to be(false)
- end
- it 'is not possible for agent' do
- requester = create(:agent_user)
- access = requested.access?(requester, 'delete')
- expect(access).to be(false)
- end
- it 'is not possible for customer' do
- requester = create(:customer_user)
- access = requested.access?(requester, 'delete')
- expect(access).to be(false)
- end
- end
- context 'customer' do
- let(:requested) { create(:customer_user) }
- it 'is possible for admin.user' do
- requester = admin_with_admin_user_permissions
- access = requested.access?(requester, 'delete')
- expect(access).to be(true)
- end
- it 'is not possible for sub admin without admin.user' do
- requester = admin_without_admin_user_permissions
- access = requested.access?(requester, 'delete')
- expect(access).to be(false)
- end
- it 'is not possible for agent' do
- requester = create(:agent_user)
- access = requested.access?(requester, 'delete')
- expect(access).to be(false)
- end
- it 'is not possible for same customer' do
- access = requested.access?(requested, 'delete')
- expect(access).to be(false)
- end
- it 'is not possible for same organization' do
- organization = create(:organization)
- requester = create(:customer_user, organization: organization)
- requested.update!(organization: organization)
- access = requested.access?(requester, 'delete')
- expect(access).to be(false)
- end
- it 'is not possible for different customer' do
- requester = create(:customer_user)
- access = requested.access?(requester, 'delete')
- expect(access).to be(false)
- end
- end
- end
- end
- context 'agent limit' do
- def current_agent_count
- User.with_permissions('ticket.agent').count
- end
- let(:agent_role) { Role.lookup(name: 'Agent') }
- let(:admin_role) { Role.lookup(name: 'Admin') }
- context '#validate_agent_limit_by_role' do
- context 'agent creation limit not reached' do
- it 'grants agent creation' do
- Setting.set('system_agent_limit', current_agent_count + 1)
- expect do
- create(:agent_user)
- end.to change {
- current_agent_count
- }.by(1)
- end
- it 'grants role change' do
- Setting.set('system_agent_limit', current_agent_count + 1)
- future_agent = create(:customer_user)
- expect do
- future_agent.roles = [agent_role]
- end.to change {
- current_agent_count
- }.by(1)
- end
- context 'role updates' do
- it 'grants update by instances' do
- Setting.set('system_agent_limit', current_agent_count + 1)
- agent = create(:agent_user)
- expect do
- agent.roles = [
- admin_role,
- agent_role
- ]
- agent.save!
- end.not_to raise_error
- end
- it 'grants update by id (Integer)' do
- Setting.set('system_agent_limit', current_agent_count + 1)
- agent = create(:agent_user)
- expect do
- agent.role_ids = [
- admin_role.id,
- agent_role.id
- ]
- agent.save!
- end.not_to raise_error
- end
- it 'grants update by id (String)' do
- Setting.set('system_agent_limit', current_agent_count + 1)
- agent = create(:agent_user)
- expect do
- agent.role_ids = [
- admin_role.id.to_s,
- agent_role.id.to_s
- ]
- agent.save!
- end.not_to raise_error
- end
- end
- end
- context 'agent creation limit surpassing prevention' do
- it 'creation of new agents' do
- Setting.set('system_agent_limit', current_agent_count + 2)
- create_list(:agent_user, 2)
- initial_agent_count = current_agent_count
- expect do
- create(:agent_user)
- end.to raise_error(Exceptions::UnprocessableEntity)
- expect(current_agent_count).to eq(initial_agent_count)
- end
- it 'prevents role change' do
- Setting.set('system_agent_limit', current_agent_count)
- future_agent = create(:customer_user)
- initial_agent_count = current_agent_count
- expect do
- future_agent.roles = [agent_role]
- end.to raise_error(Exceptions::UnprocessableEntity)
- expect(current_agent_count).to eq(initial_agent_count)
- end
- end
- end
- context '#validate_agent_limit_by_attributes' do
- context 'agent creation limit surpassing prevention' do
- it 'prevents re-activation of agents' do
- Setting.set('system_agent_limit', current_agent_count)
- inactive_agent = create(:agent_user, active: false)
- initial_agent_count = current_agent_count
- expect do
- inactive_agent.update!(active: true)
- end.to raise_error(Exceptions::UnprocessableEntity)
- expect(current_agent_count).to eq(initial_agent_count)
- end
- end
- end
- context '#validate_agent_limit_by_role by string' do
- context 'agent creation limit not reached' do
- it 'grants agent creation' do
- Setting.set('system_agent_limit', (current_agent_count + 1).to_s)
- expect do
- create(:agent_user)
- end.to change {
- current_agent_count
- }.by(1)
- end
- it 'grants role change' do
- Setting.set('system_agent_limit', (current_agent_count + 1).to_s)
- future_agent = create(:customer_user)
- expect do
- future_agent.roles = [agent_role]
- end.to change {
- current_agent_count
- }.by(1)
- end
- context 'role updates' do
- it 'grants update by instances' do
- Setting.set('system_agent_limit', (current_agent_count + 1).to_s)
- agent = create(:agent_user)
- expect do
- agent.roles = [
- admin_role,
- agent_role
- ]
- agent.save!
- end.not_to raise_error
- end
- it 'grants update by id (Integer)' do
- Setting.set('system_agent_limit', (current_agent_count + 1).to_s)
- agent = create(:agent_user)
- expect do
- agent.role_ids = [
- admin_role.id,
- agent_role.id
- ]
- agent.save!
- end.not_to raise_error
- end
- it 'grants update by id (String)' do
- Setting.set('system_agent_limit', (current_agent_count + 1).to_s)
- agent = create(:agent_user)
- expect do
- agent.role_ids = [
- admin_role.id.to_s,
- agent_role.id.to_s
- ]
- agent.save!
- end.not_to raise_error
- end
- end
- end
- context 'agent creation limit surpassing prevention' do
- it 'creation of new agents' do
- Setting.set('system_agent_limit', (current_agent_count + 2).to_s)
- create_list(:agent_user, 2)
- initial_agent_count = current_agent_count
- expect do
- create(:agent_user)
- end.to raise_error(Exceptions::UnprocessableEntity)
- expect(current_agent_count).to eq(initial_agent_count)
- end
- it 'prevents role change' do
- Setting.set('system_agent_limit', current_agent_count.to_s)
- future_agent = create(:customer_user)
- initial_agent_count = current_agent_count
- expect do
- future_agent.roles = [agent_role]
- end.to raise_error(Exceptions::UnprocessableEntity)
- expect(current_agent_count).to eq(initial_agent_count)
- end
- end
- end
- context '#validate_agent_limit_by_attributes' do
- context 'agent creation limit surpassing prevention' do
- it 'prevents re-activation of agents' do
- Setting.set('system_agent_limit', current_agent_count.to_s)
- inactive_agent = create(:agent_user, active: false)
- initial_agent_count = current_agent_count
- expect do
- inactive_agent.update!(active: true)
- end.to raise_error(Exceptions::UnprocessableEntity)
- expect(current_agent_count).to eq(initial_agent_count)
- end
- end
- end
- end
- context 'when phone attribute' do
- let(:user_attrs) { { phone: orig_number } }
- context 'included on create' do
- let(:orig_number) { '1234567890' }
- it 'adds corresponding CallerId record' do
- expect { subject }
- .to change { Cti::CallerId.where(caller_id: orig_number).count }.by(1)
- end
- end
- context 'added on update' do
- let(:orig_number) { nil }
- let(:new_number) { '1234567890' }
- before { subject } # create user
- it 'adds corresponding CallerId record' do
- expect { subject.update(phone: new_number) }
- .to change { Cti::CallerId.where(caller_id: new_number).count }.by(1)
- end
- end
- context 'falsely added on update (change: [nil, ""])' do
- let(:orig_number) { nil }
- let(:new_number) { '' }
- before { subject } # create user
- it 'does not attempt to update CallerId record' do
- allow(Cti::CallerId).to receive(:build).with(any_args)
- expect(Cti::CallerId.where(object: 'User', o_id: subject.id).count)
- .to eq(0)
- expect { subject.update(phone: new_number) }
- .to change { Cti::CallerId.where(object: 'User', o_id: subject.id).count }.by(0)
- expect(Cti::CallerId).not_to have_received(:build)
- end
- end
- context 'removed on update' do
- let(:orig_number) { '1234567890' }
- let(:new_number) { nil }
- before { subject } # create user
- it 'removes corresponding CallerId record' do
- expect { subject.update(phone: nil) }
- .to change { Cti::CallerId.where(caller_id: orig_number).count }.by(-1)
- end
- end
- context 'changed on update' do
- let(:orig_number) { '1234567890' }
- let(:new_number) { orig_number.next }
- before { subject } # create user
- it 'replaces CallerId record' do
- # rubocop:disable Layout/MultilineMethodCallIndentation
- expect { subject.update(phone: new_number) }
- .to change { Cti::CallerId.where(caller_id: orig_number).count }.by(-1)
- .and change { Cti::CallerId.where(caller_id: new_number).count }.by(1)
- # rubocop:enable Layout/MultilineMethodCallIndentation
- end
- end
- end
- end
|