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
cd3587c9
Commit
cd3587c9
authored
Mar 15, 2016
by
Rémy Coutable
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'ce/master' into ce-to-ee
parents
cce36cb3
bc590ce6
Changes
41
Hide whitespace changes
Inline
Side-by-side
Showing
41 changed files
with
660 additions
and
137 deletions
+660
-137
CHANGELOG
CHANGELOG
+1
-0
app/assets/javascripts/subscription.js.coffee
app/assets/javascripts/subscription.js.coffee
+19
-15
app/assets/stylesheets/pages/labels.scss
app/assets/stylesheets/pages/labels.scss
+4
-0
app/controllers/concerns/toggle_subscription_action.rb
app/controllers/concerns/toggle_subscription_action.rb
+17
-0
app/controllers/projects/issues_controller.rb
app/controllers/projects/issues_controller.rb
+4
-7
app/controllers/projects/labels_controller.rb
app/controllers/projects/labels_controller.rb
+7
-2
app/controllers/projects/merge_requests_controller.rb
app/controllers/projects/merge_requests_controller.rb
+3
-7
app/helpers/labels_helper.rb
app/helpers/labels_helper.rb
+8
-0
app/mailers/emails/issues.rb
app/mailers/emails/issues.rb
+18
-10
app/mailers/emails/merge_requests.rb
app/mailers/emails/merge_requests.rb
+24
-25
app/models/concerns/issuable.rb
app/models/concerns/issuable.rb
+2
-20
app/models/concerns/subscribable.rb
app/models/concerns/subscribable.rb
+44
-0
app/models/label.rb
app/models/label.rb
+2
-0
app/models/subscription.rb
app/models/subscription.rb
+1
-1
app/services/issuable_base_service.rb
app/services/issuable_base_service.rb
+8
-9
app/services/issues/update_service.rb
app/services/issues/update_service.rb
+7
-2
app/services/merge_requests/update_service.rb
app/services/merge_requests/update_service.rb
+11
-2
app/services/notification_service.rb
app/services/notification_service.rb
+57
-13
app/views/layouts/notify.html.haml
app/views/layouts/notify.html.haml
+8
-5
app/views/notify/_reassigned_issuable_email.text.erb
app/views/notify/_reassigned_issuable_email.text.erb
+1
-1
app/views/notify/_relabeled_issuable_email.html.haml
app/views/notify/_relabeled_issuable_email.html.haml
+3
-0
app/views/notify/_relabeled_issuable_email.text.erb
app/views/notify/_relabeled_issuable_email.text.erb
+3
-0
app/views/notify/relabeled_issue_email.html.haml
app/views/notify/relabeled_issue_email.html.haml
+1
-0
app/views/notify/relabeled_issue_email.text.erb
app/views/notify/relabeled_issue_email.text.erb
+1
-0
app/views/notify/relabeled_merge_request_email.html.haml
app/views/notify/relabeled_merge_request_email.html.haml
+1
-0
app/views/notify/relabeled_merge_request_email.text.erb
app/views/notify/relabeled_merge_request_email.text.erb
+1
-0
app/views/projects/labels/_label.html.haml
app/views/projects/labels/_label.html.haml
+10
-0
app/views/shared/issuable/_sidebar.html.haml
app/views/shared/issuable/_sidebar.html.haml
+2
-2
config/routes.rb
config/routes.rb
+4
-0
features/project/labels.feature
features/project/labels.feature
+15
-0
features/steps/project/labels.rb
features/steps/project/labels.rb
+34
-0
spec/factories/labels.rb
spec/factories/labels.rb
+1
-1
spec/mailers/notify_spec.rb
spec/mailers/notify_spec.rb
+56
-0
spec/mailers/shared/notify.rb
spec/mailers/shared/notify.rb
+5
-1
spec/models/concerns/issuable_spec.rb
spec/models/concerns/issuable_spec.rb
+42
-0
spec/models/concerns/subscribable_spec.rb
spec/models/concerns/subscribable_spec.rb
+57
-0
spec/services/issues/update_service_spec.rb
spec/services/issues/update_service_spec.rb
+44
-1
spec/services/merge_requests/update_service_spec.rb
spec/services/merge_requests/update_service_spec.rb
+44
-1
spec/services/notification_service_spec.rb
spec/services/notification_service_spec.rb
+76
-12
spec/spec_helper.rb
spec/spec_helper.rb
+1
-0
spec/support/email_helpers.rb
spec/support/email_helpers.rb
+13
-0
No files found.
CHANGELOG
View file @
cd3587c9
...
...
@@ -28,6 +28,7 @@ v 8.6.0 (unreleased)
- Update documentation to reflect Guest role not being enforced on internal projects
- Allow search for logged out users
- Allow to define on which builds the current one depends on
- Allow user subscription to a label: get notified for issues/merge requests related to that label (Timothy Andrew)
- Fix bug where Bitbucket `closed` issues were imported as `opened` (Iuri de Silvio)
- Don't show Issues/MRs from archived projects in Groups view
- Fix wrong "iid of max iid" in Issuable sidebar for some merged MRs
...
...
app/assets/javascripts/subscription.js.coffee
View file @
cd3587c9
class
@
Subscription
constructor
:
(
url
)
->
$
(
".subscribe-button"
).
unbind
(
"click"
).
click
(
event
)
=>
btn
=
$
(
event
.
currentTarget
)
action
=
btn
.
find
(
"span"
).
text
()
current_status
=
$
(
".subscription-status"
).
attr
(
"data-status"
)
btn
.
prop
(
"disabled"
,
true
)
$
.
post
url
,
=>
btn
.
prop
(
"disabled"
,
false
)
status
=
if
current_status
==
"subscribed"
then
"unsubscribed"
else
"subscribed"
$
(
".subscription-status"
).
attr
(
"data-status"
,
status
)
action
=
if
status
==
"subscribed"
then
"Unsubscribe"
else
"Subscribe"
btn
.
find
(
"span"
).
text
(
action
)
$
(
".subscription-status>div"
).
toggleClass
(
"hidden"
)
constructor
:
(
container
)
->
$container
=
$
(
container
)
@
url
=
$container
.
attr
(
'data-url'
)
@
subscribe_button
=
$container
.
find
(
'.subscribe-button'
)
@
subscription_status
=
$container
.
find
(
'.subscription-status'
)
@
subscribe_button
.
unbind
(
'click'
).
click
(
@
toggleSubscription
)
toggleSubscription
:
(
event
)
=>
btn
=
$
(
event
.
currentTarget
)
action
=
btn
.
find
(
'span'
).
text
()
current_status
=
@
subscription_status
.
attr
(
'data-status'
)
btn
.
prop
(
'disabled'
,
true
)
$
.
post
@
url
,
=>
btn
.
prop
(
'disabled'
,
false
)
status
=
if
current_status
==
'subscribed'
then
'unsubscribed'
else
'subscribed'
@
subscription_status
.
attr
(
'data-status'
,
status
)
action
=
if
status
==
'subscribed'
then
'Unsubscribe'
else
'Subscribe'
btn
.
find
(
'span'
).
text
(
action
)
@
subscription_status
.
find
(
'>div'
).
toggleClass
(
'hidden'
)
app/assets/stylesheets/pages/labels.scss
View file @
cd3587c9
...
...
@@ -41,3 +41,7 @@
.color-label
{
padding
:
3px
4px
;
}
.label-subscription
{
display
:
inline-block
;
}
app/controllers/concerns/toggle_subscription_action.rb
0 → 100644
View file @
cd3587c9
module
ToggleSubscriptionAction
extend
ActiveSupport
::
Concern
def
toggle_subscription
return
unless
current_user
subscribable_resource
.
toggle_subscription
(
current_user
)
render
nothing:
true
end
private
def
subscribable_resource
raise
NotImplementedError
end
end
app/controllers/projects/issues_controller.rb
View file @
cd3587c9
class
Projects::IssuesController
<
Projects
::
ApplicationController
include
ToggleSubscriptionAction
before_action
:module_enabled
before_action
:issue
,
only:
[
:edit
,
:update
,
:show
,
:toggle_subscription
]
before_action
:issue
,
only:
[
:edit
,
:update
,
:show
]
# Allow read any issue
before_action
:authorize_read_issue!
...
...
@@ -116,12 +118,6 @@ class Projects::IssuesController < Projects::ApplicationController
redirect_back_or_default
(
default:
{
action:
'index'
},
options:
{
notice:
"
#{
result
[
:count
]
}
issues updated"
})
end
def
toggle_subscription
@issue
.
toggle_subscription
(
current_user
)
render
nothing:
true
end
def
closed_by_merge_requests
@closed_by_merge_requests
||=
@issue
.
closed_by_merge_requests
(
current_user
)
end
...
...
@@ -135,6 +131,7 @@ class Projects::IssuesController < Projects::ApplicationController
redirect_old
end
end
alias_method
:subscribable_resource
,
:issue
def
authorize_update_issue!
return
render_404
unless
can?
(
current_user
,
:update_issue
,
@issue
)
...
...
app/controllers/projects/labels_controller.rb
View file @
cd3587c9
class
Projects::LabelsController
<
Projects
::
ApplicationController
include
ToggleSubscriptionAction
before_action
:module_enabled
before_action
:label
,
only:
[
:edit
,
:update
,
:destroy
]
before_action
:authorize_read_label!
before_action
:authorize_admin_labels!
,
except:
[
:index
]
before_action
:authorize_admin_labels!
,
only:
[
:new
,
:create
,
:edit
,
:update
,
:generate
,
:destroy
]
respond_to
:js
,
:html
...
...
@@ -73,8 +77,9 @@ class Projects::LabelsController < Projects::ApplicationController
end
def
label
@label
=
@project
.
labels
.
find
(
params
[
:id
])
@label
||
=
@project
.
labels
.
find
(
params
[
:id
])
end
alias_method
:subscribable_resource
,
:label
def
authorize_admin_labels!
return
render_404
unless
can?
(
current_user
,
:admin_label
,
@project
)
...
...
app/controllers/projects/merge_requests_controller.rb
View file @
cd3587c9
class
Projects::MergeRequestsController
<
Projects
::
ApplicationController
include
ToggleSubscriptionAction
include
DiffHelper
before_action
:module_enabled
before_action
:merge_request
,
only:
[
:edit
,
:update
,
:show
,
:diffs
,
:commits
,
:builds
,
:merge
,
:merge_check
,
:ci_status
,
:
toggle_subscription
,
:
approve
,
:rebase
,
:cancel_merge_when_build_succeeds
:ci_status
,
:approve
,
:rebase
,
:cancel_merge_when_build_succeeds
]
before_action
:closes_issues
,
only:
[
:edit
,
:update
,
:show
,
:diffs
,
:commits
,
:builds
]
before_action
:validates_merge_request
,
only:
[
:show
,
:diffs
,
:commits
,
:builds
]
...
...
@@ -247,12 +248,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
render
json:
response
end
def
toggle_subscription
@merge_request
.
toggle_subscription
(
current_user
)
render
nothing:
true
end
def
approve
unless
@merge_request
.
can_approve?
(
current_user
)
return
render_404
...
...
@@ -281,6 +276,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def
merge_request
@merge_request
||=
@project
.
merge_requests
.
find_by!
(
iid:
params
[
:id
])
end
alias_method
:subscribable_resource
,
:merge_request
def
closes_issues
@closes_issues
||=
@merge_request
.
closes_issues
...
...
app/helpers/labels_helper.rb
View file @
cd3587c9
...
...
@@ -124,6 +124,14 @@ module LabelsHelper
options_from_collection_for_select
(
grouped_labels
,
'name'
,
'title'
,
params
[
:label_name
])
end
def
label_subscription_status
(
label
)
label
.
subscribed?
(
current_user
)
?
'subscribed'
:
'unsubscribed'
end
def
label_subscription_toggle_button_text
(
label
)
label
.
subscribed?
(
current_user
)
?
'Unsubscribe'
:
'Subscribe'
end
# Required for Banzai::Filter::LabelReferenceFilter
module_function
:render_colored_label
,
:render_colored_cross_project_label
,
:text_color_for_bg
,
:escape_once
...
...
app/mailers/emails/issues.rb
View file @
cd3587c9
...
...
@@ -16,7 +16,15 @@ module Emails
def
closed_issue_email
(
recipient_id
,
issue_id
,
updated_by_user_id
)
setup_issue_mail
(
issue_id
,
recipient_id
)
@updated_by
=
User
.
find
updated_by_user_id
@updated_by
=
User
.
find
(
updated_by_user_id
)
mail_answer_thread
(
@issue
,
issue_thread_options
(
updated_by_user_id
,
recipient_id
))
end
def
relabeled_issue_email
(
recipient_id
,
issue_id
,
label_names
,
updated_by_user_id
)
setup_issue_mail
(
issue_id
,
recipient_id
)
@label_names
=
label_names
@labels_url
=
namespace_project_labels_url
(
@project
.
namespace
,
@project
)
mail_answer_thread
(
@issue
,
issue_thread_options
(
updated_by_user_id
,
recipient_id
))
end
...
...
@@ -24,20 +32,12 @@ module Emails
setup_issue_mail
(
issue_id
,
recipient_id
)
@issue_status
=
status
@updated_by
=
User
.
find
updated_by_user_id
@updated_by
=
User
.
find
(
updated_by_user_id
)
mail_answer_thread
(
@issue
,
issue_thread_options
(
updated_by_user_id
,
recipient_id
))
end
private
def
issue_thread_options
(
sender_id
,
recipient_id
)
{
from:
sender
(
sender_id
),
to:
recipient
(
recipient_id
),
subject:
subject
(
"
#{
@issue
.
title
}
(#
#{
@issue
.
iid
}
)"
)
}
end
def
setup_issue_mail
(
issue_id
,
recipient_id
)
@issue
=
Issue
.
find
(
issue_id
)
@project
=
@issue
.
project
...
...
@@ -45,5 +45,13 @@ module Emails
@sent_notification
=
SentNotification
.
record
(
@issue
,
recipient_id
,
reply_key
)
end
def
issue_thread_options
(
sender_id
,
recipient_id
)
{
from:
sender
(
sender_id
),
to:
recipient
(
recipient_id
),
subject:
subject
(
"
#{
@issue
.
title
}
(#
#{
@issue
.
iid
}
)"
)
}
end
end
end
app/mailers/emails/merge_requests.rb
View file @
cd3587c9
...
...
@@ -3,50 +3,43 @@ module Emails
def
new_merge_request_email
(
recipient_id
,
merge_request_id
)
setup_merge_request_mail
(
merge_request_id
,
recipient_id
)
mail_new_thread
(
@merge_request
,
from:
sender
(
@merge_request
.
author_id
),
to:
recipient
(
recipient_id
),
subject:
subject
(
"
#{
@merge_request
.
title
}
(#
#{
@merge_request
.
iid
}
)"
))
mail_new_thread
(
@merge_request
,
merge_request_thread_options
(
@merge_request
.
author_id
,
recipient_id
))
end
def
reassigned_merge_request_email
(
recipient_id
,
merge_request_id
,
previous_assignee_id
,
updated_by_user_id
)
setup_merge_request_mail
(
merge_request_id
,
recipient_id
)
@previous_assignee
=
User
.
find_by
(
id:
previous_assignee_id
)
if
previous_assignee_id
mail_answer_thread
(
@merge_request
,
from:
sender
(
updated_by_user_id
),
to:
recipient
(
recipient_id
),
subject:
subject
(
"
#{
@merge_request
.
title
}
(#
#{
@merge_request
.
iid
}
)"
))
mail_answer_thread
(
@merge_request
,
merge_request_thread_options
(
updated_by_user_id
,
recipient_id
))
end
def
relabeled_merge_request_email
(
recipient_id
,
merge_request_id
,
label_names
,
updated_by_user_id
)
setup_merge_request_mail
(
merge_request_id
,
recipient_id
)
@label_names
=
label_names
@labels_url
=
namespace_project_labels_url
(
@project
.
namespace
,
@project
)
mail_answer_thread
(
@merge_request
,
merge_request_thread_options
(
updated_by_user_id
,
recipient_id
))
end
def
closed_merge_request_email
(
recipient_id
,
merge_request_id
,
updated_by_user_id
)
setup_merge_request_mail
(
merge_request_id
,
recipient_id
)
@updated_by
=
User
.
find
updated_by_user_id
mail_answer_thread
(
@merge_request
,
from:
sender
(
updated_by_user_id
),
to:
recipient
(
recipient_id
),
subject:
subject
(
"
#{
@merge_request
.
title
}
(#
#{
@merge_request
.
iid
}
)"
))
@updated_by
=
User
.
find
(
updated_by_user_id
)
mail_answer_thread
(
@merge_request
,
merge_request_thread_options
(
updated_by_user_id
,
recipient_id
))
end
def
merged_merge_request_email
(
recipient_id
,
merge_request_id
,
updated_by_user_id
)
setup_merge_request_mail
(
merge_request_id
,
recipient_id
)
mail_answer_thread
(
@merge_request
,
from:
sender
(
updated_by_user_id
),
to:
recipient
(
recipient_id
),
subject:
subject
(
"
#{
@merge_request
.
title
}
(#
#{
@merge_request
.
iid
}
)"
))
mail_answer_thread
(
@merge_request
,
merge_request_thread_options
(
updated_by_user_id
,
recipient_id
))
end
def
merge_request_status_email
(
recipient_id
,
merge_request_id
,
status
,
updated_by_user_id
)
setup_merge_request_mail
(
merge_request_id
,
recipient_id
)
@mr_status
=
status
@updated_by
=
User
.
find
updated_by_user_id
mail_answer_thread
(
@merge_request
,
from:
sender
(
updated_by_user_id
),
to:
recipient
(
recipient_id
),
subject:
subject
(
"
#{
@merge_request
.
title
}
(#
#{
@merge_request
.
iid
}
)"
))
@updated_by
=
User
.
find
(
updated_by_user_id
)
mail_answer_thread
(
@merge_request
,
merge_request_thread_options
(
updated_by_user_id
,
recipient_id
))
end
private
...
...
@@ -54,11 +47,17 @@ module Emails
def
setup_merge_request_mail
(
merge_request_id
,
recipient_id
)
@merge_request
=
MergeRequest
.
find
(
merge_request_id
)
@project
=
@merge_request
.
project
@target_url
=
namespace_project_merge_request_url
(
@project
.
namespace
,
@project
,
@merge_request
)
@target_url
=
namespace_project_merge_request_url
(
@project
.
namespace
,
@project
,
@merge_request
)
@sent_notification
=
SentNotification
.
record
(
@merge_request
,
recipient_id
,
reply_key
)
end
def
merge_request_thread_options
(
sender_id
,
recipient_id
)
{
from:
sender
(
sender_id
),
to:
recipient
(
recipient_id
),
subject:
subject
(
"
#{
@merge_request
.
title
}
(#
#{
@merge_request
.
iid
}
)"
)
}
end
end
end
app/models/concerns/issuable.rb
View file @
cd3587c9
...
...
@@ -8,6 +8,7 @@ module Issuable
extend
ActiveSupport
::
Concern
include
Participable
include
Mentionable
include
Subscribable
include
StripAttribute
included
do
...
...
@@ -18,7 +19,6 @@ module Issuable
has_many
:notes
,
as: :noteable
,
dependent: :destroy
has_many
:label_links
,
as: :target
,
dependent: :destroy
has_many
:labels
,
through: :label_links
has_many
:subscriptions
,
dependent: :destroy
,
as: :subscribable
validates
:author
,
presence:
true
validates
:title
,
presence:
true
,
length:
{
within:
0
..
255
}
...
...
@@ -149,28 +149,10 @@ module Issuable
notes
.
awards
.
where
(
note:
"thumbsup"
).
count
end
def
subscribed?
(
user
)
subscription
=
subscriptions
.
find_by_user_id
(
user
.
id
)
if
subscription
return
subscription
.
subscribed
end
def
subscribed_without_subscriptions?
(
user
)
participants
(
user
).
include?
(
user
)
end
def
toggle_subscription
(
user
)
subscriptions
.
find_or_initialize_by
(
user_id:
user
.
id
).
update
(
subscribed:
!
subscribed?
(
user
))
end
def
unsubscribe
(
user
)
subscriptions
.
find_or_initialize_by
(
user_id:
user
.
id
).
update
(
subscribed:
false
)
end
def
to_hook_data
(
user
)
hook_data
=
{
object_kind:
self
.
class
.
name
.
underscore
,
...
...
app/models/concerns/subscribable.rb
0 → 100644
View file @
cd3587c9
# == Subscribable concern
#
# Users can subscribe to these models.
#
# Used by Issue, MergeRequest, Label
#
module
Subscribable
extend
ActiveSupport
::
Concern
included
do
has_many
:subscriptions
,
dependent: :destroy
,
as: :subscribable
end
def
subscribed?
(
user
)
if
subscription
=
subscriptions
.
find_by_user_id
(
user
.
id
)
subscription
.
subscribed
else
subscribed_without_subscriptions?
(
user
)
end
end
# Override this method to define custom logic to consider a subscribable as
# subscribed without an explicit subscription record.
def
subscribed_without_subscriptions?
(
user
)
false
end
def
subscribers
subscriptions
.
where
(
subscribed:
true
).
map
(
&
:user
)
end
def
toggle_subscription
(
user
)
subscriptions
.
find_or_initialize_by
(
user_id:
user
.
id
).
update
(
subscribed:
!
subscribed?
(
user
))
end
def
unsubscribe
(
user
)
subscriptions
.
find_or_initialize_by
(
user_id:
user
.
id
).
update
(
subscribed:
false
)
end
end
app/models/label.rb
View file @
cd3587c9
...
...
@@ -14,6 +14,8 @@
class
Label
<
ActiveRecord
::
Base
include
Referable
include
Subscribable
# Represents a "No Label" state used for filtering Issues and Merge
# Requests that have no label assigned.
LabelStruct
=
Struct
.
new
(
:title
,
:name
)
...
...
app/models/subscription.rb
View file @
cd3587c9
...
...
@@ -15,7 +15,7 @@ class Subscription < ActiveRecord::Base
belongs_to
:user
belongs_to
:subscribable
,
polymorphic:
true
validates
:user_id
,
validates
:user_id
,
uniqueness:
{
scope:
[
:subscribable_id
,
:subscribable_type
]
},
presence:
true
end
app/services/issuable_base_service.rb
View file @
cd3587c9
...
...
@@ -11,7 +11,10 @@ class IssuableBaseService < BaseService
issuable
,
issuable
.
project
,
current_user
,
issuable
.
milestone
)
end
def
create_labels_note
(
issuable
,
added_labels
,
removed_labels
)
def
create_labels_note
(
issuable
,
old_labels
)
added_labels
=
issuable
.
labels
-
old_labels
removed_labels
=
old_labels
-
issuable
.
labels
SystemNoteService
.
change_label
(
issuable
,
issuable
.
project
,
current_user
,
added_labels
,
removed_labels
)
end
...
...
@@ -71,20 +74,19 @@ class IssuableBaseService < BaseService
end
end
def
has_changes?
(
issuable
,
o
ptions
=
{}
)
def
has_changes?
(
issuable
,
o
ld_labels:
[]
)
valid_attrs
=
[
:title
,
:description
,
:assignee_id
,
:milestone_id
,
:target_branch
]
attrs_changed
=
valid_attrs
.
any?
do
|
attr
|
issuable
.
previous_changes
.
include?
(
attr
.
to_s
)
end
old_labels
=
options
[
:old_labels
]
labels_changed
=
old_labels
&&
issuable
.
labels
!=
old_labels
labels_changed
=
issuable
.
labels
!=
old_labels
attrs_changed
||
labels_changed
end
def
handle_common_system_notes
(
issuable
,
o
ptions
=
{}
)
def
handle_common_system_notes
(
issuable
,
o
ld_labels:
[]
)
if
issuable
.
previous_changes
.
include?
(
'title'
)
create_title_change_note
(
issuable
,
issuable
.
previous_changes
[
'title'
].
first
)
end
...
...
@@ -93,9 +95,6 @@ class IssuableBaseService < BaseService
create_task_status_note
(
issuable
)
end
old_labels
=
options
[
:old_labels
]
if
old_labels
&&
(
issuable
.
labels
!=
old_labels
)
create_labels_note
(
issuable
,
issuable
.
labels
-
old_labels
,
old_labels
-
issuable
.
labels
)
end
create_labels_note
(
issuable
,
old_labels
)
if
issuable
.
labels
!=
old_labels
end
end
app/services/issues/update_service.rb
View file @
cd3587c9
...
...
@@ -4,8 +4,8 @@ module Issues
update
(
issue
)
end
def
handle_changes
(
issue
,
o
ptions
=
{}
)
if
has_changes?
(
issue
,
o
ption
s
)
def
handle_changes
(
issue
,
o
ld_labels:
[]
)
if
has_changes?
(
issue
,
o
ld_labels:
old_label
s
)
todo_service
.
mark_pending_todos_as_done
(
issue
,
current_user
)
end
...
...
@@ -23,6 +23,11 @@ module Issues
notification_service
.
reassigned_issue
(
issue
,
current_user
)
todo_service
.
reassigned_issue
(
issue
,
current_user
)
end
added_labels
=
issue
.
labels
-
old_labels
if
added_labels
.
present?
notification_service
.
relabeled_issue
(
issue
,
added_labels
,
current_user
)
end
end
def
reopen_service
...
...
app/services/merge_requests/update_service.rb
View file @
cd3587c9
...
...
@@ -14,8 +14,8 @@ module MergeRequests
update
(
merge_request
)
end
def
handle_changes
(
merge_request
,
o
ptions
=
{}
)
if
has_changes?
(
merge_request
,
o
ption
s
)
def
handle_changes
(
merge_request
,
o
ld_labels:
[]
)
if
has_changes?
(
merge_request
,
o
ld_labels:
old_label
s
)
todo_service
.
mark_pending_todos_as_done
(
merge_request
,
current_user
)
end
...
...
@@ -44,6 +44,15 @@ module MergeRequests
merge_request
.
previous_changes
.
include?
(
'source_branch'
)
merge_request
.
mark_as_unchecked
end
added_labels
=
merge_request
.
labels
-
old_labels
if
added_labels
.
present?
notification_service
.
relabeled_merge_request
(
merge_request
,
added_labels
,
current_user
)
end
end
def
reopen_service
...
...
app/services/notification_service.rb
View file @
cd3587c9
...
...
@@ -24,16 +24,17 @@ class NotificationService
end
end
# When create an issue we should send
next emails
:
# When create an issue we should send
an email to
:
#
# * issue assignee if their notification level is not Disabled
# * project team members with notification level higher then Participating
# * watchers of the issue's labels
#
def
new_issue
(
issue
,
current_user
)
new_resource_email
(
issue
,
issue
.
project
,
'new_issue_email'
)
end
# When we close an issue we should send
next emails
:
# When we close an issue we should send
an email to
:
#
# * issue author if their notification level is not Disabled
# * issue assignee if their notification level is not Disabled
...
...
@@ -43,7 +44,7 @@ class NotificationService
close_resource_email
(
issue
,
issue
.
project
,
current_user
,
'closed_issue_email'
)
end
# When we reassign an issue we should send
next emails
:
# When we reassign an issue we should send
an email to
:
#
# * issue old assignee if their notification level is not Disabled
# * issue new assignee if their notification level is not Disabled
...
...
@@ -52,16 +53,25 @@ class NotificationService
reassign_resource_email
(
issue
,
issue
.
project
,
current_user
,
'reassigned_issue_email'
)
end
# When we add labels to an issue we should send an email to:
#
# * watchers of the issue's labels
#
def
relabeled_issue
(
issue
,
added_labels
,
current_user
)
relabeled_resource_email
(
issue
,
added_labels
,
current_user
,
'relabeled_issue_email'
)
end
# When create a merge request we should send
next emails
:
# When create a merge request we should send
an email to
:
#
# * mr assignee if their notification level is not Disabled
# * project team members with notification level higher then Participating
# * watchers of the mr's labels
#
def
new_merge_request
(
merge_request
,
current_user
)
new_resource_email
(
merge_request
,
merge_request
.
target_project
,
'new_merge_request_email'
)
end
# When we reassign a merge_request we should send
next emails
:
# When we reassign a merge_request we should send
an email to
:
#
# * merge_request old assignee if their notification level is not Disabled
# * merge_request assignee if their notification level is not Disabled
...
...
@@ -70,6 +80,14 @@ class NotificationService
reassign_resource_email
(
merge_request
,
merge_request
.
target_project
,
current_user
,
'reassigned_merge_request_email'
)
end
# When we add labels to a merge request we should send an email to:
#
# * watchers of the mr's labels
#
def
relabeled_merge_request
(
merge_request
,
added_labels
,
current_user
)
relabeled_resource_email
(
merge_request
,
added_labels
,
current_user
,
'relabeled_merge_request_email'
)
end
def
close_mr
(
merge_request
,
current_user
)
close_resource_email
(
merge_request
,
merge_request
.
target_project
,
current_user
,
'closed_merge_request_email'
)
end
...
...
@@ -91,7 +109,8 @@ class NotificationService
reopen_resource_email
(
merge_request
,
merge_request
.
target_project
,
current_user
,
'merge_request_status_email'
,
current_user
,
'merge_request_status_email'
,
'reopened'
)
end
...
...
@@ -348,19 +367,23 @@ class NotificationService
end
def
add_subscribed_users
(
recipients
,
target
)
return
recipients
unless
target
.
respond_to?
:subscri
ption
s
return
recipients
unless
target
.
respond_to?
:subscri
ber
s
subscriptions
=
target
.
subscriptions
recipients
+
target
.
subscribers
end
if
subscriptions
.
any?
recipients
+
subscriptions
.
where
(
subscribed:
true
).
map
(
&
:user
)
else
recipients
def
add_labels_subscribers
(
recipients
,
target
,
labels:
nil
)
return
recipients
unless
target
.
respond_to?
:labels
(
labels
||
target
.
labels
).
each
do
|
label
|
recipients
+=
label
.
subscribers
end
recipients
end
def
new_resource_email
(
target
,
project
,
method
)
recipients
=
build_recipients
(
target
,
project
,
target
.
author
)
recipients
=
build_recipients
(
target
,
project
,
target
.
author
,
action: :new
)
recipients
.
each
do
|
recipient
|
mailer
.
send
(
method
,
recipient
.
id
,
target
.
id
).
deliver_later
...
...
@@ -392,6 +415,15 @@ class NotificationService
end
end
def
relabeled_resource_email
(
target
,
labels
,
current_user
,
method
)
recipients
=
build_relabeled_recipients
(
target
,
current_user
,
labels:
labels
)
label_names
=
labels
.
map
(
&
:name
)
recipients
.
each
do
|
recipient
|
mailer
.
send
(
method
,
recipient
.
id
,
target
.
id
,
label_names
,
current_user
.
id
).
deliver_later
end
end
def
reopen_resource_email
(
target
,
project
,
current_user
,
method
,
status
)
recipients
=
build_recipients
(
target
,
project
,
current_user
)
...
...
@@ -416,6 +448,11 @@ class NotificationService
recipients
=
reject_muted_users
(
recipients
,
project
)
recipients
=
add_subscribed_users
(
recipients
,
target
)
if
action
==
:new
recipients
=
add_labels_subscribers
(
recipients
,
target
)
end
recipients
=
reject_unsubscribed_users
(
recipients
,
target
)
recipients
.
delete
(
current_user
)
...
...
@@ -423,6 +460,13 @@ class NotificationService
recipients
.
uniq
end
def
build_relabeled_recipients
(
target
,
current_user
,
labels
:)
recipients
=
add_labels_subscribers
([],
target
,
labels:
labels
)
recipients
=
reject_unsubscribed_users
(
recipients
,
target
)
recipients
.
delete
(
current_user
)
recipients
.
uniq
end
def
mailer
Notify
end
...
...
app/views/layouts/notify.html.haml
View file @
cd3587c9
...
...
@@ -42,12 +42,15 @@
-
else
#{
link_to
"View it on GitLab"
,
@target_url
}
.
%br
-# Don't link the host i
s
the line below, one link in the email is easier to quickly click than two.
-# Don't link the host i
n
the line below, one link in the email is easier to quickly click than two.
You're receiving this email because of your account on
#{
Gitlab
.
config
.
gitlab
.
host
}
.
If you'd like to receive fewer emails, you can
-
if
@sent_notification
&&
@sent_notification
.
unsubscribable?
=
link_to
"unsubscribe"
,
unsubscribe_sent_notification_url
(
@sent_notification
)
from this thread or
adjust your notification settings.
-
if
@labels_url
adjust your
#{
link_to
'label subscriptions'
,
@labels_url
}
.
-
else
-
if
@sent_notification
&&
@sent_notification
.
unsubscribable?
=
link_to
"unsubscribe"
,
unsubscribe_sent_notification_url
(
@sent_notification
)
from this thread or
adjust your notification settings.
=
email_action
@target_url
app/views/notify/_reassigned_issuable_email.text.erb
View file @
cd3587c9
Reassigned
<%=
issuable
.
class
.
model_name
.
human
.
titleize
%>
<%=
issuable
.
iid
%>
<%=
url_for
([
issuable
.
project
.
namespace
.
becomes
(
Namespace
),
issuable
.
project
,
issuable
,
{
only_path:
false
}])
%>
<%=
url_for
([
issuable
.
project
.
namespace
.
becomes
(
Namespace
),
issuable
.
project
,
issuable
,
{
only_path:
false
}])
%>
Assignee changed
<%=
"from
#{
@previous_assignee
.
name
}
"
if
@previous_assignee
-%>
to
<%=
"
#{
issuable
.
assignee_id
?
issuable
.
assignee_name
:
'Unassigned'
}
"
%>
app/views/notify/_relabeled_issuable_email.html.haml
0 → 100644
View file @
cd3587c9
%p
#{
'Label'
.
pluralize
(
@label_names
.
size
)
}
added:
%em
=
@label_names
.
to_sentence
app/views/notify/_relabeled_issuable_email.text.erb
0 → 100644
View file @
cd3587c9
<%=
'Label'
.
pluralize
(
@label_names
.
size
)
%>
added:
<%=
@label_names
.
to_sentence
%>
<%=
url_for
([
issuable
.
project
.
namespace
.
becomes
(
Namespace
),
issuable
.
project
,
issuable
,
{
only_path:
false
}])
%>
app/views/notify/relabeled_issue_email.html.haml
0 → 100644
View file @
cd3587c9
=
render
'relabeled_issuable_email'
,
issuable:
@issue
app/views/notify/relabeled_issue_email.text.erb
0 → 100644
View file @
cd3587c9
<%=
render
'relabeled_issuable_email'
,
issuable:
@issue
%>
app/views/notify/relabeled_merge_request_email.html.haml
0 → 100644
View file @
cd3587c9
=
render
'relabeled_issuable_email'
,
issuable:
@merge_request
app/views/notify/relabeled_merge_request_email.text.erb
0 → 100644
View file @
cd3587c9
<%=
render
'relabeled_issuable_email'
,
issuable:
@merge_request
%>
app/views/projects/labels/_label.html.haml
View file @
cd3587c9
...
...
@@ -10,6 +10,16 @@
=
link_to_label
(
label
)
do
=
pluralize
label
.
open_issues_count
,
'open issue'
-
if
current_user
.label-subscription
{
data:
{
url:
toggle_subscription_namespace_project_label_path
(
@project
.
namespace
,
@project
,
label
)}}
.subscription-status
{
data:
{
status:
label_subscription_status
(
label
)}}
%button
.btn.btn-sm.btn-info.subscribe-button
%span
=
label_subscription_toggle_button_text
(
label
)
-
if
can?
current_user
,
:admin_label
,
@project
=
link_to
'Edit'
,
edit_namespace_project_label_path
(
@project
.
namespace
,
@project
,
label
),
class:
'btn btn-sm'
=
link_to
'Delete'
,
namespace_project_label_path
(
@project
.
namespace
,
@project
,
label
),
class:
'btn btn-sm btn-remove remove-row'
,
method: :delete
,
remote:
true
,
data:
{
confirm:
"Remove this label? Are you sure?"
}
-
if
current_user
:javascript
new
Subscription
(
'
##{dom_id(label)} .label-subscription
'
);
app/views/shared/issuable/_sidebar.html.haml
View file @
cd3587c9
...
...
@@ -122,7 +122,7 @@
%hr
-
if
current_user
-
subscribed
=
issuable
.
subscribed?
(
current_user
)
.block.light
.block.light
.subscription
{
data:
{
url:
toggle_subscription_path
(
issuable
)}}
.sidebar-collapsed-icon
=
icon
(
'rss'
)
.title.hide-collapsed
...
...
@@ -148,5 +148,5 @@
=
clipboard_button
(
clipboard_text:
project_ref
)
:javascript
new
Subscription
(
"
#{
toggle_subscription_path
(
issuable
)
}
"
);
new
Subscription
(
'
.subscription
'
);
new
IssuableContext
();
config/routes.rb
View file @
cd3587c9
...
...
@@ -727,6 +727,10 @@ Rails.application.routes.draw do
collection
do
post
:generate
end
member
do
post
:toggle_subscription
end
end
resources
:issues
,
constraints:
{
id:
/\d+/
},
except:
[
:destroy
]
do
...
...
features/project/labels.feature
0 → 100644
View file @
cd3587c9
@labels
Feature
:
Labels
Background
:
Given
I sign in as a user
And
I own project
"Shop"
And project "Shop" has labels
:
"bug",
"feature",
"enhancement"
When
I visit project
"Shop"
labels page
@javascript
Scenario
:
I
can subscribe to a label
Then
I should see that I am not subscribed to the
"bug"
label
When
I click button
"Subscribe"
for the
"bug"
label
Then
I should see that I am subscribed to the
"bug"
label
When
I click button
"Unsubscribe"
for the
"bug"
label
Then
I should see that I am not subscribed to the
"bug"
label
features/steps/project/labels.rb
0 → 100644
View file @
cd3587c9
class
Spinach::Features::Labels
<
Spinach
::
FeatureSteps
include
SharedAuthentication
include
SharedIssuable
include
SharedProject
include
SharedNote
include
SharedPaths
include
SharedMarkdown
step
'And I visit project "Shop" labels page'
do
visit
namespace_project_labels_path
(
project
.
namespace
,
project
)
end
step
'I should see that I am subscribed to the "bug" label'
do
expect
(
subscribe_button
).
to
have_content
'Unsubscribe'
end
step
'I should see that I am not subscribed to the "bug" label'
do
expect
(
subscribe_button
).
to
have_content
'Subscribe'
end
step
'I click button "Unsubscribe" for the "bug" label'
do
subscribe_button
.
click
end
step
'I click button "Subscribe" for the "bug" label'
do
subscribe_button
.
click
end
private
def
subscribe_button
first
(
'.subscribe-button span'
)
end
end
spec/factories/labels.rb
View file @
cd3587c9
...
...
@@ -13,7 +13,7 @@
FactoryGirl
.
define
do
factory
:label
do
title
"Bug"
sequence
(
:title
)
{
|
n
|
"label
#{
n
}
"
}
color
"#990000"
project
end
...
...
spec/mailers/notify_spec.rb
View file @
cd3587c9
...
...
@@ -100,6 +100,34 @@ describe Notify do
end
end
describe
'that have been relabeled'
do
subject
{
Notify
.
relabeled_issue_email
(
recipient
.
id
,
issue
.
id
,
%w[foo bar baz]
,
current_user
.
id
)
}
it_behaves_like
'a multiple recipients email'
it_behaves_like
'an answer to an existing thread'
,
'issue'
it_behaves_like
'it should show Gmail Actions View Issue link'
it_behaves_like
'a user cannot unsubscribe through footer link'
it_behaves_like
'an email with a labels subscriptions link in its footer'
it
'is sent as the author'
do
sender
=
subject
.
header
[
:from
].
addrs
[
0
]
expect
(
sender
.
display_name
).
to
eq
(
current_user
.
name
)
expect
(
sender
.
address
).
to
eq
(
gitlab_sender
)
end
it
'has the correct subject'
do
is_expected
.
to
have_subject
/
#{
issue
.
title
}
\(#
#{
issue
.
iid
}
\)/
end
it
'contains the names of the added labels'
do
is_expected
.
to
have_body_text
/foo, bar, and baz/
end
it
'contains a link to the issue'
do
is_expected
.
to
have_body_text
/
#{
namespace_project_issue_path
project
.
namespace
,
project
,
issue
}
/
end
end
describe
'status changed'
do
let
(
:status
)
{
'closed'
}
subject
{
Notify
.
issue_status_changed_email
(
recipient
.
id
,
issue
.
id
,
status
,
current_user
.
id
)
}
...
...
@@ -238,6 +266,34 @@ describe Notify do
end
end
describe
'that have been relabeled'
do
subject
{
Notify
.
relabeled_merge_request_email
(
recipient
.
id
,
merge_request
.
id
,
%w[foo bar baz]
,
current_user
.
id
)
}
it_behaves_like
'a multiple recipients email'
it_behaves_like
'an answer to an existing thread'
,
'merge_request'
it_behaves_like
'it should show Gmail Actions View Merge request link'
it_behaves_like
'a user cannot unsubscribe through footer link'
it_behaves_like
'an email with a labels subscriptions link in its footer'
it
'is sent as the author'
do
sender
=
subject
.
header
[
:from
].
addrs
[
0
]
expect
(
sender
.
display_name
).
to
eq
(
current_user
.
name
)
expect
(
sender
.
address
).
to
eq
(
gitlab_sender
)
end
it
'has the correct subject'
do
is_expected
.
to
have_subject
/
#{
merge_request
.
title
}
\(#
#{
merge_request
.
iid
}
\)/
end
it
'contains the names of the added labels'
do
is_expected
.
to
have_body_text
/foo, bar, and baz/
end
it
'contains a link to the merge request'
do
is_expected
.
to
have_body_text
/
#{
namespace_project_merge_request_path
project
.
namespace
,
project
,
merge_request
}
/
end
end
describe
'status changed'
do
let
(
:status
)
{
'reopened'
}
subject
{
Notify
.
merge_request_status_email
(
recipient
.
id
,
merge_request
.
id
,
status
,
current_user
.
id
)
}
...
...
spec/mailers/shared/notify.rb
View file @
cd3587c9
...
...
@@ -112,6 +112,10 @@ shared_examples 'an unsubscribeable thread' do
it
{
is_expected
.
to
have_body_text
/unsubscribe/
}
end
shared_examples
"a user cannot unsubscribe through footer link"
do
shared_examples
'a user cannot unsubscribe through footer link'
do
it
{
is_expected
.
not_to
have_body_text
/unsubscribe/
}
end
shared_examples
'an email with a labels subscriptions link in its footer'
do
it
{
is_expected
.
to
have_body_text
/label subscriptions/
}
end
spec/models/concerns/issuable_spec.rb
View file @
cd3587c9
...
...
@@ -113,6 +113,48 @@ describe Issue, "Issuable" do
end
end
describe
'#subscribed?'
do
context
'user is not a participant in the issue'
do
before
{
allow
(
issue
).
to
receive
(
:participants
).
with
(
user
).
and_return
([])
}
it
'returns false when no subcription exists'
do
expect
(
issue
.
subscribed?
(
user
)).
to
be_falsey
end
it
'returns true when a subcription exists and subscribed is true'
do
issue
.
subscriptions
.
create
(
user:
user
,
subscribed:
true
)
expect
(
issue
.
subscribed?
(
user
)).
to
be_truthy
end
it
'returns false when a subcription exists and subscribed is false'
do
issue
.
subscriptions
.
create
(
user:
user
,
subscribed:
false
)
expect
(
issue
.
subscribed?
(
user
)).
to
be_falsey
end
end
context
'user is a participant in the issue'
do
before
{
allow
(
issue
).
to
receive
(
:participants
).
with
(
user
).
and_return
([
user
])
}
it
'returns false when no subcription exists'
do
expect
(
issue
.
subscribed?
(
user
)).
to
be_truthy
end
it
'returns true when a subcription exists and subscribed is true'
do
issue
.
subscriptions
.
create
(
user:
user
,
subscribed:
true
)
expect
(
issue
.
subscribed?
(
user
)).
to
be_truthy
end
it
'returns false when a subcription exists and subscribed is false'
do
issue
.
subscriptions
.
create
(
user:
user
,
subscribed:
false
)
expect
(
issue
.
subscribed?
(
user
)).
to
be_falsey
end
end
end
describe
"#to_hook_data"
do
let
(
:data
)
{
issue
.
to_hook_data
(
user
)
}
let
(
:project
)
{
issue
.
project
}
...
...
spec/models/concerns/subscribable_spec.rb
0 → 100644
View file @
cd3587c9
require
'spec_helper'
describe
Subscribable
,
'Subscribable'
do
let
(
:resource
)
{
create
(
:issue
)
}
let
(
:user
)
{
create
(
:user
)
}
describe
'#subscribed?'
do
it
'returns false when no subcription exists'
do
expect
(
resource
.
subscribed?
(
user
)).
to
be_falsey
end
it
'returns true when a subcription exists and subscribed is true'
do
resource
.
subscriptions
.
create
(
user:
user
,
subscribed:
true
)
expect
(
resource
.
subscribed?
(
user
)).
to
be_truthy
end
it
'returns false when a subcription exists and subscribed is false'
do
resource
.
subscriptions
.
create
(
user:
user
,
subscribed:
false
)
expect
(
resource
.
subscribed?
(
user
)).
to
be_falsey
end
end
describe
'#subscribers'
do
it
'returns [] when no subcribers exists'
do
expect
(
resource
.
subscribers
).
to
be_empty
end
it
'returns the subscribed users'
do
resource
.
subscriptions
.
create
(
user:
user
,
subscribed:
true
)
resource
.
subscriptions
.
create
(
user:
create
(
:user
),
subscribed:
false
)
expect
(
resource
.
subscribers
).
to
eq
[
user
]
end
end
describe
'#toggle_subscription'
do
it
'toggles the current subscription state for the given user'
do
expect
(
resource
.
subscribed?
(
user
)).
to
be_falsey
resource
.
toggle_subscription
(
user
)
expect
(
resource
.
subscribed?
(
user
)).
to
be_truthy
end
end
describe
'#unsubscribe'
do
it
'unsubscribes the given current user'
do
resource
.
subscriptions
.
create
(
user:
user
,
subscribed:
true
)
expect
(
resource
.
subscribed?
(
user
)).
to
be_truthy
resource
.
unsubscribe
(
user
)
expect
(
resource
.
subscribed?
(
user
)).
to
be_falsey
end
end
end
spec/services/issues/update_service_spec.rb
View file @
cd3587c9
...
...
@@ -6,6 +6,7 @@ describe Issues::UpdateService, services: true do
let
(
:user3
)
{
create
(
:user
)
}
let
(
:issue
)
{
create
(
:issue
,
title:
'Old title'
,
assignee_id:
user3
.
id
)
}
let
(
:label
)
{
create
(
:label
)
}
let
(
:label2
)
{
create
(
:label
)
}
let
(
:project
)
{
issue
.
project
}
before
do
...
...
@@ -48,7 +49,7 @@ describe Issues::UpdateService, services: true do
it
{
expect
(
@issue
.
assignee
).
to
eq
(
user2
)
}
it
{
expect
(
@issue
).
to
be_closed
}
it
{
expect
(
@issue
.
labels
.
count
).
to
eq
(
1
)
}
it
{
expect
(
@issue
.
labels
.
first
.
title
).
to
eq
(
'Bug'
)
}
it
{
expect
(
@issue
.
labels
.
first
.
title
).
to
eq
(
label
.
name
)
}
it
'should send email to user2 about assign of new issue and email to user3 about issue unassignment'
do
deliveries
=
ActionMailer
::
Base
.
deliveries
...
...
@@ -148,6 +149,48 @@ describe Issues::UpdateService, services: true do
end
end
context
'when the issue is relabeled'
do
let!
(
:non_subscriber
)
{
create
(
:user
)
}
let!
(
:subscriber
)
{
create
(
:user
).
tap
{
|
u
|
label
.
toggle_subscription
(
u
)
}
}
it
'sends notifications for subscribers of newly added labels'
do
opts
=
{
label_ids:
[
label
.
id
]
}
perform_enqueued_jobs
do
@issue
=
Issues
::
UpdateService
.
new
(
project
,
user
,
opts
).
execute
(
issue
)
end
should_email
(
subscriber
)
should_not_email
(
non_subscriber
)
end
context
'when issue has the `label` label'
do
before
{
issue
.
labels
<<
label
}
it
'does not send notifications for existing labels'
do
opts
=
{
label_ids:
[
label
.
id
,
label2
.
id
]
}
perform_enqueued_jobs
do
@issue
=
Issues
::
UpdateService
.
new
(
project
,
user
,
opts
).
execute
(
issue
)
end
should_not_email
(
subscriber
)
should_not_email
(
non_subscriber
)
end
it
'does not send notifications for removed labels'
do
opts
=
{
label_ids:
[
label2
.
id
]
}
perform_enqueued_jobs
do
@issue
=
Issues
::
UpdateService
.
new
(
project
,
user
,
opts
).
execute
(
issue
)
end
should_not_email
(
subscriber
)
should_not_email
(
non_subscriber
)
end
end
end
context
'when Issue has tasks'
do
before
{
update_issue
({
description:
"- [ ] Task 1
\n
- [ ] Task 2"
})
}
...
...
spec/services/merge_requests/update_service_spec.rb
View file @
cd3587c9
...
...
@@ -7,6 +7,7 @@ describe MergeRequests::UpdateService, services: true do
let
(
:merge_request
)
{
create
(
:merge_request
,
:simple
,
title:
'Old title'
,
assignee_id:
user3
.
id
)
}
let
(
:project
)
{
merge_request
.
project
}
let
(
:label
)
{
create
(
:label
)
}
let
(
:label2
)
{
create
(
:label
)
}
before
do
project
.
team
<<
[
user
,
:master
]
...
...
@@ -53,7 +54,7 @@ describe MergeRequests::UpdateService, services: true do
it
{
expect
(
@merge_request
.
assignee
).
to
eq
(
user2
)
}
it
{
expect
(
@merge_request
).
to
be_closed
}
it
{
expect
(
@merge_request
.
labels
.
count
).
to
eq
(
1
)
}
it
{
expect
(
@merge_request
.
labels
.
first
.
title
).
to
eq
(
'Bug'
)
}
it
{
expect
(
@merge_request
.
labels
.
first
.
title
).
to
eq
(
label
.
name
)
}
it
{
expect
(
@merge_request
.
target_branch
).
to
eq
(
'target'
)
}
it
'should execute hooks with update action'
do
...
...
@@ -176,6 +177,48 @@ describe MergeRequests::UpdateService, services: true do
end
end
context
'when the issue is relabeled'
do
let!
(
:non_subscriber
)
{
create
(
:user
)
}
let!
(
:subscriber
)
{
create
(
:user
).
tap
{
|
u
|
label
.
toggle_subscription
(
u
)
}
}
it
'sends notifications for subscribers of newly added labels'
do
opts
=
{
label_ids:
[
label
.
id
]
}
perform_enqueued_jobs
do
@merge_request
=
MergeRequests
::
UpdateService
.
new
(
project
,
user
,
opts
).
execute
(
merge_request
)
end
should_email
(
subscriber
)
should_not_email
(
non_subscriber
)
end
context
'when issue has the `label` label'
do
before
{
merge_request
.
labels
<<
label
}
it
'does not send notifications for existing labels'
do
opts
=
{
label_ids:
[
label
.
id
,
label2
.
id
]
}
perform_enqueued_jobs
do
@merge_request
=
MergeRequests
::
UpdateService
.
new
(
project
,
user
,
opts
).
execute
(
merge_request
)
end
should_not_email
(
subscriber
)
should_not_email
(
non_subscriber
)
end
it
'does not send notifications for removed labels'
do
opts
=
{
label_ids:
[
label2
.
id
]
}
perform_enqueued_jobs
do
@merge_request
=
MergeRequests
::
UpdateService
.
new
(
project
,
user
,
opts
).
execute
(
merge_request
)
end
should_not_email
(
subscriber
)
should_not_email
(
non_subscriber
)
end
end
end
context
'when MergeRequest has tasks'
do
before
{
update_merge_request
({
description:
"- [ ] Task 1
\n
- [ ] Task 2"
})
}
...
...
spec/services/notification_service_spec.rb
View file @
cd3587c9
...
...
@@ -224,6 +224,15 @@ describe NotificationService, services: true do
should_not_email
(
issue
.
assignee
)
end
it
"emails subscribers of the issue's labels"
do
subscriber
=
create
(
:user
)
label
=
create
(
:label
,
issues:
[
issue
])
label
.
toggle_subscription
(
subscriber
)
notification
.
new_issue
(
issue
,
@u_disabled
)
should_email
(
subscriber
)
end
end
describe
:reassigned_issue
do
...
...
@@ -296,6 +305,35 @@ describe NotificationService, services: true do
end
end
describe
'#relabeled_issue'
do
let
(
:label
)
{
create
(
:label
,
issues:
[
issue
])
}
let
(
:label2
)
{
create
(
:label
)
}
let!
(
:subscriber_to_label
)
{
create
(
:user
).
tap
{
|
u
|
label
.
toggle_subscription
(
u
)
}
}
let!
(
:subscriber_to_label2
)
{
create
(
:user
).
tap
{
|
u
|
label2
.
toggle_subscription
(
u
)
}
}
it
"emails subscribers of the issue's added labels only"
do
notification
.
relabeled_issue
(
issue
,
[
label2
],
@u_disabled
)
should_not_email
(
subscriber_to_label
)
should_email
(
subscriber_to_label2
)
end
it
"doesn't send email to anyone but subscribers of the given labels"
do
notification
.
relabeled_issue
(
issue
,
[
label2
],
@u_disabled
)
should_not_email
(
issue
.
assignee
)
should_not_email
(
issue
.
author
)
should_not_email
(
@u_watcher
)
should_not_email
(
@u_participant_mentioned
)
should_not_email
(
@subscriber
)
should_not_email
(
@watcher_and_subscriber
)
should_not_email
(
@unsubscriber
)
should_not_email
(
@u_participating
)
should_not_email
(
subscriber_to_label
)
should_email
(
subscriber_to_label2
)
end
end
describe
:close_issue
do
it
'should sent email to issue assignee and issue author'
do
notification
.
close_issue
(
issue
,
@u_disabled
)
...
...
@@ -349,6 +387,15 @@ describe NotificationService, services: true do
should_not_email
(
@u_participating
)
should_not_email
(
@u_disabled
)
end
it
"emails subscribers of the merge request's labels"
do
subscriber
=
create
(
:user
)
label
=
create
(
:label
,
merge_requests:
[
merge_request
])
label
.
toggle_subscription
(
subscriber
)
notification
.
new_merge_request
(
merge_request
,
@u_disabled
)
should_email
(
subscriber
)
end
end
describe
:reassigned_merge_request
do
...
...
@@ -366,6 +413,35 @@ describe NotificationService, services: true do
end
end
describe
:relabel_merge_request
do
let
(
:label
)
{
create
(
:label
,
merge_requests:
[
merge_request
])
}
let
(
:label2
)
{
create
(
:label
)
}
let!
(
:subscriber_to_label
)
{
create
(
:user
).
tap
{
|
u
|
label
.
toggle_subscription
(
u
)
}
}
let!
(
:subscriber_to_label2
)
{
create
(
:user
).
tap
{
|
u
|
label2
.
toggle_subscription
(
u
)
}
}
it
"emails subscribers of the merge request's added labels only"
do
notification
.
relabeled_merge_request
(
merge_request
,
[
label2
],
@u_disabled
)
should_not_email
(
subscriber_to_label
)
should_email
(
subscriber_to_label2
)
end
it
"doesn't send email to anyone but subscribers of the given labels"
do
notification
.
relabeled_merge_request
(
merge_request
,
[
label2
],
@u_disabled
)
should_not_email
(
merge_request
.
assignee
)
should_not_email
(
merge_request
.
author
)
should_not_email
(
@u_watcher
)
should_not_email
(
@u_participant_mentioned
)
should_not_email
(
@subscriber
)
should_not_email
(
@watcher_and_subscriber
)
should_not_email
(
@unsubscriber
)
should_not_email
(
@u_participating
)
should_not_email
(
subscriber_to_label
)
should_email
(
subscriber_to_label2
)
end
end
describe
:closed_merge_request
do
it
do
notification
.
close_mr
(
merge_request
,
@u_disabled
)
...
...
@@ -467,16 +543,4 @@ describe NotificationService, services: true do
# Make the watcher a subscriber to detect dupes
issuable
.
subscriptions
.
create
(
user:
@watcher_and_subscriber
,
subscribed:
true
)
end
def
sent_to_user?
(
user
)
ActionMailer
::
Base
.
deliveries
.
map
(
&
:to
).
flatten
.
count
(
user
.
email
)
==
1
end
def
should_email
(
user
)
expect
(
sent_to_user?
(
user
)).
to
be_truthy
end
def
should_not_email
(
user
)
expect
(
sent_to_user?
(
user
)).
to
be_falsey
end
end
spec/spec_helper.rb
View file @
cd3587c9
...
...
@@ -32,6 +32,7 @@ RSpec.configure do |config|
config
.
include
LoginHelpers
,
type: :feature
config
.
include
LoginHelpers
,
type: :request
config
.
include
StubConfiguration
config
.
include
EmailHelpers
config
.
include
RelativeUrl
,
type:
feature
config
.
include
TestEnv
config
.
include
ActiveJob
::
TestHelper
...
...
spec/support/email_helpers.rb
0 → 100644
View file @
cd3587c9
module
EmailHelpers
def
sent_to_user?
(
user
)
ActionMailer
::
Base
.
deliveries
.
map
(
&
:to
).
flatten
.
count
(
user
.
email
)
==
1
end
def
should_email
(
user
)
expect
(
sent_to_user?
(
user
)).
to
be_truthy
end
def
should_not_email
(
user
)
expect
(
sent_to_user?
(
user
)).
to
be_falsey
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