Commit 27f7c92d authored by Michael Kozono's avatar Michael Kozono

Merge branch 'ajk-design-todos-send-notifications' into 'master'

Ensure design notifications are sent

Closes #12527

See merge request gitlab-org/gitlab!15250
parents bca260ad 8dfe1b9e
...@@ -45,7 +45,11 @@ module Emails ...@@ -45,7 +45,11 @@ module Emails
private private
def note_target_url_options def note_target_url_options
[@project || @group, @note.noteable, anchor: "note_#{@note.id}"] [@project || @group, @note.noteable, note_target_url_query_params]
end
def note_target_url_query_params
{ anchor: "note_#{@note.id}" }
end end
def note_thread_options(recipient_id, reason) def note_thread_options(recipient_id, reason)
......
...@@ -10,6 +10,18 @@ module EE ...@@ -10,6 +10,18 @@ module EE
@target_url = group_epic_url(*note_target_url_options) @target_url = group_epic_url(*note_target_url_options)
mail_answer_note_thread(@epic, @note, note_thread_options(recipient_id, reason)) mail_answer_note_thread(@epic, @note, note_thread_options(recipient_id, reason))
end end
def note_design_email(recipient_id, note_id, reason = nil)
setup_note_mail(note_id, recipient_id)
design = @note.noteable
@target_url = ::Gitlab::Routing.url_helpers.designs_project_issue_url(
@note.parent,
design.issue,
note_target_url_query_params.merge(vueroute: design.filename)
)
mail_answer_note_thread(design, @note, note_thread_options(recipient_id, reason))
end
end end
end end
end end
...@@ -5,6 +5,7 @@ module DesignManagement ...@@ -5,6 +5,7 @@ module DesignManagement
include Noteable include Noteable
include Gitlab::FileTypeDetection include Gitlab::FileTypeDetection
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
include Referable
belongs_to :project, inverse_of: :designs belongs_to :project, inverse_of: :designs
belongs_to :issue belongs_to :issue
...@@ -67,8 +68,17 @@ module DesignManagement ...@@ -67,8 +68,17 @@ module DesignManagement
strong_memoize(:most_recent_design_version) { design_versions.ordered.last } strong_memoize(:most_recent_design_version) { design_versions.ordered.last }
end end
# A reference for a design is the issue reference, indexed by the filename
# with an optional infix when full.
#
# e.g.
# #123[homescreen.png]
# other-project#72[sidebar.jpg]
# #38/designs[transition.gif]
def to_reference(from = nil, full: false) def to_reference(from = nil, full: false)
filename infix = full ? '/designs' : ''
"%s%s[%s]" % [issue.to_reference(from, full: full), infix, filename]
end end
def to_ability_name def to_ability_name
......
...@@ -52,7 +52,7 @@ module EE ...@@ -52,7 +52,7 @@ module EE
end end
def for_design? def for_design?
noteable.is_a?(DesignManagement::Design) noteable_type == DesignManagement::Design.name
end end
override :parent override :parent
......
---
title: Ensure design notifications are sent
merge_request: 15250
author:
type: changed
...@@ -87,12 +87,16 @@ module Gitlab ...@@ -87,12 +87,16 @@ module Gitlab
approvals_before_merge || target_project.approvals_before_merge approvals_before_merge || target_project.approvals_before_merge
end end
def distinct(column)
Arel.sql("distinct #{column}")
end
def approver_ids def approver_ids
@approver_ids ||= Approver.where(target_type: 'MergeRequest', target_id: id).joins(:user).pluck('distinct user_id') @approver_ids ||= Approver.where(target_type: 'MergeRequest', target_id: id).joins(:user).pluck(distinct(:user_id))
end end
def approver_group_ids def approver_group_ids
@approver_group_ids ||= ApproverGroup.where(target_type: 'MergeRequest', target_id: id).joins(:group).pluck('distinct group_id') @approver_group_ids ||= ApproverGroup.where(target_type: 'MergeRequest', target_id: id).joins(:group).pluck(distinct(:group_id))
end end
def sync_code_owners_with_approvers def sync_code_owners_with_approvers
......
...@@ -34,8 +34,8 @@ describe 'Dashboard todos' do ...@@ -34,8 +34,8 @@ describe 'Dashboard todos' do
expect(page).to have_selector('.todos-list .todo', count: 1) expect(page).to have_selector('.todos-list .todo', count: 1)
end end
it 'has a link that will take me to the design page', :js do it 'has a link that will take me to the design page' do
click_link "design #{target.filename}" click_link "design #{target.to_reference}"
expectation = Gitlab::Routing.url_helpers.designs_project_issue_path( expectation = Gitlab::Routing.url_helpers.designs_project_issue_path(
target.project, target.issue, target.filename target.project, target.issue, target.filename
......
...@@ -29,7 +29,7 @@ describe ::TodosHelper do ...@@ -29,7 +29,7 @@ describe ::TodosHelper do
it 'produces a good link' do it 'produces a good link' do
path = helper.todo_target_path(todo) path = helper.todo_target_path(todo)
link = helper.todo_target_link(todo) link = helper.todo_target_link(todo)
expected = "<a href=\"#{path}\">design #{design.filename}</a>" expected = "<a href=\"#{path}\">design #{design.to_reference}</a>"
expect(link).to eq(expected) expect(link).to eq(expected)
end end
......
...@@ -36,6 +36,30 @@ describe Notify do ...@@ -36,6 +36,30 @@ describe Notify do
description: 'Awesome description') description: 'Awesome description')
end end
describe '.note_design_email' do
set(:design) { create(:design, :with_file) }
set(:recipient) { create(:user) }
set(:note) do
create(:diff_note_on_design,
noteable: design,
project: design.project,
note: "Hello #{recipient.to_reference}")
end
let(:header_name) { 'X-Gitlab-DesignManagement-Design-ID' }
let(:refer_to_design) do
have_attributes(subject: a_string_including(design.filename))
end
subject { described_class.note_design_email(recipient.id, note.id) }
it { is_expected.to have_header(header_name, design.id.to_s) }
it { is_expected.to have_body_text(design.filename) }
it { is_expected.to refer_to_design }
end
context 'for a project' do context 'for a project' do
context 'for service desk issues' do context 'for service desk issues' do
before do before do
...@@ -90,7 +114,7 @@ describe Notify do ...@@ -90,7 +114,7 @@ describe Notify do
end end
it "contains the approvers list" do it "contains the approvers list" do
is_expected.to have_body_text /#{merge_request.approvers.first.user.name}/ is_expected.to have_body_text %r[#{merge_request.approvers.first.user.name}]
end end
end end
...@@ -117,26 +141,32 @@ describe Notify do ...@@ -117,26 +141,32 @@ describe Notify do
end end
it 'has the correct subject' do it 'has the correct subject' do
is_expected.to have_subject /#{merge_request.title} \(#{merge_request.to_reference}\)/ is_expected.to have_attributes(
subject: a_string_including("#{merge_request.title} (#{merge_request.to_reference})")
)
end end
it 'contains the new status' do it 'contains the new status' do
is_expected.to have_body_text /approved/i is_expected.to have_body_text('approved')
end end
it 'contains a link to the merge request' do it 'contains a link to the merge request' do
is_expected.to have_body_text /#{project_merge_request_path project, merge_request}/ is_expected.to have_body_text("#{project_merge_request_path project, merge_request}")
end end
it 'contains the names of all of the approvers' do it 'contains the names of all of the approvers' do
merge_request.approvals.each do |approval| names = merge_request.approvals.map { |a| a.user.name }
is_expected.to have_body_text /#{approval.user.name}/
aggregate_failures do
names.each { |name| is_expected.to have_body_text(name) }
end end
end end
it 'contains the names of all assignees' do it 'contains the names of all assignees' do
merge_request.assignees.each do |assignee| names = merge_request.assignees.map(&:name)
is_expected.to have_body_text /#{assignee.name}/
aggregate_failures do
names.each { |name| is_expected.to have_body_text(name) }
end end
end end
...@@ -173,26 +203,32 @@ describe Notify do ...@@ -173,26 +203,32 @@ describe Notify do
end end
it 'has the correct subject' do it 'has the correct subject' do
is_expected.to have_subject /#{merge_request.title} \(#{merge_request.to_reference}\)/ is_expected.to have_attributes(
subject: a_string_including("#{merge_request.title} (#{merge_request.to_reference})")
)
end end
it 'contains the new status' do it 'contains the new status' do
is_expected.to have_body_text /unapproved/i is_expected.to have_body_text('unapproved')
end end
it 'contains a link to the merge request' do it 'contains a link to the merge request' do
is_expected.to have_body_text /#{project_merge_request_path project, merge_request}/ is_expected.to have_body_text("#{project_merge_request_path project, merge_request}")
end end
it 'contains the names of all of the approvers' do it 'contains the names of all of the approvers' do
merge_request.approvals.each do |approval| names = merge_request.approvals.map { |a| a.user.name }
is_expected.to have_body_text /#{approval.user.name}/
aggregate_failures do
names.each { |name| is_expected.to have_body_text(name) }
end end
end end
it 'contains the names of all assignees' do it 'contains the names of all assignees' do
merge_request.assignees.each do |assignee| names = merge_request.assignees.map(&:name)
is_expected.to have_body_text /#{assignee.name}/
aggregate_failures do
names.each { |name| is_expected.to have_body_text(name) }
end end
end end
end end
...@@ -208,7 +244,7 @@ describe Notify do ...@@ -208,7 +244,7 @@ describe Notify do
end end
it 'contains the new status' do it 'contains the new status' do
is_expected.to have_body_text /unapproved/i is_expected.to have_body_text('unapproved')
end end
end end
end end
......
...@@ -39,6 +39,17 @@ describe Notes::CreateService do ...@@ -39,6 +39,17 @@ describe Notes::CreateService do
expect(note.noteable).to eq(design) expect(note.noteable).to eq(design)
end end
it 'sends a notification about this note' do
notifier = double
allow(::NotificationService).to receive(:new).and_return(notifier)
expect(notifier)
.to receive(:new_note)
.with have_attributes(noteable: design)
service.execute
end
it 'correctly builds the position of the note' do it 'correctly builds the position of the note' do
note = service.execute note = service.execute
......
...@@ -3,13 +3,65 @@ require 'spec_helper' ...@@ -3,13 +3,65 @@ require 'spec_helper'
describe EE::NotificationService, :mailer do describe EE::NotificationService, :mailer do
include EmailSpec::Matchers include EmailSpec::Matchers
include NotificationHelpers include NotificationHelpers
include DesignManagementTestHelpers
let(:subject) { NotificationService.new } let(:subject) { NotificationService.new }
let(:mailer) { double(deliver_later: true) }
context 'when notified of a new design diff note' do
set(:design) { create(:design, :with_file) }
set(:project) { design.project }
set(:dev) { create(:user) }
set(:stranger) { create(:user) }
set(:note) do
create(:diff_note_on_design,
noteable: design,
project: project,
note: "Hello #{dev.to_reference}, G'day #{stranger.to_reference}")
end
context 'design management is enabled' do
before do
enable_design_management
project.add_developer(dev)
allow(Notify).to receive(:note_design_email) { mailer }
end
it 'sends new note notifications' do
expect(subject).to receive(:send_new_note_notifications).with(note)
subject.new_note(note)
end
it 'sends a mail to the developer' do
expect(Notify)
.to receive(:note_design_email).with(dev.id, note.id, "mentioned")
subject.new_note(note)
end
it 'does not notify non-developers' do
expect(Notify)
.not_to receive(:note_design_email).with(stranger.id, note.id)
subject.new_note(note)
end
end
context 'design management is disabled' do
it 'does not notify the user' do
expect(Notify).not_to receive(:note_design_email)
subject.new_note(note)
end
end
end
context 'service desk issues' do context 'service desk issues' do
before do before do
allow(Notify).to receive(:service_desk_new_note_email) allow(Notify).to receive(:service_desk_new_note_email)
.with(kind_of(Integer), kind_of(Integer)).and_return(double(deliver_later: true)) .with(Integer, Integer).and_return(mailer)
allow(::EE::Gitlab::ServiceDesk).to receive(:enabled?).and_return(true) allow(::EE::Gitlab::ServiceDesk).to receive(:enabled?).and_return(true)
allow(::Gitlab::IncomingEmail).to receive(:enabled?) { true } allow(::Gitlab::IncomingEmail).to receive(:enabled?) { true }
...@@ -17,7 +69,8 @@ describe EE::NotificationService, :mailer do ...@@ -17,7 +69,8 @@ describe EE::NotificationService, :mailer do
end end
def should_email! def should_email!
expect(Notify).to receive(:service_desk_new_note_email).with(issue.id, kind_of(Integer)) expect(Notify).to receive(:service_desk_new_note_email)
.with(issue.id, note.id)
end end
def should_not_email! def should_not_email!
......
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