summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZ.J. van de Weg <zegerjan@gitlab.com>2016-06-08 09:33:41 +0200
committerZ.J. van de Weg <zegerjan@gitlab.com>2016-06-17 20:07:17 +0200
commit3f88221c2dcb1c42cc2f5a765d2586f1755128c3 (patch)
tree80f246dc0c3bbc848225cfbbea973c69bad44c1e
parent6c37e0f61774e4f0c7dff7830055233b3ab2726b (diff)
downloadgitlab-ce-3f88221c2dcb1c42cc2f5a765d2586f1755128c3.tar.gz
Add endpoints for Award Emoji
This only supports Issues and MergeRequests right now because of the consistency of the routes those models provide.
-rw-r--r--lib/api/api.rb1
-rw-r--r--lib/api/award_emoji.rb97
-rw-r--r--lib/api/entities.rb8
-rw-r--r--lib/api/issues.rb2
-rw-r--r--spec/requests/api/award_emoji_spec.rb149
5 files changed, 256 insertions, 1 deletions
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 51ddd0dbfc4..7944c80cf7a 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -36,6 +36,7 @@ module API
mount ::API::Session
mount ::API::MergeRequests
mount ::API::Notes
+ mount ::API::AwardEmoji
mount ::API::Internal
mount ::API::SystemHooks
mount ::API::ProjectSnippets
diff --git a/lib/api/award_emoji.rb b/lib/api/award_emoji.rb
new file mode 100644
index 00000000000..26b30d30163
--- /dev/null
+++ b/lib/api/award_emoji.rb
@@ -0,0 +1,97 @@
+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"
+
+ # 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.to_sym])
+
+ if can?(current_user, awardable_read_ability_name(awardable), 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 ":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?(current_user, awardable_read_ability_name(awardable), 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
+ # noteable_id (required) - The ID of an issue or snippet
+ # name (required) - The name of a award_emoji (without colons)
+ # Example Request:
+ # POST /projects/:id/issues/:noteable_id/notes
+ # POST /projects/:id/snippets/:noteable_id/notes
+ post ":id/#{awardable_string}/:#{awardable_id_string}/award_emoji" 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?(current_user, awardable_read_ability_name(awardable), 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/: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])
+
+ unauthorized! unless award.user == current_user || current_user.admin?
+
+ award.destroy
+ present award, with: Entities::AwardEmoji
+ end
+ end
+ end
+ helpers do
+ def awardable_read_ability_name(awardable)
+ "read_#{awardable.class.to_s.underscore.downcase}".to_sym
+ end
+ end
+ end
+end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index cc29c7ef428..2e397643ed1 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -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
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 4c43257c48a..aa0b9ca3957 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -1,6 +1,6 @@
module API
# Issues API
- class Issues < Grape::API
+ class Issues < Grape::API
before { authenticate! }
helpers ::Gitlab::AkismetHelper
diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb
new file mode 100644
index 00000000000..49964cb51de
--- /dev/null
+++ b/spec/requests/api/award_emoji_spec.rb
@@ -0,0 +1,149 @@
+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) }
+
+ 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/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(issue.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 "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 'DELETE /projects/:id/awardable/:awardable_id/award_emoji/:award_emoji_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
+end