API: Ability to subscribe and unsubscribe from an issue
This commit is contained in:
parent
861e685e18
commit
bd0be13f5b
5 changed files with 197 additions and 0 deletions
|
@ -11,6 +11,7 @@ v 8.7.0 (unreleased)
|
||||||
- Fix `signed_in_ip` being set to 127.0.0.1 when using a reverse proxy !3524
|
- Fix `signed_in_ip` being set to 127.0.0.1 when using a reverse proxy !3524
|
||||||
- Improved Markdown rendering performance !3389 (Yorick Peterse)
|
- Improved Markdown rendering performance !3389 (Yorick Peterse)
|
||||||
- Don't attempt to look up an avatar in repo if repo directory does not exist (Stan Hu)
|
- Don't attempt to look up an avatar in repo if repo directory does not exist (Stan Hu)
|
||||||
|
- API: Ability to subscribe and unsubscribe from an issue (Robert Schilling)
|
||||||
- Expose project badges in project settings
|
- Expose project badges in project settings
|
||||||
- Preserve time notes/comments have been updated at when moving issue
|
- Preserve time notes/comments have been updated at when moving issue
|
||||||
- Make HTTP(s) label consistent on clone bar (Stan Hu)
|
- Make HTTP(s) label consistent on clone bar (Stan Hu)
|
||||||
|
|
|
@ -406,6 +406,114 @@ Example response:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Subscribe to an issue
|
||||||
|
|
||||||
|
Subscribes to an issue to receive notifications. If the operation is successful,
|
||||||
|
status code `201` together with the updated issue is returned. If the user is
|
||||||
|
already subscribed to the issue, the status code `304` is returned. If the
|
||||||
|
project or issue is not found, status code `404` is returned.
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /projects/:id/issues/:issue_id/subscribe
|
||||||
|
```
|
||||||
|
|
||||||
|
| Attribute | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `id` | integer | yes | The ID of a project |
|
||||||
|
| `issue_id` | integer | yes | The ID of a project's issue |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/issues/93/subscribe
|
||||||
|
```
|
||||||
|
|
||||||
|
Example response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 92,
|
||||||
|
"iid": 11,
|
||||||
|
"project_id": 5,
|
||||||
|
"title": "Sit voluptas tempora quisquam aut doloribus et.",
|
||||||
|
"description": "Repellat voluptas quibusdam voluptatem exercitationem.",
|
||||||
|
"state": "opened",
|
||||||
|
"created_at": "2016-04-05T21:41:45.652Z",
|
||||||
|
"updated_at": "2016-04-07T12:20:17.596Z",
|
||||||
|
"labels": [],
|
||||||
|
"milestone": null,
|
||||||
|
"assignee": {
|
||||||
|
"name": "Miss Monserrate Beier",
|
||||||
|
"username": "axel.block",
|
||||||
|
"id": 12,
|
||||||
|
"state": "active",
|
||||||
|
"avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
|
||||||
|
"web_url": "https://gitlab.example.com/u/axel.block"
|
||||||
|
},
|
||||||
|
"author": {
|
||||||
|
"name": "Kris Steuber",
|
||||||
|
"username": "solon.cremin",
|
||||||
|
"id": 10,
|
||||||
|
"state": "active",
|
||||||
|
"avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon",
|
||||||
|
"web_url": "https://gitlab.example.com/u/solon.cremin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Unsubscribe from an issue
|
||||||
|
|
||||||
|
Unsubscribes from an issue to not receive notifications from that issue. If the
|
||||||
|
operation is successful, status code `201` together with the updated issue is
|
||||||
|
returned. If the user is not subscribed to the issue, the status code `304`
|
||||||
|
is returned. If the project or issue is not found, status code `404` is
|
||||||
|
returned.
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /projects/:id/issues/:issue_id/unsubscribe
|
||||||
|
```
|
||||||
|
|
||||||
|
| Attribute | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `id` | integer | yes | The ID of a project |
|
||||||
|
| `issue_id` | integer | yes | The ID of a project's issue |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST -H "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/u/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": "http://lgitlab.example.com/u/orville"
|
||||||
|
},
|
||||||
|
"subscribed": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Comments on issues
|
## Comments on issues
|
||||||
|
|
||||||
Comments are done via the [notes](notes.md) resource.
|
Comments are done via the [notes](notes.md) resource.
|
||||||
|
|
|
@ -241,6 +241,10 @@ module API
|
||||||
render_api_error!('413 Request Entity Too Large', 413)
|
render_api_error!('413 Request Entity Too Large', 413)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def not_modified!
|
||||||
|
render_api_error!('304 Not modified', 304)
|
||||||
|
end
|
||||||
|
|
||||||
def render_validation_error!(model)
|
def render_validation_error!(model)
|
||||||
if model.errors.any?
|
if model.errors.any?
|
||||||
render_api_error!(model.errors.messages || '400 Bad Request', 400)
|
render_api_error!(model.errors.messages || '400 Bad Request', 400)
|
||||||
|
|
|
@ -231,6 +231,59 @@ module API
|
||||||
authorize!(:destroy_issue, issue)
|
authorize!(:destroy_issue, issue)
|
||||||
issue.destroy
|
issue.destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Subscribes to a project issue
|
||||||
|
#
|
||||||
|
# Parameters:
|
||||||
|
# id (required) - The ID of a project
|
||||||
|
# issue_id (required) - The ID of a project issue
|
||||||
|
# Example Request:
|
||||||
|
# POST /projects/:id/issues/:issue_id
|
||||||
|
post ":id/issues/:issue_idsubscribe" do
|
||||||
|
issue = user_project.issues.find_by(id: params[:issue_id])
|
||||||
|
|
||||||
|
if !issue.subscribed?(current_user)
|
||||||
|
present issue, with: Entities::Issue, current_user: current_user
|
||||||
|
else
|
||||||
|
not_modified!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Subscribes to a project issue
|
||||||
|
#
|
||||||
|
# Parameters:
|
||||||
|
# id (required) - The ID of a project
|
||||||
|
# issue_id (required) - The ID of a project issue
|
||||||
|
# Example Request:
|
||||||
|
# POST /projects/:id/issues/:issue_id/subscribe
|
||||||
|
post ":id/issues/:issue_id/subscribe" do
|
||||||
|
issue = user_project.issues.find_by(id: params[:issue_id])
|
||||||
|
|
||||||
|
if !issue.subscribed?(current_user)
|
||||||
|
issue.toggle_subscription(current_user)
|
||||||
|
present issue, with: Entities::Issue, current_user: current_user
|
||||||
|
else
|
||||||
|
not_modified!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Unsubscribes from a project issue
|
||||||
|
#
|
||||||
|
# Parameters:
|
||||||
|
# id (required) - The ID of a project
|
||||||
|
# issue_id (required) - The ID of a project issue
|
||||||
|
# Example Request:
|
||||||
|
# POST /projects/:id/issues/:issue_id/unsubscribe
|
||||||
|
post ":id/issues/:issue_id/unsubscribe" do
|
||||||
|
issue = user_project.issues.find_by(id: params[:issue_id])
|
||||||
|
|
||||||
|
if issue.subscribed?(current_user)
|
||||||
|
issue.unsubscribe(current_user)
|
||||||
|
present issue, with: Entities::Issue, current_user: current_user
|
||||||
|
else
|
||||||
|
not_modified!
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,6 +3,7 @@ require 'spec_helper'
|
||||||
describe API::API, api: true do
|
describe API::API, api: true do
|
||||||
include ApiHelpers
|
include ApiHelpers
|
||||||
let(:user) { create(:user) }
|
let(:user) { create(:user) }
|
||||||
|
let(:user2) { create(:user) }
|
||||||
let(:non_member) { create(:user) }
|
let(:non_member) { create(:user) }
|
||||||
let(:author) { create(:author) }
|
let(:author) { create(:author) }
|
||||||
let(:assignee) { create(:assignee) }
|
let(:assignee) { create(:assignee) }
|
||||||
|
@ -569,4 +570,34 @@ describe API::API, api: true do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'POST :id/issues/:issue_id/subscribe' do
|
||||||
|
it 'subscribes to an issue' do
|
||||||
|
post api("/projects/#{project.id}/issues/#{issue.id}/subscribe", user2)
|
||||||
|
|
||||||
|
expect(response.status).to eq(201)
|
||||||
|
expect(json_response['subscribed']).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns 304 if already subscribed' do
|
||||||
|
post api("/projects/#{project.id}/issues/#{issue.id}/subscribe", user)
|
||||||
|
|
||||||
|
expect(response.status).to eq(304)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'POST :id/issues/:issue_id/unsubscribe' do
|
||||||
|
it 'unsubscribes from an issue' do
|
||||||
|
post api("/projects/#{project.id}/issues/#{issue.id}/unsubscribe", user)
|
||||||
|
|
||||||
|
expect(response.status).to eq(201)
|
||||||
|
expect(json_response['subscribed']).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns 304 if not subscribed' do
|
||||||
|
post api("/projects/#{project.id}/issues/#{issue.id}/unsubscribe", user2)
|
||||||
|
|
||||||
|
expect(response.status).to eq(304)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue