Commit cba2c203 authored by Toon Claes's avatar Toon Claes

Add scope to CustomEmoji to find emoji for resource

Award Emoji can be awarded on many things and it can be difficult to
determine which namespace the awardable belongs to.

Thus to centralize the logic that finds the custom emoji for an
awardable, we introduce a scope on the CustomEmoji model that accepts a
resource (being either a Project or a Group), determines it's root
namespace, and finds all CustomEmoji for it. In combination with the
previous commit, all the Awardable models respond to #resource_parent,
which can be provided to this new scope.

This change fixes award emoji on merge requests, epics, and issues in
nested groups.

Changelog: fixed
parent 69e73b0f
...@@ -19,6 +19,8 @@ class AwardEmoji < ApplicationRecord ...@@ -19,6 +19,8 @@ class AwardEmoji < ApplicationRecord
participant :user participant :user
delegate :resource_parent, to: :awardable, allow_nil: true
scope :downvotes, -> { named(DOWNVOTE_NAME) } scope :downvotes, -> { named(DOWNVOTE_NAME) }
scope :upvotes, -> { named(UPVOTE_NAME) } scope :upvotes, -> { named(UPVOTE_NAME) }
scope :named, -> (names) { where(name: names) } scope :named, -> (names) { where(name: names) }
...@@ -63,7 +65,7 @@ class AwardEmoji < ApplicationRecord ...@@ -63,7 +65,7 @@ class AwardEmoji < ApplicationRecord
def url def url
return if TanukiEmoji.find_by_alpha_code(name) return if TanukiEmoji.find_by_alpha_code(name)
awardable.try(:namespace)&.custom_emoji&.by_name(name)&.first&.url CustomEmoji.for_resource(resource_parent).by_name(name).select(:url).first&.url
end end
def expire_cache def expire_cache
......
...@@ -28,6 +28,19 @@ class CustomEmoji < ApplicationRecord ...@@ -28,6 +28,19 @@ class CustomEmoji < ApplicationRecord
alias_attribute :url, :file # this might need a change in https://gitlab.com/gitlab-org/gitlab/-/issues/230467 alias_attribute :url, :file # this might need a change in https://gitlab.com/gitlab-org/gitlab/-/issues/230467
# Find custom emoji for the given resource.
# A resource can be either a Project or a Group, or anything responding to #root_ancestor.
# Usually it's the return value of #resource_parent on any model.
scope :for_resource, -> (resource) do
return none if resource.nil?
namespace = resource.root_ancestor
return none if namespace.nil?
namespace.custom_emoji
end
private private
def valid_emoji_name def valid_emoji_name
......
...@@ -24,11 +24,9 @@ module Gitlab ...@@ -24,11 +24,9 @@ module Gitlab
end end
def valid_custom_emoji?(record, value) def valid_custom_emoji?(record, value)
namespace = record.try(:awardable).try(:namespace) resource = record.try(:resource_parent)
return unless namespace CustomEmoji.for_resource(resource).by_name(value.to_s).any?
namespace.custom_emoji&.by_name(value.to_s)&.any?
end end
end end
end end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe AwardEmoji do
describe 'validations' do
context 'custom emoji' do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:emoji) { create(:custom_emoji, name: 'partyparrot', namespace: group) }
before do
group.add_maintainer(user)
end
it 'accepts custom emoji on epic' do
epic = create(:epic, group: group)
new_award = build(:award_emoji, user: user, awardable: epic, name: emoji.name)
expect(new_award).to be_valid
end
it 'accepts custom emoji on subgroup epic' do
subgroup = create(:group, parent: group)
epic = create(:epic, group: subgroup)
new_award = build(:award_emoji, user: user, awardable: epic, name: emoji.name)
expect(new_award).to be_valid
end
end
end
end
...@@ -59,17 +59,41 @@ RSpec.describe AwardEmoji do ...@@ -59,17 +59,41 @@ RSpec.describe AwardEmoji do
end end
end end
it 'accepts custom emoji' do context 'custom emoji' do
user = create(:user) let_it_be(:user) { create(:user) }
group = create(:group) let_it_be(:group) { create(:group) }
group.add_maintainer(user) let_it_be(:emoji) { create(:custom_emoji, name: 'partyparrot', namespace: group) }
project = create(:project, namespace: group) before do
issue = create(:issue, project: project) group.add_maintainer(user)
emoji = create(:custom_emoji, name: 'partyparrot', namespace: group) end
new_award = build(:award_emoji, user: user, awardable: issue, name: emoji.name)
%i[issue merge_request note_on_issue snippet].each do |awardable_type|
let_it_be(:project) { create(:project, namespace: group) }
let(:awardable) { create(awardable_type, project: project) }
it "is accepted on #{awardable_type}" do
new_award = build(:award_emoji, user: user, awardable: awardable, name: emoji.name)
expect(new_award).to be_valid
end
end
expect(new_award).to be_valid it 'is accepted on subgroup issue' do
subgroup = create(:group, parent: group)
project = create(:project, namespace: subgroup)
issue = create(:issue, project: project)
new_award = build(:award_emoji, user: user, awardable: issue, name: emoji.name)
expect(new_award).to be_valid
end
it 'is not supported on personal snippet (yet)' do
snippet = create(:personal_snippet)
new_award = build(:award_emoji, user: snippet.author, awardable: snippet, name: 'null')
expect(new_award).not_to be_valid
end
end end
end end
......
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