Merge branch 'api-endpoints-award-emoji' into 'master'
API endpoints for award emoji Closes #10884 See merge request !4575
This commit is contained in:
commit
6980489ca8
|
@ -48,6 +48,7 @@ v 8.9.0 (unreleased)
|
|||
- Upgrade to jQuery 2
|
||||
- Adds selected branch name to the dropdown toggle
|
||||
- Add API endpoint for Sidekiq Metrics !4653
|
||||
- Refactoring Award Emoji with API support for Issues and MergeRequests
|
||||
- Use Knapsack to evenly distribute tests across multiple nodes
|
||||
- Add `sha` parameter to MR merge API, to ensure only reviewed changes are merged
|
||||
- Don't allow MRs to be merged when commits were added since the last review / page load
|
||||
|
|
|
@ -8,6 +8,7 @@ under [`/lib/api`](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/lib/api).
|
|||
Documentation for various API resources can be found separately in the
|
||||
following locations:
|
||||
|
||||
- [Award Emoji](award_emoji.md)
|
||||
- [Branches](branches.md)
|
||||
- [Builds](builds.md)
|
||||
- [Build triggers](build_triggers.md)
|
||||
|
@ -44,10 +45,10 @@ The following documentation is for the [internal CI API](ci/README.md):
|
|||
|
||||
## Authentication
|
||||
|
||||
All API requests require authentication via a token. There are three types of tokens
|
||||
All API requests require authentication via a token. There are three types of tokens
|
||||
available: private tokens, OAuth 2 tokens, and personal access tokens.
|
||||
|
||||
If a token is invalid or omitted, an error message will be returned with
|
||||
If a token is invalid or omitted, an error message will be returned with
|
||||
status code `401`:
|
||||
|
||||
```json
|
||||
|
@ -58,8 +59,8 @@ status code `401`:
|
|||
|
||||
### Private Tokens
|
||||
|
||||
You need to pass a `private_token` parameter via query string or header. If passed as a
|
||||
header, the header name must be `PRIVATE-TOKEN` (uppercase and with a dash instead of
|
||||
You need to pass a `private_token` parameter via query string or header. If passed as a
|
||||
header, the header name must be `PRIVATE-TOKEN` (uppercase and with a dash instead of
|
||||
an underscore). You can find or reset your private token in your account page
|
||||
(`/profile/account`).
|
||||
|
||||
|
@ -80,7 +81,7 @@ Read more about [GitLab as an OAuth2 client](oauth2.md).
|
|||
|
||||
> **Note:** This feature was [introduced][ce-3749] in GitLab 8.8
|
||||
|
||||
You can create as many personal access tokens as you like from your GitLab
|
||||
You can create as many personal access tokens as you like from your GitLab
|
||||
profile (`/profile/personal_access_tokens`); perhaps one for each application
|
||||
that needs access to the GitLab API.
|
||||
|
||||
|
|
|
@ -0,0 +1,367 @@
|
|||
# Award Emoji
|
||||
|
||||
>**Note:** This feature was introduced in GitLab 8.9
|
||||
|
||||
An awarded emoji tells a thousand words, and can be awarded on issues, merge
|
||||
requests and notes/comments. Issues, merge requests and notes are further called
|
||||
`awardables`.
|
||||
|
||||
## Issues and merge requests
|
||||
|
||||
### List an awardable's award emoji
|
||||
|
||||
Gets a list of all award emoji
|
||||
|
||||
```
|
||||
GET /projects/:id/issues/:issue_id/award_emoji
|
||||
GET /projects/:id/merge_requests/:merge_request_id/award_emoji
|
||||
```
|
||||
|
||||
Parameters:
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer | yes | The ID of a project |
|
||||
| `awardable_id` | integer | yes | The ID of an awardable |
|
||||
|
||||
```bash
|
||||
curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" http://gitlab.example.com/api/v3/projects/1/issues/80/award_emoji
|
||||
```
|
||||
|
||||
Example Response:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 4,
|
||||
"name": "1234",
|
||||
"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/u/root"
|
||||
},
|
||||
"created_at": "2016-06-15T10:09:34.206Z",
|
||||
"updated_at": "2016-06-15T10:09:34.206Z",
|
||||
"awardable_id": 80,
|
||||
"awardable_type": "Issue"
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "microphone",
|
||||
"user": {
|
||||
"name": "User 4",
|
||||
"username": "user4",
|
||||
"id": 26,
|
||||
"state": "active",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/7e65550957227bd38fe2d7fbc6fd2f7b?s=80&d=identicon",
|
||||
"web_url": "http://gitlab.example.com/u/user4"
|
||||
},
|
||||
"created_at": "2016-06-15T10:09:34.177Z",
|
||||
"updated_at": "2016-06-15T10:09:34.177Z",
|
||||
"awardable_id": 80,
|
||||
"awardable_type": "Issue"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Get single issue note
|
||||
|
||||
Gets a single award emoji
|
||||
|
||||
```
|
||||
GET /projects/:id/issues/:issue_id/award_emoji/:award_id
|
||||
GET /projects/:id/merge_requests/:merge_request_id/award_emoji/:award_id
|
||||
```
|
||||
|
||||
Parameters:
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer | yes | The ID of a project |
|
||||
| `awardable_id` | integer | yes | The ID of an awardable |
|
||||
| `award_id` | integer | yes | The ID of the award emoji |
|
||||
|
||||
```bash
|
||||
curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" http://gitlab.example.com/api/v3/projects/1/issues/80/award_emoji/1
|
||||
```
|
||||
|
||||
Example Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"name": "microphone",
|
||||
"user": {
|
||||
"name": "User 4",
|
||||
"username": "user4",
|
||||
"id": 26,
|
||||
"state": "active",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/7e65550957227bd38fe2d7fbc6fd2f7b?s=80&d=identicon",
|
||||
"web_url": "http://gitlab.example.com/u/user4"
|
||||
},
|
||||
"created_at": "2016-06-15T10:09:34.177Z",
|
||||
"updated_at": "2016-06-15T10:09:34.177Z",
|
||||
"awardable_id": 80,
|
||||
"awardable_type": "Issue"
|
||||
}
|
||||
```
|
||||
|
||||
### Award a new emoji
|
||||
|
||||
This end point creates an award emoji on the specified resource
|
||||
|
||||
```
|
||||
POST /projects/:id/issues/:issue_id/award_emoji
|
||||
POST /projects/:id/merge_requests/:merge_request_id/award_emoji
|
||||
```
|
||||
|
||||
Parameters:
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer | yes | The ID of a project |
|
||||
| `awardable_id` | integer | yes | The ID of an awardable |
|
||||
| `name` | string | yes | The name of the emoji, without colons |
|
||||
|
||||
```bash
|
||||
curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" http://gitlab.example.com/api/v3/projects/1/issues/80/award_emoji?name=blowfish
|
||||
```
|
||||
|
||||
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/u/root"
|
||||
},
|
||||
"created_at": "2016-06-17T17:47:29.266Z",
|
||||
"updated_at": "2016-06-17T17:47:29.266Z",
|
||||
"awardable_id": 80,
|
||||
"awardable_type": "Issue"
|
||||
}
|
||||
```
|
||||
|
||||
### Delete an award emoji
|
||||
|
||||
Sometimes its just not meant to be, and you'll have to remove your award. Only available to
|
||||
admins or the author of the award. Status code 200 on success, 401 if unauthorized.
|
||||
|
||||
```
|
||||
DELETE /projects/:id/issues/:issue_id/award_emoji/:award_id
|
||||
DELETE /projects/:id/merge_requests/:merge_request_id/award_emoji/:award_id
|
||||
```
|
||||
|
||||
Parameters:
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer | yes | The ID of a project |
|
||||
| `issue_id` | integer | yes | The ID of an issue |
|
||||
| `award_id` | integer | yes | The ID of a award_emoji |
|
||||
|
||||
```bash
|
||||
curl -X DELETE -H "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/u/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
|
||||
|
||||
The endpoints documented above are available for Notes as well. Notes
|
||||
are a sub-resource of Issues and Merge Requests. The examples below
|
||||
describe working with Award Emoji on notes for an Issue, but can be
|
||||
easily adapted for notes on a Merge Request.
|
||||
|
||||
### List a note's award emoji
|
||||
|
||||
```
|
||||
GET /projects/:id/issues/:issue_id/notes/:note_id/award_emoji
|
||||
```
|
||||
|
||||
Parameters:
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer | yes | The ID of a project |
|
||||
| `issue_id` | integer | yes | The ID of an issue |
|
||||
| `note_id` | integer | yes | The ID of an note |
|
||||
|
||||
|
||||
```bash
|
||||
curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" http://gitlab.example.com/api/v3/projects/1/issues/80/notes/1/award_emoji
|
||||
```
|
||||
|
||||
Example Response:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 2,
|
||||
"name": "mood_bubble_lightning",
|
||||
"user": {
|
||||
"name": "User 4",
|
||||
"username": "user4",
|
||||
"id": 26,
|
||||
"state": "active",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/7e65550957227bd38fe2d7fbc6fd2f7b?s=80&d=identicon",
|
||||
"web_url": "http://gitlab.example.com/u/user4"
|
||||
},
|
||||
"created_at": "2016-06-15T10:09:34.197Z",
|
||||
"updated_at": "2016-06-15T10:09:34.197Z",
|
||||
"awardable_id": 1,
|
||||
"awardable_type": "Note"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Get single note's award emoji
|
||||
|
||||
```
|
||||
GET /projects/:id/issues/:issue_id/notes/:note_id/award_emoji/:award_id
|
||||
```
|
||||
|
||||
Parameters:
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer | yes | The ID of a project |
|
||||
| `issue_id` | integer | yes | The ID of an issue |
|
||||
| `note_id` | integer | yes | The ID of a note |
|
||||
| `award_id` | integer | yes | The ID of the award emoji |
|
||||
|
||||
```bash
|
||||
curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" http://gitlab.example.com/api/v3/projects/1/issues/80/notes/1/award_emoji/2
|
||||
```
|
||||
|
||||
Example Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 2,
|
||||
"name": "mood_bubble_lightning",
|
||||
"user": {
|
||||
"name": "User 4",
|
||||
"username": "user4",
|
||||
"id": 26,
|
||||
"state": "active",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/7e65550957227bd38fe2d7fbc6fd2f7b?s=80&d=identicon",
|
||||
"web_url": "http://gitlab.example.com/u/user4"
|
||||
},
|
||||
"created_at": "2016-06-15T10:09:34.197Z",
|
||||
"updated_at": "2016-06-15T10:09:34.197Z",
|
||||
"awardable_id": 1,
|
||||
"awardable_type": "Note"
|
||||
}
|
||||
```
|
||||
|
||||
### Award a new emoji on a note
|
||||
|
||||
```
|
||||
POST /projects/:id/issues/:issue_id/notes/:note_id/award_emoji
|
||||
```
|
||||
|
||||
Parameters:
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer | yes | The ID of a project |
|
||||
| `issue_id` | integer | yes | The ID of an issue |
|
||||
| `note_id` | integer | yes | The ID of a note |
|
||||
| `name` | string | yes | The name of the emoji, without colons |
|
||||
|
||||
```bash
|
||||
curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" http://gitlab.example.com/api/v3/projects/1/issues/80/notes/1/award_emoji?name=rocket
|
||||
```
|
||||
|
||||
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/u/root"
|
||||
},
|
||||
"created_at": "2016-06-17T19:59:55.888Z",
|
||||
"updated_at": "2016-06-17T19:59:55.888Z",
|
||||
"awardable_id": 1,
|
||||
"awardable_type": "Note"
|
||||
}
|
||||
```
|
||||
|
||||
### Delete an award emoji
|
||||
|
||||
Sometimes its just not meant to be, and you'll have to remove your award. Only available to
|
||||
admins or the author of the award. Status code 200 on success, 401 if unauthorized.
|
||||
|
||||
```
|
||||
DELETE /projects/:id/issues/:issue_id/notes/:note_id/award_emoji/:award_id
|
||||
```
|
||||
|
||||
Parameters:
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer | yes | The ID of a project |
|
||||
| `issue_id` | integer | yes | The ID of an issue |
|
||||
| `note_id` | integer | yes | The ID of a note |
|
||||
| `award_id` | integer | yes | The ID of a award_emoji |
|
||||
|
||||
```bash
|
||||
curl -X DELETE -H "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/u/root"
|
||||
},
|
||||
"created_at": "2016-06-17T19:59:55.888Z",
|
||||
"updated_at": "2016-06-17T19:59:55.888Z",
|
||||
"awardable_id": 1,
|
||||
"awardable_type": "Note"
|
||||
}
|
||||
```
|
|
@ -26,39 +26,40 @@ module API
|
|||
# Ensure the namespace is right, otherwise we might load Grape::API::Helpers
|
||||
helpers ::API::Helpers
|
||||
|
||||
mount ::API::Groups
|
||||
mount ::API::AwardEmoji
|
||||
mount ::API::Branches
|
||||
mount ::API::Builds
|
||||
mount ::API::CommitStatuses
|
||||
mount ::API::Commits
|
||||
mount ::API::DeployKeys
|
||||
mount ::API::Files
|
||||
mount ::API::Gitignores
|
||||
mount ::API::GroupMembers
|
||||
mount ::API::Users
|
||||
mount ::API::Groups
|
||||
mount ::API::Internal
|
||||
mount ::API::Issues
|
||||
mount ::API::Keys
|
||||
mount ::API::Labels
|
||||
mount ::API::Licenses
|
||||
mount ::API::MergeRequests
|
||||
mount ::API::Milestones
|
||||
mount ::API::Namespaces
|
||||
mount ::API::Notes
|
||||
mount ::API::ProjectHooks
|
||||
mount ::API::ProjectMembers
|
||||
mount ::API::ProjectSnippets
|
||||
mount ::API::Projects
|
||||
mount ::API::Repositories
|
||||
mount ::API::Issues
|
||||
mount ::API::Milestones
|
||||
mount ::API::Session
|
||||
mount ::API::MergeRequests
|
||||
mount ::API::Notes
|
||||
mount ::API::Internal
|
||||
mount ::API::SystemHooks
|
||||
mount ::API::ProjectSnippets
|
||||
mount ::API::ProjectMembers
|
||||
mount ::API::DeployKeys
|
||||
mount ::API::ProjectHooks
|
||||
mount ::API::Runners
|
||||
mount ::API::Services
|
||||
mount ::API::Files
|
||||
mount ::API::Commits
|
||||
mount ::API::CommitStatuses
|
||||
mount ::API::Namespaces
|
||||
mount ::API::Branches
|
||||
mount ::API::Labels
|
||||
mount ::API::Session
|
||||
mount ::API::Settings
|
||||
mount ::API::Keys
|
||||
mount ::API::SidekiqMetrics
|
||||
mount ::API::Subscriptions
|
||||
mount ::API::SystemHooks
|
||||
mount ::API::Tags
|
||||
mount ::API::Triggers
|
||||
mount ::API::Builds
|
||||
mount ::API::Users
|
||||
mount ::API::Variables
|
||||
mount ::API::Runners
|
||||
mount ::API::Licenses
|
||||
mount ::API::Subscriptions
|
||||
mount ::API::Gitignores
|
||||
mount ::API::SidekiqMetrics
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
module API
|
||||
class AwardEmoji < Grape::API
|
||||
before { authenticate! }
|
||||
AWARDABLES = [Issue, MergeRequest]
|
||||
|
||||
resource :projects do
|
||||
AWARDABLES.each do |awardable_type|
|
||||
awardable_string = awardable_type.to_s.underscore.pluralize
|
||||
awardable_id_string = "#{awardable_type.to_s.underscore}_id"
|
||||
|
||||
[ ":id/#{awardable_string}/:#{awardable_id_string}/award_emoji",
|
||||
":id/#{awardable_string}/:#{awardable_id_string}/notes/:note_id/award_emoji"
|
||||
].each do |endpoint|
|
||||
|
||||
# Get a list of project +awardable+ award emoji
|
||||
#
|
||||
# Parameters:
|
||||
# id (required) - The ID of a project
|
||||
# awardable_id (required) - The ID of an issue or MR
|
||||
# Example Request:
|
||||
# GET /projects/:id/issues/:awardable_id/award_emoji
|
||||
get endpoint do
|
||||
if can_read_awardable?
|
||||
awards = paginate(awardable.award_emoji)
|
||||
present awards, with: Entities::AwardEmoji
|
||||
else
|
||||
not_found!("Award Emoji")
|
||||
end
|
||||
end
|
||||
|
||||
# Get a specific award emoji
|
||||
#
|
||||
# Parameters:
|
||||
# id (required) - The ID of a project
|
||||
# awardable_id (required) - The ID of an issue or MR
|
||||
# award_id (required) - The ID of the award
|
||||
# Example Request:
|
||||
# GET /projects/:id/issues/:awardable_id/award_emoji/:award_id
|
||||
get "#{endpoint}/:award_id" do
|
||||
if can_read_awardable?
|
||||
present awardable.award_emoji.find(params[:award_id]), with: Entities::AwardEmoji
|
||||
else
|
||||
not_found!("Award Emoji")
|
||||
end
|
||||
end
|
||||
|
||||
# Award a new Emoji
|
||||
#
|
||||
# Parameters:
|
||||
# id (required) - The ID of a project
|
||||
# awardable_id (required) - The ID of an issue or mr
|
||||
# name (required) - The name of a award_emoji (without colons)
|
||||
# Example Request:
|
||||
# POST /projects/:id/issues/:awardable_id/award_emoji
|
||||
post endpoint do
|
||||
required_attributes! [:name]
|
||||
|
||||
not_found!('Award Emoji') unless can_read_awardable?
|
||||
|
||||
award = awardable.award_emoji.new(name: params[:name], user: current_user)
|
||||
|
||||
if award.save
|
||||
present award, with: Entities::AwardEmoji
|
||||
else
|
||||
not_found!("Award Emoji #{award.errors.messages}")
|
||||
end
|
||||
end
|
||||
|
||||
# Delete a +awardables+ award emoji
|
||||
#
|
||||
# Parameters:
|
||||
# id (required) - The ID of a project
|
||||
# awardable_id (required) - The ID of an issue or MR
|
||||
# award_emoji_id (required) - The ID of an award emoji
|
||||
# Example Request:
|
||||
# DELETE /projects/:id/issues/:issue_id/notes/:note_id/award_emoji/:award_id
|
||||
delete "#{endpoint}/:award_id" do
|
||||
award = awardable.award_emoji.find(params[:award_id])
|
||||
|
||||
unauthorized! unless award.user == current_user || current_user.admin?
|
||||
|
||||
award.destroy
|
||||
present award, with: Entities::AwardEmoji
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
helpers do
|
||||
def can_read_awardable?
|
||||
ability = "read_#{awardable.class.to_s.underscore}".to_sym
|
||||
|
||||
can?(current_user, ability, awardable)
|
||||
end
|
||||
|
||||
def awardable
|
||||
@awardable ||=
|
||||
begin
|
||||
if params.include?(:note_id)
|
||||
noteable.notes.find(params[:note_id])
|
||||
else
|
||||
noteable
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def noteable
|
||||
if params.include?(:issue_id)
|
||||
user_project.issues.find(params[:issue_id])
|
||||
else
|
||||
user_project.merge_requests.find(params[:merge_request_id])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -225,6 +225,14 @@ module API
|
|||
expose(:downvote?) { |note| false }
|
||||
end
|
||||
|
||||
class AwardEmoji < Grape::Entity
|
||||
expose :id
|
||||
expose :name
|
||||
expose :user, using: Entities::UserBasic
|
||||
expose :created_at, :updated_at
|
||||
expose :awardable_id, :awardable_type
|
||||
end
|
||||
|
||||
class MRNote < Grape::Entity
|
||||
expose :note
|
||||
expose :author, using: Entities::UserBasic
|
||||
|
|
|
@ -144,7 +144,7 @@ module API
|
|||
|
||||
helpers do
|
||||
def noteable_read_ability_name(noteable)
|
||||
"read_#{noteable.class.to_s.underscore.downcase}".to_sym
|
||||
"read_#{noteable.class.to_s.underscore}".to_sym
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe API::API, api: true do
|
||||
include ApiHelpers
|
||||
let(:user) { create(:user) }
|
||||
let!(:project) { create(:project) }
|
||||
let(:issue) { create(:issue, project: project, author: user) }
|
||||
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 "GET /projects/:id/awardable/:awardable_id/award_emoji" do
|
||||
context 'on an issue' do
|
||||
it "returns an array of award_emoji" do
|
||||
get api("/projects/#{project.id}/issues/#{issue.id}/award_emoji", user)
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(json_response).to be_an Array
|
||||
expect(json_response.first['name']).to eq(award_emoji.name)
|
||||
end
|
||||
|
||||
it "should return a 404 error when issue id not found" do
|
||||
get api("/projects/#{project.id}/issues/12345/award_emoji", user)
|
||||
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'on a merge request' do
|
||||
it "returns an array of award_emoji" do
|
||||
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/award_emoji", user)
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(json_response).to be_an Array
|
||||
expect(json_response.first['name']).to eq(downvote.name)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user has no access' do
|
||||
it 'returns a status code 404' do
|
||||
user1 = create(:user)
|
||||
|
||||
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/award_emoji", user1)
|
||||
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /projects/:id/awardable/:awardable_id/notes/:note_id/award_emoji' do
|
||||
let!(:rocket) { create(:award_emoji, awardable: note, name: 'rocket') }
|
||||
|
||||
it 'returns an array of award emoji' do
|
||||
get api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji", user)
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(json_response).to be_an Array
|
||||
expect(json_response.first['name']).to eq(rocket.name)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "GET /projects/:id/awardable/:awardable_id/award_emoji/:award_id" do
|
||||
context 'on an issue' do
|
||||
it "returns the award emoji" do
|
||||
get api("/projects/#{project.id}/issues/#{issue.id}/award_emoji/#{award_emoji.id}", user)
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(json_response['name']).to eq(award_emoji.name)
|
||||
expect(json_response['awardable_id']).to eq(issue.id)
|
||||
expect(json_response['awardable_type']).to eq("Issue")
|
||||
end
|
||||
|
||||
it "returns a 404 error if the award is not found" do
|
||||
get api("/projects/#{project.id}/issues/#{issue.id}/award_emoji/12345", user)
|
||||
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'on a merge request' do
|
||||
it 'returns the award emoji' do
|
||||
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/award_emoji/#{downvote.id}", user)
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(json_response['name']).to eq(downvote.name)
|
||||
expect(json_response['awardable_id']).to eq(merge_request.id)
|
||||
expect(json_response['awardable_type']).to eq("MergeRequest")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user has no access' do
|
||||
it 'returns a status code 404' do
|
||||
user1 = create(:user)
|
||||
|
||||
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/award_emoji/#{downvote.id}", user1)
|
||||
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /projects/:id/awardable/:awardable_id/notes/:note_id/award_emoji/:award_id' do
|
||||
let!(:rocket) { create(:award_emoji, awardable: note, name: 'rocket') }
|
||||
|
||||
it 'returns an award emoji' do
|
||||
get api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji/#{rocket.id}", user)
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(json_response).not_to be_an Array
|
||||
expect(json_response['name']).to eq(rocket.name)
|
||||
end
|
||||
end
|
||||
|
||||
describe "POST /projects/:id/awardable/:awardable_id/award_emoji" do
|
||||
context "on an issue" do
|
||||
it "creates a new award emoji" do
|
||||
post api("/projects/#{project.id}/issues/#{issue.id}/award_emoji", user), name: 'blowfish'
|
||||
|
||||
expect(response.status).to eq(201)
|
||||
expect(json_response['name']).to eq('blowfish')
|
||||
expect(json_response['user']['username']).to eq(user.username)
|
||||
end
|
||||
|
||||
it "should return a 400 bad request error if the name is not given" do
|
||||
post api("/projects/#{project.id}/issues/#{issue.id}/award_emoji", user)
|
||||
|
||||
expect(response.status).to eq(400)
|
||||
end
|
||||
|
||||
it "should return a 401 unauthorized error if the user is not authenticated" do
|
||||
post api("/projects/#{project.id}/issues/#{issue.id}/award_emoji"), name: 'thumbsup'
|
||||
|
||||
expect(response.status).to eq(401)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "POST /projects/:id/awardable/:awardable_id/notes/:note_id/award_emoji" do
|
||||
it 'creates a new award emoji' do
|
||||
expect do
|
||||
post api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji", user), name: 'rocket'
|
||||
end.to change { note.award_emoji.count }.from(0).to(1)
|
||||
|
||||
expect(response.status).to eq(201)
|
||||
expect(json_response['user']['username']).to eq(user.username)
|
||||
end
|
||||
end
|
||||
|
||||
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 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.status).to eq(200)
|
||||
end
|
||||
|
||||
it 'returns a 404 error when the award emoji can not be found' do
|
||||
delete api("/projects/#{project.id}/issues/#{issue.id}/award_emoji/12345", user)
|
||||
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the awardable is a Merge Request' do
|
||||
it 'deletes the award' do
|
||||
expect do
|
||||
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.status).to eq(200)
|
||||
end
|
||||
|
||||
it 'returns a 404 error when note id not found' do
|
||||
delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}/notes/12345", user)
|
||||
|
||||
expect(response.status).to eq(404)
|
||||
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 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.status).to eq(200)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue