summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorMarius Balteanu <marius.balteanu@zitec.com>2022-02-23 21:16:18 +0000
committerMarius Balteanu <marius.balteanu@zitec.com>2022-02-23 21:16:18 +0000
commitba74ba1c702e7a122328094341e659c2baf9fd3d (patch)
treeb6d43d8beaf9538ff54bebd16768f29f7ef782a6 /app
parent3a6c43deeec8f9f444008e43f53e58a6614716ed (diff)
downloadredmine-ba74ba1c702e7a122328094341e659c2baf9fd3d.tar.gz
redmine-ba74ba1c702e7a122328094341e659c2baf9fd3d.zip
Allow users to be mentioned using @ in issues and wiki pages (#13919):
* the user must have add watchers permission on that object in order to mention other users * mentioned user will receive a notification email * only visible users who can view the object can be mentioned git-svn-id: http://svn.redmine.org/redmine/trunk@21435 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'app')
-rw-r--r--app/controllers/watchers_controller.rb43
-rw-r--r--app/helpers/application_helper.rb24
-rw-r--r--app/models/issue.rb2
-rw-r--r--app/models/journal.rb18
-rw-r--r--app/models/mailer.rb7
-rw-r--r--app/models/wiki_content.rb3
-rw-r--r--app/views/issues/_form.html.erb5
-rw-r--r--app/views/wiki/edit.html.erb4
8 files changed, 90 insertions, 16 deletions
diff --git a/app/controllers/watchers_controller.rb b/app/controllers/watchers_controller.rb
index 9170acb34..dd537d6f6 100644
--- a/app/controllers/watchers_controller.rb
+++ b/app/controllers/watchers_controller.rb
@@ -28,7 +28,7 @@ class WatchersController < ApplicationController
set_watcher(@watchables, User.current, false)
end
- before_action :find_project, :authorize, :only => [:new, :create, :append, :destroy, :autocomplete_for_user]
+ before_action :find_project, :authorize, :only => [:new, :create, :append, :destroy, :autocomplete_for_user, :autocomplete_for_mention]
accept_api_auth :create, :destroy
def new
@@ -93,6 +93,11 @@ class WatchersController < ApplicationController
render :layout => false
end
+ def autocomplete_for_mention
+ users = users_for_mention
+ render :json => format_users_json(users)
+ end
+
private
def find_project
@@ -155,6 +160,42 @@ class WatchersController < ApplicationController
users
end
+ def users_for_mention
+ users = []
+ q = params[:q].to_s.strip
+
+ scope = nil
+ if params[:q].blank? && @project.present?
+ scope = @project.principals.assignable_watchers
+ else
+ scope = Principal.assignable_watchers.limit(10)
+ end
+ # Exclude Group principal for now
+ scope = scope.where(:type => ['User'])
+
+ users = scope.sorted.like(params[:q]).to_a
+
+ if @watchables && @watchables.size == 1
+ object = @watchables.first
+ if object.respond_to?(:visible?)
+ users.reject! {|user| user.is_a?(User) && !object.visible?(user)}
+ end
+ end
+
+ users
+ end
+
+ def format_users_json(users)
+ users.map do |user|
+ {
+ 'firstname' => user.firstname,
+ 'lastname' => user.lastname,
+ 'name' => user.name,
+ 'login' => user.login
+ }
+ end
+ end
+
def find_objects_from_params
klass =
begin
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 0e3f56c2c..33798501a 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -1819,19 +1819,20 @@ module ApplicationHelper
end
end
- def autocomplete_data_sources(project)
- {
- issues: auto_complete_issues_path(:project_id => project, :q => ''),
- wiki_pages: auto_complete_wiki_pages_path(:project_id => project, :q => '')
- }
- end
-
def heads_for_auto_complete(project)
data_sources = autocomplete_data_sources(project)
javascript_tag(
"rm = window.rm || {};" \
"rm.AutoComplete = rm.AutoComplete || {};" \
- "rm.AutoComplete.dataSources = '#{data_sources.to_json}';"
+ "rm.AutoComplete.dataSources = JSON.parse('#{data_sources.to_json}');"
+ )
+ end
+
+ def update_data_sources_for_auto_complete(data_sources)
+ javascript_tag(
+ "const currentDataSources = rm.AutoComplete.dataSources;" \
+ "const newDataSources = JSON.parse('#{data_sources.to_json}'); " \
+ "rm.AutoComplete.dataSources = Object.assign(currentDataSources, newDataSources);"
)
end
@@ -1866,4 +1867,11 @@ module ApplicationHelper
name = identifier.gsub(%r{^"(.*)"$}, "\\1")
return CGI.unescapeHTML(name)
end
+
+ def autocomplete_data_sources(project)
+ {
+ issues: auto_complete_issues_path(project_id: project, q: ''),
+ wiki_pages: auto_complete_wiki_pages_path(project_id: project, q: ''),
+ }
+ end
end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 02aaff33b..ab9f794db 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -54,6 +54,8 @@ class Issue < ActiveRecord::Base
acts_as_activity_provider :scope => proc {preload(:project, :author, :tracker, :status)},
:author_key => :author_id
+ acts_as_mentionable :attributes => ['description']
+
DONE_RATIO_OPTIONS = %w(issue_field issue_status)
attr_reader :transition_warning
diff --git a/app/models/journal.rb b/app/models/journal.rb
index 333441204..3d1feb906 100644
--- a/app/models/journal.rb
+++ b/app/models/journal.rb
@@ -58,6 +58,7 @@ class Journal < ActiveRecord::Base
" (#{JournalDetail.table_name}.prop_key = 'status_id' OR #{Journal.table_name}.notes <> '')").distinct
end
)
+ acts_as_mentionable :attributes => ['notes']
before_create :split_private_notes
after_create_commit :send_notification
@@ -172,10 +173,12 @@ class Journal < ActiveRecord::Base
def notified_watchers
notified = journalized.notified_watchers
- if private_notes?
- notified = notified.select {|user| user.allowed_to?(:view_private_notes, journalized.project)}
- end
- notified
+ select_journal_visible_user(notified)
+ end
+
+ def notified_mentions
+ notified = super
+ select_journal_visible_user(notified)
end
def watcher_recipients
@@ -337,4 +340,11 @@ class Journal < ActiveRecord::Base
Mailer.deliver_issue_edit(self)
end
end
+
+ def select_journal_visible_user(notified)
+ if private_notes?
+ notified = notified.select {|user| user.allowed_to?(:view_private_notes, journalized.project)}
+ end
+ notified
+ end
end
diff --git a/app/models/mailer.rb b/app/models/mailer.rb
index cdf7aedba..3007350b7 100644
--- a/app/models/mailer.rb
+++ b/app/models/mailer.rb
@@ -94,7 +94,7 @@ class Mailer < ActionMailer::Base
# Example:
# Mailer.deliver_issue_add(issue)
def self.deliver_issue_add(issue)
- users = issue.notified_users | issue.notified_watchers
+ users = issue.notified_users | issue.notified_watchers | issue.notified_mentions
users.each do |user|
issue_add(user, issue).deliver_later
end
@@ -129,7 +129,7 @@ class Mailer < ActionMailer::Base
# Example:
# Mailer.deliver_issue_edit(journal)
def self.deliver_issue_edit(journal)
- users = journal.notified_users | journal.notified_watchers
+ users = journal.notified_users | journal.notified_watchers | journal.notified_mentions | journal.journalized.notified_mentions
users.select! do |user|
journal.notes? || journal.visible_details(user).any?
end
@@ -306,7 +306,7 @@ class Mailer < ActionMailer::Base
# Example:
# Mailer.deliver_wiki_content_added(wiki_content)
def self.deliver_wiki_content_added(wiki_content)
- users = wiki_content.notified_users | wiki_content.page.wiki.notified_watchers
+ users = wiki_content.notified_users | wiki_content.page.wiki.notified_watchers | wiki_content.notified_mentions
users.each do |user|
wiki_content_added(user, wiki_content).deliver_later
end
@@ -343,6 +343,7 @@ class Mailer < ActionMailer::Base
users = wiki_content.notified_users
users |= wiki_content.page.notified_watchers
users |= wiki_content.page.wiki.notified_watchers
+ users |= wiki_content.notified_mentions
users.each do |user|
wiki_content_updated(user, wiki_content).deliver_later
diff --git a/app/models/wiki_content.rb b/app/models/wiki_content.rb
index ba16b7e29..7fa61560f 100644
--- a/app/models/wiki_content.rb
+++ b/app/models/wiki_content.rb
@@ -24,6 +24,9 @@ class WikiContent < ActiveRecord::Base
belongs_to :page, :class_name => 'WikiPage'
belongs_to :author, :class_name => 'User'
has_many :versions, :class_name => 'WikiContentVersion', :dependent => :delete_all
+
+ acts_as_mentionable :attributes => ['text']
+
validates_presence_of :text
validates_length_of :comments, :maximum => 1024, :allow_nil => true
diff --git a/app/views/issues/_form.html.erb b/app/views/issues/_form.html.erb
index 9654d631d..3993b9ebf 100644
--- a/app/views/issues/_form.html.erb
+++ b/app/views/issues/_form.html.erb
@@ -55,6 +55,11 @@
<% heads_for_wiki_formatter %>
<%= heads_for_auto_complete(@issue.project) %>
+<% if User.current.allowed_to?(:add_issue_watchers, @issue.project)%>
+ <%= update_data_sources_for_auto_complete({users: watchers_autocomplete_for_mention_path(project_id: @issue.project, q: '', object_type: 'issue',
+ object_id: @issue.id)}) %>
+<% end %>
+
<%= javascript_tag do %>
$(document).ready(function(){
$("#issue_tracker_id, #issue_status_id").each(function(){
diff --git a/app/views/wiki/edit.html.erb b/app/views/wiki/edit.html.erb
index c501d6e28..7e9cf42af 100644
--- a/app/views/wiki/edit.html.erb
+++ b/app/views/wiki/edit.html.erb
@@ -64,6 +64,10 @@
<%= link_to l(:button_cancel), wiki_page_edit_cancel_path(@page) %>
</p>
<%= wikitoolbar_for 'content_text', preview_project_wiki_page_path(:project_id => @project, :id => @page.title) %>
+
+<% if User.current.allowed_to?(:add_wiki_page_watchers, @project)%>
+ <%= update_data_sources_for_auto_complete({users: watchers_autocomplete_for_mention_path(project_id: @project, q: '', object_type: 'wiki_page', object_id: @page.id)}) %>
+ <% end %>
<% end %>
<% content_for :header_tags do %>