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 |