Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
baa05571
Commit
baa05571
authored
Apr 25, 2018
by
Mario de la Ossa
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add notifications to Epics
parent
954b8603
Changes
36
Hide whitespace changes
Inline
Side-by-side
Showing
36 changed files
with
499 additions
and
99 deletions
+499
-99
app/helpers/emails_helper.rb
app/helpers/emails_helper.rb
+2
-0
app/mailers/emails/notes.rb
app/mailers/emails/notes.rb
+5
-2
app/mailers/notify.rb
app/mailers/notify.rb
+11
-4
app/models/note.rb
app/models/note.rb
+0
-4
app/models/sent_notification.rb
app/models/sent_notification.rb
+2
-2
app/services/notification_recipient_service.rb
app/services/notification_recipient_service.rb
+30
-5
app/workers/new_note_worker.rb
app/workers/new_note_worker.rb
+1
-1
config/routes/group.rb
config/routes/group.rb
+1
-0
ee/app/controllers/groups/epics_controller.rb
ee/app/controllers/groups/epics_controller.rb
+6
-0
ee/app/helpers/ee/emails_helper.rb
ee/app/helpers/ee/emails_helper.rb
+12
-0
ee/app/helpers/epics_helper.rb
ee/app/helpers/epics_helper.rb
+7
-1
ee/app/mailers/ee/notify.rb
ee/app/mailers/ee/notify.rb
+19
-0
ee/app/mailers/emails/ee/notes.rb
ee/app/mailers/emails/ee/notes.rb
+15
-0
ee/app/models/ee/note.rb
ee/app/models/ee/note.rb
+0
-5
ee/app/views/groups/epics/show.html.haml
ee/app/views/groups/epics/show.html.haml
+1
-2
ee/app/views/notify/note_epic_email.html.haml
ee/app/views/notify/note_epic_email.html.haml
+1
-0
ee/app/views/notify/note_epic_email.text.erb
ee/app/views/notify/note_epic_email.text.erb
+1
-0
ee/changelogs/unreleased/5480-epic-notifications.yml
ee/changelogs/unreleased/5480-epic-notifications.yml
+5
-0
ee/spec/helpers/ee/emails_helper_spec.rb
ee/spec/helpers/ee/emails_helper_spec.rb
+21
-0
ee/spec/helpers/epics_helper_spec.rb
ee/spec/helpers/epics_helper_spec.rb
+4
-2
ee/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
ee/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
+116
-0
ee/spec/lib/gitlab/email/handler/ee/service_desk_handler_spec.rb
.../lib/gitlab/email/handler/ee/service_desk_handler_spec.rb
+0
-1
ee/spec/mailers/notify_spec.rb
ee/spec/mailers/notify_spec.rb
+46
-0
ee/spec/services/ee/notification_service_spec.rb
ee/spec/services/ee/notification_service_spec.rb
+119
-0
lib/gitlab/email/handler/create_note_handler.rb
lib/gitlab/email/handler/create_note_handler.rb
+2
-1
lib/gitlab/email/handler/reply_processing.rb
lib/gitlab/email/handler/reply_processing.rb
+6
-2
spec/lib/gitlab/email/handler/create_issue_handler_spec.rb
spec/lib/gitlab/email/handler/create_issue_handler_spec.rb
+0
-1
spec/lib/gitlab/email/handler/create_merge_request_handler_spec.rb
...gitlab/email/handler/create_merge_request_handler_spec.rb
+0
-1
spec/lib/gitlab/email/handler/create_note_handler_spec.rb
spec/lib/gitlab/email/handler/create_note_handler_spec.rb
+0
-1
spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb
spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb
+0
-1
spec/lib/gitlab/email/receiver_spec.rb
spec/lib/gitlab/email/receiver_spec.rb
+0
-1
spec/mailers/notify_spec.rb
spec/mailers/notify_spec.rb
+0
-32
spec/services/notification_service_spec.rb
spec/services/notification_service_spec.rb
+1
-30
spec/support/helpers/notification_helpers.rb
spec/support/helpers/notification_helpers.rb
+33
-0
spec/support/shared_contexts/email_shared_blocks.rb
spec/support/shared_contexts/email_shared_blocks.rb
+0
-0
spec/support/shared_examples/notify_shared_examples.rb
spec/support/shared_examples/notify_shared_examples.rb
+32
-0
No files found.
app/helpers/emails_helper.rb
View file @
baa05571
module
EmailsHelper
prepend
EE
::
EmailsHelper
include
AppearancesHelper
# Google Actions
...
...
app/mailers/emails/notes.rb
View file @
baa05571
module
Emails
module
Notes
prepend
Emails
::
EE
::
Notes
def
note_commit_email
(
recipient_id
,
note_id
)
setup_note_mail
(
note_id
,
recipient_id
)
...
...
@@ -43,7 +45,7 @@ module Emails
private
def
note_target_url_options
[
@project
,
@note
.
noteable
,
anchor:
"note_
#{
@note
.
id
}
"
]
[
@project
||
@group
,
@note
.
noteable
,
anchor:
"note_
#{
@note
.
id
}
"
]
end
def
note_thread_options
(
recipient_id
)
...
...
@@ -58,8 +60,9 @@ module Emails
# `note_id` is a `Note` when originating in `NotifyPreview`
@note
=
note_id
.
is_a?
(
Note
)
?
note_id
:
Note
.
find
(
note_id
)
@project
=
@note
.
project
@group
=
@note
.
noteable
.
try
(
:group
)
if
@project
&&
@note
.
persisted?
if
(
@project
||
@group
)
&&
@note
.
persisted?
@sent_notification
=
SentNotification
.
record_note
(
@note
,
recipient_id
,
reply_key
)
end
end
...
...
app/mailers/notify.rb
View file @
baa05571
class
Notify
<
BaseMailer
prepend
EE
::
Notify
include
ActionDispatch
::
Routing
::
PolymorphicRoutes
include
GitlabRoutingHelper
...
...
@@ -98,6 +100,7 @@ class Notify < BaseMailer
def
subject
(
*
extra
)
subject
=
""
subject
<<
"
#{
@project
.
name
}
| "
if
@project
subject
<<
"
#{
@group
.
name
}
| "
if
@group
subject
<<
extra
.
join
(
' | '
)
if
extra
.
present?
subject
<<
" |
#{
Gitlab
.
config
.
gitlab
.
email_subject_suffix
}
"
if
Gitlab
.
config
.
gitlab
.
email_subject_suffix
.
present?
subject
...
...
@@ -121,10 +124,9 @@ class Notify < BaseMailer
@reason
=
headers
[
'X-GitLab-NotificationReason'
]
if
Gitlab
::
IncomingEmail
.
enabled?
&&
@sent_notification
address
=
Mail
::
Address
.
new
(
Gitlab
::
IncomingEmail
.
reply_address
(
reply_key
))
address
.
display_name
=
@project
.
full_name
headers
[
'Reply-To'
]
=
address
headers
[
'Reply-To'
]
=
Mail
::
Address
.
new
(
Gitlab
::
IncomingEmail
.
reply_address
(
reply_key
)).
tap
do
|
address
|
address
.
display_name
=
reply_display_name
(
model
)
end
fallback_reply_message_id
=
"<reply-
#{
reply_key
}
@
#{
Gitlab
.
config
.
gitlab
.
host
}
>"
.
freeze
headers
[
'References'
]
||=
[]
...
...
@@ -136,6 +138,11 @@ class Notify < BaseMailer
mail
(
headers
)
end
# `model` is used on EE code
def
reply_display_name
(
_model
)
@project
.
full_name
end
# Send an email that starts a new conversation thread,
# with headers suitable for grouping by thread in email clients.
#
...
...
app/models/note.rb
View file @
baa05571
...
...
@@ -325,10 +325,6 @@ class Note < ActiveRecord::Base
!
system
?
&&
!
for_snippet?
end
def
can_create_notification?
true
end
def
discussion_class
(
noteable
=
nil
)
# When commit notes are rendered on an MR's Discussion page, they are
# displayed in one discussion instead of individually.
...
...
app/models/sent_notification.rb
View file @
baa05571
...
...
@@ -5,14 +5,14 @@ class SentNotification < ActiveRecord::Base
belongs_to
:noteable
,
polymorphic:
true
# rubocop:disable Cop/PolymorphicAssociations
belongs_to
:recipient
,
class_name:
"User"
validates
:
project
,
:
recipient
,
presence:
true
validates
:recipient
,
presence:
true
validates
:reply_key
,
presence:
true
,
uniqueness:
true
validates
:noteable_id
,
presence:
true
,
unless: :for_commit?
validates
:commit_id
,
presence:
true
,
if: :for_commit?
validates
:in_reply_to_discussion_id
,
format:
{
with:
/\A\h{40}\z/
,
allow_nil:
true
}
validate
:note_valid
after_save
:keep_around_commit
after_save
:keep_around_commit
,
if: :for_commit?
class
<<
self
def
reply_key
...
...
app/services/notification_recipient_service.rb
View file @
baa05571
...
...
@@ -45,6 +45,10 @@ module NotificationRecipientService
target
.
project
end
def
group
project
&
.
group
||
target
.
try
(
:group
)
end
def
recipients
@recipients
||=
[]
end
...
...
@@ -67,6 +71,7 @@ module NotificationRecipientService
user
,
type
,
reason:
reason
,
project:
project
,
group:
group
,
custom_action:
custom_action
,
target:
target
,
acting_user:
acting_user
...
...
@@ -107,11 +112,11 @@ module NotificationRecipientService
# Users with a notification setting on group or project
user_ids
+=
user_ids_notifiable_on
(
project
,
:custom
)
user_ids
+=
user_ids_notifiable_on
(
project
.
group
,
:custom
)
user_ids
+=
user_ids_notifiable_on
(
group
,
:custom
)
# Users with global level custom
user_ids_with_project_level_global
=
user_ids_notifiable_on
(
project
,
:global
)
user_ids_with_group_level_global
=
user_ids_notifiable_on
(
project
.
group
,
:global
)
user_ids_with_group_level_global
=
user_ids_notifiable_on
(
group
,
:global
)
global_users_ids
=
user_ids_with_project_level_global
.
concat
(
user_ids_with_group_level_global
)
user_ids
+=
user_ids_with_global_level_custom
(
global_users_ids
,
custom_action
)
...
...
@@ -123,6 +128,10 @@ module NotificationRecipientService
add_recipients
(
project_watchers
,
:watch
,
nil
)
end
def
add_group_watchers
add_recipients
(
group_watchers
,
:watch
,
nil
)
end
# Get project users with WATCH notification level
def
project_watchers
project_members_ids
=
user_ids_notifiable_on
(
project
)
...
...
@@ -138,6 +147,14 @@ module NotificationRecipientService
user_scope
.
where
(
id:
user_ids_with_project_setting
.
concat
(
user_ids_with_group_setting
).
uniq
)
end
def
group_watchers
user_ids_with_group_global
=
user_ids_notifiable_on
(
group
,
:global
)
user_ids
=
user_ids_with_global_level_watch
(
user_ids_with_group_global
)
user_ids_with_group_setting
=
select_group_members_ids
(
group
,
[],
user_ids_with_group_global
,
user_ids
)
user_scope
.
where
(
id:
user_ids_with_group_setting
)
end
def
add_subscribed_users
return
unless
target
.
respond_to?
:subscribers
...
...
@@ -281,6 +298,14 @@ module NotificationRecipientService
note
.
project
end
def
group
if
note
.
for_project_noteable?
project
.
group
else
target
.
try
(
:group
)
end
end
def
build!
# Add all users participating in the thread (author, assignee, comment authors)
add_participants
(
note
.
author
)
...
...
@@ -289,11 +314,11 @@ module NotificationRecipientService
if
note
.
for_project_noteable?
# Merge project watchers
add_project_watchers
# Merge project with custom notification
add_custom_notifications
else
add_group_watchers
end
add_custom_notifications
add_subscribed_users
end
...
...
app/workers/new_note_worker.rb
View file @
baa05571
...
...
@@ -5,7 +5,7 @@ class NewNoteWorker
# old `NewNoteWorker` jobs (can remove later)
def
perform
(
note_id
,
_params
=
{})
if
note
=
Note
.
find_by
(
id:
note_id
)
NotificationService
.
new
.
new_note
(
note
)
if
note
.
can_create_notification?
NotificationService
.
new
.
new_note
(
note
)
Notes
::
PostProcessService
.
new
(
note
).
execute
else
Rails
.
logger
.
error
(
"NewNoteWorker: couldn't find note with ID=
#{
note_id
}
, skipping job"
)
...
...
config/routes/group.rb
View file @
baa05571
...
...
@@ -95,6 +95,7 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
member
do
get
:discussions
,
format: :json
get
:realtime_changes
post
:toggle_subscription
end
resources
:epic_issues
,
only:
[
:index
,
:create
,
:destroy
,
:update
],
as:
'issues'
,
path:
'issues'
...
...
ee/app/controllers/groups/epics_controller.rb
View file @
baa05571
...
...
@@ -2,6 +2,7 @@ class Groups::EpicsController < Groups::ApplicationController
include
IssuableActions
include
IssuableCollections
include
ToggleAwardEmoji
include
ToggleSubscriptionAction
include
RendersNotes
before_action
:check_epics_available!
...
...
@@ -51,6 +52,11 @@ class Groups::EpicsController < Groups::ApplicationController
end
alias_method
:issuable
,
:epic
alias_method
:awardable
,
:epic
alias_method
:subscribable_resource
,
:epic
def
subscribable_project
nil
end
def
epic_params
params
.
require
(
:epic
).
permit
(
*
epic_params_attributes
)
...
...
ee/app/helpers/ee/emails_helper.rb
0 → 100644
View file @
baa05571
module
EE
module
EmailsHelper
extend
::
Gitlab
::
Utils
::
Override
override
:action_title
def
action_title
(
url
)
return
"View Epic"
if
url
.
split
(
"/"
).
include?
(
'epics'
)
super
end
end
end
ee/app/helpers/epics_helper.rb
View file @
baa05571
...
...
@@ -15,11 +15,17 @@ module EpicsHelper
end_date:
epic
.
end_date
}
participants
=
UserSerializer
.
new
.
represent
(
epic
.
participants
)
initial
=
opts
[
:initial
].
merge
(
labels:
epic
.
labels
,
participants:
participants
,
subscribed:
epic
.
subscribed?
(
current_user
))
{
initial:
opts
[
:initial
].
merge
(
labels:
epic
.
labels
)
.
to_json
,
initial:
initial
.
to_json
,
meta:
epic_meta
.
to_json
,
namespace:
group
.
path
,
labels_path:
group_labels_path
(
group
,
format: :json
,
only_group_labels:
true
,
include_ancestor_groups:
true
),
toggle_subscription_path:
toggle_subscription_group_epic_path
(
group
,
epic
),
labels_web_url:
group_labels_path
(
group
),
epics_web_url:
group_epics_path
(
group
)
}
...
...
ee/app/mailers/ee/notify.rb
0 → 100644
View file @
baa05571
module
EE
module
Notify
extend
ActiveSupport
::
Concern
extend
::
Gitlab
::
Utils
::
Override
included
do
attr_reader
:group
end
private
override
:reply_display_name
def
reply_display_name
(
model
)
return
super
unless
model
.
is_a?
(
Epic
)
group
.
full_name
end
end
end
ee/app/mailers/emails/ee/notes.rb
0 → 100644
View file @
baa05571
module
Emails
module
EE
module
Notes
extend
::
Gitlab
::
Utils
::
Override
def
note_epic_email
(
recipient_id
,
note_id
)
setup_note_mail
(
note_id
,
recipient_id
)
@epic
=
@note
.
noteable
@target_url
=
group_epic_url
(
*
note_target_url_options
)
mail_answer_note_thread
(
@epic
,
@note
,
note_thread_options
(
recipient_id
))
end
end
end
end
ee/app/models/ee/note.rb
View file @
baa05571
...
...
@@ -21,11 +21,6 @@ module EE
!
for_epic?
&&
super
end
override
:can_create_notification?
def
can_create_notification?
!
for_epic?
&&
super
end
override
:etag_key
def
etag_key
if
for_epic?
...
...
ee/app/views/groups/epics/show.html.haml
View file @
baa05571
...
...
@@ -2,8 +2,7 @@
-
@no_container
=
false
-
@content_class
=
"limit-container-width"
unless
fluid_layout
-# TODO: Move this to @epic.to_reference when implementing gitlab-ee#3853
-
epic_reference
=
"&
#{
@epic
.
iid
}
"
-
epic_reference
=
@epic
.
to_reference
-
add_to_breadcrumbs
_
(
"Epics"
),
group_epics_path
(
@group
)
-
breadcrumb_title
epic_reference
...
...
ee/app/views/notify/note_epic_email.html.haml
0 → 100644
View file @
baa05571
=
render
'note_email'
ee/app/views/notify/note_epic_email.text.erb
0 → 100644
View file @
baa05571
<%=
render
'note_email'
%>
ee/changelogs/unreleased/5480-epic-notifications.yml
0 → 100644
View file @
baa05571
---
title
:
Email notifications for epics
merge_request
:
author
:
type
:
added
ee/spec/helpers/ee/emails_helper_spec.rb
0 → 100644
View file @
baa05571
require
"spec_helper"
describe
EE
::
EmailsHelper
do
describe
'#action_title'
do
using
RSpec
::
Parameterized
::
TableSyntax
where
(
:path
,
:result
)
do
'somedomain.com/groups/agroup/-/epics/231'
|
'View Epic'
'somedomain.com/aproject/issues/231'
|
'View Issue'
'somedomain.com/aproject/merge_requests/231'
|
'View Merge request'
'somedomain.com/aproject/commit/al3f231'
|
'View Commit'
end
with_them
do
it
'should return the expected title'
do
title
=
helper
.
action_title
(
path
)
expect
(
title
).
to
eq
(
result
)
end
end
end
end
ee/spec/helpers/epics_helper_spec.rb
View file @
baa05571
...
...
@@ -8,10 +8,12 @@ describe EpicsHelper do
user
=
create
(
:user
)
@epic
=
create
(
:epic
,
author:
user
)
data
=
epic_show_app_data
(
@epic
,
initial:
{},
author_icon:
'icon_path'
)
allow
(
helper
).
to
receive
(
:current_user
).
and_return
(
user
)
data
=
helper
.
epic_show_app_data
(
@epic
,
initial:
{},
author_icon:
'icon_path'
)
meta_data
=
JSON
.
parse
(
data
[
:meta
])
expected_keys
=
%i(initial meta namespace labels_path labels_web_url epics_web_url)
expected_keys
=
%i(initial meta namespace labels_path
toggle_subscription_path
labels_web_url epics_web_url)
expect
(
data
.
keys
).
to
match_array
(
expected_keys
)
expect
(
meta_data
.
keys
).
to
match_array
(
%w[created author start_date end_date]
)
expect
(
meta_data
[
'author'
]).
to
eq
({
...
...
ee/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
0 → 100644
View file @
baa05571
require
'spec_helper'
describe
Gitlab
::
Email
::
Handler
::
CreateNoteHandler
do
include_context
:email_shared_context
before
do
stub_incoming_email_setting
(
enabled:
true
,
address:
"reply+%{key}@appmail.adventuretime.ooo"
)
stub_config_setting
(
host:
'localhost'
)
stub_licensed_features
(
epics:
true
)
end
let
(
:email_raw
)
{
fixture_file
(
'emails/valid_reply.eml'
)
}
let
(
:group
)
{
create
(
:group_with_members
)
}
let
(
:user
)
{
group
.
users
.
first
}
let
(
:noteable
)
{
create
(
:epic
,
group:
group
)
}
let
(
:note
)
{
create
(
:note
,
project:
nil
,
noteable:
noteable
)}
let!
(
:sent_notification
)
do
SentNotification
.
record_note
(
note
,
user
.
id
,
mail_key
)
end
context
"when the note could not be saved"
do
before
do
allow_any_instance_of
(
Note
).
to
receive
(
:persisted?
).
and_return
(
false
)
end
it
"raises an InvalidNoteError"
do
expect
{
receiver
.
execute
}.
to
raise_error
(
Gitlab
::
Email
::
InvalidNoteError
)
end
end
context
'when the note contains quick actions'
do
let!
(
:email_raw
)
{
fixture_file
(
"emails/commands_in_reply.eml"
)
}
context
'and current user cannot update the noteable'
do
it
'only executes the commands that the user can perform'
do
expect
{
receiver
.
execute
}
.
to
change
{
noteable
.
notes
.
user
.
count
}.
by
(
1
)
end
end
context
'and current user can update noteable'
do
before
do
group
.
add_developer
(
user
)
end
it
'posts a note and updates the noteable'
do
expect
(
TodoService
.
new
.
todo_exist?
(
noteable
,
user
)).
to
be_falsy
expect
{
receiver
.
execute
}
.
to
change
{
noteable
.
notes
.
user
.
count
}.
by
(
1
)
end
end
end
context
"when the reply is blank"
do
let!
(
:email_raw
)
{
fixture_file
(
"emails/no_content_reply.eml"
)
}
it
"raises an EmptyEmailError"
do
expect
{
receiver
.
execute
}.
to
raise_error
(
Gitlab
::
Email
::
EmptyEmailError
)
end
end
context
"when everything is fine"
do
before
do
setup_attachment
end
it
"creates a comment"
do
expect
{
receiver
.
execute
}.
to
change
{
noteable
.
notes
.
count
}.
by
(
1
)
new_note
=
noteable
.
notes
.
last
expect
(
new_note
.
author
).
to
eq
(
sent_notification
.
recipient
)
expect
(
new_note
.
position
).
to
eq
(
note
.
position
)
expect
(
new_note
.
note
).
to
include
(
"I could not disagree more."
)
expect
(
new_note
.
in_reply_to?
(
note
)).
to
be_truthy
end
it
"adds all attachments"
do
receiver
.
execute
note
=
noteable
.
notes
.
last
expect
(
note
.
note
).
to
include
(
markdown
)
end
context
'when sub-addressing is not supported'
do
before
do
stub_incoming_email_setting
(
enabled:
true
,
address:
nil
)
end
shared_examples
'an email that contains a mail key'
do
|
header
|
it
"fetches the mail key from the
#{
header
}
header and creates a comment"
do
expect
{
receiver
.
execute
}.
to
change
{
noteable
.
notes
.
count
}.
by
(
1
)
new_note
=
noteable
.
notes
.
last
expect
(
new_note
.
author
).
to
eq
(
sent_notification
.
recipient
)
expect
(
new_note
.
position
).
to
eq
(
note
.
position
)
expect
(
new_note
.
note
).
to
include
(
'I could not disagree more.'
)
end
end
context
'mail key is in the References header'
do
let
(
:email_raw
)
{
fixture_file
(
'emails/reply_without_subaddressing_and_key_inside_references.eml'
)
}
it_behaves_like
'an email that contains a mail key'
,
'References'
end
context
'mail key is in the References header with a comma'
do
let
(
:email_raw
)
{
fixture_file
(
'emails/reply_without_subaddressing_and_key_inside_references_with_a_comma.eml'
)
}
it_behaves_like
'an email that contains a mail key'
,
'References'
end
end
end
end
ee/spec/lib/gitlab/email/handler/ee/service_desk_handler_spec.rb
View file @
baa05571
require
'spec_helper'
require
Rails
.
root
.
join
(
'spec/lib/gitlab/email/email_shared_blocks'
)
describe
Gitlab
::
Email
::
Handler
::
EE
::
ServiceDeskHandler
do
include_context
:email_shared_context
...
...
ee/spec/mailers/notify_spec.rb
View file @
baa05571
...
...
@@ -149,4 +149,50 @@ describe Notify do
end
end
end
context
'for a group'
do
context
'for epic notes'
do
set
(
:group
)
{
create
(
:group
)
}
set
(
:epic
)
{
create
(
:epic
,
group:
group
)
}
set
(
:note
)
{
create
(
:note
,
project:
nil
,
noteable:
epic
)
}
let
(
:note_author
)
{
note
.
author
}
let
(
:epic_note_path
)
{
group_epic_path
(
group
,
epic
,
anchor:
"note_
#{
note
.
id
}
"
)
}
subject
{
described_class
.
note_epic_email
(
recipient
.
id
,
note
.
id
)
}
it_behaves_like
'a note email'
it_behaves_like
'an unsubscribeable thread'
it
'has the characteristics of a threaded reply'
do
host
=
Gitlab
.
config
.
gitlab
.
host
route_key
=
"
#{
epic
.
class
.
model_name
.
singular_route_key
}
_
#{
epic
.
id
}
"
aggregate_failures
do
is_expected
.
to
have_header
(
'Message-ID'
,
/\A<.*@
#{
host
}
>\Z/
)
is_expected
.
to
have_header
(
'In-Reply-To'
,
"<
#{
route_key
}
@
#{
host
}
>"
)
is_expected
.
to
have_header
(
'References'
,
/\A<
#{
route_key
}
@
#{
host
}
> <reply\-.*@
#{
host
}
>\Z/
)
is_expected
.
to
have_subject
(
/^Re: /
)
end
end
context
'when reply-by-email is enabled with incoming address with %{key}'
do
it
'has a Reply-To header'
do
is_expected
.
to
have_header
'Reply-To'
,
/<reply+(.*)@
#{
Gitlab
.
config
.
gitlab
.
host
}
>\Z/
end
end
it
{
is_expected
.
to
have_body_text
(
'View Epic'
)
}
it
'has the correct subject and body'
do
prefix
=
"Re:
#{
epic
.
group
.
name
}
| "
suffix
=
"
#{
epic
.
title
}
(
#{
epic
.
to_reference
}
)"
aggregate_failures
do
is_expected
.
to
have_subject
[
prefix
,
suffix
].
compact
.
join
is_expected
.
to
have_body_text
(
epic_note_path
)
end
end
end
end
end
ee/spec/services/ee/notification_service_spec.rb
View file @
baa05571
require
'spec_helper'
describe
EE
::
NotificationService
,
:mailer
do
include
NotificationHelpers
include
ExternalAuthorizationServiceHelpers
let
(
:subject
)
{
NotificationService
.
new
}
...
...
@@ -236,4 +237,122 @@ describe EE::NotificationService, :mailer do
subject
.
project_mirror_user_changed
(
new_mirror_user
,
mirror_user
.
name
,
project
)
end
end
describe
'Notes'
do
around
do
|
example
|
perform_enqueued_jobs
do
example
.
run
end
end
context
'epic notes'
do
set
(
:group
)
{
create
(
:group
,
:private
)
}
set
(
:epic
)
{
create
(
:epic
,
group:
group
)
}
set
(
:note
)
{
create
(
:note
,
project:
nil
,
noteable:
epic
,
note:
'@mention referenced, @unsubscribed_mentioned and @outsider also'
)
}
before
(
:all
)
do
create
(
:group_member
,
group:
group
,
user:
epic
.
author
)
create
(
:group_member
,
group:
group
,
user:
note
.
author
)
end
before
do
stub_licensed_features
(
epics:
true
)
build_group_members
(
group
)
@u_custom_off
=
create_user_with_notification
(
:custom
,
'custom_off'
,
group
)
create
(
:group_member
,
group:
group
,
user:
@u_custom_off
)
create
(
:note
,
project:
nil
,
noteable:
epic
,
author:
@u_custom_off
,
note:
'i think @subscribed_participant should see this'
)
update_custom_notification
(
:new_note
,
@u_guest_custom
,
resource:
group
)
update_custom_notification
(
:new_note
,
@u_custom_global
)
end
describe
'#new_note'
do
it
do
add_users_with_subscription
(
group
,
epic
)
reset_delivered_emails!
expect
(
SentNotification
).
to
receive
(
:record
).
with
(
epic
,
any_args
).
exactly
(
9
).
times
subject
.
new_note
(
note
)
should_email
(
@u_watcher
)
should_email
(
note
.
noteable
.
author
)
should_email
(
@u_custom_global
)
should_email
(
@u_mentioned
)
should_email
(
@subscriber
)
should_email
(
@watcher_and_subscriber
)
should_email
(
@subscribed_participant
)
should_email
(
@u_custom_off
)
should_email
(
@unsubscribed_mentioned
)
should_not_email
(
@u_guest_custom
)
should_not_email
(
@u_guest_watcher
)
should_not_email
(
note
.
author
)
should_not_email
(
@u_participating
)
should_not_email
(
@u_disabled
)
should_not_email
(
@unsubscriber
)
should_not_email
(
@u_outsider_mentioned
)
should_not_email
(
@u_lazy_participant
)
end
end
end
end
def
build_group_members
(
group
)
@u_watcher
=
create_global_setting_for
(
create
(
:user
),
:watch
)
@u_participating
=
create_global_setting_for
(
create
(
:user
),
:participating
)
@u_participant_mentioned
=
create_global_setting_for
(
create
(
:user
,
username:
'participant'
),
:participating
)
@u_disabled
=
create_global_setting_for
(
create
(
:user
),
:disabled
)
@u_mentioned
=
create_global_setting_for
(
create
(
:user
,
username:
'mention'
),
:mention
)
@u_committer
=
create
(
:user
,
username:
'committer'
)
@u_not_mentioned
=
create_global_setting_for
(
create
(
:user
,
username:
'regular'
),
:participating
)
@u_outsider_mentioned
=
create
(
:user
,
username:
'outsider'
)
@u_custom_global
=
create_global_setting_for
(
create
(
:user
,
username:
'custom_global'
),
:custom
)
# User to be participant by default
# This user does not contain any record in notification settings table
# It should be treated with a :participating notification_level
@u_lazy_participant
=
create
(
:user
,
username:
'lazy-participant'
)
@u_guest_watcher
=
create_user_with_notification
(
:watch
,
'guest_watching'
,
group
)
@u_guest_custom
=
create_user_with_notification
(
:custom
,
'guest_custom'
,
group
)
create
(
:group_member
,
group:
group
,
user:
@u_watcher
)
create
(
:group_member
,
group:
group
,
user:
@u_participating
)
create
(
:group_member
,
group:
group
,
user:
@u_participant_mentioned
)
create
(
:group_member
,
group:
group
,
user:
@u_disabled
)
create
(
:group_member
,
group:
group
,
user:
@u_mentioned
)
create
(
:group_member
,
group:
group
,
user:
@u_committer
)
create
(
:group_member
,
group:
group
,
user:
@u_not_mentioned
)
create
(
:group_member
,
group:
group
,
user:
@u_lazy_participant
)
create
(
:group_member
,
group:
group
,
user:
@u_custom_global
)
end
def
add_users_with_subscription
(
group
,
issuable
)
@subscriber
=
create
:user
@unsubscriber
=
create
:user
@unsubscribed_mentioned
=
create
:user
,
username:
'unsubscribed_mentioned'
@subscribed_participant
=
create_global_setting_for
(
create
(
:user
,
username:
'subscribed_participant'
),
:participating
)
@watcher_and_subscriber
=
create_global_setting_for
(
create
(
:user
),
:watch
)
create
(
:group_member
,
group:
group
,
user:
@subscribed_participant
)
create
(
:group_member
,
group:
group
,
user:
@subscriber
)
create
(
:group_member
,
group:
group
,
user:
@unsubscriber
)
create
(
:group_member
,
group:
group
,
user:
@watcher_and_subscriber
)
create
(
:group_member
,
group:
group
,
user:
@unsubscribed_mentioned
)
issuable
.
subscriptions
.
create
(
user:
@unsubscribed_mentioned
,
subscribed:
false
)
issuable
.
subscriptions
.
create
(
user:
@subscriber
,
subscribed:
true
)
issuable
.
subscriptions
.
create
(
user:
@subscribed_participant
,
subscribed:
true
)
issuable
.
subscriptions
.
create
(
user:
@unsubscriber
,
subscribed:
false
)
# Make the watcher a subscriber to detect dupes
issuable
.
subscriptions
.
create
(
user:
@watcher_and_subscriber
,
subscribed:
true
)
end
end
lib/gitlab/email/handler/create_note_handler.rb
View file @
baa05571
...
...
@@ -8,6 +8,7 @@ module Gitlab
include
ReplyProcessing
delegate
:project
,
to: :sent_notification
,
allow_nil:
true
delegate
:noteable
,
to: :sent_notification
def
can_handle?
mail_key
=~
/\A\w+\z/
...
...
@@ -18,7 +19,7 @@ module Gitlab
validate_permission!
(
:create_note
)
raise
NoteableNotFoundError
unless
sent_notification
.
noteable
raise
NoteableNotFoundError
unless
noteable
raise
EmptyEmailError
if
message
.
blank?
verify_record!
(
...
...
lib/gitlab/email/handler/reply_processing.rb
View file @
baa05571
...
...
@@ -32,8 +32,12 @@ module Gitlab
def
validate_permission!
(
permission
)
raise
UserNotFoundError
unless
author
raise
UserBlockedError
if
author
.
blocked?
raise
ProjectNotFound
unless
author
.
can?
(
:read_project
,
project
)
raise
UserNotAuthorizedError
unless
author
.
can?
(
permission
,
project
)
if
project
raise
ProjectNotFound
unless
author
.
can?
(
:read_project
,
project
)
end
raise
UserNotAuthorizedError
unless
author
.
can?
(
permission
,
project
||
noteable
)
end
def
verify_record!
(
record
:,
invalid_exception
:,
record_name
:)
...
...
spec/lib/gitlab/email/handler/create_issue_handler_spec.rb
View file @
baa05571
require
'spec_helper'
require_relative
'../email_shared_blocks'
describe
Gitlab
::
Email
::
Handler
::
CreateIssueHandler
do
include_context
:email_shared_context
...
...
spec/lib/gitlab/email/handler/create_merge_request_handler_spec.rb
View file @
baa05571
require
'spec_helper'
require_relative
'../email_shared_blocks'
describe
Gitlab
::
Email
::
Handler
::
CreateMergeRequestHandler
do
include_context
:email_shared_context
...
...
spec/lib/gitlab/email/handler/create_note_handler_spec.rb
View file @
baa05571
require
'spec_helper'
require_relative
'../email_shared_blocks'
describe
Gitlab
::
Email
::
Handler
::
CreateNoteHandler
do
include_context
:email_shared_context
...
...
spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb
View file @
baa05571
require
'spec_helper'
require_relative
'../email_shared_blocks'
describe
Gitlab
::
Email
::
Handler
::
UnsubscribeHandler
do
include_context
:email_shared_context
...
...
spec/lib/gitlab/email/receiver_spec.rb
View file @
baa05571
require
'spec_helper'
require_relative
'email_shared_blocks'
describe
Gitlab
::
Email
::
Receiver
do
include_context
:email_shared_context
...
...
spec/mailers/notify_spec.rb
View file @
baa05571
...
...
@@ -665,38 +665,6 @@ describe Notify do
allow
(
Note
).
to
receive
(
:find
).
with
(
note
.
id
).
and_return
(
note
)
end
shared_examples
'a note email'
do
it_behaves_like
'it should have Gmail Actions links'
it
'is sent to the given recipient as the author'
do
sender
=
subject
.
header
[
:from
].
addrs
[
0
]
aggregate_failures
do
expect
(
sender
.
display_name
).
to
eq
(
note_author
.
name
)
expect
(
sender
.
address
).
to
eq
(
gitlab_sender
)
expect
(
subject
).
to
deliver_to
(
recipient
.
notification_email
)
end
end
it
'contains the message from the note'
do
is_expected
.
to
have_html_escaped_body_text
note
.
note
end
it
'does not contain note author'
do
is_expected
.
not_to
have_body_text
note
.
author_name
end
context
'when enabled email_author_in_body'
do
before
do
stub_application_setting
(
email_author_in_body:
true
)
end
it
'contains a link to note author'
do
is_expected
.
to
have_html_escaped_body_text
note
.
author_name
end
end
end
describe
'on a commit'
do
let
(
:commit
)
{
project
.
commit
}
...
...
spec/services/notification_service_spec.rb
View file @
baa05571
...
...
@@ -2,6 +2,7 @@ require 'spec_helper'
describe
NotificationService
,
:mailer
do
include
EmailSpec
::
Matchers
include
NotificationHelpers
let
(
:notification
)
{
described_class
.
new
}
let
(
:assignee
)
{
create
(
:user
)
}
...
...
@@ -13,12 +14,6 @@ describe NotificationService, :mailer do
end
shared_examples
'notifications for new mentions'
do
def
send_notifications
(
*
new_mentions
)
mentionable
.
description
=
new_mentions
.
map
(
&
:to_reference
).
join
(
' '
)
notification
.
send
(
notification_method
,
mentionable
,
new_mentions
,
@u_disabled
)
end
it
'sends no emails when no new mentions are present'
do
send_notifications
should_not_email_anyone
...
...
@@ -1956,30 +1951,6 @@ describe NotificationService, :mailer do
group
end
def
create_global_setting_for
(
user
,
level
)
setting
=
user
.
global_notification_setting
setting
.
level
=
level
setting
.
save
user
end
def
create_user_with_notification
(
level
,
username
,
resource
=
project
)
user
=
create
(
:user
,
username:
username
)
setting
=
user
.
notification_settings_for
(
resource
)
setting
.
level
=
level
setting
.
save
user
end
# Create custom notifications
# When resource is nil it means global notification
def
update_custom_notification
(
event
,
user
,
resource:
nil
,
value:
true
)
setting
=
user
.
notification_settings_for
(
resource
)
setting
.
update!
(
event
=>
value
)
end
def
add_users_with_subscription
(
project
,
issuable
)
@subscriber
=
create
:user
@unsubscriber
=
create
:user
...
...
spec/support/helpers/notification_helpers.rb
0 → 100644
View file @
baa05571
module
NotificationHelpers
extend
self
def
send_notifications
(
*
new_mentions
)
mentionable
.
description
=
new_mentions
.
map
(
&
:to_reference
).
join
(
' '
)
notification
.
send
(
notification_method
,
mentionable
,
new_mentions
,
@u_disabled
)
end
def
create_global_setting_for
(
user
,
level
)
setting
=
user
.
global_notification_setting
setting
.
level
=
level
setting
.
save
user
end
def
create_user_with_notification
(
level
,
username
,
resource
=
project
)
user
=
create
(
:user
,
username:
username
)
setting
=
user
.
notification_settings_for
(
resource
)
setting
.
level
=
level
setting
.
save
user
end
# Create custom notifications
# When resource is nil it means global notification
def
update_custom_notification
(
event
,
user
,
resource:
nil
,
value:
true
)
setting
=
user
.
notification_settings_for
(
resource
)
setting
.
update!
(
event
=>
value
)
end
end
spec/
lib/gitlab/email
/email_shared_blocks.rb
→
spec/
support/shared_contexts
/email_shared_blocks.rb
View file @
baa05571
File moved
spec/support/shared_examples/notify_shared_examples.rb
View file @
baa05571
...
...
@@ -197,3 +197,35 @@ end
shared_examples
'an email with a labels subscriptions link in its footer'
do
it
{
is_expected
.
to
have_body_text
(
'label subscriptions'
)
}
end
shared_examples
'a note email'
do
it_behaves_like
'it should have Gmail Actions links'
it
'is sent to the given recipient as the author'
do
sender
=
subject
.
header
[
:from
].
addrs
[
0
]
aggregate_failures
do
expect
(
sender
.
display_name
).
to
eq
(
note_author
.
name
)
expect
(
sender
.
address
).
to
eq
(
gitlab_sender
)
expect
(
subject
).
to
deliver_to
(
recipient
.
notification_email
)
end
end
it
'contains the message from the note'
do
is_expected
.
to
have_html_escaped_body_text
note
.
note
end
it
'does not contain note author'
do
is_expected
.
not_to
have_body_text
note
.
author_name
end
context
'when enabled email_author_in_body'
do
before
do
stub_application_setting
(
email_author_in_body:
true
)
end
it
'contains a link to note author'
do
is_expected
.
to
have_html_escaped_body_text
note
.
author_name
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment