diff --git a/doc/api/projects.md b/doc/api/projects.md index 3703f4b327a..44d40235e9e 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -491,6 +491,170 @@ Parameters: - `id` (required) - The ID of the project to be forked +### Archive a project + +Archives a project if the user has the right access level to this project. This action is +idempotent, thus archiving an already archived project will not change the project. + +Status code 200 with the project as body is given when successful, in case the user doesn't +have the proper access rights, code 404 is returned. + +``` +PUT /projects/:id/archive +``` + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer | yes | The ID of the project | + +```bash +curl -X PUT -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/archive" +``` + +Example response: + +```json +{ + "id": 3, + "description": null, + "default_branch": "master", + "public": false, + "visibility_level": 0, + "ssh_url_to_repo": "git@example.com:diaspora/diaspora-project-site.git", + "http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git", + "web_url": "http://example.com/diaspora/diaspora-project-site", + "tag_list": [ + "example", + "disapora project" + ], + "owner": { + "id": 3, + "name": "Diaspora", + "created_at": "2013-09-30T13: 46: 02Z" + }, + "name": "Diaspora Project Site", + "name_with_namespace": "Diaspora / Diaspora Project Site", + "path": "diaspora-project-site", + "path_with_namespace": "diaspora/diaspora-project-site", + "issues_enabled": true, + "open_issues_count": 1, + "merge_requests_enabled": true, + "builds_enabled": true, + "wiki_enabled": true, + "snippets_enabled": false, + "created_at": "2013-09-30T13: 46: 02Z", + "last_activity_at": "2013-09-30T13: 46: 02Z", + "creator_id": 3, + "namespace": { + "created_at": "2013-09-30T13: 46: 02Z", + "description": "", + "id": 3, + "name": "Diaspora", + "owner_id": 1, + "path": "diaspora", + "updated_at": "2013-09-30T13: 46: 02Z" + }, + "permissions": { + "project_access": { + "access_level": 10, + "notification_level": 3 + }, + "group_access": { + "access_level": 50, + "notification_level": 3 + } + }, + "archived": true, + "avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png", + "shared_runners_enabled": true, + "forks_count": 0, + "star_count": 0, + "runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b" +} +``` + +### Unarchive a project + +Unarchives a project if the user has the right access level to this project. This action is +idempotent, thus unarchiving an non-archived project will not change the project. + +Status code 200 with the project as body is given when successful, in case the user doesn't +have the proper access rights, code 404 is returned. + +``` +PUT /projects/:id/archive +``` + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer | yes | The ID of the project | + +```bash +curl -X PUT -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/unarchive" +``` + +Example response: + +```json +{ + "id": 3, + "description": null, + "default_branch": "master", + "public": false, + "visibility_level": 0, + "ssh_url_to_repo": "git@example.com:diaspora/diaspora-project-site.git", + "http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git", + "web_url": "http://example.com/diaspora/diaspora-project-site", + "tag_list": [ + "example", + "disapora project" + ], + "owner": { + "id": 3, + "name": "Diaspora", + "created_at": "2013-09-30T13: 46: 02Z" + }, + "name": "Diaspora Project Site", + "name_with_namespace": "Diaspora / Diaspora Project Site", + "path": "diaspora-project-site", + "path_with_namespace": "diaspora/diaspora-project-site", + "issues_enabled": true, + "open_issues_count": 1, + "merge_requests_enabled": true, + "builds_enabled": true, + "wiki_enabled": true, + "snippets_enabled": false, + "created_at": "2013-09-30T13: 46: 02Z", + "last_activity_at": "2013-09-30T13: 46: 02Z", + "creator_id": 3, + "namespace": { + "created_at": "2013-09-30T13: 46: 02Z", + "description": "", + "id": 3, + "name": "Diaspora", + "owner_id": 1, + "path": "diaspora", + "updated_at": "2013-09-30T13: 46: 02Z" + }, + "permissions": { + "project_access": { + "access_level": 10, + "notification_level": 3 + }, + "group_access": { + "access_level": 50, + "notification_level": 3 + } + }, + "archived": false, + "avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png", + "shared_runners_enabled": true, + "forks_count": 0, + "star_count": 0, + "runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b" +} +``` + ### Remove project Removes a project including all associated resources (issues, merge requests etc.) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 6fcb5261e40..aa60a39f341 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -244,6 +244,34 @@ module API end end + # Archive project + # + # Parameters: + # id (required) - The ID of a project + # Example Request: + # PUT /projects/:id/archive + put ':id/archive' do + authorize!(:archive_project, user_project) + + user_project.archive! + + present @project, with: Entities::Project + end + + # Unarchive project + # + # Parameters: + # id (required) - The ID of a project + # Example Request: + # PUT /projects/:id/unarchive + put ':id/unarchive' do + authorize!(:archive_project, user_project) + + user_project.unarchive! + + present @project, with: Entities::Project + end + # Remove project # # Parameters: diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index a5d4985dc78..0a5b50e2884 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -948,6 +948,78 @@ describe API::API, api: true do end end + describe 'PUT /projects/:id/archive' do + context 'on an unarchived project' do + it 'archives the project' do + put api("/projects/#{project.id}/archive", user) + + expect(response.status).to eq(200) + expect(json_response['archived']).to be_truthy + end + + it 'rejects archivation on other users' do + put api("/projects/#{project.id}/archive", user3) + + expect(response.status).to eq(404) + end + end + + context 'on an archived project' do + before do + project.archive! + end + + it 'remains archived' do + put api("/projects/#{project.id}/archive", user) + + expect(response.status).to eq(200) + expect(json_response['archived']).to be_truthy + end + + it 'rejects archivation on other users' do + put api("/projects/#{project.id}/archive", user3) + + expect(response.status).to eq(404) + end + end + end + + describe 'PUT /projects/:id/unarchive' do + context 'on an unarchived project' do + it 'remains unarchived' do + put api("/projects/#{project.id}/unarchive", user) + + expect(response.status).to eq(200) + expect(json_response['archived']).to be_falsey + end + + it 'rejects archivation on other users' do + put api("/projects/#{project.id}/unarchive", user3) + + expect(response.status).to eq(404) + end + end + + context 'on an archived project' do + before do + project.archive! + end + + it 'remains archived' do + put api("/projects/#{project.id}/unarchive", user) + + expect(response.status).to eq(200) + expect(json_response['archived']).to be_falsey + end + + it 'rejects archivation on other users' do + put api("/projects/#{project.id}/archive", user3) + + expect(response.status).to eq(404) + end + end + end + describe 'DELETE /projects/:id' do context 'when authenticated as user' do it 'should remove project' do