Commit 3b8c81fe authored by Rémy Coutable's avatar Rémy Coutable

Merge branch...

Merge branch '19966-api-call-to-move-project-to-different-group-fails-when-using-group-and-project-names-instead-of-id' into 'master'

Fix groups API to accept path when transferring a project

Closes #19966

See merge request !8408
parents e0254708 b5f4fc84
---
title: Allow group and project paths when transferring projects via the API
merge_request:
author:
...@@ -335,7 +335,7 @@ POST /groups/:id/projects/:project_id ...@@ -335,7 +335,7 @@ POST /groups/:id/projects/:project_id
Parameters: Parameters:
- `id` (required) - The ID or path of a group - `id` (required) - The ID or path of a group
- `project_id` (required) - The ID of a project - `project_id` (required) - The ID or path of a project
## Update group ## Update group
......
...@@ -156,12 +156,12 @@ module API ...@@ -156,12 +156,12 @@ module API
success Entities::GroupDetail success Entities::GroupDetail
end end
params do params do
requires :project_id, type: String, desc: 'The ID of the project' requires :project_id, type: String, desc: 'The ID or path of the project'
end end
post ":id/projects/:project_id" do post ":id/projects/:project_id" do
authenticated_as_admin! authenticated_as_admin!
group = Group.find_by(id: params[:id]) group = find_group!(params[:id])
project = Project.find(params[:project_id]) project = find_project!(params[:project_id])
result = ::Projects::TransferService.new(project, current_user).execute(group) result = ::Projects::TransferService.new(project, current_user).execute(group)
if result if result
......
...@@ -23,6 +23,7 @@ describe API::Groups, api: true do ...@@ -23,6 +23,7 @@ describe API::Groups, api: true do
context "when unauthenticated" do context "when unauthenticated" do
it "returns authentication error" do it "returns authentication error" do
get api("/groups") get api("/groups")
expect(response).to have_http_status(401) expect(response).to have_http_status(401)
end end
end end
...@@ -30,6 +31,7 @@ describe API::Groups, api: true do ...@@ -30,6 +31,7 @@ describe API::Groups, api: true do
context "when authenticated as user" do context "when authenticated as user" do
it "normal user: returns an array of groups of user1" do it "normal user: returns an array of groups of user1" do
get api("/groups", user1) get api("/groups", user1)
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response.length).to eq(1) expect(json_response.length).to eq(1)
...@@ -48,6 +50,7 @@ describe API::Groups, api: true do ...@@ -48,6 +50,7 @@ describe API::Groups, api: true do
context "when authenticated as admin" do context "when authenticated as admin" do
it "admin: returns an array of all groups" do it "admin: returns an array of all groups" do
get api("/groups", admin) get api("/groups", admin)
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response.length).to eq(2) expect(json_response.length).to eq(2)
...@@ -94,6 +97,7 @@ describe API::Groups, api: true do ...@@ -94,6 +97,7 @@ describe API::Groups, api: true do
it "returns all groups you have access to" do it "returns all groups you have access to" do
public_group = create :group, :public public_group = create :group, :public
get api("/groups", user1), all_available: true get api("/groups", user1), all_available: true
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
...@@ -140,6 +144,7 @@ describe API::Groups, api: true do ...@@ -140,6 +144,7 @@ describe API::Groups, api: true do
context 'when unauthenticated' do context 'when unauthenticated' do
it 'returns authentication error' do it 'returns authentication error' do
get api('/groups/owned') get api('/groups/owned')
expect(response).to have_http_status(401) expect(response).to have_http_status(401)
end end
end end
...@@ -147,6 +152,7 @@ describe API::Groups, api: true do ...@@ -147,6 +152,7 @@ describe API::Groups, api: true do
context 'when authenticated as group owner' do context 'when authenticated as group owner' do
it 'returns an array of groups the user owns' do it 'returns an array of groups the user owns' do
get api('/groups/owned', user2) get api('/groups/owned', user2)
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response.first['name']).to eq(group2.name) expect(json_response.first['name']).to eq(group2.name)
...@@ -179,6 +185,7 @@ describe API::Groups, api: true do ...@@ -179,6 +185,7 @@ describe API::Groups, api: true do
it "does not return a non existing group" do it "does not return a non existing group" do
get api("/groups/1328", user1) get api("/groups/1328", user1)
expect(response).to have_http_status(404) expect(response).to have_http_status(404)
end end
...@@ -192,12 +199,14 @@ describe API::Groups, api: true do ...@@ -192,12 +199,14 @@ describe API::Groups, api: true do
context "when authenticated as admin" do context "when authenticated as admin" do
it "returns any existing group" do it "returns any existing group" do
get api("/groups/#{group2.id}", admin) get api("/groups/#{group2.id}", admin)
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
expect(json_response['name']).to eq(group2.name) expect(json_response['name']).to eq(group2.name)
end end
it "does not return a non existing group" do it "does not return a non existing group" do
get api("/groups/1328", admin) get api("/groups/1328", admin)
expect(response).to have_http_status(404) expect(response).to have_http_status(404)
end end
end end
...@@ -205,12 +214,14 @@ describe API::Groups, api: true do ...@@ -205,12 +214,14 @@ describe API::Groups, api: true do
context 'when using group path in URL' do context 'when using group path in URL' do
it 'returns any existing group' do it 'returns any existing group' do
get api("/groups/#{group1.path}", admin) get api("/groups/#{group1.path}", admin)
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
expect(json_response['name']).to eq(group1.name) expect(json_response['name']).to eq(group1.name)
end end
it 'does not return a non existing group' do it 'does not return a non existing group' do
get api('/groups/unknown', admin) get api('/groups/unknown', admin)
expect(response).to have_http_status(404) expect(response).to have_http_status(404)
end end
...@@ -302,6 +313,7 @@ describe API::Groups, api: true do ...@@ -302,6 +313,7 @@ describe API::Groups, api: true do
it "does not return a non existing group" do it "does not return a non existing group" do
get api("/groups/1328/projects", user1) get api("/groups/1328/projects", user1)
expect(response).to have_http_status(404) expect(response).to have_http_status(404)
end end
...@@ -325,6 +337,7 @@ describe API::Groups, api: true do ...@@ -325,6 +337,7 @@ describe API::Groups, api: true do
context "when authenticated as admin" do context "when authenticated as admin" do
it "should return any existing group" do it "should return any existing group" do
get api("/groups/#{group2.id}/projects", admin) get api("/groups/#{group2.id}/projects", admin)
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
expect(json_response.length).to eq(1) expect(json_response.length).to eq(1)
expect(json_response.first['name']).to eq(project2.name) expect(json_response.first['name']).to eq(project2.name)
...@@ -332,6 +345,7 @@ describe API::Groups, api: true do ...@@ -332,6 +345,7 @@ describe API::Groups, api: true do
it "should not return a non existing group" do it "should not return a non existing group" do
get api("/groups/1328/projects", admin) get api("/groups/1328/projects", admin)
expect(response).to have_http_status(404) expect(response).to have_http_status(404)
end end
end end
...@@ -347,6 +361,7 @@ describe API::Groups, api: true do ...@@ -347,6 +361,7 @@ describe API::Groups, api: true do
it 'does not return a non existing group' do it 'does not return a non existing group' do
get api('/groups/unknown/projects', admin) get api('/groups/unknown/projects', admin)
expect(response).to have_http_status(404) expect(response).to have_http_status(404)
end end
...@@ -362,6 +377,7 @@ describe API::Groups, api: true do ...@@ -362,6 +377,7 @@ describe API::Groups, api: true do
context "when authenticated as user without group permissions" do context "when authenticated as user without group permissions" do
it "does not create group" do it "does not create group" do
post api("/groups", user1), attributes_for(:group) post api("/groups", user1), attributes_for(:group)
expect(response).to have_http_status(403) expect(response).to have_http_status(403)
end end
end end
...@@ -371,6 +387,7 @@ describe API::Groups, api: true do ...@@ -371,6 +387,7 @@ describe API::Groups, api: true do
group = attributes_for(:group, { request_access_enabled: false }) group = attributes_for(:group, { request_access_enabled: false })
post api("/groups", user3), group post api("/groups", user3), group
expect(response).to have_http_status(201) expect(response).to have_http_status(201)
expect(json_response["name"]).to eq(group[:name]) expect(json_response["name"]).to eq(group[:name])
...@@ -380,17 +397,20 @@ describe API::Groups, api: true do ...@@ -380,17 +397,20 @@ describe API::Groups, api: true do
it "does not create group, duplicate" do it "does not create group, duplicate" do
post api("/groups", user3), { name: 'Duplicate Test', path: group2.path } post api("/groups", user3), { name: 'Duplicate Test', path: group2.path }
expect(response).to have_http_status(400) expect(response).to have_http_status(400)
expect(response.message).to eq("Bad Request") expect(response.message).to eq("Bad Request")
end end
it "returns 400 bad request error if name not given" do it "returns 400 bad request error if name not given" do
post api("/groups", user3), { path: group2.path } post api("/groups", user3), { path: group2.path }
expect(response).to have_http_status(400) expect(response).to have_http_status(400)
end end
it "returns 400 bad request error if path not given" do it "returns 400 bad request error if path not given" do
post api("/groups", user3), { name: 'test' } post api("/groups", user3), { name: 'test' }
expect(response).to have_http_status(400) expect(response).to have_http_status(400)
end end
end end
...@@ -400,18 +420,22 @@ describe API::Groups, api: true do ...@@ -400,18 +420,22 @@ describe API::Groups, api: true do
context "when authenticated as user" do context "when authenticated as user" do
it "removes group" do it "removes group" do
delete api("/groups/#{group1.id}", user1) delete api("/groups/#{group1.id}", user1)
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
end end
it "does not remove a group if not an owner" do it "does not remove a group if not an owner" do
user4 = create(:user) user4 = create(:user)
group1.add_master(user4) group1.add_master(user4)
delete api("/groups/#{group1.id}", user3) delete api("/groups/#{group1.id}", user3)
expect(response).to have_http_status(403) expect(response).to have_http_status(403)
end end
it "does not remove a non existing group" do it "does not remove a non existing group" do
delete api("/groups/1328", user1) delete api("/groups/1328", user1)
expect(response).to have_http_status(404) expect(response).to have_http_status(404)
end end
...@@ -425,11 +449,13 @@ describe API::Groups, api: true do ...@@ -425,11 +449,13 @@ describe API::Groups, api: true do
context "when authenticated as admin" do context "when authenticated as admin" do
it "removes any existing group" do it "removes any existing group" do
delete api("/groups/#{group2.id}", admin) delete api("/groups/#{group2.id}", admin)
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
end end
it "does not remove a non existing group" do it "does not remove a non existing group" do
delete api("/groups/1328", admin) delete api("/groups/1328", admin)
expect(response).to have_http_status(404) expect(response).to have_http_status(404)
end end
end end
...@@ -437,15 +463,17 @@ describe API::Groups, api: true do ...@@ -437,15 +463,17 @@ describe API::Groups, api: true do
describe "POST /groups/:id/projects/:project_id" do describe "POST /groups/:id/projects/:project_id" do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:project_path) { "#{project.namespace.path}%2F#{project.path}" }
before(:each) do before(:each) do
allow_any_instance_of(Projects::TransferService). allow_any_instance_of(Projects::TransferService).
to receive(:execute).and_return(true) to receive(:execute).and_return(true)
allow(Project).to receive(:find).and_return(project)
end end
context "when authenticated as user" do context "when authenticated as user" do
it "does not transfer project to group" do it "does not transfer project to group" do
post api("/groups/#{group1.id}/projects/#{project.id}", user2) post api("/groups/#{group1.id}/projects/#{project.id}", user2)
expect(response).to have_http_status(403) expect(response).to have_http_status(403)
end end
end end
...@@ -453,8 +481,45 @@ describe API::Groups, api: true do ...@@ -453,8 +481,45 @@ describe API::Groups, api: true do
context "when authenticated as admin" do context "when authenticated as admin" do
it "transfers project to group" do it "transfers project to group" do
post api("/groups/#{group1.id}/projects/#{project.id}", admin) post api("/groups/#{group1.id}/projects/#{project.id}", admin)
expect(response).to have_http_status(201) expect(response).to have_http_status(201)
end end
context 'when using project path in URL' do
context 'with a valid project path' do
it "transfers project to group" do
post api("/groups/#{group1.id}/projects/#{project_path}", admin)
expect(response).to have_http_status(201)
end
end
context 'with a non-existent project path' do
it "does not transfer project to group" do
post api("/groups/#{group1.id}/projects/nogroup%2Fnoproject", admin)
expect(response).to have_http_status(404)
end
end
end
context 'when using a group path in URL' do
context 'with a valid group path' do
it "transfers project to group" do
post api("/groups/#{group1.path}/projects/#{project_path}", admin)
expect(response).to have_http_status(201)
end
end
context 'with a non-existent group path' do
it "does not transfer project to group" do
post api("/groups/noexist/projects/#{project_path}", admin)
expect(response).to have_http_status(404)
end
end
end
end end
end end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment