Commit 34599448 authored by Jan Provaznik's avatar Jan Provaznik

Merge branch 'ph/awardEmojiEpicsAPI' into 'master'

Added award emoji to the epics public API

See merge request gitlab-org/gitlab!60410
parents 69d0803f 29065637
---
title: Added award emoji to epics REST API
merge_request: 60410
author:
type: added
# frozen_string_literal: true
module EE
module API
module Helpers
module AwardEmoji
extend ActiveSupport::Concern
extend ::Gitlab::Utils::Override
class_methods do
extend ::Gitlab::Utils::Override
override :awardables
def awardables
super.concat([
{ type: 'epic', resource: :groups, find_by: :iid, feature_category: :epics }
])
end
override :awardable_id_desc
def awardable_id_desc
"The ID of an Issue, Merge Request, Epic or Snippet"
end
end
# rubocop: disable CodeReuse/ActiveRecord
override :awardable
def awardable
super
@awardable ||= # rubocop:disable Gitlab/ModuleWithInstanceVariables
begin
if params.include?(:epic_iid)
user_group.epics.find_by!(iid: params[:epic_iid])
end
end
end
# rubocop: enable CodeReuse/ActiveRecord
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe API::AwardEmoji do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:epic) { create(:epic, group: group, author: user) }
let_it_be(:award_emoji) { create(:award_emoji, awardable: epic, user: user) }
let_it_be(:note) { create(:note, noteable: epic) }
before do
stub_licensed_features(epics: true)
group.add_developer(user)
end
describe "GET /groups/:id/awardable/:awardable_id/award_emoji" do
context 'on an epic' do
it "returns an array of award_emoji" do
get api("/groups/#{group.id}/epics/#{epic.iid}/award_emoji", user)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Array
expect(json_response.first['name']).to eq(award_emoji.name)
end
it "returns a 404 error when epic id not found" do
get api("/groups/#{group.id}/epics/#{non_existing_record_iid}/award_emoji", user)
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
describe 'GET /groups/: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("/groups/#{group.id}/epics/#{epic.iid}/notes/#{note.id}/award_emoji", user)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Array
expect(json_response.first['name']).to eq(rocket.name)
end
end
describe "GET /groups/:id/awardable/:awardable_id/award_emoji/:award_id" do
context 'on an epic' do
it "returns the award emoji" do
get api("/groups/#{group.id}/epics/#{epic.iid}/award_emoji/#{award_emoji.id}", user)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['name']).to eq(award_emoji.name)
expect(json_response['awardable_id']).to eq(epic.id)
expect(json_response['awardable_type']).to eq("Epic")
end
it "returns a 404 error if the award is not found" do
get api("/groups/#{group.id}/epics/#{epic.iid}/award_emoji/#{non_existing_record_id}", user)
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
describe 'GET /groups/: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("/groups/#{group.id}/epics/#{epic.iid}/notes/#{note.id}/award_emoji/#{rocket.id}", user)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).not_to be_an Array
expect(json_response['name']).to eq(rocket.name)
end
end
describe "POST /groups/:id/awardable/:awardable_id/award_emoji" do
context "on an epic" do
it "creates a new award emoji" do
post api("/groups/#{group.id}/epics/#{epic.iid}/award_emoji", user), params: { name: 'blowfish' }
expect(response).to have_gitlab_http_status(:created)
expect(json_response['name']).to eq('blowfish')
expect(json_response['user']['username']).to eq(user.username)
end
it "returns a 400 bad request error if the name is not given" do
post api("/groups/#{group.id}/epics/#{epic.iid}/award_emoji", user)
expect(response).to have_gitlab_http_status(:bad_request)
end
it "returns a 401 unauthorized error if the user is not authenticated" do
post api("/groups/#{group.id}/epics/#{epic.iid}/award_emoji"), params: { name: 'thumbsup' }
expect(response).to have_gitlab_http_status(:unauthorized)
end
it "normalizes +1 as thumbsup award" do
post api("/groups/#{group.id}/epics/#{epic.iid}/award_emoji", user), params: { name: '+1' }
expect(epic.award_emoji.last.name).to eq("thumbsup")
end
context 'when the emoji already has been awarded' do
it 'returns a 404 status code' do
post api("/groups/#{group.id}/epics/#{epic.iid}/award_emoji", user), params: { name: 'thumbsup' }
post api("/groups/#{group.id}/epics/#{epic.iid}/award_emoji", user), params: { name: 'thumbsup' }
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response["message"]).to match("has already been taken")
end
end
end
end
describe "POST /groups/:id/awardable/:awardable_id/notes/:note_id/award_emoji" do
let(:note2) { create(:note, noteable: epic, author: user) }
it 'creates a new award emoji' do
expect do
post api("/groups/#{group.id}/epics/#{epic.iid}/notes/#{note.id}/award_emoji", user), params: { name: 'rocket' }
end.to change { note.award_emoji.count }.from(0).to(1)
expect(response).to have_gitlab_http_status(:created)
expect(json_response['user']['username']).to eq(user.username)
end
it 'marks Todos on the Noteable as done' do
todo = create(:todo, target: note2.noteable, group: group, user: user)
post api("/groups/#{group.id}/epics/#{epic.iid}/notes/#{note.id}/award_emoji", user), params: { name: 'rocket' }
expect(todo.reload).to be_done
end
it "normalizes +1 as thumbsup award" do
post api("/groups/#{group.id}/epics/#{epic.iid}/notes/#{note.id}/award_emoji", user), params: { name: '+1' }
expect(note.award_emoji.last.name).to eq("thumbsup")
end
context 'when the emoji already has been awarded' do
it 'returns a 404 status code' do
post api("/groups/#{group.id}/epics/#{epic.iid}/notes/#{note.id}/award_emoji", user), params: { name: 'rocket' }
post api("/groups/#{group.id}/epics/#{epic.iid}/notes/#{note.id}/award_emoji", user), params: { name: 'rocket' }
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response["message"]).to match("has already been taken")
end
end
end
describe 'DELETE /groups/:id/awardable/:awardable_id/award_emoji/:award_id' do
context 'when the awardable is an Epic' do
it 'deletes the award' do
expect do
delete api("/groups/#{group.id}/epics/#{epic.iid}/award_emoji/#{award_emoji.id}", user)
expect(response).to have_gitlab_http_status(:no_content)
end.to change { epic.award_emoji.count }.from(1).to(0)
end
it 'returns a 404 error when the award emoji can not be found' do
delete api("/groups/#{group.id}/epics/#{epic.iid}/award_emoji/#{non_existing_record_id}", user)
expect(response).to have_gitlab_http_status(:not_found)
end
it_behaves_like '412 response' do
let(:request) { api("/groups/#{group.id}/epics/#{epic.iid}/award_emoji/#{award_emoji.id}", user) }
end
end
end
describe 'DELETE /groups/: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("/groups/#{group.id}/epics/#{epic.iid}/notes/#{note.id}/award_emoji/#{rocket.id}", user)
expect(response).to have_gitlab_http_status(:no_content)
end.to change { note.award_emoji.count }.from(1).to(0)
end
it_behaves_like '412 response' do
let(:request) { api("/groups/#{group.id}/epics/#{epic.iid}/notes/#{note.id}/award_emoji/#{rocket.id}", user) }
end
end
end
......@@ -4,23 +4,18 @@ module API
class AwardEmoji < ::API::Base
include PaginationParams
helpers ::API::Helpers::AwardEmoji
before { authenticate! }
AWARDABLES = [
{ type: 'issue', find_by: :iid, feature_category: :issue_tracking },
{ type: 'merge_request', find_by: :iid, feature_category: :code_review },
{ type: 'snippet', find_by: :id, feature_category: :snippets }
].freeze
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
AWARDABLES.each do |awardable_params|
Helpers::AwardEmoji.awardables.each do |awardable_params|
resource awardable_params[:resource], requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
awardable_string = awardable_params[:type].pluralize
awardable_id_string = "#{awardable_params[:type]}_#{awardable_params[:find_by]}"
params do
requires :"#{awardable_id_string}", type: Integer, desc: "The ID of an Issue, Merge Request or Snippet"
requires :id, type: String, desc: "The ID of a #{awardable_params[:resource] == :projects ? 'project' : 'group'}"
requires :"#{awardable_id_string}", type: Integer, desc: Helpers::AwardEmoji.awardable_id_desc
end
[
......@@ -104,25 +99,6 @@ module API
awardable.user_can_award?(current_user)
end
# rubocop: disable CodeReuse/ActiveRecord
def awardable
@awardable ||=
begin
if params.include?(:note_id)
note_id = params.delete(:note_id)
awardable.notes.find(note_id)
elsif params.include?(:issue_iid)
user_project.issues.find_by!(iid: params[:issue_iid])
elsif params.include?(:merge_request_iid)
user_project.merge_requests.find_by!(iid: params[:merge_request_iid])
else
user_project.snippets.find(params[:snippet_id])
end
end
end
# rubocop: enable CodeReuse/ActiveRecord
def read_ability(awardable)
case awardable
when Note
......
# frozen_string_literal: true
module API
module Helpers
module AwardEmoji
def self.awardables
[
{ type: 'issue', resource: :projects, find_by: :iid, feature_category: :issue_tracking },
{ type: 'merge_request', resource: :projects, find_by: :iid, feature_category: :code_review },
{ type: 'snippet', resource: :projects, find_by: :id, feature_category: :snippets }
]
end
def self.awardable_id_desc
"The ID of an Issue, Merge Request or Snippet"
end
# rubocop: disable CodeReuse/ActiveRecord
def awardable
@awardable ||=
begin
if params.include?(:note_id)
note_id = params.delete(:note_id)
awardable.notes.find(note_id)
elsif params.include?(:issue_iid)
user_project.issues.find_by!(iid: params[:issue_iid])
elsif params.include?(:merge_request_iid)
user_project.merge_requests.find_by!(iid: params[:merge_request_iid])
elsif params.include?(:snippet_id)
user_project.snippets.find(params[:snippet_id])
end
end
end
# rubocop: enable CodeReuse/ActiveRecord
end
end
end
API::Helpers::AwardEmoji.prepend_if_ee('EE::API::Helpers::AwardEmoji')
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