Feature #13919 » feature_13919_v1.patch
app/helpers/application_helper.rb | ||
---|---|---|
54 | 54 |
name = h(user.name(options[:format])) |
55 | 55 |
if user.active? || (User.current.admin? && user.logged?) |
56 | 56 |
only_path = options[:only_path].nil? ? true : options[:only_path] |
57 |
link_to name, user_url(user, :only_path => only_path), :class => user.css_classes |
|
57 |
css_classes = options[:class] ? "#{user.css_classes} #{options[:class]}" : user.css_classes |
|
58 |
link_to name, user_url(user, :only_path => only_path), :class => css_classes |
|
58 | 59 |
else |
59 | 60 |
name |
60 | 61 |
end |
... | ... | |
974 | 975 |
if p = Project.visible.find_by_id(oid) |
975 | 976 |
link = link_to_project(p, {:only_path => only_path}, :class => 'project') |
976 | 977 |
end |
977 |
when 'user' |
|
978 |
u = User.visible.find_by(:id => oid, :type => 'User') |
|
979 |
link = link_to_user(u, :only_path => only_path) if u |
|
980 | 978 |
end |
981 | 979 |
elsif sep == ':' |
982 | 980 |
name = remove_double_quotes(identifier) |
... | ... | |
1035 | 1033 |
if p = Project.visible.where("identifier = :s OR LOWER(name) = :s", :s => name.downcase).first |
1036 | 1034 |
link = link_to_project(p, {:only_path => only_path}, :class => 'project') |
1037 | 1035 |
end |
1038 |
when 'user' |
|
1039 |
u = User.visible.find_by("LOWER(login) = :s AND type = 'User'", :s => name.downcase) |
|
1040 |
link = link_to_user(u, :only_path => only_path) if u |
|
1041 | 1036 |
end |
1042 |
elsif sep == "@" |
|
1043 |
name = remove_double_quotes(identifier) |
|
1044 |
u = User.visible.find_by("LOWER(login) = :s AND type = 'User'", :s => name.downcase) |
|
1045 |
link = link_to_user(u, :only_path => only_path) if u |
|
1037 |
end |
|
1038 |
if link.nil? && $~ |
|
1039 |
user = User.mentioned_user($~.named_captures.symbolize_keys) |
|
1040 |
if user |
|
1041 |
css_classes = (user.notify_mentioned_user?(obj) ? 'notified' : nil) |
|
1042 |
link = link_to_user(user, :only_path => only_path, :class => css_classes) |
|
1043 |
end |
|
1046 | 1044 |
end |
1047 | 1045 |
end |
1048 | 1046 |
(leading + (link || "#{project_prefix}#{prefix}#{repo_prefix}#{sep}#{identifier}#{comment_suffix}")) |
app/models/document.rb | ||
---|---|---|
61 | 61 |
end |
62 | 62 | |
63 | 63 |
def notified_users |
64 |
project.notified_users.reject {|user| !visible?(user)}
|
|
64 |
project.notified_users.select {|user| user.allowed_to_view_notify_target?(self) }
|
|
65 | 65 |
end |
66 | 66 | |
67 | 67 |
private |
app/models/issue.rb | ||
---|---|---|
1038 | 1038 |
notified += project.notified_users |
1039 | 1039 |
notified.uniq! |
1040 | 1040 |
# Remove users that can not view the issue |
1041 |
notified.reject! {|user| !visible?(user)} |
|
1042 |
notified |
|
1041 |
notified.select {|user| user.allowed_to_view_notify_target?(self)} |
|
1043 | 1042 |
end |
1044 | 1043 | |
1045 | 1044 |
# Returns the email addresses that should be notified |
app/models/journal.rb | ||
---|---|---|
141 | 141 | |
142 | 142 |
def notified_users |
143 | 143 |
notified = journalized.notified_users |
144 |
if private_notes? |
|
145 |
notified = notified.select {|user| user.allowed_to?(:view_private_notes, journalized.project)} |
|
146 |
end |
|
147 |
notified |
|
144 |
notified.select{ |u| u.allowed_to_view_notify_target?(self) } |
|
148 | 145 |
end |
149 | 146 | |
150 | 147 |
def recipients |
app/models/mailer.rb | ||
---|---|---|
90 | 90 |
# Mailer.deliver_issue_add(issue) |
91 | 91 |
def self.deliver_issue_add(issue) |
92 | 92 |
users = issue.notified_users | issue.notified_watchers |
93 |
users |= mentioned_users(issue.description, issue) |
|
93 | 94 |
users.each do |user| |
94 | 95 |
issue_add(user, issue).deliver_later |
95 | 96 |
end |
... | ... | |
124 | 125 |
# Mailer.deliver_issue_edit(journal) |
125 | 126 |
def self.deliver_issue_edit(journal) |
126 | 127 |
users = journal.notified_users | journal.notified_watchers |
128 |
users |= mentioned_users(journal.notes, journal) |
|
127 | 129 |
users.select! do |user| |
128 | 130 |
journal.notes? || journal.visible_details(user).any? |
129 | 131 |
end |
... | ... | |
149 | 151 |
# Mailer.deliver_document_added(document, author) |
150 | 152 |
def self.deliver_document_added(document, author) |
151 | 153 |
users = document.notified_users |
154 |
users |= mentioned_users(document.description, document) |
|
152 | 155 |
users.each do |user| |
153 | 156 |
document_added(user, document, author).deliver_later |
154 | 157 |
end |
... | ... | |
217 | 220 |
# Mailer.deliver_news_added(news) |
218 | 221 |
def self.deliver_news_added(news) |
219 | 222 |
users = news.notified_users | news.notified_watchers_for_added_news |
223 |
users |= mentioned_users(news.description, news) |
|
220 | 224 |
users.each do |user| |
221 | 225 |
news_added(user, news).deliver_later |
222 | 226 |
end |
... | ... | |
244 | 248 |
def self.deliver_news_comment_added(comment) |
245 | 249 |
news = comment.commented |
246 | 250 |
users = news.notified_users | news.notified_watchers |
251 |
users |= mentioned_users(comment.content, news) |
|
247 | 252 |
users.each do |user| |
248 | 253 |
news_comment_added(user, comment).deliver_later |
249 | 254 |
end |
... | ... | |
271 | 276 |
users = message.notified_users |
272 | 277 |
users |= message.root.notified_watchers |
273 | 278 |
users |= message.board.notified_watchers |
279 |
users |= mentioned_users(message.content, message) |
|
274 | 280 | |
275 | 281 |
users.each do |user| |
276 | 282 |
message_posted(user, message).deliver_later |
... | ... | |
329 | 335 |
users = wiki_content.notified_users |
330 | 336 |
users |= wiki_content.page.notified_watchers |
331 | 337 |
users |= wiki_content.page.wiki.notified_watchers |
338 |
users |= mentioned_users(wiki_content.text, wiki_content) |
|
332 | 339 | |
333 | 340 |
users.each do |user| |
334 | 341 |
wiki_content_updated(user, wiki_content).deliver_later |
... | ... | |
758 | 765 |
@references_objects ||= [] |
759 | 766 |
@references_objects << object |
760 | 767 |
end |
768 | ||
769 |
def self.mentioned_users(text, obj) |
|
770 |
users = [] |
|
771 |
return users if text.blank? |
|
772 |
text.scan(ApplicationHelper::LINKS_RE) do |_| |
|
773 |
target = User.mentioned_user($~.named_captures.symbolize_keys) |
|
774 |
next if target.blank? || users.include?(target) |
|
775 |
users << target if target.notify_mentioned_user?(obj) |
|
776 |
end |
|
777 |
users |
|
778 |
end |
|
761 | 779 |
end |
762 | 780 |
app/models/message.rb | ||
---|---|---|
103 | 103 |
end |
104 | 104 | |
105 | 105 |
def notified_users |
106 |
project.notified_users.reject {|user| !visible?(user)}
|
|
106 |
project.notified_users.select {|user| user.allowed_to_view_notify_target?(self) }
|
|
107 | 107 |
end |
108 | 108 | |
109 | 109 |
private |
app/models/news.rb | ||
---|---|---|
54 | 54 |
end |
55 | 55 | |
56 | 56 |
def notified_users |
57 |
project.users.select {|user| user.notify_about?(self) && user.allowed_to?(:view_news, project)}
|
|
57 |
project.users.select {|user| user.notify_about?(self) && user.allowed_to_view_notify_target?(self)}
|
|
58 | 58 |
end |
59 | 59 | |
60 | 60 |
def recipients |
app/models/user.rb | ||
---|---|---|
787 | 787 |
end |
788 | 788 |
end |
789 | 789 | |
790 |
# Return true if the user is allowed to view the notify target. |
|
791 |
def allowed_to_view_notify_target?(object) |
|
792 |
case object |
|
793 |
when Journal |
|
794 |
self.allowed_to_view_notify_target?(object.journalized) && |
|
795 |
(!object.private_notes? || self.allowed_to?(:view_private_notes, object.journalized.project)) |
|
796 |
else |
|
797 |
object.try(:visible?, self) |
|
798 |
end |
|
799 |
end |
|
800 | ||
790 | 801 |
def self.current=(user) |
791 | 802 |
RequestStore.store[:current_user] = user |
792 | 803 |
end |
... | ... | |
795 | 806 |
RequestStore.store[:current_user] ||= User.anonymous |
796 | 807 |
end |
797 | 808 | |
809 |
# Return the mentioned user to based on the match data |
|
810 |
# of ApplicationHelper::LINKS_RE. |
|
811 |
# user:jsmith -> Link to user with login jsmith |
|
812 |
# @jsmith -> Link to user with login jsmith |
|
813 |
# user#2 -> Link to user with id 2 |
|
814 |
def self.mentioned_user(match_data) |
|
815 |
return nil if match_data[:esc] |
|
816 |
sep = match_data[:sep1] || match_data[:sep2] || match_data[:sep3] || match_data[:sep4] |
|
817 |
identifier = match_data[:identifier1] || match_data[:identifier2] || match_data[:identifier3] |
|
818 |
prefix = match_data[:prefix] |
|
819 |
if (sep == '#' || sep == '##') && prefix == 'user' |
|
820 |
User.visible.find_by(:id => identifier.to_i, :type => 'User') |
|
821 |
elsif sep == '@' || (sep == ':' && prefix == 'user') |
|
822 |
name = identifier.gsub(%r{^"(.*)"$}, "\\1") |
|
823 |
User.find_by_login(CGI.unescapeHTML(name).downcase) |
|
824 |
end |
|
825 |
end |
|
826 | ||
827 |
# Return true if notify the mentioned user. |
|
828 |
def notify_mentioned_user?(object) |
|
829 |
self.active? && |
|
830 |
self.mail.present? && |
|
831 |
self.mail_notification.present? && self.mail_notification != 'none' && |
|
832 |
self.allowed_to_view_notify_target?(object) |
|
833 |
end |
|
834 | ||
798 | 835 |
# Returns the anonymous user. If the anonymous user does not exist, it is created. There can be only |
799 | 836 |
# one anonymous user per database. |
800 | 837 |
def self.anonymous |
app/models/wiki_content.rb | ||
---|---|---|
51 | 51 |
end |
52 | 52 | |
53 | 53 |
def notified_users |
54 |
project.notified_users.reject {|user| !visible?(user)}
|
|
54 |
project.notified_users.select {|user| user.allowed_to_view_notify_target?(self) }
|
|
55 | 55 |
end |
56 | 56 | |
57 | 57 |
# Returns the mail addresses of users that should be notified |
test/unit/mailer_test.rb | ||
---|---|---|
365 | 365 |
assert_include 'dlopper@somenet.foo', recipients |
366 | 366 |
end |
367 | 367 | |
368 |
def test_issue_added_should_notify_mentioned_users |
|
369 |
# issue with non-public project |
|
370 |
issue = Issue.find(4) |
|
371 |
# Developer |
|
372 |
user = User.find(8) |
|
373 | ||
374 |
# notify mentioned user |
|
375 |
["user##{user.id}", "@#{user.login}", "user:#{user.login}"].each do |description| |
|
376 |
issue.update(description: description) |
|
377 |
ActionMailer::Base.deliveries.clear |
|
378 |
Mailer.deliver_issue_add(issue) |
|
379 |
assert_include user.mail, recipients |
|
380 |
end |
|
381 | ||
382 |
# Do not notify mentioned users without view_issues permission. |
|
383 |
Role.find(2).remove_permission!(:view_issues) |
|
384 |
issue.update(description: "user##{user.id}") |
|
385 |
ActionMailer::Base.deliveries.clear |
|
386 |
Mailer.deliver_issue_add(issue) |
|
387 |
assert_not_include user.mail, recipients |
|
388 |
end |
|
389 | ||
368 | 390 |
def test_issue_add_should_send_mail_to_all_user_email_address |
369 | 391 |
EmailAddress.create!(:user_id => 3, :address => 'otheremail@somenet.foo') |
370 | 392 |
issue = Issue.find(1) |