##// END OF EJS Templates
Merged r9908 from trunk....
Jean-Philippe Lang -
r9772:81553d396e4d
parent child
Show More
@@ -1,865 +1,865
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class QueryColumn
19 19 attr_accessor :name, :sortable, :groupable, :default_order
20 20 include Redmine::I18n
21 21
22 22 def initialize(name, options={})
23 23 self.name = name
24 24 self.sortable = options[:sortable]
25 25 self.groupable = options[:groupable] || false
26 26 if groupable == true
27 27 self.groupable = name.to_s
28 28 end
29 29 self.default_order = options[:default_order]
30 30 @caption_key = options[:caption] || "field_#{name}"
31 31 end
32 32
33 33 def caption
34 34 l(@caption_key)
35 35 end
36 36
37 37 # Returns true if the column is sortable, otherwise false
38 38 def sortable?
39 39 !@sortable.nil?
40 40 end
41 41
42 42 def sortable
43 43 @sortable.is_a?(Proc) ? @sortable.call : @sortable
44 44 end
45 45
46 46 def value(issue)
47 47 issue.send name
48 48 end
49 49
50 50 def css_classes
51 51 name
52 52 end
53 53 end
54 54
55 55 class QueryCustomFieldColumn < QueryColumn
56 56
57 57 def initialize(custom_field)
58 58 self.name = "cf_#{custom_field.id}".to_sym
59 59 self.sortable = custom_field.order_statement || false
60 60 if %w(list date bool int).include?(custom_field.field_format) && !custom_field.multiple?
61 61 self.groupable = custom_field.order_statement
62 62 end
63 63 self.groupable ||= false
64 64 @cf = custom_field
65 65 end
66 66
67 67 def caption
68 68 @cf.name
69 69 end
70 70
71 71 def custom_field
72 72 @cf
73 73 end
74 74
75 75 def value(issue)
76 76 cv = issue.custom_values.select {|v| v.custom_field_id == @cf.id}.collect {|v| @cf.cast_value(v.value)}
77 77 cv.size > 1 ? cv : cv.first
78 78 end
79 79
80 80 def css_classes
81 81 @css_classes ||= "#{name} #{@cf.field_format}"
82 82 end
83 83 end
84 84
85 85 class Query < ActiveRecord::Base
86 86 class StatementInvalid < ::ActiveRecord::StatementInvalid
87 87 end
88 88
89 89 belongs_to :project
90 90 belongs_to :user
91 91 serialize :filters
92 92 serialize :column_names
93 93 serialize :sort_criteria, Array
94 94
95 95 attr_protected :project_id, :user_id
96 96
97 97 validates_presence_of :name
98 98 validates_length_of :name, :maximum => 255
99 99 validate :validate_query_filters
100 100
101 101 @@operators = { "=" => :label_equals,
102 102 "!" => :label_not_equals,
103 103 "o" => :label_open_issues,
104 104 "c" => :label_closed_issues,
105 105 "!*" => :label_none,
106 106 "*" => :label_all,
107 107 ">=" => :label_greater_or_equal,
108 108 "<=" => :label_less_or_equal,
109 109 "><" => :label_between,
110 110 "<t+" => :label_in_less_than,
111 111 ">t+" => :label_in_more_than,
112 112 "t+" => :label_in,
113 113 "t" => :label_today,
114 114 "w" => :label_this_week,
115 115 ">t-" => :label_less_than_ago,
116 116 "<t-" => :label_more_than_ago,
117 117 "t-" => :label_ago,
118 118 "~" => :label_contains,
119 119 "!~" => :label_not_contains }
120 120
121 121 cattr_reader :operators
122 122
123 123 @@operators_by_filter_type = { :list => [ "=", "!" ],
124 124 :list_status => [ "o", "=", "!", "c", "*" ],
125 125 :list_optional => [ "=", "!", "!*", "*" ],
126 126 :list_subprojects => [ "*", "!*", "=" ],
127 127 :date => [ "=", ">=", "<=", "><", "<t+", ">t+", "t+", "t", "w", ">t-", "<t-", "t-", "!*", "*" ],
128 128 :date_past => [ "=", ">=", "<=", "><", ">t-", "<t-", "t-", "t", "w", "!*", "*" ],
129 129 :string => [ "=", "~", "!", "!~", "!*", "*" ],
130 130 :text => [ "~", "!~", "!*", "*" ],
131 131 :integer => [ "=", ">=", "<=", "><", "!*", "*" ],
132 132 :float => [ "=", ">=", "<=", "><", "!*", "*" ] }
133 133
134 134 cattr_reader :operators_by_filter_type
135 135
136 136 @@available_columns = [
137 137 QueryColumn.new(:project, :sortable => "#{Project.table_name}.name", :groupable => true),
138 138 QueryColumn.new(:tracker, :sortable => "#{Tracker.table_name}.position", :groupable => true),
139 139 QueryColumn.new(:parent, :sortable => ["#{Issue.table_name}.root_id", "#{Issue.table_name}.lft ASC"], :default_order => 'desc', :caption => :field_parent_issue),
140 140 QueryColumn.new(:status, :sortable => "#{IssueStatus.table_name}.position", :groupable => true),
141 141 QueryColumn.new(:priority, :sortable => "#{IssuePriority.table_name}.position", :default_order => 'desc', :groupable => true),
142 142 QueryColumn.new(:subject, :sortable => "#{Issue.table_name}.subject"),
143 143 QueryColumn.new(:author, :sortable => lambda {User.fields_for_order_statement("authors")}, :groupable => true),
144 144 QueryColumn.new(:assigned_to, :sortable => lambda {User.fields_for_order_statement}, :groupable => true),
145 145 QueryColumn.new(:updated_on, :sortable => "#{Issue.table_name}.updated_on", :default_order => 'desc'),
146 146 QueryColumn.new(:category, :sortable => "#{IssueCategory.table_name}.name", :groupable => true),
147 147 QueryColumn.new(:fixed_version, :sortable => ["#{Version.table_name}.effective_date", "#{Version.table_name}.name"], :default_order => 'desc', :groupable => true),
148 148 QueryColumn.new(:start_date, :sortable => "#{Issue.table_name}.start_date"),
149 149 QueryColumn.new(:due_date, :sortable => "#{Issue.table_name}.due_date"),
150 150 QueryColumn.new(:estimated_hours, :sortable => "#{Issue.table_name}.estimated_hours"),
151 151 QueryColumn.new(:done_ratio, :sortable => "#{Issue.table_name}.done_ratio", :groupable => true),
152 152 QueryColumn.new(:created_on, :sortable => "#{Issue.table_name}.created_on", :default_order => 'desc'),
153 153 ]
154 154 cattr_reader :available_columns
155 155
156 156 named_scope :visible, lambda {|*args|
157 157 user = args.shift || User.current
158 158 base = Project.allowed_to_condition(user, :view_issues, *args)
159 159 user_id = user.logged? ? user.id : 0
160 160 {
161 161 :conditions => ["(#{table_name}.project_id IS NULL OR (#{base})) AND (#{table_name}.is_public = ? OR #{table_name}.user_id = ?)", true, user_id],
162 162 :include => :project
163 163 }
164 164 }
165 165
166 166 def initialize(attributes=nil, *args)
167 167 super attributes
168 168 self.filters ||= { 'status_id' => {:operator => "o", :values => [""]} }
169 169 @is_for_all = project.nil?
170 170 end
171 171
172 172 def validate_query_filters
173 173 filters.each_key do |field|
174 174 if values_for(field)
175 175 case type_for(field)
176 176 when :integer
177 add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^\d+$/) }
177 add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^[+-]?\d+$/) }
178 178 when :float
179 add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^\d+(\.\d*)?$/) }
179 add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^[+-]?\d+(\.\d*)?$/) }
180 180 when :date, :date_past
181 181 case operator_for(field)
182 182 when "=", ">=", "<=", "><"
183 183 add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && (!v.match(/^\d{4}-\d{2}-\d{2}$/) || (Date.parse(v) rescue nil).nil?) }
184 184 when ">t-", "<t-", "t-"
185 185 add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^\d+$/) }
186 186 end
187 187 end
188 188 end
189 189
190 190 add_filter_error(field, :blank) unless
191 191 # filter requires one or more values
192 192 (values_for(field) and !values_for(field).first.blank?) or
193 193 # filter doesn't require any value
194 194 ["o", "c", "!*", "*", "t", "w"].include? operator_for(field)
195 195 end if filters
196 196 end
197 197
198 198 def add_filter_error(field, message)
199 199 m = label_for(field) + " " + l(message, :scope => 'activerecord.errors.messages')
200 200 errors.add(:base, m)
201 201 end
202 202
203 203 # Returns true if the query is visible to +user+ or the current user.
204 204 def visible?(user=User.current)
205 205 (project.nil? || user.allowed_to?(:view_issues, project)) && (self.is_public? || self.user_id == user.id)
206 206 end
207 207
208 208 def editable_by?(user)
209 209 return false unless user
210 210 # Admin can edit them all and regular users can edit their private queries
211 211 return true if user.admin? || (!is_public && self.user_id == user.id)
212 212 # Members can not edit public queries that are for all project (only admin is allowed to)
213 213 is_public && !@is_for_all && user.allowed_to?(:manage_public_queries, project)
214 214 end
215 215
216 216 def available_filters
217 217 return @available_filters if @available_filters
218 218
219 219 trackers = project.nil? ? Tracker.find(:all, :order => 'position') : project.rolled_up_trackers
220 220
221 221 @available_filters = { "status_id" => { :type => :list_status, :order => 1, :values => IssueStatus.find(:all, :order => 'position').collect{|s| [s.name, s.id.to_s] } },
222 222 "tracker_id" => { :type => :list, :order => 2, :values => trackers.collect{|s| [s.name, s.id.to_s] } },
223 223 "priority_id" => { :type => :list, :order => 3, :values => IssuePriority.all.collect{|s| [s.name, s.id.to_s] } },
224 224 "subject" => { :type => :text, :order => 8 },
225 225 "created_on" => { :type => :date_past, :order => 9 },
226 226 "updated_on" => { :type => :date_past, :order => 10 },
227 227 "start_date" => { :type => :date, :order => 11 },
228 228 "due_date" => { :type => :date, :order => 12 },
229 229 "estimated_hours" => { :type => :float, :order => 13 },
230 230 "done_ratio" => { :type => :integer, :order => 14 }}
231 231
232 232 principals = []
233 233 if project
234 234 principals += project.principals.sort
235 235 unless project.leaf?
236 236 subprojects = project.descendants.visible.all
237 237 if subprojects.any?
238 238 @available_filters["subproject_id"] = { :type => :list_subprojects, :order => 13, :values => subprojects.collect{|s| [s.name, s.id.to_s] } }
239 239 principals += Principal.member_of(subprojects)
240 240 end
241 241 end
242 242 else
243 243 all_projects = Project.visible.all
244 244 if all_projects.any?
245 245 # members of visible projects
246 246 principals += Principal.member_of(all_projects)
247 247
248 248 # project filter
249 249 project_values = []
250 250 if User.current.logged? && User.current.memberships.any?
251 251 project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"]
252 252 end
253 253 Project.project_tree(all_projects) do |p, level|
254 254 prefix = (level > 0 ? ('--' * level + ' ') : '')
255 255 project_values << ["#{prefix}#{p.name}", p.id.to_s]
256 256 end
257 257 @available_filters["project_id"] = { :type => :list, :order => 1, :values => project_values} unless project_values.empty?
258 258 end
259 259 end
260 260 principals.uniq!
261 261 principals.sort!
262 262 users = principals.select {|p| p.is_a?(User)}
263 263
264 264 assigned_to_values = []
265 265 assigned_to_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
266 266 assigned_to_values += (Setting.issue_group_assignment? ? principals : users).collect{|s| [s.name, s.id.to_s] }
267 267 @available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => assigned_to_values } unless assigned_to_values.empty?
268 268
269 269 author_values = []
270 270 author_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
271 271 author_values += users.collect{|s| [s.name, s.id.to_s] }
272 272 @available_filters["author_id"] = { :type => :list, :order => 5, :values => author_values } unless author_values.empty?
273 273
274 274 group_values = Group.all.collect {|g| [g.name, g.id.to_s] }
275 275 @available_filters["member_of_group"] = { :type => :list_optional, :order => 6, :values => group_values } unless group_values.empty?
276 276
277 277 role_values = Role.givable.collect {|r| [r.name, r.id.to_s] }
278 278 @available_filters["assigned_to_role"] = { :type => :list_optional, :order => 7, :values => role_values } unless role_values.empty?
279 279
280 280 if User.current.logged?
281 281 @available_filters["watcher_id"] = { :type => :list, :order => 15, :values => [["<< #{l(:label_me)} >>", "me"]] }
282 282 end
283 283
284 284 if project
285 285 # project specific filters
286 286 categories = project.issue_categories.all
287 287 unless categories.empty?
288 288 @available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => categories.collect{|s| [s.name, s.id.to_s] } }
289 289 end
290 290 versions = project.shared_versions.all
291 291 unless versions.empty?
292 292 @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] } }
293 293 end
294 294 add_custom_fields_filters(project.all_issue_custom_fields)
295 295 else
296 296 # global filters for cross project issue list
297 297 system_shared_versions = Version.visible.find_all_by_sharing('system')
298 298 unless system_shared_versions.empty?
299 299 @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => system_shared_versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] } }
300 300 end
301 301 add_custom_fields_filters(IssueCustomField.find(:all, :conditions => {:is_filter => true, :is_for_all => true}))
302 302 end
303 303 @available_filters
304 304 end
305 305
306 306 def add_filter(field, operator, values)
307 307 # values must be an array
308 308 return unless values.nil? || values.is_a?(Array)
309 309 # check if field is defined as an available filter
310 310 if available_filters.has_key? field
311 311 filter_options = available_filters[field]
312 312 # check if operator is allowed for that filter
313 313 #if @@operators_by_filter_type[filter_options[:type]].include? operator
314 314 # allowed_values = values & ([""] + (filter_options[:values] || []).collect {|val| val[1]})
315 315 # filters[field] = {:operator => operator, :values => allowed_values } if (allowed_values.first and !allowed_values.first.empty?) or ["o", "c", "!*", "*", "t"].include? operator
316 316 #end
317 317 filters[field] = {:operator => operator, :values => (values || [''])}
318 318 end
319 319 end
320 320
321 321 def add_short_filter(field, expression)
322 322 return unless expression && available_filters.has_key?(field)
323 323 field_type = available_filters[field][:type]
324 324 @@operators_by_filter_type[field_type].sort.reverse.detect do |operator|
325 325 next unless expression =~ /^#{Regexp.escape(operator)}(.*)$/
326 326 add_filter field, operator, $1.present? ? $1.split('|') : ['']
327 327 end || add_filter(field, '=', expression.split('|'))
328 328 end
329 329
330 330 # Add multiple filters using +add_filter+
331 331 def add_filters(fields, operators, values)
332 332 if fields.is_a?(Array) && operators.is_a?(Hash) && (values.nil? || values.is_a?(Hash))
333 333 fields.each do |field|
334 334 add_filter(field, operators[field], values && values[field])
335 335 end
336 336 end
337 337 end
338 338
339 339 def has_filter?(field)
340 340 filters and filters[field]
341 341 end
342 342
343 343 def type_for(field)
344 344 available_filters[field][:type] if available_filters.has_key?(field)
345 345 end
346 346
347 347 def operator_for(field)
348 348 has_filter?(field) ? filters[field][:operator] : nil
349 349 end
350 350
351 351 def values_for(field)
352 352 has_filter?(field) ? filters[field][:values] : nil
353 353 end
354 354
355 355 def value_for(field, index=0)
356 356 (values_for(field) || [])[index]
357 357 end
358 358
359 359 def label_for(field)
360 360 label = available_filters[field][:name] if available_filters.has_key?(field)
361 361 label ||= l("field_#{field.to_s.gsub(/_id$/, '')}", :default => field)
362 362 end
363 363
364 364 def available_columns
365 365 return @available_columns if @available_columns
366 366 @available_columns = ::Query.available_columns.dup
367 367 @available_columns += (project ?
368 368 project.all_issue_custom_fields :
369 369 IssueCustomField.find(:all)
370 370 ).collect {|cf| QueryCustomFieldColumn.new(cf) }
371 371
372 372 if User.current.allowed_to?(:view_time_entries, project, :global => true)
373 373 index = nil
374 374 @available_columns.each_with_index {|column, i| index = i if column.name == :estimated_hours}
375 375 index = (index ? index + 1 : -1)
376 376 # insert the column after estimated_hours or at the end
377 377 @available_columns.insert index, QueryColumn.new(:spent_hours,
378 378 :sortable => "(SELECT COALESCE(SUM(hours), 0) FROM #{TimeEntry.table_name} WHERE #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id)",
379 379 :default_order => 'desc',
380 380 :caption => :label_spent_time
381 381 )
382 382 end
383 383 @available_columns
384 384 end
385 385
386 386 def self.available_columns=(v)
387 387 self.available_columns = (v)
388 388 end
389 389
390 390 def self.add_available_column(column)
391 391 self.available_columns << (column) if column.is_a?(QueryColumn)
392 392 end
393 393
394 394 # Returns an array of columns that can be used to group the results
395 395 def groupable_columns
396 396 available_columns.select {|c| c.groupable}
397 397 end
398 398
399 399 # Returns a Hash of columns and the key for sorting
400 400 def sortable_columns
401 401 {'id' => "#{Issue.table_name}.id"}.merge(available_columns.inject({}) {|h, column|
402 402 h[column.name.to_s] = column.sortable
403 403 h
404 404 })
405 405 end
406 406
407 407 def columns
408 408 # preserve the column_names order
409 409 (has_default_columns? ? default_columns_names : column_names).collect do |name|
410 410 available_columns.find { |col| col.name == name }
411 411 end.compact
412 412 end
413 413
414 414 def default_columns_names
415 415 @default_columns_names ||= begin
416 416 default_columns = Setting.issue_list_default_columns.map(&:to_sym)
417 417
418 418 project.present? ? default_columns : [:project] | default_columns
419 419 end
420 420 end
421 421
422 422 def column_names=(names)
423 423 if names
424 424 names = names.select {|n| n.is_a?(Symbol) || !n.blank? }
425 425 names = names.collect {|n| n.is_a?(Symbol) ? n : n.to_sym }
426 426 # Set column_names to nil if default columns
427 427 if names == default_columns_names
428 428 names = nil
429 429 end
430 430 end
431 431 write_attribute(:column_names, names)
432 432 end
433 433
434 434 def has_column?(column)
435 435 column_names && column_names.include?(column.is_a?(QueryColumn) ? column.name : column)
436 436 end
437 437
438 438 def has_default_columns?
439 439 column_names.nil? || column_names.empty?
440 440 end
441 441
442 442 def sort_criteria=(arg)
443 443 c = []
444 444 if arg.is_a?(Hash)
445 445 arg = arg.keys.sort.collect {|k| arg[k]}
446 446 end
447 447 c = arg.select {|k,o| !k.to_s.blank?}.slice(0,3).collect {|k,o| [k.to_s, o == 'desc' ? o : 'asc']}
448 448 write_attribute(:sort_criteria, c)
449 449 end
450 450
451 451 def sort_criteria
452 452 read_attribute(:sort_criteria) || []
453 453 end
454 454
455 455 def sort_criteria_key(arg)
456 456 sort_criteria && sort_criteria[arg] && sort_criteria[arg].first
457 457 end
458 458
459 459 def sort_criteria_order(arg)
460 460 sort_criteria && sort_criteria[arg] && sort_criteria[arg].last
461 461 end
462 462
463 463 # Returns the SQL sort order that should be prepended for grouping
464 464 def group_by_sort_order
465 465 if grouped? && (column = group_by_column)
466 466 column.sortable.is_a?(Array) ?
467 467 column.sortable.collect {|s| "#{s} #{column.default_order}"}.join(',') :
468 468 "#{column.sortable} #{column.default_order}"
469 469 end
470 470 end
471 471
472 472 # Returns true if the query is a grouped query
473 473 def grouped?
474 474 !group_by_column.nil?
475 475 end
476 476
477 477 def group_by_column
478 478 groupable_columns.detect {|c| c.groupable && c.name.to_s == group_by}
479 479 end
480 480
481 481 def group_by_statement
482 482 group_by_column.try(:groupable)
483 483 end
484 484
485 485 def project_statement
486 486 project_clauses = []
487 487 if project && !project.descendants.active.empty?
488 488 ids = [project.id]
489 489 if has_filter?("subproject_id")
490 490 case operator_for("subproject_id")
491 491 when '='
492 492 # include the selected subprojects
493 493 ids += values_for("subproject_id").each(&:to_i)
494 494 when '!*'
495 495 # main project only
496 496 else
497 497 # all subprojects
498 498 ids += project.descendants.collect(&:id)
499 499 end
500 500 elsif Setting.display_subprojects_issues?
501 501 ids += project.descendants.collect(&:id)
502 502 end
503 503 project_clauses << "#{Project.table_name}.id IN (%s)" % ids.join(',')
504 504 elsif project
505 505 project_clauses << "#{Project.table_name}.id = %d" % project.id
506 506 end
507 507 project_clauses.any? ? project_clauses.join(' AND ') : nil
508 508 end
509 509
510 510 def statement
511 511 # filters clauses
512 512 filters_clauses = []
513 513 filters.each_key do |field|
514 514 next if field == "subproject_id"
515 515 v = values_for(field).clone
516 516 next unless v and !v.empty?
517 517 operator = operator_for(field)
518 518
519 519 # "me" value subsitution
520 520 if %w(assigned_to_id author_id watcher_id).include?(field)
521 521 if v.delete("me")
522 522 if User.current.logged?
523 523 v.push(User.current.id.to_s)
524 524 v += User.current.group_ids.map(&:to_s) if field == 'assigned_to_id'
525 525 else
526 526 v.push("0")
527 527 end
528 528 end
529 529 end
530 530
531 531 if field == 'project_id'
532 532 if v.delete('mine')
533 533 v += User.current.memberships.map(&:project_id).map(&:to_s)
534 534 end
535 535 end
536 536
537 537 if field =~ /^cf_(\d+)$/
538 538 # custom field
539 539 filters_clauses << sql_for_custom_field(field, operator, v, $1)
540 540 elsif respond_to?("sql_for_#{field}_field")
541 541 # specific statement
542 542 filters_clauses << send("sql_for_#{field}_field", field, operator, v)
543 543 else
544 544 # regular field
545 545 filters_clauses << '(' + sql_for_field(field, operator, v, Issue.table_name, field) + ')'
546 546 end
547 547 end if filters and valid?
548 548
549 549 filters_clauses << project_statement
550 550 filters_clauses.reject!(&:blank?)
551 551
552 552 filters_clauses.any? ? filters_clauses.join(' AND ') : nil
553 553 end
554 554
555 555 # Returns the issue count
556 556 def issue_count
557 557 Issue.visible.count(:include => [:status, :project], :conditions => statement)
558 558 rescue ::ActiveRecord::StatementInvalid => e
559 559 raise StatementInvalid.new(e.message)
560 560 end
561 561
562 562 # Returns the issue count by group or nil if query is not grouped
563 563 def issue_count_by_group
564 564 r = nil
565 565 if grouped?
566 566 begin
567 567 # Rails will raise an (unexpected) RecordNotFound if there's only a nil group value
568 568 r = Issue.visible.count(:group => group_by_statement, :include => [:status, :project], :conditions => statement)
569 569 rescue ActiveRecord::RecordNotFound
570 570 r = {nil => issue_count}
571 571 end
572 572 c = group_by_column
573 573 if c.is_a?(QueryCustomFieldColumn)
574 574 r = r.keys.inject({}) {|h, k| h[c.custom_field.cast_value(k)] = r[k]; h}
575 575 end
576 576 end
577 577 r
578 578 rescue ::ActiveRecord::StatementInvalid => e
579 579 raise StatementInvalid.new(e.message)
580 580 end
581 581
582 582 # Returns the issues
583 583 # Valid options are :order, :offset, :limit, :include, :conditions
584 584 def issues(options={})
585 585 order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',')
586 586 order_option = nil if order_option.blank?
587 587
588 588 joins = (order_option && order_option.include?('authors')) ? "LEFT OUTER JOIN users authors ON authors.id = #{Issue.table_name}.author_id" : nil
589 589
590 590 issues = Issue.visible.scoped(:conditions => options[:conditions]).find :all, :include => ([:status, :project] + (options[:include] || [])).uniq,
591 591 :conditions => statement,
592 592 :order => order_option,
593 593 :joins => joins,
594 594 :limit => options[:limit],
595 595 :offset => options[:offset]
596 596
597 597 if has_column?(:spent_hours)
598 598 Issue.load_visible_spent_hours(issues)
599 599 end
600 600 issues
601 601 rescue ::ActiveRecord::StatementInvalid => e
602 602 raise StatementInvalid.new(e.message)
603 603 end
604 604
605 605 # Returns the issues ids
606 606 def issue_ids(options={})
607 607 order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',')
608 608 order_option = nil if order_option.blank?
609 609
610 610 joins = (order_option && order_option.include?('authors')) ? "LEFT OUTER JOIN users authors ON authors.id = #{Issue.table_name}.author_id" : nil
611 611
612 612 Issue.visible.scoped(:conditions => options[:conditions]).scoped(:include => ([:status, :project] + (options[:include] || [])).uniq,
613 613 :conditions => statement,
614 614 :order => order_option,
615 615 :joins => joins,
616 616 :limit => options[:limit],
617 617 :offset => options[:offset]).find_ids
618 618 rescue ::ActiveRecord::StatementInvalid => e
619 619 raise StatementInvalid.new(e.message)
620 620 end
621 621
622 622 # Returns the journals
623 623 # Valid options are :order, :offset, :limit
624 624 def journals(options={})
625 625 Journal.visible.find :all, :include => [:details, :user, {:issue => [:project, :author, :tracker, :status]}],
626 626 :conditions => statement,
627 627 :order => options[:order],
628 628 :limit => options[:limit],
629 629 :offset => options[:offset]
630 630 rescue ::ActiveRecord::StatementInvalid => e
631 631 raise StatementInvalid.new(e.message)
632 632 end
633 633
634 634 # Returns the versions
635 635 # Valid options are :conditions
636 636 def versions(options={})
637 637 Version.visible.scoped(:conditions => options[:conditions]).find :all, :include => :project, :conditions => project_statement
638 638 rescue ::ActiveRecord::StatementInvalid => e
639 639 raise StatementInvalid.new(e.message)
640 640 end
641 641
642 642 def sql_for_watcher_id_field(field, operator, value)
643 643 db_table = Watcher.table_name
644 644 "#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (SELECT #{db_table}.watchable_id FROM #{db_table} WHERE #{db_table}.watchable_type='Issue' AND " +
645 645 sql_for_field(field, '=', value, db_table, 'user_id') + ')'
646 646 end
647 647
648 648 def sql_for_member_of_group_field(field, operator, value)
649 649 if operator == '*' # Any group
650 650 groups = Group.all
651 651 operator = '=' # Override the operator since we want to find by assigned_to
652 652 elsif operator == "!*"
653 653 groups = Group.all
654 654 operator = '!' # Override the operator since we want to find by assigned_to
655 655 else
656 656 groups = Group.find_all_by_id(value)
657 657 end
658 658 groups ||= []
659 659
660 660 members_of_groups = groups.inject([]) {|user_ids, group|
661 661 if group && group.user_ids.present?
662 662 user_ids << group.user_ids
663 663 end
664 664 user_ids.flatten.uniq.compact
665 665 }.sort.collect(&:to_s)
666 666
667 667 '(' + sql_for_field("assigned_to_id", operator, members_of_groups, Issue.table_name, "assigned_to_id", false) + ')'
668 668 end
669 669
670 670 def sql_for_assigned_to_role_field(field, operator, value)
671 671 case operator
672 672 when "*", "!*" # Member / Not member
673 673 sw = operator == "!*" ? 'NOT' : ''
674 674 nl = operator == "!*" ? "#{Issue.table_name}.assigned_to_id IS NULL OR" : ''
675 675 "(#{nl} #{Issue.table_name}.assigned_to_id #{sw} IN (SELECT DISTINCT #{Member.table_name}.user_id FROM #{Member.table_name}" +
676 676 " WHERE #{Member.table_name}.project_id = #{Issue.table_name}.project_id))"
677 677 when "=", "!"
678 678 role_cond = value.any? ?
679 679 "#{MemberRole.table_name}.role_id IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")" :
680 680 "1=0"
681 681
682 682 sw = operator == "!" ? 'NOT' : ''
683 683 nl = operator == "!" ? "#{Issue.table_name}.assigned_to_id IS NULL OR" : ''
684 684 "(#{nl} #{Issue.table_name}.assigned_to_id #{sw} IN (SELECT DISTINCT #{Member.table_name}.user_id FROM #{Member.table_name}, #{MemberRole.table_name}" +
685 685 " WHERE #{Member.table_name}.project_id = #{Issue.table_name}.project_id AND #{Member.table_name}.id = #{MemberRole.table_name}.member_id AND #{role_cond}))"
686 686 end
687 687 end
688 688
689 689 private
690 690
691 691 def sql_for_custom_field(field, operator, value, custom_field_id)
692 692 db_table = CustomValue.table_name
693 693 db_field = 'value'
694 694 filter = @available_filters[field]
695 695 if filter && filter[:format] == 'user'
696 696 if value.delete('me')
697 697 value.push User.current.id.to_s
698 698 end
699 699 end
700 700 not_in = nil
701 701 if operator == '!'
702 702 # Makes ! operator work for custom fields with multiple values
703 703 operator = '='
704 704 not_in = 'NOT'
705 705 end
706 706 "#{Issue.table_name}.id #{not_in} IN (SELECT #{Issue.table_name}.id FROM #{Issue.table_name} LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='Issue' AND #{db_table}.customized_id=#{Issue.table_name}.id AND #{db_table}.custom_field_id=#{custom_field_id} WHERE " +
707 707 sql_for_field(field, operator, value, db_table, db_field, true) + ')'
708 708 end
709 709
710 710 # Helper method to generate the WHERE sql for a +field+, +operator+ and a +value+
711 711 def sql_for_field(field, operator, value, db_table, db_field, is_custom_filter=false)
712 712 sql = ''
713 713 case operator
714 714 when "="
715 715 if value.any?
716 716 case type_for(field)
717 717 when :date, :date_past
718 718 sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), (Date.parse(value.first) rescue nil))
719 719 when :integer
720 720 if is_custom_filter
721 721 sql = "(#{db_table}.#{db_field} <> '' AND CAST(#{db_table}.#{db_field} AS decimal(60,3)) = #{value.first.to_i})"
722 722 else
723 723 sql = "#{db_table}.#{db_field} = #{value.first.to_i}"
724 724 end
725 725 when :float
726 726 if is_custom_filter
727 727 sql = "(#{db_table}.#{db_field} <> '' AND CAST(#{db_table}.#{db_field} AS decimal(60,3)) BETWEEN #{value.first.to_f - 1e-5} AND #{value.first.to_f + 1e-5})"
728 728 else
729 729 sql = "#{db_table}.#{db_field} BETWEEN #{value.first.to_f - 1e-5} AND #{value.first.to_f + 1e-5}"
730 730 end
731 731 else
732 732 sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")"
733 733 end
734 734 else
735 735 # IN an empty set
736 736 sql = "1=0"
737 737 end
738 738 when "!"
739 739 if value.any?
740 740 sql = "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + "))"
741 741 else
742 742 # NOT IN an empty set
743 743 sql = "1=1"
744 744 end
745 745 when "!*"
746 746 sql = "#{db_table}.#{db_field} IS NULL"
747 747 sql << " OR #{db_table}.#{db_field} = ''" if is_custom_filter
748 748 when "*"
749 749 sql = "#{db_table}.#{db_field} IS NOT NULL"
750 750 sql << " AND #{db_table}.#{db_field} <> ''" if is_custom_filter
751 751 when ">="
752 752 if [:date, :date_past].include?(type_for(field))
753 753 sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), nil)
754 754 else
755 755 if is_custom_filter
756 756 sql = "(#{db_table}.#{db_field} <> '' AND CAST(#{db_table}.#{db_field} AS decimal(60,3)) >= #{value.first.to_f})"
757 757 else
758 758 sql = "#{db_table}.#{db_field} >= #{value.first.to_f}"
759 759 end
760 760 end
761 761 when "<="
762 762 if [:date, :date_past].include?(type_for(field))
763 763 sql = date_clause(db_table, db_field, nil, (Date.parse(value.first) rescue nil))
764 764 else
765 765 if is_custom_filter
766 766 sql = "(#{db_table}.#{db_field} <> '' AND CAST(#{db_table}.#{db_field} AS decimal(60,3)) <= #{value.first.to_f})"
767 767 else
768 768 sql = "#{db_table}.#{db_field} <= #{value.first.to_f}"
769 769 end
770 770 end
771 771 when "><"
772 772 if [:date, :date_past].include?(type_for(field))
773 773 sql = date_clause(db_table, db_field, (Date.parse(value[0]) rescue nil), (Date.parse(value[1]) rescue nil))
774 774 else
775 775 if is_custom_filter
776 776 sql = "(#{db_table}.#{db_field} <> '' AND CAST(#{db_table}.#{db_field} AS decimal(60,3)) BETWEEN #{value[0].to_f} AND #{value[1].to_f})"
777 777 else
778 778 sql = "#{db_table}.#{db_field} BETWEEN #{value[0].to_f} AND #{value[1].to_f}"
779 779 end
780 780 end
781 781 when "o"
782 782 sql = "#{Issue.table_name}.status_id IN (SELECT id FROM #{IssueStatus.table_name} WHERE is_closed=#{connection.quoted_false})" if field == "status_id"
783 783 when "c"
784 784 sql = "#{Issue.table_name}.status_id IN (SELECT id FROM #{IssueStatus.table_name} WHERE is_closed=#{connection.quoted_true})" if field == "status_id"
785 785 when ">t-"
786 786 sql = relative_date_clause(db_table, db_field, - value.first.to_i, 0)
787 787 when "<t-"
788 788 sql = relative_date_clause(db_table, db_field, nil, - value.first.to_i)
789 789 when "t-"
790 790 sql = relative_date_clause(db_table, db_field, - value.first.to_i, - value.first.to_i)
791 791 when ">t+"
792 792 sql = relative_date_clause(db_table, db_field, value.first.to_i, nil)
793 793 when "<t+"
794 794 sql = relative_date_clause(db_table, db_field, 0, value.first.to_i)
795 795 when "t+"
796 796 sql = relative_date_clause(db_table, db_field, value.first.to_i, value.first.to_i)
797 797 when "t"
798 798 sql = relative_date_clause(db_table, db_field, 0, 0)
799 799 when "w"
800 800 first_day_of_week = l(:general_first_day_of_week).to_i
801 801 day_of_week = Date.today.cwday
802 802 days_ago = (day_of_week >= first_day_of_week ? day_of_week - first_day_of_week : day_of_week + 7 - first_day_of_week)
803 803 sql = relative_date_clause(db_table, db_field, - days_ago, - days_ago + 6)
804 804 when "~"
805 805 sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'"
806 806 when "!~"
807 807 sql = "LOWER(#{db_table}.#{db_field}) NOT LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'"
808 808 else
809 809 raise "Unknown query operator #{operator}"
810 810 end
811 811
812 812 return sql
813 813 end
814 814
815 815 def add_custom_fields_filters(custom_fields)
816 816 @available_filters ||= {}
817 817
818 818 custom_fields.select(&:is_filter?).each do |field|
819 819 case field.field_format
820 820 when "text"
821 821 options = { :type => :text, :order => 20 }
822 822 when "list"
823 823 options = { :type => :list_optional, :values => field.possible_values, :order => 20}
824 824 when "date"
825 825 options = { :type => :date, :order => 20 }
826 826 when "bool"
827 827 options = { :type => :list, :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]], :order => 20 }
828 828 when "int"
829 829 options = { :type => :integer, :order => 20 }
830 830 when "float"
831 831 options = { :type => :float, :order => 20 }
832 832 when "user", "version"
833 833 next unless project
834 834 values = field.possible_values_options(project)
835 835 if User.current.logged? && field.field_format == 'user'
836 836 values.unshift ["<< #{l(:label_me)} >>", "me"]
837 837 end
838 838 options = { :type => :list_optional, :values => values, :order => 20}
839 839 else
840 840 options = { :type => :string, :order => 20 }
841 841 end
842 842 @available_filters["cf_#{field.id}"] = options.merge({ :name => field.name, :format => field.field_format })
843 843 end
844 844 end
845 845
846 846 # Returns a SQL clause for a date or datetime field.
847 847 def date_clause(table, field, from, to)
848 848 s = []
849 849 if from
850 850 from_yesterday = from - 1
851 851 from_yesterday_utc = Time.gm(from_yesterday.year, from_yesterday.month, from_yesterday.day)
852 852 s << ("#{table}.#{field} > '%s'" % [connection.quoted_date(from_yesterday_utc.end_of_day)])
853 853 end
854 854 if to
855 855 to_utc = Time.gm(to.year, to.month, to.day)
856 856 s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date(to_utc.end_of_day)])
857 857 end
858 858 s.join(' AND ')
859 859 end
860 860
861 861 # Returns a SQL clause for a date or datetime field using relative dates.
862 862 def relative_date_clause(table, field, days_from, days_to)
863 863 date_clause(table, field, (days_from ? Date.today + days_from : nil), (days_to ? Date.today + days_to : nil))
864 864 end
865 865 end
@@ -1,2024 +1,2025
1 1 == Redmine changelog
2 2
3 3 Redmine - project management software
4 4 Copyright (C) 2006-2012 Jean-Philippe Lang
5 5 http://www.redmine.org/
6 6
7 7 == TBD v1.4.5
8 8
9 9 * Defect #11192: Make repository identifier accept underscores
10 * Defect #11307: Can't filter for negative numeric custom fields
10 11 * Patch #11328: Fix Japanese mistranslation for 'label_language_based'
11 12
12 13 == 2012-06-18 v1.4.4
13 14
14 15 * Defect #10688: PDF export from Wiki - Problems with tables
15 16 * Defect #11061: Cannot choose commit versions to view differences in Git/Mercurial repository view
16 17 * Defect #11112: REST API - custom fields in POST/PUT ignored for time_entries
17 18 * Defect #11133: Wiki-page section edit link can point to incorrect section
18 19 * Defect #11160: SQL Error on time report if a custom field has multiple values for an entry
19 20 * Defect #11178: Spent time sorted by date-descending order lists same-date entries in physical order
20 21 * Defect #11185: Redmine fails to delete a project with parent/child task
21 22 * Feature #6597: Configurable session lifetime and timeout
22 23 * Patch #11113: Small glitch in German localization
23 24 * Fix for Rails vulnerabilities CVE-2012-2694 and CVE-2012-2695
24 25
25 26 == 2012-06-05 v1.4.3
26 27
27 28 * Defect #11038: "Create and continue" should preserve project, issue and activity when logging time
28 29 * Defect #11046: Redmine.pm does not support "bind as user" ldap authentication
29 30 * Defect #11051: reposman.rb fails in 1.4.2 because of missing require for rubygems
30 31 * Fix for Rails vulnerability CVE-2012-2660
31 32
32 33 == 2012-05-13 v1.4.2
33 34
34 35 * Defect #10744: rake task redmine:email:test broken
35 36 * Defect #10787: "Allow users to unsubscribe" option is confusing
36 37 * Defect #10827: Cannot access Repositories page and Settings in a Project - Error 500
37 38 * Defect #10829: db:migrate fails 0.8.2 -> 1.4.1
38 39 * Defect #10832: REST Uploads fail with fastcgi
39 40 * Defect #10837: reposman and rdm-mailhandler not working with ruby 1.9.x
40 41 * Defect #10856: can not load translations from hr.yml with ruby1.9.3-p194
41 42 * Defect #10865: Filter reset when deleting locked user
42 43 * Feature #9790: Allow filtering text custom fields on "is null" and "is not null"
43 44 * Feature #10778: svn:ignore for config/additional_environment.rb
44 45 * Feature #10875: Partial Albanian Translations
45 46 * Feature #10888: Bring back List-Id to help aid Gmail filtering
46 47 * Patch #10733: Traditional Chinese language file (to r9502)
47 48 * Patch #10745: Japanese translation update (r9519)
48 49 * Patch #10750: Swedish Translation for r9522
49 50 * Patch #10785: Bulgarian translation (jstoolbar)
50 51 * Patch #10800: Simplified Chinese translation
51 52
52 53 == 2012-04-20 v1.4.1
53 54
54 55 * Defect #8574: Time report: date range fields not enabled when using the calendar popup
55 56 * Defect #10642: Nested textile ol/ul lists generate invalid HTML
56 57 * Defect #10668: RSS key is generated twice when user is not reloaded
57 58 * Defect #10669: Token.destroy_expired should not delete API tokens
58 59 * Defect #10675: "Submit and continue" is broken
59 60 * Defect #10711: User cannot change account details with "Login has already been taken" error
60 61 * Feature #10664: Unsubscribe Own User Account
61 62 * Patch #10693: German Translation Update
62 63
63 64 == 2012-04-14 v1.4.0
64 65
65 66 * Defect #2719: Increase username length limit from 30 to 60
66 67 * Defect #3087: Revision referring to issues across all projects
67 68 * Defect #4824: Unable to connect (can't convert Net::LDAP::LdapError into String)
68 69 * Defect #5058: reminder mails are not sent when delivery_method is :async_smtp
69 70 * Defect #6859: Moving issues to a tracker with different custom fields should let fill these fields
70 71 * Defect #7398: Error when trying to quick create a version with required custom field
71 72 * Defect #7495: Python multiline comments highlighting problem in Repository browser
72 73 * Defect #7826: bigdecimal-segfault-fix.rb must be removed for Oracle
73 74 * Defect #7920: Attempted to update a stale object when copying a project
74 75 * Defect #8857: Git: Too long in fetching repositories after upgrade from 1.1 or new branch at first time
75 76 * Defect #9472: The git scm module causes an excess amount of DB traffic.
76 77 * Defect #9685: Adding multiple times the same related issue relation is possible
77 78 * Defect #9798: Release 1.3.0 does not detect rubytree under ruby 1.9.3p0 / rails 2.3.14
78 79 * Defect #9978: Japanese "permission_add_issue_watchers" is wrong
79 80 * Defect #10006: Email reminders are sent for closed issues
80 81 * Defect #10150: CSV export and spent time: rounding issue
81 82 * Defect #10168: CSV export breaks custom columns
82 83 * Defect #10181: Issue context menu and bulk edit form show irrelevant statuses
83 84 * Defect #10198: message_id regex in pop3.rb only recognizes Message-ID header (not Message-Id)
84 85 * Defect #10251: Description diff link in note details is relative when received by email
85 86 * Defect #10272: Ruby 1.9.3: "incompatible character encoding" with LDAP auth
86 87 * Defect #10275: Message object not passed to wiki macros for head topic and in preview edit mode
87 88 * Defect #10334: Full name is not unquoted when creating users from emails
88 89 * Defect #10410: [Localization] Grammar issue of Simplified Chinese in zh.yml
89 90 * Defect #10442: Ruby 1.9.3 Time Zone setting Internal error.
90 91 * Defect #10467: Confusing behavior while moving issue to a project with disabled Issues module
91 92 * Defect #10575: Uploading of attachments which filename contains non-ASCII chars fails with Ruby 1.9
92 93 * Defect #10590: WikiContent::Version#text return string with #<Encoding:ASCII-8BIT> when uncompressed
93 94 * Defect #10593: Error: 'incompatible character encodings: UTF-8 and ASCII-8BIT' (old annoing issue) on ruby-1.9.3
94 95 * Defect #10600: Watchers search generates an Internal error
95 96 * Defect #10605: Bulk edit selected issues does not allow selection of blank values for custom fields
96 97 * Defect #10619: When changing status before tracker, it shows improper status
97 98 * Feature #779: Multiple SCM per project
98 99 * Feature #971: Add "Spent time" column to query
99 100 * Feature #1060: Add a LDAP-filter using external auth sources
100 101 * Feature #1102: Shortcut for assigning an issue to me
101 102 * Feature #1189: Multiselect custom fields
102 103 * Feature #1363: Allow underscores in project identifiers
103 104 * Feature #1913: LDAP - authenticate as user
104 105 * Feature #1972: Attachments for News
105 106 * Feature #2009: Manually add related revisions
106 107 * Feature #2323: Workflow permissions for administrators
107 108 * Feature #2416: {background:color} doesn't work in text formatting
108 109 * Feature #2694: Notification on loosing assignment
109 110 * Feature #2715: "Magic links" to notes
110 111 * Feature #2850: Add next/previous navigation to issue
111 112 * Feature #3055: Option to copy attachments when copying an issue
112 113 * Feature #3108: set parent automatically for new pages
113 114 * Feature #3463: Export all wiki pages to PDF
114 115 * Feature #4050: Ruby 1.9 support
115 116 * Feature #4769: Ability to move an issue to a different project from the update form
116 117 * Feature #4774: Change the hyperlink for file attachment to view and download
117 118 * Feature #5159: Ability to add Non-Member watchers to the watch list
118 119 * Feature #5638: Use Bundler (Gemfile) for gem management
119 120 * Feature #5643: Add X-Redmine-Sender header to email notifications
120 121 * Feature #6296: Bulk-edit custom fields through context menu
121 122 * Feature #6386: Issue mail should render the HTML version of the issue details
122 123 * Feature #6449: Edit a wiki page's parent on the edit page
123 124 * Feature #6555: Double-click on "Submit" and "Save" buttons should not send two requests to server
124 125 * Feature #7361: Highlight active query in the side bar
125 126 * Feature #7420: Rest API for projects members
126 127 * Feature #7603: Please make editing issues more obvious than "Change properties (More)"
127 128 * Feature #8171: Adding attachments through the REST API
128 129 * Feature #8691: Better handling of issue update conflict
129 130 * Feature #9803: Change project through REST API issue update
130 131 * Feature #9923: User type custom fields should be filterable by "Me".
131 132 * Feature #9985: Group time report by the Status field
132 133 * Feature #9995: Time entries insertion, "Create and continue" button
133 134 * Feature #10020: Enable global time logging at /time_entries/new
134 135 * Feature #10042: Bulk change private flag
135 136 * Feature #10126: Add members of subprojects in the assignee and author filters
136 137 * Feature #10131: Include custom fiels in time entries API responses
137 138 * Feature #10207: Git: use default branch from HEAD
138 139 * Feature #10208: Estonian translation
139 140 * Feature #10253: Better handling of attachments when validation fails
140 141 * Feature #10350: Bulk copy should allow for changing the target version
141 142 * Feature #10607: Ignore out-of-office incoming emails
142 143 * Feature #10635: Adding time like "123 Min" is invalid
143 144 * Patch #9998: Make attachement "Optional Description" less wide
144 145 * Patch #10066: i18n not working with russian gem
145 146 * Patch #10128: Disable IE 8 compatibility mode to fix wrong div.autoscroll scroll bar behaviour
146 147 * Patch #10155: Russian translation changed
147 148 * Patch #10464: Enhanced PDF output for Issues list
148 149 * Patch #10470: Efficiently process new git revisions in a single batch
149 150 * Patch #10513: Dutch translation improvement
150 151
151 152 == 2012-04-14 v1.3.3
152 153
153 154 * Defect #10505: Error when exporting to PDF with NoMethodError (undefined method `downcase' for nil:NilClass)
154 155 * Defect #10554: Defect symbols when exporting tasks in pdf
155 156 * Defect #10564: Unable to change locked, sticky flags and board when editing a message
156 157 * Defect #10591: Dutch "label_file_added" translation is wrong
157 158 * Defect #10622: "Default administrator account changed" is always true
158 159 * Patch #10555: rake redmine:send_reminders aborted if issue assigned to group
159 160 * Patch #10611: Simplified Chinese translations for 1.3-stable
160 161
161 162 == 2012-03-11 v1.3.2
162 163
163 164 * Defect #8194: {{toc}} uses identical anchors for subsections with the same name
164 165 * Defect #9143: Partial diff comparison should be done on actual code, not on html
165 166 * Defect #9523: {{toc}} does not display headers with @ code markup
166 167 * Defect #9815: Release 1.3.0 does not detect rubytree with rubgems 1.8
167 168 * Defect #10053: undefined method `<=>' for nil:NilClass when accessing the settings of a project
168 169 * Defect #10135: ActionView::TemplateError (can't convert Fixnum into String)
169 170 * Defect #10193: Unappropriate icons in highlighted code block
170 171 * Defect #10199: No wiki section edit when title contains code
171 172 * Defect #10218: Error when creating a project with a version custom field
172 173 * Defect #10241: "get version by ID" fails with "401 not authorized" error when using API access key
173 174 * Defect #10284: Note added by commit from a subproject does not contain project identifier
174 175 * Defect #10374: User list is empty when adding users to project / group if remaining users are added late
175 176 * Defect #10390: Mass assignment security vulnerability
176 177 * Patch #8413: Confirmation message before deleting a relationship
177 178 * Patch #10160: Bulgarian translation (r8777)
178 179 * Patch #10242: Migrate Redmine.pm from Digest::Sha1 to Digest::Sha
179 180 * Patch #10258: Italian translation for 1.3-stable
180 181
181 182 == 2012-02-06 v1.3.1
182 183
183 184 * Defect #9775: app/views/repository/_revision_graph.html.erb sets window.onload directly..
184 185 * Defect #9792: Ruby 1.9: [v1.3.0] Error: incompatible character encodings for it translation on Calendar page
185 186 * Defect #9793: Bad spacing between numbered list and heading (recently broken).
186 187 * Defect #9795: Unrelated error message when creating a group with an invalid name
187 188 * Defect #9832: Revision graph height should depend on height of rows in revisions table
188 189 * Defect #9937: Repository settings are not saved when all SCM are disabled
189 190 * Defect #9961: Ukrainian "default_tracker_bug" is wrong
190 191 * Defect #10013: Rest API - Create Version -> Internal server error 500
191 192 * Defect #10115: Javascript error - Can't attach more than 1 file on IE 6 and 7
192 193 * Defect #10130: Broken italic text style in edited comment preview
193 194 * Defect #10152: Attachment diff type is not saved in user preference
194 195 * Feature #9943: Arabic translation
195 196 * Patch #9874: pt-BR translation updates
196 197 * Patch #9922: Spanish translation updated
197 198 * Patch #10137: Korean language file ko.yml updated to Redmine 1.3.0
198 199
199 200 == 2011-12-10 v1.3.0
200 201
201 202 * Defect #2109: Context menu is being submitted twice per right click
202 203 * Defect #7717: MailHandler user creation for unknown_user impossible due to diverging length-limits of login and email fields
203 204 * Defect #7917: Creating users via email fails if user real name containes special chars
204 205 * Defect #7966: MailHandler does not include JournalDetail for attached files
205 206 * Defect #8368: Bad decimal separator in time entry CSV
206 207 * Defect #8371: MySQL error when filtering a custom field using the REST api
207 208 * Defect #8549: Export CSV has character encoding error
208 209 * Defect #8573: Do not show inactive Enumerations where not needed
209 210 * Defect #8611: rake/rdoctask is deprecated
210 211 * Defect #8751: Email notification: bug, when number of recipients more then 8
211 212 * Defect #8894: Private issues - make it more obvious in the UI?
212 213 * Defect #8994: Hardcoded French string "anonyme"
213 214 * Defect #9043: Hardcoded string "diff" in Wiki#show and Repositories_Helper
214 215 * Defect #9051: wrong "text_issue_added" in russian translation.
215 216 * Defect #9108: Custom query not saving status filter
216 217 * Defect #9252: Regression: application title escaped 2 times
217 218 * Defect #9264: Bad Portuguese translation
218 219 * Defect #9470: News list is missing Avatars
219 220 * Defect #9471: Inline markup broken in Wiki link labels
220 221 * Defect #9489: Label all input field and control tags
221 222 * Defect #9534: Precedence: bulk email header is non standard and discouraged
222 223 * Defect #9540: Issue filter by assigned_to_role is not project specific
223 224 * Defect #9619: Time zone ignored when logging time while editing ticket
224 225 * Defect #9638: Inconsistent image filename extensions
225 226 * Defect #9669: Issue list doesn't sort assignees/authors regarding user display format
226 227 * Defect #9672: Message-quoting in forums module broken
227 228 * Defect #9719: Filtering by numeric custom field types broken after update to master
228 229 * Defect #9724: Can't remote add new categories
229 230 * Defect #9738: Setting of cross-project custom query is not remembered inside project
230 231 * Defect #9748: Error about configuration.yml validness should mention file path
231 232 * Feature #69: Textilized description in PDF
232 233 * Feature #401: Add pdf export for WIKI page
233 234 * Feature #1567: Make author column sortable and groupable
234 235 * Feature #2222: Single section edit.
235 236 * Feature #2269: Default issue start date should become configurable.
236 237 * Feature #2371: character encoding for attachment file
237 238 * Feature #2964: Ability to assign issues to groups
238 239 * Feature #3033: Bug Reporting: Using "Create and continue" should show bug id of saved bug
239 240 * Feature #3261: support attachment images in PDF export
240 241 * Feature #4264: Update CodeRay to 1.0 final
241 242 * Feature #4324: Redmine renames my files, it shouldn't.
242 243 * Feature #4729: Add Date-Based Filters for Issues List
243 244 * Feature #4742: CSV export: option to export selected or all columns
244 245 * Feature #4976: Allow rdm-mailhandler to read the API key from a file
245 246 * Feature #5501: Git: Mercurial: Adding visual merge/branch history to repository view
246 247 * Feature #5634: Export issue to PDF does not include Subtasks and Related Issues
247 248 * Feature #5670: Cancel option for file upload
248 249 * Feature #5737: Custom Queries available through the REST Api
249 250 * Feature #6180: Searchable custom fields do not provide adequate operators
250 251 * Feature #6954: Filter from date to date
251 252 * Feature #7180: List of statuses in REST API
252 253 * Feature #7181: List of trackers in REST API
253 254 * Feature #7366: REST API for Issue Relations
254 255 * Feature #7403: REST API for Versions
255 256 * Feature #7671: REST API for reading attachments
256 257 * Feature #7832: Ability to assign issue categories to groups
257 258 * Feature #8420: Consider removing #7013 workaround
258 259 * Feature #9196: Improve logging in MailHandler when user creation fails
259 260 * Feature #9496: Adds an option in mailhandler to disable server certificate verification
260 261 * Feature #9553: CRUD operations for "Issue categories" in REST API
261 262 * Feature #9593: HTML title should be reordered
262 263 * Feature #9600: Wiki links for news and forums
263 264 * Feature #9607: Filter for issues without start date (or any another field based on date type)
264 265 * Feature #9609: Upgrade to Rails 2.3.14
265 266 * Feature #9612: "side by side" and "inline" patch view for attachments
266 267 * Feature #9667: Check attachment size before upload
267 268 * Feature #9690: Link in notification pointing to the actual update
268 269 * Feature #9720: Add note number for single issue's PDF
269 270 * Patch #8617: Indent subject of subtask ticket in exported issues PDF
270 271 * Patch #8778: Traditional Chinese 'issue' translation change
271 272 * Patch #9053: Fix up Russian translation
272 273 * Patch #9129: Improve wording of Git repository note at project setting
273 274 * Patch #9148: Better handling of field_due_date italian translation
274 275 * Patch #9273: Fix typos in russian localization
275 276 * Patch #9484: Limit SCM annotate to text files under the maximum file size for viewing
276 277 * Patch #9659: Indexing rows in auth_sources/index view
277 278 * Patch #9692: Fix Textilized description in PDF for CodeRay
278 279
279 280 == 2011-12-10 v1.2.3
280 281
281 282 * Defect #8707: Reposman: wrong constant name
282 283 * Defect #8809: Table in timelog report overflows
283 284 * Defect #9055: Version files in Files module cannot be downloaded if issue tracking is disabled
284 285 * Defect #9137: db:encrypt fails to handle repositories with blank password
285 286 * Defect #9394: Custom date field only validating on regex and not a valid date
286 287 * Defect #9405: Any user with :log_time permission can edit time entries via context menu
287 288 * Defect #9448: The attached images are not shown in documents
288 289 * Defect #9520: Copied private query not visible after project copy
289 290 * Defect #9552: Error when reading ciphered text from the database without cipher key configured
290 291 * Defect #9566: Redmine.pm considers all projects private when login_required is enabled
291 292 * Defect #9567: Redmine.pm potential security issue with cache credential enabled and subversion
292 293 * Defect #9577: Deleting a subtasks doesn't update parent's rgt & lft values
293 294 * Defect #9597: Broken version links in wiki annotate history
294 295 * Defect #9682: Wiki HTML Export only useful when Access history is accessible
295 296 * Defect #9737: Custom values deleted before issue submit
296 297 * Defect #9741: calendar-hr.js (Croatian) is not UTF-8
297 298 * Patch #9558: Simplified Chinese translation for 1.2.2 updated
298 299 * Patch #9695: Bulgarian translation (r7942)
299 300
300 301 == 2011-11-11 v1.2.2
301 302
302 303 * Defect #3276: Incorrect handling of anchors in Wiki to HTML export
303 304 * Defect #7215: Wiki formatting mangles links to internal headers
304 305 * Defect #7613: Generated test instances may share the same attribute value object
305 306 * Defect #8411: Can't remove "Project" column on custom query
306 307 * Defect #8615: Custom 'version' fields don't show shared versions
307 308 * Defect #8633: Pagination counts non visible issues
308 309 * Defect #8651: Email attachments are not added to issues any more in v1.2
309 310 * Defect #8825: JRuby + Windows: SCMs do not work on Redmine 1.2
310 311 * Defect #8836: Additional workflow transitions not available when set to both author and assignee
311 312 * Defect #8865: Custom field regular expression is not validated
312 313 * Defect #8880: Error deleting issue with grandchild
313 314 * Defect #8884: Assignee is cleared when updating issue with locked assignee
314 315 * Defect #8892: Unused fonts in rfpdf plugin folder
315 316 * Defect #9161: pt-BR field_warn_on_leaving_unsaved has a small gramatical error
316 317 * Defect #9308: Search fails when a role haven't "view wiki" permission
317 318 * Defect #9465: Mercurial: can't browse named branch below Mercurial 1.5
318 319
319 320 == 2011-07-11 v1.2.1
320 321
321 322 * Defect #5089: i18N error on truncated revision diff view
322 323 * Defect #7501: Search options get lost after clicking on a specific result type
323 324 * Defect #8229: "project.xml" response does not include the parent ID
324 325 * Defect #8449: Wiki annotated page does not display author of version 1
325 326 * Defect #8467: Missing german translation - Warn me when leaving a page with unsaved text
326 327 * Defect #8468: No warning when leaving page with unsaved text that has not lost focus
327 328 * Defect #8472: Private checkbox ignored on issue creation with "Set own issues public or private" permission
328 329 * Defect #8510: JRuby: Can't open administrator panel if scm command is not available
329 330 * Defect #8512: Syntax highlighter on Welcome page
330 331 * Defect #8554: Translation missing error on custom field validation
331 332 * Defect #8565: JRuby: Japanese PDF export error
332 333 * Defect #8566: Exported PDF UTF-8 Vietnamese not correct
333 334 * Defect #8569: JRuby: PDF export error with TypeError
334 335 * Defect #8576: Missing german translation - different things
335 336 * Defect #8616: Circular relations
336 337 * Defect #8646: Russian translation "label_follows" and "label_follows" are wrong
337 338 * Defect #8712: False 'Description updated' journal details messages
338 339 * Defect #8729: Not-public queries are not private
339 340 * Defect #8737: Broken line of long issue description on issue PDF.
340 341 * Defect #8738: Missing revision number/id of associated revisions on issue PDF
341 342 * Defect #8739: Workflow copy does not copy advanced workflow settings
342 343 * Defect #8759: Setting issue attributes from mail should be case-insensitive
343 344 * Defect #8777: Mercurial: Not able to Resetting Redmine project respository
344 345
345 346 == 2011-05-30 v1.2.0
346 347
347 348 * Defect #61: Broken character encoding in pdf export
348 349 * Defect #1965: Redmine is not Tab Safe
349 350 * Defect #2274: Filesystem Repository path encoding of non UTF-8 characters
350 351 * Defect #2664: Mercurial: Repository path encoding of non UTF-8 characters
351 352 * Defect #3421: Mercurial reads files from working dir instead of changesets
352 353 * Defect #3462: CVS: Repository path encoding of non UTF-8 characters
353 354 * Defect #3715: Login page should not show projects link and search box if authentication is required
354 355 * Defect #3724: Mercurial repositories display revision ID instead of changeset ID
355 356 * Defect #3761: Most recent CVS revisions are missing in "revisions" view
356 357 * Defect #4270: CVS Repository view in Project doesn't show Author, Revision, Comment
357 358 * Defect #5138: Don't use Ajax for pagination
358 359 * Defect #5152: Cannot use certain characters for user and role names.
359 360 * Defect #5251: Git: Repository path encoding of non UTF-8 characters
360 361 * Defect #5373: Translation missing when adding invalid watchers
361 362 * Defect #5817: Shared versions not shown in subproject's gantt chart
362 363 * Defect #6013: git tab,browsing, very slow -- even after first time
363 364 * Defect #6148: Quoting, newlines, and nightmares...
364 365 * Defect #6256: Redmine considers non ASCII and UTF-16 text files as binary in SCM
365 366 * Defect #6476: Subproject's issues are not shown in the subproject's gantt
366 367 * Defect #6496: Remove i18n 0.3.x/0.4.x hack for Rails 2.3.5
367 368 * Defect #6562: Context-menu deletion of issues deletes all subtasks too without explicit prompt
368 369 * Defect #6604: Issues targeted at parent project versions' are not shown on gantt chart
369 370 * Defect #6706: Resolving issues with the commit message produces the wrong comment with CVS
370 371 * Defect #6901: Copy/Move an issue does not give any history of who actually did the action.
371 372 * Defect #6905: Specific heading-content breaks CSS
372 373 * Defect #7000: Project filter not applied on versions in Gantt chart
373 374 * Defect #7097: Starting day of week cannot be set to Saturday
374 375 * Defect #7114: New gantt doesn't display some projects
375 376 * Defect #7146: Git adapter lost commits before 7 days from database latest changeset
376 377 * Defect #7218: Date range error on issue query
377 378 * Defect #7257: "Issues by" version links bad criterias
378 379 * Defect #7279: CSS class ".icon-home" is not used.
379 380 * Defect #7320: circular dependency >2 issues
380 381 * Defect #7352: Filters not working in Gantt charts
381 382 * Defect #7367: Receiving pop3 email should not output debug messages
382 383 * Defect #7373: Error with PDF output and ruby 1.9.2
383 384 * Defect #7379: Remove extraneous hidden_field on wiki history
384 385 * Defect #7516: Redmine does not work with RubyGems 1.5.0
385 386 * Defect #7518: Mercurial diff can be wrong if the previous changeset isn't the parent
386 387 * Defect #7581: Not including a spent time value on the main issue update screen causes silent data loss
387 388 * Defect #7582: hiding form pages from search engines
388 389 * Defect #7597: Subversion and Mercurial log have the possibility to miss encoding
389 390 * Defect #7604: ActionView::TemplateError (undefined method `name' for nil:NilClass)
390 391 * Defect #7605: Using custom queries always redirects to "Issues" tab
391 392 * Defect #7615: CVS diffs do not handle new files properly
392 393 * Defect #7618: SCM diffs do not handle one line new files properly
393 394 * Defect #7639: Some date fields do not have requested format.
394 395 * Defect #7657: Wrong commit range in git log command on Windows
395 396 * Defect #7818: Wiki pages don't use the local timezone to display the "Updated ? hours ago" mouseover
396 397 * Defect #7821: Git "previous" and "next" revisions are incorrect
397 398 * Defect #7827: CVS: Age column on repository view is off by timezone delta
398 399 * Defect #7843: Add a relation between issues = explicit login window ! (basic authentication popup is prompted on AJAX request)
399 400 * Defect #8011: {{toc}} does not display headlines with inline code markup
400 401 * Defect #8029: List of users for adding to a group may be empty if 100 first users have been added
401 402 * Defect #8064: Text custom fields do not wrap on the issue list
402 403 * Defect #8071: Watching a subtask from the context menu updates main issue watch link
403 404 * Defect #8072: Two untranslatable default role names
404 405 * Defect #8075: Some "notifiable" names are not i18n-enabled
405 406 * Defect #8081: GIT: Commits missing when user has the "decorate" git option enabled
406 407 * Defect #8088: Colorful indentation of subprojects must be on right in RTL locales
407 408 * Defect #8239: notes field is not propagated during issue copy
408 409 * Defect #8356: GET /time_entries.xml ignores limit/offset parameters
409 410 * Defect #8432: Private issues information shows up on Activity page for unauthorized users
410 411 * Feature #746: Versioned issue descriptions
411 412 * Feature #1067: Differentiate public/private saved queries in the sidebar
412 413 * Feature #1236: Make destination folder for attachment uploads configurable
413 414 * Feature #1735: Per project repository log encoding setting
414 415 * Feature #1763: Autologin-cookie should be configurable
415 416 * Feature #1981: display mercurial tags
416 417 * Feature #2074: Sending email notifications when comments are added in the news section
417 418 * Feature #2096: Custom fields referencing system tables (users and versions)
418 419 * Feature #2732: Allow additional workflow transitions for author and assignee
419 420 * Feature #2910: Warning on leaving edited issue/wiki page without saving
420 421 * Feature #3396: Git: use --encoding=UTF-8 in "git log"
421 422 * Feature #4273: SCM command availability automatic check in administration panel
422 423 * Feature #4477: Use mime types in downloading from repository
423 424 * Feature #5518: Graceful fallback for "missing translation" needed
424 425 * Feature #5520: Text format buttons and preview link missing when editing comment
425 426 * Feature #5831: Parent Task to Issue Bulk Edit
426 427 * Feature #6887: Upgrade to Rails 2.3.11
427 428 * Feature #7139: Highlight changes inside diff lines
428 429 * Feature #7236: Collapse All for Groups
429 430 * Feature #7246: Handle "named branch" for mercurial
430 431 * Feature #7296: Ability for admin to delete users
431 432 * Feature #7318: Add user agent to Redmine Mailhandler
432 433 * Feature #7408: Add an application configuration file
433 434 * Feature #7409: Cross project Redmine links
434 435 * Feature #7410: Add salt to user passwords
435 436 * Feature #7411: Option to cipher LDAP ans SCM passwords stored in the database
436 437 * Feature #7412: Add an issue visibility level to each role
437 438 * Feature #7414: Private issues
438 439 * Feature #7517: Configurable path of executable for scm adapters
439 440 * Feature #7640: Add "mystery man" gravatar to options
440 441 * Feature #7858: RubyGems 1.6 support
441 442 * Feature #7893: Group filter on the users list
442 443 * Feature #7899: Box for editing comments should open with the formatting toolbar
443 444 * Feature #7921: issues by pulldown should have 'status' option
444 445 * Feature #7996: Bulk edit and context menu for time entries
445 446 * Feature #8006: Right click context menu for Related Issues
446 447 * Feature #8209: I18n YAML files not parsable with psych yaml library
447 448 * Feature #8345: Link to user profile from account page
448 449 * Feature #8365: Git: per project setting to report last commit or not in repository tree
449 450 * Patch #5148: metaKey not handled in issues selection
450 451 * Patch #5629: Wrap text fields properly in PDF
451 452 * Patch #7418: Redmine Persian Translation
452 453 * Patch #8295: Wrap title fields properly in PDF
453 454 * Patch #8310: fixes automatic line break problem with TCPDF
454 455 * Patch #8312: Switch to TCPDF from FPDF for PDF export
455 456
456 457 == 2011-04-29 v1.1.3
457 458
458 459 * Defect #5773: Email reminders are sent to locked users
459 460 * Defect #6590: Wrong file list link in email notification on new file upload
460 461 * Defect #7589: Wiki page with backslash in title can not be found
461 462 * Defect #7785: Mailhandler keywords are not removed when updating issues
462 463 * Defect #7794: Internal server error on formatting an issue as a PDF in Japanese
463 464 * Defect #7838: Gantt- Issues does not show up in green when start and end date are the same
464 465 * Defect #7846: Headers (h1, etc.) containing backslash followed by a digit are not displayed correctly
465 466 * Defect #7875: CSV export separators in polish locale (pl.yml)
466 467 * Defect #7890: Internal server error when referencing an issue without project in commit message
467 468 * Defect #7904: Subprojects not properly deleted when deleting a parent project
468 469 * Defect #7939: Simultaneous Wiki Updates Cause Internal Error
469 470 * Defect #7951: Atom links broken on wiki index
470 471 * Defect #7954: IE 9 can not select issues, does not display context menu
471 472 * Defect #7985: Trying to do a bulk edit results in "Internal Error"
472 473 * Defect #8003: Error raised by reposman.rb under Windows server 2003
473 474 * Defect #8012: Wrong selection of modules when adding new project after validation error
474 475 * Defect #8038: Associated Revisions OL/LI items are not styled properly in issue view
475 476 * Defect #8067: CSV exporting in Italian locale
476 477 * Defect #8235: bulk edit issues and copy issues error in es, gl and ca locales
477 478 * Defect #8244: selected modules are not activated when copying a project
478 479 * Patch #7278: Update Simplified Chinese translation to 1.1
479 480 * Patch #7390: Fixes in Czech localization
480 481 * Patch #7963: Reminder email: Link for show all issues does not sort
481 482
482 483 == 2011-03-07 v1.1.2
483 484
484 485 * Defect #3132: Bulk editing menu non-functional in Opera browser
485 486 * Defect #6090: Most binary files become corrupted when downloading from CVS repository browser when Redmine is running on a Windows server
486 487 * Defect #7280: Issues subjects wrap in Gantt
487 488 * Defect #7288: Non ASCII filename downloaded from repo is broken on Internet Explorer.
488 489 * Defect #7317: Gantt tab gives internal error due to nil avatar icon
489 490 * Defect #7497: Aptana Studio .project file added to version 1.1.1-stable
490 491 * Defect #7611: Workflow summary shows X icon for workflow with exactly 1 status transition
491 492 * Defect #7625: Syntax highlighting unavailable from board new topic or topic edit preview
492 493 * Defect #7630: Spent time in commits not recognized
493 494 * Defect #7656: MySQL SQL Syntax Error when filtering issues by Assignee's Group
494 495 * Defect #7718: Minutes logged in commit message are converted to hours
495 496 * Defect #7763: Email notification are sent to watchers even if 'No events' setting is chosen
496 497 * Feature #7608: Add "retro" gravatars
497 498 * Patch #7598: Extensible MailHandler
498 499 * Patch #7795: Internal server error at journals#index with custom fields
499 500
500 501 == 2011-01-30 v1.1.1
501 502
502 503 * Defect #4899: Redmine fails to list files for darcs repository
503 504 * Defect #7245: Wiki fails to find pages with cyrillic characters using postgresql
504 505 * Defect #7256: redmine/public/.htaccess must be moved for non-fastcgi installs/upgrades
505 506 * Defect #7258: Automatic spent time logging does not work properly with SQLite3
506 507 * Defect #7259: Released 1.1.0 uses "devel" label inside admin information
507 508 * Defect #7265: "Loading..." icon does not disappear after add project member
508 509 * Defect #7266: Test test_due_date_distance_in_words fail due to undefined locale
509 510 * Defect #7274: CSV value separator in dutch locale
510 511 * Defect #7277: Enabling gravatas causes usernames to overlap first name field in user list
511 512 * Defect #7294: "Notifiy for only project I select" is not available anymore in 1.1.0
512 513 * Defect #7307: HTTP 500 error on query for empty revision
513 514 * Defect #7313: Label not translated in french in Settings/Email Notification tab
514 515 * Defect #7329: <code class="javascript"> with long strings may hang server
515 516 * Defect #7337: My page french translation
516 517 * Defect #7348: French Translation of "Connection"
517 518 * Defect #7385: Error when viewing an issue which was related to a deleted subtask
518 519 * Defect #7386: NoMethodError on pdf export
519 520 * Defect #7415: Darcs adapter recognizes new files as modified files above Darcs 2.4
520 521 * Defect #7421: no email sent with 'Notifiy for any event on the selected projects only'
521 522 * Feature #5344: Update to latest CodeRay 0.9.x
522 523
523 524 == 2011-01-09 v1.1.0
524 525
525 526 * Defect #2038: Italics in wiki headers show-up wrong in the toc
526 527 * Defect #3449: Redmine Takes Too Long On Large Mercurial Repository
527 528 * Defect #3567: Sorting for changesets might go wrong on Mercurial repos
528 529 * Defect #3707: {{toc}} doesn't work with {{include}}
529 530 * Defect #5096: Redmine hangs up while browsing Git repository
530 531 * Defect #6000: Safe Attributes prevents plugin extension of Issue model...
531 532 * Defect #6064: Modules not assigned to projects created via API
532 533 * Defect #6110: MailHandler should allow updating Issue Priority and Custom fields
533 534 * Defect #6136: JSON API holds less information than XML API
534 535 * Defect #6345: xml used by rest API is invalid
535 536 * Defect #6348: Gantt chart PDF rendering errors
536 537 * Defect #6403: Updating an issue with custom fields fails
537 538 * Defect #6467: "Member of role", "Member of group" filter not work correctly
538 539 * Defect #6473: New gantt broken after clearing issue filters
539 540 * Defect #6541: Email notifications send to everybody
540 541 * Defect #6549: Notification settings not migrated properly
541 542 * Defect #6591: Acronyms must have a minimum of three characters
542 543 * Defect #6674: Delete time log broken after changes to REST
543 544 * Defect #6681: Mercurial, Bazaar and Darcs auto close issue text should be commit id instead of revision number
544 545 * Defect #6724: Wiki uploads does not work anymore (SVN 4266)
545 546 * Defect #6746: Wiki links are broken on Activity page
546 547 * Defect #6747: Wiki diff does not work since r4265
547 548 * Defect #6763: New gantt charts: subject displayed twice on issues
548 549 * Defect #6826: Clicking "Add" twice creates duplicate member record
549 550 * Defect #6844: Unchecking status filter on the issue list has no effect
550 551 * Defect #6895: Wrong Polish translation of "blocks"
551 552 * Defect #6943: Migration from boolean to varchar fails on PostgreSQL 8.1
552 553 * Defect #7064: Mercurial adapter does not recognize non alphabetic nor numeric in UTF-8 copied files
553 554 * Defect #7128: New gantt chart does not render subtasks under parent task
554 555 * Defect #7135: paging mechanism returns the same last page forever
555 556 * Defect #7188: Activity page not refreshed when changing language
556 557 * Defect #7195: Apply CLI-supplied defaults for incoming mail only to new issues not replies
557 558 * Defect #7197: Tracker reset to default when replying to an issue email
558 559 * Defect #7213: Copy project does not copy all roles and permissions
559 560 * Defect #7225: Project settings: Trackers & Custom fields only relevant if module Issue tracking is active
560 561 * Feature #630: Allow non-unique names for projects
561 562 * Feature #1738: Add a "Visible" flag to project/user custom fields
562 563 * Feature #2803: Support for Javascript in Themes
563 564 * Feature #2852: Clean Incoming Email of quoted text "----- Reply above this line ------"
564 565 * Feature #2995: Improve error message when trying to access an archived project
565 566 * Feature #3170: Autocomplete issue relations on subject
566 567 * Feature #3503: Administrator Be Able To Modify Email settings Of Users
567 568 * Feature #4155: Automatic spent time logging from commit messages
568 569 * Feature #5136: Parent select on Wiki rename page
569 570 * Feature #5338: Descendants (subtasks) should be available via REST API
570 571 * Feature #5494: Wiki TOC should display heading from level 4
571 572 * Feature #5594: Improve MailHandler's keyword handling
572 573 * Feature #5622: Allow version to be set via incoming email
573 574 * Feature #5712: Reload themes
574 575 * Feature #5869: Issue filters by Group and Role
575 576 * Feature #6092: Truncate Git revision labels in Activity page/feed and allow configurable length
576 577 * Feature #6112: Accept localized keywords when receiving emails
577 578 * Feature #6140: REST issues response with issue count limit and offset
578 579 * Feature #6260: REST API for Users
579 580 * Feature #6276: Gantt Chart rewrite
580 581 * Feature #6446: Remove length limits on project identifier and name
581 582 * Feature #6628: Improvements in truncate email
582 583 * Feature #6779: Project JSON API
583 584 * Feature #6823: REST API for time tracker.
584 585 * Feature #7072: REST API for news
585 586 * Feature #7111: Expose more detail on journal entries
586 587 * Feature #7141: REST API: get information about current user
587 588 * Patch #4807: Allow to set the done_ratio field with the incoming mail system
588 589 * Patch #5441: Initialize TimeEntry attributes with params[:time_entry]
589 590 * Patch #6762: Use GET instead of POST to retrieve context_menu
590 591 * Patch #7160: French translation ofr "not_a_date" is missing
591 592 * Patch #7212: Missing remove_index in AddUniqueIndexOnMembers down migration
592 593
593 594
594 595 == 2010-12-23 v1.0.5
595 596
596 597 * #6656: Mercurial adapter loses seconds of commit times
597 598 * #6996: Migration trac(sqlite3) -> redmine(postgresql) doesnt escape ' char
598 599 * #7013: v-1.0.4 trunk - see {{count}} in page display rather than value
599 600 * #7016: redundant 'field_start_date' in ja.yml
600 601 * #7018: 'undefined method `reschedule_after' for nil:NilClass' on new issues
601 602 * #7024: E-mail notifications about Wiki changes.
602 603 * #7033: 'class' attribute of <pre> tag shouldn't be truncate
603 604 * #7035: CSV value separator in russian
604 605 * #7122: Issue-description Quote-button missing
605 606 * #7144: custom queries making use of deleted custom fields cause a 500 error
606 607 * #7162: Multiply defined label in french translation
607 608
608 609 == 2010-11-28 v1.0.4
609 610
610 611 * #5324: Git not working if color.ui is enabled
611 612 * #6447: Issues API doesn't allow full key auth for all actions
612 613 * #6457: Edit User group problem
613 614 * #6575: start date being filled with current date even when blank value is submitted
614 615 * #6740: Max attachment size, incorrect usage of 'KB'
615 616 * #6760: Select box sorted by ID instead of name in Issue Category
616 617 * #6766: Changing target version name can cause an internal error
617 618 * #6784: Redmine not working with i18n gem 0.4.2
618 619 * #6839: Hardcoded absolute links in my/page_layout
619 620 * #6841: Projects API doesn't allow full key auth for all actions
620 621 * #6860: svn: Write error: Broken pipe when browsing repository
621 622 * #6874: API should return XML description when creating a project
622 623 * #6932: submitting wrong parent task input creates a 500 error
623 624 * #6966: Records of Forums are remained, deleting project
624 625 * #6990: Layout problem in workflow overview
625 626 * #5117: mercurial_adapter should ensure the right LANG environment variable
626 627 * #6782: Traditional Chinese language file (to r4352)
627 628 * #6783: Swedish Translation for r4352
628 629 * #6804: Bugfix: spelling fixes
629 630 * #6814: Japanese Translation for r4362
630 631 * #6948: Bulgarian translation
631 632 * #6973: Update es.yml
632 633
633 634 == 2010-10-31 v1.0.3
634 635
635 636 * #4065: Redmine.pm doesn't work with LDAPS and a non-standard port
636 637 * #4416: Link from version details page to edit the wiki.
637 638 * #5484: Add new issue as subtask to an existing ticket
638 639 * #5948: Update help/wiki_syntax_detailed.html with more link options
639 640 * #6494: Typo in pt_BR translation for 1.0.2
640 641 * #6508: Japanese translation update
641 642 * #6509: Localization pt-PT (new strings)
642 643 * #6511: Rake task to test email
643 644 * #6525: Traditional Chinese language file (to r4225)
644 645 * #6536: Patch for swedish translation
645 646 * #6548: Rake tasks to add/remove i18n strings
646 647 * #6569: Updated Hebrew translation
647 648 * #6570: Japanese Translation for r4231
648 649 * #6596: pt-BR translation updates
649 650 * #6629: Change field-name of issues start date
650 651 * #6669: Bulgarian translation
651 652 * #6731: Macedonian translation fix
652 653 * #6732: Japanese Translation for r4287
653 654 * #6735: Add user-agent to reposman
654 655 * #6736: Traditional Chinese language file (to r4288)
655 656 * #6739: Swedish Translation for r4288
656 657 * #6765: Traditional Chinese language file (to r4302)
657 658 * Fixed #5324: Git not working if color.ui is enabled
658 659 * Fixed #5652: Bad URL parsing in the wiki when it ends with right-angle-bracket(greater-than mark).
659 660 * Fixed #5803: Precedes/Follows Relationships Broke
660 661 * Fixed #6435: Links to wikipages bound to versions do not respect version-sharing in Settings -> Versions
661 662 * Fixed #6438: Autologin cannot be disabled again once it's enabled
662 663 * Fixed #6513: "Move" and "Copy" are not displayed when deployed in subdirectory
663 664 * Fixed #6521: Tooltip/label for user "search-refinment" field on group/project member list
664 665 * Fixed #6563: i18n-issues on calendar view
665 666 * Fixed #6598: Wrong caption for button_create_and_continue in German language file
666 667 * Fixed #6607: Unclear caption for german button_update
667 668 * Fixed #6612: SortHelper missing from CalendarsController
668 669 * Fixed #6740: Max attachment size, incorrect usage of 'KB'
669 670 * Fixed #6750: ActionView::TemplateError (undefined method `empty?' for nil:NilClass) on line #12 of app/views/context_menus/issues.html.erb:
670 671
671 672 == 2010-09-26 v1.0.2
672 673
673 674 * #2285: issue-refinement: pressing enter should result to an "apply"
674 675 * #3411: Allow mass status update trough context menu
675 676 * #5929: https-enabled gravatars when called over https
676 677 * #6189: Japanese Translation for r4011
677 678 * #6197: Traditional Chinese language file (to r4036)
678 679 * #6198: Updated german translation
679 680 * #6208: Macedonian translation
680 681 * #6210: Swedish Translation for r4039
681 682 * #6248: nl translation update for r4050
682 683 * #6263: Catalan translation update
683 684 * #6275: After submitting a related issue, the Issue field should be re-focused
684 685 * #6289: Checkboxes in issues list shouldn't be displayed when printing
685 686 * #6290: Make journals theming easier
686 687 * #6291: User#allowed_to? is not tested
687 688 * #6306: Traditional Chinese language file (to r4061)
688 689 * #6307: Korean translation update for 4066(4061)
689 690 * #6316: pt_BR update
690 691 * #6339: SERBIAN Updated
691 692 * #6358: Updated Polish translation
692 693 * #6363: Japanese Translation for r4080
693 694 * #6365: Traditional Chinese language file (to r4081)
694 695 * #6382: Issue PDF export variable usage
695 696 * #6428: Interim solution for i18n >= 0.4
696 697 * #6441: Japanese Translation for r4162
697 698 * #6451: Traditional Chinese language file (to r4167)
698 699 * #6465: Japanese Translation for r4171
699 700 * #6466: Traditional Chinese language file (to r4171)
700 701 * #6490: pt-BR translation for 1.0.2
701 702 * Fixed #3935: stylesheet_link_tag with plugin doesn't take into account relative_url_root
702 703 * Fixed #4998: Global issue list's context menu has enabled options for parent menus but there are no valid selections
703 704 * Fixed #5170: Done ratio can not revert to 0% if status is used for done ratio
704 705 * Fixed #5608: broken with i18n 0.4.0
705 706 * Fixed #6054: Error 500 on filenames with whitespace in git reposities
706 707 * Fixed #6135: Default logger configuration grows without bound.
707 708 * Fixed #6191: Deletion of a main task deletes all subtasks
708 709 * Fixed #6195: Missing move issues between projects
709 710 * Fixed #6242: can't switch between inline and side-by-side diff
710 711 * Fixed #6249: Create and continue returns 404
711 712 * Fixed #6267: changing the authentication mode from ldap to internal with setting the password
712 713 * Fixed #6270: diff coderay malformed in the "news" page
713 714 * Fixed #6278: missing "cant_link_an_issue_with_a_descendant"from locale files
714 715 * Fixed #6333: Create and continue results in a 404 Error
715 716 * Fixed #6346: Age column on repository view is skewed for git, probably CVS too
716 717 * Fixed #6351: Context menu on roadmap broken
717 718 * Fixed #6388: New Subproject leads to a 404
718 719 * Fixed #6392: Updated/Created links to activity broken
719 720 * Fixed #6413: Error in SQL
720 721 * Fixed #6443: Redirect to project settings after Copying a Project
721 722 * Fixed #6448: Saving a wiki page with no content has a translation missing
722 723 * Fixed #6452: Unhandled exception on creating File
723 724 * Fixed #6471: Typo in label_report in Czech translation
724 725 * Fixed #6479: Changing tracker type will lose watchers
725 726 * Fixed #6499: Files with leading or trailing whitespace are not shown in git.
726 727
727 728 == 2010-08-22 v1.0.1
728 729
729 730 * #819: Add a body ID and class to all pages
730 731 * #871: Commit new CSS styles!
731 732 * #3301: Add favicon to base layout
732 733 * #4656: On Issue#show page, clicking on Ò€œAdd related issueҀ� should focus on the input
733 734 * #4896: Project identifier should be a limited field
734 735 * #5084: Filter all isssues by projects
735 736 * #5477: Replace Test::Unit::TestCase with ActiveSupport::TestCase
736 737 * #5591: 'calendar' action is used with 'issue' controller in issue/sidebar
737 738 * #5735: Traditional Chinese language file (to r3810)
738 739 * #5740: Swedish Translation for r3810
739 740 * #5785: pt-BR translation update
740 741 * #5898: Projects should be displayed as links in users/memberships
741 742 * #5910: Chinese translation to redmine-1.0.0
742 743 * #5912: Translation update for french locale
743 744 * #5962: Hungarian translation update to r3892
744 745 * #5971: Remove falsly applied chrome on revision links
745 746 * #5972: Updated Hebrew translation for 1.0.0
746 747 * #5982: Updated german translation
747 748 * #6008: Move admin_menu to Redmine::MenuManager
748 749 * #6012: RTL layout
749 750 * #6021: Spanish translation 1.0.0-RC
750 751 * #6025: nl translation updated for r3905
751 752 * #6030: Japanese Translation for r3907
752 753 * #6074: sr-CY.yml contains DOS-type newlines (\r\n)
753 754 * #6087: SERBIAN translation updated
754 755 * #6093: Updated italian translation
755 756 * #6142: Swedish Translation for r3940
756 757 * #6153: Move view_calendar and view_gantt to own modules
757 758 * #6169: Add issue status to issue tooltip
758 759 * Fixed #3834: Add a warning when not choosing a member role
759 760 * Fixed #3922: Bad english arround "Assigned to" text in journal entries
760 761 * Fixed #5158: Simplified Chinese language file zh.yml updated to r3608
761 762 * Fixed #5162: translation missing: zh-TW, field_time_entrie
762 763 * Fixed #5297: openid not validated correctly
763 764 * Fixed #5628: Wrong commit range in git log command
764 765 * Fixed #5760: Assigned_to and author filters in "Projects>View all issues" should be based on user's project visibility
765 766 * Fixed #5771: Problem when importing git repository
766 767 * Fixed #5775: ldap authentication in admin menu should have an icon
767 768 * Fixed #5811: deleting statuses doesnt delete workflow entries
768 769 * Fixed #5834: Emails with trailing spaces incorrectly detected as invalid
769 770 * Fixed #5846: ChangeChangesPathLengthLimit does not remove default for MySQL
770 771 * Fixed #5861: Vertical scrollbar always visible in Wiki "code" blocks in Chrome.
771 772 * Fixed #5883: correct label_project_latest Chinese translation
772 773 * Fixed #5892: Changing status from contextual menu opens the ticket instead
773 774 * Fixed #5904: Global gantt PDF and PNG should display project names
774 775 * Fixed #5925: parent task's priority edit should be disabled through shortcut menu in issues list page
775 776 * Fixed #5935: Add Another file to ticket doesn't work in IE Internet Explorer
776 777 * Fixed #5937: Harmonize french locale "zero" translation with other locales
777 778 * Fixed #5945: Forum message permalinks don't take pagination into account
778 779 * Fixed #5978: Debug code still remains
779 780 * Fixed #6009: When using "English (British)", the repository browser (svn) shows files over 1000 bytes as floating point (2.334355)
780 781 * Fixed #6045: Repository file Diff view sometimes shows more than selected file
781 782 * Fixed #6079: German Translation error in TimeEntryActivity
782 783 * Fixed #6100: User's profile should display all visible projects
783 784 * Fixed #6132: Allow Key based authentication in the Boards atom feed
784 785 * Fixed #6163: Bad CSS class for calendar project menu_item
785 786 * Fixed #6172: Browsing to a missing user's page shows the admin sidebar
786 787
787 788 == 2010-07-18 v1.0.0 (Release candidate)
788 789
789 790 * #443: Adds context menu to the roadmap issue lists
790 791 * #443: Subtasking
791 792 * #741: Description preview while editing an issue
792 793 * #1131: Add support for alternate (non-LDAP) authentication
793 794 * #1214: REST API for Issues
794 795 * #1223: File upload on wiki edit form
795 796 * #1755: add "blocked by" as a related issues option
796 797 * #2420: Fetching emails from an POP server
797 798 * #2482: Named scopes in Issue and ActsAsWatchable plus some view refactoring (logic extraction).
798 799 * #2924: Make the right click menu more discoverable using a cursor property
799 800 * #2985: Make syntax highlighting pluggable
800 801 * #3201: Workflow Check/Uncheck All Rows/Columns
801 802 * #3359: Update CodeRay 0.9
802 803 * #3706: Allow assigned_to field configuration on Issue creation by email
803 804 * #3936: configurable list of models to include in search
804 805 * #4480: Create a link to the user profile from the administration interface
805 806 * #4482: Cache textile rendering
806 807 * #4572: Make it harder to ruin your database
807 808 * #4573: Move github gems to Gemcutter
808 809 * #4664: Add pagination to forum threads
809 810 * #4732: Make login case-insensitive also for PostgreSQL
810 811 * #4812: Create links to other projects
811 812 * #4819: Replace images with smushed ones for speed
812 813 * #4945: Allow custom fields attached to project to be searchable
813 814 * #5121: Fix issues list layout overflow
814 815 * #5169: Issue list view hook request
815 816 * #5208: Aibility to edit wiki sidebar
816 817 * #5281: Remove empty ul tags in the issue history
817 818 * #5291: Updated basque translations
818 819 * #5328: Automatically add "Repository" menu_item after repository creation
819 820 * #5415: Fewer SQL statements generated for watcher_recipients
820 821 * #5416: Exclude "fields_for" from overridden methods in TabularFormBuilder
821 822 * #5573: Allow issue assignment in email
822 823 * #5595: Allow start date and due dates to be set via incoming email
823 824 * #5752: The projects view (/projects) renders ul's wrong
824 825 * #5781: Allow to use more macros on the welcome page and project list
825 826 * Fixed #1288: Unable to past escaped wiki syntax in an issue description
826 827 * Fixed #1334: Wiki formatting character *_ and _*
827 828 * Fixed #1416: Inline code with less-then/greater-than produces @lt; and @gt; respectively
828 829 * Fixed #2473: Login and mail should not be case sensitive
829 830 * Fixed #2990: Ruby 1.9 - wrong number of arguments (1 for 0) on rake db:migrate
830 831 * Fixed #3089: Text formatting sometimes breaks when combined
831 832 * Fixed #3690: Status change info duplicates on the issue screen
832 833 * Fixed #3691: Redmine allows two files with the same file name to be uploaded to the same issue
833 834 * Fixed #3764: ApplicationHelperTest fails with JRuby
834 835 * Fixed #4265: Unclosed code tags in issue descriptions affects main UI
835 836 * Fixed #4745: Bug in index.xml.builder (issues)
836 837 * Fixed #4852: changing user/roles of project member not possible without javascript
837 838 * Fixed #4857: Week number calculation in date picker is wrong if a week starts with Sunday
838 839 * Fixed #4883: Bottom "contextual" placement in issue with associated changeset
839 840 * Fixed #4918: Revisions r3453 and r3454 broke On-the-fly user creation with LDAP
840 841 * Fixed #4935: Navigation to the Master Timesheet page (time_entries)
841 842 * Fixed #5043: Flash messages are not displayed after the project settings[module/activity] saved
842 843 * Fixed #5081: Broken links on public/help/wiki_syntax_detailed.html
843 844 * Fixed #5104: Description of document not wikified on documents index
844 845 * Fixed #5108: Issue linking fails inside of []s
845 846 * Fixed #5199: diff code coloring using coderay
846 847 * Fixed #5233: Add a hook to the issue report (Summary) view
847 848 * Fixed #5265: timetracking: subtasks time is added to the main task
848 849 * Fixed #5343: acts_as_event Doesn't Accept Outside URLs
849 850 * Fixed #5440: UI Inconsistency : Administration > Enumerations table row headers should be enclosed in <thead>
850 851 * Fixed #5463: 0.9.4 INSTALL and/or UPGRADE, missing session_store.rb
851 852 * Fixed #5524: Update_parent_attributes doesn't work for the old parent issue when reparenting
852 853 * Fixed #5548: SVN Repository: Can not list content of a folder which includes square brackets.
853 854 * Fixed #5589: "with subproject" malfunction
854 855 * Fixed #5676: Search for Numeric Value
855 856 * Fixed #5696: Redmine + PostgreSQL 8.4.4 fails on _dir_list_content.rhtml
856 857 * Fixed #5698: redmine:email:receive_imap fails silently for mails with subject longer than 255 characters
857 858 * Fixed #5700: TimelogController#destroy assumes success
858 859 * Fixed #5751: developer role is mispelled
859 860 * Fixed #5769: Popup Calendar doesn't Advance in Chrome
860 861 * Fixed #5771: Problem when importing git repository
861 862 * Fixed #5823: Error in comments in plugin.rb
862 863
863 864
864 865 == 2010-07-07 v0.9.6
865 866
866 867 * Fixed: Redmine.pm access by unauthorized users
867 868
868 869 == 2010-06-24 v0.9.5
869 870
870 871 * Linkify folder names on revision view
871 872 * "fiters" and "options" should be hidden in print view via css
872 873 * Fixed: NoMethodError when no issue params are submitted
873 874 * Fixed: projects.atom with required authentication
874 875 * Fixed: External links not correctly displayed in Wiki TOC
875 876 * Fixed: Member role forms in project settings are not hidden after member added
876 877 * Fixed: pre can't be inside p
877 878 * Fixed: session cookie path does not respect RAILS_RELATIVE_URL_ROOT
878 879 * Fixed: mail handler fails when the from address is empty
879 880
880 881
881 882 == 2010-05-01 v0.9.4
882 883
883 884 * Filters collapsed by default on issues index page for a saved query
884 885 * Fixed: When categories list is too big the popup menu doesn't adjust (ex. in the issue list)
885 886 * Fixed: remove "main-menu" div when the menu is empty
886 887 * Fixed: Code syntax highlighting not working in Document page
887 888 * Fixed: Git blame/annotate fails on moved files
888 889 * Fixed: Failing test in test_show_atom
889 890 * Fixed: Migrate from trac - not displayed Wikis
890 891 * Fixed: Email notifications on file upload sent to empty recipient list
891 892 * Fixed: Migrating from trac is not possible, fails to allocate memory
892 893 * Fixed: Lost password no longer flashes a confirmation message
893 894 * Fixed: Crash while deleting in-use enumeration
894 895 * Fixed: Hard coded English string at the selection of issue watchers
895 896 * Fixed: Bazaar v2.1.0 changed behaviour
896 897 * Fixed: Roadmap display can raise an exception if no trackers are selected
897 898 * Fixed: Gravatar breaks layout of "logged in" page
898 899 * Fixed: Reposman.rb on Windows
899 900 * Fixed: Possible error 500 while moving an issue to another project with SQLite
900 901 * Fixed: backslashes in issue description/note should be escaped when quoted
901 902 * Fixed: Long text in <pre> disrupts Associated revisions
902 903 * Fixed: Links to missing wiki pages not red on project overview page
903 904 * Fixed: Cannot delete a project with subprojects that shares versions
904 905 * Fixed: Update of Subversion changesets broken under Solaris
905 906 * Fixed: "Move issues" permission not working for Non member
906 907 * Fixed: Sidebar overlap on Users tab of Group editor
907 908 * Fixed: Error on db:migrate with table prefix set (hardcoded name in principal.rb)
908 909 * Fixed: Report shows sub-projects for non-members
909 910 * Fixed: 500 internal error when browsing any Redmine page in epiphany
910 911 * Fixed: Watchers selection lost when issue creation fails
911 912 * Fixed: When copying projects, redmine should not generate an email to people who created issues
912 913 * Fixed: Issue "#" table cells should have a class attribute to enable fine-grained CSS theme
913 914 * Fixed: Plugin generators should display help if no parameter is given
914 915
915 916
916 917 == 2010-02-28 v0.9.3
917 918
918 919 * Adds filter for system shared versions on the cross project issue list
919 920 * Makes project identifiers searchable
920 921 * Remove invalid utf8 sequences from commit comments and author name
921 922 * Fixed: Wrong link when "http" not included in project "Homepage" link
922 923 * Fixed: Escaping in html email templates
923 924 * Fixed: Pound (#) followed by number with leading zero (0) removes leading zero when rendered in wiki
924 925 * Fixed: Deselecting textile text formatting causes interning empty string errors
925 926 * Fixed: error with postgres when entering a non-numeric id for an issue relation
926 927 * Fixed: div.task incorrectly wrapping on Gantt Chart
927 928 * Fixed: Project copy loses wiki pages hierarchy
928 929 * Fixed: parent project field doesn't include blank value when a member with 'add subproject' permission edits a child project
929 930 * Fixed: Repository.fetch_changesets tries to fetch changesets for archived projects
930 931 * Fixed: Duplicated project name for subproject version on gantt chart
931 932 * Fixed: roadmap shows subprojects issues even if subprojects is unchecked
932 933 * Fixed: IndexError if all the :last menu items are deleted from a menu
933 934 * Fixed: Very high CPU usage for a long time when fetching commits from a large Git repository
934 935
935 936
936 937 == 2010-02-07 v0.9.2
937 938
938 939 * Fixed: Sub-project repository commits not displayed on parent project issues
939 940 * Fixed: Potential security leak on my page calendar
940 941 * Fixed: Project tree structure is broken by deleting the project with the subproject
941 942 * Fixed: Error message shown duplicated when creating a new group
942 943 * Fixed: Firefox cuts off large pages
943 944 * Fixed: Invalid format parameter returns a DoubleRenderError on issues index
944 945 * Fixed: Unnecessary Quote button on locked forum message
945 946 * Fixed: Error raised when trying to view the gantt or calendar with a grouped query
946 947 * Fixed: PDF support for Korean locale
947 948 * Fixed: Deprecation warning in extra/svn/reposman.rb
948 949
949 950
950 951 == 2010-01-30 v0.9.1
951 952
952 953 * Vertical alignment for inline images in formatted text set to 'middle'
953 954 * Fixed: Redmine.pm error "closing dbh with active statement handles at /usr/lib/perl5/Apache/Redmine.pm"
954 955 * Fixed: copyright year in footer set to 2010
955 956 * Fixed: Trac migration script may not output query lines
956 957 * Fixed: Email notifications may affect language of notice messages on the UI
957 958 * Fixed: Can not search for 2 letters word
958 959 * Fixed: Attachments get saved on issue update even if validation fails
959 960 * Fixed: Tab's 'border-bottom' not absent when selected
960 961 * Fixed: Issue summary tables that list by user are not sorted
961 962 * Fixed: Issue pdf export fails if target version is set
962 963 * Fixed: Issue list export to PDF breaks when issues are sorted by a custom field
963 964 * Fixed: SQL error when adding a group
964 965 * Fixes: Min password length during password reset always displays as 4 chars
965 966
966 967
967 968 == 2010-01-09 v0.9.0 (Release candidate)
968 969
969 970 * Unlimited subproject nesting
970 971 * Multiple roles per user per project
971 972 * User groups
972 973 * Inheritence of versions
973 974 * OpenID login
974 975 * "Watched by me" issue filter
975 976 * Project copy
976 977 * Project creation by non admin users
977 978 * Accept emails from anyone on a private project
978 979 * Add email notification on Wiki changes
979 980 * Make issue description non-required field
980 981 * Custom fields for Versions
981 982 * Being able to sort the issue list by custom fields
982 983 * Ability to close versions
983 984 * User display/editing of custom fields attached to their user profile
984 985 * Add "follows" issue relation
985 986 * Copy workflows between trackers and roles
986 987 * Defaults enabled modules list for project creation
987 988 * Weighted version completion percentage on the roadmap
988 989 * Autocreate user account when user submits email that creates new issue
989 990 * CSS class on overdue issues on the issue list
990 991 * Enable tracker update on issue edit form
991 992 * Remove issue watchers
992 993 * Ability to move threads between project forums
993 994 * Changed custom field "Possible values" to a textarea
994 995 * Adds projects association on tracker form
995 996 * Set session store to cookie store by default
996 997 * Set a default wiki page on project creation
997 998 * Roadmap for main project should see Roadmaps for sub projects
998 999 * Ticket grouping on the issue list
999 1000 * Hierarchical Project links in the page header
1000 1001 * Allow My Page blocks to be added to from a plugin
1001 1002 * Sort issues by multiple columns
1002 1003 * Filters of saved query are now visible and be adjusted without editing the query
1003 1004 * Saving "sort order" in custom queries
1004 1005 * Url to fetch changesets for a repository
1005 1006 * Managers able to create subprojects
1006 1007 * Issue Totals on My Page Modules
1007 1008 * Convert Enumerations to single table inheritance (STI)
1008 1009 * Allow custom my_page blocks to define drop-down names
1009 1010 * "View Issues" user permission added
1010 1011 * Ask user what to do with child pages when deleting a parent wiki page
1011 1012 * Contextual quick search
1012 1013 * Allow resending of password by email
1013 1014 * Change reply subject to be a link to the reply itself
1014 1015 * Include Logged Time as part of the project's Activity history
1015 1016 * REST API for authentication
1016 1017 * Browse through Git branches
1017 1018 * Setup Object Daddy to replace test fixtures
1018 1019 * Setup shoulda to make it easier to test
1019 1020 * Custom fields and overrides on Enumerations
1020 1021 * Add or remove columns from the issue list
1021 1022 * Ability to add new version from issues screen
1022 1023 * Setting to choose which day calendars start
1023 1024 * Asynchronous email delivery method
1024 1025 * RESTful URLs for (almost) everything
1025 1026 * Include issue status in search results and activity pages
1026 1027 * Add email to admin user search filter
1027 1028 * Proper content type for plain text mails
1028 1029 * Default value of project jump box
1029 1030 * Tree based menus
1030 1031 * Ability to use issue status to update percent done
1031 1032 * Second set of issue "Action Links" at the bottom of an issue page
1032 1033 * Proper exist status code for rdm-mailhandler.rb
1033 1034 * Remove incoming email body via a delimiter
1034 1035 * Fixed: Custom querry 'Export to PDF' ignores field selection
1035 1036 * Fixed: Related e-mail notifications aren't threaded
1036 1037 * Fixed: No warning when the creation of a categories from the issue form fails
1037 1038 * Fixed: Actually block issues from closing when relation 'blocked by' isn't closed
1038 1039 * Fixed: Include both first and last name when sorting by users
1039 1040 * Fixed: Table cell with multiple line text
1040 1041 * Fixed: Project overview page shows disabled trackers
1041 1042 * Fixed: Cross project issue relations and user permissions
1042 1043 * Fixed: My page shows tickets the user doesn't have access to
1043 1044 * Fixed: TOC does not parse wiki page reference links with description
1044 1045 * Fixed: Target version-list on bulk edit form is incorrectly sorted
1045 1046 * Fixed: Cannot modify/delete project named "Documents"
1046 1047 * Fixed: Email address in brackets breaks html
1047 1048 * Fixed: Timelog detail loose issue filter passing to report tab
1048 1049 * Fixed: Inform about custom field's name maximum length
1049 1050 * Fixed: Activity page and Atom feed links contain project id instead of identifier
1050 1051 * Fixed: no Atom key for forums with only 1 forum
1051 1052 * Fixed: When reading RSS feed in MS Outlook, the inline links are broken.
1052 1053 * Fixed: Sometimes new posts don't show up in the topic list of a forum.
1053 1054 * Fixed: The all/active filter selection in the project view does not stick.
1054 1055 * Fixed: Login box has Different width
1055 1056 * Fixed: User removed from project - still getting project update emails
1056 1057 * Fixed: Project with the identifier of 'new' cannot be viewed
1057 1058 * Fixed: Artefacts in search view (Cyrillic)
1058 1059 * Fixed: Allow [#id] as subject to reply by email
1059 1060 * Fixed: Wrong language used when closing an issue via a commit message
1060 1061 * Fixed: email handler drops emails for new issues with no subject
1061 1062 * Fixed: Calendar misspelled under Roles/Permissions
1062 1063 * Fixed: Emails from no-reply redmine's address hell cycle
1063 1064 * Fixed: child_pages macro fails on wiki page history
1064 1065 * Fixed: Pre-filled time tracking date ignores timezone
1065 1066 * Fixed: Links on locked users lead to 404 page
1066 1067 * Fixed: Page changes in issue-list when using context menu
1067 1068 * Fixed: diff parser removes lines starting with multiple dashes
1068 1069 * Fixed: Quoting in forums resets message subject
1069 1070 * Fixed: Editing issue comment removes quote link
1070 1071 * Fixed: Redmine.pm ignore browse_repository permission
1071 1072 * Fixed: text formatting breaks on [msg1][msg2]
1072 1073 * Fixed: Spent Time Default Value of 0.0
1073 1074 * Fixed: Wiki pages in search results are referenced by project number, not by project identifier.
1074 1075 * Fixed: When logging in via an autologin cookie the user's last_login_on should be updated
1075 1076 * Fixed: 50k users cause problems in project->settings->members screen
1076 1077 * Fixed: Document timestamp needs to show updated timestamps
1077 1078 * Fixed: Users getting notifications for issues they are no longer allowed to view
1078 1079 * Fixed: issue summary counts should link to the issue list without subprojects
1079 1080 * Fixed: 'Delete' link on LDAP list has no effect
1080 1081
1081 1082
1082 1083 == 2009-11-15 v0.8.7
1083 1084
1084 1085 * Fixed: Hide paragraph terminator at the end of headings on html export
1085 1086 * Fixed: pre tags containing "<pre*"
1086 1087 * Fixed: First date of the date range not included in the time report with SQLite
1087 1088 * Fixed: Password field not styled correctly on alternative stylesheet
1088 1089 * Fixed: Error when sumbitting a POST request that requires a login
1089 1090 * Fixed: CSRF vulnerabilities
1090 1091
1091 1092
1092 1093 == 2009-11-04 v0.8.6
1093 1094
1094 1095 * Change links to closed issues to be a grey color
1095 1096 * Change subversion adapter to not cache authentication and run non interactively
1096 1097 * Fixed: Custom Values with a nil value cause HTTP error 500
1097 1098 * Fixed: Failure to convert HTML entities when editing an Issue reply
1098 1099 * Fixed: Error trying to show repository when there are no comments in a changeset
1099 1100 * Fixed: account/show/:user_id should not be accessible for other users not in your projects
1100 1101 * Fixed: XSS vulnerabilities
1101 1102 * Fixed: IssuesController#destroy should accept POST only
1102 1103 * Fixed: Inline images in wiki headings
1103 1104
1104 1105
1105 1106 == 2009-09-13 v0.8.5
1106 1107
1107 1108 * Incoming mail handler : Allow spaces between keywords and colon
1108 1109 * Do not require a non-word character after a comma in Redmine links
1109 1110 * Include issue hyperlinks in reminder emails
1110 1111 * Prevent nil error when retrieving svn version
1111 1112 * Various plugin hooks added
1112 1113 * Add plugins information to script/about
1113 1114 * Fixed: 500 Internal Server Error is raised if add an empty comment to the news
1114 1115 * Fixed: Atom links for wiki pages are not correct
1115 1116 * Fixed: Atom feeds leak email address
1116 1117 * Fixed: Case sensitivity in Issue filtering
1117 1118 * Fixed: When reading RSS feed, the inline-embedded images are not properly shown
1118 1119
1119 1120
1120 1121 == 2009-05-17 v0.8.4
1121 1122
1122 1123 * Allow textile mailto links
1123 1124 * Fixed: memory consumption when uploading file
1124 1125 * Fixed: Mercurial integration doesn't work if Redmine is installed in folder path containing space
1125 1126 * Fixed: an error is raised when no tab is available on project settings
1126 1127 * Fixed: insert image macro corrupts urls with excalamation marks
1127 1128 * Fixed: error on cross-project gantt PNG export
1128 1129 * Fixed: self and alternate links in atom feeds do not respect Atom specs
1129 1130 * Fixed: accept any svn tunnel scheme in repository URL
1130 1131 * Fixed: issues/show should accept user's rss key
1131 1132 * Fixed: consistency of custom fields display on the issue detail view
1132 1133 * Fixed: wiki comments length validation is missing
1133 1134 * Fixed: weak autologin token generation algorithm causes duplicate tokens
1134 1135
1135 1136
1136 1137 == 2009-04-05 v0.8.3
1137 1138
1138 1139 * Separate project field and subject in cross-project issue view
1139 1140 * Ability to set language for redmine:load_default_data task using REDMINE_LANG environment variable
1140 1141 * Rescue Redmine::DefaultData::DataAlreadyLoaded in redmine:load_default_data task
1141 1142 * CSS classes to highlight own and assigned issues
1142 1143 * Hide "New file" link on wiki pages from printing
1143 1144 * Flush buffer when asking for language in redmine:load_default_data task
1144 1145 * Minimum project identifier length set to 1
1145 1146 * Include headers so that emails don't trigger vacation auto-responders
1146 1147 * Fixed: Time entries csv export links for all projects are malformed
1147 1148 * Fixed: Files without Version aren't visible in the Activity page
1148 1149 * Fixed: Commit logs are centered in the repo browser
1149 1150 * Fixed: News summary field content is not searchable
1150 1151 * Fixed: Journal#save has a wrong signature
1151 1152 * Fixed: Email footer signature convention
1152 1153 * Fixed: Timelog report do not show time for non-versioned issues
1153 1154
1154 1155
1155 1156 == 2009-03-07 v0.8.2
1156 1157
1157 1158 * Send an email to the user when an administrator activates a registered user
1158 1159 * Strip keywords from received email body
1159 1160 * Footer updated to 2009
1160 1161 * Show RSS-link even when no issues is found
1161 1162 * One click filter action in activity view
1162 1163 * Clickable/linkable line #'s while browsing the repo or viewing a file
1163 1164 * Links to versions on files list
1164 1165 * Added request and controller objects to the hooks by default
1165 1166 * Fixed: exporting an issue with attachments to PDF raises an error
1166 1167 * Fixed: "too few arguments" error may occur on activerecord error translation
1167 1168 * Fixed: "Default columns Displayed on the Issues list" setting is not easy to read
1168 1169 * Fixed: visited links to closed tickets are not striked through with IE6
1169 1170 * Fixed: MailHandler#plain_text_body returns nil if there was nothing to strip
1170 1171 * Fixed: MailHandler raises an error when processing an email without From header
1171 1172
1172 1173
1173 1174 == 2009-02-15 v0.8.1
1174 1175
1175 1176 * Select watchers on new issue form
1176 1177 * Issue description is no longer a required field
1177 1178 * Files module: ability to add files without version
1178 1179 * Jump to the current tab when using the project quick-jump combo
1179 1180 * Display a warning if some attachments were not saved
1180 1181 * Import custom fields values from emails on issue creation
1181 1182 * Show view/annotate/download links on entry and annotate views
1182 1183 * Admin Info Screen: Display if plugin assets directory is writable
1183 1184 * Adds a 'Create and continue' button on the new issue form
1184 1185 * IMAP: add options to move received emails
1185 1186 * Do not show Category field when categories are not defined
1186 1187 * Lower the project identifier limit to a minimum of two characters
1187 1188 * Add "closed" html class to closed entries in issue list
1188 1189 * Fixed: broken redirect URL on login failure
1189 1190 * Fixed: Deleted files are shown when using Darcs
1190 1191 * Fixed: Darcs adapter works on Win32 only
1191 1192 * Fixed: syntax highlight doesn't appear in new ticket preview
1192 1193 * Fixed: email notification for changes I make still occurs when running Repository.fetch_changesets
1193 1194 * Fixed: no error is raised when entering invalid hours on the issue update form
1194 1195 * Fixed: Details time log report CSV export doesn't honour date format from settings
1195 1196 * Fixed: invalid css classes on issue details
1196 1197 * Fixed: Trac importer creates duplicate custom values
1197 1198 * Fixed: inline attached image should not match partial filename
1198 1199
1199 1200
1200 1201 == 2008-12-30 v0.8.0
1201 1202
1202 1203 * Setting added in order to limit the number of diff lines that should be displayed
1203 1204 * Makes logged-in username in topbar linking to
1204 1205 * Mail handler: strip tags when receiving a html-only email
1205 1206 * Mail handler: add watchers before sending notification
1206 1207 * Adds a css class (overdue) to overdue issues on issue lists and detail views
1207 1208 * Fixed: project activity truncated after viewing user's activity
1208 1209 * Fixed: email address entered for password recovery shouldn't be case-sensitive
1209 1210 * Fixed: default flag removed when editing a default enumeration
1210 1211 * Fixed: default category ignored when adding a document
1211 1212 * Fixed: error on repository user mapping when a repository username is blank
1212 1213 * Fixed: Firefox cuts off large diffs
1213 1214 * Fixed: CVS browser should not show dead revisions (deleted files)
1214 1215 * Fixed: escape double-quotes in image titles
1215 1216 * Fixed: escape textarea content when editing a issue note
1216 1217 * Fixed: JS error on context menu with IE
1217 1218 * Fixed: bold syntax around single character in series doesn't work
1218 1219 * Fixed several XSS vulnerabilities
1219 1220 * Fixed a SQL injection vulnerability
1220 1221
1221 1222
1222 1223 == 2008-12-07 v0.8.0-rc1
1223 1224
1224 1225 * Wiki page protection
1225 1226 * Wiki page hierarchy. Parent page can be assigned on the Rename screen
1226 1227 * Adds support for issue creation via email
1227 1228 * Adds support for free ticket filtering and custom queries on Gantt chart and calendar
1228 1229 * Cross-project search
1229 1230 * Ability to search a project and its subprojects
1230 1231 * Ability to search the projects the user belongs to
1231 1232 * Adds custom fields on time entries
1232 1233 * Adds boolean and list custom fields for time entries as criteria on time report
1233 1234 * Cross-project time reports
1234 1235 * Display latest user's activity on account/show view
1235 1236 * Show last connexion time on user's page
1236 1237 * Obfuscates email address on user's account page using javascript
1237 1238 * wiki TOC rendered as an unordered list
1238 1239 * Adds the ability to search for a user on the administration users list
1239 1240 * Adds the ability to search for a project name or identifier on the administration projects list
1240 1241 * Redirect user to the previous page after logging in
1241 1242 * Adds a permission 'view wiki edits' so that wiki history can be hidden to certain users
1242 1243 * Adds permissions for viewing the watcher list and adding new watchers on the issue detail view
1243 1244 * Adds permissions to let users edit and/or delete their messages
1244 1245 * Link to activity view when displaying dates
1245 1246 * Hide Redmine version in atom feeds and pdf properties
1246 1247 * Maps repository users to Redmine users. Users with same username or email are automatically mapped. Mapping can be manually adjusted in repository settings. Multiple usernames can be mapped to the same Redmine user.
1247 1248 * Sort users by their display names so that user dropdown lists are sorted alphabetically
1248 1249 * Adds estimated hours to issue filters
1249 1250 * Switch order of current and previous revisions in side-by-side diff
1250 1251 * Render the commit changes list as a tree
1251 1252 * Adds watch/unwatch functionality at forum topic level
1252 1253 * When moving an issue to another project, reassign it to the category with same name if any
1253 1254 * Adds child_pages macro for wiki pages
1254 1255 * Use GET instead of POST on roadmap (#718), gantt and calendar forms
1255 1256 * Search engine: display total results count and count by result type
1256 1257 * Email delivery configuration moved to an unversioned YAML file (config/email.yml, see the sample file)
1257 1258 * Adds icons on search results
1258 1259 * Adds 'Edit' link on account/show for admin users
1259 1260 * Adds Lock/Unlock/Activate link on user edit screen
1260 1261 * Adds user count in status drop down on admin user list
1261 1262 * Adds multi-levels blockquotes support by using > at the beginning of lines
1262 1263 * Adds a Reply link to each issue note
1263 1264 * Adds plain text only option for mail notifications
1264 1265 * Gravatar support for issue detail, user grid, and activity stream (disabled by default)
1265 1266 * Adds 'Delete wiki pages attachments' permission
1266 1267 * Show the most recent file when displaying an inline image
1267 1268 * Makes permission screens localized
1268 1269 * AuthSource list: display associated users count and disable 'Delete' buton if any
1269 1270 * Make the 'duplicates of' relation asymmetric
1270 1271 * Adds username to the password reminder email
1271 1272 * Adds links to forum messages using message#id syntax
1272 1273 * Allow same name for custom fields on different object types
1273 1274 * One-click bulk edition using the issue list context menu within the same project
1274 1275 * Adds support for commit logs reencoding to UTF-8 before insertion in the database. Source encoding of commit logs can be selected in Application settings -> Repositories.
1275 1276 * Adds checkboxes toggle links on permissions report
1276 1277 * Adds Trac-Like anchors on wiki headings
1277 1278 * Adds support for wiki links with anchor
1278 1279 * Adds category to the issue context menu
1279 1280 * Adds a workflow overview screen
1280 1281 * Appends the filename to the attachment url so that clients that ignore content-disposition http header get the real filename
1281 1282 * Dots allowed in custom field name
1282 1283 * Adds posts quoting functionality
1283 1284 * Adds an option to generate sequential project identifiers
1284 1285 * Adds mailto link on the user administration list
1285 1286 * Ability to remove enumerations (activities, priorities, document categories) that are in use. Associated objects can be reassigned to another value
1286 1287 * Gantt chart: display issues that don't have a due date if they are assigned to a version with a date
1287 1288 * Change projects homepage limit to 255 chars
1288 1289 * Improved on-the-fly account creation. If some attributes are missing (eg. not present in the LDAP) or are invalid, the registration form is displayed so that the user is able to fill or fix these attributes
1289 1290 * Adds "please select" to activity select box if no activity is set as default
1290 1291 * Do not silently ignore timelog validation failure on issue edit
1291 1292 * Adds a rake task to send reminder emails
1292 1293 * Allow empty cells in wiki tables
1293 1294 * Makes wiki text formatter pluggable
1294 1295 * Adds back textile acronyms support
1295 1296 * Remove pre tag attributes
1296 1297 * Plugin hooks
1297 1298 * Pluggable admin menu
1298 1299 * Plugins can provide activity content
1299 1300 * Moves plugin list to its own administration menu item
1300 1301 * Adds url and author_url plugin attributes
1301 1302 * Adds Plugin#requires_redmine method so that plugin compatibility can be checked against current Redmine version
1302 1303 * Adds atom feed on time entries details
1303 1304 * Adds project name to issues feed title
1304 1305 * Adds a css class on menu items in order to apply item specific styles (eg. icons)
1305 1306 * Adds a Redmine plugin generators
1306 1307 * Adds timelog link to the issue context menu
1307 1308 * Adds links to the user page on various views
1308 1309 * Turkish translation by Ismail Sezen
1309 1310 * Catalan translation
1310 1311 * Vietnamese translation
1311 1312 * Slovak translation
1312 1313 * Better naming of activity feed if only one kind of event is displayed
1313 1314 * Enable syntax highlight on issues, messages and news
1314 1315 * Add target version to the issue list context menu
1315 1316 * Hide 'Target version' filter if no version is defined
1316 1317 * Add filters on cross-project issue list for custom fields marked as 'For all projects'
1317 1318 * Turn ftp urls into links
1318 1319 * Hiding the View Differences button when a wiki page's history only has one version
1319 1320 * Messages on a Board can now be sorted by the number of replies
1320 1321 * Adds a class ('me') to events of the activity view created by current user
1321 1322 * Strip pre/code tags content from activity view events
1322 1323 * Display issue notes in the activity view
1323 1324 * Adds links to changesets atom feed on repository browser
1324 1325 * Track project and tracker changes in issue history
1325 1326 * Adds anchor to atom feed messages links
1326 1327 * Adds a key in lang files to set the decimal separator (point or comma) in csv exports
1327 1328 * Makes importer work with Trac 0.8.x
1328 1329 * Upgraded to Prototype 1.6.0.1
1329 1330 * File viewer for attached text files
1330 1331 * Menu mapper: add support for :before, :after and :last options to #push method and add #delete method
1331 1332 * Removed inconsistent revision numbers on diff view
1332 1333 * CVS: add support for modules names with spaces
1333 1334 * Log the user in after registration if account activation is not needed
1334 1335 * Mercurial adapter improvements
1335 1336 * Trac importer: read session_attribute table to find user's email and real name
1336 1337 * Ability to disable unused SCM adapters in application settings
1337 1338 * Adds Filesystem adapter
1338 1339 * Clear changesets and changes with raw sql when deleting a repository for performance
1339 1340 * Redmine.pm now uses the 'commit access' permission defined in Redmine
1340 1341 * Reposman can create any type of scm (--scm option)
1341 1342 * Reposman creates a repository if the 'repository' module is enabled at project level only
1342 1343 * Display svn properties in the browser, svn >= 1.5.0 only
1343 1344 * Reduces memory usage when importing large git repositories
1344 1345 * Wider SVG graphs in repository stats
1345 1346 * SubversionAdapter#entries performance improvement
1346 1347 * SCM browser: ability to download raw unified diffs
1347 1348 * More detailed error message in log when scm command fails
1348 1349 * Adds support for file viewing with Darcs 2.0+
1349 1350 * Check that git changeset is not in the database before creating it
1350 1351 * Unified diff viewer for attached files with .patch or .diff extension
1351 1352 * File size display with Bazaar repositories
1352 1353 * Git adapter: use commit time instead of author time
1353 1354 * Prettier url for changesets
1354 1355 * Makes changes link to entries on the revision view
1355 1356 * Adds a field on the repository view to browse at specific revision
1356 1357 * Adds new projects atom feed
1357 1358 * Added rake tasks to generate rcov code coverage reports
1358 1359 * Add Redcloth's :block_markdown_rule to allow horizontal rules in wiki
1359 1360 * Show the project hierarchy in the drop down list for new membership on user administration screen
1360 1361 * Split user edit screen into tabs
1361 1362 * Renames bundled RedCloth to RedCloth3 to avoid RedCloth 4 to be loaded instead
1362 1363 * Fixed: Roadmap crashes when a version has a due date > 2037
1363 1364 * Fixed: invalid effective date (eg. 99999-01-01) causes an error on version edition screen
1364 1365 * Fixed: login filter providing incorrect back_url for Redmine installed in sub-directory
1365 1366 * Fixed: logtime entry duplicated when edited from parent project
1366 1367 * Fixed: wrong digest for text files under Windows
1367 1368 * Fixed: associated revisions are displayed in wrong order on issue view
1368 1369 * Fixed: Git Adapter date parsing ignores timezone
1369 1370 * Fixed: Printing long roadmap doesn't split across pages
1370 1371 * Fixes custom fields display order at several places
1371 1372 * Fixed: urls containing @ are parsed as email adress by the wiki formatter
1372 1373 * Fixed date filters accuracy with SQLite
1373 1374 * Fixed: tokens not escaped in highlight_tokens regexp
1374 1375 * Fixed Bazaar shared repository browsing
1375 1376 * Fixes platform determination under JRuby
1376 1377 * Fixed: Estimated time in issue's journal should be rounded to two decimals
1377 1378 * Fixed: 'search titles only' box ignored after one search is done on titles only
1378 1379 * Fixed: non-ASCII subversion path can't be displayed
1379 1380 * Fixed: Inline images don't work if file name has upper case letters or if image is in BMP format
1380 1381 * Fixed: document listing shows on "my page" when viewing documents is disabled for the role
1381 1382 * Fixed: Latest news appear on the homepage for projects with the News module disabled
1382 1383 * Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled
1383 1384 * Fixed: the default status is lost when reordering issue statuses
1384 1385 * Fixes error with Postgresql and non-UTF8 commit logs
1385 1386 * Fixed: textile footnotes no longer work
1386 1387 * Fixed: http links containing parentheses fail to reder correctly
1387 1388 * Fixed: GitAdapter#get_rev should use current branch instead of hardwiring master
1388 1389
1389 1390
1390 1391 == 2008-07-06 v0.7.3
1391 1392
1392 1393 * Allow dot in firstnames and lastnames
1393 1394 * Add project name to cross-project Atom feeds
1394 1395 * Encoding set to utf8 in example database.yml
1395 1396 * HTML titles on forums related views
1396 1397 * Fixed: various XSS vulnerabilities
1397 1398 * Fixed: Entourage (and some old client) fails to correctly render notification styles
1398 1399 * Fixed: Fixed: timelog redirects inappropriately when :back_url is blank
1399 1400 * Fixed: wrong relative paths to images in wiki_syntax.html
1400 1401
1401 1402
1402 1403 == 2008-06-15 v0.7.2
1403 1404
1404 1405 * "New Project" link on Projects page
1405 1406 * Links to repository directories on the repo browser
1406 1407 * Move status to front in Activity View
1407 1408 * Remove edit step from Status context menu
1408 1409 * Fixed: No way to do textile horizontal rule
1409 1410 * Fixed: Repository: View differences doesn't work
1410 1411 * Fixed: attachement's name maybe invalid.
1411 1412 * Fixed: Error when creating a new issue
1412 1413 * Fixed: NoMethodError on @available_filters.has_key?
1413 1414 * Fixed: Check All / Uncheck All in Email Settings
1414 1415 * Fixed: "View differences" of one file at /repositories/revision/ fails
1415 1416 * Fixed: Column width in "my page"
1416 1417 * Fixed: private subprojects are listed on Issues view
1417 1418 * Fixed: Textile: bold, italics, underline, etc... not working after parentheses
1418 1419 * Fixed: Update issue form: comment field from log time end out of screen
1419 1420 * Fixed: Editing role: "issue can be assigned to this role" out of box
1420 1421 * Fixed: Unable use angular braces after include word
1421 1422 * Fixed: Using '*' as keyword for repository referencing keywords doesn't work
1422 1423 * Fixed: Subversion repository "View differences" on each file rise ERROR
1423 1424 * Fixed: View differences for individual file of a changeset fails if the repository URL doesn't point to the repository root
1424 1425 * Fixed: It is possible to lock out the last admin account
1425 1426 * Fixed: Wikis are viewable for anonymous users on public projects, despite not granting access
1426 1427 * Fixed: Issue number display clipped on 'my issues'
1427 1428 * Fixed: Roadmap version list links not carrying state
1428 1429 * Fixed: Log Time fieldset in IssueController#edit doesn't set default Activity as default
1429 1430 * Fixed: git's "get_rev" API should use repo's current branch instead of hardwiring "master"
1430 1431 * Fixed: browser's language subcodes ignored
1431 1432 * Fixed: Error on project selection with numeric (only) identifier.
1432 1433 * Fixed: Link to PDF doesn't work after creating new issue
1433 1434 * Fixed: "Replies" should not be shown on forum threads that are locked
1434 1435 * Fixed: SVN errors lead to svn username/password being displayed to end users (security issue)
1435 1436 * Fixed: http links containing hashes don't display correct
1436 1437 * Fixed: Allow ampersands in Enumeration names
1437 1438 * Fixed: Atom link on saved query does not include query_id
1438 1439 * Fixed: Logtime info lost when there's an error updating an issue
1439 1440 * Fixed: TOC does not parse colorization markups
1440 1441 * Fixed: CVS: add support for modules names with spaces
1441 1442 * Fixed: Bad rendering on projects/add
1442 1443 * Fixed: exception when viewing differences on cvs
1443 1444 * Fixed: export issue to pdf will messup when use Chinese language
1444 1445 * Fixed: Redmine::Scm::Adapters::GitAdapter#get_rev ignored GIT_BIN constant
1445 1446 * Fixed: Adding non-ASCII new issue type in the New Issue page have encoding error using IE
1446 1447 * Fixed: Importing from trac : some wiki links are messed
1447 1448 * Fixed: Incorrect weekend definition in Hebrew calendar locale
1448 1449 * Fixed: Atom feeds don't provide author section for repository revisions
1449 1450 * Fixed: In Activity views, changesets titles can be multiline while they should not
1450 1451 * Fixed: Ignore unreadable subversion directories (read disabled using authz)
1451 1452 * Fixed: lib/SVG/Graph/Graph.rb can't externalize stylesheets
1452 1453 * Fixed: Close statement handler in Redmine.pm
1453 1454
1454 1455
1455 1456 == 2008-05-04 v0.7.1
1456 1457
1457 1458 * Thai translation added (Gampol Thitinilnithi)
1458 1459 * Translations updates
1459 1460 * Escape HTML comment tags
1460 1461 * Prevent "can't convert nil into String" error when :sort_order param is not present
1461 1462 * Fixed: Updating tickets add a time log with zero hours
1462 1463 * Fixed: private subprojects names are revealed on the project overview
1463 1464 * Fixed: Search for target version of "none" fails with postgres 8.3
1464 1465 * Fixed: Home, Logout, Login links shouldn't be absolute links
1465 1466 * Fixed: 'Latest projects' box on the welcome screen should be hidden if there are no projects
1466 1467 * Fixed: error when using upcase language name in coderay
1467 1468 * Fixed: error on Trac import when :due attribute is nil
1468 1469
1469 1470
1470 1471 == 2008-04-28 v0.7.0
1471 1472
1472 1473 * Forces Redmine to use rails 2.0.2 gem when vendor/rails is not present
1473 1474 * Queries can be marked as 'For all projects'. Such queries will be available on all projects and on the global issue list.
1474 1475 * Add predefined date ranges to the time report
1475 1476 * Time report can be done at issue level
1476 1477 * Various timelog report enhancements
1477 1478 * Accept the following formats for "hours" field: 1h, 1 h, 1 hour, 2 hours, 30m, 30min, 1h30, 1h30m, 1:30
1478 1479 * Display the context menu above and/or to the left of the click if needed
1479 1480 * Make the admin project files list sortable
1480 1481 * Mercurial: display working directory files sizes unless browsing a specific revision
1481 1482 * Preserve status filter and page number when using lock/unlock/activate links on the users list
1482 1483 * Redmine.pm support for LDAP authentication
1483 1484 * Better error message and AR errors in log for failed LDAP on-the-fly user creation
1484 1485 * Redirected user to where he is coming from after logging hours
1485 1486 * Warn user that subprojects are also deleted when deleting a project
1486 1487 * Include subprojects versions on calendar and gantt
1487 1488 * Notify project members when a message is posted if they want to receive notifications
1488 1489 * Fixed: Feed content limit setting has no effect
1489 1490 * Fixed: Priorities not ordered when displayed as a filter in issue list
1490 1491 * Fixed: can not display attached images inline in message replies
1491 1492 * Fixed: Boards are not deleted when project is deleted
1492 1493 * Fixed: trying to preview a new issue raises an exception with postgresql
1493 1494 * Fixed: single file 'View difference' links do not work because of duplicate slashes in url
1494 1495 * Fixed: inline image not displayed when including a wiki page
1495 1496 * Fixed: CVS duplicate key violation
1496 1497 * Fixed: ActiveRecord::StaleObjectError exception on closing a set of circular duplicate issues
1497 1498 * Fixed: custom field filters behaviour
1498 1499 * Fixed: Postgresql 8.3 compatibility
1499 1500 * Fixed: Links to repository directories don't work
1500 1501
1501 1502
1502 1503 == 2008-03-29 v0.7.0-rc1
1503 1504
1504 1505 * Overall activity view and feed added, link is available on the project list
1505 1506 * Git VCS support
1506 1507 * Rails 2.0 sessions cookie store compatibility
1507 1508 * Use project identifiers in urls instead of ids
1508 1509 * Default configuration data can now be loaded from the administration screen
1509 1510 * Administration settings screen split to tabs (email notifications options moved to 'Settings')
1510 1511 * Project description is now unlimited and optional
1511 1512 * Wiki annotate view
1512 1513 * Escape HTML tag in textile content
1513 1514 * Add Redmine links to documents, versions, attachments and repository files
1514 1515 * New setting to specify how many objects should be displayed on paginated lists. There are 2 ways to select a set of issues on the issue list:
1515 1516 * by using checkbox and/or the little pencil that will select/unselect all issues
1516 1517 * by clicking on the rows (but not on the links), Ctrl and Shift keys can be used to select multiple issues
1517 1518 * Context menu disabled on links so that the default context menu of the browser is displayed when right-clicking on a link (click anywhere else on the row to display the context menu)
1518 1519 * User display format is now configurable in administration settings
1519 1520 * Issue list now supports bulk edit/move/delete (for a set of issues that belong to the same project)
1520 1521 * Merged 'change status', 'edit issue' and 'add note' actions:
1521 1522 * Users with 'edit issues' permission can now update any property including custom fields when adding a note or changing the status
1522 1523 * 'Change issue status' permission removed. To change an issue status, a user just needs to have either 'Edit' or 'Add note' permissions and some workflow transitions allowed
1523 1524 * Details by assignees on issue summary view
1524 1525 * 'New issue' link in the main menu (accesskey 7). The drop-down lists to add an issue on the project overview and the issue list are removed
1525 1526 * Change status select box default to current status
1526 1527 * Preview for issue notes, news and messages
1527 1528 * Optional description for attachments
1528 1529 * 'Fixed version' label changed to 'Target version'
1529 1530 * Let the user choose when deleting issues with reported hours to:
1530 1531 * delete the hours
1531 1532 * assign the hours to the project
1532 1533 * reassign the hours to another issue
1533 1534 * Date range filter and pagination on time entries detail view
1534 1535 * Propagate time tracking to the parent project
1535 1536 * Switch added on the project activity view to include subprojects
1536 1537 * Display total estimated and spent hours on the version detail view
1537 1538 * Weekly time tracking block for 'My page'
1538 1539 * Permissions to edit time entries
1539 1540 * Include subprojects on the issue list, calendar, gantt and timelog by default (can be turned off is administration settings)
1540 1541 * Roadmap enhancements (separate related issues from wiki contents, leading h1 in version wiki pages is hidden, smaller wiki headings)
1541 1542 * Make versions with same date sorted by name
1542 1543 * Allow issue list to be sorted by target version
1543 1544 * Related changesets messages displayed on the issue details view
1544 1545 * Create a journal and send an email when an issue is closed by commit
1545 1546 * Add 'Author' to the available columns for the issue list
1546 1547 * More appropriate default sort order on sortable columns
1547 1548 * Add issue subject to the time entries view and issue subject, description and tracker to the csv export
1548 1549 * Permissions to edit issue notes
1549 1550 * Display date/time instead of date on files list
1550 1551 * Do not show Roadmap menu item if the project doesn't define any versions
1551 1552 * Allow longer version names (60 chars)
1552 1553 * Ability to copy an existing workflow when creating a new role
1553 1554 * Display custom fields in two columns on the issue form
1554 1555 * Added 'estimated time' in the csv export of the issue list
1555 1556 * Display the last 30 days on the activity view rather than the current month (number of days can be configured in the application settings)
1556 1557 * Setting for whether new projects should be public by default
1557 1558 * User preference to choose how comments/replies are displayed: in chronological or reverse chronological order
1558 1559 * Added default value for custom fields
1559 1560 * Added tabindex property on wiki toolbar buttons (to easily move from field to field using the tab key)
1560 1561 * Redirect to issue page after creating a new issue
1561 1562 * Wiki toolbar improvements (mainly for Firefox)
1562 1563 * Display wiki syntax quick ref link on all wiki textareas
1563 1564 * Display links to Atom feeds
1564 1565 * Breadcrumb nav for the forums
1565 1566 * Show replies when choosing to display messages in the activity
1566 1567 * Added 'include' macro to include another wiki page
1567 1568 * RedmineWikiFormatting page available as a static HTML file locally
1568 1569 * Wrap diff content
1569 1570 * Strip out email address from authors in repository screens
1570 1571 * Highlight the current item of the main menu
1571 1572 * Added simple syntax highlighters for php and java languages
1572 1573 * Do not show empty diffs
1573 1574 * Show explicit error message when the scm command failed (eg. when svn binary is not available)
1574 1575 * Lithuanian translation added (Sergej Jegorov)
1575 1576 * Ukrainan translation added (Natalia Konovka & Mykhaylo Sorochan)
1576 1577 * Danish translation added (Mads Vestergaard)
1577 1578 * Added i18n support to the jstoolbar and various settings screen
1578 1579 * RedCloth's glyphs no longer user
1579 1580 * New icons for the wiki toolbar (from http://www.famfamfam.com/lab/icons/silk/)
1580 1581 * The following menus can now be extended by plugins: top_menu, account_menu, application_menu
1581 1582 * Added a simple rake task to fetch changesets from the repositories: rake redmine:fetch_changesets
1582 1583 * Remove hardcoded "Redmine" strings in account related emails and use application title instead
1583 1584 * Mantis importer preserve bug ids
1584 1585 * Trac importer: Trac guide wiki pages skipped
1585 1586 * Trac importer: wiki attachments migration added
1586 1587 * Trac importer: support database schema for Trac migration
1587 1588 * Trac importer: support CamelCase links
1588 1589 * Removes the Redmine version from the footer (can be viewed on admin -> info)
1589 1590 * Rescue and display an error message when trying to delete a role that is in use
1590 1591 * Add various 'X-Redmine' headers to email notifications: X-Redmine-Host, X-Redmine-Site, X-Redmine-Project, X-Redmine-Issue-Id, -Author, -Assignee, X-Redmine-Topic-Id
1591 1592 * Add "--encoding utf8" option to the Mercurial "hg log" command in order to get utf8 encoded commit logs
1592 1593 * Fixed: Gantt and calendar not properly refreshed (fragment caching removed)
1593 1594 * Fixed: Textile image with style attribute cause internal server error
1594 1595 * Fixed: wiki TOC not rendered properly when used in an issue or document description
1595 1596 * Fixed: 'has already been taken' error message on username and email fields if left empty
1596 1597 * Fixed: non-ascii attachement filename with IE
1597 1598 * Fixed: wrong url for wiki syntax pop-up when Redmine urls are prefixed
1598 1599 * Fixed: search for all words doesn't work
1599 1600 * Fixed: Do not show sticky and locked checkboxes when replying to a message
1600 1601 * Fixed: Mantis importer: do not duplicate Mantis username in firstname and lastname if realname is blank
1601 1602 * Fixed: Date custom fields not displayed as specified in application settings
1602 1603 * Fixed: titles not escaped in the activity view
1603 1604 * Fixed: issue queries can not use custom fields marked as 'for all projects' in a project context
1604 1605 * Fixed: on calendar, gantt and in the tracker filter on the issue list, only active trackers of the project (and its sub projects) should be available
1605 1606 * Fixed: locked users should not receive email notifications
1606 1607 * Fixed: custom field selection is not saved when unchecking them all on project settings
1607 1608 * Fixed: can not lock a topic when creating it
1608 1609 * Fixed: Incorrect filtering for unset values when using 'is not' filter
1609 1610 * Fixed: PostgreSQL issues_seq_id not updated when using Trac importer
1610 1611 * Fixed: ajax pagination does not scroll up
1611 1612 * Fixed: error when uploading a file with no content-type specified by the browser
1612 1613 * Fixed: wiki and changeset links not displayed when previewing issue description or notes
1613 1614 * Fixed: 'LdapError: no bind result' error when authenticating
1614 1615 * Fixed: 'LdapError: invalid binding information' when no username/password are set on the LDAP account
1615 1616 * Fixed: CVS repository doesn't work if port is used in the url
1616 1617 * Fixed: Email notifications: host name is missing in generated links
1617 1618 * Fixed: Email notifications: referenced changesets, wiki pages, attachments... are not turned into links
1618 1619 * Fixed: Do not clear issue relations when moving an issue to another project if cross-project issue relations are allowed
1619 1620 * Fixed: "undefined method 'textilizable'" error on email notification when running Repository#fetch_changesets from the console
1620 1621 * Fixed: Do not send an email with no recipient, cc or bcc
1621 1622 * Fixed: fetch_changesets fails on commit comments that close 2 duplicates issues.
1622 1623 * Fixed: Mercurial browsing under unix-like os and for directory depth > 2
1623 1624 * Fixed: Wiki links with pipe can not be used in wiki tables
1624 1625 * Fixed: migrate_from_trac doesn't import timestamps of wiki and tickets
1625 1626 * Fixed: when bulk editing, setting "Assigned to" to "nobody" causes an sql error with Postgresql
1626 1627
1627 1628
1628 1629 == 2008-03-12 v0.6.4
1629 1630
1630 1631 * Fixed: private projects name are displayed on account/show even if the current user doesn't have access to these private projects
1631 1632 * Fixed: potential LDAP authentication security flaw
1632 1633 * Fixed: context submenus on the issue list don't show up with IE6.
1633 1634 * Fixed: Themes are not applied with Rails 2.0
1634 1635 * Fixed: crash when fetching Mercurial changesets if changeset[:files] is nil
1635 1636 * Fixed: Mercurial repository browsing
1636 1637 * Fixed: undefined local variable or method 'log' in CvsAdapter when a cvs command fails
1637 1638 * Fixed: not null constraints not removed with Postgresql
1638 1639 * Doctype set to transitional
1639 1640
1640 1641
1641 1642 == 2007-12-18 v0.6.3
1642 1643
1643 1644 * Fixed: upload doesn't work in 'Files' section
1644 1645
1645 1646
1646 1647 == 2007-12-16 v0.6.2
1647 1648
1648 1649 * Search engine: issue custom fields can now be searched
1649 1650 * News comments are now textilized
1650 1651 * Updated Japanese translation (Satoru Kurashiki)
1651 1652 * Updated Chinese translation (Shortie Lo)
1652 1653 * Fixed Rails 2.0 compatibility bugs:
1653 1654 * Unable to create a wiki
1654 1655 * Gantt and calendar error
1655 1656 * Trac importer error (readonly? is defined by ActiveRecord)
1656 1657 * Fixed: 'assigned to me' filter broken
1657 1658 * Fixed: crash when validation fails on issue edition with no custom fields
1658 1659 * Fixed: reposman "can't find group" error
1659 1660 * Fixed: 'LDAP account password is too long' error when leaving the field empty on creation
1660 1661 * Fixed: empty lines when displaying repository files with Windows style eol
1661 1662 * Fixed: missing body closing tag in repository annotate and entry views
1662 1663
1663 1664
1664 1665 == 2007-12-10 v0.6.1
1665 1666
1666 1667 * Rails 2.0 compatibility
1667 1668 * Custom fields can now be displayed as columns on the issue list
1668 1669 * Added version details view (accessible from the roadmap)
1669 1670 * Roadmap: more accurate completion percentage calculation (done ratio of open issues is now taken into account)
1670 1671 * Added per-project tracker selection. Trackers can be selected on project settings
1671 1672 * Anonymous users can now be allowed to create, edit, comment issues, comment news and post messages in the forums
1672 1673 * Forums: messages can now be edited/deleted (explicit permissions need to be given)
1673 1674 * Forums: topics can be locked so that no reply can be added
1674 1675 * Forums: topics can be marked as sticky so that they always appear at the top of the list
1675 1676 * Forums: attachments can now be added to replies
1676 1677 * Added time zone support
1677 1678 * Added a setting to choose the account activation strategy (available in application settings)
1678 1679 * Added 'Classic' theme (inspired from the v0.51 design)
1679 1680 * Added an alternate theme which provides issue list colorization based on issues priority
1680 1681 * Added Bazaar SCM adapter
1681 1682 * Added Annotate/Blame view in the repository browser (except for Darcs SCM)
1682 1683 * Diff style (inline or side by side) automatically saved as a user preference
1683 1684 * Added issues status changes on the activity view (by Cyril Mougel)
1684 1685 * Added forums topics on the activity view (disabled by default)
1685 1686 * Added an option on 'My account' for users who don't want to be notified of changes that they make
1686 1687 * Trac importer now supports mysql and postgresql databases
1687 1688 * Trac importer improvements (by Mat Trudel)
1688 1689 * 'fixed version' field can now be displayed on the issue list
1689 1690 * Added a couple of new formats for the 'date format' setting
1690 1691 * Added Traditional Chinese translation (by Shortie Lo)
1691 1692 * Added Russian translation (iGor kMeta)
1692 1693 * Project name format limitation removed (name can now contain any character)
1693 1694 * Project identifier maximum length changed from 12 to 20
1694 1695 * Changed the maximum length of LDAP account to 255 characters
1695 1696 * Removed the 12 characters limit on passwords
1696 1697 * Added wiki macros support
1697 1698 * Performance improvement on workflow setup screen
1698 1699 * More detailed html title on several views
1699 1700 * Custom fields can now be reordered
1700 1701 * Search engine: search can be restricted to an exact phrase by using quotation marks
1701 1702 * Added custom fields marked as 'For all projects' to the csv export of the cross project issue list
1702 1703 * Email notifications are now sent as Blind carbon copy by default
1703 1704 * Fixed: all members (including non active) should be deleted when deleting a project
1704 1705 * Fixed: Error on wiki syntax link (accessible from wiki/edit)
1705 1706 * Fixed: 'quick jump to a revision' form on the revisions list
1706 1707 * Fixed: error on admin/info if there's more than 1 plugin installed
1707 1708 * Fixed: svn or ldap password can be found in clear text in the html source in editing mode
1708 1709 * Fixed: 'Assigned to' drop down list is not sorted
1709 1710 * Fixed: 'View all issues' link doesn't work on issues/show
1710 1711 * Fixed: error on account/register when validation fails
1711 1712 * Fixed: Error when displaying the issue list if a float custom field is marked as 'used as filter'
1712 1713 * Fixed: Mercurial adapter breaks on missing :files entry in changeset hash (James Britt)
1713 1714 * Fixed: Wrong feed URLs on the home page
1714 1715 * Fixed: Update of time entry fails when the issue has been moved to an other project
1715 1716 * Fixed: Error when moving an issue without changing its tracker (Postgresql)
1716 1717 * Fixed: Changes not recorded when using :pserver string (CVS adapter)
1717 1718 * Fixed: admin should be able to move issues to any project
1718 1719 * Fixed: adding an attachment is not possible when changing the status of an issue
1719 1720 * Fixed: No mime-types in documents/files downloading
1720 1721 * Fixed: error when sorting the messages if there's only one board for the project
1721 1722 * Fixed: 'me' doesn't appear in the drop down filters on a project issue list.
1722 1723
1723 1724 == 2007-11-04 v0.6.0
1724 1725
1725 1726 * Permission model refactoring.
1726 1727 * Permissions: there are now 2 builtin roles that can be used to specify permissions given to other users than members of projects
1727 1728 * Permissions: some permissions (eg. browse the repository) can be removed for certain roles
1728 1729 * Permissions: modules (eg. issue tracking, news, documents...) can be enabled/disabled at project level
1729 1730 * Added Mantis and Trac importers
1730 1731 * New application layout
1731 1732 * Added "Bulk edit" functionality on the issue list
1732 1733 * More flexible mail notifications settings at user level
1733 1734 * Added AJAX based context menu on the project issue list that provide shortcuts for editing, re-assigning, changing the status or the priority, moving or deleting an issue
1734 1735 * Added the hability to copy an issue. It can be done from the "issue/show" view or from the context menu on the issue list
1735 1736 * Added the ability to customize issue list columns (at application level or for each saved query)
1736 1737 * Overdue versions (date reached and open issues > 0) are now always displayed on the roadmap
1737 1738 * Added the ability to rename wiki pages (specific permission required)
1738 1739 * Search engines now supports pagination. Results are sorted in reverse chronological order
1739 1740 * Added "Estimated hours" attribute on issues
1740 1741 * A category with assigned issue can now be deleted. 2 options are proposed: remove assignments or reassign issues to another category
1741 1742 * Forum notifications are now also sent to the authors of the thread, even if they donΓ―ΒΏΒ½t watch the board
1742 1743 * Added an application setting to specify the application protocol (http or https) used to generate urls in emails
1743 1744 * Gantt chart: now starts at the current month by default
1744 1745 * Gantt chart: month count and zoom factor are automatically saved as user preferences
1745 1746 * Wiki links can now refer to other project wikis
1746 1747 * Added wiki index by date
1747 1748 * Added preview on add/edit issue form
1748 1749 * Emails footer can now be customized from the admin interface (Admin -> Email notifications)
1749 1750 * Default encodings for repository files can now be set in application settings (used to convert files content and diff to UTF-8 so that theyΓ―ΒΏΒ½re properly displayed)
1750 1751 * Calendar: first day of week can now be set in lang files
1751 1752 * Automatic closing of duplicate issues
1752 1753 * Added a cross-project issue list
1753 1754 * AJAXified the SCM browser (tree view)
1754 1755 * Pretty URL for the repository browser (Cyril Mougel)
1755 1756 * Search engine: added a checkbox to search titles only
1756 1757 * Added "% done" in the filter list
1757 1758 * Enumerations: values can now be reordered and a default value can be specified (eg. default issue priority)
1758 1759 * Added some accesskeys
1759 1760 * Added "Float" as a custom field format
1760 1761 * Added basic Theme support
1761 1762 * Added the ability to set the Γ―ΒΏΒ½done ratioΓ―ΒΏΒ½ of issues fixed by commit (Nikolay Solakov)
1762 1763 * Added custom fields in issue related mail notifications
1763 1764 * Email notifications are now sent in plain text and html
1764 1765 * Gantt chart can now be exported to a graphic file (png). This functionality is only available if RMagick is installed.
1765 1766 * Added syntax highlightment for repository files and wiki
1766 1767 * Improved automatic Redmine links
1767 1768 * Added automatic table of content support on wiki pages
1768 1769 * Added radio buttons on the documents list to sort documents by category, date, title or author
1769 1770 * Added basic plugin support, with a sample plugin
1770 1771 * Added a link to add a new category when creating or editing an issue
1771 1772 * Added a "Assignable" boolean on the Role model. If unchecked, issues can not be assigned to users having this role.
1772 1773 * Added an option to be able to relate issues in different projects
1773 1774 * Added the ability to move issues (to another project) without changing their trackers.
1774 1775 * Atom feeds added on project activity, news and changesets
1775 1776 * Added the ability to reset its own RSS access key
1776 1777 * Main project list now displays root projects with their subprojects
1777 1778 * Added anchor links to issue notes
1778 1779 * Added reposman Ruby version. This script can now register created repositories in Redmine (Nicolas Chuche)
1779 1780 * Issue notes are now included in search
1780 1781 * Added email sending test functionality
1781 1782 * Added LDAPS support for LDAP authentication
1782 1783 * Removed hard-coded URLs in mail templates
1783 1784 * Subprojects are now grouped by projects in the navigation drop-down menu
1784 1785 * Added a new value for date filters: this week
1785 1786 * Added cache for application settings
1786 1787 * Added Polish translation (Tomasz Gawryl)
1787 1788 * Added Czech translation (Jan Kadlecek)
1788 1789 * Added Romanian translation (Csongor Bartus)
1789 1790 * Added Hebrew translation (Bob Builder)
1790 1791 * Added Serbian translation (Dragan Matic)
1791 1792 * Added Korean translation (Choi Jong Yoon)
1792 1793 * Fixed: the link to delete issue relations is displayed even if the user is not authorized to delete relations
1793 1794 * Performance improvement on calendar and gantt
1794 1795 * Fixed: wiki preview doesnΓ―ΒΏΒ½t work on long entries
1795 1796 * Fixed: queries with multiple custom fields return no result
1796 1797 * Fixed: Can not authenticate user against LDAP if its DN contains non-ascii characters
1797 1798 * Fixed: URL with ~ broken in wiki formatting
1798 1799 * Fixed: some quotation marks are rendered as strange characters in pdf
1799 1800
1800 1801
1801 1802 == 2007-07-15 v0.5.1
1802 1803
1803 1804 * per project forums added
1804 1805 * added the ability to archive projects
1805 1806 * added Γ―ΒΏΒ½WatchΓ―ΒΏΒ½ functionality on issues. It allows users to receive notifications about issue changes
1806 1807 * custom fields for issues can now be used as filters on issue list
1807 1808 * added per user custom queries
1808 1809 * commit messages are now scanned for referenced or fixed issue IDs (keywords defined in Admin -> Settings)
1809 1810 * projects list now shows the list of public projects and private projects for which the user is a member
1810 1811 * versions can now be created with no date
1811 1812 * added issue count details for versions on Reports view
1812 1813 * added time report, by member/activity/tracker/version and year/month/week for the selected period
1813 1814 * each category can now be associated to a user, so that new issues in that category are automatically assigned to that user
1814 1815 * added autologin feature (disabled by default)
1815 1816 * optimistic locking added for wiki edits
1816 1817 * added wiki diff
1817 1818 * added the ability to destroy wiki pages (requires permission)
1818 1819 * a wiki page can now be attached to each version, and displayed on the roadmap
1819 1820 * attachments can now be added to wiki pages (original patch by Pavol Murin) and displayed online
1820 1821 * added an option to see all versions in the roadmap view (including completed ones)
1821 1822 * added basic issue relations
1822 1823 * added the ability to log time when changing an issue status
1823 1824 * account information can now be sent to the user when creating an account
1824 1825 * author and assignee of an issue always receive notifications (even if they turned of mail notifications)
1825 1826 * added a quick search form in page header
1826 1827 * added 'me' value for 'assigned to' and 'author' query filters
1827 1828 * added a link on revision screen to see the entire diff for the revision
1828 1829 * added last commit message for each entry in repository browser
1829 1830 * added the ability to view a file diff with free to/from revision selection.
1830 1831 * text files can now be viewed online when browsing the repository
1831 1832 * added basic support for other SCM: CVS (Ralph Vater), Mercurial and Darcs
1832 1833 * added fragment caching for svn diffs
1833 1834 * added fragment caching for calendar and gantt views
1834 1835 * login field automatically focused on login form
1835 1836 * subproject name displayed on issue list, calendar and gantt
1836 1837 * added an option to choose the date format: language based or ISO 8601
1837 1838 * added a simple mail handler. It lets users add notes to an existing issue by replying to the initial notification email.
1838 1839 * a 403 error page is now displayed (instead of a blank page) when trying to access a protected page
1839 1840 * added portuguese translation (Joao Carlos Clementoni)
1840 1841 * added partial online help japanese translation (Ken Date)
1841 1842 * added bulgarian translation (Nikolay Solakov)
1842 1843 * added dutch translation (Linda van den Brink)
1843 1844 * added swedish translation (Thomas Habets)
1844 1845 * italian translation update (Alessio Spadaro)
1845 1846 * japanese translation update (Satoru Kurashiki)
1846 1847 * fixed: error on history atom feed when thereΓ―ΒΏΒ½s no notes on an issue change
1847 1848 * fixed: error in journalizing an issue with longtext custom fields (Postgresql)
1848 1849 * fixed: creation of Oracle schema
1849 1850 * fixed: last day of the month not included in project activity
1850 1851 * fixed: files with an apostrophe in their names can't be accessed in SVN repository
1851 1852 * fixed: performance issue on RepositoriesController#revisions when a changeset has a great number of changes (eg. 100,000)
1852 1853 * fixed: open/closed issue counts are always 0 on reports view (postgresql)
1853 1854 * fixed: date query filters (wrong results and sql error with postgresql)
1854 1855 * fixed: confidentiality issue on account/show (private project names displayed to anyone)
1855 1856 * fixed: Long text custom fields displayed without line breaks
1856 1857 * fixed: Error when editing the wokflow after deleting a status
1857 1858 * fixed: SVN commit dates are now stored as local time
1858 1859
1859 1860
1860 1861 == 2007-04-11 v0.5.0
1861 1862
1862 1863 * added per project Wiki
1863 1864 * added rss/atom feeds at project level (custom queries can be used as feeds)
1864 1865 * added search engine (search in issues, news, commits, wiki pages, documents)
1865 1866 * simple time tracking functionality added
1866 1867 * added version due dates on calendar and gantt
1867 1868 * added subprojects issue count on project Reports page
1868 1869 * added the ability to copy an existing workflow when creating a new tracker
1869 1870 * added the ability to include subprojects on calendar and gantt
1870 1871 * added the ability to select trackers to display on calendar and gantt (Jeffrey Jones)
1871 1872 * added side by side svn diff view (Cyril Mougel)
1872 1873 * added back subproject filter on issue list
1873 1874 * added permissions report in admin area
1874 1875 * added a status filter on users list
1875 1876 * support for password-protected SVN repositories
1876 1877 * SVN commits are now stored in the database
1877 1878 * added simple svn statistics SVG graphs
1878 1879 * progress bars for roadmap versions (Nick Read)
1879 1880 * issue history now shows file uploads and deletions
1880 1881 * #id patterns are turned into links to issues in descriptions and commit messages
1881 1882 * japanese translation added (Satoru Kurashiki)
1882 1883 * chinese simplified translation added (Andy Wu)
1883 1884 * italian translation added (Alessio Spadaro)
1884 1885 * added scripts to manage SVN repositories creation and user access control using ssh+svn (Nicolas Chuche)
1885 1886 * better calendar rendering time
1886 1887 * fixed migration scripts to work with mysql 5 running in strict mode
1887 1888 * fixed: error when clicking "add" with no block selected on my/page_layout
1888 1889 * fixed: hard coded links in navigation bar
1889 1890 * fixed: table_name pre/suffix support
1890 1891
1891 1892
1892 1893 == 2007-02-18 v0.4.2
1893 1894
1894 1895 * Rails 1.2 is now required
1895 1896 * settings are now stored in the database and editable through the application in: Admin -> Settings (config_custom.rb is no longer used)
1896 1897 * added project roadmap view
1897 1898 * mail notifications added when a document, a file or an attachment is added
1898 1899 * tooltips added on Gantt chart and calender to view the details of the issues
1899 1900 * ability to set the sort order for roles, trackers, issue statuses
1900 1901 * added missing fields to csv export: priority, start date, due date, done ratio
1901 1902 * added total number of issues per tracker on project overview
1902 1903 * all icons replaced (new icons are based on GPL icon set: "KDE Crystal Diamond 2.5" -by paolino- and "kNeu! Alpha v0.1" -by Pablo Fabregat-)
1903 1904 * added back "fixed version" field on issue screen and in filters
1904 1905 * project settings screen split in 4 tabs
1905 1906 * custom fields screen split in 3 tabs (one for each kind of custom field)
1906 1907 * multiple issues pdf export now rendered as a table
1907 1908 * added a button on users/list to manually activate an account
1908 1909 * added a setting option to disable "password lost" functionality
1909 1910 * added a setting option to set max number of issues in csv/pdf exports
1910 1911 * fixed: subprojects count is always 0 on projects list
1911 1912 * fixed: locked users are proposed when adding a member to a project
1912 1913 * fixed: setting an issue status as default status leads to an sql error with SQLite
1913 1914 * fixed: unable to delete an issue status even if it's not used yet
1914 1915 * fixed: filters ignored when exporting a predefined query to csv/pdf
1915 1916 * fixed: crash when french "issue_edit" email notification is sent
1916 1917 * fixed: hide mail preference not saved (my/account)
1917 1918 * fixed: crash when a new user try to edit its "my page" layout
1918 1919
1919 1920
1920 1921 == 2007-01-03 v0.4.1
1921 1922
1922 1923 * fixed: emails have no recipient when one of the project members has notifications disabled
1923 1924
1924 1925
1925 1926 == 2007-01-02 v0.4.0
1926 1927
1927 1928 * simple SVN browser added (just needs svn binaries in PATH)
1928 1929 * comments can now be added on news
1929 1930 * "my page" is now customizable
1930 1931 * more powerfull and savable filters for issues lists
1931 1932 * improved issues change history
1932 1933 * new functionality: move an issue to another project or tracker
1933 1934 * new functionality: add a note to an issue
1934 1935 * new report: project activity
1935 1936 * "start date" and "% done" fields added on issues
1936 1937 * project calendar added
1937 1938 * gantt chart added (exportable to pdf)
1938 1939 * single/multiple issues pdf export added
1939 1940 * issues reports improvements
1940 1941 * multiple file upload for issues, documents and files
1941 1942 * option to set maximum size of uploaded files
1942 1943 * textile formating of issue and news descritions (RedCloth required)
1943 1944 * integration of DotClear jstoolbar for textile formatting
1944 1945 * calendar date picker for date fields (LGPL DHTML Calendar http://sourceforge.net/projects/jscalendar)
1945 1946 * new filter in issues list: Author
1946 1947 * ajaxified paginators
1947 1948 * news rss feed added
1948 1949 * option to set number of results per page on issues list
1949 1950 * localized csv separator (comma/semicolon)
1950 1951 * csv output encoded to ISO-8859-1
1951 1952 * user custom field displayed on account/show
1952 1953 * default configuration improved (default roles, trackers, status, permissions and workflows)
1953 1954 * language for default configuration data can now be chosen when running 'load_default_data' task
1954 1955 * javascript added on custom field form to show/hide fields according to the format of custom field
1955 1956 * fixed: custom fields not in csv exports
1956 1957 * fixed: project settings now displayed according to user's permissions
1957 1958 * fixed: application error when no version is selected on projects/add_file
1958 1959 * fixed: public actions not authorized for members of non public projects
1959 1960 * fixed: non public projects were shown on welcome screen even if current user is not a member
1960 1961
1961 1962
1962 1963 == 2006-10-08 v0.3.0
1963 1964
1964 1965 * user authentication against multiple LDAP (optional)
1965 1966 * token based "lost password" functionality
1966 1967 * user self-registration functionality (optional)
1967 1968 * custom fields now available for issues, users and projects
1968 1969 * new custom field format "text" (displayed as a textarea field)
1969 1970 * project & administration drop down menus in navigation bar for quicker access
1970 1971 * text formatting is preserved for long text fields (issues, projects and news descriptions)
1971 1972 * urls and emails are turned into clickable links in long text fields
1972 1973 * "due date" field added on issues
1973 1974 * tracker selection filter added on change log
1974 1975 * Localization plugin replaced with GLoc 1.1.0 (iconv required)
1975 1976 * error messages internationalization
1976 1977 * german translation added (thanks to Karim Trott)
1977 1978 * data locking for issues to prevent update conflicts (using ActiveRecord builtin optimistic locking)
1978 1979 * new filter in issues list: "Fixed version"
1979 1980 * active filters are displayed with colored background on issues list
1980 1981 * custom configuration is now defined in config/config_custom.rb
1981 1982 * user object no more stored in session (only user_id)
1982 1983 * news summary field is no longer required
1983 1984 * tables and forms redesign
1984 1985 * Fixed: boolean custom field not working
1985 1986 * Fixed: error messages for custom fields are not displayed
1986 1987 * Fixed: invalid custom fields should have a red border
1987 1988 * Fixed: custom fields values are not validated on issue update
1988 1989 * Fixed: unable to choose an empty value for 'List' custom fields
1989 1990 * Fixed: no issue categories sorting
1990 1991 * Fixed: incorrect versions sorting
1991 1992
1992 1993
1993 1994 == 2006-07-12 - v0.2.2
1994 1995
1995 1996 * Fixed: bug in "issues list"
1996 1997
1997 1998
1998 1999 == 2006-07-09 - v0.2.1
1999 2000
2000 2001 * new databases supported: Oracle, PostgreSQL, SQL Server
2001 2002 * projects/subprojects hierarchy (1 level of subprojects only)
2002 2003 * environment information display in admin/info
2003 2004 * more filter options in issues list (rev6)
2004 2005 * default language based on browser settings (Accept-Language HTTP header)
2005 2006 * issues list exportable to CSV (rev6)
2006 2007 * simple_format and auto_link on long text fields
2007 2008 * more data validations
2008 2009 * Fixed: error when all mail notifications are unchecked in admin/mail_options
2009 2010 * Fixed: all project news are displayed on project summary
2010 2011 * Fixed: Can't change user password in users/edit
2011 2012 * Fixed: Error on tables creation with PostgreSQL (rev5)
2012 2013 * Fixed: SQL error in "issue reports" view with PostgreSQL (rev5)
2013 2014
2014 2015
2015 2016 == 2006-06-25 - v0.1.0
2016 2017
2017 2018 * multiple users/multiple projects
2018 2019 * role based access control
2019 2020 * issue tracking system
2020 2021 * fully customizable workflow
2021 2022 * documents/files repository
2022 2023 * email notifications on issue creation and update
2023 2024 * multilanguage support (except for error messages):english, french, spanish
2024 2025 * online manual in french (unfinished)
@@ -1,991 +1,1019
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../test_helper', __FILE__)
19 19
20 20 class QueryTest < ActiveSupport::TestCase
21 21 fixtures :projects, :enabled_modules, :users, :members,
22 22 :member_roles, :roles, :trackers, :issue_statuses,
23 23 :issue_categories, :enumerations, :issues,
24 24 :watchers, :custom_fields, :custom_values, :versions,
25 25 :queries,
26 26 :projects_trackers
27 27
28 28 def test_custom_fields_for_all_projects_should_be_available_in_global_queries
29 29 query = Query.new(:project => nil, :name => '_')
30 30 assert query.available_filters.has_key?('cf_1')
31 31 assert !query.available_filters.has_key?('cf_3')
32 32 end
33 33
34 34 def test_system_shared_versions_should_be_available_in_global_queries
35 35 Version.find(2).update_attribute :sharing, 'system'
36 36 query = Query.new(:project => nil, :name => '_')
37 37 assert query.available_filters.has_key?('fixed_version_id')
38 38 assert query.available_filters['fixed_version_id'][:values].detect {|v| v.last == '2'}
39 39 end
40 40
41 41 def test_project_filter_in_global_queries
42 42 query = Query.new(:project => nil, :name => '_')
43 43 project_filter = query.available_filters["project_id"]
44 44 assert_not_nil project_filter
45 45 project_ids = project_filter[:values].map{|p| p[1]}
46 46 assert project_ids.include?("1") #public project
47 47 assert !project_ids.include?("2") #private project user cannot see
48 48 end
49 49
50 50 def find_issues_with_query(query)
51 51 Issue.find :all,
52 52 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
53 53 :conditions => query.statement
54 54 end
55 55
56 56 def assert_find_issues_with_query_is_successful(query)
57 57 assert_nothing_raised do
58 58 find_issues_with_query(query)
59 59 end
60 60 end
61 61
62 62 def assert_query_statement_includes(query, condition)
63 63 assert query.statement.include?(condition), "Query statement condition not found in: #{query.statement}"
64 64 end
65 65
66 66 def assert_query_result(expected, query)
67 67 assert_nothing_raised do
68 68 assert_equal expected.map(&:id).sort, query.issues.map(&:id).sort
69 69 assert_equal expected.size, query.issue_count
70 70 end
71 71 end
72 72
73 73 def test_query_should_allow_shared_versions_for_a_project_query
74 74 subproject_version = Version.find(4)
75 75 query = Query.new(:project => Project.find(1), :name => '_')
76 76 query.add_filter('fixed_version_id', '=', [subproject_version.id.to_s])
77 77
78 78 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IN ('4')")
79 79 end
80 80
81 81 def test_query_with_multiple_custom_fields
82 82 query = Query.find(1)
83 83 assert query.valid?
84 84 assert query.statement.include?("#{CustomValue.table_name}.value IN ('MySQL')")
85 85 issues = find_issues_with_query(query)
86 86 assert_equal 1, issues.length
87 87 assert_equal Issue.find(3), issues.first
88 88 end
89 89
90 90 def test_operator_none
91 91 query = Query.new(:project => Project.find(1), :name => '_')
92 92 query.add_filter('fixed_version_id', '!*', [''])
93 93 query.add_filter('cf_1', '!*', [''])
94 94 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NULL")
95 95 assert query.statement.include?("#{CustomValue.table_name}.value IS NULL OR #{CustomValue.table_name}.value = ''")
96 96 find_issues_with_query(query)
97 97 end
98 98
99 99 def test_operator_none_for_integer
100 100 query = Query.new(:project => Project.find(1), :name => '_')
101 101 query.add_filter('estimated_hours', '!*', [''])
102 102 issues = find_issues_with_query(query)
103 103 assert !issues.empty?
104 104 assert issues.all? {|i| !i.estimated_hours}
105 105 end
106 106
107 107 def test_operator_none_for_date
108 108 query = Query.new(:project => Project.find(1), :name => '_')
109 109 query.add_filter('start_date', '!*', [''])
110 110 issues = find_issues_with_query(query)
111 111 assert !issues.empty?
112 112 assert issues.all? {|i| i.start_date.nil?}
113 113 end
114 114
115 115 def test_operator_none_for_string_custom_field
116 116 query = Query.new(:project => Project.find(1), :name => '_')
117 117 query.add_filter('cf_2', '!*', [''])
118 118 assert query.has_filter?('cf_2')
119 119 issues = find_issues_with_query(query)
120 120 assert !issues.empty?
121 121 assert issues.all? {|i| i.custom_field_value(2).blank?}
122 122 end
123 123
124 124 def test_operator_all
125 125 query = Query.new(:project => Project.find(1), :name => '_')
126 126 query.add_filter('fixed_version_id', '*', [''])
127 127 query.add_filter('cf_1', '*', [''])
128 128 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NOT NULL")
129 129 assert query.statement.include?("#{CustomValue.table_name}.value IS NOT NULL AND #{CustomValue.table_name}.value <> ''")
130 130 find_issues_with_query(query)
131 131 end
132 132
133 133 def test_operator_all_for_date
134 134 query = Query.new(:project => Project.find(1), :name => '_')
135 135 query.add_filter('start_date', '*', [''])
136 136 issues = find_issues_with_query(query)
137 137 assert !issues.empty?
138 138 assert issues.all? {|i| i.start_date.present?}
139 139 end
140 140
141 141 def test_operator_all_for_string_custom_field
142 142 query = Query.new(:project => Project.find(1), :name => '_')
143 143 query.add_filter('cf_2', '*', [''])
144 144 assert query.has_filter?('cf_2')
145 145 issues = find_issues_with_query(query)
146 146 assert !issues.empty?
147 147 assert issues.all? {|i| i.custom_field_value(2).present?}
148 148 end
149 149
150 150 def test_numeric_filter_should_not_accept_non_numeric_values
151 151 query = Query.new(:name => '_')
152 152 query.add_filter('estimated_hours', '=', ['a'])
153 153
154 154 assert query.has_filter?('estimated_hours')
155 155 assert !query.valid?
156 156 end
157 157
158 158 def test_operator_is_on_float
159 159 Issue.update_all("estimated_hours = 171.2", "id=2")
160 160
161 161 query = Query.new(:name => '_')
162 162 query.add_filter('estimated_hours', '=', ['171.20'])
163 163 issues = find_issues_with_query(query)
164 164 assert_equal 1, issues.size
165 165 assert_equal 2, issues.first.id
166 166 end
167 167
168 168 def test_operator_is_on_integer_custom_field
169 169 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_for_all => true, :is_filter => true)
170 170 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7')
171 171 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12')
172 172 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
173 173
174 174 query = Query.new(:name => '_')
175 175 query.add_filter("cf_#{f.id}", '=', ['12'])
176 176 issues = find_issues_with_query(query)
177 177 assert_equal 1, issues.size
178 178 assert_equal 2, issues.first.id
179 179 end
180 180
181 def test_operator_is_on_integer_custom_field_should_accept_negative_value
182 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_for_all => true, :is_filter => true)
183 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7')
184 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '-12')
185 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
186
187 query = Query.new(:name => '_')
188 query.add_filter("cf_#{f.id}", '=', ['-12'])
189 assert query.valid?
190 issues = find_issues_with_query(query)
191 assert_equal 1, issues.size
192 assert_equal 2, issues.first.id
193 end
194
181 195 def test_operator_is_on_float_custom_field
182 196 f = IssueCustomField.create!(:name => 'filter', :field_format => 'float', :is_filter => true, :is_for_all => true)
183 197 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7.3')
184 198 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12.7')
185 199 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
186 200
187 201 query = Query.new(:name => '_')
188 202 query.add_filter("cf_#{f.id}", '=', ['12.7'])
189 203 issues = find_issues_with_query(query)
190 204 assert_equal 1, issues.size
191 205 assert_equal 2, issues.first.id
192 206 end
193 207
208 def test_operator_is_on_float_custom_field_should_accept_negative_value
209 f = IssueCustomField.create!(:name => 'filter', :field_format => 'float', :is_filter => true, :is_for_all => true)
210 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7.3')
211 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '-12.7')
212 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
213
214 query = Query.new(:name => '_')
215 query.add_filter("cf_#{f.id}", '=', ['-12.7'])
216 assert query.valid?
217 issues = find_issues_with_query(query)
218 assert_equal 1, issues.size
219 assert_equal 2, issues.first.id
220 end
221
194 222 def test_operator_is_on_multi_list_custom_field
195 223 f = IssueCustomField.create!(:name => 'filter', :field_format => 'list', :is_filter => true, :is_for_all => true,
196 224 :possible_values => ['value1', 'value2', 'value3'], :multiple => true)
197 225 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value1')
198 226 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value2')
199 227 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => 'value1')
200 228
201 229 query = Query.new(:name => '_')
202 230 query.add_filter("cf_#{f.id}", '=', ['value1'])
203 231 issues = find_issues_with_query(query)
204 232 assert_equal [1, 3], issues.map(&:id).sort
205 233
206 234 query = Query.new(:name => '_')
207 235 query.add_filter("cf_#{f.id}", '=', ['value2'])
208 236 issues = find_issues_with_query(query)
209 237 assert_equal [1], issues.map(&:id).sort
210 238 end
211 239
212 240 def test_operator_is_not_on_multi_list_custom_field
213 241 f = IssueCustomField.create!(:name => 'filter', :field_format => 'list', :is_filter => true, :is_for_all => true,
214 242 :possible_values => ['value1', 'value2', 'value3'], :multiple => true)
215 243 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value1')
216 244 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value2')
217 245 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => 'value1')
218 246
219 247 query = Query.new(:name => '_')
220 248 query.add_filter("cf_#{f.id}", '!', ['value1'])
221 249 issues = find_issues_with_query(query)
222 250 assert !issues.map(&:id).include?(1)
223 251 assert !issues.map(&:id).include?(3)
224 252
225 253 query = Query.new(:name => '_')
226 254 query.add_filter("cf_#{f.id}", '!', ['value2'])
227 255 issues = find_issues_with_query(query)
228 256 assert !issues.map(&:id).include?(1)
229 257 assert issues.map(&:id).include?(3)
230 258 end
231 259
232 260 def test_operator_greater_than
233 261 query = Query.new(:project => Project.find(1), :name => '_')
234 262 query.add_filter('done_ratio', '>=', ['40'])
235 263 assert query.statement.include?("#{Issue.table_name}.done_ratio >= 40.0")
236 264 find_issues_with_query(query)
237 265 end
238 266
239 267 def test_operator_greater_than_a_float
240 268 query = Query.new(:project => Project.find(1), :name => '_')
241 269 query.add_filter('estimated_hours', '>=', ['40.5'])
242 270 assert query.statement.include?("#{Issue.table_name}.estimated_hours >= 40.5")
243 271 find_issues_with_query(query)
244 272 end
245 273
246 274 def test_operator_greater_than_on_int_custom_field
247 275 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
248 276 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7')
249 277 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12')
250 278 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
251 279
252 280 query = Query.new(:project => Project.find(1), :name => '_')
253 281 query.add_filter("cf_#{f.id}", '>=', ['8'])
254 282 issues = find_issues_with_query(query)
255 283 assert_equal 1, issues.size
256 284 assert_equal 2, issues.first.id
257 285 end
258 286
259 287 def test_operator_lesser_than
260 288 query = Query.new(:project => Project.find(1), :name => '_')
261 289 query.add_filter('done_ratio', '<=', ['30'])
262 290 assert query.statement.include?("#{Issue.table_name}.done_ratio <= 30.0")
263 291 find_issues_with_query(query)
264 292 end
265 293
266 294 def test_operator_lesser_than_on_custom_field
267 295 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
268 296 query = Query.new(:project => Project.find(1), :name => '_')
269 297 query.add_filter("cf_#{f.id}", '<=', ['30'])
270 298 assert query.statement.include?("CAST(custom_values.value AS decimal(60,3)) <= 30.0")
271 299 find_issues_with_query(query)
272 300 end
273 301
274 302 def test_operator_between
275 303 query = Query.new(:project => Project.find(1), :name => '_')
276 304 query.add_filter('done_ratio', '><', ['30', '40'])
277 305 assert_include "#{Issue.table_name}.done_ratio BETWEEN 30.0 AND 40.0", query.statement
278 306 find_issues_with_query(query)
279 307 end
280 308
281 309 def test_operator_between_on_custom_field
282 310 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
283 311 query = Query.new(:project => Project.find(1), :name => '_')
284 312 query.add_filter("cf_#{f.id}", '><', ['30', '40'])
285 313 assert_include "CAST(custom_values.value AS decimal(60,3)) BETWEEN 30.0 AND 40.0", query.statement
286 314 find_issues_with_query(query)
287 315 end
288 316
289 317 def test_date_filter_should_not_accept_non_date_values
290 318 query = Query.new(:name => '_')
291 319 query.add_filter('created_on', '=', ['a'])
292 320
293 321 assert query.has_filter?('created_on')
294 322 assert !query.valid?
295 323 end
296 324
297 325 def test_date_filter_should_not_accept_invalid_date_values
298 326 query = Query.new(:name => '_')
299 327 query.add_filter('created_on', '=', ['2011-01-34'])
300 328
301 329 assert query.has_filter?('created_on')
302 330 assert !query.valid?
303 331 end
304 332
305 333 def test_relative_date_filter_should_not_accept_non_integer_values
306 334 query = Query.new(:name => '_')
307 335 query.add_filter('created_on', '>t-', ['a'])
308 336
309 337 assert query.has_filter?('created_on')
310 338 assert !query.valid?
311 339 end
312 340
313 341 def test_operator_date_equals
314 342 query = Query.new(:name => '_')
315 343 query.add_filter('due_date', '=', ['2011-07-10'])
316 344 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
317 345 find_issues_with_query(query)
318 346 end
319 347
320 348 def test_operator_date_lesser_than
321 349 query = Query.new(:name => '_')
322 350 query.add_filter('due_date', '<=', ['2011-07-10'])
323 351 assert_match /issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement
324 352 find_issues_with_query(query)
325 353 end
326 354
327 355 def test_operator_date_greater_than
328 356 query = Query.new(:name => '_')
329 357 query.add_filter('due_date', '>=', ['2011-07-10'])
330 358 assert_match /issues\.due_date > '2011-07-09 23:59:59(\.9+)?'/, query.statement
331 359 find_issues_with_query(query)
332 360 end
333 361
334 362 def test_operator_date_between
335 363 query = Query.new(:name => '_')
336 364 query.add_filter('due_date', '><', ['2011-06-23', '2011-07-10'])
337 365 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
338 366 find_issues_with_query(query)
339 367 end
340 368
341 369 def test_operator_in_more_than
342 370 Issue.find(7).update_attribute(:due_date, (Date.today + 15))
343 371 query = Query.new(:project => Project.find(1), :name => '_')
344 372 query.add_filter('due_date', '>t+', ['15'])
345 373 issues = find_issues_with_query(query)
346 374 assert !issues.empty?
347 375 issues.each {|issue| assert(issue.due_date >= (Date.today + 15))}
348 376 end
349 377
350 378 def test_operator_in_less_than
351 379 query = Query.new(:project => Project.find(1), :name => '_')
352 380 query.add_filter('due_date', '<t+', ['15'])
353 381 issues = find_issues_with_query(query)
354 382 assert !issues.empty?
355 383 issues.each {|issue| assert(issue.due_date >= Date.today && issue.due_date <= (Date.today + 15))}
356 384 end
357 385
358 386 def test_operator_less_than_ago
359 387 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
360 388 query = Query.new(:project => Project.find(1), :name => '_')
361 389 query.add_filter('due_date', '>t-', ['3'])
362 390 issues = find_issues_with_query(query)
363 391 assert !issues.empty?
364 392 issues.each {|issue| assert(issue.due_date >= (Date.today - 3) && issue.due_date <= Date.today)}
365 393 end
366 394
367 395 def test_operator_more_than_ago
368 396 Issue.find(7).update_attribute(:due_date, (Date.today - 10))
369 397 query = Query.new(:project => Project.find(1), :name => '_')
370 398 query.add_filter('due_date', '<t-', ['10'])
371 399 assert query.statement.include?("#{Issue.table_name}.due_date <=")
372 400 issues = find_issues_with_query(query)
373 401 assert !issues.empty?
374 402 issues.each {|issue| assert(issue.due_date <= (Date.today - 10))}
375 403 end
376 404
377 405 def test_operator_in
378 406 Issue.find(7).update_attribute(:due_date, (Date.today + 2))
379 407 query = Query.new(:project => Project.find(1), :name => '_')
380 408 query.add_filter('due_date', 't+', ['2'])
381 409 issues = find_issues_with_query(query)
382 410 assert !issues.empty?
383 411 issues.each {|issue| assert_equal((Date.today + 2), issue.due_date)}
384 412 end
385 413
386 414 def test_operator_ago
387 415 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
388 416 query = Query.new(:project => Project.find(1), :name => '_')
389 417 query.add_filter('due_date', 't-', ['3'])
390 418 issues = find_issues_with_query(query)
391 419 assert !issues.empty?
392 420 issues.each {|issue| assert_equal((Date.today - 3), issue.due_date)}
393 421 end
394 422
395 423 def test_operator_today
396 424 query = Query.new(:project => Project.find(1), :name => '_')
397 425 query.add_filter('due_date', 't', [''])
398 426 issues = find_issues_with_query(query)
399 427 assert !issues.empty?
400 428 issues.each {|issue| assert_equal Date.today, issue.due_date}
401 429 end
402 430
403 431 def test_operator_this_week_on_date
404 432 query = Query.new(:project => Project.find(1), :name => '_')
405 433 query.add_filter('due_date', 'w', [''])
406 434 find_issues_with_query(query)
407 435 end
408 436
409 437 def test_operator_this_week_on_datetime
410 438 query = Query.new(:project => Project.find(1), :name => '_')
411 439 query.add_filter('created_on', 'w', [''])
412 440 find_issues_with_query(query)
413 441 end
414 442
415 443 def test_operator_contains
416 444 query = Query.new(:project => Project.find(1), :name => '_')
417 445 query.add_filter('subject', '~', ['uNable'])
418 446 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) LIKE '%unable%'")
419 447 result = find_issues_with_query(query)
420 448 assert result.empty?
421 449 result.each {|issue| assert issue.subject.downcase.include?('unable') }
422 450 end
423 451
424 452 def test_range_for_this_week_with_week_starting_on_monday
425 453 I18n.locale = :fr
426 454 assert_equal '1', I18n.t(:general_first_day_of_week)
427 455
428 456 Date.stubs(:today).returns(Date.parse('2011-04-29'))
429 457
430 458 query = Query.new(:project => Project.find(1), :name => '_')
431 459 query.add_filter('due_date', 'w', [''])
432 460 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}"
433 461 I18n.locale = :en
434 462 end
435 463
436 464 def test_range_for_this_week_with_week_starting_on_sunday
437 465 I18n.locale = :en
438 466 assert_equal '7', I18n.t(:general_first_day_of_week)
439 467
440 468 Date.stubs(:today).returns(Date.parse('2011-04-29'))
441 469
442 470 query = Query.new(:project => Project.find(1), :name => '_')
443 471 query.add_filter('due_date', 'w', [''])
444 472 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}"
445 473 end
446 474
447 475 def test_operator_does_not_contains
448 476 query = Query.new(:project => Project.find(1), :name => '_')
449 477 query.add_filter('subject', '!~', ['uNable'])
450 478 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) NOT LIKE '%unable%'")
451 479 find_issues_with_query(query)
452 480 end
453 481
454 482 def test_filter_assigned_to_me
455 483 user = User.find(2)
456 484 group = Group.find(10)
457 485 User.current = user
458 486 i1 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => user)
459 487 i2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => group)
460 488 i3 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => Group.find(11))
461 489 group.users << user
462 490
463 491 query = Query.new(:name => '_', :filters => { 'assigned_to_id' => {:operator => '=', :values => ['me']}})
464 492 result = query.issues
465 493 assert_equal Issue.visible.all(:conditions => {:assigned_to_id => ([2] + user.reload.group_ids)}).sort_by(&:id), result.sort_by(&:id)
466 494
467 495 assert result.include?(i1)
468 496 assert result.include?(i2)
469 497 assert !result.include?(i3)
470 498 end
471 499
472 500 def test_user_custom_field_filtered_on_me
473 501 User.current = User.find(2)
474 502 cf = IssueCustomField.create!(:field_format => 'user', :is_for_all => true, :is_filter => true, :name => 'User custom field', :tracker_ids => [1])
475 503 issue1 = Issue.create!(:project_id => 1, :tracker_id => 1, :custom_field_values => {cf.id.to_s => '2'}, :subject => 'Test', :author_id => 1)
476 504 issue2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {cf.id.to_s => '3'})
477 505
478 506 query = Query.new(:name => '_', :project => Project.find(1))
479 507 filter = query.available_filters["cf_#{cf.id}"]
480 508 assert_not_nil filter
481 509 assert_include 'me', filter[:values].map{|v| v[1]}
482 510
483 511 query.filters = { "cf_#{cf.id}" => {:operator => '=', :values => ['me']}}
484 512 result = query.issues
485 513 assert_equal 1, result.size
486 514 assert_equal issue1, result.first
487 515 end
488 516
489 517 def test_filter_my_projects
490 518 User.current = User.find(2)
491 519 query = Query.new(:name => '_')
492 520 filter = query.available_filters['project_id']
493 521 assert_not_nil filter
494 522 assert_include 'mine', filter[:values].map{|v| v[1]}
495 523
496 524 query.filters = { 'project_id' => {:operator => '=', :values => ['mine']}}
497 525 result = query.issues
498 526 assert_nil result.detect {|issue| !User.current.member_of?(issue.project)}
499 527 end
500 528
501 529 def test_filter_watched_issues
502 530 User.current = User.find(1)
503 531 query = Query.new(:name => '_', :filters => { 'watcher_id' => {:operator => '=', :values => ['me']}})
504 532 result = find_issues_with_query(query)
505 533 assert_not_nil result
506 534 assert !result.empty?
507 535 assert_equal Issue.visible.watched_by(User.current).sort_by(&:id), result.sort_by(&:id)
508 536 User.current = nil
509 537 end
510 538
511 539 def test_filter_unwatched_issues
512 540 User.current = User.find(1)
513 541 query = Query.new(:name => '_', :filters => { 'watcher_id' => {:operator => '!', :values => ['me']}})
514 542 result = find_issues_with_query(query)
515 543 assert_not_nil result
516 544 assert !result.empty?
517 545 assert_equal((Issue.visible - Issue.watched_by(User.current)).sort_by(&:id).size, result.sort_by(&:id).size)
518 546 User.current = nil
519 547 end
520 548
521 549 def test_statement_should_be_nil_with_no_filters
522 550 q = Query.new(:name => '_')
523 551 q.filters = {}
524 552
525 553 assert q.valid?
526 554 assert_nil q.statement
527 555 end
528 556
529 557 def test_default_columns
530 558 q = Query.new
531 559 assert !q.columns.empty?
532 560 end
533 561
534 562 def test_set_column_names
535 563 q = Query.new
536 564 q.column_names = ['tracker', :subject, '', 'unknonw_column']
537 565 assert_equal [:tracker, :subject], q.columns.collect {|c| c.name}
538 566 c = q.columns.first
539 567 assert q.has_column?(c)
540 568 end
541 569
542 570 def test_query_should_preload_spent_hours
543 571 q = Query.new(:name => '_', :column_names => [:subject, :spent_hours])
544 572 assert q.has_column?(:spent_hours)
545 573 issues = q.issues
546 574 assert_not_nil issues.first.instance_variable_get("@spent_hours")
547 575 end
548 576
549 577 def test_groupable_columns_should_include_custom_fields
550 578 q = Query.new
551 579 column = q.groupable_columns.detect {|c| c.name == :cf_1}
552 580 assert_not_nil column
553 581 assert_kind_of QueryCustomFieldColumn, column
554 582 end
555 583
556 584 def test_groupable_columns_should_not_include_multi_custom_fields
557 585 field = CustomField.find(1)
558 586 field.update_attribute :multiple, true
559 587
560 588 q = Query.new
561 589 column = q.groupable_columns.detect {|c| c.name == :cf_1}
562 590 assert_nil column
563 591 end
564 592
565 593 def test_grouped_with_valid_column
566 594 q = Query.new(:group_by => 'status')
567 595 assert q.grouped?
568 596 assert_not_nil q.group_by_column
569 597 assert_equal :status, q.group_by_column.name
570 598 assert_not_nil q.group_by_statement
571 599 assert_equal 'status', q.group_by_statement
572 600 end
573 601
574 602 def test_grouped_with_invalid_column
575 603 q = Query.new(:group_by => 'foo')
576 604 assert !q.grouped?
577 605 assert_nil q.group_by_column
578 606 assert_nil q.group_by_statement
579 607 end
580 608
581 609 def test_sortable_columns_should_sort_assignees_according_to_user_format_setting
582 610 with_settings :user_format => 'lastname_coma_firstname' do
583 611 q = Query.new
584 612 assert q.sortable_columns.has_key?('assigned_to')
585 613 assert_equal %w(users.lastname users.firstname users.id), q.sortable_columns['assigned_to']
586 614 end
587 615 end
588 616
589 617 def test_sortable_columns_should_sort_authors_according_to_user_format_setting
590 618 with_settings :user_format => 'lastname_coma_firstname' do
591 619 q = Query.new
592 620 assert q.sortable_columns.has_key?('author')
593 621 assert_equal %w(authors.lastname authors.firstname authors.id), q.sortable_columns['author']
594 622 end
595 623 end
596 624
597 625 def test_sortable_columns_should_include_custom_field
598 626 q = Query.new
599 627 assert q.sortable_columns['cf_1']
600 628 end
601 629
602 630 def test_sortable_columns_should_not_include_multi_custom_field
603 631 field = CustomField.find(1)
604 632 field.update_attribute :multiple, true
605 633
606 634 q = Query.new
607 635 assert !q.sortable_columns['cf_1']
608 636 end
609 637
610 638 def test_default_sort
611 639 q = Query.new
612 640 assert_equal [], q.sort_criteria
613 641 end
614 642
615 643 def test_set_sort_criteria_with_hash
616 644 q = Query.new
617 645 q.sort_criteria = {'0' => ['priority', 'desc'], '2' => ['tracker']}
618 646 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
619 647 end
620 648
621 649 def test_set_sort_criteria_with_array
622 650 q = Query.new
623 651 q.sort_criteria = [['priority', 'desc'], 'tracker']
624 652 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
625 653 end
626 654
627 655 def test_create_query_with_sort
628 656 q = Query.new(:name => 'Sorted')
629 657 q.sort_criteria = [['priority', 'desc'], 'tracker']
630 658 assert q.save
631 659 q.reload
632 660 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
633 661 end
634 662
635 663 def test_sort_by_string_custom_field_asc
636 664 q = Query.new
637 665 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
638 666 assert c
639 667 assert c.sortable
640 668 issues = Issue.find :all,
641 669 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
642 670 :conditions => q.statement,
643 671 :order => "#{c.sortable} ASC"
644 672 values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s}
645 673 assert !values.empty?
646 674 assert_equal values.sort, values
647 675 end
648 676
649 677 def test_sort_by_string_custom_field_desc
650 678 q = Query.new
651 679 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
652 680 assert c
653 681 assert c.sortable
654 682 issues = Issue.find :all,
655 683 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
656 684 :conditions => q.statement,
657 685 :order => "#{c.sortable} DESC"
658 686 values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s}
659 687 assert !values.empty?
660 688 assert_equal values.sort.reverse, values
661 689 end
662 690
663 691 def test_sort_by_float_custom_field_asc
664 692 q = Query.new
665 693 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'float' }
666 694 assert c
667 695 assert c.sortable
668 696 issues = Issue.find :all,
669 697 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
670 698 :conditions => q.statement,
671 699 :order => "#{c.sortable} ASC"
672 700 values = issues.collect {|i| begin; Kernel.Float(i.custom_value_for(c.custom_field).to_s); rescue; nil; end}.compact
673 701 assert !values.empty?
674 702 assert_equal values.sort, values
675 703 end
676 704
677 705 def test_invalid_query_should_raise_query_statement_invalid_error
678 706 q = Query.new
679 707 assert_raise Query::StatementInvalid do
680 708 q.issues(:conditions => "foo = 1")
681 709 end
682 710 end
683 711
684 712 def test_issue_count
685 713 q = Query.new(:name => '_')
686 714 issue_count = q.issue_count
687 715 assert_equal q.issues.size, issue_count
688 716 end
689 717
690 718 def test_issue_count_with_archived_issues
691 719 p = Project.generate!( :status => Project::STATUS_ARCHIVED )
692 720 i = Issue.generate!( :project => p, :tracker => p.trackers.first )
693 721 assert !i.visible?
694 722
695 723 test_issue_count
696 724 end
697 725
698 726 def test_issue_count_by_association_group
699 727 q = Query.new(:name => '_', :group_by => 'assigned_to')
700 728 count_by_group = q.issue_count_by_group
701 729 assert_kind_of Hash, count_by_group
702 730 assert_equal %w(NilClass User), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
703 731 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
704 732 assert count_by_group.has_key?(User.find(3))
705 733 end
706 734
707 735 def test_issue_count_by_list_custom_field_group
708 736 q = Query.new(:name => '_', :group_by => 'cf_1')
709 737 count_by_group = q.issue_count_by_group
710 738 assert_kind_of Hash, count_by_group
711 739 assert_equal %w(NilClass String), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
712 740 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
713 741 assert count_by_group.has_key?('MySQL')
714 742 end
715 743
716 744 def test_issue_count_by_date_custom_field_group
717 745 q = Query.new(:name => '_', :group_by => 'cf_8')
718 746 count_by_group = q.issue_count_by_group
719 747 assert_kind_of Hash, count_by_group
720 748 assert_equal %w(Date NilClass), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
721 749 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
722 750 end
723 751
724 752 def test_issue_ids
725 753 q = Query.new(:name => '_')
726 754 order = "issues.subject, issues.id"
727 755 issues = q.issues(:order => order)
728 756 assert_equal issues.map(&:id), q.issue_ids(:order => order)
729 757 end
730 758
731 759 def test_label_for
732 760 q = Query.new
733 761 assert_equal 'Assignee', q.label_for('assigned_to_id')
734 762 end
735 763
736 764 def test_editable_by
737 765 admin = User.find(1)
738 766 manager = User.find(2)
739 767 developer = User.find(3)
740 768
741 769 # Public query on project 1
742 770 q = Query.find(1)
743 771 assert q.editable_by?(admin)
744 772 assert q.editable_by?(manager)
745 773 assert !q.editable_by?(developer)
746 774
747 775 # Private query on project 1
748 776 q = Query.find(2)
749 777 assert q.editable_by?(admin)
750 778 assert !q.editable_by?(manager)
751 779 assert q.editable_by?(developer)
752 780
753 781 # Private query for all projects
754 782 q = Query.find(3)
755 783 assert q.editable_by?(admin)
756 784 assert !q.editable_by?(manager)
757 785 assert q.editable_by?(developer)
758 786
759 787 # Public query for all projects
760 788 q = Query.find(4)
761 789 assert q.editable_by?(admin)
762 790 assert !q.editable_by?(manager)
763 791 assert !q.editable_by?(developer)
764 792 end
765 793
766 794 def test_visible_scope
767 795 query_ids = Query.visible(User.anonymous).map(&:id)
768 796
769 797 assert query_ids.include?(1), 'public query on public project was not visible'
770 798 assert query_ids.include?(4), 'public query for all projects was not visible'
771 799 assert !query_ids.include?(2), 'private query on public project was visible'
772 800 assert !query_ids.include?(3), 'private query for all projects was visible'
773 801 assert !query_ids.include?(7), 'public query on private project was visible'
774 802 end
775 803
776 804 context "#available_filters" do
777 805 setup do
778 806 @query = Query.new(:name => "_")
779 807 end
780 808
781 809 should "include users of visible projects in cross-project view" do
782 810 users = @query.available_filters["assigned_to_id"]
783 811 assert_not_nil users
784 812 assert users[:values].map{|u|u[1]}.include?("3")
785 813 end
786 814
787 815 should "include users of subprojects" do
788 816 user1 = User.generate_with_protected!
789 817 user2 = User.generate_with_protected!
790 818 project = Project.find(1)
791 819 Member.create!(:principal => user1, :project => project.children.visible.first, :role_ids => [1])
792 820 @query.project = project
793 821
794 822 users = @query.available_filters["assigned_to_id"]
795 823 assert_not_nil users
796 824 assert users[:values].map{|u|u[1]}.include?(user1.id.to_s)
797 825 assert !users[:values].map{|u|u[1]}.include?(user2.id.to_s)
798 826 end
799 827
800 828 should "include visible projects in cross-project view" do
801 829 projects = @query.available_filters["project_id"]
802 830 assert_not_nil projects
803 831 assert projects[:values].map{|u|u[1]}.include?("1")
804 832 end
805 833
806 834 context "'member_of_group' filter" do
807 835 should "be present" do
808 836 assert @query.available_filters.keys.include?("member_of_group")
809 837 end
810 838
811 839 should "be an optional list" do
812 840 assert_equal :list_optional, @query.available_filters["member_of_group"][:type]
813 841 end
814 842
815 843 should "have a list of the groups as values" do
816 844 Group.destroy_all # No fixtures
817 845 group1 = Group.generate!.reload
818 846 group2 = Group.generate!.reload
819 847
820 848 expected_group_list = [
821 849 [group1.name, group1.id.to_s],
822 850 [group2.name, group2.id.to_s]
823 851 ]
824 852 assert_equal expected_group_list.sort, @query.available_filters["member_of_group"][:values].sort
825 853 end
826 854
827 855 end
828 856
829 857 context "'assigned_to_role' filter" do
830 858 should "be present" do
831 859 assert @query.available_filters.keys.include?("assigned_to_role")
832 860 end
833 861
834 862 should "be an optional list" do
835 863 assert_equal :list_optional, @query.available_filters["assigned_to_role"][:type]
836 864 end
837 865
838 866 should "have a list of the Roles as values" do
839 867 assert @query.available_filters["assigned_to_role"][:values].include?(['Manager','1'])
840 868 assert @query.available_filters["assigned_to_role"][:values].include?(['Developer','2'])
841 869 assert @query.available_filters["assigned_to_role"][:values].include?(['Reporter','3'])
842 870 end
843 871
844 872 should "not include the built in Roles as values" do
845 873 assert ! @query.available_filters["assigned_to_role"][:values].include?(['Non member','4'])
846 874 assert ! @query.available_filters["assigned_to_role"][:values].include?(['Anonymous','5'])
847 875 end
848 876
849 877 end
850 878
851 879 end
852 880
853 881 context "#statement" do
854 882 context "with 'member_of_group' filter" do
855 883 setup do
856 884 Group.destroy_all # No fixtures
857 885 @user_in_group = User.generate!
858 886 @second_user_in_group = User.generate!
859 887 @user_in_group2 = User.generate!
860 888 @user_not_in_group = User.generate!
861 889
862 890 @group = Group.generate!.reload
863 891 @group.users << @user_in_group
864 892 @group.users << @second_user_in_group
865 893
866 894 @group2 = Group.generate!.reload
867 895 @group2.users << @user_in_group2
868 896
869 897 end
870 898
871 899 should "search assigned to for users in the group" do
872 900 @query = Query.new(:name => '_')
873 901 @query.add_filter('member_of_group', '=', [@group.id.to_s])
874 902
875 903 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}')"
876 904 assert_find_issues_with_query_is_successful @query
877 905 end
878 906
879 907 should "search not assigned to any group member (none)" do
880 908 @query = Query.new(:name => '_')
881 909 @query.add_filter('member_of_group', '!*', [''])
882 910
883 911 # Users not in a group
884 912 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IS NULL OR #{Issue.table_name}.assigned_to_id NOT IN ('#{@user_in_group.id}','#{@second_user_in_group.id}','#{@user_in_group2.id}')"
885 913 assert_find_issues_with_query_is_successful @query
886 914 end
887 915
888 916 should "search assigned to any group member (all)" do
889 917 @query = Query.new(:name => '_')
890 918 @query.add_filter('member_of_group', '*', [''])
891 919
892 920 # Only users in a group
893 921 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}','#{@user_in_group2.id}')"
894 922 assert_find_issues_with_query_is_successful @query
895 923 end
896 924
897 925 should "return an empty set with = empty group" do
898 926 @empty_group = Group.generate!
899 927 @query = Query.new(:name => '_')
900 928 @query.add_filter('member_of_group', '=', [@empty_group.id.to_s])
901 929
902 930 assert_equal [], find_issues_with_query(@query)
903 931 end
904 932
905 933 should "return issues with ! empty group" do
906 934 @empty_group = Group.generate!
907 935 @query = Query.new(:name => '_')
908 936 @query.add_filter('member_of_group', '!', [@empty_group.id.to_s])
909 937
910 938 assert_find_issues_with_query_is_successful @query
911 939 end
912 940 end
913 941
914 942 context "with 'assigned_to_role' filter" do
915 943 setup do
916 944 @manager_role = Role.find_by_name('Manager')
917 945 @developer_role = Role.find_by_name('Developer')
918 946
919 947 @project = Project.generate!
920 948 @manager = User.generate!
921 949 @developer = User.generate!
922 950 @boss = User.generate!
923 951 @guest = User.generate!
924 952 User.add_to_project(@manager, @project, @manager_role)
925 953 User.add_to_project(@developer, @project, @developer_role)
926 954 User.add_to_project(@boss, @project, [@manager_role, @developer_role])
927 955
928 956 @issue1 = Issue.generate_for_project!(@project, :assigned_to_id => @manager.id)
929 957 @issue2 = Issue.generate_for_project!(@project, :assigned_to_id => @developer.id)
930 958 @issue3 = Issue.generate_for_project!(@project, :assigned_to_id => @boss.id)
931 959 @issue4 = Issue.generate_for_project!(@project, :assigned_to_id => @guest.id)
932 960 @issue5 = Issue.generate_for_project!(@project)
933 961 end
934 962
935 963 should "search assigned to for users with the Role" do
936 964 @query = Query.new(:name => '_', :project => @project)
937 965 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
938 966
939 967 assert_query_result [@issue1, @issue3], @query
940 968 end
941 969
942 970 should "search assigned to for users with the Role on the issue project" do
943 971 other_project = Project.generate!
944 972 User.add_to_project(@developer, other_project, @manager_role)
945 973
946 974 @query = Query.new(:name => '_', :project => @project)
947 975 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
948 976
949 977 assert_query_result [@issue1, @issue3], @query
950 978 end
951 979
952 980 should "return an empty set with empty role" do
953 981 @empty_role = Role.generate!
954 982 @query = Query.new(:name => '_', :project => @project)
955 983 @query.add_filter('assigned_to_role', '=', [@empty_role.id.to_s])
956 984
957 985 assert_query_result [], @query
958 986 end
959 987
960 988 should "search assigned to for users without the Role" do
961 989 @query = Query.new(:name => '_', :project => @project)
962 990 @query.add_filter('assigned_to_role', '!', [@manager_role.id.to_s])
963 991
964 992 assert_query_result [@issue2, @issue4, @issue5], @query
965 993 end
966 994
967 995 should "search assigned to for users not assigned to any Role (none)" do
968 996 @query = Query.new(:name => '_', :project => @project)
969 997 @query.add_filter('assigned_to_role', '!*', [''])
970 998
971 999 assert_query_result [@issue4, @issue5], @query
972 1000 end
973 1001
974 1002 should "search assigned to for users assigned to any Role (all)" do
975 1003 @query = Query.new(:name => '_', :project => @project)
976 1004 @query.add_filter('assigned_to_role', '*', [''])
977 1005
978 1006 assert_query_result [@issue1, @issue2, @issue3], @query
979 1007 end
980 1008
981 1009 should "return issues with ! empty role" do
982 1010 @empty_role = Role.generate!
983 1011 @query = Query.new(:name => '_', :project => @project)
984 1012 @query.add_filter('assigned_to_role', '!', [@empty_role.id.to_s])
985 1013
986 1014 assert_query_result [@issue1, @issue2, @issue3, @issue4, @issue5], @query
987 1015 end
988 1016 end
989 1017 end
990 1018
991 1019 end
General Comments 0
You need to be logged in to leave comments. Login now