Project

General

Profile

Feature #13919 » feature_13919_v2.patch

Mizuki ISHIKAWA, 2019-03-26 07:15

View differences:

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
......
990 991
              if p = Project.visible.find_by_id(oid)
991 992
                link = link_to_project(p, {:only_path => only_path}, :class => 'project')
992 993
              end
993
            when 'user'
994
              u = User.visible.find_by(:id => oid, :type => 'User')
995
              link = link_to_user(u, :only_path => only_path) if u
996 994
            end
997 995
          elsif sep == ':'
998 996
            name = remove_double_quotes(identifier)
......
1051 1049
              if p = Project.visible.where("identifier = :s OR LOWER(name) = :s", :s => name.downcase).first
1052 1050
                link = link_to_project(p, {:only_path => only_path}, :class => 'project')
1053 1051
              end
1054
            when 'user'
1055
              u = User.visible.find_by("LOWER(login) = :s AND type = 'User'", :s => name.downcase)
1056
              link = link_to_user(u, :only_path => only_path) if u
1057 1052
            end
1058
          elsif sep == "@"
1059
            name = remove_double_quotes(identifier)
1060
            u = User.visible.find_by("LOWER(login) = :s AND type = 'User'", :s => name.downcase)
1061
            link = link_to_user(u, :only_path => only_path) if u
1053
          end
1054
          if link.nil? && $~
1055
            user = User.mentioned_user($~.named_captures.symbolize_keys)
1056
            if user
1057
              css_classes = (user.notify_mentioned_user?(obj) ? 'notified' : nil)
1058
              link = link_to_user(user, :only_path => only_path, :class => css_classes)
1059
            end
1062 1060
          end
1063 1061
        end
1064 1062
        (leading + (link || "#{project_prefix}#{prefix}#{repo_prefix}#{sep}#{identifier}#{comment_suffix}"))
app/models/document.rb
63 63
  end
64 64

  
65 65
  def notified_users
66
    project.notified_users.reject {|user| !visible?(user)}
66
    project.notified_users.select {|user| user.allowed_to_view_notify_target?(self) }
67 67
  end
68 68

  
69 69
  private
app/models/issue.rb
1040 1040
    notified += project.notified_users
1041 1041
    notified.uniq!
1042 1042
    # Remove users that can not view the issue
1043
    notified.reject! {|user| !visible?(user)}
1044
    notified
1043
    notified.select {|user| user.allowed_to_view_notify_target?(self)}
1045 1044
  end
1046 1045

  
1047 1046
  # Returns the email addresses that should be notified
app/models/journal.rb
143 143

  
144 144
  def notified_users
145 145
    notified = journalized.notified_users
146
    if private_notes?
147
      notified = notified.select {|user| user.allowed_to?(:view_private_notes, journalized.project)}
148
    end
149
    notified
146
    notified.select{ |u| u.allowed_to_view_notify_target?(self) }
150 147
  end
151 148

  
152 149
  def recipients
app/models/mailer.rb
92 92
  #   Mailer.deliver_issue_add(issue)
93 93
  def self.deliver_issue_add(issue)
94 94
    users = issue.notified_users | issue.notified_watchers
95
    users |= mentioned_users(issue.description, issue)
95 96
    users.each do |user|
96 97
      issue_add(user, issue).deliver_later
97 98
    end
......
126 127
  #   Mailer.deliver_issue_edit(journal)
127 128
  def self.deliver_issue_edit(journal)
128 129
    users  = journal.notified_users | journal.notified_watchers
130
    users |= mentioned_users(journal.notes, journal)
129 131
    users.select! do |user|
130 132
      journal.notes? || journal.visible_details(user).any?
131 133
    end
......
151 153
  #   Mailer.deliver_document_added(document, author)
152 154
  def self.deliver_document_added(document, author)
153 155
    users = document.notified_users
156
    users |= mentioned_users(document.description, document)
154 157
    users.each do |user|
155 158
      document_added(user, document, author).deliver_later
156 159
    end
......
219 222
  #   Mailer.deliver_news_added(news)
220 223
  def self.deliver_news_added(news)
221 224
    users = news.notified_users | news.notified_watchers_for_added_news
225
    users |= mentioned_users(news.description, news)
222 226
    users.each do |user|
223 227
      news_added(user, news).deliver_later
224 228
    end
......
246 250
  def self.deliver_news_comment_added(comment)
247 251
    news = comment.commented
248 252
    users = news.notified_users | news.notified_watchers
253
    users |= mentioned_users(comment.content, news)
249 254
    users.each do |user|
250 255
      news_comment_added(user, comment).deliver_later
251 256
    end
......
273 278
    users  = message.notified_users
274 279
    users |= message.root.notified_watchers
275 280
    users |= message.board.notified_watchers
281
    users |= mentioned_users(message.content, message)
276 282

  
277 283
    users.each do |user|
278 284
      message_posted(user, message).deliver_later
......
300 306
  #   Mailer.deliver_wiki_content_added(wiki_content)
301 307
  def self.deliver_wiki_content_added(wiki_content)
302 308
    users = wiki_content.notified_users | wiki_content.page.wiki.notified_watchers
309
    users |= mentioned_users(wiki_content.text, wiki_content)
303 310
    users.each do |user|
304 311
      wiki_content_added(user, wiki_content).deliver_later
305 312
    end
......
331 338
    users  = wiki_content.notified_users
332 339
    users |= wiki_content.page.notified_watchers
333 340
    users |= wiki_content.page.wiki.notified_watchers
341
    users |= mentioned_users(wiki_content.text, wiki_content)
334 342

  
335 343
    users.each do |user|
336 344
      wiki_content_updated(user, wiki_content).deliver_later
......
760 768
    @references_objects ||= []
761 769
    @references_objects << object
762 770
  end
771

  
772
  def self.mentioned_users(text, obj)
773
    users = []
774
    return users if text.blank?
775
    text.scan(ApplicationHelper::LINKS_RE) do |_|
776
      target = User.mentioned_user($~.named_captures.symbolize_keys)
777
      next if target.blank? || users.include?(target)
778
      users << target if target.notify_mentioned_user?(obj)
779
    end
780
    users
781
  end
763 782
end
764 783

  
app/models/message.rb
105 105
  end
106 106

  
107 107
  def notified_users
108
    project.notified_users.reject {|user| !visible?(user)}
108
    project.notified_users.select {|user| user.allowed_to_view_notify_target?(self) }
109 109
  end
110 110

  
111 111
  private
app/models/news.rb
56 56
  end
57 57

  
58 58
  def notified_users
59
    project.users.select {|user| user.notify_about?(self) && user.allowed_to?(:view_news, project)}
59
    project.users.select {|user| user.notify_about?(self) && user.allowed_to_view_notify_target?(self)}
60 60
  end
61 61

  
62 62
  def recipients
app/models/user.rb
797 797
    RequestStore.store[:current_user] ||= User.anonymous
798 798
  end
799 799

  
800
  # Return the mentioned user to based on the match data
801
  #  of ApplicationHelper::LINKS_RE.
802
  #     user:jsmith -> Link to user with login jsmith
803
  #     @jsmith -> Link to user with login jsmith
804
  #     user#2 -> Link to user with id 2
805
  def self.mentioned_user(match_data)
806
    return nil if match_data[:esc]
807
    sep = match_data[:sep1] || match_data[:sep2] || match_data[:sep3] || match_data[:sep4]
808
    identifier = match_data[:identifier1] || match_data[:identifier2] || match_data[:identifier3]
809
    prefix = match_data[:prefix]
810
    if (sep == '#' || sep == '##') && prefix == 'user'
811
      User.visible.find_by(:id => identifier.to_i, :type => 'User')
812
    elsif sep == '@' || (sep == ':' && prefix == 'user')
813
      name = identifier.gsub(%r{^"(.*)"$}, "\\1")
814
      User.find_by_login(CGI.unescapeHTML(name).downcase)
815
    end
816
  end
817

  
818
  # Return true if notify the mentioned user.
819
  def notify_mentioned_user?(object)
820
    self.active? &&
821
      self.mail.present? &&
822
      self.mail_notification.present? && self.mail_notification != 'none' &&
823
      self.allowed_to_view_notify_target?(object)
824
  end
825

  
826
  # Return true if the user is allowed to view the notify target.
827
  def allowed_to_view_notify_target?(object)
828
    case object
829
    when Journal
830
      self.allowed_to_view_notify_target?(object.journalized) &&
831
        (!object.private_notes? || self.allowed_to?(:view_private_notes, object.journalized.project))
832
    when Comment
833
      self.allowed_to_view_notify_target?(object.commented)
834
    when nil
835
      false
836
    else
837
      object.visible?(self)
838
    end
839
  end
840

  
800 841
  # Returns the anonymous user.  If the anonymous user does not exist, it is created.  There can be only
801 842
  # one anonymous user per database.
802 843
  def self.anonymous
app/models/wiki_content.rb
53 53
  end
54 54

  
55 55
  def notified_users
56
    project.notified_users.reject {|user| !visible?(user)}
56
    project.notified_users.select {|user| user.allowed_to_view_notify_target?(self) }
57 57
  end
58 58

  
59 59
  # Returns the mail addresses of users that should be notified
test/helpers/application_helper_test.rb
1562 1562
    assert_equal ::I18n.t(:label_user_anonymous), t
1563 1563
  end
1564 1564

  
1565
  def test_link_to_user_with_class_name_should_include_class
1566
    user = User.find(2)
1567
    result = link_to("John Smith", "/users/2", :class => "user active test")
1568
    assert_equal result, link_to_user(user, :class => 'test')
1569
  end
1570

  
1565 1571
  def test_link_to_attachment
1566 1572
    a = Attachment.find(3)
1567 1573
    assert_equal '<a href="/attachments/3">logo.gif</a>',
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
    # Non-public project issue
370
    issue = Issue.find(4)
371
    # Developer
372
    user = User.find(8)
373
    assert issue.visible?(user)
374

  
375
    # Notify mentioned users.
376
    ["user##{user.id}", "@#{user.login}", "user:#{user.login}"].each do |description|
377
      issue.update(:description => description)
378
      ActionMailer::Base.deliveries.clear
379
      Mailer.deliver_issue_add(issue)
380
      assert_include user.mail, recipients
381
    end
382

  
383
    # Do not notify unauthorized mentioned users.
384
    Role.find(2).remove_permission!(:view_issues)
385
    assert_not issue.visible?(user.reload)
386
    issue.update(:description => "user##{user.id}")
387
    ActionMailer::Base.deliveries.clear
388
    Mailer.deliver_issue_add(issue)
389
    assert_not_include user.mail, recipients
390
  end
391

  
368 392
  def test_issue_add_should_send_mail_to_all_user_email_address
369 393
    EmailAddress.create!(:user_id => 3, :address => 'otheremail@somenet.foo')
370 394
    issue = Issue.find(1)
......
534 558
    end
535 559
  end
536 560

  
561
  def test_issue_edit_should_notify_mentioned_users
562
    # Non-public project journal
563
    issue = Issue.find(4)
564
    journal = Journal.generate!(:notes => '', :details => [JournalDetail.new], :journalized => issue)
565
    # Developer
566
    user = User.find(8)
567

  
568
    # Notify mentioned users.
569
    ["user##{user.id}", "@#{user.login}", "user:#{user.login}"].each do |note|
570
      journal.update(:notes => note)
571
      Mailer.deliver_issue_edit(journal)
572
      assert_include user.mail, recipients
573
      ActionMailer::Base.deliveries.clear
574
    end
575

  
576
    # Do not notify mentioned users without view_private_notes permission and journal is private.
577
    Role.find(2).remove_permission!(:view_private_notes)
578
    journal.update(:notes => "user##{user.id}", :private_notes => true)
579
    Mailer.deliver_issue_edit(journal)
580
    assert_not_include user.mail, recipients
581
    ActionMailer::Base.deliveries.clear
582
  end
583

  
537 584
  def test_version_file_added
538 585
    attachements = [ Attachment.find_by_container_type('Version') ]
539 586
    assert Mailer.deliver_attachments_added(attachements)
......
565 612
    assert_not_include user2.mail, recipients
566 613
  end
567 614

  
615
  def test_news_added_should_notify_mentioned_users
616
    project = Project.find(1)
617
    news = project.news.first
618
    user = User.find(8) # non member
619
    assert news.visible?(user)
620

  
621
    # Notify mentioned users.
622
    ["user##{user.id}", "@#{user.login}", "user:#{user.login}"].each do |description|
623
      news.update(:description => description)
624
      Mailer.deliver_news_added(news)
625
      assert_include user.mail, recipients
626
      ActionMailer::Base.deliveries.clear
627
    end
628

  
629
    # Do not notify unauthorized mentioned users.
630
    Role.non_member.remove_permission!(:view_news)
631
    assert_not news.visible?(user.reload)
632
    news.update(:description => "user##{user.id}")
633
    Mailer.deliver_news_added(news)
634
    assert_not_include user.mail, recipients
635
    ActionMailer::Base.deliveries.clear
636
  end
637

  
638
  def test_news_comment_added_should_notify_mentioned_users
639
    project = Project.find(1) # public project
640
    news = project.news.first
641
    comment = news.comments.first
642
    user = User.find(8) # non member
643
    assert news.visible?(user)
644

  
645
    # Notify mentioned users.
646
    ["user##{user.id}", "@#{user.login}", "user:#{user.login}"].each do |text|
647
      comment.update(:content => text)
648
      Mailer.deliver_news_comment_added(comment)
649
      assert_include user.mail, recipients
650
      ActionMailer::Base.deliveries.clear
651
    end
652

  
653
    # Do not notify unauthorized mentioned users.
654
    Role.non_member.remove_permission!(:view_news)
655
    assert_not news.visible?(user.reload)
656
    comment.update(:content => "user##{user.id}")
657
    Mailer.deliver_news_comment_added(comment)
658
    assert_not_include user.mail, recipients
659
    ActionMailer::Base.deliveries.clear
660
  end
661

  
568 662
  def test_wiki_content_added
569 663
    content = WikiContent.find(1)
570 664
    assert_difference 'ActionMailer::Base.deliveries.size', 2 do
......
577 671
    end
578 672
  end
579 673

  
674
  def test_wiki_content_added_should_notify_mentioned_users
675
    # Non-public project wiki_content
676
    project = Project.find(2)
677
    wiki_content = project.wiki.pages.first.content
678
    user = User.find(8)
679
    assert wiki_content.visible?(user)
680

  
681
    # Notify mentioned users.
682
    ["user##{user.id}", "@#{user.login}", "user:#{user.login}"].each do |text|
683
      wiki_content.update(:text => text)
684
      Mailer.deliver_wiki_content_added(wiki_content)
685
      assert_include user.mail, recipients
686
      ActionMailer::Base.deliveries.clear
687
    end
688

  
689
    # Do not notify unauthorized mentioned users.
690
    Role.find(2).remove_permission!(:view_wiki_pages)
691
    assert_not wiki_content.visible?(user.reload)
692
    wiki_content.update(:text => "user##{user.id}")
693
    Mailer.deliver_wiki_content_added(wiki_content)
694
    assert_not_include user.mail, recipients
695
    ActionMailer::Base.deliveries.clear
696
  end
697

  
580 698
  def test_wiki_content_updated
581 699
    content = WikiContent.find(1)
582 700
    assert Mailer.deliver_wiki_content_updated(content)
......
946 1064
      Mailer.email_addresses(User.find(2)).sort
947 1065
  end
948 1066

  
1067
  def test_document_added_should_notify_mentioned_users
1068
    # Non-public project document
1069
    project = Project.find(2)
1070
    project.enable_module!(:documents)
1071
    document = Document.generate!(:project => project)
1072
    # Developer
1073
    user = User.find(8)
1074
    assert document.visible?(user)
1075

  
1076
    # Notify mentioned users.
1077
    ["user##{user.id}", "@#{user.login}", "user:#{user.login}"].each do |description|
1078
      document.update(:description => description)
1079
      Mailer.deliver_document_added(document, User.first)
1080
      assert_include user.mail, recipients
1081
      ActionMailer::Base.deliveries.clear
1082
    end
1083

  
1084
    # Do not notify unauthorized mentioned users.
1085
    Role.find(2).remove_permission!(:view_documents)
1086
    assert_not document.visible?(user.reload)
1087
    document.update(:description => "user##{user.id}")
1088
    Mailer.deliver_document_added(document, User.first)
1089
    assert_not_include user.mail, recipients
1090
    ActionMailer::Base.deliveries.clear
1091
  end
1092

  
1093
  def test_message_posted_should_notify_mentioned_users
1094
    # Non-public project message
1095
    project = Project.find(2)
1096
    message = project.boards.first.messages.first
1097
    user = User.find(8)
1098
    assert message.visible?(user)
1099

  
1100
    # Notify mentioned users.
1101
    ["user##{user.id}", "@#{user.login}", "user:#{user.login}"].each do |text|
1102
      message.update(:content => text)
1103
      Mailer.deliver_message_posted(message)
1104
      assert_include user.mail, recipients
1105
      ActionMailer::Base.deliveries.clear
1106
    end
1107

  
1108
    # Do not notify unauthorized mentioned users.
1109
    Role.find(2).remove_permission!(:view_messages)
1110
    assert_not message.visible?(user.reload)
1111
    message.update(:content => "user##{user.id}")
1112
    Mailer.deliver_message_posted(message)
1113
    assert_not_include user.mail, recipients
1114
    ActionMailer::Base.deliveries.clear
1115
  end
1116

  
949 1117
  private
950 1118

  
951 1119
  # Returns an array of email addresses to which emails were sent
test/unit/user_test.rb
461 461
    assert_nil changeset.reload.user_id
462 462
  end
463 463

  
464
  def test_mentioned_user
465
    # user#id
466
    match_data = { :esc => nil,  :prefix => 'user', :sep1 => '#', :identifier1 => '1' }
467
    assert_equal User.mentioned_user(match_data), User.find(1)
468

  
469
    # user:login
470
    match_data = { :esc => nil,  :prefix => 'user', :sep3 => ':', :identifier2 => 'admin' }
471
    assert_equal User.mentioned_user(match_data), User.find_by_login('admin')
472

  
473
    # @login
474
    match_data = { :esc => nil,  :sep4 => '@', :identifier3 => 'admin' }
475
    assert_equal User.mentioned_user(match_data), User.find_by_login('admin')
476
  end
477

  
478
  def test_notify_mentioned_user?
479
    issue = Issue.first
480
    user = User.find(2)
481
    assert user.notify_mentioned_user?(issue)
482

  
483
    user.roles_for_project(issue.project).first.remove_permission!(:view_issues)
484
    assert_not user.reload.notify_mentioned_user?(issue)
485
  end
486

  
487
  def test_allowed_to_view_notify_target
488
    issue = Issue.first
489
    user = User.find(2)
490

  
491
    assert issue.visible?(user)
492
    assert user.allowed_to_view_notify_target?(issue)
493

  
494
    user.roles_for_project(issue.project).first.remove_permission!(:view_issues)
495
    user.reload
496
    assert_not issue.visible?(user)
497
    assert_not user.allowed_to_view_notify_target?(issue)
498
  end
499

  
500
  def test_allowed_to_view_notify_target_with_journal
501
    journal = Journal.first
502
    user = User.find(3)
503

  
504
    assert journal.issue.visible?(user)
505
    assert user.allowed_to_view_notify_target?(journal)
506

  
507
    journal.update(:private_notes => true)
508
    Role.find(2).remove_permission!(:view_private_note)
509
    assert_not user.reload.allowed_to_view_notify_target?(journal)
510

  
511
    journal.update(:private_notes => false)
512
    Role.find(2).remove_permission!(:view_issues)
513
    assert_not user.reload.allowed_to_view_notify_target?(journal)
514
  end
515

  
516
  def test_allowed_to_view_notify_target_with_comment
517
    comment = Comment.first
518
    user = User.find(3)
519

  
520
    assert comment.commented.visible?(user)
521
    assert user.allowed_to_view_notify_target?(comment)
522

  
523
    Role.find(2).remove_permission!(:view_news)
524
    assert_not user.reload.allowed_to_view_notify_target?(comment)
525
  end
526

  
464 527
  def test_anonymous_user_should_not_be_destroyable
465 528
    assert_no_difference 'User.count' do
466 529
      assert_equal false, User.anonymous.destroy
(2-2/12)