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) |