|
|
@ -42,9 +42,9 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
end |
|
|
|
end |
|
|
|
let(:own_member) do |
|
|
|
let(:own_member) do |
|
|
|
create(:member, |
|
|
|
create(:member, |
|
|
|
roles: [create(:role, permissions: permissions)], |
|
|
|
roles: [create(:role, permissions: permissions)], |
|
|
|
project: project, |
|
|
|
project: project, |
|
|
|
user: current_user) |
|
|
|
user: current_user) |
|
|
|
end |
|
|
|
end |
|
|
|
let(:permissions) { %i[view_members manage_members] } |
|
|
|
let(:permissions) { %i[view_members manage_members] } |
|
|
|
let(:project) { create(:project) } |
|
|
|
let(:project) { create(:project) } |
|
|
@ -53,17 +53,17 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
let(:other_user) { create(:user) } |
|
|
|
let(:other_user) { create(:user) } |
|
|
|
let(:other_member) do |
|
|
|
let(:other_member) do |
|
|
|
create(:member, |
|
|
|
create(:member, |
|
|
|
roles: [other_role], |
|
|
|
roles: [other_role], |
|
|
|
principal: other_user, |
|
|
|
principal: other_user, |
|
|
|
project: project) |
|
|
|
project: project) |
|
|
|
end |
|
|
|
end |
|
|
|
let(:invisible_member) do |
|
|
|
let(:invisible_member) do |
|
|
|
create(:member, |
|
|
|
create(:member, |
|
|
|
roles: [create(:role)]) |
|
|
|
roles: [create(:role)]) |
|
|
|
end |
|
|
|
end |
|
|
|
let(:global_member) do |
|
|
|
let(:global_member) do |
|
|
|
create(:global_member, |
|
|
|
create(:global_member, |
|
|
|
roles: [global_role]) |
|
|
|
roles: [global_role]) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
subject(:response) { last_response } |
|
|
|
subject(:response) { last_response } |
|
|
@ -87,6 +87,8 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
|
|
|
|
|
|
|
|
describe 'GET api/v3/memberships' do |
|
|
|
describe 'GET api/v3/memberships' do |
|
|
|
let(:members) { [own_member, other_member, invisible_member, global_member] } |
|
|
|
let(:members) { [own_member, other_member, invisible_member, global_member] } |
|
|
|
|
|
|
|
let(:filters) { nil } |
|
|
|
|
|
|
|
let(:path) { api_v3_paths.path_for(:memberships, filters: filters, sort_by: [%i(id asc)]) } |
|
|
|
|
|
|
|
|
|
|
|
before do |
|
|
|
before do |
|
|
|
members |
|
|
|
members |
|
|
@ -96,9 +98,6 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
get path |
|
|
|
get path |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
let(:filters) { nil } |
|
|
|
|
|
|
|
let(:path) { api_v3_paths.path_for(:memberships, filters: filters, sort_by: [%i(id asc)]) } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
context 'without params' do |
|
|
|
context 'without params' do |
|
|
|
it 'responds 200 OK' do |
|
|
|
it 'responds 200 OK' do |
|
|
|
expect(subject.status).to eq(200) |
|
|
|
expect(subject.status).to eq(200) |
|
|
@ -183,9 +182,9 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
let(:group) { create(:group) } |
|
|
|
let(:group) { create(:group) } |
|
|
|
let(:group_member) do |
|
|
|
let(:group_member) do |
|
|
|
create(:member, |
|
|
|
create(:member, |
|
|
|
roles: [create(:role)], |
|
|
|
roles: [create(:role)], |
|
|
|
project: project, |
|
|
|
project: project, |
|
|
|
principal: group) |
|
|
|
principal: group) |
|
|
|
end |
|
|
|
end |
|
|
|
let(:members) { [own_member, group_member] } |
|
|
|
let(:members) { [own_member, group_member] } |
|
|
|
|
|
|
|
|
|
|
@ -214,9 +213,9 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
end |
|
|
|
end |
|
|
|
let(:placeholder_member) do |
|
|
|
let(:placeholder_member) do |
|
|
|
create(:member, |
|
|
|
create(:member, |
|
|
|
roles: [create(:role)], |
|
|
|
roles: [create(:role)], |
|
|
|
project: project, |
|
|
|
project: project, |
|
|
|
principal: placeholder_user) |
|
|
|
principal: placeholder_user) |
|
|
|
end |
|
|
|
end |
|
|
|
let(:members) { [own_member, placeholder_member] } |
|
|
|
let(:members) { [own_member, placeholder_member] } |
|
|
|
|
|
|
|
|
|
|
@ -239,7 +238,7 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
context 'filtering by user name' do |
|
|
|
context 'when filtering by user name' do |
|
|
|
let(:filters) do |
|
|
|
let(:filters) do |
|
|
|
[{ 'any_name_attribute' => { |
|
|
|
[{ 'any_name_attribute' => { |
|
|
|
'operator' => '~', |
|
|
|
'operator' => '~', |
|
|
@ -258,14 +257,14 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
context 'filtering by project' do |
|
|
|
context 'when filtering by project' do |
|
|
|
let(:members) { [own_member, other_member, invisible_member, own_other_member] } |
|
|
|
let(:members) { [own_member, other_member, invisible_member, own_other_member] } |
|
|
|
|
|
|
|
|
|
|
|
let(:own_other_member) do |
|
|
|
let(:own_other_member) do |
|
|
|
create(:member, |
|
|
|
create(:member, |
|
|
|
roles: [create(:role, permissions: permissions)], |
|
|
|
roles: [create(:role, permissions: permissions)], |
|
|
|
project: other_project, |
|
|
|
project: other_project, |
|
|
|
user: current_user) |
|
|
|
user: current_user) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
let(:other_project) { create(:project) } |
|
|
|
let(:other_project) { create(:project) } |
|
|
@ -288,13 +287,13 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
context 'filtering by principal' do |
|
|
|
context 'when filtering by principal' do |
|
|
|
let(:group) { create(:group) } |
|
|
|
let(:group) { create(:group) } |
|
|
|
let(:group_member) do |
|
|
|
let(:group_member) do |
|
|
|
create(:member, |
|
|
|
create(:member, |
|
|
|
roles: [create(:role)], |
|
|
|
roles: [create(:role)], |
|
|
|
principal: group, |
|
|
|
principal: group, |
|
|
|
project: project) |
|
|
|
project: project) |
|
|
|
end |
|
|
|
end |
|
|
|
let(:members) { [own_member, other_member, group_member, invisible_member] } |
|
|
|
let(:members) { [own_member, other_member, group_member, invisible_member] } |
|
|
|
|
|
|
|
|
|
|
@ -318,6 +317,24 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
.to be_json_eql(group_member.id.to_json) |
|
|
|
.to be_json_eql(group_member.id.to_json) |
|
|
|
.at_path('_embedded/elements/1/id') |
|
|
|
.at_path('_embedded/elements/1/id') |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
context 'when principal is a group without any memberships' do |
|
|
|
|
|
|
|
let(:members) { [own_member, other_member, invisible_member] } |
|
|
|
|
|
|
|
let(:filters) do |
|
|
|
|
|
|
|
[{ 'principal' => { |
|
|
|
|
|
|
|
'operator' => '=', |
|
|
|
|
|
|
|
'values' => [group.id.to_s] |
|
|
|
|
|
|
|
} }] |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it 'returns empty members' do |
|
|
|
|
|
|
|
expect(subject.status).to eq(200) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expect(subject.body) |
|
|
|
|
|
|
|
.to be_json_eql([]) |
|
|
|
|
|
|
|
.at_path('_embedded/elements') |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
context 'with the outdated created_on sort by (renamed to created_at)' do |
|
|
|
context 'with the outdated created_on sort by (renamed to created_at)' do |
|
|
@ -363,6 +380,7 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
|
|
|
|
|
|
|
|
context 'without permissions' do |
|
|
|
context 'without permissions' do |
|
|
|
let(:permissions) { [] } |
|
|
|
let(:permissions) { [] } |
|
|
|
|
|
|
|
|
|
|
|
it 'is empty' do |
|
|
|
it 'is empty' do |
|
|
|
expect(subject.body) |
|
|
|
expect(subject.body) |
|
|
|
.to be_json_eql('0') |
|
|
|
.to be_json_eql('0') |
|
|
@ -416,7 +434,7 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
it 'creates the member' do |
|
|
|
it 'creates the member' do |
|
|
|
expect(Member.find_by(user_id: principal.id, project: project)) |
|
|
|
expect(Member.find_by(principal: principal, project: project)) |
|
|
|
.to be_present |
|
|
|
.to be_present |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
@ -551,6 +569,33 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
.to be_empty |
|
|
|
.to be_empty |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
context 'when creating global role permission as admin' do |
|
|
|
|
|
|
|
let(:current_user) { admin } |
|
|
|
|
|
|
|
let(:project) { nil } |
|
|
|
|
|
|
|
let(:expected_role) { global_role } |
|
|
|
|
|
|
|
let(:body) do |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
_links: { |
|
|
|
|
|
|
|
principal: { |
|
|
|
|
|
|
|
href: principal_path |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
roles: [ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
href: api_v3_paths.role(global_role.id) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
] |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
_meta: { |
|
|
|
|
|
|
|
notificationMessage: { |
|
|
|
|
|
|
|
raw: custom_message |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}.to_json |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it_behaves_like 'successful member creation' |
|
|
|
|
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
context 'for a placeholder user' do |
|
|
|
context 'for a placeholder user' do |
|
|
@ -738,7 +783,7 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
|
|
|
|
|
|
|
|
it 'returns 200 OK' do |
|
|
|
it 'returns 200 OK' do |
|
|
|
expect(subject.status) |
|
|
|
expect(subject.status) |
|
|
|
.to eql(200) |
|
|
|
.to be(200) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
it 'returns the member' do |
|
|
|
it 'returns the member' do |
|
|
@ -758,7 +803,7 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
|
|
|
|
|
|
|
|
it 'returns 404 NOT FOUND' do |
|
|
|
it 'returns 404 NOT FOUND' do |
|
|
|
expect(subject.status) |
|
|
|
expect(subject.status) |
|
|
|
.to eql(404) |
|
|
|
.to be(404) |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
@ -767,7 +812,7 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
|
|
|
|
|
|
|
|
it 'returns 404 NOT FOUND' do |
|
|
|
it 'returns 404 NOT FOUND' do |
|
|
|
expect(subject.status) |
|
|
|
expect(subject.status) |
|
|
|
.to eql(404) |
|
|
|
.to be(404) |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
@ -869,13 +914,19 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
context 'with a group' do |
|
|
|
context 'with a group' do |
|
|
|
|
|
|
|
# first user has no direct roles |
|
|
|
|
|
|
|
# second user has direct role `another_role` |
|
|
|
|
|
|
|
# both users belong to a group which has `other_role`, so this role is inherited by users |
|
|
|
|
|
|
|
# when updating `group` role from `other_role` to `another_role` |
|
|
|
|
|
|
|
# expecting to have first user role changed from `other_role` to `another_role` |
|
|
|
|
|
|
|
# and second user role extended from `[other_role]` to `[other_role, another_role]` because has direct role |
|
|
|
let(:group) do |
|
|
|
let(:group) do |
|
|
|
create(:group, member_in_project: project, member_through_role: other_role, members: users) |
|
|
|
create(:group, member_in_project: project, member_through_role: other_role, members: users) |
|
|
|
end |
|
|
|
end |
|
|
|
let(:principal) { group } |
|
|
|
let(:principal) { group } |
|
|
|
let(:users) { [create(:user), create(:user)] } |
|
|
|
let(:users) { [create(:user), create(:user)] } |
|
|
|
let(:other_member) do |
|
|
|
let(:other_member) do |
|
|
|
Member.find_by(principal: group).tap do |m| |
|
|
|
Member.find_by(principal: group).tap do |
|
|
|
# Behaves as if the user had that role before the role's membership was created. |
|
|
|
# Behaves as if the user had that role before the role's membership was created. |
|
|
|
# Because the user had the role independent of the group, it is not to be removed. |
|
|
|
# Because the user had the role independent of the group, it is not to be removed. |
|
|
|
user_member = Member.find_by(principal: users.first) |
|
|
|
user_member = Member.find_by(principal: users.first) |
|
|
@ -967,6 +1018,45 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
.to be_empty |
|
|
|
.to be_empty |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
context 'when updating global role permission as admin' do |
|
|
|
|
|
|
|
let(:group) do |
|
|
|
|
|
|
|
create(:group, global_role: other_role, members: users) |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
let(:current_user) { admin } |
|
|
|
|
|
|
|
let(:project) { nil } |
|
|
|
|
|
|
|
let(:other_role) { create(:global_role) } |
|
|
|
|
|
|
|
let(:another_role) { create(:global_role) } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it 'responds with 200' do |
|
|
|
|
|
|
|
expect(last_response.status).to eq(200) |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it 'updates the member and all inherited members but does not update memberships users have already had' do |
|
|
|
|
|
|
|
# other member is the group member |
|
|
|
|
|
|
|
expect(other_member.reload.roles) |
|
|
|
|
|
|
|
.to match_array [another_role] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expect(other_member.updated_at > other_member_updated_at) |
|
|
|
|
|
|
|
.to be_truthy |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
last_user_member = Member.find_by(principal: users.last) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expect(last_user_member.roles) |
|
|
|
|
|
|
|
.to match_array [another_role] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expect(last_user_member.updated_at > last_user_member_updated_at) |
|
|
|
|
|
|
|
.to be_truthy |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
first_user_member = Member.find_by(principal: users.first) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expect(first_user_member.roles.uniq) |
|
|
|
|
|
|
|
.to match_array [other_role, another_role] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expect(first_user_member.updated_at) |
|
|
|
|
|
|
|
.to eql first_user_member_updated_at |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
context 'if attempting to empty the roles' do |
|
|
|
context 'if attempting to empty the roles' do |
|
|
@ -980,7 +1070,7 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
|
|
|
|
|
|
|
|
it 'returns 422' do |
|
|
|
it 'returns 422' do |
|
|
|
expect(last_response.status) |
|
|
|
expect(last_response.status) |
|
|
|
.to eql(422) |
|
|
|
.to be(422) |
|
|
|
|
|
|
|
|
|
|
|
expect(last_response.body) |
|
|
|
expect(last_response.body) |
|
|
|
.to be_json_eql("Roles need to be assigned.".to_json) |
|
|
|
.to be_json_eql("Roles need to be assigned.".to_json) |
|
|
@ -1004,7 +1094,7 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
|
|
|
|
|
|
|
|
it 'returns 422' do |
|
|
|
it 'returns 422' do |
|
|
|
expect(last_response.status) |
|
|
|
expect(last_response.status) |
|
|
|
.to eql(422) |
|
|
|
.to be(422) |
|
|
|
|
|
|
|
|
|
|
|
expect(last_response.body) |
|
|
|
expect(last_response.body) |
|
|
|
.to be_json_eql("Roles has an unassignable role.".to_json) |
|
|
|
.to be_json_eql("Roles has an unassignable role.".to_json) |
|
|
@ -1016,9 +1106,9 @@ describe 'API v3 memberships resource', type: :request, content_type: :json do |
|
|
|
let(:other_project) do |
|
|
|
let(:other_project) do |
|
|
|
create(:project).tap do |p| |
|
|
|
create(:project).tap do |p| |
|
|
|
create(:member, |
|
|
|
create(:member, |
|
|
|
project: p, |
|
|
|
project: p, |
|
|
|
roles: [create(:role, permissions: [:manage_members])], |
|
|
|
roles: [create(:role, permissions: [:manage_members])], |
|
|
|
user: current_user) |
|
|
|
user: current_user) |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|