##// END OF EJS Templates
Adds STI to Query model. Issue queries are now IssueQuery instances....
Jean-Philippe Lang -
r10737:ab066317e62b
parent child
Show More
@@ -0,0 +1,321
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18 class IssueQuery < Query
19
20 self.available_columns = [
21 QueryColumn.new(:project, :sortable => "#{Project.table_name}.name", :groupable => true),
22 QueryColumn.new(:tracker, :sortable => "#{Tracker.table_name}.position", :groupable => true),
23 QueryColumn.new(:parent, :sortable => ["#{Issue.table_name}.root_id", "#{Issue.table_name}.lft ASC"], :default_order => 'desc', :caption => :field_parent_issue),
24 QueryColumn.new(:status, :sortable => "#{IssueStatus.table_name}.position", :groupable => true),
25 QueryColumn.new(:priority, :sortable => "#{IssuePriority.table_name}.position", :default_order => 'desc', :groupable => true),
26 QueryColumn.new(:subject, :sortable => "#{Issue.table_name}.subject"),
27 QueryColumn.new(:author, :sortable => lambda {User.fields_for_order_statement("authors")}, :groupable => true),
28 QueryColumn.new(:assigned_to, :sortable => lambda {User.fields_for_order_statement}, :groupable => true),
29 QueryColumn.new(:updated_on, :sortable => "#{Issue.table_name}.updated_on", :default_order => 'desc'),
30 QueryColumn.new(:category, :sortable => "#{IssueCategory.table_name}.name", :groupable => true),
31 QueryColumn.new(:fixed_version, :sortable => lambda {Version.fields_for_order_statement}, :groupable => true),
32 QueryColumn.new(:start_date, :sortable => "#{Issue.table_name}.start_date"),
33 QueryColumn.new(:due_date, :sortable => "#{Issue.table_name}.due_date"),
34 QueryColumn.new(:estimated_hours, :sortable => "#{Issue.table_name}.estimated_hours"),
35 QueryColumn.new(:done_ratio, :sortable => "#{Issue.table_name}.done_ratio", :groupable => true),
36 QueryColumn.new(:created_on, :sortable => "#{Issue.table_name}.created_on", :default_order => 'desc'),
37 QueryColumn.new(:relations, :caption => :label_related_issues),
38 QueryColumn.new(:description, :inline => false)
39 ]
40
41 scope :visible, lambda {|*args|
42 user = args.shift || User.current
43 base = Project.allowed_to_condition(user, :view_issues, *args)
44 user_id = user.logged? ? user.id : 0
45
46 includes(:project).where("(#{table_name}.project_id IS NULL OR (#{base})) AND (#{table_name}.is_public = ? OR #{table_name}.user_id = ?)", true, user_id)
47 }
48
49 def initialize(attributes=nil, *args)
50 super attributes
51 self.filters ||= { 'status_id' => {:operator => "o", :values => [""]} }
52 end
53
54 # Returns true if the query is visible to +user+ or the current user.
55 def visible?(user=User.current)
56 (project.nil? || user.allowed_to?(:view_issues, project)) && (self.is_public? || self.user_id == user.id)
57 end
58
59 def available_filters
60 return @available_filters if @available_filters
61 @available_filters = {
62 "status_id" => {
63 :type => :list_status, :order => 0,
64 :values => IssueStatus.sorted.all.collect{|s| [s.name, s.id.to_s] }
65 },
66 "tracker_id" => {
67 :type => :list, :order => 2, :values => trackers.collect{|s| [s.name, s.id.to_s] }
68 },
69 "priority_id" => {
70 :type => :list, :order => 3, :values => IssuePriority.all.collect{|s| [s.name, s.id.to_s] }
71 },
72 "subject" => { :type => :text, :order => 8 },
73 "created_on" => { :type => :date_past, :order => 9 },
74 "updated_on" => { :type => :date_past, :order => 10 },
75 "start_date" => { :type => :date, :order => 11 },
76 "due_date" => { :type => :date, :order => 12 },
77 "estimated_hours" => { :type => :float, :order => 13 },
78 "done_ratio" => { :type => :integer, :order => 14 }
79 }
80 IssueRelation::TYPES.each do |relation_type, options|
81 @available_filters[relation_type] = {
82 :type => :relation, :order => @available_filters.size + 100,
83 :label => options[:name]
84 }
85 end
86 principals = []
87 if project
88 principals += project.principals.sort
89 unless project.leaf?
90 subprojects = project.descendants.visible.all
91 if subprojects.any?
92 @available_filters["subproject_id"] = {
93 :type => :list_subprojects, :order => 13,
94 :values => subprojects.collect{|s| [s.name, s.id.to_s] }
95 }
96 principals += Principal.member_of(subprojects)
97 end
98 end
99 else
100 if all_projects.any?
101 # members of visible projects
102 principals += Principal.member_of(all_projects)
103 # project filter
104 project_values = []
105 if User.current.logged? && User.current.memberships.any?
106 project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"]
107 end
108 project_values += all_projects_values
109 @available_filters["project_id"] = {
110 :type => :list, :order => 1, :values => project_values
111 } unless project_values.empty?
112 end
113 end
114 principals.uniq!
115 principals.sort!
116 users = principals.select {|p| p.is_a?(User)}
117
118 assigned_to_values = []
119 assigned_to_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
120 assigned_to_values += (Setting.issue_group_assignment? ?
121 principals : users).collect{|s| [s.name, s.id.to_s] }
122 @available_filters["assigned_to_id"] = {
123 :type => :list_optional, :order => 4, :values => assigned_to_values
124 } unless assigned_to_values.empty?
125
126 author_values = []
127 author_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
128 author_values += users.collect{|s| [s.name, s.id.to_s] }
129 @available_filters["author_id"] = {
130 :type => :list, :order => 5, :values => author_values
131 } unless author_values.empty?
132
133 group_values = Group.all.collect {|g| [g.name, g.id.to_s] }
134 @available_filters["member_of_group"] = {
135 :type => :list_optional, :order => 6, :values => group_values
136 } unless group_values.empty?
137
138 role_values = Role.givable.collect {|r| [r.name, r.id.to_s] }
139 @available_filters["assigned_to_role"] = {
140 :type => :list_optional, :order => 7, :values => role_values
141 } unless role_values.empty?
142
143 if User.current.logged?
144 @available_filters["watcher_id"] = {
145 :type => :list, :order => 15, :values => [["<< #{l(:label_me)} >>", "me"]]
146 }
147 end
148
149 if project
150 # project specific filters
151 categories = project.issue_categories.all
152 unless categories.empty?
153 @available_filters["category_id"] = {
154 :type => :list_optional, :order => 6,
155 :values => categories.collect{|s| [s.name, s.id.to_s] }
156 }
157 end
158 versions = project.shared_versions.all
159 unless versions.empty?
160 @available_filters["fixed_version_id"] = {
161 :type => :list_optional, :order => 7,
162 :values => versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] }
163 }
164 end
165 add_custom_fields_filters(project.all_issue_custom_fields)
166 else
167 # global filters for cross project issue list
168 system_shared_versions = Version.visible.find_all_by_sharing('system')
169 unless system_shared_versions.empty?
170 @available_filters["fixed_version_id"] = {
171 :type => :list_optional, :order => 7,
172 :values => system_shared_versions.sort.collect{|s|
173 ["#{s.project.name} - #{s.name}", s.id.to_s]
174 }
175 }
176 end
177 add_custom_fields_filters(IssueCustomField.where(:is_filter => true, :is_for_all => true).all)
178 end
179 add_associations_custom_fields_filters :project, :author, :assigned_to, :fixed_version
180 if User.current.allowed_to?(:set_issues_private, nil, :global => true) ||
181 User.current.allowed_to?(:set_own_issues_private, nil, :global => true)
182 @available_filters["is_private"] = {
183 :type => :list, :order => 16,
184 :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]]
185 }
186 end
187 Tracker.disabled_core_fields(trackers).each {|field|
188 @available_filters.delete field
189 }
190 @available_filters.each do |field, options|
191 options[:name] ||= l(options[:label] || "field_#{field}".gsub(/_id$/, ''))
192 end
193 @available_filters
194 end
195
196 def available_columns
197 return @available_columns if @available_columns
198 @available_columns = self.class.available_columns.dup
199 @available_columns += (project ?
200 project.all_issue_custom_fields :
201 IssueCustomField.all
202 ).collect {|cf| QueryCustomFieldColumn.new(cf) }
203
204 if User.current.allowed_to?(:view_time_entries, project, :global => true)
205 index = nil
206 @available_columns.each_with_index {|column, i| index = i if column.name == :estimated_hours}
207 index = (index ? index + 1 : -1)
208 # insert the column after estimated_hours or at the end
209 @available_columns.insert index, QueryColumn.new(:spent_hours,
210 :sortable => "(SELECT COALESCE(SUM(hours), 0) FROM #{TimeEntry.table_name} WHERE #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id)",
211 :default_order => 'desc',
212 :caption => :label_spent_time
213 )
214 end
215
216 if User.current.allowed_to?(:set_issues_private, nil, :global => true) ||
217 User.current.allowed_to?(:set_own_issues_private, nil, :global => true)
218 @available_columns << QueryColumn.new(:is_private, :sortable => "#{Issue.table_name}.is_private")
219 end
220
221 disabled_fields = Tracker.disabled_core_fields(trackers).map {|field| field.sub(/_id$/, '')}
222 @available_columns.reject! {|column|
223 disabled_fields.include?(column.name.to_s)
224 }
225
226 @available_columns
227 end
228
229 # Returns the issue count
230 def issue_count
231 Issue.visible.count(:include => [:status, :project], :conditions => statement)
232 rescue ::ActiveRecord::StatementInvalid => e
233 raise StatementInvalid.new(e.message)
234 end
235
236 # Returns the issue count by group or nil if query is not grouped
237 def issue_count_by_group
238 r = nil
239 if grouped?
240 begin
241 # Rails3 will raise an (unexpected) RecordNotFound if there's only a nil group value
242 r = Issue.visible.count(:group => group_by_statement, :include => [:status, :project], :conditions => statement)
243 rescue ActiveRecord::RecordNotFound
244 r = {nil => issue_count}
245 end
246 c = group_by_column
247 if c.is_a?(QueryCustomFieldColumn)
248 r = r.keys.inject({}) {|h, k| h[c.custom_field.cast_value(k)] = r[k]; h}
249 end
250 end
251 r
252 rescue ::ActiveRecord::StatementInvalid => e
253 raise StatementInvalid.new(e.message)
254 end
255
256 # Returns the issues
257 # Valid options are :order, :offset, :limit, :include, :conditions
258 def issues(options={})
259 order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',')
260 order_option = nil if order_option.blank?
261
262 issues = Issue.visible.where(options[:conditions]).all(
263 :include => ([:status, :project] + (options[:include] || [])).uniq,
264 :conditions => statement,
265 :order => order_option,
266 :joins => joins_for_order_statement(order_option),
267 :limit => options[:limit],
268 :offset => options[:offset]
269 )
270
271 if has_column?(:spent_hours)
272 Issue.load_visible_spent_hours(issues)
273 end
274 if has_column?(:relations)
275 Issue.load_visible_relations(issues)
276 end
277 issues
278 rescue ::ActiveRecord::StatementInvalid => e
279 raise StatementInvalid.new(e.message)
280 end
281
282 # Returns the issues ids
283 def issue_ids(options={})
284 order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',')
285 order_option = nil if order_option.blank?
286
287 Issue.visible.scoped(:conditions => options[:conditions]).scoped(:include => ([:status, :project] + (options[:include] || [])).uniq,
288 :conditions => statement,
289 :order => order_option,
290 :joins => joins_for_order_statement(order_option),
291 :limit => options[:limit],
292 :offset => options[:offset]).find_ids
293 rescue ::ActiveRecord::StatementInvalid => e
294 raise StatementInvalid.new(e.message)
295 end
296
297 # Returns the journals
298 # Valid options are :order, :offset, :limit
299 def journals(options={})
300 Journal.visible.all(
301 :include => [:details, :user, {:issue => [:project, :author, :tracker, :status]}],
302 :conditions => statement,
303 :order => options[:order],
304 :limit => options[:limit],
305 :offset => options[:offset]
306 )
307 rescue ::ActiveRecord::StatementInvalid => e
308 raise StatementInvalid.new(e.message)
309 end
310
311 # Returns the versions
312 # Valid options are :conditions
313 def versions(options={})
314 Version.visible.where(options[:conditions]).all(
315 :include => :project,
316 :conditions => project_statement
317 )
318 rescue ::ActiveRecord::StatementInvalid => e
319 raise StatementInvalid.new(e.message)
320 end
321 end
@@ -0,0 +1,9
1 class AddQueriesType < ActiveRecord::Migration
2 def up
3 add_column :queries, :type, :string
4 end
5
6 def down
7 remove_column :queries, :type
8 end
9 end
@@ -0,0 +1,9
1 class UpdateQueriesToSti < ActiveRecord::Migration
2 def up
3 ::Query.update_all :type => 'IssueQuery'
4 end
5
6 def down
7 ::Query.update_all :type => nil
8 end
9 end
@@ -32,9 +32,9 class QueriesController < ApplicationController
32 @limit = per_page_option
32 @limit = per_page_option
33 end
33 end
34
34
35 @query_count = Query.visible.count
35 @query_count = IssueQuery.visible.count
36 @query_pages = Paginator.new self, @query_count, @limit, params['page']
36 @query_pages = Paginator.new self, @query_count, @limit, params['page']
37 @queries = Query.visible.all(:limit => @limit, :offset => @offset, :order => "#{Query.table_name}.name")
37 @queries = IssueQuery.visible.all(:limit => @limit, :offset => @offset, :order => "#{Query.table_name}.name")
38
38
39 respond_to do |format|
39 respond_to do |format|
40 format.html { render :nothing => true }
40 format.html { render :nothing => true }
@@ -43,7 +43,7 class QueriesController < ApplicationController
43 end
43 end
44
44
45 def new
45 def new
46 @query = Query.new
46 @query = IssueQuery.new
47 @query.user = User.current
47 @query.user = User.current
48 @query.project = @project
48 @query.project = @project
49 @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
49 @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
@@ -51,7 +51,7 class QueriesController < ApplicationController
51 end
51 end
52
52
53 def create
53 def create
54 @query = Query.new(params[:query])
54 @query = IssueQuery.new(params[:query])
55 @query.user = User.current
55 @query.user = User.current
56 @query.project = params[:query_is_for_all] ? nil : @project
56 @query.project = params[:query_is_for_all] ? nil : @project
57 @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
57 @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
@@ -91,7 +91,7 class QueriesController < ApplicationController
91
91
92 private
92 private
93 def find_query
93 def find_query
94 @query = Query.find(params[:id])
94 @query = IssueQuery.find(params[:id])
95 @project = @query.project
95 @project = @query.project
96 render_403 unless @query.editable_by?(User.current)
96 render_403 unless @query.editable_by?(User.current)
97 rescue ActiveRecord::RecordNotFound
97 rescue ActiveRecord::RecordNotFound
@@ -184,7 +184,7 module IssuesHelper
184
184
185 def sidebar_queries
185 def sidebar_queries
186 unless @sidebar_queries
186 unless @sidebar_queries
187 @sidebar_queries = Query.visible.all(
187 @sidebar_queries = IssueQuery.visible.all(
188 :order => "#{Query.table_name}.name ASC",
188 :order => "#{Query.table_name}.name ASC",
189 # Project specific queries and global queries
189 # Project specific queries and global queries
190 :conditions => (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id])
190 :conditions => (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id])
@@ -122,21 +122,21 module QueriesHelper
122 if !params[:query_id].blank?
122 if !params[:query_id].blank?
123 cond = "project_id IS NULL"
123 cond = "project_id IS NULL"
124 cond << " OR project_id = #{@project.id}" if @project
124 cond << " OR project_id = #{@project.id}" if @project
125 @query = Query.find(params[:query_id], :conditions => cond)
125 @query = IssueQuery.find(params[:query_id], :conditions => cond)
126 raise ::Unauthorized unless @query.visible?
126 raise ::Unauthorized unless @query.visible?
127 @query.project = @project
127 @query.project = @project
128 session[:query] = {:id => @query.id, :project_id => @query.project_id}
128 session[:query] = {:id => @query.id, :project_id => @query.project_id}
129 sort_clear
129 sort_clear
130 elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil)
130 elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil)
131 # Give it a name, required to be valid
131 # Give it a name, required to be valid
132 @query = Query.new(:name => "_")
132 @query = IssueQuery.new(:name => "_")
133 @query.project = @project
133 @query.project = @project
134 build_query_from_params
134 build_query_from_params
135 session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names}
135 session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names}
136 else
136 else
137 # retrieve from session
137 # retrieve from session
138 @query = Query.find_by_id(session[:query][:id]) if session[:query][:id]
138 @query = IssueQuery.find_by_id(session[:query][:id]) if session[:query][:id]
139 @query ||= Query.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
139 @query ||= IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
140 @query.project = @project
140 @query.project = @project
141 end
141 end
142 end
142 end
@@ -144,10 +144,10 module QueriesHelper
144 def retrieve_query_from_session
144 def retrieve_query_from_session
145 if session[:query]
145 if session[:query]
146 if session[:query][:id]
146 if session[:query][:id]
147 @query = Query.find_by_id(session[:query][:id])
147 @query = IssueQuery.find_by_id(session[:query][:id])
148 return unless @query
148 return unless @query
149 else
149 else
150 @query = Query.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
150 @query = IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
151 end
151 end
152 if session[:query].has_key?(:project_id)
152 if session[:query].has_key?(:project_id)
153 @query.project_id = session[:query][:project_id]
153 @query.project_id = session[:query][:project_id]
@@ -42,7 +42,7 class Project < ActiveRecord::Base
42 has_many :issue_changes, :through => :issues, :source => :journals
42 has_many :issue_changes, :through => :issues, :source => :journals
43 has_many :versions, :dependent => :destroy, :order => "#{Version.table_name}.effective_date DESC, #{Version.table_name}.name DESC"
43 has_many :versions, :dependent => :destroy, :order => "#{Version.table_name}.effective_date DESC, #{Version.table_name}.name DESC"
44 has_many :time_entries, :dependent => :delete_all
44 has_many :time_entries, :dependent => :delete_all
45 has_many :queries, :dependent => :delete_all
45 has_many :queries, :class_name => 'IssueQuery', :dependent => :delete_all
46 has_many :documents, :dependent => :destroy
46 has_many :documents, :dependent => :destroy
47 has_many :news, :dependent => :destroy, :include => :author
47 has_many :news, :dependent => :destroy, :include => :author
48 has_many :issue_categories, :dependent => :delete_all, :order => "#{IssueCategory.table_name}.name"
48 has_many :issue_categories, :dependent => :delete_all, :order => "#{IssueCategory.table_name}.name"
@@ -869,7 +869,7 class Project < ActiveRecord::Base
869 # Copies queries from +project+
869 # Copies queries from +project+
870 def copy_queries(project)
870 def copy_queries(project)
871 project.queries.each do |query|
871 project.queries.each do |query|
872 new_query = ::Query.new
872 new_query = IssueQuery.new
873 new_query.attributes = query.attributes.dup.except("id", "project_id", "sort_criteria")
873 new_query.attributes = query.attributes.dup.except("id", "project_id", "sort_criteria")
874 new_query.sort_criteria = query.sort_criteria if query.sort_criteria
874 new_query.sort_criteria = query.sort_criteria if query.sort_criteria
875 new_query.project = self
875 new_query.project = self
@@ -145,38 +145,10 class Query < ActiveRecord::Base
145 }
145 }
146
146
147 class_attribute :available_columns
147 class_attribute :available_columns
148 self.available_columns = [
148 self.available_columns = []
149 QueryColumn.new(:project, :sortable => "#{Project.table_name}.name", :groupable => true),
150 QueryColumn.new(:tracker, :sortable => "#{Tracker.table_name}.position", :groupable => true),
151 QueryColumn.new(:parent, :sortable => ["#{Issue.table_name}.root_id", "#{Issue.table_name}.lft ASC"], :default_order => 'desc', :caption => :field_parent_issue),
152 QueryColumn.new(:status, :sortable => "#{IssueStatus.table_name}.position", :groupable => true),
153 QueryColumn.new(:priority, :sortable => "#{IssuePriority.table_name}.position", :default_order => 'desc', :groupable => true),
154 QueryColumn.new(:subject, :sortable => "#{Issue.table_name}.subject"),
155 QueryColumn.new(:author, :sortable => lambda {User.fields_for_order_statement("authors")}, :groupable => true),
156 QueryColumn.new(:assigned_to, :sortable => lambda {User.fields_for_order_statement}, :groupable => true),
157 QueryColumn.new(:updated_on, :sortable => "#{Issue.table_name}.updated_on", :default_order => 'desc'),
158 QueryColumn.new(:category, :sortable => "#{IssueCategory.table_name}.name", :groupable => true),
159 QueryColumn.new(:fixed_version, :sortable => lambda {Version.fields_for_order_statement}, :groupable => true),
160 QueryColumn.new(:start_date, :sortable => "#{Issue.table_name}.start_date"),
161 QueryColumn.new(:due_date, :sortable => "#{Issue.table_name}.due_date"),
162 QueryColumn.new(:estimated_hours, :sortable => "#{Issue.table_name}.estimated_hours"),
163 QueryColumn.new(:done_ratio, :sortable => "#{Issue.table_name}.done_ratio", :groupable => true),
164 QueryColumn.new(:created_on, :sortable => "#{Issue.table_name}.created_on", :default_order => 'desc'),
165 QueryColumn.new(:relations, :caption => :label_related_issues),
166 QueryColumn.new(:description, :inline => false)
167 ]
168
169 scope :visible, lambda {|*args|
170 user = args.shift || User.current
171 base = Project.allowed_to_condition(user, :view_issues, *args)
172 user_id = user.logged? ? user.id : 0
173
174 includes(:project).where("(#{table_name}.project_id IS NULL OR (#{base})) AND (#{table_name}.is_public = ? OR #{table_name}.user_id = ?)", true, user_id)
175 }
176
149
177 def initialize(attributes=nil, *args)
150 def initialize(attributes=nil, *args)
178 super attributes
151 super attributes
179 self.filters ||= { 'status_id' => {:operator => "o", :values => [""]} }
180 @is_for_all = project.nil?
152 @is_for_all = project.nil?
181 end
153 end
182
154
@@ -211,11 +183,6 class Query < ActiveRecord::Base
211 errors.add(:base, m)
183 errors.add(:base, m)
212 end
184 end
213
185
214 # Returns true if the query is visible to +user+ or the current user.
215 def visible?(user=User.current)
216 (project.nil? || user.allowed_to?(:view_issues, project)) && (self.is_public? || self.user_id == user.id)
217 end
218
219 def editable_by?(user)
186 def editable_by?(user)
220 return false unless user
187 return false unless user
221 # Admin can edit them all and regular users can edit their private queries
188 # Admin can edit them all and regular users can edit their private queries
@@ -233,143 +200,6 class Query < ActiveRecord::Base
233 operators.inject({}) {|h, operator| h[operator.first] = l(operator.last); h}
200 operators.inject({}) {|h, operator| h[operator.first] = l(operator.last); h}
234 end
201 end
235
202
236 def available_filters
237 return @available_filters if @available_filters
238 @available_filters = {
239 "status_id" => {
240 :type => :list_status, :order => 0,
241 :values => IssueStatus.sorted.all.collect{|s| [s.name, s.id.to_s] }
242 },
243 "tracker_id" => {
244 :type => :list, :order => 2, :values => trackers.collect{|s| [s.name, s.id.to_s] }
245 },
246 "priority_id" => {
247 :type => :list, :order => 3, :values => IssuePriority.all.collect{|s| [s.name, s.id.to_s] }
248 },
249 "subject" => { :type => :text, :order => 8 },
250 "created_on" => { :type => :date_past, :order => 9 },
251 "updated_on" => { :type => :date_past, :order => 10 },
252 "start_date" => { :type => :date, :order => 11 },
253 "due_date" => { :type => :date, :order => 12 },
254 "estimated_hours" => { :type => :float, :order => 13 },
255 "done_ratio" => { :type => :integer, :order => 14 }
256 }
257 IssueRelation::TYPES.each do |relation_type, options|
258 @available_filters[relation_type] = {
259 :type => :relation, :order => @available_filters.size + 100,
260 :label => options[:name]
261 }
262 end
263 principals = []
264 if project
265 principals += project.principals.sort
266 unless project.leaf?
267 subprojects = project.descendants.visible.all
268 if subprojects.any?
269 @available_filters["subproject_id"] = {
270 :type => :list_subprojects, :order => 13,
271 :values => subprojects.collect{|s| [s.name, s.id.to_s] }
272 }
273 principals += Principal.member_of(subprojects)
274 end
275 end
276 else
277 if all_projects.any?
278 # members of visible projects
279 principals += Principal.member_of(all_projects)
280 # project filter
281 project_values = []
282 if User.current.logged? && User.current.memberships.any?
283 project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"]
284 end
285 project_values += all_projects_values
286 @available_filters["project_id"] = {
287 :type => :list, :order => 1, :values => project_values
288 } unless project_values.empty?
289 end
290 end
291 principals.uniq!
292 principals.sort!
293 users = principals.select {|p| p.is_a?(User)}
294
295 assigned_to_values = []
296 assigned_to_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
297 assigned_to_values += (Setting.issue_group_assignment? ?
298 principals : users).collect{|s| [s.name, s.id.to_s] }
299 @available_filters["assigned_to_id"] = {
300 :type => :list_optional, :order => 4, :values => assigned_to_values
301 } unless assigned_to_values.empty?
302
303 author_values = []
304 author_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
305 author_values += users.collect{|s| [s.name, s.id.to_s] }
306 @available_filters["author_id"] = {
307 :type => :list, :order => 5, :values => author_values
308 } unless author_values.empty?
309
310 group_values = Group.all.collect {|g| [g.name, g.id.to_s] }
311 @available_filters["member_of_group"] = {
312 :type => :list_optional, :order => 6, :values => group_values
313 } unless group_values.empty?
314
315 role_values = Role.givable.collect {|r| [r.name, r.id.to_s] }
316 @available_filters["assigned_to_role"] = {
317 :type => :list_optional, :order => 7, :values => role_values
318 } unless role_values.empty?
319
320 if User.current.logged?
321 @available_filters["watcher_id"] = {
322 :type => :list, :order => 15, :values => [["<< #{l(:label_me)} >>", "me"]]
323 }
324 end
325
326 if project
327 # project specific filters
328 categories = project.issue_categories.all
329 unless categories.empty?
330 @available_filters["category_id"] = {
331 :type => :list_optional, :order => 6,
332 :values => categories.collect{|s| [s.name, s.id.to_s] }
333 }
334 end
335 versions = project.shared_versions.all
336 unless versions.empty?
337 @available_filters["fixed_version_id"] = {
338 :type => :list_optional, :order => 7,
339 :values => versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] }
340 }
341 end
342 add_custom_fields_filters(project.all_issue_custom_fields)
343 else
344 # global filters for cross project issue list
345 system_shared_versions = Version.visible.find_all_by_sharing('system')
346 unless system_shared_versions.empty?
347 @available_filters["fixed_version_id"] = {
348 :type => :list_optional, :order => 7,
349 :values => system_shared_versions.sort.collect{|s|
350 ["#{s.project.name} - #{s.name}", s.id.to_s]
351 }
352 }
353 end
354 add_custom_fields_filters(IssueCustomField.where(:is_filter => true, :is_for_all => true).all)
355 end
356 add_associations_custom_fields_filters :project, :author, :assigned_to, :fixed_version
357 if User.current.allowed_to?(:set_issues_private, nil, :global => true) ||
358 User.current.allowed_to?(:set_own_issues_private, nil, :global => true)
359 @available_filters["is_private"] = {
360 :type => :list, :order => 16,
361 :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]]
362 }
363 end
364 Tracker.disabled_core_fields(trackers).each {|field|
365 @available_filters.delete field
366 }
367 @available_filters.each do |field, options|
368 options[:name] ||= l(options[:label] || "field_#{field}".gsub(/_id$/, ''))
369 end
370 @available_filters
371 end
372
373 # Returns a representation of the available filters for JSON serialization
203 # Returns a representation of the available filters for JSON serialization
374 def available_filters_as_json
204 def available_filters_as_json
375 json = {}
205 json = {}
@@ -447,39 +277,6 class Query < ActiveRecord::Base
447 label ||= l("field_#{field.to_s.gsub(/_id$/, '')}", :default => field)
277 label ||= l("field_#{field.to_s.gsub(/_id$/, '')}", :default => field)
448 end
278 end
449
279
450 def available_columns
451 return @available_columns if @available_columns
452 @available_columns = ::Query.available_columns.dup
453 @available_columns += (project ?
454 project.all_issue_custom_fields :
455 IssueCustomField.all
456 ).collect {|cf| QueryCustomFieldColumn.new(cf) }
457
458 if User.current.allowed_to?(:view_time_entries, project, :global => true)
459 index = nil
460 @available_columns.each_with_index {|column, i| index = i if column.name == :estimated_hours}
461 index = (index ? index + 1 : -1)
462 # insert the column after estimated_hours or at the end
463 @available_columns.insert index, QueryColumn.new(:spent_hours,
464 :sortable => "(SELECT COALESCE(SUM(hours), 0) FROM #{TimeEntry.table_name} WHERE #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id)",
465 :default_order => 'desc',
466 :caption => :label_spent_time
467 )
468 end
469
470 if User.current.allowed_to?(:set_issues_private, nil, :global => true) ||
471 User.current.allowed_to?(:set_own_issues_private, nil, :global => true)
472 @available_columns << QueryColumn.new(:is_private, :sortable => "#{Issue.table_name}.is_private")
473 end
474
475 disabled_fields = Tracker.disabled_core_fields(trackers).map {|field| field.sub(/_id$/, '')}
476 @available_columns.reject! {|column|
477 disabled_fields.include?(column.name.to_s)
478 }
479
480 @available_columns
481 end
482
483 def self.add_available_column(column)
280 def self.add_available_column(column)
484 self.available_columns << (column) if column.is_a?(QueryColumn)
281 self.available_columns << (column) if column.is_a?(QueryColumn)
485 end
282 end
@@ -666,99 +463,6 class Query < ActiveRecord::Base
666 filters_clauses.any? ? filters_clauses.join(' AND ') : nil
463 filters_clauses.any? ? filters_clauses.join(' AND ') : nil
667 end
464 end
668
465
669 # Returns the issue count
670 def issue_count
671 Issue.visible.count(:include => [:status, :project], :conditions => statement)
672 rescue ::ActiveRecord::StatementInvalid => e
673 raise StatementInvalid.new(e.message)
674 end
675
676 # Returns the issue count by group or nil if query is not grouped
677 def issue_count_by_group
678 r = nil
679 if grouped?
680 begin
681 # Rails3 will raise an (unexpected) RecordNotFound if there's only a nil group value
682 r = Issue.visible.count(:group => group_by_statement, :include => [:status, :project], :conditions => statement)
683 rescue ActiveRecord::RecordNotFound
684 r = {nil => issue_count}
685 end
686 c = group_by_column
687 if c.is_a?(QueryCustomFieldColumn)
688 r = r.keys.inject({}) {|h, k| h[c.custom_field.cast_value(k)] = r[k]; h}
689 end
690 end
691 r
692 rescue ::ActiveRecord::StatementInvalid => e
693 raise StatementInvalid.new(e.message)
694 end
695
696 # Returns the issues
697 # Valid options are :order, :offset, :limit, :include, :conditions
698 def issues(options={})
699 order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',')
700 order_option = nil if order_option.blank?
701
702 issues = Issue.visible.where(options[:conditions]).all(
703 :include => ([:status, :project] + (options[:include] || [])).uniq,
704 :conditions => statement,
705 :order => order_option,
706 :joins => joins_for_order_statement(order_option),
707 :limit => options[:limit],
708 :offset => options[:offset]
709 )
710
711 if has_column?(:spent_hours)
712 Issue.load_visible_spent_hours(issues)
713 end
714 if has_column?(:relations)
715 Issue.load_visible_relations(issues)
716 end
717 issues
718 rescue ::ActiveRecord::StatementInvalid => e
719 raise StatementInvalid.new(e.message)
720 end
721
722 # Returns the issues ids
723 def issue_ids(options={})
724 order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',')
725 order_option = nil if order_option.blank?
726
727 Issue.visible.scoped(:conditions => options[:conditions]).scoped(:include => ([:status, :project] + (options[:include] || [])).uniq,
728 :conditions => statement,
729 :order => order_option,
730 :joins => joins_for_order_statement(order_option),
731 :limit => options[:limit],
732 :offset => options[:offset]).find_ids
733 rescue ::ActiveRecord::StatementInvalid => e
734 raise StatementInvalid.new(e.message)
735 end
736
737 # Returns the journals
738 # Valid options are :order, :offset, :limit
739 def journals(options={})
740 Journal.visible.all(
741 :include => [:details, :user, {:issue => [:project, :author, :tracker, :status]}],
742 :conditions => statement,
743 :order => options[:order],
744 :limit => options[:limit],
745 :offset => options[:offset]
746 )
747 rescue ::ActiveRecord::StatementInvalid => e
748 raise StatementInvalid.new(e.message)
749 end
750
751 # Returns the versions
752 # Valid options are :conditions
753 def versions(options={})
754 Version.visible.where(options[:conditions]).all(
755 :include => :project,
756 :conditions => project_statement
757 )
758 rescue ::ActiveRecord::StatementInvalid => e
759 raise StatementInvalid.new(e.message)
760 end
761
762 def sql_for_watcher_id_field(field, operator, value)
466 def sql_for_watcher_id_field(field, operator, value)
763 db_table = Watcher.table_name
467 db_table = Watcher.table_name
764 "#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (SELECT #{db_table}.watchable_id FROM #{db_table} WHERE #{db_table}.watchable_type='Issue' AND " +
468 "#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (SELECT #{db_table}.watchable_id FROM #{db_table} WHERE #{db_table}.watchable_type='Issue' AND " +
@@ -24,7 +24,7
24 <legend><%= l(:setting_issue_list_default_columns) %></legend>
24 <legend><%= l(:setting_issue_list_default_columns) %></legend>
25 <%= render :partial => 'queries/columns',
25 <%= render :partial => 'queries/columns',
26 :locals => {
26 :locals => {
27 :query => Query.new(:column_names => Setting.issue_list_default_columns),
27 :query => IssueQuery.new(:column_names => Setting.issue_list_default_columns),
28 :tag_name => 'settings[issue_list_default_columns][]'
28 :tag_name => 'settings[issue_list_default_columns][]'
29 } %>
29 } %>
30 </fieldset>
30 </fieldset>
@@ -1,6 +1,7
1 ---
1 ---
2 queries_001:
2 queries_001:
3 id: 1
3 id: 1
4 type: IssueQuery
4 project_id: 1
5 project_id: 1
5 is_public: true
6 is_public: true
6 name: Multiple custom fields query
7 name: Multiple custom fields query
@@ -23,6 +24,7 queries_001:
23 column_names:
24 column_names:
24 queries_002:
25 queries_002:
25 id: 2
26 id: 2
27 type: IssueQuery
26 project_id: 1
28 project_id: 1
27 is_public: false
29 is_public: false
28 name: Private query for cookbook
30 name: Private query for cookbook
@@ -41,6 +43,7 queries_002:
41 column_names:
43 column_names:
42 queries_003:
44 queries_003:
43 id: 3
45 id: 3
46 type: IssueQuery
44 project_id:
47 project_id:
45 is_public: false
48 is_public: false
46 name: Private query for all projects
49 name: Private query for all projects
@@ -55,6 +58,7 queries_003:
55 column_names:
58 column_names:
56 queries_004:
59 queries_004:
57 id: 4
60 id: 4
61 type: IssueQuery
58 project_id:
62 project_id:
59 is_public: true
63 is_public: true
60 name: Public query for all projects
64 name: Public query for all projects
@@ -69,6 +73,7 queries_004:
69 column_names:
73 column_names:
70 queries_005:
74 queries_005:
71 id: 5
75 id: 5
76 type: IssueQuery
72 project_id:
77 project_id:
73 is_public: true
78 is_public: true
74 name: Open issues by priority and tracker
79 name: Open issues by priority and tracker
@@ -89,6 +94,7 queries_005:
89 - asc
94 - asc
90 queries_006:
95 queries_006:
91 id: 6
96 id: 6
97 type: IssueQuery
92 project_id:
98 project_id:
93 is_public: true
99 is_public: true
94 name: Open issues grouped by tracker
100 name: Open issues grouped by tracker
@@ -108,6 +114,7 queries_006:
108 - desc
114 - desc
109 queries_007:
115 queries_007:
110 id: 7
116 id: 7
117 type: IssueQuery
111 project_id: 2
118 project_id: 2
112 is_public: true
119 is_public: true
113 name: Public query for project 2
120 name: Public query for project 2
@@ -122,6 +129,7 queries_007:
122 column_names:
129 column_names:
123 queries_008:
130 queries_008:
124 id: 8
131 id: 8
132 type: IssueQuery
125 project_id: 2
133 project_id: 2
126 is_public: false
134 is_public: false
127 name: Private query for project 2
135 name: Private query for project 2
@@ -136,6 +144,7 queries_008:
136 column_names:
144 column_names:
137 queries_009:
145 queries_009:
138 id: 9
146 id: 9
147 type: IssueQuery
139 project_id:
148 project_id:
140 is_public: true
149 is_public: true
141 name: Open issues grouped by list custom field
150 name: Open issues grouped by list custom field
@@ -42,7 +42,7 class CalendarsControllerTest < ActionController::TestCase
42
42
43 context "GET :show" do
43 context "GET :show" do
44 should "run custom queries" do
44 should "run custom queries" do
45 @query = Query.create!(:name => 'Calendar', :is_public => true)
45 @query = IssueQuery.create!(:name => 'Calendar', :is_public => true)
46
46
47 get :show, :query_id => @query.id
47 get :show, :query_id => @query.id
48 assert_response :success
48 assert_response :success
@@ -327,7 +327,7 class IssuesControllerTest < ActionController::TestCase
327 end
327 end
328
328
329 def test_index_with_cross_project_query_in_session_should_show_project_issues
329 def test_index_with_cross_project_query_in_session_should_show_project_issues
330 q = Query.create!(:name => "test", :user_id => 2, :is_public => false, :project => nil)
330 q = IssueQuery.create!(:name => "test", :user_id => 2, :is_public => false, :project => nil)
331 @request.session[:query] = {:id => q.id, :project_id => 1}
331 @request.session[:query] = {:id => q.id, :project_id => 1}
332
332
333 with_settings :display_subprojects_issues => '0' do
333 with_settings :display_subprojects_issues => '0' do
@@ -341,7 +341,7 class IssuesControllerTest < ActionController::TestCase
341 end
341 end
342
342
343 def test_private_query_should_not_be_available_to_other_users
343 def test_private_query_should_not_be_available_to_other_users
344 q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
344 q = IssueQuery.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
345 @request.session[:user_id] = 3
345 @request.session[:user_id] = 3
346
346
347 get :index, :query_id => q.id
347 get :index, :query_id => q.id
@@ -349,7 +349,7 class IssuesControllerTest < ActionController::TestCase
349 end
349 end
350
350
351 def test_private_query_should_be_available_to_its_user
351 def test_private_query_should_be_available_to_its_user
352 q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
352 q = IssueQuery.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
353 @request.session[:user_id] = 2
353 @request.session[:user_id] = 2
354
354
355 get :index, :query_id => q.id
355 get :index, :query_id => q.id
@@ -357,7 +357,7 class IssuesControllerTest < ActionController::TestCase
357 end
357 end
358
358
359 def test_public_query_should_be_available_to_other_users
359 def test_public_query_should_be_available_to_other_users
360 q = Query.create!(:name => "private", :user => User.find(2), :is_public => true, :project => nil)
360 q = IssueQuery.create!(:name => "private", :user => User.find(2), :is_public => true, :project => nil)
361 @request.session[:user_id] = 3
361 @request.session[:user_id] = 3
362
362
363 get :index, :query_id => q.id
363 get :index, :query_id => q.id
@@ -666,7 +666,7 class IssuesControllerTest < ActionController::TestCase
666
666
667 # query should use specified columns
667 # query should use specified columns
668 query = assigns(:query)
668 query = assigns(:query)
669 assert_kind_of Query, query
669 assert_kind_of IssueQuery, query
670 assert_equal columns, query.column_names.map(&:to_s)
670 assert_equal columns, query.column_names.map(&:to_s)
671
671
672 # columns should be stored in session
672 # columns should be stored in session
@@ -688,7 +688,7 class IssuesControllerTest < ActionController::TestCase
688
688
689 # query should use specified columns
689 # query should use specified columns
690 query = assigns(:query)
690 query = assigns(:query)
691 assert_kind_of Query, query
691 assert_kind_of IssueQuery, query
692 assert_equal [:project, :tracker, :subject, :assigned_to], query.columns.map(&:name)
692 assert_equal [:project, :tracker, :subject, :assigned_to], query.columns.map(&:name)
693 end
693 end
694
694
@@ -699,7 +699,7 class IssuesControllerTest < ActionController::TestCase
699
699
700 # query should use specified columns
700 # query should use specified columns
701 query = assigns(:query)
701 query = assigns(:query)
702 assert_kind_of Query, query
702 assert_kind_of IssueQuery, query
703 assert_equal columns.map(&:to_sym), query.columns.map(&:name)
703 assert_equal columns.map(&:to_sym), query.columns.map(&:name)
704 end
704 end
705
705
@@ -710,7 +710,7 class IssuesControllerTest < ActionController::TestCase
710
710
711 # query should use specified columns
711 # query should use specified columns
712 query = assigns(:query)
712 query = assigns(:query)
713 assert_kind_of Query, query
713 assert_kind_of IssueQuery, query
714 assert_equal columns, query.column_names.map(&:to_s)
714 assert_equal columns, query.column_names.map(&:to_s)
715
715
716 assert_select 'table.issues td.cf_2.string'
716 assert_select 'table.issues td.cf_2.string'
@@ -1136,7 +1136,7 class IssuesControllerTest < ActionController::TestCase
1136 end
1136 end
1137
1137
1138 def test_show_should_display_prev_next_links_with_saved_query_in_session
1138 def test_show_should_display_prev_next_links_with_saved_query_in_session
1139 query = Query.create!(:name => 'test', :is_public => true, :user_id => 1,
1139 query = IssueQuery.create!(:name => 'test', :is_public => true, :user_id => 1,
1140 :filters => {'status_id' => {:values => ['5'], :operator => '='}},
1140 :filters => {'status_id' => {:values => ['5'], :operator => '='}},
1141 :sort_criteria => [['id', 'asc']])
1141 :sort_criteria => [['id', 'asc']])
1142 @request.session[:query] = {:id => query.id, :project_id => nil}
1142 @request.session[:query] = {:id => query.id, :project_id => nil}
@@ -1228,7 +1228,7 class IssuesControllerTest < ActionController::TestCase
1228 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
1228 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
1229 CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
1229 CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
1230
1230
1231 query = Query.create!(:name => 'test', :is_public => true, :user_id => 1, :filters => {},
1231 query = IssueQuery.create!(:name => 'test', :is_public => true, :user_id => 1, :filters => {},
1232 :sort_criteria => [["cf_#{cf.id}", 'asc'], ['id', 'asc']])
1232 :sort_criteria => [["cf_#{cf.id}", 'asc'], ['id', 'asc']])
1233 @request.session[:query] = {:id => query.id, :project_id => nil}
1233 @request.session[:query] = {:id => query.id, :project_id => nil}
1234
1234
@@ -252,7 +252,7 class IssuesControllerTransactionTest < ActionController::TestCase
252 end
252 end
253
253
254 def test_index_should_rescue_invalid_sql_query
254 def test_index_should_rescue_invalid_sql_query
255 Query.any_instance.stubs(:statement).returns("INVALID STATEMENT")
255 IssueQuery.any_instance.stubs(:statement).returns("INVALID STATEMENT")
256
256
257 get :index
257 get :index
258 assert_response 500
258 assert_response 500
@@ -31,7 +31,7 class QueriesHelperTest < ActionView::TestCase
31
31
32 def test_order
32 def test_order
33 User.current = User.find_by_login('admin')
33 User.current = User.find_by_login('admin')
34 query = Query.new(:project => nil, :name => '_')
34 query = IssueQuery.new(:project => nil, :name => '_')
35 assert_equal 30, query.available_filters.size
35 assert_equal 30, query.available_filters.size
36 fo = filters_options(query)
36 fo = filters_options(query)
37 assert_equal 31, fo.size
37 assert_equal 31, fo.size
@@ -52,7 +52,7 class QueriesHelperTest < ActionView::TestCase
52 )
52 )
53 assert field.save
53 assert field.save
54 User.current = User.find_by_login('admin')
54 User.current = User.find_by_login('admin')
55 query = Query.new(:project => nil, :name => '_')
55 query = IssueQuery.new(:project => nil, :name => '_')
56 assert_equal 32, query.available_filters.size
56 assert_equal 32, query.available_filters.size
57 fo = filters_options(query)
57 fo = filters_options(query)
58 assert_equal 33, fo.size
58 assert_equal 33, fo.size
@@ -50,7 +50,7 class Redmine::Helpers::GanttHelperTest < ActionView::TestCase
50 @project = project
50 @project = project
51 @gantt = Redmine::Helpers::Gantt.new(options)
51 @gantt = Redmine::Helpers::Gantt.new(options)
52 @gantt.project = @project
52 @gantt.project = @project
53 @gantt.query = Query.create!(:project => @project, :name => 'Gantt')
53 @gantt.query = IssueQuery.create!(:project => @project, :name => 'Gantt')
54 @gantt.view = self
54 @gantt.view = self
55 @gantt.instance_variable_set('@date_from', options[:date_from] || (today - 14))
55 @gantt.instance_variable_set('@date_from', options[:date_from] || (today - 14))
56 @gantt.instance_variable_set('@date_to', options[:date_to] || (today + 14))
56 @gantt.instance_variable_set('@date_to', options[:date_to] || (today + 14))
@@ -29,20 +29,20 class QueryTest < ActiveSupport::TestCase
29 :custom_fields_trackers
29 :custom_fields_trackers
30
30
31 def test_custom_fields_for_all_projects_should_be_available_in_global_queries
31 def test_custom_fields_for_all_projects_should_be_available_in_global_queries
32 query = Query.new(:project => nil, :name => '_')
32 query = IssueQuery.new(:project => nil, :name => '_')
33 assert query.available_filters.has_key?('cf_1')
33 assert query.available_filters.has_key?('cf_1')
34 assert !query.available_filters.has_key?('cf_3')
34 assert !query.available_filters.has_key?('cf_3')
35 end
35 end
36
36
37 def test_system_shared_versions_should_be_available_in_global_queries
37 def test_system_shared_versions_should_be_available_in_global_queries
38 Version.find(2).update_attribute :sharing, 'system'
38 Version.find(2).update_attribute :sharing, 'system'
39 query = Query.new(:project => nil, :name => '_')
39 query = IssueQuery.new(:project => nil, :name => '_')
40 assert query.available_filters.has_key?('fixed_version_id')
40 assert query.available_filters.has_key?('fixed_version_id')
41 assert query.available_filters['fixed_version_id'][:values].detect {|v| v.last == '2'}
41 assert query.available_filters['fixed_version_id'][:values].detect {|v| v.last == '2'}
42 end
42 end
43
43
44 def test_project_filter_in_global_queries
44 def test_project_filter_in_global_queries
45 query = Query.new(:project => nil, :name => '_')
45 query = IssueQuery.new(:project => nil, :name => '_')
46 project_filter = query.available_filters["project_id"]
46 project_filter = query.available_filters["project_id"]
47 assert_not_nil project_filter
47 assert_not_nil project_filter
48 project_ids = project_filter[:values].map{|p| p[1]}
48 project_ids = project_filter[:values].map{|p| p[1]}
@@ -75,14 +75,14 class QueryTest < ActiveSupport::TestCase
75
75
76 def test_query_should_allow_shared_versions_for_a_project_query
76 def test_query_should_allow_shared_versions_for_a_project_query
77 subproject_version = Version.find(4)
77 subproject_version = Version.find(4)
78 query = Query.new(:project => Project.find(1), :name => '_')
78 query = IssueQuery.new(:project => Project.find(1), :name => '_')
79 query.add_filter('fixed_version_id', '=', [subproject_version.id.to_s])
79 query.add_filter('fixed_version_id', '=', [subproject_version.id.to_s])
80
80
81 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IN ('4')")
81 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IN ('4')")
82 end
82 end
83
83
84 def test_query_with_multiple_custom_fields
84 def test_query_with_multiple_custom_fields
85 query = Query.find(1)
85 query = IssueQuery.find(1)
86 assert query.valid?
86 assert query.valid?
87 assert query.statement.include?("#{CustomValue.table_name}.value IN ('MySQL')")
87 assert query.statement.include?("#{CustomValue.table_name}.value IN ('MySQL')")
88 issues = find_issues_with_query(query)
88 issues = find_issues_with_query(query)
@@ -91,7 +91,7 class QueryTest < ActiveSupport::TestCase
91 end
91 end
92
92
93 def test_operator_none
93 def test_operator_none
94 query = Query.new(:project => Project.find(1), :name => '_')
94 query = IssueQuery.new(:project => Project.find(1), :name => '_')
95 query.add_filter('fixed_version_id', '!*', [''])
95 query.add_filter('fixed_version_id', '!*', [''])
96 query.add_filter('cf_1', '!*', [''])
96 query.add_filter('cf_1', '!*', [''])
97 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NULL")
97 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NULL")
@@ -100,7 +100,7 class QueryTest < ActiveSupport::TestCase
100 end
100 end
101
101
102 def test_operator_none_for_integer
102 def test_operator_none_for_integer
103 query = Query.new(:project => Project.find(1), :name => '_')
103 query = IssueQuery.new(:project => Project.find(1), :name => '_')
104 query.add_filter('estimated_hours', '!*', [''])
104 query.add_filter('estimated_hours', '!*', [''])
105 issues = find_issues_with_query(query)
105 issues = find_issues_with_query(query)
106 assert !issues.empty?
106 assert !issues.empty?
@@ -108,7 +108,7 class QueryTest < ActiveSupport::TestCase
108 end
108 end
109
109
110 def test_operator_none_for_date
110 def test_operator_none_for_date
111 query = Query.new(:project => Project.find(1), :name => '_')
111 query = IssueQuery.new(:project => Project.find(1), :name => '_')
112 query.add_filter('start_date', '!*', [''])
112 query.add_filter('start_date', '!*', [''])
113 issues = find_issues_with_query(query)
113 issues = find_issues_with_query(query)
114 assert !issues.empty?
114 assert !issues.empty?
@@ -116,7 +116,7 class QueryTest < ActiveSupport::TestCase
116 end
116 end
117
117
118 def test_operator_none_for_string_custom_field
118 def test_operator_none_for_string_custom_field
119 query = Query.new(:project => Project.find(1), :name => '_')
119 query = IssueQuery.new(:project => Project.find(1), :name => '_')
120 query.add_filter('cf_2', '!*', [''])
120 query.add_filter('cf_2', '!*', [''])
121 assert query.has_filter?('cf_2')
121 assert query.has_filter?('cf_2')
122 issues = find_issues_with_query(query)
122 issues = find_issues_with_query(query)
@@ -125,7 +125,7 class QueryTest < ActiveSupport::TestCase
125 end
125 end
126
126
127 def test_operator_all
127 def test_operator_all
128 query = Query.new(:project => Project.find(1), :name => '_')
128 query = IssueQuery.new(:project => Project.find(1), :name => '_')
129 query.add_filter('fixed_version_id', '*', [''])
129 query.add_filter('fixed_version_id', '*', [''])
130 query.add_filter('cf_1', '*', [''])
130 query.add_filter('cf_1', '*', [''])
131 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NOT NULL")
131 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NOT NULL")
@@ -134,7 +134,7 class QueryTest < ActiveSupport::TestCase
134 end
134 end
135
135
136 def test_operator_all_for_date
136 def test_operator_all_for_date
137 query = Query.new(:project => Project.find(1), :name => '_')
137 query = IssueQuery.new(:project => Project.find(1), :name => '_')
138 query.add_filter('start_date', '*', [''])
138 query.add_filter('start_date', '*', [''])
139 issues = find_issues_with_query(query)
139 issues = find_issues_with_query(query)
140 assert !issues.empty?
140 assert !issues.empty?
@@ -142,7 +142,7 class QueryTest < ActiveSupport::TestCase
142 end
142 end
143
143
144 def test_operator_all_for_string_custom_field
144 def test_operator_all_for_string_custom_field
145 query = Query.new(:project => Project.find(1), :name => '_')
145 query = IssueQuery.new(:project => Project.find(1), :name => '_')
146 query.add_filter('cf_2', '*', [''])
146 query.add_filter('cf_2', '*', [''])
147 assert query.has_filter?('cf_2')
147 assert query.has_filter?('cf_2')
148 issues = find_issues_with_query(query)
148 issues = find_issues_with_query(query)
@@ -151,7 +151,7 class QueryTest < ActiveSupport::TestCase
151 end
151 end
152
152
153 def test_numeric_filter_should_not_accept_non_numeric_values
153 def test_numeric_filter_should_not_accept_non_numeric_values
154 query = Query.new(:name => '_')
154 query = IssueQuery.new(:name => '_')
155 query.add_filter('estimated_hours', '=', ['a'])
155 query.add_filter('estimated_hours', '=', ['a'])
156
156
157 assert query.has_filter?('estimated_hours')
157 assert query.has_filter?('estimated_hours')
@@ -161,7 +161,7 class QueryTest < ActiveSupport::TestCase
161 def test_operator_is_on_float
161 def test_operator_is_on_float
162 Issue.update_all("estimated_hours = 171.2", "id=2")
162 Issue.update_all("estimated_hours = 171.2", "id=2")
163
163
164 query = Query.new(:name => '_')
164 query = IssueQuery.new(:name => '_')
165 query.add_filter('estimated_hours', '=', ['171.20'])
165 query.add_filter('estimated_hours', '=', ['171.20'])
166 issues = find_issues_with_query(query)
166 issues = find_issues_with_query(query)
167 assert_equal 1, issues.size
167 assert_equal 1, issues.size
@@ -174,7 +174,7 class QueryTest < ActiveSupport::TestCase
174 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12')
174 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12')
175 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
175 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
176
176
177 query = Query.new(:name => '_')
177 query = IssueQuery.new(:name => '_')
178 query.add_filter("cf_#{f.id}", '=', ['12'])
178 query.add_filter("cf_#{f.id}", '=', ['12'])
179 issues = find_issues_with_query(query)
179 issues = find_issues_with_query(query)
180 assert_equal 1, issues.size
180 assert_equal 1, issues.size
@@ -187,7 +187,7 class QueryTest < ActiveSupport::TestCase
187 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '-12')
187 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '-12')
188 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
188 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
189
189
190 query = Query.new(:name => '_')
190 query = IssueQuery.new(:name => '_')
191 query.add_filter("cf_#{f.id}", '=', ['-12'])
191 query.add_filter("cf_#{f.id}", '=', ['-12'])
192 assert query.valid?
192 assert query.valid?
193 issues = find_issues_with_query(query)
193 issues = find_issues_with_query(query)
@@ -201,7 +201,7 class QueryTest < ActiveSupport::TestCase
201 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12.7')
201 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12.7')
202 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
202 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
203
203
204 query = Query.new(:name => '_')
204 query = IssueQuery.new(:name => '_')
205 query.add_filter("cf_#{f.id}", '=', ['12.7'])
205 query.add_filter("cf_#{f.id}", '=', ['12.7'])
206 issues = find_issues_with_query(query)
206 issues = find_issues_with_query(query)
207 assert_equal 1, issues.size
207 assert_equal 1, issues.size
@@ -214,7 +214,7 class QueryTest < ActiveSupport::TestCase
214 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '-12.7')
214 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '-12.7')
215 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
215 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
216
216
217 query = Query.new(:name => '_')
217 query = IssueQuery.new(:name => '_')
218 query.add_filter("cf_#{f.id}", '=', ['-12.7'])
218 query.add_filter("cf_#{f.id}", '=', ['-12.7'])
219 assert query.valid?
219 assert query.valid?
220 issues = find_issues_with_query(query)
220 issues = find_issues_with_query(query)
@@ -229,12 +229,12 class QueryTest < ActiveSupport::TestCase
229 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value2')
229 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value2')
230 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => 'value1')
230 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => 'value1')
231
231
232 query = Query.new(:name => '_')
232 query = IssueQuery.new(:name => '_')
233 query.add_filter("cf_#{f.id}", '=', ['value1'])
233 query.add_filter("cf_#{f.id}", '=', ['value1'])
234 issues = find_issues_with_query(query)
234 issues = find_issues_with_query(query)
235 assert_equal [1, 3], issues.map(&:id).sort
235 assert_equal [1, 3], issues.map(&:id).sort
236
236
237 query = Query.new(:name => '_')
237 query = IssueQuery.new(:name => '_')
238 query.add_filter("cf_#{f.id}", '=', ['value2'])
238 query.add_filter("cf_#{f.id}", '=', ['value2'])
239 issues = find_issues_with_query(query)
239 issues = find_issues_with_query(query)
240 assert_equal [1], issues.map(&:id).sort
240 assert_equal [1], issues.map(&:id).sort
@@ -247,13 +247,13 class QueryTest < ActiveSupport::TestCase
247 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value2')
247 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value2')
248 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => 'value1')
248 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => 'value1')
249
249
250 query = Query.new(:name => '_')
250 query = IssueQuery.new(:name => '_')
251 query.add_filter("cf_#{f.id}", '!', ['value1'])
251 query.add_filter("cf_#{f.id}", '!', ['value1'])
252 issues = find_issues_with_query(query)
252 issues = find_issues_with_query(query)
253 assert !issues.map(&:id).include?(1)
253 assert !issues.map(&:id).include?(1)
254 assert !issues.map(&:id).include?(3)
254 assert !issues.map(&:id).include?(3)
255
255
256 query = Query.new(:name => '_')
256 query = IssueQuery.new(:name => '_')
257 query.add_filter("cf_#{f.id}", '!', ['value2'])
257 query.add_filter("cf_#{f.id}", '!', ['value2'])
258 issues = find_issues_with_query(query)
258 issues = find_issues_with_query(query)
259 assert !issues.map(&:id).include?(1)
259 assert !issues.map(&:id).include?(1)
@@ -264,7 +264,7 class QueryTest < ActiveSupport::TestCase
264 # is_private filter only available for those who can set issues private
264 # is_private filter only available for those who can set issues private
265 User.current = User.find(2)
265 User.current = User.find(2)
266
266
267 query = Query.new(:name => '_')
267 query = IssueQuery.new(:name => '_')
268 assert query.available_filters.key?('is_private')
268 assert query.available_filters.key?('is_private')
269
269
270 query.add_filter("is_private", '=', ['1'])
270 query.add_filter("is_private", '=', ['1'])
@@ -279,7 +279,7 class QueryTest < ActiveSupport::TestCase
279 # is_private filter only available for those who can set issues private
279 # is_private filter only available for those who can set issues private
280 User.current = User.find(2)
280 User.current = User.find(2)
281
281
282 query = Query.new(:name => '_')
282 query = IssueQuery.new(:name => '_')
283 assert query.available_filters.key?('is_private')
283 assert query.available_filters.key?('is_private')
284
284
285 query.add_filter("is_private", '!', ['1'])
285 query.add_filter("is_private", '!', ['1'])
@@ -291,14 +291,14 class QueryTest < ActiveSupport::TestCase
291 end
291 end
292
292
293 def test_operator_greater_than
293 def test_operator_greater_than
294 query = Query.new(:project => Project.find(1), :name => '_')
294 query = IssueQuery.new(:project => Project.find(1), :name => '_')
295 query.add_filter('done_ratio', '>=', ['40'])
295 query.add_filter('done_ratio', '>=', ['40'])
296 assert query.statement.include?("#{Issue.table_name}.done_ratio >= 40.0")
296 assert query.statement.include?("#{Issue.table_name}.done_ratio >= 40.0")
297 find_issues_with_query(query)
297 find_issues_with_query(query)
298 end
298 end
299
299
300 def test_operator_greater_than_a_float
300 def test_operator_greater_than_a_float
301 query = Query.new(:project => Project.find(1), :name => '_')
301 query = IssueQuery.new(:project => Project.find(1), :name => '_')
302 query.add_filter('estimated_hours', '>=', ['40.5'])
302 query.add_filter('estimated_hours', '>=', ['40.5'])
303 assert query.statement.include?("#{Issue.table_name}.estimated_hours >= 40.5")
303 assert query.statement.include?("#{Issue.table_name}.estimated_hours >= 40.5")
304 find_issues_with_query(query)
304 find_issues_with_query(query)
@@ -310,7 +310,7 class QueryTest < ActiveSupport::TestCase
310 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12')
310 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12')
311 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
311 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
312
312
313 query = Query.new(:project => Project.find(1), :name => '_')
313 query = IssueQuery.new(:project => Project.find(1), :name => '_')
314 query.add_filter("cf_#{f.id}", '>=', ['8'])
314 query.add_filter("cf_#{f.id}", '>=', ['8'])
315 issues = find_issues_with_query(query)
315 issues = find_issues_with_query(query)
316 assert_equal 1, issues.size
316 assert_equal 1, issues.size
@@ -318,7 +318,7 class QueryTest < ActiveSupport::TestCase
318 end
318 end
319
319
320 def test_operator_lesser_than
320 def test_operator_lesser_than
321 query = Query.new(:project => Project.find(1), :name => '_')
321 query = IssueQuery.new(:project => Project.find(1), :name => '_')
322 query.add_filter('done_ratio', '<=', ['30'])
322 query.add_filter('done_ratio', '<=', ['30'])
323 assert query.statement.include?("#{Issue.table_name}.done_ratio <= 30.0")
323 assert query.statement.include?("#{Issue.table_name}.done_ratio <= 30.0")
324 find_issues_with_query(query)
324 find_issues_with_query(query)
@@ -326,14 +326,14 class QueryTest < ActiveSupport::TestCase
326
326
327 def test_operator_lesser_than_on_custom_field
327 def test_operator_lesser_than_on_custom_field
328 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
328 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
329 query = Query.new(:project => Project.find(1), :name => '_')
329 query = IssueQuery.new(:project => Project.find(1), :name => '_')
330 query.add_filter("cf_#{f.id}", '<=', ['30'])
330 query.add_filter("cf_#{f.id}", '<=', ['30'])
331 assert query.statement.include?("CAST(custom_values.value AS decimal(60,3)) <= 30.0")
331 assert query.statement.include?("CAST(custom_values.value AS decimal(60,3)) <= 30.0")
332 find_issues_with_query(query)
332 find_issues_with_query(query)
333 end
333 end
334
334
335 def test_operator_between
335 def test_operator_between
336 query = Query.new(:project => Project.find(1), :name => '_')
336 query = IssueQuery.new(:project => Project.find(1), :name => '_')
337 query.add_filter('done_ratio', '><', ['30', '40'])
337 query.add_filter('done_ratio', '><', ['30', '40'])
338 assert_include "#{Issue.table_name}.done_ratio BETWEEN 30.0 AND 40.0", query.statement
338 assert_include "#{Issue.table_name}.done_ratio BETWEEN 30.0 AND 40.0", query.statement
339 find_issues_with_query(query)
339 find_issues_with_query(query)
@@ -341,14 +341,14 class QueryTest < ActiveSupport::TestCase
341
341
342 def test_operator_between_on_custom_field
342 def test_operator_between_on_custom_field
343 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
343 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
344 query = Query.new(:project => Project.find(1), :name => '_')
344 query = IssueQuery.new(:project => Project.find(1), :name => '_')
345 query.add_filter("cf_#{f.id}", '><', ['30', '40'])
345 query.add_filter("cf_#{f.id}", '><', ['30', '40'])
346 assert_include "CAST(custom_values.value AS decimal(60,3)) BETWEEN 30.0 AND 40.0", query.statement
346 assert_include "CAST(custom_values.value AS decimal(60,3)) BETWEEN 30.0 AND 40.0", query.statement
347 find_issues_with_query(query)
347 find_issues_with_query(query)
348 end
348 end
349
349
350 def test_date_filter_should_not_accept_non_date_values
350 def test_date_filter_should_not_accept_non_date_values
351 query = Query.new(:name => '_')
351 query = IssueQuery.new(:name => '_')
352 query.add_filter('created_on', '=', ['a'])
352 query.add_filter('created_on', '=', ['a'])
353
353
354 assert query.has_filter?('created_on')
354 assert query.has_filter?('created_on')
@@ -356,7 +356,7 class QueryTest < ActiveSupport::TestCase
356 end
356 end
357
357
358 def test_date_filter_should_not_accept_invalid_date_values
358 def test_date_filter_should_not_accept_invalid_date_values
359 query = Query.new(:name => '_')
359 query = IssueQuery.new(:name => '_')
360 query.add_filter('created_on', '=', ['2011-01-34'])
360 query.add_filter('created_on', '=', ['2011-01-34'])
361
361
362 assert query.has_filter?('created_on')
362 assert query.has_filter?('created_on')
@@ -364,7 +364,7 class QueryTest < ActiveSupport::TestCase
364 end
364 end
365
365
366 def test_relative_date_filter_should_not_accept_non_integer_values
366 def test_relative_date_filter_should_not_accept_non_integer_values
367 query = Query.new(:name => '_')
367 query = IssueQuery.new(:name => '_')
368 query.add_filter('created_on', '>t-', ['a'])
368 query.add_filter('created_on', '>t-', ['a'])
369
369
370 assert query.has_filter?('created_on')
370 assert query.has_filter?('created_on')
@@ -372,28 +372,28 class QueryTest < ActiveSupport::TestCase
372 end
372 end
373
373
374 def test_operator_date_equals
374 def test_operator_date_equals
375 query = Query.new(:name => '_')
375 query = IssueQuery.new(:name => '_')
376 query.add_filter('due_date', '=', ['2011-07-10'])
376 query.add_filter('due_date', '=', ['2011-07-10'])
377 assert_match /issues\.due_date > '2011-07-09 23:59:59(\.9+)?' AND issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement
377 assert_match /issues\.due_date > '2011-07-09 23:59:59(\.9+)?' AND issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement
378 find_issues_with_query(query)
378 find_issues_with_query(query)
379 end
379 end
380
380
381 def test_operator_date_lesser_than
381 def test_operator_date_lesser_than
382 query = Query.new(:name => '_')
382 query = IssueQuery.new(:name => '_')
383 query.add_filter('due_date', '<=', ['2011-07-10'])
383 query.add_filter('due_date', '<=', ['2011-07-10'])
384 assert_match /issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement
384 assert_match /issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement
385 find_issues_with_query(query)
385 find_issues_with_query(query)
386 end
386 end
387
387
388 def test_operator_date_greater_than
388 def test_operator_date_greater_than
389 query = Query.new(:name => '_')
389 query = IssueQuery.new(:name => '_')
390 query.add_filter('due_date', '>=', ['2011-07-10'])
390 query.add_filter('due_date', '>=', ['2011-07-10'])
391 assert_match /issues\.due_date > '2011-07-09 23:59:59(\.9+)?'/, query.statement
391 assert_match /issues\.due_date > '2011-07-09 23:59:59(\.9+)?'/, query.statement
392 find_issues_with_query(query)
392 find_issues_with_query(query)
393 end
393 end
394
394
395 def test_operator_date_between
395 def test_operator_date_between
396 query = Query.new(:name => '_')
396 query = IssueQuery.new(:name => '_')
397 query.add_filter('due_date', '><', ['2011-06-23', '2011-07-10'])
397 query.add_filter('due_date', '><', ['2011-06-23', '2011-07-10'])
398 assert_match /issues\.due_date > '2011-06-22 23:59:59(\.9+)?' AND issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement
398 assert_match /issues\.due_date > '2011-06-22 23:59:59(\.9+)?' AND issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement
399 find_issues_with_query(query)
399 find_issues_with_query(query)
@@ -401,7 +401,7 class QueryTest < ActiveSupport::TestCase
401
401
402 def test_operator_in_more_than
402 def test_operator_in_more_than
403 Issue.find(7).update_attribute(:due_date, (Date.today + 15))
403 Issue.find(7).update_attribute(:due_date, (Date.today + 15))
404 query = Query.new(:project => Project.find(1), :name => '_')
404 query = IssueQuery.new(:project => Project.find(1), :name => '_')
405 query.add_filter('due_date', '>t+', ['15'])
405 query.add_filter('due_date', '>t+', ['15'])
406 issues = find_issues_with_query(query)
406 issues = find_issues_with_query(query)
407 assert !issues.empty?
407 assert !issues.empty?
@@ -409,7 +409,7 class QueryTest < ActiveSupport::TestCase
409 end
409 end
410
410
411 def test_operator_in_less_than
411 def test_operator_in_less_than
412 query = Query.new(:project => Project.find(1), :name => '_')
412 query = IssueQuery.new(:project => Project.find(1), :name => '_')
413 query.add_filter('due_date', '<t+', ['15'])
413 query.add_filter('due_date', '<t+', ['15'])
414 issues = find_issues_with_query(query)
414 issues = find_issues_with_query(query)
415 assert !issues.empty?
415 assert !issues.empty?
@@ -417,7 +417,7 class QueryTest < ActiveSupport::TestCase
417 end
417 end
418
418
419 def test_operator_in_the_next_days
419 def test_operator_in_the_next_days
420 query = Query.new(:project => Project.find(1), :name => '_')
420 query = IssueQuery.new(:project => Project.find(1), :name => '_')
421 query.add_filter('due_date', '><t+', ['15'])
421 query.add_filter('due_date', '><t+', ['15'])
422 issues = find_issues_with_query(query)
422 issues = find_issues_with_query(query)
423 assert !issues.empty?
423 assert !issues.empty?
@@ -426,7 +426,7 class QueryTest < ActiveSupport::TestCase
426
426
427 def test_operator_less_than_ago
427 def test_operator_less_than_ago
428 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
428 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
429 query = Query.new(:project => Project.find(1), :name => '_')
429 query = IssueQuery.new(:project => Project.find(1), :name => '_')
430 query.add_filter('due_date', '>t-', ['3'])
430 query.add_filter('due_date', '>t-', ['3'])
431 issues = find_issues_with_query(query)
431 issues = find_issues_with_query(query)
432 assert !issues.empty?
432 assert !issues.empty?
@@ -435,7 +435,7 class QueryTest < ActiveSupport::TestCase
435
435
436 def test_operator_in_the_past_days
436 def test_operator_in_the_past_days
437 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
437 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
438 query = Query.new(:project => Project.find(1), :name => '_')
438 query = IssueQuery.new(:project => Project.find(1), :name => '_')
439 query.add_filter('due_date', '><t-', ['3'])
439 query.add_filter('due_date', '><t-', ['3'])
440 issues = find_issues_with_query(query)
440 issues = find_issues_with_query(query)
441 assert !issues.empty?
441 assert !issues.empty?
@@ -444,7 +444,7 class QueryTest < ActiveSupport::TestCase
444
444
445 def test_operator_more_than_ago
445 def test_operator_more_than_ago
446 Issue.find(7).update_attribute(:due_date, (Date.today - 10))
446 Issue.find(7).update_attribute(:due_date, (Date.today - 10))
447 query = Query.new(:project => Project.find(1), :name => '_')
447 query = IssueQuery.new(:project => Project.find(1), :name => '_')
448 query.add_filter('due_date', '<t-', ['10'])
448 query.add_filter('due_date', '<t-', ['10'])
449 assert query.statement.include?("#{Issue.table_name}.due_date <=")
449 assert query.statement.include?("#{Issue.table_name}.due_date <=")
450 issues = find_issues_with_query(query)
450 issues = find_issues_with_query(query)
@@ -454,7 +454,7 class QueryTest < ActiveSupport::TestCase
454
454
455 def test_operator_in
455 def test_operator_in
456 Issue.find(7).update_attribute(:due_date, (Date.today + 2))
456 Issue.find(7).update_attribute(:due_date, (Date.today + 2))
457 query = Query.new(:project => Project.find(1), :name => '_')
457 query = IssueQuery.new(:project => Project.find(1), :name => '_')
458 query.add_filter('due_date', 't+', ['2'])
458 query.add_filter('due_date', 't+', ['2'])
459 issues = find_issues_with_query(query)
459 issues = find_issues_with_query(query)
460 assert !issues.empty?
460 assert !issues.empty?
@@ -463,7 +463,7 class QueryTest < ActiveSupport::TestCase
463
463
464 def test_operator_ago
464 def test_operator_ago
465 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
465 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
466 query = Query.new(:project => Project.find(1), :name => '_')
466 query = IssueQuery.new(:project => Project.find(1), :name => '_')
467 query.add_filter('due_date', 't-', ['3'])
467 query.add_filter('due_date', 't-', ['3'])
468 issues = find_issues_with_query(query)
468 issues = find_issues_with_query(query)
469 assert !issues.empty?
469 assert !issues.empty?
@@ -471,7 +471,7 class QueryTest < ActiveSupport::TestCase
471 end
471 end
472
472
473 def test_operator_today
473 def test_operator_today
474 query = Query.new(:project => Project.find(1), :name => '_')
474 query = IssueQuery.new(:project => Project.find(1), :name => '_')
475 query.add_filter('due_date', 't', [''])
475 query.add_filter('due_date', 't', [''])
476 issues = find_issues_with_query(query)
476 issues = find_issues_with_query(query)
477 assert !issues.empty?
477 assert !issues.empty?
@@ -479,19 +479,19 class QueryTest < ActiveSupport::TestCase
479 end
479 end
480
480
481 def test_operator_this_week_on_date
481 def test_operator_this_week_on_date
482 query = Query.new(:project => Project.find(1), :name => '_')
482 query = IssueQuery.new(:project => Project.find(1), :name => '_')
483 query.add_filter('due_date', 'w', [''])
483 query.add_filter('due_date', 'w', [''])
484 find_issues_with_query(query)
484 find_issues_with_query(query)
485 end
485 end
486
486
487 def test_operator_this_week_on_datetime
487 def test_operator_this_week_on_datetime
488 query = Query.new(:project => Project.find(1), :name => '_')
488 query = IssueQuery.new(:project => Project.find(1), :name => '_')
489 query.add_filter('created_on', 'w', [''])
489 query.add_filter('created_on', 'w', [''])
490 find_issues_with_query(query)
490 find_issues_with_query(query)
491 end
491 end
492
492
493 def test_operator_contains
493 def test_operator_contains
494 query = Query.new(:project => Project.find(1), :name => '_')
494 query = IssueQuery.new(:project => Project.find(1), :name => '_')
495 query.add_filter('subject', '~', ['uNable'])
495 query.add_filter('subject', '~', ['uNable'])
496 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) LIKE '%unable%'")
496 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) LIKE '%unable%'")
497 result = find_issues_with_query(query)
497 result = find_issues_with_query(query)
@@ -505,7 +505,7 class QueryTest < ActiveSupport::TestCase
505
505
506 Date.stubs(:today).returns(Date.parse('2011-04-29'))
506 Date.stubs(:today).returns(Date.parse('2011-04-29'))
507
507
508 query = Query.new(:project => Project.find(1), :name => '_')
508 query = IssueQuery.new(:project => Project.find(1), :name => '_')
509 query.add_filter('due_date', 'w', [''])
509 query.add_filter('due_date', 'w', [''])
510 assert query.statement.match(/issues\.due_date > '2011-04-24 23:59:59(\.9+)?' AND issues\.due_date <= '2011-05-01 23:59:59(\.9+)?/), "range not found in #{query.statement}"
510 assert query.statement.match(/issues\.due_date > '2011-04-24 23:59:59(\.9+)?' AND issues\.due_date <= '2011-05-01 23:59:59(\.9+)?/), "range not found in #{query.statement}"
511 I18n.locale = :en
511 I18n.locale = :en
@@ -517,13 +517,13 class QueryTest < ActiveSupport::TestCase
517
517
518 Date.stubs(:today).returns(Date.parse('2011-04-29'))
518 Date.stubs(:today).returns(Date.parse('2011-04-29'))
519
519
520 query = Query.new(:project => Project.find(1), :name => '_')
520 query = IssueQuery.new(:project => Project.find(1), :name => '_')
521 query.add_filter('due_date', 'w', [''])
521 query.add_filter('due_date', 'w', [''])
522 assert query.statement.match(/issues\.due_date > '2011-04-23 23:59:59(\.9+)?' AND issues\.due_date <= '2011-04-30 23:59:59(\.9+)?/), "range not found in #{query.statement}"
522 assert query.statement.match(/issues\.due_date > '2011-04-23 23:59:59(\.9+)?' AND issues\.due_date <= '2011-04-30 23:59:59(\.9+)?/), "range not found in #{query.statement}"
523 end
523 end
524
524
525 def test_operator_does_not_contains
525 def test_operator_does_not_contains
526 query = Query.new(:project => Project.find(1), :name => '_')
526 query = IssueQuery.new(:project => Project.find(1), :name => '_')
527 query.add_filter('subject', '!~', ['uNable'])
527 query.add_filter('subject', '!~', ['uNable'])
528 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) NOT LIKE '%unable%'")
528 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) NOT LIKE '%unable%'")
529 find_issues_with_query(query)
529 find_issues_with_query(query)
@@ -538,7 +538,7 class QueryTest < ActiveSupport::TestCase
538 i3 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => Group.find(11))
538 i3 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => Group.find(11))
539 group.users << user
539 group.users << user
540
540
541 query = Query.new(:name => '_', :filters => { 'assigned_to_id' => {:operator => '=', :values => ['me']}})
541 query = IssueQuery.new(:name => '_', :filters => { 'assigned_to_id' => {:operator => '=', :values => ['me']}})
542 result = query.issues
542 result = query.issues
543 assert_equal Issue.visible.all(:conditions => {:assigned_to_id => ([2] + user.reload.group_ids)}).sort_by(&:id), result.sort_by(&:id)
543 assert_equal Issue.visible.all(:conditions => {:assigned_to_id => ([2] + user.reload.group_ids)}).sort_by(&:id), result.sort_by(&:id)
544
544
@@ -553,7 +553,7 class QueryTest < ActiveSupport::TestCase
553 issue1 = Issue.create!(:project_id => 1, :tracker_id => 1, :custom_field_values => {cf.id.to_s => '2'}, :subject => 'Test', :author_id => 1)
553 issue1 = Issue.create!(:project_id => 1, :tracker_id => 1, :custom_field_values => {cf.id.to_s => '2'}, :subject => 'Test', :author_id => 1)
554 issue2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {cf.id.to_s => '3'})
554 issue2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {cf.id.to_s => '3'})
555
555
556 query = Query.new(:name => '_', :project => Project.find(1))
556 query = IssueQuery.new(:name => '_', :project => Project.find(1))
557 filter = query.available_filters["cf_#{cf.id}"]
557 filter = query.available_filters["cf_#{cf.id}"]
558 assert_not_nil filter
558 assert_not_nil filter
559 assert_include 'me', filter[:values].map{|v| v[1]}
559 assert_include 'me', filter[:values].map{|v| v[1]}
@@ -566,7 +566,7 class QueryTest < ActiveSupport::TestCase
566
566
567 def test_filter_my_projects
567 def test_filter_my_projects
568 User.current = User.find(2)
568 User.current = User.find(2)
569 query = Query.new(:name => '_')
569 query = IssueQuery.new(:name => '_')
570 filter = query.available_filters['project_id']
570 filter = query.available_filters['project_id']
571 assert_not_nil filter
571 assert_not_nil filter
572 assert_include 'mine', filter[:values].map{|v| v[1]}
572 assert_include 'mine', filter[:values].map{|v| v[1]}
@@ -578,7 +578,7 class QueryTest < ActiveSupport::TestCase
578
578
579 def test_filter_watched_issues
579 def test_filter_watched_issues
580 User.current = User.find(1)
580 User.current = User.find(1)
581 query = Query.new(:name => '_', :filters => { 'watcher_id' => {:operator => '=', :values => ['me']}})
581 query = IssueQuery.new(:name => '_', :filters => { 'watcher_id' => {:operator => '=', :values => ['me']}})
582 result = find_issues_with_query(query)
582 result = find_issues_with_query(query)
583 assert_not_nil result
583 assert_not_nil result
584 assert !result.empty?
584 assert !result.empty?
@@ -588,7 +588,7 class QueryTest < ActiveSupport::TestCase
588
588
589 def test_filter_unwatched_issues
589 def test_filter_unwatched_issues
590 User.current = User.find(1)
590 User.current = User.find(1)
591 query = Query.new(:name => '_', :filters => { 'watcher_id' => {:operator => '!', :values => ['me']}})
591 query = IssueQuery.new(:name => '_', :filters => { 'watcher_id' => {:operator => '!', :values => ['me']}})
592 result = find_issues_with_query(query)
592 result = find_issues_with_query(query)
593 assert_not_nil result
593 assert_not_nil result
594 assert !result.empty?
594 assert !result.empty?
@@ -601,7 +601,7 class QueryTest < ActiveSupport::TestCase
601 CustomValue.create!(:custom_field => field, :customized => Project.find(3), :value => 'Foo')
601 CustomValue.create!(:custom_field => field, :customized => Project.find(3), :value => 'Foo')
602 CustomValue.create!(:custom_field => field, :customized => Project.find(5), :value => 'Foo')
602 CustomValue.create!(:custom_field => field, :customized => Project.find(5), :value => 'Foo')
603
603
604 query = Query.new(:name => '_')
604 query = IssueQuery.new(:name => '_')
605 filter_name = "project.cf_#{field.id}"
605 filter_name = "project.cf_#{field.id}"
606 assert_include filter_name, query.available_filters.keys
606 assert_include filter_name, query.available_filters.keys
607 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
607 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
@@ -612,7 +612,7 class QueryTest < ActiveSupport::TestCase
612 field = UserCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
612 field = UserCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
613 CustomValue.create!(:custom_field => field, :customized => User.find(3), :value => 'Foo')
613 CustomValue.create!(:custom_field => field, :customized => User.find(3), :value => 'Foo')
614
614
615 query = Query.new(:name => '_')
615 query = IssueQuery.new(:name => '_')
616 filter_name = "author.cf_#{field.id}"
616 filter_name = "author.cf_#{field.id}"
617 assert_include filter_name, query.available_filters.keys
617 assert_include filter_name, query.available_filters.keys
618 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
618 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
@@ -623,7 +623,7 class QueryTest < ActiveSupport::TestCase
623 field = UserCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
623 field = UserCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
624 CustomValue.create!(:custom_field => field, :customized => User.find(3), :value => 'Foo')
624 CustomValue.create!(:custom_field => field, :customized => User.find(3), :value => 'Foo')
625
625
626 query = Query.new(:name => '_')
626 query = IssueQuery.new(:name => '_')
627 filter_name = "assigned_to.cf_#{field.id}"
627 filter_name = "assigned_to.cf_#{field.id}"
628 assert_include filter_name, query.available_filters.keys
628 assert_include filter_name, query.available_filters.keys
629 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
629 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
@@ -634,7 +634,7 class QueryTest < ActiveSupport::TestCase
634 field = VersionCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
634 field = VersionCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
635 CustomValue.create!(:custom_field => field, :customized => Version.find(2), :value => 'Foo')
635 CustomValue.create!(:custom_field => field, :customized => Version.find(2), :value => 'Foo')
636
636
637 query = Query.new(:name => '_')
637 query = IssueQuery.new(:name => '_')
638 filter_name = "fixed_version.cf_#{field.id}"
638 filter_name = "fixed_version.cf_#{field.id}"
639 assert_include filter_name, query.available_filters.keys
639 assert_include filter_name, query.available_filters.keys
640 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
640 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
@@ -646,11 +646,11 class QueryTest < ActiveSupport::TestCase
646 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(2))
646 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(2))
647 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(3), :issue_to => Issue.find(1))
647 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(3), :issue_to => Issue.find(1))
648
648
649 query = Query.new(:name => '_')
649 query = IssueQuery.new(:name => '_')
650 query.filters = {"relates" => {:operator => '=', :values => ['1']}}
650 query.filters = {"relates" => {:operator => '=', :values => ['1']}}
651 assert_equal [2, 3], find_issues_with_query(query).map(&:id).sort
651 assert_equal [2, 3], find_issues_with_query(query).map(&:id).sort
652
652
653 query = Query.new(:name => '_')
653 query = IssueQuery.new(:name => '_')
654 query.filters = {"relates" => {:operator => '=', :values => ['2']}}
654 query.filters = {"relates" => {:operator => '=', :values => ['2']}}
655 assert_equal [1], find_issues_with_query(query).map(&:id).sort
655 assert_equal [1], find_issues_with_query(query).map(&:id).sort
656 end
656 end
@@ -663,15 +663,15 class QueryTest < ActiveSupport::TestCase
663 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(3).issues.first)
663 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(3).issues.first)
664 end
664 end
665
665
666 query = Query.new(:name => '_')
666 query = IssueQuery.new(:name => '_')
667 query.filters = {"relates" => {:operator => '=p', :values => ['2']}}
667 query.filters = {"relates" => {:operator => '=p', :values => ['2']}}
668 assert_equal [1, 2], find_issues_with_query(query).map(&:id).sort
668 assert_equal [1, 2], find_issues_with_query(query).map(&:id).sort
669
669
670 query = Query.new(:name => '_')
670 query = IssueQuery.new(:name => '_')
671 query.filters = {"relates" => {:operator => '=p', :values => ['3']}}
671 query.filters = {"relates" => {:operator => '=p', :values => ['3']}}
672 assert_equal [1], find_issues_with_query(query).map(&:id).sort
672 assert_equal [1], find_issues_with_query(query).map(&:id).sort
673
673
674 query = Query.new(:name => '_')
674 query = IssueQuery.new(:name => '_')
675 query.filters = {"relates" => {:operator => '=p', :values => ['4']}}
675 query.filters = {"relates" => {:operator => '=p', :values => ['4']}}
676 assert_equal [], find_issues_with_query(query).map(&:id).sort
676 assert_equal [], find_issues_with_query(query).map(&:id).sort
677 end
677 end
@@ -684,7 +684,7 class QueryTest < ActiveSupport::TestCase
684 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(3).issues.first)
684 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(3).issues.first)
685 end
685 end
686
686
687 query = Query.new(:name => '_')
687 query = IssueQuery.new(:name => '_')
688 query.filters = {"relates" => {:operator => '=!p', :values => ['1']}}
688 query.filters = {"relates" => {:operator => '=!p', :values => ['1']}}
689 assert_equal [1], find_issues_with_query(query).map(&:id).sort
689 assert_equal [1], find_issues_with_query(query).map(&:id).sort
690 end
690 end
@@ -697,7 +697,7 class QueryTest < ActiveSupport::TestCase
697 IssueRelation.create!(:relation_type => "relates", :issue_to => Project.find(2).issues.first, :issue_from => Issue.find(3))
697 IssueRelation.create!(:relation_type => "relates", :issue_to => Project.find(2).issues.first, :issue_from => Issue.find(3))
698 end
698 end
699
699
700 query = Query.new(:name => '_')
700 query = IssueQuery.new(:name => '_')
701 query.filters = {"relates" => {:operator => '!p', :values => ['2']}}
701 query.filters = {"relates" => {:operator => '!p', :values => ['2']}}
702 ids = find_issues_with_query(query).map(&:id).sort
702 ids = find_issues_with_query(query).map(&:id).sort
703 assert_include 2, ids
703 assert_include 2, ids
@@ -710,7 +710,7 class QueryTest < ActiveSupport::TestCase
710 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(2))
710 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(2))
711 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(3), :issue_to => Issue.find(1))
711 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(3), :issue_to => Issue.find(1))
712
712
713 query = Query.new(:name => '_')
713 query = IssueQuery.new(:name => '_')
714 query.filters = {"relates" => {:operator => '!*', :values => ['']}}
714 query.filters = {"relates" => {:operator => '!*', :values => ['']}}
715 ids = find_issues_with_query(query).map(&:id)
715 ids = find_issues_with_query(query).map(&:id)
716 assert_equal [], ids & [1, 2, 3]
716 assert_equal [], ids & [1, 2, 3]
@@ -722,13 +722,13 class QueryTest < ActiveSupport::TestCase
722 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(2))
722 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(2))
723 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(3), :issue_to => Issue.find(1))
723 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(3), :issue_to => Issue.find(1))
724
724
725 query = Query.new(:name => '_')
725 query = IssueQuery.new(:name => '_')
726 query.filters = {"relates" => {:operator => '*', :values => ['']}}
726 query.filters = {"relates" => {:operator => '*', :values => ['']}}
727 assert_equal [1, 2, 3], find_issues_with_query(query).map(&:id).sort
727 assert_equal [1, 2, 3], find_issues_with_query(query).map(&:id).sort
728 end
728 end
729
729
730 def test_statement_should_be_nil_with_no_filters
730 def test_statement_should_be_nil_with_no_filters
731 q = Query.new(:name => '_')
731 q = IssueQuery.new(:name => '_')
732 q.filters = {}
732 q.filters = {}
733
733
734 assert q.valid?
734 assert q.valid?
@@ -736,14 +736,14 class QueryTest < ActiveSupport::TestCase
736 end
736 end
737
737
738 def test_default_columns
738 def test_default_columns
739 q = Query.new
739 q = IssueQuery.new
740 assert q.columns.any?
740 assert q.columns.any?
741 assert q.inline_columns.any?
741 assert q.inline_columns.any?
742 assert q.block_columns.empty?
742 assert q.block_columns.empty?
743 end
743 end
744
744
745 def test_set_column_names
745 def test_set_column_names
746 q = Query.new
746 q = IssueQuery.new
747 q.column_names = ['tracker', :subject, '', 'unknonw_column']
747 q.column_names = ['tracker', :subject, '', 'unknonw_column']
748 assert_equal [:tracker, :subject], q.columns.collect {|c| c.name}
748 assert_equal [:tracker, :subject], q.columns.collect {|c| c.name}
749 c = q.columns.first
749 c = q.columns.first
@@ -751,7 +751,7 class QueryTest < ActiveSupport::TestCase
751 end
751 end
752
752
753 def test_inline_and_block_columns
753 def test_inline_and_block_columns
754 q = Query.new
754 q = IssueQuery.new
755 q.column_names = ['subject', 'description', 'tracker']
755 q.column_names = ['subject', 'description', 'tracker']
756
756
757 assert_equal [:subject, :tracker], q.inline_columns.map(&:name)
757 assert_equal [:subject, :tracker], q.inline_columns.map(&:name)
@@ -759,21 +759,21 class QueryTest < ActiveSupport::TestCase
759 end
759 end
760
760
761 def test_custom_field_columns_should_be_inline
761 def test_custom_field_columns_should_be_inline
762 q = Query.new
762 q = IssueQuery.new
763 columns = q.available_columns.select {|column| column.is_a? QueryCustomFieldColumn}
763 columns = q.available_columns.select {|column| column.is_a? QueryCustomFieldColumn}
764 assert columns.any?
764 assert columns.any?
765 assert_nil columns.detect {|column| !column.inline?}
765 assert_nil columns.detect {|column| !column.inline?}
766 end
766 end
767
767
768 def test_query_should_preload_spent_hours
768 def test_query_should_preload_spent_hours
769 q = Query.new(:name => '_', :column_names => [:subject, :spent_hours])
769 q = IssueQuery.new(:name => '_', :column_names => [:subject, :spent_hours])
770 assert q.has_column?(:spent_hours)
770 assert q.has_column?(:spent_hours)
771 issues = q.issues
771 issues = q.issues
772 assert_not_nil issues.first.instance_variable_get("@spent_hours")
772 assert_not_nil issues.first.instance_variable_get("@spent_hours")
773 end
773 end
774
774
775 def test_groupable_columns_should_include_custom_fields
775 def test_groupable_columns_should_include_custom_fields
776 q = Query.new
776 q = IssueQuery.new
777 column = q.groupable_columns.detect {|c| c.name == :cf_1}
777 column = q.groupable_columns.detect {|c| c.name == :cf_1}
778 assert_not_nil column
778 assert_not_nil column
779 assert_kind_of QueryCustomFieldColumn, column
779 assert_kind_of QueryCustomFieldColumn, column
@@ -783,7 +783,7 class QueryTest < ActiveSupport::TestCase
783 field = CustomField.find(1)
783 field = CustomField.find(1)
784 field.update_attribute :multiple, true
784 field.update_attribute :multiple, true
785
785
786 q = Query.new
786 q = IssueQuery.new
787 column = q.groupable_columns.detect {|c| c.name == :cf_1}
787 column = q.groupable_columns.detect {|c| c.name == :cf_1}
788 assert_nil column
788 assert_nil column
789 end
789 end
@@ -791,19 +791,19 class QueryTest < ActiveSupport::TestCase
791 def test_groupable_columns_should_include_user_custom_fields
791 def test_groupable_columns_should_include_user_custom_fields
792 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1], :field_format => 'user')
792 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1], :field_format => 'user')
793
793
794 q = Query.new
794 q = IssueQuery.new
795 assert q.groupable_columns.detect {|c| c.name == "cf_#{cf.id}".to_sym}
795 assert q.groupable_columns.detect {|c| c.name == "cf_#{cf.id}".to_sym}
796 end
796 end
797
797
798 def test_groupable_columns_should_include_version_custom_fields
798 def test_groupable_columns_should_include_version_custom_fields
799 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1], :field_format => 'version')
799 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1], :field_format => 'version')
800
800
801 q = Query.new
801 q = IssueQuery.new
802 assert q.groupable_columns.detect {|c| c.name == "cf_#{cf.id}".to_sym}
802 assert q.groupable_columns.detect {|c| c.name == "cf_#{cf.id}".to_sym}
803 end
803 end
804
804
805 def test_grouped_with_valid_column
805 def test_grouped_with_valid_column
806 q = Query.new(:group_by => 'status')
806 q = IssueQuery.new(:group_by => 'status')
807 assert q.grouped?
807 assert q.grouped?
808 assert_not_nil q.group_by_column
808 assert_not_nil q.group_by_column
809 assert_equal :status, q.group_by_column.name
809 assert_equal :status, q.group_by_column.name
@@ -812,7 +812,7 class QueryTest < ActiveSupport::TestCase
812 end
812 end
813
813
814 def test_grouped_with_invalid_column
814 def test_grouped_with_invalid_column
815 q = Query.new(:group_by => 'foo')
815 q = IssueQuery.new(:group_by => 'foo')
816 assert !q.grouped?
816 assert !q.grouped?
817 assert_nil q.group_by_column
817 assert_nil q.group_by_column
818 assert_nil q.group_by_statement
818 assert_nil q.group_by_statement
@@ -820,7 +820,7 class QueryTest < ActiveSupport::TestCase
820
820
821 def test_sortable_columns_should_sort_assignees_according_to_user_format_setting
821 def test_sortable_columns_should_sort_assignees_according_to_user_format_setting
822 with_settings :user_format => 'lastname_coma_firstname' do
822 with_settings :user_format => 'lastname_coma_firstname' do
823 q = Query.new
823 q = IssueQuery.new
824 assert q.sortable_columns.has_key?('assigned_to')
824 assert q.sortable_columns.has_key?('assigned_to')
825 assert_equal %w(users.lastname users.firstname users.id), q.sortable_columns['assigned_to']
825 assert_equal %w(users.lastname users.firstname users.id), q.sortable_columns['assigned_to']
826 end
826 end
@@ -828,14 +828,14 class QueryTest < ActiveSupport::TestCase
828
828
829 def test_sortable_columns_should_sort_authors_according_to_user_format_setting
829 def test_sortable_columns_should_sort_authors_according_to_user_format_setting
830 with_settings :user_format => 'lastname_coma_firstname' do
830 with_settings :user_format => 'lastname_coma_firstname' do
831 q = Query.new
831 q = IssueQuery.new
832 assert q.sortable_columns.has_key?('author')
832 assert q.sortable_columns.has_key?('author')
833 assert_equal %w(authors.lastname authors.firstname authors.id), q.sortable_columns['author']
833 assert_equal %w(authors.lastname authors.firstname authors.id), q.sortable_columns['author']
834 end
834 end
835 end
835 end
836
836
837 def test_sortable_columns_should_include_custom_field
837 def test_sortable_columns_should_include_custom_field
838 q = Query.new
838 q = IssueQuery.new
839 assert q.sortable_columns['cf_1']
839 assert q.sortable_columns['cf_1']
840 end
840 end
841
841
@@ -843,29 +843,29 class QueryTest < ActiveSupport::TestCase
843 field = CustomField.find(1)
843 field = CustomField.find(1)
844 field.update_attribute :multiple, true
844 field.update_attribute :multiple, true
845
845
846 q = Query.new
846 q = IssueQuery.new
847 assert !q.sortable_columns['cf_1']
847 assert !q.sortable_columns['cf_1']
848 end
848 end
849
849
850 def test_default_sort
850 def test_default_sort
851 q = Query.new
851 q = IssueQuery.new
852 assert_equal [], q.sort_criteria
852 assert_equal [], q.sort_criteria
853 end
853 end
854
854
855 def test_set_sort_criteria_with_hash
855 def test_set_sort_criteria_with_hash
856 q = Query.new
856 q = IssueQuery.new
857 q.sort_criteria = {'0' => ['priority', 'desc'], '2' => ['tracker']}
857 q.sort_criteria = {'0' => ['priority', 'desc'], '2' => ['tracker']}
858 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
858 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
859 end
859 end
860
860
861 def test_set_sort_criteria_with_array
861 def test_set_sort_criteria_with_array
862 q = Query.new
862 q = IssueQuery.new
863 q.sort_criteria = [['priority', 'desc'], 'tracker']
863 q.sort_criteria = [['priority', 'desc'], 'tracker']
864 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
864 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
865 end
865 end
866
866
867 def test_create_query_with_sort
867 def test_create_query_with_sort
868 q = Query.new(:name => 'Sorted')
868 q = IssueQuery.new(:name => 'Sorted')
869 q.sort_criteria = [['priority', 'desc'], 'tracker']
869 q.sort_criteria = [['priority', 'desc'], 'tracker']
870 assert q.save
870 assert q.save
871 q.reload
871 q.reload
@@ -873,7 +873,7 class QueryTest < ActiveSupport::TestCase
873 end
873 end
874
874
875 def test_sort_by_string_custom_field_asc
875 def test_sort_by_string_custom_field_asc
876 q = Query.new
876 q = IssueQuery.new
877 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
877 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
878 assert c
878 assert c
879 assert c.sortable
879 assert c.sortable
@@ -886,7 +886,7 class QueryTest < ActiveSupport::TestCase
886 end
886 end
887
887
888 def test_sort_by_string_custom_field_desc
888 def test_sort_by_string_custom_field_desc
889 q = Query.new
889 q = IssueQuery.new
890 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
890 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
891 assert c
891 assert c
892 assert c.sortable
892 assert c.sortable
@@ -899,7 +899,7 class QueryTest < ActiveSupport::TestCase
899 end
899 end
900
900
901 def test_sort_by_float_custom_field_asc
901 def test_sort_by_float_custom_field_asc
902 q = Query.new
902 q = IssueQuery.new
903 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'float' }
903 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'float' }
904 assert c
904 assert c
905 assert c.sortable
905 assert c.sortable
@@ -912,14 +912,14 class QueryTest < ActiveSupport::TestCase
912 end
912 end
913
913
914 def test_invalid_query_should_raise_query_statement_invalid_error
914 def test_invalid_query_should_raise_query_statement_invalid_error
915 q = Query.new
915 q = IssueQuery.new
916 assert_raise Query::StatementInvalid do
916 assert_raise Query::StatementInvalid do
917 q.issues(:conditions => "foo = 1")
917 q.issues(:conditions => "foo = 1")
918 end
918 end
919 end
919 end
920
920
921 def test_issue_count
921 def test_issue_count
922 q = Query.new(:name => '_')
922 q = IssueQuery.new(:name => '_')
923 issue_count = q.issue_count
923 issue_count = q.issue_count
924 assert_equal q.issues.size, issue_count
924 assert_equal q.issues.size, issue_count
925 end
925 end
@@ -935,7 +935,7 class QueryTest < ActiveSupport::TestCase
935 end
935 end
936
936
937 def test_issue_count_by_association_group
937 def test_issue_count_by_association_group
938 q = Query.new(:name => '_', :group_by => 'assigned_to')
938 q = IssueQuery.new(:name => '_', :group_by => 'assigned_to')
939 count_by_group = q.issue_count_by_group
939 count_by_group = q.issue_count_by_group
940 assert_kind_of Hash, count_by_group
940 assert_kind_of Hash, count_by_group
941 assert_equal %w(NilClass User), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
941 assert_equal %w(NilClass User), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
@@ -944,7 +944,7 class QueryTest < ActiveSupport::TestCase
944 end
944 end
945
945
946 def test_issue_count_by_list_custom_field_group
946 def test_issue_count_by_list_custom_field_group
947 q = Query.new(:name => '_', :group_by => 'cf_1')
947 q = IssueQuery.new(:name => '_', :group_by => 'cf_1')
948 count_by_group = q.issue_count_by_group
948 count_by_group = q.issue_count_by_group
949 assert_kind_of Hash, count_by_group
949 assert_kind_of Hash, count_by_group
950 assert_equal %w(NilClass String), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
950 assert_equal %w(NilClass String), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
@@ -953,7 +953,7 class QueryTest < ActiveSupport::TestCase
953 end
953 end
954
954
955 def test_issue_count_by_date_custom_field_group
955 def test_issue_count_by_date_custom_field_group
956 q = Query.new(:name => '_', :group_by => 'cf_8')
956 q = IssueQuery.new(:name => '_', :group_by => 'cf_8')
957 count_by_group = q.issue_count_by_group
957 count_by_group = q.issue_count_by_group
958 assert_kind_of Hash, count_by_group
958 assert_kind_of Hash, count_by_group
959 assert_equal %w(Date NilClass), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
959 assert_equal %w(Date NilClass), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
@@ -963,7 +963,7 class QueryTest < ActiveSupport::TestCase
963 def test_issue_count_with_nil_group_only
963 def test_issue_count_with_nil_group_only
964 Issue.update_all("assigned_to_id = NULL")
964 Issue.update_all("assigned_to_id = NULL")
965
965
966 q = Query.new(:name => '_', :group_by => 'assigned_to')
966 q = IssueQuery.new(:name => '_', :group_by => 'assigned_to')
967 count_by_group = q.issue_count_by_group
967 count_by_group = q.issue_count_by_group
968 assert_kind_of Hash, count_by_group
968 assert_kind_of Hash, count_by_group
969 assert_equal 1, count_by_group.keys.size
969 assert_equal 1, count_by_group.keys.size
@@ -971,7 +971,7 class QueryTest < ActiveSupport::TestCase
971 end
971 end
972
972
973 def test_issue_ids
973 def test_issue_ids
974 q = Query.new(:name => '_')
974 q = IssueQuery.new(:name => '_')
975 order = "issues.subject, issues.id"
975 order = "issues.subject, issues.id"
976 issues = q.issues(:order => order)
976 issues = q.issues(:order => order)
977 assert_equal issues.map(&:id), q.issue_ids(:order => order)
977 assert_equal issues.map(&:id), q.issue_ids(:order => order)
@@ -979,13 +979,13 class QueryTest < ActiveSupport::TestCase
979
979
980 def test_label_for
980 def test_label_for
981 set_language_if_valid 'en'
981 set_language_if_valid 'en'
982 q = Query.new
982 q = IssueQuery.new
983 assert_equal 'Assignee', q.label_for('assigned_to_id')
983 assert_equal 'Assignee', q.label_for('assigned_to_id')
984 end
984 end
985
985
986 def test_label_for_fr
986 def test_label_for_fr
987 set_language_if_valid 'fr'
987 set_language_if_valid 'fr'
988 q = Query.new
988 q = IssueQuery.new
989 s = "Assign\xc3\xa9 \xc3\xa0"
989 s = "Assign\xc3\xa9 \xc3\xa0"
990 s.force_encoding('UTF-8') if s.respond_to?(:force_encoding)
990 s.force_encoding('UTF-8') if s.respond_to?(:force_encoding)
991 assert_equal s, q.label_for('assigned_to_id')
991 assert_equal s, q.label_for('assigned_to_id')
@@ -997,32 +997,32 class QueryTest < ActiveSupport::TestCase
997 developer = User.find(3)
997 developer = User.find(3)
998
998
999 # Public query on project 1
999 # Public query on project 1
1000 q = Query.find(1)
1000 q = IssueQuery.find(1)
1001 assert q.editable_by?(admin)
1001 assert q.editable_by?(admin)
1002 assert q.editable_by?(manager)
1002 assert q.editable_by?(manager)
1003 assert !q.editable_by?(developer)
1003 assert !q.editable_by?(developer)
1004
1004
1005 # Private query on project 1
1005 # Private query on project 1
1006 q = Query.find(2)
1006 q = IssueQuery.find(2)
1007 assert q.editable_by?(admin)
1007 assert q.editable_by?(admin)
1008 assert !q.editable_by?(manager)
1008 assert !q.editable_by?(manager)
1009 assert q.editable_by?(developer)
1009 assert q.editable_by?(developer)
1010
1010
1011 # Private query for all projects
1011 # Private query for all projects
1012 q = Query.find(3)
1012 q = IssueQuery.find(3)
1013 assert q.editable_by?(admin)
1013 assert q.editable_by?(admin)
1014 assert !q.editable_by?(manager)
1014 assert !q.editable_by?(manager)
1015 assert q.editable_by?(developer)
1015 assert q.editable_by?(developer)
1016
1016
1017 # Public query for all projects
1017 # Public query for all projects
1018 q = Query.find(4)
1018 q = IssueQuery.find(4)
1019 assert q.editable_by?(admin)
1019 assert q.editable_by?(admin)
1020 assert !q.editable_by?(manager)
1020 assert !q.editable_by?(manager)
1021 assert !q.editable_by?(developer)
1021 assert !q.editable_by?(developer)
1022 end
1022 end
1023
1023
1024 def test_visible_scope
1024 def test_visible_scope
1025 query_ids = Query.visible(User.anonymous).map(&:id)
1025 query_ids = IssueQuery.visible(User.anonymous).map(&:id)
1026
1026
1027 assert query_ids.include?(1), 'public query on public project was not visible'
1027 assert query_ids.include?(1), 'public query on public project was not visible'
1028 assert query_ids.include?(4), 'public query for all projects was not visible'
1028 assert query_ids.include?(4), 'public query for all projects was not visible'
@@ -1033,7 +1033,7 class QueryTest < ActiveSupport::TestCase
1033
1033
1034 context "#available_filters" do
1034 context "#available_filters" do
1035 setup do
1035 setup do
1036 @query = Query.new(:name => "_")
1036 @query = IssueQuery.new(:name => "_")
1037 end
1037 end
1038
1038
1039 should "include users of visible projects in cross-project view" do
1039 should "include users of visible projects in cross-project view" do
@@ -1127,7 +1127,7 class QueryTest < ActiveSupport::TestCase
1127 end
1127 end
1128
1128
1129 should "search assigned to for users in the group" do
1129 should "search assigned to for users in the group" do
1130 @query = Query.new(:name => '_')
1130 @query = IssueQuery.new(:name => '_')
1131 @query.add_filter('member_of_group', '=', [@group.id.to_s])
1131 @query.add_filter('member_of_group', '=', [@group.id.to_s])
1132
1132
1133 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}')"
1133 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}')"
@@ -1135,7 +1135,7 class QueryTest < ActiveSupport::TestCase
1135 end
1135 end
1136
1136
1137 should "search not assigned to any group member (none)" do
1137 should "search not assigned to any group member (none)" do
1138 @query = Query.new(:name => '_')
1138 @query = IssueQuery.new(:name => '_')
1139 @query.add_filter('member_of_group', '!*', [''])
1139 @query.add_filter('member_of_group', '!*', [''])
1140
1140
1141 # Users not in a group
1141 # Users not in a group
@@ -1144,7 +1144,7 class QueryTest < ActiveSupport::TestCase
1144 end
1144 end
1145
1145
1146 should "search assigned to any group member (all)" do
1146 should "search assigned to any group member (all)" do
1147 @query = Query.new(:name => '_')
1147 @query = IssueQuery.new(:name => '_')
1148 @query.add_filter('member_of_group', '*', [''])
1148 @query.add_filter('member_of_group', '*', [''])
1149
1149
1150 # Only users in a group
1150 # Only users in a group
@@ -1154,7 +1154,7 class QueryTest < ActiveSupport::TestCase
1154
1154
1155 should "return an empty set with = empty group" do
1155 should "return an empty set with = empty group" do
1156 @empty_group = Group.generate!
1156 @empty_group = Group.generate!
1157 @query = Query.new(:name => '_')
1157 @query = IssueQuery.new(:name => '_')
1158 @query.add_filter('member_of_group', '=', [@empty_group.id.to_s])
1158 @query.add_filter('member_of_group', '=', [@empty_group.id.to_s])
1159
1159
1160 assert_equal [], find_issues_with_query(@query)
1160 assert_equal [], find_issues_with_query(@query)
@@ -1162,7 +1162,7 class QueryTest < ActiveSupport::TestCase
1162
1162
1163 should "return issues with ! empty group" do
1163 should "return issues with ! empty group" do
1164 @empty_group = Group.generate!
1164 @empty_group = Group.generate!
1165 @query = Query.new(:name => '_')
1165 @query = IssueQuery.new(:name => '_')
1166 @query.add_filter('member_of_group', '!', [@empty_group.id.to_s])
1166 @query.add_filter('member_of_group', '!', [@empty_group.id.to_s])
1167
1167
1168 assert_find_issues_with_query_is_successful @query
1168 assert_find_issues_with_query_is_successful @query
@@ -1191,7 +1191,7 class QueryTest < ActiveSupport::TestCase
1191 end
1191 end
1192
1192
1193 should "search assigned to for users with the Role" do
1193 should "search assigned to for users with the Role" do
1194 @query = Query.new(:name => '_', :project => @project)
1194 @query = IssueQuery.new(:name => '_', :project => @project)
1195 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
1195 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
1196
1196
1197 assert_query_result [@issue1, @issue3], @query
1197 assert_query_result [@issue1, @issue3], @query
@@ -1201,7 +1201,7 class QueryTest < ActiveSupport::TestCase
1201 other_project = Project.generate!
1201 other_project = Project.generate!
1202 User.add_to_project(@developer, other_project, @manager_role)
1202 User.add_to_project(@developer, other_project, @manager_role)
1203
1203
1204 @query = Query.new(:name => '_', :project => @project)
1204 @query = IssueQuery.new(:name => '_', :project => @project)
1205 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
1205 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
1206
1206
1207 assert_query_result [@issue1, @issue3], @query
1207 assert_query_result [@issue1, @issue3], @query
@@ -1209,28 +1209,28 class QueryTest < ActiveSupport::TestCase
1209
1209
1210 should "return an empty set with empty role" do
1210 should "return an empty set with empty role" do
1211 @empty_role = Role.generate!
1211 @empty_role = Role.generate!
1212 @query = Query.new(:name => '_', :project => @project)
1212 @query = IssueQuery.new(:name => '_', :project => @project)
1213 @query.add_filter('assigned_to_role', '=', [@empty_role.id.to_s])
1213 @query.add_filter('assigned_to_role', '=', [@empty_role.id.to_s])
1214
1214
1215 assert_query_result [], @query
1215 assert_query_result [], @query
1216 end
1216 end
1217
1217
1218 should "search assigned to for users without the Role" do
1218 should "search assigned to for users without the Role" do
1219 @query = Query.new(:name => '_', :project => @project)
1219 @query = IssueQuery.new(:name => '_', :project => @project)
1220 @query.add_filter('assigned_to_role', '!', [@manager_role.id.to_s])
1220 @query.add_filter('assigned_to_role', '!', [@manager_role.id.to_s])
1221
1221
1222 assert_query_result [@issue2, @issue4, @issue5], @query
1222 assert_query_result [@issue2, @issue4, @issue5], @query
1223 end
1223 end
1224
1224
1225 should "search assigned to for users not assigned to any Role (none)" do
1225 should "search assigned to for users not assigned to any Role (none)" do
1226 @query = Query.new(:name => '_', :project => @project)
1226 @query = IssueQuery.new(:name => '_', :project => @project)
1227 @query.add_filter('assigned_to_role', '!*', [''])
1227 @query.add_filter('assigned_to_role', '!*', [''])
1228
1228
1229 assert_query_result [@issue4, @issue5], @query
1229 assert_query_result [@issue4, @issue5], @query
1230 end
1230 end
1231
1231
1232 should "search assigned to for users assigned to any Role (all)" do
1232 should "search assigned to for users assigned to any Role (all)" do
1233 @query = Query.new(:name => '_', :project => @project)
1233 @query = IssueQuery.new(:name => '_', :project => @project)
1234 @query.add_filter('assigned_to_role', '*', [''])
1234 @query.add_filter('assigned_to_role', '*', [''])
1235
1235
1236 assert_query_result [@issue1, @issue2, @issue3], @query
1236 assert_query_result [@issue1, @issue2, @issue3], @query
@@ -1238,12 +1238,11 class QueryTest < ActiveSupport::TestCase
1238
1238
1239 should "return issues with ! empty role" do
1239 should "return issues with ! empty role" do
1240 @empty_role = Role.generate!
1240 @empty_role = Role.generate!
1241 @query = Query.new(:name => '_', :project => @project)
1241 @query = IssueQuery.new(:name => '_', :project => @project)
1242 @query.add_filter('assigned_to_role', '!', [@empty_role.id.to_s])
1242 @query.add_filter('assigned_to_role', '!', [@empty_role.id.to_s])
1243
1243
1244 assert_query_result [@issue1, @issue2, @issue3, @issue4, @issue5], @query
1244 assert_query_result [@issue1, @issue2, @issue3, @issue4, @issue5], @query
1245 end
1245 end
1246 end
1246 end
1247 end
1247 end
1248
1249 end
1248 end
General Comments 0
You need to be logged in to leave comments. Login now