Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGrzegorz Bizon <grzegorz@gitlab.com>2019-08-21 12:38:40 +0300
committerGrzegorz Bizon <grzegorz@gitlab.com>2019-08-21 12:38:40 +0300
commit89f6584fb30544dbd27c291c3b62e3f2b0399e63 (patch)
tree6a364a9b79bcabb4df38bb7adf4a1190f8b83a7a /app
parent9174d60ba1ce3e183396f360c6e41ed23540b6d0 (diff)
parent926bf71e511e084fa033b4e96f5b4067e0eeca0a (diff)
Merge branch '63372-award-emoji-services' into 'master'
Add service classes for mutating AwardEmoji Closes #63372 See merge request gitlab-org/gitlab-ce!29782
Diffstat (limited to 'app')
-rw-r--r--app/controllers/autocomplete_controller.rb2
-rw-r--r--app/controllers/concerns/toggle_award_emoji.rb19
-rw-r--r--app/finders/award_emojis_finder.rb55
-rw-r--r--app/finders/awarded_emoji_finder.rb21
-rw-r--r--app/graphql/mutations/award_emojis/add.rb9
-rw-r--r--app/graphql/mutations/award_emojis/remove.rb15
-rw-r--r--app/graphql/mutations/award_emojis/toggle.rb14
-rw-r--r--app/models/award_emoji.rb6
-rw-r--r--app/models/concerns/awardable.rb26
-rw-r--r--app/services/award_emojis/add_service.rb42
-rw-r--r--app/services/award_emojis/base_service.rb32
-rw-r--r--app/services/award_emojis/collect_user_emoji_service.rb23
-rw-r--r--app/services/award_emojis/destroy_service.rb21
-rw-r--r--app/services/award_emojis/toggle_service.rb13
-rw-r--r--app/services/issuable_base_service.rb5
15 files changed, 203 insertions, 100 deletions
diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb
index f111c7ca8cc..30a567c3bef 100644
--- a/app/controllers/autocomplete_controller.rb
+++ b/app/controllers/autocomplete_controller.rb
@@ -36,7 +36,7 @@ class AutocompleteController < ApplicationController
end
def award_emojis
- render json: AwardedEmojiFinder.new(current_user).execute
+ render json: AwardEmojis::CollectUserEmojiService.new(current_user).execute
end
def merge_request_target_branches
diff --git a/app/controllers/concerns/toggle_award_emoji.rb b/app/controllers/concerns/toggle_award_emoji.rb
index 97b343f8b1a..24d178781d6 100644
--- a/app/controllers/concerns/toggle_award_emoji.rb
+++ b/app/controllers/concerns/toggle_award_emoji.rb
@@ -7,12 +7,9 @@ module ToggleAwardEmoji
authenticate_user!
name = params.require(:name)
- if awardable.user_can_award?(current_user)
- awardable.toggle_award_emoji(name, current_user)
-
- todoable = to_todoable(awardable)
- TodoService.new.new_award_emoji(todoable, current_user) if todoable
+ service = AwardEmojis::ToggleService.new(awardable, name, current_user).execute
+ if service[:status] == :success
render json: { ok: true }
else
render json: { ok: false }
@@ -21,18 +18,6 @@ module ToggleAwardEmoji
private
- def to_todoable(awardable)
- case awardable
- when Note
- # we don't create todos for personal snippet comments for now
- awardable.for_personal_snippet? ? nil : awardable.noteable
- when MergeRequest, Issue
- awardable
- when Snippet
- nil
- end
- end
-
def awardable
raise NotImplementedError
end
diff --git a/app/finders/award_emojis_finder.rb b/app/finders/award_emojis_finder.rb
new file mode 100644
index 00000000000..7320e035409
--- /dev/null
+++ b/app/finders/award_emojis_finder.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+class AwardEmojisFinder
+ attr_reader :awardable, :params
+
+ def initialize(awardable, params = {})
+ @awardable = awardable
+ @params = params
+
+ validate_params
+ end
+
+ def execute
+ awards = awardable.award_emoji
+ awards = by_name(awards)
+ awards = by_awarded_by(awards)
+ awards
+ end
+
+ private
+
+ def by_name(awards)
+ return awards unless params[:name]
+
+ awards.named(params[:name])
+ end
+
+ def by_awarded_by(awards)
+ return awards unless params[:awarded_by]
+
+ awards.awarded_by(params[:awarded_by])
+ end
+
+ def validate_params
+ return unless params.present?
+
+ validate_name_param
+ validate_awarded_by_param
+ end
+
+ def validate_name_param
+ return unless params[:name]
+
+ raise ArgumentError, 'Invalid name param' unless params[:name].in?(Gitlab::Emoji.emojis_names)
+ end
+
+ def validate_awarded_by_param
+ return unless params[:awarded_by]
+
+ # awarded_by can be a `User`, or an ID
+ unless params[:awarded_by].is_a?(User) || params[:awarded_by].to_s.match(/\A\d+\Z/)
+ raise ArgumentError, 'Invalid awarded_by param'
+ end
+ end
+end
diff --git a/app/finders/awarded_emoji_finder.rb b/app/finders/awarded_emoji_finder.rb
deleted file mode 100644
index f0cc17f3b26..00000000000
--- a/app/finders/awarded_emoji_finder.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-# Class for retrieving information about emoji awarded _by_ a particular user.
-class AwardedEmojiFinder
- attr_reader :current_user
-
- # current_user - The User to generate the data for.
- def initialize(current_user = nil)
- @current_user = current_user
- end
-
- def execute
- return [] unless current_user
-
- # We want the resulting data set to be an Array containing the emoji names
- # in descending order, based on how often they were awarded.
- AwardEmoji
- .award_counts_for_user(current_user)
- .map { |name, _| { name: name } }
- end
-end
diff --git a/app/graphql/mutations/award_emojis/add.rb b/app/graphql/mutations/award_emojis/add.rb
index 8e050dd6d29..85f3eb065bb 100644
--- a/app/graphql/mutations/award_emojis/add.rb
+++ b/app/graphql/mutations/award_emojis/add.rb
@@ -10,14 +10,11 @@ module Mutations
check_object_is_awardable!(awardable)
- # TODO this will be handled by AwardEmoji::AddService
- # See https://gitlab.com/gitlab-org/gitlab-ce/issues/63372 and
- # https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/29782
- award = awardable.create_award_emoji(args[:name], current_user)
+ service = ::AwardEmojis::AddService.new(awardable, args[:name], current_user).execute
{
- award_emoji: (award if award.persisted?),
- errors: errors_on_object(award)
+ award_emoji: (service[:award] if service[:status] == :success),
+ errors: service[:errors] || []
}
end
end
diff --git a/app/graphql/mutations/award_emojis/remove.rb b/app/graphql/mutations/award_emojis/remove.rb
index 3ba85e445b8..f8a3d0ce390 100644
--- a/app/graphql/mutations/award_emojis/remove.rb
+++ b/app/graphql/mutations/award_emojis/remove.rb
@@ -10,22 +10,11 @@ module Mutations
check_object_is_awardable!(awardable)
- # TODO this check can be removed once AwardEmoji services are available.
- # See https://gitlab.com/gitlab-org/gitlab-ce/issues/63372 and
- # https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/29782
- unless awardable.awarded_emoji?(args[:name], current_user)
- raise Gitlab::Graphql::Errors::ResourceNotAvailable,
- 'You have not awarded emoji of type name to the awardable'
- end
-
- # TODO this will be handled by AwardEmoji::DestroyService
- # See https://gitlab.com/gitlab-org/gitlab-ce/issues/63372 and
- # https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/29782
- awardable.remove_award_emoji(args[:name], current_user)
+ service = ::AwardEmojis::DestroyService.new(awardable, args[:name], current_user).execute
{
# Mutation response is always a `nil` award_emoji
- errors: []
+ errors: service[:errors] || []
}
end
end
diff --git a/app/graphql/mutations/award_emojis/toggle.rb b/app/graphql/mutations/award_emojis/toggle.rb
index c03902e8035..d822048f3a6 100644
--- a/app/graphql/mutations/award_emojis/toggle.rb
+++ b/app/graphql/mutations/award_emojis/toggle.rb
@@ -15,23 +15,15 @@ module Mutations
check_object_is_awardable!(awardable)
- # TODO this will be handled by AwardEmoji::ToggleService
- # See https://gitlab.com/gitlab-org/gitlab-ce/issues/63372 and
- # https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/29782
- award = awardable.toggle_award_emoji(args[:name], current_user)
-
- # Destroy returns a collection :(
- award = award.first if award.is_a?(Array)
-
- errors = errors_on_object(award)
+ service = ::AwardEmojis::ToggleService.new(awardable, args[:name], current_user).execute
toggled_on = awardable.awarded_emoji?(args[:name], current_user)
{
# For consistency with the AwardEmojis::Remove mutation, only return
# the AwardEmoji if it was created and not destroyed
- award_emoji: (award if toggled_on),
- errors: errors,
+ award_emoji: (service[:award] if toggled_on),
+ errors: service[:errors] || [],
toggled_on: toggled_on
}
end
diff --git a/app/models/award_emoji.rb b/app/models/award_emoji.rb
index e26162f6151..0ab302a0f3e 100644
--- a/app/models/award_emoji.rb
+++ b/app/models/award_emoji.rb
@@ -16,8 +16,10 @@ class AwardEmoji < ApplicationRecord
participant :user
- scope :downvotes, -> { where(name: DOWNVOTE_NAME) }
- scope :upvotes, -> { where(name: UPVOTE_NAME) }
+ scope :downvotes, -> { named(DOWNVOTE_NAME) }
+ scope :upvotes, -> { named(UPVOTE_NAME) }
+ scope :named, -> (names) { where(name: names) }
+ scope :awarded_by, -> (users) { where(user: users) }
after_save :expire_etag_cache
after_destroy :expire_etag_cache
diff --git a/app/models/concerns/awardable.rb b/app/models/concerns/awardable.rb
index 14bc56f0eee..f229b42ade6 100644
--- a/app/models/concerns/awardable.rb
+++ b/app/models/concerns/awardable.rb
@@ -106,30 +106,6 @@ module Awardable
end
def awarded_emoji?(emoji_name, current_user)
- award_emoji.where(name: emoji_name, user: current_user).exists?
- end
-
- def create_award_emoji(name, current_user)
- return unless emoji_awardable?
-
- award_emoji.create(name: normalize_name(name), user: current_user)
- end
-
- def remove_award_emoji(name, current_user)
- award_emoji.where(name: name, user: current_user).destroy_all # rubocop: disable DestroyAll
- end
-
- def toggle_award_emoji(emoji_name, current_user)
- if awarded_emoji?(emoji_name, current_user)
- remove_award_emoji(emoji_name, current_user)
- else
- create_award_emoji(emoji_name, current_user)
- end
- end
-
- private
-
- def normalize_name(name)
- Gitlab::Emoji.normalize_emoji_name(name)
+ award_emoji.named(emoji_name).awarded_by(current_user).exists?
end
end
diff --git a/app/services/award_emojis/add_service.rb b/app/services/award_emojis/add_service.rb
new file mode 100644
index 00000000000..eac15dabbf0
--- /dev/null
+++ b/app/services/award_emojis/add_service.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+module AwardEmojis
+ class AddService < AwardEmojis::BaseService
+ include Gitlab::Utils::StrongMemoize
+
+ def execute
+ unless awardable.user_can_award?(current_user)
+ return error('User cannot award emoji to awardable', status: :forbidden)
+ end
+
+ unless awardable.emoji_awardable?
+ return error('Awardable cannot be awarded emoji', status: :unprocessable_entity)
+ end
+
+ award = awardable.award_emoji.create(name: name, user: current_user)
+
+ if award.persisted?
+ TodoService.new.new_award_emoji(todoable, current_user) if todoable
+ success(award: award)
+ else
+ error(award.errors.full_messages, award: award)
+ end
+ end
+
+ private
+
+ def todoable
+ strong_memoize(:todoable) do
+ case awardable
+ when Note
+ # We don't create todos for personal snippet comments for now
+ awardable.noteable unless awardable.for_personal_snippet?
+ when MergeRequest, Issue
+ awardable
+ when Snippet
+ nil
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/award_emojis/base_service.rb b/app/services/award_emojis/base_service.rb
new file mode 100644
index 00000000000..a677d03a221
--- /dev/null
+++ b/app/services/award_emojis/base_service.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module AwardEmojis
+ class BaseService < ::BaseService
+ attr_accessor :awardable, :name
+
+ def initialize(awardable, name, current_user)
+ @awardable = awardable
+ @name = normalize_name(name)
+
+ super(awardable.project, current_user)
+ end
+
+ private
+
+ def normalize_name(name)
+ Gitlab::Emoji.normalize_emoji_name(name)
+ end
+
+ # Provide more error state data than what BaseService allows.
+ # - An array of errors
+ # - The `AwardEmoji` if present
+ def error(errors, award: nil, status: nil)
+ errors = Array.wrap(errors)
+
+ super(errors.to_sentence.presence, status).merge({
+ award: award,
+ errors: errors
+ })
+ end
+ end
+end
diff --git a/app/services/award_emojis/collect_user_emoji_service.rb b/app/services/award_emojis/collect_user_emoji_service.rb
new file mode 100644
index 00000000000..6cab23f3edf
--- /dev/null
+++ b/app/services/award_emojis/collect_user_emoji_service.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+# Class for retrieving information about emoji awarded _by_ a particular user.
+module AwardEmojis
+ class CollectUserEmojiService
+ attr_reader :current_user
+
+ # current_user - The User to generate the data for.
+ def initialize(current_user = nil)
+ @current_user = current_user
+ end
+
+ def execute
+ return [] unless current_user
+
+ # We want the resulting data set to be an Array containing the emoji names
+ # in descending order, based on how often they were awarded.
+ AwardEmoji
+ .award_counts_for_user(current_user)
+ .map { |name, _| { name: name } }
+ end
+ end
+end
diff --git a/app/services/award_emojis/destroy_service.rb b/app/services/award_emojis/destroy_service.rb
new file mode 100644
index 00000000000..3789a8403bc
--- /dev/null
+++ b/app/services/award_emojis/destroy_service.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module AwardEmojis
+ class DestroyService < AwardEmojis::BaseService
+ def execute
+ unless awardable.user_can_award?(current_user)
+ return error('User cannot destroy emoji on the awardable', status: :forbidden)
+ end
+
+ awards = AwardEmojisFinder.new(awardable, name: name, awarded_by: current_user).execute
+
+ if awards.empty?
+ return error("User has not awarded emoji of type #{name} on the awardable", status: :forbidden)
+ end
+
+ award = awards.destroy_all.first # rubocop: disable DestroyAll
+
+ success(award: award)
+ end
+ end
+end
diff --git a/app/services/award_emojis/toggle_service.rb b/app/services/award_emojis/toggle_service.rb
new file mode 100644
index 00000000000..812dd1c2889
--- /dev/null
+++ b/app/services/award_emojis/toggle_service.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module AwardEmojis
+ class ToggleService < AwardEmojis::BaseService
+ def execute
+ if awardable.awarded_emoji?(name, current_user)
+ DestroyService.new(awardable, name, current_user).execute
+ else
+ AddService.new(awardable, name, current_user).execute
+ end
+ end
+ end
+end
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index 77c2224ee3b..2ab6e88599f 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -344,10 +344,7 @@ class IssuableBaseService < BaseService
def toggle_award(issuable)
award = params.delete(:emoji_award)
- if award
- todo_service.new_award_emoji(issuable, current_user)
- issuable.toggle_award_emoji(award, current_user)
- end
+ AwardEmojis::ToggleService.new(issuable, award, current_user).execute if award
end
def associations_before_update(issuable)