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