summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZ.J. van de Weg <zegerjan@gitlab.com>2016-06-17 15:44:38 +0200
committerZ.J. van de Weg <zegerjan@gitlab.com>2016-06-17 19:56:54 +0200
commit71c59b82989399ac48fc29372ba40f97730aec83 (patch)
tree4798f459490009733c9e7401eebe624811d9da30
parent49dce334664b1c6ce7c0f73c342010945fefc9fe (diff)
downloadgitlab-ce-api-endpoints-award-emoji.tar.gz
Add endpoints for award emoji on notesapi-endpoints-award-emoji
Docs also added.
-rw-r--r--doc/api/award_emoji.md204
-rw-r--r--lib/api/api.rb1
-rw-r--r--lib/api/award_emoji.rb151
-rw-r--r--spec/requests/api/award_emoji_spec.rb57
4 files changed, 340 insertions, 73 deletions
diff --git a/doc/api/award_emoji.md b/doc/api/award_emoji.md
new file mode 100644
index 00000000000..ecabc5dc7b8
--- /dev/null
+++ b/doc/api/award_emoji.md
@@ -0,0 +1,204 @@
+# Award Emoji
+
+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 MergeRequests
+
+### List an awardables emoji awards
+
+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 -X GET -H "PRIVATE-TOKEN: ir6jesYP_Am5DPy7d1y7" 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://localhost:3000/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://localhost:3000/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 -X GET -H "PRIVATE-TOKEN: ir6jesYP_Am5DPy7d1y7" 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://localhost:3000/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: ir6jesYP_Am5DPy7d1y7" 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://localhost:3000/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: ir6jesYP_Am5DPy7d1y7" http://localhost:3000/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://localhost:3000/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 end points mentioned above are available for notes too. Notes are a sub
+resource of both Issues and MergeRequests. The endpoints changes, for example,
+to receive all awards on an issue the endpoint would be:
+`/projects/:id/issues/:issue_id/award_emoji`, for the note it would be:
+`/projects/:id/issues/:issue_id/notes/:note_id/award_emoji`. Thus after the
+resource you'd add `notes/:note_id`.
+
+Parameters stay the same, only the note id has to be added in the URI.
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 7d25d7cf490..8f2efae9fa1 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -26,7 +26,6 @@ module API
# Ensure the namespace is right, otherwise we might load Grape::API::Helpers
helpers ::API::Helpers
- # Sort these alphabetically
mount ::API::AwardEmoji
mount ::API::Branches
mount ::API::Builds
diff --git a/lib/api/award_emoji.rb b/lib/api/award_emoji.rb
index a7949b9e11d..985590312e3 100644
--- a/lib/api/award_emoji.rb
+++ b/lib/api/award_emoji.rb
@@ -1,7 +1,6 @@
module API
class AwardEmoji < Grape::API
before { authenticate! }
-
AWARDABLES = [Issue, MergeRequest]
resource :projects do
@@ -9,93 +8,109 @@ module API
awardable_string = awardable_type.to_s.underscore.pluralize
awardable_id_string = "#{awardable_type.to_s.underscore}_id"
- # 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 ":id/#{awardable_string}/:#{awardable_id_string}/award_emoji" do
- awardable = user_project.send(awardable_string.to_sym).find(params[awardable_id_string])
+ [ ":id/#{awardable_string}/:#{awardable_id_string}/award_emoji",
+ ":id/#{awardable_string}/:#{awardable_id_string}/notes/:note_id/award_emoji"
+ ].each do |endpoint|
- if can_read_awardable?(awardable)
- awards = paginate(awardable.award_emoji)
- present awards, with: Entities::AwardEmoji
- else
- not_found!("Award Emoji")
+ # 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
- 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 ":id/#{awardable_string}/:#{awardable_id_string}/award_emoji/:award_id" do
- awardable = user_project.send(awardable_string.to_sym).find(params[awardable_id_string.to_sym])
- if can_read_awardable?(awardable)
- present awardable.award_emoji.find(params[:award_id]), with: Entities::AwardEmoji
- else
- not_found!("Award Emoji")
+ # 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
- 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/notes
- post ":id/#{awardable_string}/:#{awardable_id_string}/award_emoji" do
- required_attributes! [:name]
+ # 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]
- awardable = user_project.send(awardable_string.to_sym).find(params[awardable_id_string.to_sym])
- not_found!('Award Emoji') unless can_read_awardable?(awardable)
+ not_found!('Award Emoji') unless can_read_awardable?
- award = awardable.award_emoji.new(name: params[:name], user: current_user)
+ 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}")
+ if award.save
+ present award, with: Entities::AwardEmoji
+ else
+ not_found!("Award Emoji #{award.errors.messages}")
+ end
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/:noteable_id/notes/:note_id
- delete ":id/#{awardable_string}/:#{awardable_id_string}/award_emoji/:award_id" do
- awardable = user_project.send(awardable_string.to_sym).find(params[awardable_id_string.to_sym])
- award = awardable.award_emoji.find(params[:award_id])
+ # 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?
+ unauthorized! unless award.user == current_user || current_user.admin?
- award.destroy
- present award, with: Entities::AwardEmoji
+ award.destroy
+ present award, with: Entities::AwardEmoji
+ end
end
end
end
- helpers do
- def awardable_read_ability_name(awardable)
- end
- def can_read_awardable?(awardable)
+ 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
diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb
index 49964cb51de..5359873476c 100644
--- a/spec/requests/api/award_emoji_spec.rb
+++ b/spec/requests/api/award_emoji_spec.rb
@@ -5,9 +5,10 @@ describe API::API, api: true do
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!(: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] }
@@ -49,6 +50,19 @@ describe API::API, api: true do
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
@@ -89,6 +103,18 @@ describe API::API, api: true do
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
@@ -113,7 +139,18 @@ describe API::API, api: true do
end
end
- describe 'DELETE /projects/:id/awardable/:awardable_id/award_emoji/:award_emoji_id' do
+ 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
@@ -146,4 +183,16 @@ describe API::API, api: true do
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