Merge branch 'and-you-get-awards' into 'master'
And Snippets get awards ## What does this MR do? Makes snippets more awesome, by making them awardables ## Why was this MR needed? Because Snippets were left behind. ## What are the relevant issue numbers? Closes #17878 See merge request !4456
This commit is contained in:
commit
24fed56787
21 changed files with 183 additions and 51 deletions
|
@ -52,6 +52,7 @@ v 8.12.0 (unreleased)
|
|||
- Move parsing of sidekiq ps into helper !6245 (pascalbetz)
|
||||
- Added go to issue boards keyboard shortcut
|
||||
- Expose `sha` and `merge_commit_sha` in merge request API (Ben Boeckel)
|
||||
- Emoji can be awarded on Snippets !4456
|
||||
- Set path for all JavaScript cookies to honor GitLab's subdirectory setting !5627 (Mike Greiling)
|
||||
- Fix blame table layout width
|
||||
- Spec testing if issue authors can read issues on private projects
|
||||
|
|
|
@ -12,11 +12,18 @@
|
|||
|
||||
.snippet-file-content {
|
||||
border-radius: 3px;
|
||||
margin-bottom: $gl-padding;
|
||||
|
||||
.btn-clipboard {
|
||||
@extend .btn;
|
||||
}
|
||||
}
|
||||
|
||||
.project-snippets .awards {
|
||||
border-bottom: 1px solid $table-border-color;
|
||||
padding-bottom: $gl-padding;
|
||||
}
|
||||
|
||||
.snippet-title {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
|
|
|
@ -10,7 +10,9 @@ module ToggleAwardEmoji
|
|||
|
||||
if awardable.user_can_award?(current_user, name)
|
||||
awardable.toggle_award_emoji(name, current_user)
|
||||
TodoService.new.new_award_emoji(to_todoable(awardable), current_user)
|
||||
|
||||
todoable = to_todoable(awardable)
|
||||
TodoService.new.new_award_emoji(todoable, current_user) if todoable
|
||||
|
||||
render json: { ok: true }
|
||||
else
|
||||
|
@ -24,8 +26,10 @@ module ToggleAwardEmoji
|
|||
case awardable
|
||||
when Note
|
||||
awardable.noteable
|
||||
else
|
||||
when MergeRequest, Issue
|
||||
awardable
|
||||
when Snippet
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
class Projects::SnippetsController < Projects::ApplicationController
|
||||
include ToggleAwardEmoji
|
||||
|
||||
before_action :module_enabled
|
||||
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw]
|
||||
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw, :toggle_award_emoji]
|
||||
|
||||
# Allow read any snippet
|
||||
before_action :authorize_read_project_snippet!, except: [:new, :create, :index]
|
||||
|
@ -80,6 +82,7 @@ class Projects::SnippetsController < Projects::ApplicationController
|
|||
def snippet
|
||||
@snippet ||= @project.snippets.find(params[:id])
|
||||
end
|
||||
alias_method :awardable, :snippet
|
||||
|
||||
def authorize_read_project_snippet!
|
||||
return render_404 unless can?(current_user, :read_project_snippet, @snippet)
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
class SnippetsController < ApplicationController
|
||||
include ToggleAwardEmoji
|
||||
|
||||
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw]
|
||||
|
||||
# Allow read snippet
|
||||
|
@ -85,6 +87,7 @@ class SnippetsController < ApplicationController
|
|||
PersonalSnippet.find(params[:id])
|
||||
end
|
||||
end
|
||||
alias_method :awardable, :snippet
|
||||
|
||||
def authorize_read_snippet!
|
||||
authenticate_user! unless can?(current_user, :read_personal_snippet, @snippet)
|
||||
|
|
9
app/helpers/award_emoji_helper.rb
Normal file
9
app/helpers/award_emoji_helper.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
module AwardEmojiHelper
|
||||
def toggle_award_url(awardable)
|
||||
if @project
|
||||
url_for([:toggle_award_emoji, @project.namespace.becomes(Namespace), @project, awardable])
|
||||
else
|
||||
url_for([:toggle_award_emoji, awardable])
|
||||
end
|
||||
end
|
||||
end
|
|
@ -106,6 +106,14 @@ module GitlabRoutingHelper
|
|||
end
|
||||
end
|
||||
|
||||
def toggle_award_emoji_personal_snippet_path(*args)
|
||||
toggle_award_emoji_snippet_path(*args)
|
||||
end
|
||||
|
||||
def toggle_award_emoji_namespace_project_project_snippet_path(*args)
|
||||
toggle_award_emoji_namespace_project_snippet_path(*args)
|
||||
end
|
||||
|
||||
## Members
|
||||
def project_members_url(project, *args)
|
||||
namespace_project_project_members_url(project.namespace, project)
|
||||
|
|
|
@ -71,6 +71,12 @@ module Awardable
|
|||
end
|
||||
end
|
||||
|
||||
def user_authored?(current_user)
|
||||
author = self.respond_to?(:author) ? self.author : self.user
|
||||
|
||||
author == current_user
|
||||
end
|
||||
|
||||
def awarded_emoji?(emoji_name, current_user)
|
||||
award_emoji.where(name: emoji_name, user: current_user).exists?
|
||||
end
|
||||
|
|
|
@ -200,10 +200,6 @@ module Issuable
|
|||
end
|
||||
end
|
||||
|
||||
def user_authored?(user)
|
||||
user == author
|
||||
end
|
||||
|
||||
def subscribed_without_subscriptions?(user)
|
||||
participants(user).include?(user)
|
||||
end
|
||||
|
|
|
@ -223,10 +223,6 @@ class Note < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def user_authored?(user)
|
||||
user == author
|
||||
end
|
||||
|
||||
def award_emoji?
|
||||
can_be_award_emoji? && contains_emoji_only?
|
||||
end
|
||||
|
|
|
@ -4,6 +4,7 @@ class Snippet < ActiveRecord::Base
|
|||
include Participable
|
||||
include Referable
|
||||
include Sortable
|
||||
include Awardable
|
||||
|
||||
default_value_for :visibility_level, Snippet::PRIVATE
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
- grouped_emojis = awardable.grouped_awards(with_thumbs: inline)
|
||||
.awards.js-awards-block{ class: ("hidden" if !inline && grouped_emojis.empty?), data: { award_url: url_for([:toggle_award_emoji, @project.namespace.becomes(Namespace), @project, awardable]) } }
|
||||
.awards.js-awards-block{ class: ("hidden" if !inline && grouped_emojis.empty?), data: { award_url: toggle_award_url(awardable) } }
|
||||
- awards_sort(grouped_emojis).each do |emoji, awards|
|
||||
%button.btn.award-control.js-emoji-btn.has-tooltip{ type: "button", class: (award_active_class(awards, current_user)), data: { placement: "bottom", title: award_user_list(awards, current_user) } }
|
||||
= emoji_icon(emoji, sprite: false)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
= link_to new_namespace_project_snippet_path(@project.namespace, @project), class: 'btn btn-grouped btn-create new-snippet-link', title: "New Snippet" do
|
||||
New Snippet
|
||||
- if can?(current_user, :update_project_snippet, @snippet)
|
||||
= link_to namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-warning", title: 'Delete Snippet' do
|
||||
= link_to namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-danger", title: 'Delete Snippet' do
|
||||
Delete
|
||||
- if can?(current_user, :update_project_snippet, @snippet)
|
||||
= link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-grouped snippable-edit" do
|
||||
|
|
|
@ -2,13 +2,16 @@
|
|||
|
||||
= render 'shared/snippets/header'
|
||||
|
||||
%article.file-holder.snippet-file-content
|
||||
.file-title
|
||||
= blob_icon 0, @snippet.file_name
|
||||
= @snippet.file_name
|
||||
.file-actions
|
||||
= clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']")
|
||||
= link_to 'Raw', raw_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", target: "_blank"
|
||||
= render 'shared/snippets/blob'
|
||||
.project-snippets
|
||||
%article.file-holder.snippet-file-content
|
||||
.file-title
|
||||
= blob_icon 0, @snippet.file_name
|
||||
= @snippet.file_name
|
||||
.file-actions
|
||||
= clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']")
|
||||
= link_to 'Raw', raw_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", target: "_blank"
|
||||
= render 'shared/snippets/blob'
|
||||
|
||||
%div#notes= render "projects/notes/notes_with_form"
|
||||
= render 'award_emoji/awards_block', awardable: @snippet, inline: true
|
||||
|
||||
%div#notes= render "projects/notes/notes_with_form"
|
||||
|
|
|
@ -10,3 +10,5 @@
|
|||
= clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']")
|
||||
= link_to 'Raw', raw_snippet_path(@snippet), class: "btn btn-sm", target: "_blank"
|
||||
= render 'shared/snippets/blob'
|
||||
|
||||
= render 'award_emoji/awards_block', awardable: @snippet, inline: true
|
|
@ -35,6 +35,10 @@ Rails.application.routes.draw do
|
|||
post :approve_access_request, on: :member
|
||||
end
|
||||
|
||||
concern :awardable do
|
||||
post :toggle_award_emoji, on: :member
|
||||
end
|
||||
|
||||
namespace :ci do
|
||||
# CI API
|
||||
Ci::API::API.logger Rails.logger
|
||||
|
@ -98,7 +102,7 @@ Rails.application.routes.draw do
|
|||
#
|
||||
# Global snippets
|
||||
#
|
||||
resources :snippets do
|
||||
resources :snippets, concerns: :awardable do
|
||||
member do
|
||||
get 'raw'
|
||||
end
|
||||
|
@ -110,7 +114,6 @@ Rails.application.routes.draw do
|
|||
#
|
||||
# Invites
|
||||
#
|
||||
|
||||
resources :invites, only: [:show], constraints: { id: /[A-Za-z0-9_-]+/ } do
|
||||
member do
|
||||
post :accept
|
||||
|
@ -662,7 +665,7 @@ Rails.application.routes.draw do
|
|||
end
|
||||
end
|
||||
|
||||
resources :snippets, constraints: { id: /\d+/ } do
|
||||
resources :snippets, concerns: :awardable, constraints: { id: /\d+/ } do
|
||||
member do
|
||||
get 'raw'
|
||||
end
|
||||
|
@ -724,7 +727,7 @@ Rails.application.routes.draw do
|
|||
end
|
||||
end
|
||||
|
||||
resources :merge_requests, constraints: { id: /\d+/ } do
|
||||
resources :merge_requests, concerns: :awardable, constraints: { id: /\d+/ } do
|
||||
member do
|
||||
get :commits
|
||||
get :diffs
|
||||
|
@ -736,7 +739,6 @@ Rails.application.routes.draw do
|
|||
post :cancel_merge_when_build_succeeds
|
||||
get :ci_status
|
||||
post :toggle_subscription
|
||||
post :toggle_award_emoji
|
||||
post :remove_wip
|
||||
get :diff_for_path
|
||||
post :resolve_conflicts
|
||||
|
@ -840,10 +842,9 @@ Rails.application.routes.draw do
|
|||
end
|
||||
end
|
||||
|
||||
resources :issues, constraints: { id: /\d+/ } do
|
||||
resources :issues, concerns: :awardable, constraints: { id: /\d+/ } do
|
||||
member do
|
||||
post :toggle_subscription
|
||||
post :toggle_award_emoji
|
||||
post :mark_as_spam
|
||||
get :referenced_merge_requests
|
||||
get :related_branches
|
||||
|
@ -871,9 +872,8 @@ Rails.application.routes.draw do
|
|||
|
||||
resources :group_links, only: [:index, :create, :destroy], constraints: { id: /\d+/ }
|
||||
|
||||
resources :notes, only: [:index, :create, :destroy, :update], constraints: { id: /\d+/ } do
|
||||
resources :notes, only: [:index, :create, :destroy, :update], concerns: :awardable, constraints: { id: /\d+/ } do
|
||||
member do
|
||||
post :toggle_award_emoji
|
||||
delete :delete_attachment
|
||||
post :resolve
|
||||
delete :resolve, action: :unresolve
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
# Award Emoji
|
||||
|
||||
> [Introduced][ce-4575] in GitLab 8.9.
|
||||
> [Introduced][ce-4575] in GitLab 8.9, Snippet support in 8.12
|
||||
|
||||
|
||||
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
|
||||
requests, snippets, and notes/comments. Issues, merge requests, snippets, and notes are further called
|
||||
`awardables`.
|
||||
|
||||
## Issues and merge requests
|
||||
## Issues, merge requests, and snippets
|
||||
|
||||
### List an awardable's award emoji
|
||||
|
||||
|
@ -15,6 +16,7 @@ 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
|
||||
GET /projects/:id/snippets/:snippet_id/award_emoji
|
||||
```
|
||||
|
||||
Parameters:
|
||||
|
@ -69,11 +71,12 @@ Example Response:
|
|||
|
||||
### Get single award emoji
|
||||
|
||||
Gets a single award emoji from an issue or merge request.
|
||||
Gets a single award emoji from an issue, snippet, or merge request.
|
||||
|
||||
```
|
||||
GET /projects/:id/issues/:issue_id/award_emoji/:award_id
|
||||
GET /projects/:id/merge_requests/:merge_request_id/award_emoji/:award_id
|
||||
GET /projects/:id/snippets/:snippet_id/award_emoji/:award_id
|
||||
```
|
||||
|
||||
Parameters:
|
||||
|
@ -116,6 +119,7 @@ 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
|
||||
POST /projects/:id/snippets/:snippet_id/award_emoji
|
||||
```
|
||||
|
||||
Parameters:
|
||||
|
@ -159,6 +163,7 @@ admins or the author of the award. Status code 200 on success, 401 if unauthoriz
|
|||
```
|
||||
DELETE /projects/:id/issues/:issue_id/award_emoji/:award_id
|
||||
DELETE /projects/:id/merge_requests/:merge_request_id/award_emoji/:award_id
|
||||
DELETE /projects/:id/snippets/:snippet_id/award_emoji/:award_id
|
||||
```
|
||||
|
||||
Parameters:
|
||||
|
@ -197,7 +202,7 @@ Example Response:
|
|||
## 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
|
||||
are a sub-resource of Issues, Merge Requests, or Snippets. The examples below
|
||||
describe working with Award Emoji on notes for an Issue, but can be
|
||||
easily adapted for notes on a Merge Request.
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
module API
|
||||
class AwardEmoji < Grape::API
|
||||
before { authenticate! }
|
||||
AWARDABLES = [Issue, MergeRequest]
|
||||
AWARDABLES = %w[issue merge_request snippet]
|
||||
|
||||
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"
|
||||
awardable_string = awardable_type.pluralize
|
||||
awardable_id_string = "#{awardable_type}_id"
|
||||
|
||||
[ ":id/#{awardable_string}/:#{awardable_id_string}/award_emoji",
|
||||
":id/#{awardable_string}/:#{awardable_id_string}/notes/:note_id/award_emoji"
|
||||
|
@ -87,9 +87,7 @@ module API
|
|||
|
||||
helpers do
|
||||
def can_read_awardable?
|
||||
ability = "read_#{awardable.class.to_s.underscore}".to_sym
|
||||
|
||||
can?(current_user, ability, awardable)
|
||||
can?(current_user, read_ability(awardable), awardable)
|
||||
end
|
||||
|
||||
def can_award_awardable?
|
||||
|
@ -100,18 +98,25 @@ module API
|
|||
@awardable ||=
|
||||
begin
|
||||
if params.include?(:note_id)
|
||||
noteable.notes.find(params[:note_id])
|
||||
note_id = params.delete(:note_id)
|
||||
|
||||
awardable.notes.find(note_id)
|
||||
elsif params.include?(:issue_id)
|
||||
user_project.issues.find(params[:issue_id])
|
||||
elsif params.include?(:merge_request_id)
|
||||
user_project.merge_requests.find(params[:merge_request_id])
|
||||
else
|
||||
noteable
|
||||
user_project.snippets.find(params[:snippet_id])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def noteable
|
||||
if params.include?(:issue_id)
|
||||
user_project.issues.find(params[:issue_id])
|
||||
def read_ability(awardable)
|
||||
case awardable
|
||||
when Note
|
||||
read_ability(awardable.noteable)
|
||||
else
|
||||
user_project.merge_requests.find(params[:merge_request_id])
|
||||
:"read_#{awardable.class.to_s.underscore}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe SnippetsController do
|
||||
describe 'GET #show' do
|
||||
let(:user) { create(:user) }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
describe 'GET #show' do
|
||||
context 'when the personal snippet is private' do
|
||||
let(:personal_snippet) { create(:personal_snippet, :private, author: user) }
|
||||
|
||||
|
@ -230,4 +230,33 @@ describe SnippetsController do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'award emoji on snippets' do
|
||||
let(:personal_snippet) { create(:personal_snippet, :public, author: user) }
|
||||
let(:another_user) { create(:user) }
|
||||
|
||||
before do
|
||||
sign_in(another_user)
|
||||
end
|
||||
|
||||
describe 'POST #toggle_award_emoji' do
|
||||
it "toggles the award emoji" do
|
||||
expect do
|
||||
post(:toggle_award_emoji, id: personal_snippet.to_param, name: "thumbsup")
|
||||
end.to change { personal_snippet.award_emoji.count }.from(0).to(1)
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
|
||||
it "removes the already awarded emoji" do
|
||||
post(:toggle_award_emoji, id: personal_snippet.to_param, name: "thumbsup")
|
||||
|
||||
expect do
|
||||
post(:toggle_award_emoji, id: personal_snippet.to_param, name: "thumbsup")
|
||||
end.to change { personal_snippet.award_emoji.count }.from(1).to(0)
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,12 +9,14 @@ describe Snippet, models: true do
|
|||
it { is_expected.to include_module(Participable) }
|
||||
it { is_expected.to include_module(Referable) }
|
||||
it { is_expected.to include_module(Sortable) }
|
||||
it { is_expected.to include_module(Awardable) }
|
||||
end
|
||||
|
||||
describe 'associations' do
|
||||
it { is_expected.to belong_to(:author).class_name('User') }
|
||||
it { is_expected.to belong_to(:project) }
|
||||
it { is_expected.to have_many(:notes).dependent(:destroy) }
|
||||
it { is_expected.to have_many(:award_emoji).dependent(:destroy) }
|
||||
end
|
||||
|
||||
describe 'validation' do
|
||||
|
|
|
@ -3,7 +3,7 @@ require 'spec_helper'
|
|||
describe API::API, api: true do
|
||||
include ApiHelpers
|
||||
let(:user) { create(:user) }
|
||||
let!(:project) { create(:project) }
|
||||
let!(:project) { create(:empty_project) }
|
||||
let(:issue) { create(:issue, project: project) }
|
||||
let!(:award_emoji) { create(:award_emoji, awardable: issue, user: user) }
|
||||
let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
|
||||
|
@ -39,6 +39,19 @@ describe API::API, api: true do
|
|||
end
|
||||
end
|
||||
|
||||
context 'on a snippet' do
|
||||
let(:snippet) { create(:project_snippet, :public, project: project) }
|
||||
let!(:award) { create(:award_emoji, awardable: snippet) }
|
||||
|
||||
it 'returns the awarded emoji' do
|
||||
get api("/projects/#{project.id}/snippets/#{snippet.id}/award_emoji", user)
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(json_response).to be_an Array
|
||||
expect(json_response.first['name']).to eq(award.name)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user has no access' do
|
||||
it 'returns a status code 404' do
|
||||
user1 = create(:user)
|
||||
|
@ -91,6 +104,20 @@ describe API::API, api: true do
|
|||
end
|
||||
end
|
||||
|
||||
context 'on a snippet' do
|
||||
let(:snippet) { create(:project_snippet, :public, project: project) }
|
||||
let!(:award) { create(:award_emoji, awardable: snippet) }
|
||||
|
||||
it 'returns the awarded emoji' do
|
||||
get api("/projects/#{project.id}/snippets/#{snippet.id}/award_emoji/#{award.id}", user)
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(json_response['name']).to eq(award.name)
|
||||
expect(json_response['awardable_id']).to eq(snippet.id)
|
||||
expect(json_response['awardable_type']).to eq("Snippet")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user has no access' do
|
||||
it 'returns a status code 404' do
|
||||
user1 = create(:user)
|
||||
|
@ -160,6 +187,18 @@ describe API::API, api: true do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'on a snippet' do
|
||||
it 'creates a new award emoji' do
|
||||
snippet = create(:project_snippet, :public, project: project)
|
||||
|
||||
post api("/projects/#{project.id}/snippets/#{snippet.id}/award_emoji", user), name: 'blowfish'
|
||||
|
||||
expect(response).to have_http_status(201)
|
||||
expect(json_response['name']).to eq('blowfish')
|
||||
expect(json_response['user']['username']).to eq(user.username)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "POST /projects/:id/awardable/:awardable_id/notes/:note_id/award_emoji" do
|
||||
|
@ -229,6 +268,19 @@ describe API::API, api: true do
|
|||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the awardable is a Snippet' do
|
||||
let(:snippet) { create(:project_snippet, :public, project: project) }
|
||||
let!(:award) { create(:award_emoji, awardable: snippet, user: user) }
|
||||
|
||||
it 'deletes the award' do
|
||||
expect do
|
||||
delete api("/projects/#{project.id}/snippets/#{snippet.id}/award_emoji/#{award.id}", user)
|
||||
end.to change { snippet.award_emoji.count }.from(1).to(0)
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE /projects/:id/awardable/:awardable_id/award_emoji/:award_emoji_id' do
|
||||
|
|
Loading…
Reference in a new issue