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
d6b11daf
Commit
d6b11daf
authored
8 years ago
by
Jarka Kadlecova
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Support notes without project
parent
270dc226
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
204 additions
and
20 deletions
+204
-20
app/mailers/emails/notes.rb
app/mailers/emails/notes.rb
+8
-0
app/models/ability.rb
app/models/ability.rb
+11
-0
app/models/concerns/participable.rb
app/models/concerns/participable.rb
+5
-1
app/models/note.rb
app/models/note.rb
+8
-3
app/services/notes/create_service.rb
app/services/notes/create_service.rb
+4
-3
app/services/notes/post_process_service.rb
app/services/notes/post_process_service.rb
+4
-2
app/services/notification_service.rb
app/services/notification_service.rb
+20
-7
app/views/notify/note_personal_snippet_email.html.haml
app/views/notify/note_personal_snippet_email.html.haml
+1
-0
changelogs/unreleased/no_project_notes.yml
changelogs/unreleased/no_project_notes.yml
+4
-0
spec/factories/notes.rb
spec/factories/notes.rb
+6
-0
spec/models/ability_spec.rb
spec/models/ability_spec.rb
+30
-0
spec/models/concerns/mentionable_spec.rb
spec/models/concerns/mentionable_spec.rb
+10
-0
spec/models/note_spec.rb
spec/models/note_spec.rb
+13
-0
spec/services/notes/create_service_spec.rb
spec/services/notes/create_service_spec.rb
+31
-4
spec/services/notification_service_spec.rb
spec/services/notification_service_spec.rb
+49
-0
No files found.
app/mailers/emails/notes.rb
View file @
d6b11daf
...
...
@@ -38,6 +38,14 @@ module Emails
mail_answer_thread
(
@snippet
,
note_thread_options
(
recipient_id
))
end
def
note_personal_snippet_email
(
recipient_id
,
note_id
)
setup_note_mail
(
note_id
,
recipient_id
)
@snippet
=
@note
.
noteable
@target_url
=
snippet_url
(
@note
.
noteable
)
mail_answer_thread
(
@snippet
,
note_thread_options
(
recipient_id
))
end
private
def
note_target_url_options
...
...
This diff is collapsed.
Click to expand it.
app/models/ability.rb
View file @
d6b11daf
...
...
@@ -22,6 +22,17 @@ class Ability
end
end
# Given a list of users and a snippet this method returns the users that can
# read the given snippet.
def
users_that_can_read_personal_snippet
(
users
,
snippet
)
case
snippet
.
visibility_level
when
Snippet
::
INTERNAL
,
Snippet
::
PUBLIC
users
when
Snippet
::
PRIVATE
users
.
select
{
|
user
|
snippet
.
author
==
user
}
end
end
# Returns an Array of Issues that can be read by the given user.
#
# issues - The issues to reduce down to those readable by the user.
...
...
This diff is collapsed.
Click to expand it.
app/models/concerns/participable.rb
View file @
d6b11daf
...
...
@@ -96,6 +96,10 @@ module Participable
participants
.
merge
(
ext
.
users
)
Ability
.
users_that_can_read_project
(
participants
.
to_a
,
project
)
if
self
.
is_a?
(
PersonalSnippet
)
Ability
.
users_that_can_read_personal_snippet
(
participants
.
to_a
,
self
)
else
Ability
.
users_that_can_read_project
(
participants
.
to_a
,
project
)
end
end
end
This diff is collapsed.
Click to expand it.
app/models/note.rb
View file @
d6b11daf
...
...
@@ -43,7 +43,8 @@ class Note < ActiveRecord::Base
delegate
:name
,
:email
,
to: :author
,
prefix:
true
delegate
:title
,
to: :noteable
,
allow_nil:
true
validates
:note
,
:project
,
presence:
true
validates
:note
,
presence:
true
validates
:project
,
presence:
true
,
unless: :for_personal_snippet?
# Attachments are deprecated and are handled by Markdown uploader
validates
:attachment
,
file_size:
{
maximum: :max_attachment_size
}
...
...
@@ -53,7 +54,7 @@ class Note < ActiveRecord::Base
validates
:commit_id
,
presence:
true
,
if: :for_commit?
validates
:author
,
presence:
true
validate
unless:
[
:for_commit?
,
:importing?
]
do
|
note
|
validate
unless:
[
:for_commit?
,
:importing?
,
:for_personal_snippet?
]
do
|
note
|
unless
note
.
noteable
.
try
(
:project
)
==
note
.
project
errors
.
add
(
:invalid_project
,
'Note and noteable project mismatch'
)
end
...
...
@@ -83,7 +84,7 @@ class Note < ActiveRecord::Base
after_initialize
:ensure_discussion_id
before_validation
:nullify_blank_type
,
:nullify_blank_line_code
before_validation
:set_discussion_id
after_save
:keep_around_commit
after_save
:keep_around_commit
,
unless: :for_personal_snippet?
class
<<
self
def
model_name
...
...
@@ -165,6 +166,10 @@ class Note < ActiveRecord::Base
noteable_type
==
"Snippet"
end
def
for_personal_snippet?
noteable_type
==
"Snippet"
&&
noteable
.
type
==
'PersonalSnippet'
end
# override to return commits, which are not active record
def
noteable
if
for_commit?
...
...
This diff is collapsed.
Click to expand it.
app/services/notes/create_service.rb
View file @
d6b11daf
...
...
@@ -3,9 +3,10 @@ module Notes
def
execute
merge_request_diff_head_sha
=
params
.
delete
(
:merge_request_diff_head_sha
)
note
=
project
.
notes
.
new
(
params
)
note
.
author
=
current_user
note
.
system
=
false
note
=
Note
.
new
(
params
)
note
.
project
=
project
note
.
author
=
current_user
note
.
system
=
false
if
note
.
award_emoji?
noteable
=
note
.
noteable
...
...
This diff is collapsed.
Click to expand it.
app/services/notes/post_process_service.rb
View file @
d6b11daf
...
...
@@ -10,8 +10,10 @@ module Notes
# Skip system notes, like status changes and cross-references and awards
unless
@note
.
system?
EventCreateService
.
new
.
leave_note
(
@note
,
@note
.
author
)
@note
.
create_cross_references!
execute_note_hooks
unless
@note
.
for_personal_snippet?
@note
.
create_cross_references!
execute_note_hooks
end
end
end
...
...
This diff is collapsed.
Click to expand it.
app/services/notification_service.rb
View file @
d6b11daf
...
...
@@ -178,8 +178,15 @@ class NotificationService
recipients
=
[]
mentioned_users
=
note
.
mentioned_users
mentioned_users
.
select!
do
|
user
|
user
.
can?
(
:read_project
,
note
.
project
)
if
note
.
for_personal_snippet?
mentioned_users
.
select!
do
|
user
|
user
.
can?
(
:read_personal_snippet
,
note
.
noteable
)
end
else
mentioned_users
.
select!
do
|
user
|
user
.
can?
(
:read_project
,
note
.
project
)
end
end
# Add all users participating in the thread (author, assignee, comment authors)
...
...
@@ -192,11 +199,13 @@ class NotificationService
recipients
=
recipients
.
concat
(
participants
)
# Merge project watchers
recipients
=
add_project_watchers
(
recipients
,
note
.
project
)
unless
note
.
for_personal_snippet?
# Merge project watchers
recipients
=
add_project_watchers
(
recipients
,
note
.
project
)
# Merge project with custom notification
recipients
=
add_custom_notifications
(
recipients
,
note
.
project
,
:new_note
)
# Merge project with custom notification
recipients
=
add_custom_notifications
(
recipients
,
note
.
project
,
:new_note
)
end
# Reject users with Mention notification level, except those mentioned in _this_ note.
recipients
=
reject_mention_users
(
recipients
-
mentioned_users
,
note
.
project
)
...
...
@@ -212,7 +221,11 @@ class NotificationService
recipients
=
recipients
.
uniq
# build notify method like 'note_commit_email'
notify_method
=
"note_
#{
note
.
noteable_type
.
underscore
}
_email"
.
to_sym
if
note
.
for_personal_snippet?
notify_method
=
"note_personal_snippet_email"
.
to_sym
else
notify_method
=
"note_
#{
note
.
noteable_type
.
underscore
}
_email"
.
to_sym
end
recipients
.
each
do
|
recipient
|
mailer
.
send
(
notify_method
,
recipient
.
id
,
note
.
id
).
deliver_later
...
...
This diff is collapsed.
Click to expand it.
app/views/notify/note_personal_snippet_email.html.haml
0 → 100644
View file @
d6b11daf
render 'note_message'
This diff is collapsed.
Click to expand it.
changelogs/unreleased/no_project_notes.yml
0 → 100644
View file @
d6b11daf
---
title
:
Support notes when a project is not specified (personal snippet notes)
merge_request
:
8468
author
:
This diff is collapsed.
Click to expand it.
spec/factories/notes.rb
View file @
d6b11daf
...
...
@@ -13,6 +13,7 @@ FactoryGirl.define do
factory
:note_on_issue
,
traits:
[
:on_issue
],
aliases:
[
:votable_note
]
factory
:note_on_merge_request
,
traits:
[
:on_merge_request
]
factory
:note_on_project_snippet
,
traits:
[
:on_project_snippet
]
factory
:note_on_personal_snippet
,
traits:
[
:on_personal_snippet
]
factory
:system_note
,
traits:
[
:system
]
factory
:legacy_diff_note_on_commit
,
traits:
[
:on_commit
,
:legacy_diff_note
],
class:
LegacyDiffNote
...
...
@@ -70,6 +71,11 @@ FactoryGirl.define do
noteable
{
create
(
:project_snippet
,
project:
project
)
}
end
trait
:on_personal_snippet
do
noteable
{
create
(
:personal_snippet
)
}
project
nil
end
trait
:system
do
system
true
end
...
...
This diff is collapsed.
Click to expand it.
spec/models/ability_spec.rb
View file @
d6b11daf
...
...
@@ -171,6 +171,36 @@ describe Ability, lib: true do
end
end
describe
'.users_that_can_read_personal_snippet'
do
subject
{
Ability
.
users_that_can_read_personal_snippet
(
users
,
snippet
)
}
let
(
:users
)
{
create_list
(
:user
,
3
)
}
let
(
:author
)
{
users
[
0
]
}
context
'private snippet'
do
let
(
:snippet
)
{
create
(
:personal_snippet
,
:private
,
author:
author
)
}
it
'is readable only by its author'
do
expect
(
subject
).
to
match_array
([
author
])
end
end
context
'internal snippet'
do
let
(
:snippet
)
{
create
(
:personal_snippet
,
:public
,
author:
author
)
}
it
'is readable by all registered users'
do
expect
(
subject
).
to
match_array
(
users
)
end
end
context
'public snippet'
do
let
(
:snippet
)
{
create
(
:personal_snippet
,
:public
,
author:
author
)
}
it
'is readable by all users'
do
expect
(
subject
).
to
match_array
(
users
)
end
end
end
describe
'.issues_readable_by_user'
do
context
'with an admin user'
do
it
'returns all given issues'
do
...
...
This diff is collapsed.
Click to expand it.
spec/models/concerns/mentionable_spec.rb
View file @
d6b11daf
...
...
@@ -138,6 +138,16 @@ describe Issue, "Mentionable" do
issue
.
update_attributes
(
description:
issues
[
1
].
to_reference
)
issue
.
create_new_cross_references!
end
it
'notifies new references from project snippet note'
do
snippet
=
create
(
:snippet
,
project:
project
)
note
=
create
(
:note
,
note:
issues
[
0
].
to_reference
,
noteable:
snippet
,
project:
project
,
author:
author
)
expect
(
SystemNoteService
).
to
receive
(
:cross_reference
).
with
(
issues
[
1
],
any_args
)
note
.
update_attributes
(
note:
issues
[
1
].
to_reference
)
note
.
create_new_cross_references!
end
end
def
create_issue
(
description
:)
...
...
This diff is collapsed.
Click to expand it.
spec/models/note_spec.rb
View file @
d6b11daf
...
...
@@ -52,6 +52,19 @@ describe Note, models: true do
subject
{
create
(
:note
)
}
it
{
is_expected
.
to
be_valid
}
end
context
'when project is missing for a project related note'
do
subject
{
build
(
:note
,
project:
nil
,
noteable:
build_stubbed
(
:issue
))
}
it
{
is_expected
.
to
be_invalid
}
end
context
'when noteable is a personal snippet'
do
subject
{
create
(
:note_on_personal_snippet
)
}
it
'is valid without project'
do
is_expected
.
to
be_valid
end
end
end
describe
"Commit notes"
do
...
...
This diff is collapsed.
Click to expand it.
spec/services/notes/create_service_spec.rb
View file @
d6b11daf
...
...
@@ -32,9 +32,15 @@ describe Notes::CreateService, services: true do
expect
(
note
.
note
).
to
eq
(
opts
[
:note
])
end
it
'note belongs to the correct project'
do
note
=
Notes
::
CreateService
.
new
(
project
,
user
,
opts
).
execute
expect
(
note
.
project
).
to
eq
(
project
)
end
it
'TodoService#new_note is called'
do
note
=
build
(
:note
)
allow
(
project
).
to
receive_message_chain
(
:notes
,
:new
).
with
(
opts
)
{
note
}
note
=
build
(
:note
,
project:
project
)
allow
(
Note
).
to
receive
(
:new
).
with
(
opts
)
{
note
}
expect_any_instance_of
(
TodoService
).
to
receive
(
:new_note
).
with
(
note
,
user
)
...
...
@@ -42,8 +48,8 @@ describe Notes::CreateService, services: true do
end
it
'enqueues NewNoteWorker'
do
note
=
build
(
:note
,
id:
999
)
allow
(
project
).
to
receive_message_chain
(
:notes
,
:new
).
with
(
opts
)
{
note
}
note
=
build
(
:note
,
id:
999
,
project:
project
)
allow
(
Note
).
to
receive
(
:new
).
with
(
opts
)
{
note
}
expect
(
NewNoteWorker
).
to
receive
(
:perform_async
).
with
(
note
.
id
)
...
...
@@ -75,6 +81,27 @@ describe Notes::CreateService, services: true do
end
end
end
describe
'personal snippet note'
do
subject
{
described_class
.
new
(
nil
,
user
,
params
).
execute
}
let
(
:snippet
)
{
create
(
:personal_snippet
)
}
let
(
:params
)
do
{
note:
'comment'
,
noteable_type:
'Snippet'
,
noteable_id:
snippet
.
id
}
end
it
'returns a valid note'
do
expect
(
subject
).
to
be_valid
end
it
'returns a persisted note'
do
expect
(
subject
).
to
be_persisted
end
it
'note has valid content'
do
expect
(
subject
.
note
).
to
eq
(
params
[
:note
])
end
end
end
describe
"award emoji"
do
...
...
This diff is collapsed.
Click to expand it.
spec/services/notification_service_spec.rb
View file @
d6b11daf
...
...
@@ -269,6 +269,55 @@ describe NotificationService, services: true do
end
end
context
'personal snippet note'
do
let
(
:snippet
)
{
create
(
:personal_snippet
,
:public
,
author:
@u_snippet_author
)
}
let
(
:note
)
{
create
(
:note_on_personal_snippet
,
noteable:
snippet
,
note:
'@mentioned note'
,
author:
@u_note_author
)
}
before
do
@u_watcher
=
create_global_setting_for
(
create
(
:user
),
:watch
)
@u_participant
=
create_global_setting_for
(
create
(
:user
),
:participating
)
@u_disabled
=
create_global_setting_for
(
create
(
:user
),
:disabled
)
@u_mentioned
=
create_global_setting_for
(
create
(
:user
,
username:
'mentioned'
),
:mention
)
@u_mentioned_level
=
create_global_setting_for
(
create
(
:user
,
username:
'participator'
),
:mention
)
@u_note_author
=
create
(
:user
,
username:
'note_author'
)
@u_snippet_author
=
create
(
:user
,
username:
'snippet_author'
)
@u_not_mentioned
=
create_global_setting_for
(
create
(
:user
,
username:
'regular'
),
:participating
)
reset_delivered_emails!
end
let!
(
:notes
)
do
[
create
(
:note_on_personal_snippet
,
noteable:
snippet
,
note:
'note'
,
author:
@u_watcher
),
create
(
:note_on_personal_snippet
,
noteable:
snippet
,
note:
'note'
,
author:
@u_participant
),
create
(
:note_on_personal_snippet
,
noteable:
snippet
,
note:
'note'
,
author:
@u_mentioned
),
create
(
:note_on_personal_snippet
,
noteable:
snippet
,
note:
'note'
,
author:
@u_disabled
),
create
(
:note_on_personal_snippet
,
noteable:
snippet
,
note:
'note'
,
author:
@u_note_author
),
]
end
describe
'#new_note'
do
it
'notifies the participants'
do
notification
.
new_note
(
note
)
# it emails participants
should_email
(
@u_watcher
)
should_email
(
@u_participant
)
should_email
(
@u_watcher
)
should_email
(
@u_snippet_author
)
# TODO: make mentions working for pesronal snippets
# should_email(@u_mentioned_level)
# it does not email participants with mention notification level
should_not_email
(
@u_mentioned_level
)
# it does not email note author
should_not_email
(
@u_note_author
)
end
end
end
context
'commit note'
do
let
(
:project
)
{
create
(
:project
,
:public
)
}
let
(
:note
)
{
create
(
:note_on_commit
,
project:
project
)
}
...
...
This diff is collapsed.
Click to expand it.
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