Show participants on issues, including mentions, and notify email to all participants
This commit is contained in:
		
							parent
							
								
									a324960d92
								
							
						
					
					
						commit
						cf35d19c2e
					
				| 
						 | 
				
			
			@ -106,3 +106,7 @@ input.check_all_issues {
 | 
			
		|||
#update_status {
 | 
			
		||||
  width: 100px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.participants {
 | 
			
		||||
  margin-bottom: 10px;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,7 @@ module ProjectsHelper
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def link_to_member(project, author, opts = {})
 | 
			
		||||
    default_opts = { avatar: true }
 | 
			
		||||
    default_opts = { avatar: true, name: true, size: 16 }
 | 
			
		||||
    opts = default_opts.merge(opts)
 | 
			
		||||
 | 
			
		||||
    return "(deleted)" unless author
 | 
			
		||||
| 
						 | 
				
			
			@ -25,10 +25,10 @@ module ProjectsHelper
 | 
			
		|||
    author_html =  ""
 | 
			
		||||
 | 
			
		||||
    # Build avatar image tag
 | 
			
		||||
    author_html << image_tag(gravatar_icon(author.try(:email)), width: 16, class: "avatar avatar-inline s16") if opts[:avatar]
 | 
			
		||||
    author_html << image_tag(gravatar_icon(author.try(:email), opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}") if opts[:avatar]
 | 
			
		||||
 | 
			
		||||
    # Build name span tag
 | 
			
		||||
    author_html << content_tag(:span, sanitize(author.name), class: 'author')
 | 
			
		||||
    author_html << content_tag(:span, sanitize(author.name), class: 'author') if opts[:name]
 | 
			
		||||
 | 
			
		||||
    author_html = author_html.html_safe
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@
 | 
			
		|||
#
 | 
			
		||||
module Issuable
 | 
			
		||||
  extend ActiveSupport::Concern
 | 
			
		||||
  include Mentionable
 | 
			
		||||
 | 
			
		||||
  included do
 | 
			
		||||
    belongs_to :project
 | 
			
		||||
| 
						 | 
				
			
			@ -97,4 +98,18 @@ module Issuable
 | 
			
		|||
  def votes_count
 | 
			
		||||
    upvotes + downvotes
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Return all users participating on the discussion
 | 
			
		||||
  def participants
 | 
			
		||||
    users = []
 | 
			
		||||
    users << author
 | 
			
		||||
    users << assignee if is_assigned?
 | 
			
		||||
    mentions = []
 | 
			
		||||
    mentions << self.mentioned_users
 | 
			
		||||
    notes.each do |note|
 | 
			
		||||
      users << note.author
 | 
			
		||||
      mentions << note.mentioned_users
 | 
			
		||||
    end
 | 
			
		||||
    users.concat(mentions.reduce([], :|)).uniq
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,37 @@
 | 
			
		|||
# == Mentionable concern
 | 
			
		||||
#
 | 
			
		||||
# Contains common functionality shared between Issues and Notes
 | 
			
		||||
#
 | 
			
		||||
# Used by Issue, Note
 | 
			
		||||
#
 | 
			
		||||
module Mentionable
 | 
			
		||||
  extend ActiveSupport::Concern
 | 
			
		||||
 | 
			
		||||
  def mentioned_users
 | 
			
		||||
    users = []
 | 
			
		||||
    return users if mentionable_text.blank?
 | 
			
		||||
    has_project = self.respond_to? :project
 | 
			
		||||
    matches = mentionable_text.scan(/@[a-zA-Z][a-zA-Z0-9_\-\.]*/)
 | 
			
		||||
    matches.each do |match|
 | 
			
		||||
      identifier = match.delete "@"
 | 
			
		||||
      if has_project
 | 
			
		||||
        id = project.users_projects.joins(:user).where(users: { username: identifier }).pluck(:user_id).first
 | 
			
		||||
      else
 | 
			
		||||
        id = User.where(username: identifier).pluck(:id).first
 | 
			
		||||
      end
 | 
			
		||||
      users << User.find(id) unless id.blank?
 | 
			
		||||
    end
 | 
			
		||||
    users.uniq
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def mentionable_text
 | 
			
		||||
    if self.class == Issue
 | 
			
		||||
      description
 | 
			
		||||
    elsif self.class == Note
 | 
			
		||||
      note
 | 
			
		||||
    else
 | 
			
		||||
      nil
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -19,6 +19,8 @@ require 'carrierwave/orm/activerecord'
 | 
			
		|||
require 'file_size_validator'
 | 
			
		||||
 | 
			
		||||
class Note < ActiveRecord::Base
 | 
			
		||||
  include Mentionable
 | 
			
		||||
 | 
			
		||||
  attr_accessible :note, :noteable, :noteable_id, :noteable_type, :project_id,
 | 
			
		||||
                  :attachment, :line_code, :commit_id
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -110,9 +110,11 @@ class NotificationService
 | 
			
		|||
    else
 | 
			
		||||
      opts.merge!(noteable_id: note.noteable_id)
 | 
			
		||||
      target = note.noteable
 | 
			
		||||
      recipients = []
 | 
			
		||||
      recipients << target.assignee if target.respond_to?(:assignee)
 | 
			
		||||
      recipients << target.author if target.respond_to?(:author)
 | 
			
		||||
      if target.respond_to?(:participants)
 | 
			
		||||
        recipients = target.participants
 | 
			
		||||
      else
 | 
			
		||||
        recipients = []
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # Get users who left comment in thread
 | 
			
		||||
| 
						 | 
				
			
			@ -181,7 +183,12 @@ class NotificationService
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def new_resource_email(target, method)
 | 
			
		||||
    recipients = reject_muted_users([target.assignee], target.project)
 | 
			
		||||
    if target.respond_to?(:participants)
 | 
			
		||||
      recipients = target.participants
 | 
			
		||||
    else
 | 
			
		||||
      recipients = []
 | 
			
		||||
    end
 | 
			
		||||
    recipients = reject_muted_users(recipients, target.project)
 | 
			
		||||
    recipients = recipients.concat(project_watchers(target.project)).uniq
 | 
			
		||||
    recipients.delete(target.author)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -65,4 +65,9 @@
 | 
			
		|||
    - else
 | 
			
		||||
      = link_to 'Close Issue', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue"
 | 
			
		||||
 | 
			
		||||
.participants
 | 
			
		||||
  %cite.cgray #{@issue.participants.count} participants
 | 
			
		||||
  - @issue.participants.each do |participant|
 | 
			
		||||
    = link_to_member(@project, participant, name: false, size: 24)
 | 
			
		||||
 | 
			
		||||
.voting_notes#notes= render "notes/notes_with_form"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ describe NotificationService do
 | 
			
		|||
  describe 'Notes' do
 | 
			
		||||
    context 'issue note' do
 | 
			
		||||
      let(:issue) { create(:issue, assignee: create(:user)) }
 | 
			
		||||
      let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id) }
 | 
			
		||||
      let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@mention referenced') }
 | 
			
		||||
 | 
			
		||||
      before do
 | 
			
		||||
        build_team(note.project)
 | 
			
		||||
| 
						 | 
				
			
			@ -30,6 +30,7 @@ describe NotificationService do
 | 
			
		|||
          should_email(@u_watcher.id)
 | 
			
		||||
          should_email(note.noteable.author_id)
 | 
			
		||||
          should_email(note.noteable.assignee_id)
 | 
			
		||||
          should_email(@u_mentioned.id)
 | 
			
		||||
          should_not_email(note.author_id)
 | 
			
		||||
          should_not_email(@u_participating.id)
 | 
			
		||||
          should_not_email(@u_disabled.id)
 | 
			
		||||
| 
						 | 
				
			
			@ -235,9 +236,11 @@ describe NotificationService do
 | 
			
		|||
    @u_watcher = create(:user, notification_level: Notification::N_WATCH)
 | 
			
		||||
    @u_participating = create(:user, notification_level: Notification::N_PARTICIPATING)
 | 
			
		||||
    @u_disabled = create(:user, notification_level: Notification::N_DISABLED)
 | 
			
		||||
    @u_mentioned = create(:user, username: 'mention', notification_level: Notification::N_WATCH)
 | 
			
		||||
 | 
			
		||||
    project.team << [@u_watcher, :master]
 | 
			
		||||
    project.team << [@u_participating, :master]
 | 
			
		||||
    project.team << [@u_disabled, :master]
 | 
			
		||||
    project.team << [@u_mentioned, :master]
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue