Commit a69aa3da authored by Sean McGivern's avatar Sean McGivern

Merge branch 'api-empty-return' into 'master'

Return 204 on all DELETE endpoints

Closes #20429

See merge request !9397
parents 71fbbc9d 2b8005ae
...@@ -68,7 +68,7 @@ gem 'gollum-rugged_adapter', '~> 0.4.2', require: false ...@@ -68,7 +68,7 @@ gem 'gollum-rugged_adapter', '~> 0.4.2', require: false
gem 'github-linguist', '~> 4.7.0', require: 'linguist' gem 'github-linguist', '~> 4.7.0', require: 'linguist'
# API # API
gem 'grape', '~> 0.18.0' gem 'grape', '~> 0.19.0'
gem 'grape-entity', '~> 0.6.0' gem 'grape-entity', '~> 0.6.0'
gem 'rack-cors', '~> 0.4.0', require: 'rack/cors' gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
......
...@@ -304,7 +304,7 @@ GEM ...@@ -304,7 +304,7 @@ GEM
multi_json (~> 1.11) multi_json (~> 1.11)
os (~> 0.9) os (~> 0.9)
signet (~> 0.7) signet (~> 0.7)
grape (0.18.0) grape (0.19.1)
activesupport activesupport
builder builder
hashie (>= 2.1.0) hashie (>= 2.1.0)
...@@ -353,8 +353,8 @@ GEM ...@@ -353,8 +353,8 @@ GEM
json (~> 1.8) json (~> 1.8)
multi_xml (>= 0.5.2) multi_xml (>= 0.5.2)
httpclient (2.8.2) httpclient (2.8.2)
i18n (0.8.0) i18n (0.8.1)
ice_nine (0.11.1) ice_nine (0.11.2)
influxdb (0.2.3) influxdb (0.2.3)
cause cause
json json
...@@ -417,7 +417,7 @@ GEM ...@@ -417,7 +417,7 @@ GEM
minitest (5.7.0) minitest (5.7.0)
mousetrap-rails (1.4.6) mousetrap-rails (1.4.6)
multi_json (1.12.1) multi_json (1.12.1)
multi_xml (0.5.5) multi_xml (0.6.0)
multipart-post (2.0.0) multipart-post (2.0.0)
mustermann (0.4.0) mustermann (0.4.0)
tool (~> 0.2) tool (~> 0.2)
...@@ -758,7 +758,7 @@ GEM ...@@ -758,7 +758,7 @@ GEM
eventmachine (~> 1.0, >= 1.0.4) eventmachine (~> 1.0, >= 1.0.4)
rack (>= 1, < 3) rack (>= 1, < 3)
thor (0.19.4) thor (0.19.4)
thread_safe (0.3.5) thread_safe (0.3.6)
tilt (2.0.6) tilt (2.0.6)
timecop (0.8.1) timecop (0.8.1)
timfel-krb5-auth (0.8.3) timfel-krb5-auth (0.8.3)
...@@ -886,7 +886,7 @@ DEPENDENCIES ...@@ -886,7 +886,7 @@ DEPENDENCIES
gollum-rugged_adapter (~> 0.4.2) gollum-rugged_adapter (~> 0.4.2)
gon (~> 6.1.0) gon (~> 6.1.0)
google-api-client (~> 0.8.6) google-api-client (~> 0.8.6)
grape (~> 0.18.0) grape (~> 0.19.0)
grape-entity (~> 0.6.0) grape-entity (~> 0.6.0)
haml_lint (~> 0.21.0) haml_lint (~> 0.21.0)
hamlit (~> 2.6.1) hamlit (~> 2.6.1)
...@@ -1011,4 +1011,4 @@ DEPENDENCIES ...@@ -1011,4 +1011,4 @@ DEPENDENCIES
wikicloth (= 0.8.1) wikicloth (= 0.8.1)
BUNDLED WITH BUNDLED WITH
1.14.3 1.14.4
---
title: 'API: Return 204 for all delete endpoints'
merge_request: 9397
author: Robert Schilling
...@@ -159,6 +159,7 @@ The following table shows the possible return codes for API requests. ...@@ -159,6 +159,7 @@ The following table shows the possible return codes for API requests.
| Return values | Description | | Return values | Description |
| ------------- | ----------- | | ------------- | ----------- |
| `200 OK` | The `GET`, `PUT` or `DELETE` request was successful, the resource(s) itself is returned as JSON. | | `200 OK` | The `GET`, `PUT` or `DELETE` request was successful, the resource(s) itself is returned as JSON. |
| `204 OK` | The server has successfully fulfilled the request and that there is no additional content to send in the response payload body. |
| `201 Created` | The `POST` request was successful and the resource is returned as JSON. | | `201 Created` | The `POST` request was successful and the resource is returned as JSON. |
| `304 Not Modified` | Indicates that the resource has not been modified since the last request. | | `304 Not Modified` | Indicates that the resource has not been modified since the last request. |
| `400 Bad Request` | A required attribute of the API request is missing, e.g., the title of an issue is not given. | | `400 Bad Request` | A required attribute of the API request is missing, e.g., the title of an issue is not given. |
......
...@@ -178,27 +178,6 @@ Parameters: ...@@ -178,27 +178,6 @@ Parameters:
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" http://gitlab.example.com/api/v3/projects/1/issues/80/award_emoji/344 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" http://gitlab.example.com/api/v3/projects/1/issues/80/award_emoji/344
``` ```
Example Response:
```json
{
"id": 344,
"name": "blowfish",
"user": {
"name": "Administrator",
"username": "root",
"id": 1,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://gitlab.example.com/root"
},
"created_at": "2016-06-17T17:47:29.266Z",
"updated_at": "2016-06-17T17:47:29.266Z",
"awardable_id": 80,
"awardable_type": "Issue"
}
```
## Award Emoji on Notes ## Award Emoji on Notes
The endpoints documented above are available for Notes as well. Notes The endpoints documented above are available for Notes as well. Notes
...@@ -350,25 +329,4 @@ Parameters: ...@@ -350,25 +329,4 @@ Parameters:
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" http://gitlab.example.com/api/v3/projects/1/issues/80/award_emoji/345 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" http://gitlab.example.com/api/v3/projects/1/issues/80/award_emoji/345
``` ```
Example Response:
```json
{
"id": 345,
"name": "rocket",
"user": {
"name": "Administrator",
"username": "root",
"id": 1,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://gitlab.example.com/root"
},
"created_at": "2016-06-17T19:59:55.888Z",
"updated_at": "2016-06-17T19:59:55.888Z",
"awardable_id": 1,
"awardable_type": "Note"
}
```
[ce-4575]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4575 [ce-4575]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4575
...@@ -226,16 +226,3 @@ DELETE /projects/:id/boards/:board_id/lists/:list_id ...@@ -226,16 +226,3 @@ DELETE /projects/:id/boards/:board_id/lists/:list_id
```bash ```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/boards/1/lists/1 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/boards/1/lists/1
``` ```
Example response:
```json
{
"id" : 1,
"label" : {
"name" : "Testing",
"color" : "#F0AD4E",
"description" : null
},
"position" : 1
}
```
...@@ -244,14 +244,6 @@ In case of an error, an explaining message is provided. ...@@ -244,14 +244,6 @@ In case of an error, an explaining message is provided.
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/5/repository/branches/newbranch" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/5/repository/branches/newbranch"
``` ```
Example response:
```json
{
"branch_name": "newbranch"
}
```
## Delete merged branches ## Delete merged branches
Will delete all branches that are merged into the project's default branch. Will delete all branches that are merged into the project's default branch.
......
...@@ -138,17 +138,3 @@ DELETE /broadcast_messages/:id ...@@ -138,17 +138,3 @@ DELETE /broadcast_messages/:id
```bash ```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/broadcast_messages/1 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/broadcast_messages/1
``` ```
Example response:
```json
{
"message":"Update message",
"starts_at":"2016-08-26T00:41:35.060Z",
"ends_at":"2016-08-26T01:41:35.060Z",
"color":"#000",
"font":"#FFFFFF",
"id":1,
"active": true
}
```
...@@ -106,13 +106,3 @@ DELETE /projects/:id/triggers/:token ...@@ -106,13 +106,3 @@ DELETE /projects/:id/triggers/:token
``` ```
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/triggers/7b9148c158980bbd9bcea92c17522d" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/triggers/7b9148c158980bbd9bcea92c17522d"
``` ```
```json
{
"created_at": "2015-12-23T16:25:56.760Z",
"deleted_at": "2015-12-24T12:32:20.100Z",
"last_used": null,
"token": "7b9148c158980bbd9bcea92c17522d",
"updated_at": "2015-12-24T12:32:20.100Z"
}
```
...@@ -119,10 +119,3 @@ DELETE /projects/:id/variables/:key ...@@ -119,10 +119,3 @@ DELETE /projects/:id/variables/:key
``` ```
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/variables/VARIABLE_1" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/variables/VARIABLE_1"
``` ```
```json
{
"key": "VARIABLE_1",
"value": "VALUE_1"
}
```
...@@ -152,18 +152,6 @@ DELETE /projects/:id/deploy_keys/:key_id ...@@ -152,18 +152,6 @@ DELETE /projects/:id/deploy_keys/:key_id
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/5/deploy_keys/13" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/5/deploy_keys/13"
``` ```
Example response:
```json
{
"id": 6,
"deploy_key_id": 14,
"project_id": 1,
"created_at" : "2015-08-29T12:50:57.259Z",
"updated_at" : "2015-08-29T12:50:57.259Z"
}
```
## Enable a deploy key ## Enable a deploy key
Enables a deploy key for a project so this can be used. Returns the enabled key, with a status code 201 when successful. Enables a deploy key for a project so this can be used. Returns the enabled key, with a status code 201 when successful.
......
...@@ -108,14 +108,3 @@ DELETE /projects/:id/environments/:environment_id ...@@ -108,14 +108,3 @@ DELETE /projects/:id/environments/:environment_id
```bash ```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/environments/1" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/environments/1"
``` ```
Example response:
```json
{
"id": 1,
"name": "deploy",
"slug": "deploy",
"external_url": "https://deploy.example.gitlab.com"
}
```
...@@ -581,43 +581,6 @@ POST /projects/:id/issues/:issue_id/unsubscribe ...@@ -581,43 +581,6 @@ POST /projects/:id/issues/:issue_id/unsubscribe
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/issues/93/unsubscribe curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/issues/93/unsubscribe
``` ```
Example response:
```json
{
"id": 93,
"iid": 12,
"project_id": 5,
"title": "Incidunt et rerum ea expedita iure quibusdam.",
"description": "Et cumque architecto sed aut ipsam.",
"state": "opened",
"created_at": "2016-04-05T21:41:45.217Z",
"updated_at": "2016-04-07T13:02:37.905Z",
"labels": [],
"milestone": null,
"assignee": {
"name": "Edwardo Grady",
"username": "keyon",
"id": 21,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/3e6f06a86cf27fa8b56f3f74f7615987?s=80&d=identicon",
"web_url": "https://gitlab.example.com/keyon"
},
"author": {
"name": "Vivian Hermann",
"username": "orville",
"id": 11,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
"web_url": "https://gitlab.example.com/orville"
},
"subscribed": false,
"due_date": null,
"web_url": "http://example.com/example/example/issues/12",
"confidential": false
}
```
## Create a todo ## Create a todo
Manually creates a todo for the current user on an issue. If Manually creates a todo for the current user on an issue. If
......
...@@ -131,22 +131,6 @@ DELETE /projects/:id/labels ...@@ -131,22 +131,6 @@ DELETE /projects/:id/labels
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/labels?name=bug" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/labels?name=bug"
``` ```
Example response:
```json
{
"id" : 1,
"name" : "bug",
"color" : "#d9534f",
"description": "Bug reported by user",
"open_issues_count": 1,
"closed_issues_count": 0,
"open_merge_requests_count": 1,
"subscribed": false,
"priority": null
}
```
## Edit an existing label ## Edit an existing label
Updates an existing label with new name or new color. At least one parameter Updates an existing label with new name or new color. At least one parameter
...@@ -239,19 +223,3 @@ POST /projects/:id/labels/:label_id/unsubscribe ...@@ -239,19 +223,3 @@ POST /projects/:id/labels/:label_id/unsubscribe
```bash ```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/labels/1/unsubscribe curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/labels/1/unsubscribe
``` ```
Example response:
```json
{
"id" : 1,
"name" : "bug",
"color" : "#d9534f",
"description": "Bug reported by user",
"open_issues_count": 1,
"closed_issues_count": 0,
"open_merge_requests_count": 1,
"subscribed": false,
"priority": null
}
```
...@@ -123,30 +123,6 @@ Parameters: ...@@ -123,30 +123,6 @@ Parameters:
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/issues/11/notes/636 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/issues/11/notes/636
``` ```
Example Response:
```json
{
"id": 636,
"body": "This is a good idea.",
"attachment": null,
"author": {
"id": 1,
"username": "pipin",
"email": "admin@example.com",
"name": "Pip",
"state": "active",
"created_at": "2013-09-30T13:46:01Z",
"avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
"web_url": "https://gitlab.example.com/pipin"
},
"created_at": "2016-04-05T22:10:44.164Z",
"system": false,
"noteable_id": 11,
"noteable_type": "Issue"
}
```
## Snippets ## Snippets
### List all snippet notes ### List all snippet notes
...@@ -245,30 +221,6 @@ Parameters: ...@@ -245,30 +221,6 @@ Parameters:
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/snippets/52/notes/1659 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/snippets/52/notes/1659
``` ```
Example Response:
```json
{
"id": 1659,
"body": "This is a good idea.",
"attachment": null,
"author": {
"id": 1,
"username": "pipin",
"email": "admin@example.com",
"name": "Pip",
"state": "active",
"created_at": "2013-09-30T13:46:01Z",
"avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
"web_url": "https://gitlab.example.com/pipin"
},
"created_at": "2016-04-06T16:51:53.239Z",
"system": false,
"noteable_id": 52,
"noteable_type": "Snippet"
}
```
## Merge Requests ## Merge Requests
### List all merge request notes ### List all merge request notes
...@@ -369,27 +321,3 @@ Parameters: ...@@ -369,27 +321,3 @@ Parameters:
```bash ```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/merge_requests/7/notes/1602 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/merge_requests/7/notes/1602
``` ```
Example Response:
```json
{
"id": 1602,
"body": "This is a good idea.",
"attachment": null,
"author": {
"id": 1,
"username": "pipin",
"email": "admin@example.com",
"name": "Pip",
"state": "active",
"created_at": "2013-09-30T13:46:01Z",
"avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
"web_url": "https://gitlab.example.com/pipin"
},
"created_at": "2016-04-05T22:11:59.923Z",
"system": false,
"noteable_id": 7,
"noteable_type": "MergeRequest"
}
```
...@@ -210,18 +210,6 @@ DELETE /runners/:id ...@@ -210,18 +210,6 @@ DELETE /runners/:id
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/runners/6" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/runners/6"
``` ```
Example response:
```json
{
"active": true,
"description": "test-1-20150125-test",
"id": 6,
"is_shared": false,
"name": null,
}
```
## List project's runners ## List project's runners
List all runners (specific and shared) available in the project. Shared runners List all runners (specific and shared) available in the project. Shared runners
...@@ -308,15 +296,3 @@ DELETE /projects/:id/runners/:runner_id ...@@ -308,15 +296,3 @@ DELETE /projects/:id/runners/:runner_id
``` ```
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/9/runners/9" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/9/runners/9"
``` ```
Example response:
```json
{
"active": true,
"description": "test-2016-02-01",
"id": 9,
"is_shared": false,
"name": null
}
```
...@@ -125,22 +125,3 @@ Example request: ...@@ -125,22 +125,3 @@ Example request:
```bash ```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/hooks/2 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/hooks/2
``` ```
Example response:
```json
{
"note_events" : false,
"project_id" : null,
"enable_ssl_verification" : true,
"url" : "https://gitlab.example.com/hook",
"updated_at" : "2015-11-04T20:12:15.931Z",
"issues_events" : false,
"merge_requests_events" : false,
"created_at" : "2015-11-04T20:12:15.931Z",
"service_id" : null,
"id" : 2,
"push_events" : true,
"tag_push_events" : false
}
```
...@@ -141,11 +141,6 @@ Parameters: ...@@ -141,11 +141,6 @@ Parameters:
- `id` (required) - The ID of a project - `id` (required) - The ID of a project
- `tag_name` (required) - The name of a tag - `tag_name` (required) - The name of a tag
```json
{
"tag_name": "v4.3.0"
}
```
## Create a new release ## Create a new release
......
...@@ -5,10 +5,13 @@ module API ...@@ -5,10 +5,13 @@ module API
version %w(v3 v4), using: :path version %w(v3 v4), using: :path
version 'v3', using: :path do version 'v3', using: :path do
mount ::API::V3::AwardEmoji
mount ::API::V3::Boards mount ::API::V3::Boards
mount ::API::V3::Branches mount ::API::V3::Branches
mount ::API::V3::BroadcastMessages
mount ::API::V3::Commits mount ::API::V3::Commits
mount ::API::V3::DeployKeys mount ::API::V3::DeployKeys
mount ::API::V3::Environments
mount ::API::V3::Files mount ::API::V3::Files
mount ::API::V3::Groups mount ::API::V3::Groups
mount ::API::V3::Issues mount ::API::V3::Issues
...@@ -21,12 +24,16 @@ module API ...@@ -21,12 +24,16 @@ module API
mount ::API::V3::Projects mount ::API::V3::Projects
mount ::API::V3::ProjectSnippets mount ::API::V3::ProjectSnippets
mount ::API::V3::Repositories mount ::API::V3::Repositories
mount ::API::V3::Runners
mount ::API::V3::Services
mount ::API::V3::Subscriptions mount ::API::V3::Subscriptions
mount ::API::V3::SystemHooks mount ::API::V3::SystemHooks
mount ::API::V3::Tags mount ::API::V3::Tags
mount ::API::V3::Todos
mount ::API::V3::Templates mount ::API::V3::Templates
mount ::API::V3::Todos
mount ::API::V3::Triggers
mount ::API::V3::Users mount ::API::V3::Users
mount ::API::V3::Variables
end end
before { allow_access_with_scope :api } before { allow_access_with_scope :api }
......
...@@ -83,7 +83,6 @@ module API ...@@ -83,7 +83,6 @@ module API
unauthorized! unless award.user == current_user || current_user.admin? unauthorized! unless award.user == current_user || current_user.admin?
award.destroy award.destroy
present award, with: Entities::AwardEmoji
end end
end end
end end
......
...@@ -127,9 +127,7 @@ module API ...@@ -127,9 +127,7 @@ module API
service = ::Boards::Lists::DestroyService.new(user_project, current_user) service = ::Boards::Lists::DestroyService.new(user_project, current_user)
if service.execute(list) unless service.execute(list)
present list, with: Entities::List
else
render_api_error!({ error: 'List could not be deleted!' }, 400) render_api_error!({ error: 'List could not be deleted!' }, 400)
end end
end end
......
...@@ -124,11 +124,7 @@ module API ...@@ -124,11 +124,7 @@ module API
result = DeleteBranchService.new(user_project, current_user). result = DeleteBranchService.new(user_project, current_user).
execute(params[:branch]) execute(params[:branch])
if result[:status] == :success if result[:status] != :success
{
branch: params[:branch]
}
else
render_api_error!(result[:message], result[:return_code]) render_api_error!(result[:message], result[:return_code])
end end
end end
......
...@@ -91,7 +91,7 @@ module API ...@@ -91,7 +91,7 @@ module API
delete ':id' do delete ':id' do
message = find_message message = find_message
present message.destroy, with: Entities::BroadcastMessage message.destroy
end end
end end
end end
......
...@@ -79,7 +79,7 @@ module API ...@@ -79,7 +79,7 @@ module API
environment = user_project.environments.find(params[:environment_id]) environment = user_project.environments.find(params[:environment_id])
present environment.destroy, with: Entities::Environment environment.destroy
end end
end end
end end
......
...@@ -118,10 +118,7 @@ module API ...@@ -118,10 +118,7 @@ module API
file_params = declared_params(include_missing: false) file_params = declared_params(include_missing: false)
result = ::Files::DestroyService.new(user_project, current_user, commit_params(file_params)).execute result = ::Files::DestroyService.new(user_project, current_user, commit_params(file_params)).execute
if result[:status] == :success if result[:status] != :success
status(200)
commit_response(file_params)
else
render_api_error!(result[:message], 400) render_api_error!(result[:message], 400)
end end
end end
......
module API module API
class Labels < Grape::API class Labels < Grape::API
include PaginationParams include PaginationParams
before { authenticate! } before { authenticate! }
params do params do
...@@ -56,7 +56,7 @@ module API ...@@ -56,7 +56,7 @@ module API
label = user_project.labels.find_by(title: params[:name]) label = user_project.labels.find_by(title: params[:name])
not_found!('Label') unless label not_found!('Label') unless label
present label.destroy, with: Entities::Label, current_user: current_user, project: user_project label.destroy
end end
desc 'Update an existing label. At least one optional parameter is required.' do desc 'Update an existing label. At least one optional parameter is required.' do
......
...@@ -93,24 +93,10 @@ module API ...@@ -93,24 +93,10 @@ module API
end end
delete ":id/members/:user_id" do delete ":id/members/:user_id" do
source = find_source(source_type, params[:id]) source = find_source(source_type, params[:id])
# Ensure that memeber exists
source.members.find_by!(user_id: params[:user_id])
# This is to ensure back-compatibility but find_by! should be used ::Members::DestroyService.new(source, current_user, declared_params).execute
# in that casse in 9.0!
member = source.members.find_by(user_id: params[:user_id])
# This is to ensure back-compatibility but this should be removed in
# favor of find_by! in 9.0!
not_found!("Member: user_id:#{params[:user_id]}") if source_type == 'group' && member.nil?
# This is to ensure back-compatibility but 204 behavior should be used
# for all DELETE endpoints in 9.0!
if member.nil?
{ message: "Access revoked", id: params[:user_id].to_i }
else
::Members::DestroyService.new(source, current_user, declared_params).execute
present member.user, with: Entities::Member, member: member
end
end end
end end
end end
......
...@@ -132,8 +132,6 @@ module API ...@@ -132,8 +132,6 @@ module API
authorize! :admin_note, note authorize! :admin_note, note
::Notes::DestroyService.new(user_project, current_user).execute(note) ::Notes::DestroyService.new(user_project, current_user).execute(note)
present note, with: Entities::Note
end end
end end
end end
......
...@@ -90,12 +90,9 @@ module API ...@@ -90,12 +90,9 @@ module API
requires :hook_id, type: Integer, desc: 'The ID of the hook to delete' requires :hook_id, type: Integer, desc: 'The ID of the hook to delete'
end end
delete ":id/hooks/:hook_id" do delete ":id/hooks/:hook_id" do
begin hook = user_project.hooks.find(params.delete(:hook_id))
present user_project.hooks.destroy(params[:hook_id]), with: Entities::ProjectHook
rescue hook.destroy
# ProjectHook can raise Error if hook_id not found
not_found!("Error deleting hook #{params[:hook_id]}")
end
end end
end end
end end
......
...@@ -353,7 +353,6 @@ module API ...@@ -353,7 +353,6 @@ module API
not_found!('Group Link') unless link not_found!('Group Link') unless link
link.destroy link.destroy
no_content!
end end
desc 'Upload a file' desc 'Upload a file'
......
...@@ -38,7 +38,7 @@ module API ...@@ -38,7 +38,7 @@ module API
end end
desc 'Deletes a registered Runner' do desc 'Deletes a registered Runner' do
http_codes [[200, 'Runner was deleted'], [403, 'Forbidden']] http_codes [[204, 'Runner was deleted'], [403, 'Forbidden']]
end end
params do params do
requires :token, type: String, desc: %q(Runner's authentication token) requires :token, type: String, desc: %q(Runner's authentication token)
......
...@@ -78,9 +78,8 @@ module API ...@@ -78,9 +78,8 @@ module API
delete ':id' do delete ':id' do
runner = get_runner(params[:id]) runner = get_runner(params[:id])
authenticate_delete_runner!(runner) authenticate_delete_runner!(runner)
runner.destroy!
present runner, with: Entities::Runner runner.destroy!
end end
end end
...@@ -136,8 +135,6 @@ module API ...@@ -136,8 +135,6 @@ module API
forbidden!("Only one project associated with the runner. Please remove the runner instead") if runner.projects.count == 1 forbidden!("Only one project associated with the runner. Please remove the runner instead") if runner.projects.count == 1
runner_project.destroy runner_project.destroy
present runner, with: Entities::Runner
end end
end end
......
...@@ -654,9 +654,7 @@ module API ...@@ -654,9 +654,7 @@ module API
hash.merge!(key => nil) hash.merge!(key => nil)
end end
if service.update_attributes(attrs.merge(active: false)) unless service.update_attributes(attrs.merge(active: false))
true
else
render_api_error!('400 Bad Request', 400) render_api_error!('400 Bad Request', 400)
end end
end end
......
...@@ -118,9 +118,10 @@ module API ...@@ -118,9 +118,10 @@ module API
delete ':id' do delete ':id' do
snippet = snippets_for_current_user.find_by(id: params.delete(:id)) snippet = snippets_for_current_user.find_by(id: params.delete(:id))
return not_found!('Snippet') unless snippet return not_found!('Snippet') unless snippet
authorize! :destroy_personal_snippet, snippet authorize! :destroy_personal_snippet, snippet
snippet.destroy snippet.destroy
no_content!
end end
desc 'Get a raw snippet' do desc 'Get a raw snippet' do
......
...@@ -66,7 +66,7 @@ module API ...@@ -66,7 +66,7 @@ module API
hook = SystemHook.find_by(id: params[:id]) hook = SystemHook.find_by(id: params[:id])
not_found!('System hook') unless hook not_found!('System hook') unless hook
present hook.destroy, with: Entities::Hook hook.destroy
end end
end end
end end
......
...@@ -66,11 +66,7 @@ module API ...@@ -66,11 +66,7 @@ module API
result = ::Tags::DestroyService.new(user_project, current_user). result = ::Tags::DestroyService.new(user_project, current_user).
execute(params[:tag_name]) execute(params[:tag_name])
if result[:status] == :success if result[:status] != :success
{
tag_name: params[:tag_name]
}
else
render_api_error!(result[:message], result[:return_code]) render_api_error!(result[:message], result[:return_code])
end end
end end
......
...@@ -93,8 +93,6 @@ module API ...@@ -93,8 +93,6 @@ module API
return not_found!('Trigger') unless trigger return not_found!('Trigger') unless trigger
trigger.destroy trigger.destroy
present trigger, with: Entities::Trigger
end end
end end
end end
......
...@@ -236,7 +236,7 @@ module API ...@@ -236,7 +236,7 @@ module API
key = user.keys.find_by(id: params[:key_id]) key = user.keys.find_by(id: params[:key_id])
not_found!('Key') unless key not_found!('Key') unless key
present key.destroy, with: Entities::SSHKey key.destroy
end end
desc 'Add an email address to a specified user. Available only for admins.' do desc 'Add an email address to a specified user. Available only for admins.' do
...@@ -422,7 +422,7 @@ module API ...@@ -422,7 +422,7 @@ module API
key = current_user.keys.find_by(id: params[:key_id]) key = current_user.keys.find_by(id: params[:key_id])
not_found!('Key') unless key not_found!('Key') unless key
present key.destroy, with: Entities::SSHKey key.destroy
end end
desc "Get the currently authenticated user's email addresses" do desc "Get the currently authenticated user's email addresses" do
......
module API
module V3
class AwardEmoji < Grape::API
include PaginationParams
before { authenticate! }
AWARDABLES = %w[issue merge_request snippet].freeze
resource :projects do
AWARDABLES.each do |awardable_type|
awardable_string = awardable_type.pluralize
awardable_id_string = "#{awardable_type}_id"
params do
requires :id, type: String, desc: 'The ID of a project'
requires :"#{awardable_id_string}", type: Integer, desc: "The ID of an Issue, Merge Request or Snippet"
end
[":id/#{awardable_string}/:#{awardable_id_string}/award_emoji",
":id/#{awardable_string}/:#{awardable_id_string}/notes/:note_id/award_emoji"].each do |endpoint|
desc 'Delete a +awardables+ award emoji' do
detail 'This feature was introduced in 8.9'
success ::API::Entities::AwardEmoji
end
params do
requires :award_id, type: Integer, desc: 'The ID of an award emoji'
end
delete "#{endpoint}/:award_id" do
award = awardable.award_emoji.find(params[:award_id])
unauthorized! unless award.user == current_user || current_user.admin?
present award.destroy, with: ::API::Entities::AwardEmoji
end
end
end
end
helpers do
def awardable
@awardable ||=
begin
if params.include?(:note_id)
note_id = params.delete(:note_id)
awardable.notes.find(note_id)
elsif params.include?(:issue_id)
user_project.issues.find(params[:issue_id])
elsif params.include?(:merge_request_id)
user_project.merge_requests.find(params[:merge_request_id])
else
user_project.snippets.find(params[:snippet_id])
end
end
end
end
end
end
end
...@@ -44,6 +44,27 @@ module API ...@@ -44,6 +44,27 @@ module API
authorize!(:read_board, user_project) authorize!(:read_board, user_project)
present board_lists, with: ::API::Entities::List present board_lists, with: ::API::Entities::List
end end
desc 'Delete a board list' do
detail 'This feature was introduced in 8.13'
success ::API::Entities::List
end
params do
requires :list_id, type: Integer, desc: 'The ID of a board list'
end
delete "/lists/:list_id" do
authorize!(:admin_list, user_project)
list = board_lists.find(params[:list_id])
service = ::Boards::Lists::DestroyService.new(user_project, current_user)
if service.execute(list)
present list, with: ::API::Entities::List
else
render_api_error!({ error: 'List could not be deleted!' }, 400)
end
end
end end
end end
end end
......
...@@ -19,6 +19,26 @@ module API ...@@ -19,6 +19,26 @@ module API
present branches, with: ::API::Entities::RepoBranch, project: user_project present branches, with: ::API::Entities::RepoBranch, project: user_project
end end
desc 'Delete a branch'
params do
requires :branch, type: String, desc: 'The name of the branch'
end
delete ":id/repository/branches/:branch", requirements: { branch: /.+/ } do
authorize_push_project
result = DeleteBranchService.new(user_project, current_user).
execute(params[:branch])
if result[:status] == :success
status(200)
{
branch_name: params[:branch]
}
else
render_api_error!(result[:message], result[:return_code])
end
end
desc 'Delete all merged branches' desc 'Delete all merged branches'
delete ":id/repository/merged_branches" do delete ":id/repository/merged_branches" do
DeleteMergedBranchesService.new(user_project, current_user).async_execute DeleteMergedBranchesService.new(user_project, current_user).async_execute
......
module API
module V3
class BroadcastMessages < Grape::API
include PaginationParams
before { authenticate! }
before { authenticated_as_admin! }
resource :broadcast_messages do
helpers do
def find_message
BroadcastMessage.find(params[:id])
end
end
desc 'Delete a broadcast message' do
detail 'This feature was introduced in GitLab 8.12.'
success ::API::Entities::BroadcastMessage
end
params do
requires :id, type: Integer, desc: 'Broadcast message ID'
end
delete ':id' do
message = find_message
present message.destroy, with: ::API::Entities::BroadcastMessage
end
end
end
end
end
module API
module V3
class Environments < Grape::API
include PaginationParams
before { authenticate! }
params do
requires :id, type: String, desc: 'The project ID'
end
resource :projects do
desc 'Deletes an existing environment' do
detail 'This feature was introduced in GitLab 8.11.'
success ::API::Entities::Environment
end
params do
requires :environment_id, type: Integer, desc: 'The environment ID'
end
delete ':id/environments/:environment_id' do
authorize! :update_environment, user_project
environment = user_project.environments.find(params[:environment_id])
present environment.destroy, with: ::API::Entities::Environment
end
end
end
end
end
...@@ -226,6 +226,8 @@ module API ...@@ -226,6 +226,8 @@ module API
not_found!('Issue') unless issue not_found!('Issue') unless issue
authorize!(:destroy_issue, issue) authorize!(:destroy_issue, issue)
status(200)
issue.destroy issue.destroy
end end
end end
......
...@@ -13,6 +13,21 @@ module API ...@@ -13,6 +13,21 @@ module API
get ':id/labels' do get ':id/labels' do
present available_labels, with: ::API::Entities::Label, current_user: current_user, project: user_project present available_labels, with: ::API::Entities::Label, current_user: current_user, project: user_project
end end
desc 'Delete an existing label' do
success ::API::Entities::Label
end
params do
requires :name, type: String, desc: 'The name of the label to be deleted'
end
delete ':id/labels' do
authorize! :admin_label, user_project
label = user_project.labels.find_by(title: params[:name])
not_found!('Label') unless label
present label.destroy, with: ::API::Entities::Label, current_user: current_user, project: user_project
end
end end
end end
end end
......
...@@ -119,6 +119,7 @@ module API ...@@ -119,6 +119,7 @@ module API
# This is to ensure back-compatibility but 204 behavior should be used # This is to ensure back-compatibility but 204 behavior should be used
# for all DELETE endpoints in 9.0! # for all DELETE endpoints in 9.0!
if member.nil? if member.nil?
status(200 )
{ message: "Access revoked", id: params[:user_id].to_i } { message: "Access revoked", id: params[:user_id].to_i }
else else
::Members::DestroyService.new(source, current_user, declared_params).execute ::Members::DestroyService.new(source, current_user, declared_params).execute
......
...@@ -103,6 +103,8 @@ module API ...@@ -103,6 +103,8 @@ module API
merge_request = find_project_merge_request(params[:merge_request_id]) merge_request = find_project_merge_request(params[:merge_request_id])
authorize!(:destroy_merge_request, merge_request) authorize!(:destroy_merge_request, merge_request)
status(200)
merge_request.destroy merge_request.destroy
end end
......
...@@ -121,6 +121,8 @@ module API ...@@ -121,6 +121,8 @@ module API
authorize! :admin_project_snippet, snippet authorize! :admin_project_snippet, snippet
snippet.destroy snippet.destroy
status(200)
end end
desc 'Get a raw project snippet' desc 'Get a raw project snippet'
......
...@@ -359,6 +359,8 @@ module API ...@@ -359,6 +359,8 @@ module API
desc 'Remove a project' desc 'Remove a project'
delete ":id" do delete ":id" do
authorize! :remove_project, user_project authorize! :remove_project, user_project
status(200)
::Projects::DestroyService.new(user_project, current_user, {}).async_execute ::Projects::DestroyService.new(user_project, current_user, {}).async_execute
end end
...@@ -384,6 +386,7 @@ module API ...@@ -384,6 +386,7 @@ module API
authorize! :remove_fork_project, user_project authorize! :remove_fork_project, user_project
if user_project.forked? if user_project.forked?
status(200)
user_project.forked_project_link.destroy user_project.forked_project_link.destroy
else else
not_modified! not_modified!
......
module API
module V3
class Runners < Grape::API
include PaginationParams
before { authenticate! }
resource :runners do
desc 'Remove a runner' do
success ::API::Entities::Runner
end
params do
requires :id, type: Integer, desc: 'The ID of the runner'
end
delete ':id' do
runner = Ci::Runner.find(params[:id])
not_found!('Runner') unless runner
authenticate_delete_runner!(runner)
status(200)
runner.destroy
end
end
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects do
before { authorize_admin_project }
desc "Disable project's runner" do
success ::API::Entities::Runner
end
params do
requires :runner_id, type: Integer, desc: 'The ID of the runner'
end
delete ':id/runners/:runner_id' do
runner_project = user_project.runner_projects.find_by(runner_id: params[:runner_id])
not_found!('Runner') unless runner_project
runner = runner_project.runner
forbidden!("Only one project associated with the runner. Please remove the runner instead") if runner.projects.count == 1
runner_project.destroy
present runner, with: ::API::Entities::Runner
end
end
helpers do
def authenticate_delete_runner!(runner)
return if current_user.is_admin?
forbidden!("Runner is shared") if runner.is_shared?
forbidden!("Runner associated with more than one project") if runner.projects.count > 1
forbidden!("No access granted") unless user_can_access_runner?(runner)
end
def user_can_access_runner?(runner)
current_user.ci_authorized_runners.exists?(runner.id)
end
end
end
end
end
module API
module V3
class Services < Grape::API
services = {
'asana' => [
{
required: true,
name: :api_key,
type: String,
desc: 'User API token'
},
{
required: false,
name: :restrict_to_branch,
type: String,
desc: 'Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches'
}
],
'assembla' => [
{
required: true,
name: :token,
type: String,
desc: 'The authentication token'
},
{
required: false,
name: :subdomain,
type: String,
desc: 'Subdomain setting'
}
],
'bamboo' => [
{
required: true,
name: :bamboo_url,
type: String,
desc: 'Bamboo root URL like https://bamboo.example.com'
},
{
required: true,
name: :build_key,
type: String,
desc: 'Bamboo build plan key like'
},
{
required: true,
name: :username,
type: String,
desc: 'A user with API access, if applicable'
},
{
required: true,
name: :password,
type: String,
desc: 'Passord of the user'
}
],
'bugzilla' => [
{
required: true,
name: :new_issue_url,
type: String,
desc: 'New issue URL'
},
{
required: true,
name: :issues_url,
type: String,
desc: 'Issues URL'
},
{
required: true,
name: :project_url,
type: String,
desc: 'Project URL'
},
{
required: false,
name: :description,
type: String,
desc: 'Description'
},
{
required: false,
name: :title,
type: String,
desc: 'Title'
}
],
'buildkite' => [
{
required: true,
name: :token,
type: String,
desc: 'Buildkite project GitLab token'
},
{
required: true,
name: :project_url,
type: String,
desc: 'The buildkite project URL'
},
{
required: false,
name: :enable_ssl_verification,
type: Boolean,
desc: 'Enable SSL verification for communication'
}
],
'builds-email' => [
{
required: true,
name: :recipients,
type: String,
desc: 'Comma-separated list of recipient email addresses'
},
{
required: false,
name: :add_pusher,
type: Boolean,
desc: 'Add pusher to recipients list'
},
{
required: false,
name: :notify_only_broken_builds,
type: Boolean,
desc: 'Notify only broken builds'
}
],
'campfire' => [
{
required: true,
name: :token,
type: String,
desc: 'Campfire token'
},
{
required: false,
name: :subdomain,
type: String,
desc: 'Campfire subdomain'
},
{
required: false,
name: :room,
type: String,
desc: 'Campfire room'
}
],
'custom-issue-tracker' => [
{
required: true,
name: :new_issue_url,
type: String,
desc: 'New issue URL'
},
{
required: true,
name: :issues_url,
type: String,
desc: 'Issues URL'
},
{
required: true,
name: :project_url,
type: String,
desc: 'Project URL'
},
{
required: false,
name: :description,
type: String,
desc: 'Description'
},
{
required: false,
name: :title,
type: String,
desc: 'Title'
}
],
'drone-ci' => [
{
required: true,
name: :token,
type: String,
desc: 'Drone CI token'
},
{
required: true,
name: :drone_url,
type: String,
desc: 'Drone CI URL'
},
{
required: false,
name: :enable_ssl_verification,
type: Boolean,
desc: 'Enable SSL verification for communication'
}
],
'emails-on-push' => [
{
required: true,
name: :recipients,
type: String,
desc: 'Comma-separated list of recipient email addresses'
},
{
required: false,
name: :disable_diffs,
type: Boolean,
desc: 'Disable code diffs'
},
{
required: false,
name: :send_from_committer_email,
type: Boolean,
desc: 'Send from committer'
}
],
'external-wiki' => [
{
required: true,
name: :external_wiki_url,
type: String,
desc: 'The URL of the external Wiki'
}
],
'flowdock' => [
{
required: true,
name: :token,
type: String,
desc: 'Flowdock token'
}
],
'gemnasium' => [
{
required: true,
name: :api_key,
type: String,
desc: 'Your personal API key on gemnasium.com'
},
{
required: true,
name: :token,
type: String,
desc: "The project's slug on gemnasium.com"
}
],
'hipchat' => [
{
required: true,
name: :token,
type: String,
desc: 'The room token'
},
{
required: false,
name: :room,
type: String,
desc: 'The room name or ID'
},
{
required: false,
name: :color,
type: String,
desc: 'The room color'
},
{
required: false,
name: :notify,
type: Boolean,
desc: 'Enable notifications'
},
{
required: false,
name: :api_version,
type: String,
desc: 'Leave blank for default (v2)'
},
{
required: false,
name: :server,
type: String,
desc: 'Leave blank for default. https://hipchat.example.com'
}
],
'irker' => [
{
required: true,
name: :recipients,
type: String,
desc: 'Recipients/channels separated by whitespaces'
},
{
required: false,
name: :default_irc_uri,
type: String,
desc: 'Default: irc://irc.network.net:6697'
},
{
required: false,
name: :server_host,
type: String,
desc: 'Server host. Default localhost'
},
{
required: false,
name: :server_port,
type: Integer,
desc: 'Server port. Default 6659'
},
{
required: false,
name: :colorize_messages,
type: Boolean,
desc: 'Colorize messages'
}
],
'jira' => [
{
required: true,
name: :url,
type: String,
desc: 'The URL to the JIRA project which is being linked to this GitLab project, e.g., https://jira.example.com'
},
{
required: true,
name: :project_key,
type: String,
desc: 'The short identifier for your JIRA project, all uppercase, e.g., PROJ'
},
{
required: false,
name: :username,
type: String,
desc: 'The username of the user created to be used with GitLab/JIRA'
},
{
required: false,
name: :password,
type: String,
desc: 'The password of the user created to be used with GitLab/JIRA'
},
{
required: false,
name: :jira_issue_transition_id,
type: Integer,
desc: 'The ID of a transition that moves issues to a closed state. You can find this number under the JIRA workflow administration (**Administration > Issues > Workflows**) by selecting **View** under **Operations** of the desired workflow of your project. The ID of each state can be found inside the parenthesis of each transition name under the **Transitions (id)** column ([see screenshot][trans]). By default, this ID is set to `2`'
}
],
'kubernetes' => [
{
required: true,
name: :namespace,
type: String,
desc: 'The Kubernetes namespace to use'
},
{
required: true,
name: :api_url,
type: String,
desc: 'The URL to the Kubernetes cluster API, e.g., https://kubernetes.example.com'
},
{
required: true,
name: :token,
type: String,
desc: 'The service token to authenticate against the Kubernetes cluster with'
},
{
required: false,
name: :ca_pem,
type: String,
desc: 'A custom certificate authority bundle to verify the Kubernetes cluster with (PEM format)'
},
],
'mattermost-slash-commands' => [
{
required: true,
name: :token,
type: String,
desc: 'The Mattermost token'
}
],
'slack-slash-commands' => [
{
required: true,
name: :token,
type: String,
desc: 'The Slack token'
}
],
'pipelines-email' => [
{
required: true,
name: :recipients,
type: String,
desc: 'Comma-separated list of recipient email addresses'
},
{
required: false,
name: :notify_only_broken_builds,
type: Boolean,
desc: 'Notify only broken builds'
}
],
'pivotaltracker' => [
{
required: true,
name: :token,
type: String,
desc: 'The Pivotaltracker token'
},
{
required: false,
name: :restrict_to_branch,
type: String,
desc: 'Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches.'
}
],
'pushover' => [
{
required: true,
name: :api_key,
type: String,
desc: 'The application key'
},
{
required: true,
name: :user_key,
type: String,
desc: 'The user key'
},
{
required: true,
name: :priority,
type: String,
desc: 'The priority'
},
{
required: true,
name: :device,
type: String,
desc: 'Leave blank for all active devices'
},
{
required: true,
name: :sound,
type: String,
desc: 'The sound of the notification'
}
],
'redmine' => [
{
required: true,
name: :new_issue_url,
type: String,
desc: 'The new issue URL'
},
{
required: true,
name: :project_url,
type: String,
desc: 'The project URL'
},
{
required: true,
name: :issues_url,
type: String,
desc: 'The issues URL'
},
{
required: false,
name: :description,
type: String,
desc: 'The description of the tracker'
}
],
'slack' => [
{
required: true,
name: :webhook,
type: String,
desc: 'The Slack webhook. e.g. https://hooks.slack.com/services/...'
},
{
required: false,
name: :new_issue_url,
type: String,
desc: 'The user name'
},
{
required: false,
name: :channel,
type: String,
desc: 'The channel name'
}
],
'mattermost' => [
{
required: true,
name: :webhook,
type: String,
desc: 'The Mattermost webhook. e.g. http://mattermost_host/hooks/...'
}
],
'teamcity' => [
{
required: true,
name: :teamcity_url,
type: String,
desc: 'TeamCity root URL like https://teamcity.example.com'
},
{
required: true,
name: :build_type,
type: String,
desc: 'Build configuration ID'
},
{
required: true,
name: :username,
type: String,
desc: 'A user with permissions to trigger a manual build'
},
{
required: true,
name: :password,
type: String,
desc: 'The password of the user'
}
]
}
resource :projects do
before { authenticate! }
before { authorize_admin_project }
helpers do
def service_attributes(service)
service.fields.inject([]) do |arr, hash|
arr << hash[:name].to_sym
end
end
end
desc "Delete a service for project"
params do
requires :service_slug, type: String, values: services.keys, desc: 'The name of the service'
end
delete ":id/services/:service_slug" do
service = user_project.find_or_initialize_service(params[:service_slug].underscore)
attrs = service_attributes(service).inject({}) do |hash, key|
hash.merge!(key => nil)
end
if service.update_attributes(attrs.merge(active: false))
status(200)
true
else
render_api_error!('400 Bad Request', 400)
end
end
end
end
end
end
...@@ -13,6 +13,19 @@ module API ...@@ -13,6 +13,19 @@ module API
get do get do
present SystemHook.all, with: ::API::Entities::Hook present SystemHook.all, with: ::API::Entities::Hook
end end
desc 'Delete a hook' do
success ::API::Entities::Hook
end
params do
requires :id, type: Integer, desc: 'The ID of the system hook'
end
delete ":id" do
hook = SystemHook.find_by(id: params[:id])
not_found!('System hook') unless hook
present hook.destroy, with: ::API::Entities::Hook
end
end end
end end
end end
......
...@@ -14,6 +14,26 @@ module API ...@@ -14,6 +14,26 @@ module API
tags = user_project.repository.tags.sort_by(&:name).reverse tags = user_project.repository.tags.sort_by(&:name).reverse
present tags, with: ::API::Entities::RepoTag, project: user_project present tags, with: ::API::Entities::RepoTag, project: user_project
end end
desc 'Delete a repository tag'
params do
requires :tag_name, type: String, desc: 'The name of the tag'
end
delete ":id/repository/tags/:tag_name", requirements: { tag_name: /.+/ } do
authorize_push_project
result = ::Tags::DestroyService.new(user_project, current_user).
execute(params[:tag_name])
if result[:status] == :success
status(200)
{
tag_name: params[:tag_name]
}
else
render_api_error!(result[:message], result[:return_code])
end
end
end end
end end
end end
......
...@@ -19,6 +19,8 @@ module API ...@@ -19,6 +19,8 @@ module API
desc 'Mark all todos as done' desc 'Mark all todos as done'
delete do delete do
status(200)
todos = TodosFinder.new(current_user, params).execute todos = TodosFinder.new(current_user, params).execute
TodoService.new.mark_todos_as_done(todos, current_user) TodoService.new.mark_todos_as_done(todos, current_user)
end end
......
module API
module V3
class Triggers < Grape::API
include PaginationParams
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects do
desc 'Delete a trigger' do
success ::API::Entities::Trigger
end
params do
requires :token, type: String, desc: 'The unique token of trigger'
end
delete ':id/triggers/:token' do
authenticate!
authorize! :admin_build, user_project
trigger = user_project.triggers.find_by(token: params[:token].to_s)
return not_found!('Trigger') unless trigger
trigger.destroy
present trigger, with: ::API::Entities::Trigger
end
end
end
end
end
...@@ -92,6 +92,25 @@ module API ...@@ -92,6 +92,25 @@ module API
present paginate(events), with: ::API::V3::Entities::Event present paginate(events), with: ::API::V3::Entities::Event
end end
desc 'Delete an existing SSH key from a specified user. Available only for admins.' do
success ::API::Entities::SSHKey
end
params do
requires :id, type: Integer, desc: 'The ID of the user'
requires :key_id, type: Integer, desc: 'The ID of the SSH key'
end
delete ':id/keys/:key_id' do
authenticated_as_admin!
user = User.find_by(id: params[:id])
not_found!('User') unless user
key = user.keys.find_by(id: params[:key_id])
not_found!('Key') unless key
present key.destroy, with: ::API::Entities::SSHKey
end
end end
resource :user do resource :user do
...@@ -111,6 +130,19 @@ module API ...@@ -111,6 +130,19 @@ module API
get "emails" do get "emails" do
present current_user.emails, with: ::API::Entities::Email present current_user.emails, with: ::API::Entities::Email
end end
desc 'Delete an SSH key from the currently authenticated user' do
success ::API::Entities::SSHKey
end
params do
requires :key_id, type: Integer, desc: 'The ID of the SSH key'
end
delete "keys/:key_id" do
key = current_user.keys.find_by(id: params[:key_id])
not_found!('Key') unless key
present key.destroy, with: ::API::Entities::SSHKey
end
end end
end end
end end
......
module API
module V3
class Variables < Grape::API
include PaginationParams
before { authenticate! }
before { authorize! :admin_build, user_project }
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects do
desc 'Delete an existing variable from a project' do
success ::API::Entities::Variable
end
params do
requires :key, type: String, desc: 'The key of the variable'
end
delete ':id/variables/:key' do
variable = user_project.variables.find_by(key: params[:key])
not_found!('Variable') unless variable
present variable.destroy, with: ::API::Entities::Variable
end
end
end
end
end
module API module API
# Projects variables API
class Variables < Grape::API class Variables < Grape::API
include PaginationParams include PaginationParams
...@@ -81,10 +80,9 @@ module API ...@@ -81,10 +80,9 @@ module API
end end
delete ':id/variables/:key' do delete ':id/variables/:key' do
variable = user_project.variables.find_by(key: params[:key]) variable = user_project.variables.find_by(key: params[:key])
not_found!('Variable') unless variable
return not_found!('Variable') unless variable variable.destroy
present variable.destroy, with: Entities::Variable
end end
end end
end end
......
...@@ -217,6 +217,7 @@ module Ci ...@@ -217,6 +217,7 @@ module Ci
build = Ci::Build.find_by_id(params[:id]) build = Ci::Build.find_by_id(params[:id])
authenticate_build!(build) authenticate_build!(build)
status(200)
build.erase_artifacts! build.erase_artifacts!
end end
end end
......
...@@ -8,6 +8,8 @@ module Ci ...@@ -8,6 +8,8 @@ module Ci
end end
delete "delete" do delete "delete" do
authenticate_runner! authenticate_runner!
status(200)
Ci::Runner.find_by_token(params[:token]).destroy Ci::Runner.find_by_token(params[:token]).destroy
end end
......
...@@ -200,7 +200,7 @@ describe API::AccessRequests, api: true do ...@@ -200,7 +200,7 @@ describe API::AccessRequests, api: true do
expect do expect do
delete api("/#{source_type.pluralize}/#{source.id}/access_requests/#{access_requester.id}", access_requester) delete api("/#{source_type.pluralize}/#{source.id}/access_requests/#{access_requester.id}", access_requester)
expect(response).to have_http_status(200) expect(response).to have_http_status(204)
end.to change { source.requesters.count }.by(-1) end.to change { source.requesters.count }.by(-1)
end end
end end
...@@ -210,7 +210,7 @@ describe API::AccessRequests, api: true do ...@@ -210,7 +210,7 @@ describe API::AccessRequests, api: true do
expect do expect do
delete api("/#{source_type.pluralize}/#{source.id}/access_requests/#{access_requester.id}", master) delete api("/#{source_type.pluralize}/#{source.id}/access_requests/#{access_requester.id}", master)
expect(response).to have_http_status(200) expect(response).to have_http_status(204)
end.to change { source.requesters.count }.by(-1) end.to change { source.requesters.count }.by(-1)
end end
......
...@@ -242,9 +242,9 @@ describe API::AwardEmoji, api: true do ...@@ -242,9 +242,9 @@ describe API::AwardEmoji, api: true do
it 'deletes the award' do it 'deletes the award' do
expect do expect do
delete api("/projects/#{project.id}/issues/#{issue.id}/award_emoji/#{award_emoji.id}", user) delete api("/projects/#{project.id}/issues/#{issue.id}/award_emoji/#{award_emoji.id}", user)
end.to change { issue.award_emoji.count }.from(1).to(0)
expect(response).to have_http_status(200) expect(response).to have_http_status(204)
end.to change { issue.award_emoji.count }.from(1).to(0)
end end
it 'returns a 404 error when the award emoji can not be found' do it 'returns a 404 error when the award emoji can not be found' do
...@@ -258,9 +258,9 @@ describe API::AwardEmoji, api: true do ...@@ -258,9 +258,9 @@ describe API::AwardEmoji, api: true do
it 'deletes the award' do it 'deletes the award' do
expect do expect do
delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}/award_emoji/#{downvote.id}", user) delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}/award_emoji/#{downvote.id}", user)
end.to change { merge_request.award_emoji.count }.from(1).to(0)
expect(response).to have_http_status(200) expect(response).to have_http_status(204)
end.to change { merge_request.award_emoji.count }.from(1).to(0)
end end
it 'returns a 404 error when note id not found' do it 'returns a 404 error when note id not found' do
...@@ -277,9 +277,9 @@ describe API::AwardEmoji, api: true do ...@@ -277,9 +277,9 @@ describe API::AwardEmoji, api: true do
it 'deletes the award' do it 'deletes the award' do
expect do expect do
delete api("/projects/#{project.id}/snippets/#{snippet.id}/award_emoji/#{award.id}", user) delete api("/projects/#{project.id}/snippets/#{snippet.id}/award_emoji/#{award.id}", user)
end.to change { snippet.award_emoji.count }.from(1).to(0)
expect(response).to have_http_status(200) expect(response).to have_http_status(204)
end.to change { snippet.award_emoji.count }.from(1).to(0)
end end
end end
end end
...@@ -290,9 +290,9 @@ describe API::AwardEmoji, api: true do ...@@ -290,9 +290,9 @@ describe API::AwardEmoji, api: true do
it 'deletes the award' do it 'deletes the award' do
expect do expect do
delete api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji/#{rocket.id}", user) delete api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji/#{rocket.id}", user)
end.to change { note.award_emoji.count }.from(1).to(0)
expect(response).to have_http_status(200) expect(response).to have_http_status(204)
end.to change { note.award_emoji.count }.from(1).to(0)
end end
end end
end end
...@@ -195,8 +195,7 @@ describe API::Boards, api: true do ...@@ -195,8 +195,7 @@ describe API::Boards, api: true do
it "deletes the list if an admin requests it" do it "deletes the list if an admin requests it" do
delete api("#{base_url}/#{dev_list.id}", owner) delete api("#{base_url}/#{dev_list.id}", owner)
expect(response).to have_http_status(200) expect(response).to have_http_status(204)
expect(json_response['position']).to eq(1)
end end
end end
end end
......
...@@ -325,15 +325,14 @@ describe API::Branches, api: true do ...@@ -325,15 +325,14 @@ describe API::Branches, api: true do
it "removes branch" do it "removes branch" do
delete api("/projects/#{project.id}/repository/branches/#{branch_name}", user) delete api("/projects/#{project.id}/repository/branches/#{branch_name}", user)
expect(response).to have_http_status(200)
expect(json_response['branch']).to eq(branch_name) expect(response).to have_http_status(204)
end end
it "removes a branch with dots in the branch name" do it "removes a branch with dots in the branch name" do
delete api("/projects/#{project.id}/repository/branches/with.1.2.3", user) delete api("/projects/#{project.id}/repository/branches/with.1.2.3", user)
expect(response).to have_http_status(200) expect(response).to have_http_status(204)
expect(json_response['branch']).to eq("with.1.2.3")
end end
it 'returns 404 if branch not exists' do it 'returns 404 if branch not exists' do
......
...@@ -174,8 +174,11 @@ describe API::BroadcastMessages, api: true do ...@@ -174,8 +174,11 @@ describe API::BroadcastMessages, api: true do
end end
it 'deletes the broadcast message for admins' do it 'deletes the broadcast message for admins' do
expect { delete api("/broadcast_messages/#{message.id}", admin) } expect do
.to change { BroadcastMessage.count }.by(-1) delete api("/broadcast_messages/#{message.id}", admin)
expect(response).to have_http_status(204)
end.to change { BroadcastMessage.count }.by(-1)
end end
end end
end end
...@@ -116,6 +116,8 @@ describe API::DeployKeys, api: true do ...@@ -116,6 +116,8 @@ describe API::DeployKeys, api: true do
it 'should delete existing key' do it 'should delete existing key' do
expect do expect do
delete api("/projects/#{project.id}/deploy_keys/#{deploy_key.id}", admin) delete api("/projects/#{project.id}/deploy_keys/#{deploy_key.id}", admin)
expect(response).to have_http_status(204)
end.to change{ project.deploy_keys.count }.by(-1) end.to change{ project.deploy_keys.count }.by(-1)
end end
......
...@@ -122,7 +122,7 @@ describe API::Environments, api: true do ...@@ -122,7 +122,7 @@ describe API::Environments, api: true do
it 'returns a 200 for an existing environment' do it 'returns a 200 for an existing environment' do
delete api("/projects/#{project.id}/environments/#{environment.id}", user) delete api("/projects/#{project.id}/environments/#{environment.id}", user)
expect(response).to have_http_status(200) expect(response).to have_http_status(204)
end end
it 'returns a 404 for non existing id' do it 'returns a 404 for non existing id' do
......
...@@ -201,11 +201,7 @@ describe API::Files, api: true do ...@@ -201,11 +201,7 @@ describe API::Files, api: true do
it "deletes existing file in project repo" do it "deletes existing file in project repo" do
delete api("/projects/#{project.id}/repository/files", user), valid_params delete api("/projects/#{project.id}/repository/files", user), valid_params
expect(response).to have_http_status(200) expect(response).to have_http_status(204)
expect(json_response['file_path']).to eq(file_path)
last_commit = project.repository.commit.raw
expect(last_commit.author_email).to eq(user.email)
expect(last_commit.author_name).to eq(user.name)
end end
it "returns a 400 bad request if no params given" do it "returns a 400 bad request if no params given" do
...@@ -228,10 +224,7 @@ describe API::Files, api: true do ...@@ -228,10 +224,7 @@ describe API::Files, api: true do
delete api("/projects/#{project.id}/repository/files", user), valid_params delete api("/projects/#{project.id}/repository/files", user), valid_params
expect(response).to have_http_status(200) expect(response).to have_http_status(204)
last_commit = project.repository.commit.raw
expect(last_commit.author_email).to eq(author_email)
expect(last_commit.author_name).to eq(author_name)
end end
end end
end end
......
...@@ -467,7 +467,7 @@ describe API::Groups, api: true do ...@@ -467,7 +467,7 @@ describe API::Groups, api: true 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(204)
end end
it "does not remove a group if not an owner" do it "does not remove a group if not an owner" do
...@@ -496,7 +496,7 @@ describe API::Groups, api: true do ...@@ -496,7 +496,7 @@ describe API::Groups, api: true 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(204)
end end
it "does not remove a non existing group" do it "does not remove a non existing group" do
......
...@@ -1175,8 +1175,8 @@ describe API::Issues, api: true do ...@@ -1175,8 +1175,8 @@ describe API::Issues, api: true do
it "deletes the issue if an admin requests it" do it "deletes the issue if an admin requests it" do
delete api("/projects/#{project.id}/issues/#{issue.id}", owner) delete api("/projects/#{project.id}/issues/#{issue.id}", owner)
expect(response).to have_http_status(200)
expect(json_response['state']).to eq 'opened' expect(response).to have_http_status(204)
end end
end end
......
...@@ -175,9 +175,10 @@ describe API::Labels, api: true do ...@@ -175,9 +175,10 @@ describe API::Labels, api: true do
end end
describe 'DELETE /projects/:id/labels' do describe 'DELETE /projects/:id/labels' do
it 'returns 200 for existing label' do it 'returns 204 for existing label' do
delete api("/projects/#{project.id}/labels", user), name: 'label1' delete api("/projects/#{project.id}/labels", user), name: 'label1'
expect(response).to have_http_status(200)
expect(response).to have_http_status(204)
end end
it 'returns 404 for non existing label' do it 'returns 404 for non existing label' do
......
...@@ -263,18 +263,18 @@ describe API::Members, api: true do ...@@ -263,18 +263,18 @@ describe API::Members, api: true do
expect do expect do
delete api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", developer) delete api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", developer)
expect(response).to have_http_status(200) expect(response).to have_http_status(204)
end.to change { source.members.count }.by(-1) end.to change { source.members.count }.by(-1)
end end
end end
context 'when authenticated as a master/owner' do context 'when authenticated as a master/owner' do
context 'and member is a requester' do context 'and member is a requester' do
it "returns #{source_type == 'project' ? 200 : 404}" do it 'returns 404' do
expect do expect do
delete api("/#{source_type.pluralize}/#{source.id}/members/#{access_requester.id}", master) delete api("/#{source_type.pluralize}/#{source.id}/members/#{access_requester.id}", master)
expect(response).to have_http_status(source_type == 'project' ? 200 : 404) expect(response).to have_http_status(404)
end.not_to change { source.requesters.count } end.not_to change { source.requesters.count }
end end
end end
...@@ -283,15 +283,15 @@ describe API::Members, api: true do ...@@ -283,15 +283,15 @@ describe API::Members, api: true do
expect do expect do
delete api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", master) delete api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", master)
expect(response).to have_http_status(200) expect(response).to have_http_status(204)
end.to change { source.members.count }.by(-1) end.to change { source.members.count }.by(-1)
end end
end end
it "returns #{source_type == 'project' ? 200 : 404} if member does not exist" do it 'returns 404 if member does not exist' do
delete api("/#{source_type.pluralize}/#{source.id}/members/123", master) delete api("/#{source_type.pluralize}/#{source.id}/members/123", master)
expect(response).to have_http_status(source_type == 'project' ? 200 : 404) expect(response).to have_http_status(404)
end end
end end
end end
......
...@@ -411,7 +411,7 @@ describe API::MergeRequests, api: true do ...@@ -411,7 +411,7 @@ describe API::MergeRequests, api: true do
it "destroys the merge request owners can destroy" do it "destroys the merge request owners can destroy" do
delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user) delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user)
expect(response).to have_http_status(200) expect(response).to have_http_status(204)
end end
end end
end end
......
...@@ -373,7 +373,7 @@ describe API::Notes, api: true do ...@@ -373,7 +373,7 @@ describe API::Notes, api: true do
delete api("/projects/#{project.id}/issues/#{issue.id}/"\ delete api("/projects/#{project.id}/issues/#{issue.id}/"\
"notes/#{issue_note.id}", user) "notes/#{issue_note.id}", user)
expect(response).to have_http_status(200) expect(response).to have_http_status(204)
# Check if note is really deleted # Check if note is really deleted
delete api("/projects/#{project.id}/issues/#{issue.id}/"\ delete api("/projects/#{project.id}/issues/#{issue.id}/"\
"notes/#{issue_note.id}", user) "notes/#{issue_note.id}", user)
...@@ -392,7 +392,7 @@ describe API::Notes, api: true do ...@@ -392,7 +392,7 @@ describe API::Notes, api: true do
delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\ delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\
"notes/#{snippet_note.id}", user) "notes/#{snippet_note.id}", user)
expect(response).to have_http_status(200) expect(response).to have_http_status(204)
# Check if note is really deleted # Check if note is really deleted
delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\ delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\
"notes/#{snippet_note.id}", user) "notes/#{snippet_note.id}", user)
...@@ -412,7 +412,7 @@ describe API::Notes, api: true do ...@@ -412,7 +412,7 @@ describe API::Notes, api: true do
delete api("/projects/#{project.id}/merge_requests/"\ delete api("/projects/#{project.id}/merge_requests/"\
"#{merge_request.id}/notes/#{merge_request_note.id}", user) "#{merge_request.id}/notes/#{merge_request_note.id}", user)
expect(response).to have_http_status(200) expect(response).to have_http_status(204)
# Check if note is really deleted # Check if note is really deleted
delete api("/projects/#{project.id}/merge_requests/"\ delete api("/projects/#{project.id}/merge_requests/"\
"#{merge_request.id}/notes/#{merge_request_note.id}", user) "#{merge_request.id}/notes/#{merge_request_note.id}", user)
......
...@@ -183,13 +183,9 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do ...@@ -183,13 +183,9 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do
it "deletes hook from project" do it "deletes hook from project" do
expect do expect do
delete api("/projects/#{project.id}/hooks/#{hook.id}", user) delete api("/projects/#{project.id}/hooks/#{hook.id}", user)
end.to change {project.hooks.count}.by(-1)
expect(response).to have_http_status(200)
end
it "returns success when deleting hook" do expect(response).to have_http_status(204)
delete api("/projects/#{project.id}/hooks/#{hook.id}", user) end.to change {project.hooks.count}.by(-1)
expect(response).to have_http_status(200)
end end
it "returns a 404 error when deleting non existent hook" do it "returns a 404 error when deleting non existent hook" do
......
...@@ -189,7 +189,7 @@ describe API::ProjectSnippets, api: true do ...@@ -189,7 +189,7 @@ describe API::ProjectSnippets, api: true do
delete api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/", admin) delete api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/", admin)
expect(response).to have_http_status(200) expect(response).to have_http_status(204)
end end
it 'returns 404 for invalid snippet id' do it 'returns 404 for invalid snippet id' do
...@@ -212,7 +212,7 @@ describe API::ProjectSnippets, api: true do ...@@ -212,7 +212,7 @@ describe API::ProjectSnippets, api: true do
end end
it 'returns 404 for invalid snippet id' do it 'returns 404 for invalid snippet id' do
delete api("/projects/#{snippet.project.id}/snippets/1234", admin) get api("/projects/#{snippet.project.id}/snippets/1234/raw", admin)
expect(response).to have_http_status(404) expect(response).to have_http_status(404)
expect(json_response['message']).to eq('404 Snippet Not Found') expect(json_response['message']).to eq('404 Snippet Not Found')
......
...@@ -820,8 +820,9 @@ describe API::Projects, api: true do ...@@ -820,8 +820,9 @@ describe API::Projects, api: true do
it 'deletes existing project snippet' do it 'deletes existing project snippet' do
expect do expect do
delete api("/projects/#{project.id}/snippets/#{snippet.id}", user) delete api("/projects/#{project.id}/snippets/#{snippet.id}", user)
expect(response).to have_http_status(204)
end.to change { Snippet.count }.by(-1) end.to change { Snippet.count }.by(-1)
expect(response).to have_http_status(200)
end end
it 'returns 404 when deleting unknown snippet id' do it 'returns 404 when deleting unknown snippet id' do
...@@ -905,8 +906,10 @@ describe API::Projects, api: true do ...@@ -905,8 +906,10 @@ describe API::Projects, api: true do
project_fork_target.reload project_fork_target.reload
expect(project_fork_target.forked_from_project).not_to be_nil expect(project_fork_target.forked_from_project).not_to be_nil
expect(project_fork_target.forked?).to be_truthy expect(project_fork_target.forked?).to be_truthy
delete api("/projects/#{project_fork_target.id}/fork", admin) delete api("/projects/#{project_fork_target.id}/fork", admin)
expect(response).to have_http_status(200)
expect(response).to have_http_status(204)
project_fork_target.reload project_fork_target.reload
expect(project_fork_target.forked_from_project).to be_nil expect(project_fork_target.forked_from_project).to be_nil
expect(project_fork_target.forked?).not_to be_truthy expect(project_fork_target.forked?).not_to be_truthy
......
...@@ -123,6 +123,7 @@ describe API::Runner do ...@@ -123,6 +123,7 @@ describe API::Runner do
context 'when no token is provided' do context 'when no token is provided' do
it 'returns 400 error' do it 'returns 400 error' do
delete api('/runners') delete api('/runners')
expect(response).to have_http_status 400 expect(response).to have_http_status 400
end end
end end
...@@ -130,6 +131,7 @@ describe API::Runner do ...@@ -130,6 +131,7 @@ describe API::Runner do
context 'when invalid token is provided' do context 'when invalid token is provided' do
it 'returns 403 error' do it 'returns 403 error' do
delete api('/runners'), token: 'invalid' delete api('/runners'), token: 'invalid'
expect(response).to have_http_status 403 expect(response).to have_http_status 403
end end
end end
...@@ -139,7 +141,8 @@ describe API::Runner do ...@@ -139,7 +141,8 @@ describe API::Runner do
it 'deletes Runner' do it 'deletes Runner' do
delete api('/runners'), token: runner.token delete api('/runners'), token: runner.token
expect(response).to have_http_status 200
expect(response).to have_http_status 204
expect(Ci::Runner.count).to eq(0) expect(Ci::Runner.count).to eq(0)
end end
end end
......
...@@ -277,8 +277,9 @@ describe API::Runners, api: true do ...@@ -277,8 +277,9 @@ describe API::Runners, api: true do
it 'deletes runner' do it 'deletes runner' do
expect do expect do
delete api("/runners/#{shared_runner.id}", admin) delete api("/runners/#{shared_runner.id}", admin)
expect(response).to have_http_status(204)
end.to change{ Ci::Runner.shared.count }.by(-1) end.to change{ Ci::Runner.shared.count }.by(-1)
expect(response).to have_http_status(200)
end end
end end
...@@ -286,15 +287,17 @@ describe API::Runners, api: true do ...@@ -286,15 +287,17 @@ describe API::Runners, api: true do
it 'deletes unused runner' do it 'deletes unused runner' do
expect do expect do
delete api("/runners/#{unused_specific_runner.id}", admin) delete api("/runners/#{unused_specific_runner.id}", admin)
expect(response).to have_http_status(204)
end.to change{ Ci::Runner.specific.count }.by(-1) end.to change{ Ci::Runner.specific.count }.by(-1)
expect(response).to have_http_status(200)
end end
it 'deletes used runner' do it 'deletes used runner' do
expect do expect do
delete api("/runners/#{specific_runner.id}", admin) delete api("/runners/#{specific_runner.id}", admin)
expect(response).to have_http_status(204)
end.to change{ Ci::Runner.specific.count }.by(-1) end.to change{ Ci::Runner.specific.count }.by(-1)
expect(response).to have_http_status(200)
end end
end end
...@@ -327,8 +330,9 @@ describe API::Runners, api: true do ...@@ -327,8 +330,9 @@ describe API::Runners, api: true do
it 'deletes runner for one owned project' do it 'deletes runner for one owned project' do
expect do expect do
delete api("/runners/#{specific_runner.id}", user) delete api("/runners/#{specific_runner.id}", user)
expect(response).to have_http_status(204)
end.to change{ Ci::Runner.specific.count }.by(-1) end.to change{ Ci::Runner.specific.count }.by(-1)
expect(response).to have_http_status(200)
end end
end end
end end
...@@ -457,8 +461,9 @@ describe API::Runners, api: true do ...@@ -457,8 +461,9 @@ describe API::Runners, api: true do
it "disables project's runner" do it "disables project's runner" do
expect do expect do
delete api("/projects/#{project.id}/runners/#{two_projects_runner.id}", user) delete api("/projects/#{project.id}/runners/#{two_projects_runner.id}", user)
expect(response).to have_http_status(204)
end.to change{ project.runners.count }.by(-1) end.to change{ project.runners.count }.by(-1)
expect(response).to have_http_status(200)
end end
end end
......
...@@ -55,7 +55,7 @@ describe API::Services, api: true do ...@@ -55,7 +55,7 @@ describe API::Services, api: true do
it "deletes #{service}" do it "deletes #{service}" do
delete api("/projects/#{project.id}/services/#{dashed_service}", user) delete api("/projects/#{project.id}/services/#{dashed_service}", user)
expect(response).to have_http_status(200) expect(response).to have_http_status(204)
project.send(service_method).reload project.send(service_method).reload
expect(project.send(service_method).activated?).to be_falsey expect(project.send(service_method).activated?).to be_falsey
end end
......
...@@ -74,7 +74,7 @@ describe API::Snippets, api: true do ...@@ -74,7 +74,7 @@ describe API::Snippets, api: true do
end end
it 'returns 404 for invalid snippet id' do it 'returns 404 for invalid snippet id' do
delete api("/snippets/1234", user) get api("/snippets/1234/raw", user)
expect(response).to have_http_status(404) expect(response).to have_http_status(404)
expect(json_response['message']).to eq('404 Snippet Not Found') expect(json_response['message']).to eq('404 Snippet Not Found')
......
...@@ -91,6 +91,8 @@ describe API::SystemHooks, api: true do ...@@ -91,6 +91,8 @@ describe API::SystemHooks, api: true do
it "deletes a hook" do it "deletes a hook" do
expect do expect do
delete api("/hooks/#{hook.id}", admin) delete api("/hooks/#{hook.id}", admin)
expect(response).to have_http_status(204)
end.to change { SystemHook.count }.by(-1) end.to change { SystemHook.count }.by(-1)
end end
......
...@@ -137,8 +137,8 @@ describe API::Tags, api: true do ...@@ -137,8 +137,8 @@ describe API::Tags, api: true do
context 'delete tag' do context 'delete tag' do
it 'deletes an existing tag' do it 'deletes an existing tag' do
delete api("/projects/#{project.id}/repository/tags/#{tag_name}", user) delete api("/projects/#{project.id}/repository/tags/#{tag_name}", user)
expect(response).to have_http_status(200)
expect(json_response['tag_name']).to eq(tag_name) expect(response).to have_http_status(204)
end end
it 'raises 404 if the tag does not exist' do it 'raises 404 if the tag does not exist' do
......
...@@ -190,8 +190,9 @@ describe API::Triggers do ...@@ -190,8 +190,9 @@ describe API::Triggers do
it 'deletes trigger' do it 'deletes trigger' do
expect do expect do
delete api("/projects/#{project.id}/triggers/#{trigger.token}", user) delete api("/projects/#{project.id}/triggers/#{trigger.token}", user)
expect(response).to have_http_status(204)
end.to change{project.triggers.count}.by(-1) end.to change{project.triggers.count}.by(-1)
expect(response).to have_http_status(200)
end end
it 'responds with 404 Not Found if requesting non-existing trigger' do it 'responds with 404 Not Found if requesting non-existing trigger' do
......
...@@ -540,10 +540,12 @@ describe API::Users, api: true do ...@@ -540,10 +540,12 @@ describe API::Users, api: true do
it 'deletes existing key' do it 'deletes existing key' do
user.keys << key user.keys << key
user.save user.save
expect do expect do
delete api("/users/#{user.id}/keys/#{key.id}", admin) delete api("/users/#{user.id}/keys/#{key.id}", admin)
expect(response).to have_http_status(204)
end.to change { user.keys.count }.by(-1) end.to change { user.keys.count }.by(-1)
expect(response).to have_http_status(200)
end end
it 'returns 404 error if user not found' do it 'returns 404 error if user not found' do
...@@ -637,10 +639,12 @@ describe API::Users, api: true do ...@@ -637,10 +639,12 @@ describe API::Users, api: true do
it 'deletes existing email' do it 'deletes existing email' do
user.emails << email user.emails << email
user.save user.save
expect do expect do
delete api("/users/#{user.id}/emails/#{email.id}", admin) delete api("/users/#{user.id}/emails/#{email.id}", admin)
expect(response).to have_http_status(204)
end.to change { user.emails.count }.by(-1) end.to change { user.emails.count }.by(-1)
expect(response).to have_http_status(200)
end end
it 'returns 404 error if user not found' do it 'returns 404 error if user not found' do
...@@ -671,10 +675,10 @@ describe API::Users, api: true do ...@@ -671,10 +675,10 @@ describe API::Users, api: true do
it "deletes user" do it "deletes user" do
delete api("/users/#{user.id}", admin) delete api("/users/#{user.id}", admin)
expect(response).to have_http_status(200)
expect(response).to have_http_status(204)
expect { User.find(user.id) }.to raise_error ActiveRecord::RecordNotFound expect { User.find(user.id) }.to raise_error ActiveRecord::RecordNotFound
expect { Namespace.find(namespace.id) }.to raise_error ActiveRecord::RecordNotFound expect { Namespace.find(namespace.id) }.to raise_error ActiveRecord::RecordNotFound
expect(json_response['email']).to eq(user.email)
end end
it "does not delete for unauthenticated user" do it "does not delete for unauthenticated user" do
...@@ -869,10 +873,12 @@ describe API::Users, api: true do ...@@ -869,10 +873,12 @@ describe API::Users, api: true do
it "deletes existed key" do it "deletes existed key" do
user.keys << key user.keys << key
user.save user.save
expect do expect do
delete api("/user/keys/#{key.id}", user) delete api("/user/keys/#{key.id}", user)
expect(response).to have_http_status(204)
end.to change{user.keys.count}.by(-1) end.to change{user.keys.count}.by(-1)
expect(response).to have_http_status(200)
end end
it "returns 404 if key ID not found" do it "returns 404 if key ID not found" do
...@@ -976,10 +982,12 @@ describe API::Users, api: true do ...@@ -976,10 +982,12 @@ describe API::Users, api: true do
it "deletes existed email" do it "deletes existed email" do
user.emails << email user.emails << email
user.save user.save
expect do expect do
delete api("/user/emails/#{email.id}", user) delete api("/user/emails/#{email.id}", user)
expect(response).to have_http_status(204)
end.to change{user.emails.count}.by(-1) end.to change{user.emails.count}.by(-1)
expect(response).to have_http_status(200)
end end
it "returns 404 if email ID not found" do it "returns 404 if email ID not found" do
......
require 'spec_helper'
describe API::V3::AwardEmoji, api: true do
include ApiHelpers
let(:user) { create(:user) }
let!(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
let!(:award_emoji) { create(:award_emoji, awardable: issue, user: user) }
let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
let!(:downvote) { create(:award_emoji, :downvote, awardable: merge_request, user: user) }
let!(:note) { create(:note, project: project, noteable: issue) }
before { project.team << [user, :master] }
describe 'DELETE /projects/:id/awardable/:awardable_id/award_emoji/:award_id' do
context 'when the awardable is an Issue' do
it 'deletes the award' do
expect do
delete v3_api("/projects/#{project.id}/issues/#{issue.id}/award_emoji/#{award_emoji.id}", user)
expect(response).to have_http_status(200)
end.to change { issue.award_emoji.count }.from(1).to(0)
end
it 'returns a 404 error when the award emoji can not be found' do
delete v3_api("/projects/#{project.id}/issues/#{issue.id}/award_emoji/12345", user)
expect(response).to have_http_status(404)
end
end
context 'when the awardable is a Merge Request' do
it 'deletes the award' do
expect do
delete v3_api("/projects/#{project.id}/merge_requests/#{merge_request.id}/award_emoji/#{downvote.id}", user)
expect(response).to have_http_status(200)
end.to change { merge_request.award_emoji.count }.from(1).to(0)
end
it 'returns a 404 error when note id not found' do
delete v3_api("/projects/#{project.id}/merge_requests/#{merge_request.id}/notes/12345", user)
expect(response).to have_http_status(404)
end
end
context 'when the awardable is a Snippet' do
let(:snippet) { create(:project_snippet, :public, project: project) }
let!(:award) { create(:award_emoji, awardable: snippet, user: user) }
it 'deletes the award' do
expect do
delete v3_api("/projects/#{project.id}/snippets/#{snippet.id}/award_emoji/#{award.id}", user)
expect(response).to have_http_status(200)
end.to change { snippet.award_emoji.count }.from(1).to(0)
end
end
end
describe 'DELETE /projects/:id/awardable/:awardable_id/award_emoji/:award_emoji_id' do
let!(:rocket) { create(:award_emoji, awardable: note, name: 'rocket', user: user) }
it 'deletes the award' do
expect do
delete v3_api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji/#{rocket.id}", user)
expect(response).to have_http_status(200)
end.to change { note.award_emoji.count }.from(1).to(0)
end
end
end
...@@ -5,6 +5,7 @@ describe API::V3::Boards, api: true do ...@@ -5,6 +5,7 @@ describe API::V3::Boards, api: true do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:guest) { create(:user) } let(:guest) { create(:user) }
let(:non_member) { create(:user) }
let!(:project) { create(:empty_project, :public, creator_id: user.id, namespace: user.namespace ) } let!(:project) { create(:empty_project, :public, creator_id: user.id, namespace: user.namespace ) }
let!(:dev_label) do let!(:dev_label) do
...@@ -76,4 +77,37 @@ describe API::V3::Boards, api: true do ...@@ -76,4 +77,37 @@ describe API::V3::Boards, api: true do
expect(response).to have_http_status(404) expect(response).to have_http_status(404)
end end
end end
describe "DELETE /projects/:id/board/lists/:list_id" do
let(:base_url) { "/projects/#{project.id}/boards/#{board.id}/lists" }
it "rejects a non member from deleting a list" do
delete v3_api("#{base_url}/#{dev_list.id}", non_member)
expect(response).to have_http_status(403)
end
it "rejects a user with guest role from deleting a list" do
delete v3_api("#{base_url}/#{dev_list.id}", guest)
expect(response).to have_http_status(403)
end
it "returns 404 error if list id not found" do
delete v3_api("#{base_url}/44444", user)
expect(response).to have_http_status(404)
end
context "when the user is project owner" do
let(:owner) { create(:user) }
let(:project) { create(:empty_project, namespace: owner.namespace) }
it "deletes the list if an admin requests it" do
delete v3_api("#{base_url}/#{dev_list.id}", owner)
expect(response).to have_http_status(200)
end
end
end
end end
...@@ -5,8 +5,12 @@ describe API::V3::Branches, api: true do ...@@ -5,8 +5,12 @@ describe API::V3::Branches, api: true do
include ApiHelpers include ApiHelpers
let(:user) { create(:user) } let(:user) { create(:user) }
let(:user2) { create(:user) }
let!(:project) { create(:project, :repository, creator: user) } let!(:project) { create(:project, :repository, creator: user) }
let!(:master) { create(:project_member, :master, user: user, project: project) } let!(:master) { create(:project_member, :master, user: user, project: project) }
let!(:guest) { create(:project_member, :guest, user: user2, project: project) }
let!(:branch_name) { 'feature' }
let!(:branch_with_dot) { CreateBranchService.new(project, user).execute("with.1.2.3", "master") }
describe "GET /projects/:id/repository/branches" do describe "GET /projects/:id/repository/branches" do
it "returns an array of project branches" do it "returns an array of project branches" do
...@@ -21,6 +25,44 @@ describe API::V3::Branches, api: true do ...@@ -21,6 +25,44 @@ describe API::V3::Branches, api: true do
end end
end end
describe "DELETE /projects/:id/repository/branches/:branch" do
before do
allow_any_instance_of(Repository).to receive(:rm_branch).and_return(true)
end
it "removes branch" do
delete v3_api("/projects/#{project.id}/repository/branches/#{branch_name}", user)
expect(response).to have_http_status(200)
expect(json_response['branch_name']).to eq(branch_name)
end
it "removes a branch with dots in the branch name" do
delete v3_api("/projects/#{project.id}/repository/branches/with.1.2.3", user)
expect(response).to have_http_status(200)
expect(json_response['branch_name']).to eq("with.1.2.3")
end
it 'returns 404 if branch not exists' do
delete v3_api("/projects/#{project.id}/repository/branches/foobar", user)
expect(response).to have_http_status(404)
end
it "removes protected branch" do
create(:protected_branch, project: project, name: branch_name)
delete v3_api("/projects/#{project.id}/repository/branches/#{branch_name}", user)
expect(response).to have_http_status(405)
expect(json_response['message']).to eq('Protected branch cant be removed')
end
it "does not remove HEAD branch" do
delete v3_api("/projects/#{project.id}/repository/branches/master", user)
expect(response).to have_http_status(405)
expect(json_response['message']).to eq('Cannot remove HEAD branch')
end
end
describe "DELETE /projects/:id/repository/merged_branches" do describe "DELETE /projects/:id/repository/merged_branches" do
before do before do
allow_any_instance_of(Repository).to receive(:rm_branch).and_return(true) allow_any_instance_of(Repository).to receive(:rm_branch).and_return(true)
...@@ -33,10 +75,7 @@ describe API::V3::Branches, api: true do ...@@ -33,10 +75,7 @@ describe API::V3::Branches, api: true do
end end
it 'returns a 403 error if guest' do it 'returns a 403 error if guest' do
user_b = create :user delete v3_api("/projects/#{project.id}/repository/merged_branches", user2)
create(:project_member, :guest, user: user_b, project: project)
delete v3_api("/projects/#{project.id}/repository/merged_branches", user_b)
expect(response).to have_http_status(403) expect(response).to have_http_status(403)
end end
......
require 'spec_helper'
describe API::V3::BroadcastMessages, api: true do
include ApiHelpers
let(:user) { create(:user) }
let(:admin) { create(:admin) }
describe 'DELETE /broadcast_messages/:id' do
let!(:message) { create(:broadcast_message) }
it 'returns a 401 for anonymous users' do
delete v3_api("/broadcast_messages/#{message.id}"),
attributes_for(:broadcast_message)
expect(response).to have_http_status(401)
end
it 'returns a 403 for users' do
delete v3_api("/broadcast_messages/#{message.id}", user),
attributes_for(:broadcast_message)
expect(response).to have_http_status(403)
end
it 'deletes the broadcast message for admins' do
expect do
delete v3_api("/broadcast_messages/#{message.id}", admin)
expect(response).to have_http_status(200)
end.to change { BroadcastMessage.count }.by(-1)
end
end
end
require 'spec_helper'
describe API::V3::Environments, api: true do
include ApiHelpers
let(:user) { create(:user) }
let(:non_member) { create(:user) }
let(:project) { create(:empty_project, :private, namespace: user.namespace) }
let!(:environment) { create(:environment, project: project) }
before do
project.team << [user, :master]
end
describe 'DELETE /projects/:id/environments/:environment_id' do
context 'as a master' do
it 'returns a 200 for an existing environment' do
delete v3_api("/projects/#{project.id}/environments/#{environment.id}", user)
expect(response).to have_http_status(200)
end
it 'returns a 404 for non existing id' do
delete v3_api("/projects/#{project.id}/environments/12345", user)
expect(response).to have_http_status(404)
expect(json_response['message']).to eq('404 Not found')
end
end
context 'a non member' do
it 'rejects the request' do
delete v3_api("/projects/#{project.id}/environments/#{environment.id}", non_member)
expect(response).to have_http_status(404)
end
end
end
end
...@@ -2,17 +2,6 @@ require 'spec_helper' ...@@ -2,17 +2,6 @@ require 'spec_helper'
describe API::V3::Files, api: true do describe API::V3::Files, api: true do
include ApiHelpers include ApiHelpers
let(:user) { create(:user) }
let!(:project) { create(:project, :repository, namespace: user.namespace ) }
let(:guest) { create(:user) { |u| project.add_guest(u) } }
let(:file_path) { 'files/ruby/popen.rb' }
let(:params) do
{
file_path: file_path,
ref: 'master'
}
end
let(:author_email) { FFaker::Internet.email }
# I have to remove periods from the end of the name # I have to remove periods from the end of the name
# This happened when the user's name had a suffix (i.e. "Sr.") # This happened when the user's name had a suffix (i.e. "Sr.")
...@@ -26,6 +15,18 @@ describe API::V3::Files, api: true do ...@@ -26,6 +15,18 @@ describe API::V3::Files, api: true do
# ... # ...
# Author: Foo Sr <foo@example.com> # Author: Foo Sr <foo@example.com>
# ... # ...
let(:user) { create(:user) }
let!(:project) { create(:project, :repository, namespace: user.namespace ) }
let(:guest) { create(:user) { |u| project.add_guest(u) } }
let(:file_path) { 'files/ruby/popen.rb' }
let(:params) do
{
file_path: file_path,
ref: 'master'
}
end
let(:author_email) { FFaker::Internet.email }
let(:author_name) { FFaker::Name.name.chomp("\.") } let(:author_name) { FFaker::Name.name.chomp("\.") }
before { project.team << [user, :developer] } before { project.team << [user, :developer] }
......
...@@ -149,4 +149,23 @@ describe API::V3::Labels, api: true do ...@@ -149,4 +149,23 @@ describe API::V3::Labels, api: true do
end end
end end
end end
describe 'DELETE /projects/:id/labels' do
it 'returns 200 for existing label' do
delete v3_api("/projects/#{project.id}/labels", user), name: 'label1'
expect(response).to have_http_status(200)
end
it 'returns 404 for non existing label' do
delete v3_api("/projects/#{project.id}/labels", user), name: 'label2'
expect(response).to have_http_status(404)
expect(json_response['message']).to eq('404 Label Not Found')
end
it 'returns 400 for wrong parameters' do
delete v3_api("/projects/#{project.id}/labels", user)
expect(response).to have_http_status(400)
end
end
end end
require 'spec_helper' require 'spec_helper'
describe API::Members, api: true do describe API::V3::Members, api: true do
include ApiHelpers include ApiHelpers
let(:master) { create(:user) } let(:master) { create(:user) }
......
...@@ -2,6 +2,7 @@ require 'spec_helper' ...@@ -2,6 +2,7 @@ require 'spec_helper'
describe API::V3::Notes, api: true do describe API::V3::Notes, api: true do
include ApiHelpers include ApiHelpers
let(:user) { create(:user) } let(:user) { create(:user) }
let!(:project) { create(:empty_project, :public, namespace: user.namespace) } let!(:project) { create(:empty_project, :public, namespace: user.namespace) }
let!(:issue) { create(:issue, project: project, author: user) } let!(:issue) { create(:issue, project: project, author: user) }
...@@ -373,12 +374,12 @@ describe API::V3::Notes, api: true do ...@@ -373,12 +374,12 @@ describe API::V3::Notes, api: true do
context 'when noteable is an Issue' do context 'when noteable is an Issue' do
it 'deletes a note' do it 'deletes a note' do
delete v3_api("/projects/#{project.id}/issues/#{issue.id}/"\ delete v3_api("/projects/#{project.id}/issues/#{issue.id}/"\
"notes/#{issue_note.id}", user) "notes/#{issue_note.id}", user)
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
# Check if note is really deleted # Check if note is really deleted
delete v3_api("/projects/#{project.id}/issues/#{issue.id}/"\ delete v3_api("/projects/#{project.id}/issues/#{issue.id}/"\
"notes/#{issue_note.id}", user) "notes/#{issue_note.id}", user)
expect(response).to have_http_status(404) expect(response).to have_http_status(404)
end end
...@@ -392,18 +393,18 @@ describe API::V3::Notes, api: true do ...@@ -392,18 +393,18 @@ describe API::V3::Notes, api: true do
context 'when noteable is a Snippet' do context 'when noteable is a Snippet' do
it 'deletes a note' do it 'deletes a note' do
delete v3_api("/projects/#{project.id}/snippets/#{snippet.id}/"\ delete v3_api("/projects/#{project.id}/snippets/#{snippet.id}/"\
"notes/#{snippet_note.id}", user) "notes/#{snippet_note.id}", user)
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
# Check if note is really deleted # Check if note is really deleted
delete v3_api("/projects/#{project.id}/snippets/#{snippet.id}/"\ delete v3_api("/projects/#{project.id}/snippets/#{snippet.id}/"\
"notes/#{snippet_note.id}", user) "notes/#{snippet_note.id}", user)
expect(response).to have_http_status(404) expect(response).to have_http_status(404)
end end
it 'returns a 404 error when note id not found' do it 'returns a 404 error when note id not found' do
delete v3_api("/projects/#{project.id}/snippets/#{snippet.id}/"\ delete v3_api("/projects/#{project.id}/snippets/#{snippet.id}/"\
"notes/12345", user) "notes/12345", user)
expect(response).to have_http_status(404) expect(response).to have_http_status(404)
end end
...@@ -412,18 +413,18 @@ describe API::V3::Notes, api: true do ...@@ -412,18 +413,18 @@ describe API::V3::Notes, api: true do
context 'when noteable is a Merge Request' do context 'when noteable is a Merge Request' do
it 'deletes a note' do it 'deletes a note' do
delete v3_api("/projects/#{project.id}/merge_requests/"\ delete v3_api("/projects/#{project.id}/merge_requests/"\
"#{merge_request.id}/notes/#{merge_request_note.id}", user) "#{merge_request.id}/notes/#{merge_request_note.id}", user)
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
# Check if note is really deleted # Check if note is really deleted
delete v3_api("/projects/#{project.id}/merge_requests/"\ delete v3_api("/projects/#{project.id}/merge_requests/"\
"#{merge_request.id}/notes/#{merge_request_note.id}", user) "#{merge_request.id}/notes/#{merge_request_note.id}", user)
expect(response).to have_http_status(404) expect(response).to have_http_status(404)
end end
it 'returns a 404 error when note id not found' do it 'returns a 404 error when note id not found' do
delete v3_api("/projects/#{project.id}/merge_requests/"\ delete v3_api("/projects/#{project.id}/merge_requests/"\
"#{merge_request.id}/notes/12345", user) "#{merge_request.id}/notes/12345", user)
expect(response).to have_http_status(404) expect(response).to have_http_status(404)
end end
......
require 'spec_helper'
describe API::V3::Runners, api: true do
include ApiHelpers
let(:admin) { create(:user, :admin) }
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:project) { create(:empty_project, creator_id: user.id) }
let(:project2) { create(:empty_project, creator_id: user.id) }
let!(:shared_runner) { create(:ci_runner, :shared) }
let!(:unused_specific_runner) { create(:ci_runner) }
let!(:specific_runner) do
create(:ci_runner).tap do |runner|
create(:ci_runner_project, runner: runner, project: project)
end
end
let!(:two_projects_runner) do
create(:ci_runner).tap do |runner|
create(:ci_runner_project, runner: runner, project: project)
create(:ci_runner_project, runner: runner, project: project2)
end
end
before do
# Set project access for users
create(:project_member, :master, user: user, project: project)
create(:project_member, :reporter, user: user2, project: project)
end
describe 'DELETE /runners/:id' do
context 'admin user' do
context 'when runner is shared' do
it 'deletes runner' do
expect do
delete v3_api("/runners/#{shared_runner.id}", admin)
expect(response).to have_http_status(200)
end.to change{ Ci::Runner.shared.count }.by(-1)
end
end
context 'when runner is not shared' do
it 'deletes unused runner' do
expect do
delete v3_api("/runners/#{unused_specific_runner.id}", admin)
expect(response).to have_http_status(200)
end.to change{ Ci::Runner.specific.count }.by(-1)
end
it 'deletes used runner' do
expect do
delete v3_api("/runners/#{specific_runner.id}", admin)
expect(response).to have_http_status(200)
end.to change{ Ci::Runner.specific.count }.by(-1)
end
end
it 'returns 404 if runner does not exists' do
delete v3_api('/runners/9999', admin)
expect(response).to have_http_status(404)
end
end
context 'authorized user' do
context 'when runner is shared' do
it 'does not delete runner' do
delete v3_api("/runners/#{shared_runner.id}", user)
expect(response).to have_http_status(403)
end
end
context 'when runner is not shared' do
it 'does not delete runner without access to it' do
delete v3_api("/runners/#{specific_runner.id}", user2)
expect(response).to have_http_status(403)
end
it 'does not delete runner with more than one associated project' do
delete v3_api("/runners/#{two_projects_runner.id}", user)
expect(response).to have_http_status(403)
end
it 'deletes runner for one owned project' do
expect do
delete v3_api("/runners/#{specific_runner.id}", user)
expect(response).to have_http_status(200)
end.to change{ Ci::Runner.specific.count }.by(-1)
end
end
end
context 'unauthorized user' do
it 'does not delete runner' do
delete v3_api("/runners/#{specific_runner.id}")
expect(response).to have_http_status(401)
end
end
end
describe 'DELETE /projects/:id/runners/:runner_id' do
context 'authorized user' do
context 'when runner have more than one associated projects' do
it "disables project's runner" do
expect do
delete v3_api("/projects/#{project.id}/runners/#{two_projects_runner.id}", user)
expect(response).to have_http_status(200)
end.to change{ project.runners.count }.by(-1)
end
end
context 'when runner have one associated projects' do
it "does not disable project's runner" do
expect do
delete v3_api("/projects/#{project.id}/runners/#{specific_runner.id}", user)
end.to change{ project.runners.count }.by(0)
expect(response).to have_http_status(403)
end
end
it 'returns 404 is runner is not found' do
delete v3_api("/projects/#{project.id}/runners/9999", user)
expect(response).to have_http_status(404)
end
end
context 'authorized user without permissions' do
it "does not disable project's runner" do
delete v3_api("/projects/#{project.id}/runners/#{specific_runner.id}", user2)
expect(response).to have_http_status(403)
end
end
context 'unauthorized user' do
it "does not disable project's runner" do
delete v3_api("/projects/#{project.id}/runners/#{specific_runner.id}")
expect(response).to have_http_status(401)
end
end
end
end
require "spec_helper"
describe API::V3::Services, api: true do
include ApiHelpers
let(:user) { create(:user) }
let(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) }
Service.available_services_names.each do |service|
describe "DELETE /projects/:id/services/#{service.dasherize}" do
include_context service
it "deletes #{service}" do
delete v3_api("/projects/#{project.id}/services/#{dashed_service}", user)
expect(response).to have_http_status(200)
project.send(service_method).reload
expect(project.send(service_method).activated?).to be_falsey
end
end
end
end
...@@ -38,4 +38,20 @@ describe API::V3::SystemHooks, api: true do ...@@ -38,4 +38,20 @@ describe API::V3::SystemHooks, api: true do
end end
end end
end end
describe "DELETE /hooks/:id" do
it "deletes a hook" do
expect do
delete v3_api("/hooks/#{hook.id}", admin)
expect(response).to have_http_status(200)
end.to change { SystemHook.count }.by(-1)
end
it 'returns 404 if the system hook does not exist' do
delete v3_api('/hooks/12345', admin)
expect(response).to have_http_status(404)
end
end
end end
...@@ -64,4 +64,26 @@ describe API::V3::Tags, api: true do ...@@ -64,4 +64,26 @@ describe API::V3::Tags, api: true do
end end
end end
end end
describe 'DELETE /projects/:id/repository/tags/:tag_name' do
let(:tag_name) { project.repository.tag_names.sort.reverse.first }
before do
allow_any_instance_of(Repository).to receive(:rm_tag).and_return(true)
end
context 'delete tag' do
it 'deletes an existing tag' do
delete v3_api("/projects/#{project.id}/repository/tags/#{tag_name}", user)
expect(response).to have_http_status(200)
expect(json_response['tag_name']).to eq(tag_name)
end
it 'raises 404 if the tag does not exist' do
delete v3_api("/projects/#{project.id}/repository/tags/foobar", user)
expect(response).to have_http_status(404)
end
end
end
end end
require 'spec_helper'
describe API::V3::Triggers do
include ApiHelpers
let(:user) { create(:user) }
let(:user2) { create(:user) }
let!(:trigger_token) { 'secure_token' }
let!(:project) { create(:project, :repository, creator: user) }
let!(:master) { create(:project_member, :master, user: user, project: project) }
let!(:developer) { create(:project_member, :developer, user: user2, project: project) }
let!(:trigger) { create(:ci_trigger, project: project, token: trigger_token) }
describe 'DELETE /projects/:id/triggers/:token' do
context 'authenticated user with valid permissions' do
it 'deletes trigger' do
expect do
delete v3_api("/projects/#{project.id}/triggers/#{trigger.token}", user)
expect(response).to have_http_status(200)
end.to change{project.triggers.count}.by(-1)
end
it 'responds with 404 Not Found if requesting non-existing trigger' do
delete v3_api("/projects/#{project.id}/triggers/abcdef012345", user)
expect(response).to have_http_status(404)
end
end
context 'authenticated user with invalid permissions' do
it 'does not delete trigger' do
delete v3_api("/projects/#{project.id}/triggers/#{trigger.token}", user2)
expect(response).to have_http_status(403)
end
end
context 'unauthenticated user' do
it 'does not delete trigger' do
delete v3_api("/projects/#{project.id}/triggers/#{trigger.token}")
expect(response).to have_http_status(401)
end
end
end
end
...@@ -152,8 +152,9 @@ describe API::Variables, api: true do ...@@ -152,8 +152,9 @@ describe API::Variables, api: true do
it 'deletes variable' do it 'deletes variable' do
expect do expect do
delete api("/projects/#{project.id}/variables/#{variable.key}", user) delete api("/projects/#{project.id}/variables/#{variable.key}", user)
expect(response).to have_http_status(204)
end.to change{project.variables.count}.by(-1) end.to change{project.variables.count}.by(-1)
expect(response).to have_http_status(200)
end end
it 'responds with 404 Not Found if requesting non-existing variable' do it 'responds with 404 Not Found if requesting non-existing variable' do
......
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