Feature #13919 » 0001-Demo-for-acts_as_mentionable.patch
| app/controllers/auto_completes_controller.rb | ||
|---|---|---|
| 42 | 42 |
render :json => format_issues_json(issues) |
| 43 | 43 |
end |
| 44 | 44 | |
| 45 |
def users |
|
| 46 |
users = [] |
|
| 47 |
q = (params[:q] || params[:term]).to_s.strip |
|
| 48 |
scope = nil |
|
| 49 |
if params[:q].blank? && @project.present? |
|
| 50 |
scope = @project.users |
|
| 51 |
else |
|
| 52 |
scope = User.all.limit(10) |
|
| 53 |
end |
|
| 54 |
users = scope.active.visible.sorted.like(params[:q]).to_a |
|
| 55 |
render :json => format_users_json(users) |
|
| 56 |
end |
|
| 57 | ||
| 45 | 58 |
private |
| 46 | 59 | |
| 47 | 60 |
def find_project |
| ... | ... | |
| 61 | 74 |
} |
| 62 | 75 |
} |
| 63 | 76 |
end |
| 77 | ||
| 78 |
def format_users_json(users) |
|
| 79 |
users.map {|user| {
|
|
| 80 |
'firstname' => user.firstname, |
|
| 81 |
'lastname' => user.lastname, |
|
| 82 |
'name' => user.name, |
|
| 83 |
'login' => user.login |
|
| 84 |
} |
|
| 85 |
} |
|
| 86 |
end |
|
| 64 | 87 |
end |
| app/models/issue.rb | ||
|---|---|---|
| 54 | 54 |
acts_as_activity_provider :scope => preload(:project, :author, :tracker, :status), |
| 55 | 55 |
:author_key => :author_id |
| 56 | 56 | |
| 57 |
acts_as_mentionable :attributes => ['description'] |
|
| 58 | ||
| 57 | 59 |
DONE_RATIO_OPTIONS = %w(issue_field issue_status) |
| 58 | 60 | |
| 59 | 61 |
attr_reader :transition_warning |
| app/models/journal.rb | ||
|---|---|---|
| 42 | 42 |
joins("LEFT OUTER JOIN #{JournalDetail.table_name} ON #{JournalDetail.table_name}.journal_id = #{Journal.table_name}.id").
|
| 43 | 43 |
where("#{Journal.table_name}.journalized_type = 'Issue' AND" +
|
| 44 | 44 |
" (#{JournalDetail.table_name}.prop_key = 'status_id' OR #{Journal.table_name}.notes <> '')").distinct
|
| 45 |
acts_as_mentionable :attributes => ['notes'] |
|
| 45 | 46 | |
| 46 | 47 |
before_create :split_private_notes |
| 47 | 48 |
after_create_commit :send_notification |
| app/models/mailer.rb | ||
|---|---|---|
| 68 | 68 |
end |
| 69 | 69 | |
| 70 | 70 |
# Builds a mail for notifying user about a new issue |
| 71 |
def issue_add(user, issue) |
|
| 71 |
def issue_add(user, issue, reason = nil)
|
|
| 72 | 72 |
redmine_headers 'Project' => issue.project.identifier, |
| 73 | 73 |
'Issue-Tracker' => issue.tracker.name, |
| 74 | 74 |
'Issue-Id' => issue.id, |
| ... | ... | |
| 79 | 79 |
@author = issue.author |
| 80 | 80 |
@issue = issue |
| 81 | 81 |
@user = user |
| 82 |
@reason = reason |
|
| 82 | 83 |
@issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue) |
| 83 | 84 |
subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]"
|
| 84 | 85 |
subject += " (#{issue.status.name})" if Setting.show_status_changes_in_mail_subject?
|
| ... | ... | |
| 93 | 94 |
# Mailer.deliver_issue_add(issue) |
| 94 | 95 |
def self.deliver_issue_add(issue) |
| 95 | 96 |
users = issue.notified_users | issue.notified_watchers |
| 97 | ||
| 96 | 98 |
users.each do |user| |
| 97 | 99 |
issue_add(user, issue).deliver_later |
| 98 | 100 |
end |
| 101 | ||
| 102 |
mentions = issue.notified_mentions |
|
| 103 |
users.each do |user| |
|
| 104 |
issue_add(user, issue, 'mentioned').deliver_later |
|
| 105 |
end |
|
| 99 | 106 |
end |
| 100 | 107 | |
| 101 | 108 |
# Builds a mail for notifying user about an issue update |
| 102 |
def issue_edit(user, journal) |
|
| 109 |
def issue_edit(user, journal, reason = nil)
|
|
| 103 | 110 |
issue = journal.journalized |
| 104 | 111 |
redmine_headers 'Project' => issue.project.identifier, |
| 105 | 112 |
'Issue-Tracker' => issue.tracker.name, |
| ... | ... | |
| 115 | 122 |
@issue = issue |
| 116 | 123 |
@user = user |
| 117 | 124 |
@journal = journal |
| 125 |
@reason = reason |
|
| 118 | 126 |
@journal_details = journal.visible_details |
| 119 | 127 |
@issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue, :anchor => "change-#{journal.id}")
|
| 120 | 128 | |
| ... | ... | |
| 128 | 136 |
# Mailer.deliver_issue_edit(journal) |
| 129 | 137 |
def self.deliver_issue_edit(journal) |
| 130 | 138 |
users = journal.notified_users | journal.notified_watchers |
| 139 | ||
| 131 | 140 |
users.select! do |user| |
| 132 | 141 |
journal.notes? || journal.visible_details(user).any? |
| 133 | 142 |
end |
| 134 | 143 |
users.each do |user| |
| 135 | 144 |
issue_edit(user, journal).deliver_later |
| 136 | 145 |
end |
| 146 | ||
| 147 |
notified_mentions = journal.journalized.notified_mentions | journal.notified_mentions |
|
| 148 |
notified_mentions.each do |user| |
|
| 149 |
issue_edit(user, journal, 'mentioned').deliver_later |
|
| 150 |
end |
|
| 137 | 151 |
end |
| 138 | 152 | |
| 139 | 153 |
# Builds a mail to user about a new document. |
| ... | ... | |
| 220 | 234 |
# Example: |
| 221 | 235 |
# Mailer.deliver_news_added(news) |
| 222 | 236 |
def self.deliver_news_added(news) |
| 223 |
users = news.notified_users | news.notified_watchers_for_added_news |
|
| 237 |
users = news.notified_users | news.notified_watchers_for_added_news | news.notified_mentions
|
|
| 224 | 238 |
users.each do |user| |
| 225 | 239 |
news_added(user, news).deliver_later |
| 226 | 240 |
end |
| ... | ... | |
| 301 | 315 |
# Example: |
| 302 | 316 |
# Mailer.deliver_wiki_content_added(wiki_content) |
| 303 | 317 |
def self.deliver_wiki_content_added(wiki_content) |
| 304 |
users = wiki_content.notified_users | wiki_content.page.wiki.notified_watchers |
|
| 318 |
users = wiki_content.notified_users | wiki_content.page.wiki.notified_watchers | wiki_content.notified_mentions
|
|
| 305 | 319 |
users.each do |user| |
| 306 | 320 |
wiki_content_added(user, wiki_content).deliver_later |
| 307 | 321 |
end |
| ... | ... | |
| 333 | 347 |
users = wiki_content.notified_users |
| 334 | 348 |
users |= wiki_content.page.notified_watchers |
| 335 | 349 |
users |= wiki_content.page.wiki.notified_watchers |
| 350 |
users |= wiki_content.notified_mentions |
|
| 336 | 351 | |
| 337 | 352 |
users.each do |user| |
| 338 | 353 |
wiki_content_updated(user, wiki_content).deliver_later |
| app/models/wiki_content.rb | ||
|---|---|---|
| 24 | 24 |
belongs_to :page, :class_name => 'WikiPage' |
| 25 | 25 |
belongs_to :author, :class_name => 'User' |
| 26 | 26 |
has_many :versions, :class_name => 'WikiContentVersion', :dependent => :delete_all |
| 27 | ||
| 28 |
acts_as_mentionable :attributes => ['text'] |
|
| 29 | ||
| 27 | 30 |
validates_presence_of :text |
| 28 | 31 |
validates_length_of :comments, :maximum => 1024, :allow_nil => true |
| 29 | 32 | |
| app/views/documents/_form.html.erb | ||
|---|---|---|
| 6 | 6 |
<p><%= f.text_area :description, :cols => 60, :rows => 15, :class => 'wiki-edit', |
| 7 | 7 |
:data => {
|
| 8 | 8 |
:auto_complete => true, |
| 9 |
:issues_url => auto_complete_issues_path(:project_id => @project, :q => '') |
|
| 9 |
:issues_url => auto_complete_issues_path(:project_id => @project, :q => ''), |
|
| 10 |
:users_url => auto_complete_users_path(:project_id => @project, :q => '') |
|
| 10 | 11 |
} |
| 11 | 12 |
%></p> |
| 12 | 13 | |
| app/views/issues/_edit.html.erb | ||
|---|---|---|
| 32 | 32 |
<%= f.text_area :notes, :cols => 60, :rows => 10, :class => 'wiki-edit', |
| 33 | 33 |
:data => {
|
| 34 | 34 |
:auto_complete => true, |
| 35 |
:issues_url => auto_complete_issues_path(:project_id => @issue.project, :q => '') |
|
| 35 |
:issues_url => auto_complete_issues_path(:project_id => @issue.project, :q => ''), |
|
| 36 |
:users_url => auto_complete_users_path(:project_id => @issue.project, :q => '') |
|
| 36 | 37 |
}, |
| 37 | 38 |
:no_label => true %> |
| 38 | 39 |
<%= wikitoolbar_for 'issue_notes', preview_issue_path(:project_id => @project, :issue_id => @issue) %> |
| app/views/issues/_form.html.erb | ||
|---|---|---|
| 38 | 38 |
:rows => [[10, @issue.description.to_s.length / 50].max, 20].min, |
| 39 | 39 |
:data => {
|
| 40 | 40 |
:auto_complete => true, |
| 41 |
:issues_url => auto_complete_issues_path(:project_id => @issue.project, :q => '') |
|
| 41 |
:issues_url => auto_complete_issues_path(:project_id => @issue.project, :q => ''), |
|
| 42 |
:users_url => auto_complete_users_path(:project_id => @issue.project, :q => '') |
|
| 42 | 43 |
}, |
| 43 | 44 |
:no_label => true %> |
| 44 | 45 |
<% end %> |
| app/views/issues/bulk_edit.html.erb | ||
|---|---|---|
| 197 | 197 |
<%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit', |
| 198 | 198 |
:data => {
|
| 199 | 199 |
:auto_complete => true, |
| 200 |
:issues_url => auto_complete_issues_path(:project_id => @project, :q => '') |
|
| 200 |
:issues_url => auto_complete_issues_path(:project_id => @project, :q => ''), |
|
| 201 |
:users_url => auto_complete_users_path(:project_id => @project, :q => '') |
|
| 201 | 202 |
} |
| 202 | 203 |
%> |
| 203 | 204 |
<%= wikitoolbar_for 'notes' %> |
| app/views/journals/_notes_form.html.erb | ||
|---|---|---|
| 7 | 7 |
:rows => (@journal.notes.blank? ? 10 : [[10, @journal.notes.length / 50].max, 100].min), |
| 8 | 8 |
:data => {
|
| 9 | 9 |
:auto_complete => true, |
| 10 |
:issues_url => auto_complete_issues_path(:project_id => @project, :q => '') |
|
| 10 |
:issues_url => auto_complete_issues_path(:project_id => @project, :q => ''), |
|
| 11 |
:users_url => auto_complete_users_path(:project_id => @project, :q => '') |
|
| 11 | 12 |
} |
| 12 | 13 |
%> |
| 13 | 14 |
<% if @journal.safe_attribute? 'private_notes' %> |
| app/views/mailer/issue_add.html.erb | ||
|---|---|---|
| 1 | 1 |
<%= l(:text_issue_added, :id => link_to("##{@issue.id}", @issue_url), :author => h(@issue.author)).html_safe %>
|
| 2 |
<% unless @reason.nil? %> |
|
| 3 |
You have been mentioned in it. |
|
| 4 |
<% end %> |
|
| 2 | 5 |
<hr /> |
| 3 | 6 |
<%= render :partial => 'issue', :formats => [:html], :locals => { :issue => @issue, :user => @user, :issue_url => @issue_url } %>
|
| app/views/mailer/issue_edit.html.erb | ||
|---|---|---|
| 2 | 2 |
(<%= l(:field_private_notes) %>) |
| 3 | 3 |
<% end %> |
| 4 | 4 |
<%= l(:text_issue_updated, :id => link_to("##{@issue.id}", @issue_url), :author => h(@journal.user)).html_safe %>
|
| 5 |
<% unless @reason.nil? %> |
|
| 6 |
You have been mentioned in it. |
|
| 7 |
<% end %> |
|
| 5 | 8 |
<hr /> |
| 6 | 9 | |
| 7 | 10 |
<ul class="journal details"> |
| app/views/messages/_form.html.erb | ||
|---|---|---|
| 27 | 27 |
:accesskey => accesskey(:edit), |
| 28 | 28 |
:data => {
|
| 29 | 29 |
:auto_complete => true, |
| 30 |
:issues_url => auto_complete_issues_path(:project_id => @project, :q => '') |
|
| 30 |
:issues_url => auto_complete_issues_path(:project_id => @project, :q => ''), |
|
| 31 |
:users_url => auto_complete_users_path(:project_id => @project, :q => '') |
|
| 31 | 32 |
} |
| 32 | 33 |
%></p> |
| 33 | 34 |
<%= wikitoolbar_for 'message_content', preview_board_message_path(:board_id => @board, :id => @message) %> |
| app/views/news/_form.html.erb | ||
|---|---|---|
| 6 | 6 |
<p><%= f.text_area :description, :required => true, :cols => 60, :rows => 15, :class => 'wiki-edit', |
| 7 | 7 |
:data => {
|
| 8 | 8 |
:auto_complete => true, |
| 9 |
:issues_url => auto_complete_issues_path(:project_id => @project, :q => '') |
|
| 9 |
:issues_url => auto_complete_issues_path(:project_id => @project, :q => ''), |
|
| 10 |
:users_url => auto_complete_users_path(:project_id => @project, :q => '') |
|
| 10 | 11 |
} |
| 11 | 12 |
%></p> |
| 12 | 13 |
<p id="attachments_form"><label><%= l(:label_attachment_plural) %></label><%= render :partial => 'attachments/form', :locals => {:container => @news} %></p>
|
| app/views/news/show.html.erb | ||
|---|---|---|
| 56 | 56 |
<%= text_area 'comment', 'comments', :cols => 80, :rows => 15, :class => 'wiki-edit', |
| 57 | 57 |
:data => {
|
| 58 | 58 |
:auto_complete => true, |
| 59 |
:issues_url => auto_complete_issues_path(:project_id => @project, :q => '') |
|
| 59 |
:issues_url => auto_complete_issues_path(:project_id => @project, :q => ''), |
|
| 60 |
:users_url => auto_complete_users_path(:project_id => @project, :q => '') |
|
| 60 | 61 |
} |
| 61 | 62 |
%> |
| 62 | 63 |
<%= wikitoolbar_for 'comment_comments', preview_news_path(:project_id => @project, :id => @news) %> |
| app/views/wiki/edit.html.erb | ||
|---|---|---|
| 17 | 17 |
:class => 'wiki-edit', |
| 18 | 18 |
:data => {
|
| 19 | 19 |
:auto_complete => true, |
| 20 |
:issues_url => auto_complete_issues_path(:project_id => @project, :q => '') |
|
| 20 |
:issues_url => auto_complete_issues_path(:project_id => @project, :q => ''), |
|
| 21 |
:users_url => auto_complete_users_path(:project_id => @project, :q => '') |
|
| 21 | 22 |
} |
| 22 | 23 |
%> |
| 23 | 24 | |
| config/routes.rb | ||
|---|---|---|
| 45 | 45 | |
| 46 | 46 |
# Misc issue routes. TODO: move into resources |
| 47 | 47 |
match '/issues/auto_complete', :to => 'auto_completes#issues', :via => :get, :as => 'auto_complete_issues' |
| 48 |
match '/users/auto_complete', :to => 'auto_completes#users', :via => :get, :as => 'auto_complete_users' |
|
| 48 | 49 |
match '/issues/context_menu', :to => 'context_menus#issues', :as => 'issues_context_menu', :via => [:get, :post] |
| 49 | 50 |
match '/issues/changes', :to => 'journals#index', :as => 'issue_changes', :via => :get |
| 50 | 51 |
match '/issues/:id/quoted', :to => 'journals#new', :id => /\d+/, :via => :post, :as => 'quoted_issue' |
| lib/redmine.rb | ||
|---|---|---|
| 31 | 31 |
end |
| 32 | 32 | |
| 33 | 33 |
require 'redmine/acts/positioned' |
| 34 |
require 'redmine/acts/mentionable' |
|
| 34 | 35 | |
| 35 | 36 |
require 'redmine/scm/base' |
| 36 | 37 |
require 'redmine/access_control' |
| lib/redmine/acts/mentionable.rb | ||
|---|---|---|
| 1 |
# frozen_string_literal: true |
|
| 2 | ||
| 3 |
# Redmine - project management software |
|
| 4 |
# Copyright (C) 2006-2019 Jean-Philippe Lang |
|
| 5 |
# |
|
| 6 |
# This program is free software; you can redistribute it and/or |
|
| 7 |
# modify it under the terms of the GNU General Public License |
|
| 8 |
# as published by the Free Software Foundation; either version 2 |
|
| 9 |
# of the License, or (at your option) any later version. |
|
| 10 |
# |
|
| 11 |
# This program is distributed in the hope that it will be useful, |
|
| 12 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 13 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 14 |
# GNU General Public License for more details. |
|
| 15 |
# |
|
| 16 |
# You should have received a copy of the GNU General Public License |
|
| 17 |
# along with this program; if not, write to the Free Software |
|
| 18 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
| 19 | ||
| 20 |
module Redmine |
|
| 21 |
module Acts |
|
| 22 |
module Mentionable |
|
| 23 |
def self.included(base) |
|
| 24 |
base.extend ClassMethods |
|
| 25 |
end |
|
| 26 | ||
| 27 |
module ClassMethods |
|
| 28 |
def acts_as_mentionable(options = {})
|
|
| 29 |
class_attribute :mentionable_attributes |
|
| 30 |
self.mentionable_attributes = options[:attributes] |
|
| 31 | ||
| 32 |
attr_accessor :mentioned_users |
|
| 33 | ||
| 34 |
send :include, Redmine::Acts::Mentionable::InstanceMethods |
|
| 35 | ||
| 36 |
after_save :parse_mentions |
|
| 37 |
end |
|
| 38 |
end |
|
| 39 | ||
| 40 |
module InstanceMethods |
|
| 41 |
def self.included(base) |
|
| 42 |
base.extend ClassMethods |
|
| 43 |
end |
|
| 44 | ||
| 45 |
def notified_mentions |
|
| 46 |
notified = mentioned_users.to_a |
|
| 47 |
notified.reject! {|user| user.mail.blank? || user.mail_notification == 'none'}
|
|
| 48 |
notified |
|
| 49 |
end |
|
| 50 | ||
| 51 |
private |
|
| 52 | ||
| 53 |
def parse_mentions |
|
| 54 |
mentionable_attrs = self.mentionable_attributes |
|
| 55 |
saved_mentionable_attrs = self.saved_changes.select{|a| mentionable_attrs.include?(a)}
|
|
| 56 | ||
| 57 |
saved_mentionable_attrs.each do |key, attr| |
|
| 58 |
old_value, new_value = attr |
|
| 59 |
get_mentioned_users(old_value, new_value) |
|
| 60 |
end |
|
| 61 |
end |
|
| 62 | ||
| 63 |
def get_mentioned_users(old_content, new_content) |
|
| 64 |
previous_matches = scan_for_mentioned_users(old_content) |
|
| 65 |
current_matches = scan_for_mentioned_users(new_content) |
|
| 66 |
new_matches = (current_matches - previous_matches).flatten |
|
| 67 | ||
| 68 |
if new_matches.any? |
|
| 69 |
self.mentioned_users = User.visible.active.where(:login => new_matches) |
|
| 70 |
end |
|
| 71 |
end |
|
| 72 | ||
| 73 |
def scan_for_mentioned_users(content) |
|
| 74 |
return [] if content.nil? |
|
| 75 | ||
| 76 |
# remove quoted text |
|
| 77 |
content = content.gsub(%r{\r\n(?:\>\s)+(.*?)\r\n}m, '')
|
|
| 78 | ||
| 79 |
text_formatting = Setting.text_formatting |
|
| 80 |
# Remove text wrapped in pre tags based on text formatting |
|
| 81 |
if text_formatting == 'textile' |
|
| 82 |
content = content.gsub(%r{<pre>(.*?)</pre>}m, '')
|
|
| 83 |
elsif text_formatting == 'markdown' |
|
| 84 |
content = content.gsub(%r{(~~~|```)(.*?)(~~~|```)}m, '')
|
|
| 85 |
end |
|
| 86 | ||
| 87 |
content.scan(/@([a-z0-9_\-@\.]*)/i) |
|
| 88 |
end |
|
| 89 |
end |
|
| 90 |
end |
|
| 91 |
end |
|
| 92 |
end |
|
| 93 | ||
| 94 |
ActiveRecord::Base.send :include, Redmine::Acts::Mentionable |
|
| public/javascripts/application.js | ||
|---|---|---|
| 1049 | 1049 |
}; |
| 1050 | 1050 | |
| 1051 | 1051 |
const tribute = new Tribute({
|
| 1052 |
trigger: '#', |
|
| 1053 |
values: function (text, cb) {
|
|
| 1054 |
if (event.target.type === 'text' && $(element).attr('autocomplete') != 'off') {
|
|
| 1055 |
$(element).attr('autocomplete', 'off');
|
|
| 1056 |
} |
|
| 1057 |
remoteSearch(issuesUrl + text, function (issues) {
|
|
| 1058 |
return cb(issues); |
|
| 1059 |
}); |
|
| 1060 |
}, |
|
| 1061 |
lookup: 'label', |
|
| 1062 |
fillAttr: 'label', |
|
| 1063 |
requireLeadingSpace: true, |
|
| 1064 |
selectTemplate: function (issue) {
|
|
| 1065 |
return '#' + issue.original.id; |
|
| 1066 |
} |
|
| 1052 |
collection: [ |
|
| 1053 |
{
|
|
| 1054 |
trigger: '#', |
|
| 1055 |
values: function (text, cb) {
|
|
| 1056 |
if (event.target.type === 'text' && $(element).attr('autocomplete') != 'off') {
|
|
| 1057 |
$(element).attr('autocomplete', 'off');
|
|
| 1058 |
} |
|
| 1059 |
remoteSearch(issuesUrl + text, function (issues) {
|
|
| 1060 |
return cb(issues); |
|
| 1061 |
}); |
|
| 1062 |
}, |
|
| 1063 |
lookup: 'label', |
|
| 1064 |
fillAttr: 'label', |
|
| 1065 |
requireLeadingSpace: true, |
|
| 1066 |
selectTemplate: function (issue) {
|
|
| 1067 |
return '#' + issue.original.id; |
|
| 1068 |
}, |
|
| 1069 |
}, |
|
| 1070 |
{
|
|
| 1071 |
trigger: '@', |
|
| 1072 |
lookup: function (user, mentionText) {
|
|
| 1073 |
return user.name + user.firstname + user.lastname + user.login; |
|
| 1074 |
}, |
|
| 1075 |
values: function (text, cb) {
|
|
| 1076 |
remoteSearch(usersUrl + text, function (users) {
|
|
| 1077 |
return cb(users); |
|
| 1078 |
}); |
|
| 1079 |
}, |
|
| 1080 |
menuItemTemplate: function (user) {
|
|
| 1081 |
return user.original.name; |
|
| 1082 |
}, |
|
| 1083 |
selectTemplate: function (user) {
|
|
| 1084 |
return '@' + user.original.login; |
|
| 1085 |
} |
|
| 1086 |
} |
|
| 1087 |
] |
|
| 1067 | 1088 |
}); |
| 1068 | 1089 | |
| 1069 | 1090 |
tribute.attach(element); |
| test/functional/auto_completes_controller_test.rb | ||
|---|---|---|
| 78 | 78 |
assert_include "Bug #13", response.body |
| 79 | 79 |
end |
| 80 | 80 | |
| 81 |
def test_auto_complete_with_scope_all_should_search_other_projects
|
|
| 81 |
def test_issues_with_scope_all_should_search_other_projects
|
|
| 82 | 82 |
get( |
| 83 | 83 |
:issues, |
| 84 | 84 |
:params => {
|
| ... | ... | |
| 91 | 91 |
assert_include "Bug #13", response.body |
| 92 | 92 |
end |
| 93 | 93 | |
| 94 |
def test_auto_complete_without_project_should_search_all_projects
|
|
| 94 |
def test_issues_without_project_should_search_all_projects
|
|
| 95 | 95 |
get(:issues, :params => {:q => '13'})
|
| 96 | 96 |
assert_response :success |
| 97 | 97 |
assert_include "Bug #13", response.body |
| 98 | 98 |
end |
| 99 | 99 | |
| 100 |
def test_auto_complete_without_scope_all_should_not_search_other_projects
|
|
| 100 |
def test_issues_without_scope_all_should_not_search_other_projects
|
|
| 101 | 101 |
get( |
| 102 | 102 |
:issues, |
| 103 | 103 |
:params => {
|
| ... | ... | |
| 127 | 127 |
assert_equal 'Bug #13: Subproject issue two', issue['label'] |
| 128 | 128 |
end |
| 129 | 129 | |
| 130 |
def test_auto_complete_with_status_o_should_return_open_issues_only
|
|
| 130 |
def test_issues_with_status_o_should_return_open_issues_only
|
|
| 131 | 131 |
get( |
| 132 | 132 |
:issues, |
| 133 | 133 |
:params => {
|
| ... | ... | |
| 141 | 141 |
assert_not_include "closed", response.body |
| 142 | 142 |
end |
| 143 | 143 | |
| 144 |
def test_auto_complete_with_status_c_should_return_closed_issues_only
|
|
| 144 |
def test_issues_with_status_c_should_return_closed_issues_only
|
|
| 145 | 145 |
get( |
| 146 | 146 |
:issues, |
| 147 | 147 |
:params => {
|
| ... | ... | |
| 155 | 155 |
assert_not_include "Issue due today", response.body |
| 156 | 156 |
end |
| 157 | 157 | |
| 158 |
def test_auto_complete_with_issue_id_should_not_return_that_issue
|
|
| 158 |
def test_issues_with_issue_id_should_not_return_that_issue
|
|
| 159 | 159 |
get( |
| 160 | 160 |
:issues, |
| 161 | 161 |
:params => {
|
| ... | ... | |
| 181 | 181 |
assert_include 'application/json', response.headers['Content-Type'] |
| 182 | 182 |
end |
| 183 | 183 | |
| 184 |
def test_auto_complete_without_term_should_return_last_10_issues
|
|
| 184 |
def test_issue_without_term_should_return_last_10_issues
|
|
| 185 | 185 |
# There are 9 issues generated by fixtures |
| 186 | 186 |
# and we need two more to test the 10 limit |
| 187 | 187 |
%w(1..2).each do |
| ... | ... | |
| 196 | 196 |
assert_equal 10, json.count |
| 197 | 197 |
assert_equal Issue.last.id, json.first['id'].to_i |
| 198 | 198 |
end |
| 199 | ||
| 200 |
def test_users_should_accept_case_insensitive_term_param |
|
| 201 |
get :users, :params => {
|
|
| 202 |
:q => 'JoHN' |
|
| 203 |
} |
|
| 204 |
assert_response :success |
|
| 205 |
assert_include "John Smith", response.body |
|
| 206 |
end |
|
| 207 | ||
| 208 |
def test_users_should_return_json |
|
| 209 |
get :users, :params => {
|
|
| 210 |
:q => 'john' |
|
| 211 |
} |
|
| 212 |
assert_response :success |
|
| 213 |
json = ActiveSupport::JSON.decode(response.body) |
|
| 214 |
assert_kind_of Array, json |
|
| 215 |
user = json.first |
|
| 216 |
assert_kind_of Hash, user |
|
| 217 |
assert_equal 'John', user['firstname'] |
|
| 218 |
assert_equal 'Smith', user['lastname'] |
|
| 219 |
assert_equal 'John Smith', user['name'] |
|
| 220 |
assert_equal 'jsmith', user['login'] |
|
| 221 |
end |
|
| 222 | ||
| 223 |
def test_users_with_project_and_without_term_should_return_project_users |
|
| 224 |
get :users, :params => {
|
|
| 225 |
:project_id => 'onlinestore' |
|
| 226 |
} |
|
| 227 |
assert_response :success |
|
| 228 |
json = ActiveSupport::JSON.decode(response.body) |
|
| 229 |
assert_equal 2, json.count |
|
| 230 |
assert_equal 'jsmith', json.first['login'] |
|
| 231 |
assert_equal 'miscuser8', json.last['login'] |
|
| 232 |
end |
|
| 233 | ||
| 234 |
def test_users_without_project_and_with_term_should_search_in_all_users |
|
| 235 |
get :users, :params => {
|
|
| 236 |
:q => 'm' |
|
| 237 |
} |
|
| 238 |
assert_response :success |
|
| 239 |
assert_include "Redmine Admin", response.body |
|
| 240 |
assert_include "Dave Lopper", response.body |
|
| 241 |
end |
|
| 199 | 242 |
end |