@@ -146,6 +146,8 class CustomField < ActiveRecord::Base | |||||
146 | " WHERE cv_sort.customized_type='#{self.class.customized_class.base_class.name}'" + |
|
146 | " WHERE cv_sort.customized_type='#{self.class.customized_class.base_class.name}'" + | |
147 | " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" + |
|
147 | " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" + | |
148 | " AND cv_sort.custom_field_id=#{id} AND cv_sort.value <> '' AND cv_sort.value IS NOT NULL LIMIT 1)" |
|
148 | " AND cv_sort.custom_field_id=#{id} AND cv_sort.value <> '' AND cv_sort.value IS NOT NULL LIMIT 1)" | |
|
149 | when 'user', 'version' | |||
|
150 | value_class.fields_for_order_statement(value_join_alias) | |||
149 | else |
|
151 | else | |
150 | nil |
|
152 | nil | |
151 | end |
|
153 | end | |
@@ -158,15 +160,57 class CustomField < ActiveRecord::Base | |||||
158 | case field_format |
|
160 | case field_format | |
159 | when 'list', 'date', 'bool', 'int' |
|
161 | when 'list', 'date', 'bool', 'int' | |
160 | order_statement |
|
162 | order_statement | |
|
163 | when 'user', 'version' | |||
|
164 | "COALESCE((SELECT cv_sort.value FROM #{CustomValue.table_name} cv_sort" + | |||
|
165 | " WHERE cv_sort.customized_type='#{self.class.customized_class.base_class.name}'" + | |||
|
166 | " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" + | |||
|
167 | " AND cv_sort.custom_field_id=#{id} LIMIT 1), '')" | |||
|
168 | else | |||
|
169 | nil | |||
|
170 | end | |||
|
171 | end | |||
|
172 | ||||
|
173 | def join_for_order_statement | |||
|
174 | case field_format | |||
|
175 | when 'user', 'version' | |||
|
176 | "LEFT OUTER JOIN #{CustomValue.table_name} #{join_alias}" + | |||
|
177 | " ON #{join_alias}.customized_type = '#{self.class.customized_class.base_class.name}'" + | |||
|
178 | " AND #{join_alias}.customized_id = #{self.class.customized_class.table_name}.id" + | |||
|
179 | " AND #{join_alias}.custom_field_id = #{id}" + | |||
|
180 | " AND #{join_alias}.value <> ''" + | |||
|
181 | " AND #{join_alias}.id = (SELECT max(#{join_alias}_2.id) FROM #{CustomValue.table_name} #{join_alias}_2" + | |||
|
182 | " WHERE #{join_alias}_2.customized_type = #{join_alias}.customized_type" + | |||
|
183 | " AND #{join_alias}_2.customized_id = #{join_alias}.customized_id" + | |||
|
184 | " AND #{join_alias}_2.custom_field_id = #{join_alias}.custom_field_id)" + | |||
|
185 | " LEFT OUTER JOIN #{value_class.table_name} #{value_join_alias}" + | |||
|
186 | " ON CAST(#{join_alias}.value as decimal(60,0)) = #{value_join_alias}.id" | |||
161 | else |
|
187 | else | |
162 | nil |
|
188 | nil | |
163 | end |
|
189 | end | |
164 | end |
|
190 | end | |
165 |
|
191 | |||
|
192 | def join_alias | |||
|
193 | "cf_#{id}" | |||
|
194 | end | |||
|
195 | ||||
|
196 | def value_join_alias | |||
|
197 | join_alias + "_" + field_format | |||
|
198 | end | |||
|
199 | ||||
166 | def <=>(field) |
|
200 | def <=>(field) | |
167 | position <=> field.position |
|
201 | position <=> field.position | |
168 | end |
|
202 | end | |
169 |
|
203 | |||
|
204 | # Returns the class that values represent | |||
|
205 | def value_class | |||
|
206 | case field_format | |||
|
207 | when 'user', 'version' | |||
|
208 | field_format.classify.constantize | |||
|
209 | else | |||
|
210 | nil | |||
|
211 | end | |||
|
212 | end | |||
|
213 | ||||
170 | def self.customized_class |
|
214 | def self.customized_class | |
171 | self.name =~ /^(.+)CustomField$/ |
|
215 | self.name =~ /^(.+)CustomField$/ | |
172 | begin; $1.constantize; rescue nil; end |
|
216 | begin; $1.constantize; rescue nil; end |
@@ -604,13 +604,11 class Query < ActiveRecord::Base | |||||
604 | def issues(options={}) |
|
604 | def issues(options={}) | |
605 | order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',') |
|
605 | order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',') | |
606 | order_option = nil if order_option.blank? |
|
606 | order_option = nil if order_option.blank? | |
607 |
|
||||
608 | joins = (order_option && order_option.include?('authors')) ? "LEFT OUTER JOIN users authors ON authors.id = #{Issue.table_name}.author_id" : nil |
|
|||
609 |
|
607 | |||
610 | issues = Issue.visible.scoped(:conditions => options[:conditions]).find :all, :include => ([:status, :project] + (options[:include] || [])).uniq, |
|
608 | issues = Issue.visible.scoped(:conditions => options[:conditions]).find :all, :include => ([:status, :project] + (options[:include] || [])).uniq, | |
611 | :conditions => statement, |
|
609 | :conditions => statement, | |
612 | :order => order_option, |
|
610 | :order => order_option, | |
613 | :joins => joins, |
|
611 | :joins => joins_for_order_statement(order_option), | |
614 | :limit => options[:limit], |
|
612 | :limit => options[:limit], | |
615 | :offset => options[:offset] |
|
613 | :offset => options[:offset] | |
616 |
|
614 | |||
@@ -626,13 +624,11 class Query < ActiveRecord::Base | |||||
626 | def issue_ids(options={}) |
|
624 | def issue_ids(options={}) | |
627 | order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',') |
|
625 | order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',') | |
628 | order_option = nil if order_option.blank? |
|
626 | order_option = nil if order_option.blank? | |
629 |
|
||||
630 | joins = (order_option && order_option.include?('authors')) ? "LEFT OUTER JOIN users authors ON authors.id = #{Issue.table_name}.author_id" : nil |
|
|||
631 |
|
627 | |||
632 | Issue.visible.scoped(:conditions => options[:conditions]).scoped(:include => ([:status, :project] + (options[:include] || [])).uniq, |
|
628 | Issue.visible.scoped(:conditions => options[:conditions]).scoped(:include => ([:status, :project] + (options[:include] || [])).uniq, | |
633 | :conditions => statement, |
|
629 | :conditions => statement, | |
634 | :order => order_option, |
|
630 | :order => order_option, | |
635 | :joins => joins, |
|
631 | :joins => joins_for_order_statement(order_option), | |
636 | :limit => options[:limit], |
|
632 | :limit => options[:limit], | |
637 | :offset => options[:offset]).find_ids |
|
633 | :offset => options[:offset]).find_ids | |
638 | rescue ::ActiveRecord::StatementInvalid => e |
|
634 | rescue ::ActiveRecord::StatementInvalid => e | |
@@ -895,4 +891,24 class Query < ActiveRecord::Base | |||||
895 | def relative_date_clause(table, field, days_from, days_to) |
|
891 | def relative_date_clause(table, field, days_from, days_to) | |
896 | date_clause(table, field, (days_from ? Date.today + days_from : nil), (days_to ? Date.today + days_to : nil)) |
|
892 | date_clause(table, field, (days_from ? Date.today + days_from : nil), (days_to ? Date.today + days_to : nil)) | |
897 | end |
|
893 | end | |
|
894 | ||||
|
895 | # Additional joins required for the given sort options | |||
|
896 | def joins_for_order_statement(order_options) | |||
|
897 | joins = [] | |||
|
898 | ||||
|
899 | if order_options | |||
|
900 | if order_options.include?('authors') | |||
|
901 | joins << "LEFT OUTER JOIN #{User.table_name} authors ON authors.id = #{Issue.table_name}.author_id" | |||
|
902 | end | |||
|
903 | order_options.scan(/cf_\d+/).uniq.each do |name| | |||
|
904 | column = available_columns.detect {|c| c.name.to_s == name} | |||
|
905 | join = column.custom_field.join_for_order_statement | |||
|
906 | if join | |||
|
907 | joins << join | |||
|
908 | end | |||
|
909 | end | |||
|
910 | end | |||
|
911 | ||||
|
912 | joins.any? ? joins.join(' ') : nil | |||
|
913 | end | |||
898 | end |
|
914 | end |
@@ -254,6 +254,27 class IssuesControllerTest < ActionController::TestCase | |||||
254 | assert_not_nil assigns(:issue_count_by_group) |
|
254 | assert_not_nil assigns(:issue_count_by_group) | |
255 | end |
|
255 | end | |
256 |
|
256 | |||
|
257 | def test_index_with_query_grouped_by_user_custom_field | |||
|
258 | cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user') | |||
|
259 | CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2') | |||
|
260 | CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3') | |||
|
261 | CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3') | |||
|
262 | CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '') | |||
|
263 | ||||
|
264 | get :index, :project_id => 1, :set_filter => 1, :group_by => "cf_#{cf.id}" | |||
|
265 | assert_response :success | |||
|
266 | ||||
|
267 | assert_select 'tr.group', 3 | |||
|
268 | assert_select 'tr.group' do | |||
|
269 | assert_select 'a', :text => 'John Smith' | |||
|
270 | assert_select 'span.count', :text => '(1)' | |||
|
271 | end | |||
|
272 | assert_select 'tr.group' do | |||
|
273 | assert_select 'a', :text => 'Dave Lopper' | |||
|
274 | assert_select 'span.count', :text => '(2)' | |||
|
275 | end | |||
|
276 | end | |||
|
277 | ||||
257 | def test_index_with_query_id_and_project_id_should_set_session_query |
|
278 | def test_index_with_query_id_and_project_id_should_set_session_query | |
258 | get :index, :project_id => 1, :query_id => 4 |
|
279 | get :index, :project_id => 1, :query_id => 4 | |
259 | assert_response :success |
|
280 | assert_response :success | |
@@ -619,6 +640,19 class IssuesControllerTest < ActionController::TestCase | |||||
619 | assert_equal hours.sort.reverse, hours |
|
640 | assert_equal hours.sort.reverse, hours | |
620 | end |
|
641 | end | |
621 |
|
642 | |||
|
643 | def test_index_sort_by_user_custom_field | |||
|
644 | cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user') | |||
|
645 | CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2') | |||
|
646 | CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3') | |||
|
647 | CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3') | |||
|
648 | CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '') | |||
|
649 | ||||
|
650 | get :index, :project_id => 1, :set_filter => 1, :sort => "cf_#{cf.id},id" | |||
|
651 | assert_response :success | |||
|
652 | ||||
|
653 | assert_equal [2, 3, 1], assigns(:issues).select {|issue| issue.custom_field_value(cf).present?}.map(&:id) | |||
|
654 | end | |||
|
655 | ||||
622 | def test_index_with_columns |
|
656 | def test_index_with_columns | |
623 | columns = ['tracker', 'subject', 'assigned_to'] |
|
657 | columns = ['tracker', 'subject', 'assigned_to'] | |
624 | get :index, :set_filter => 1, :c => columns |
|
658 | get :index, :set_filter => 1, :c => columns | |
@@ -1114,6 +1148,24 class IssuesControllerTest < ActionController::TestCase | |||||
1114 | assert_no_tag 'a', :content => /Next/ |
|
1148 | assert_no_tag 'a', :content => /Next/ | |
1115 | end |
|
1149 | end | |
1116 |
|
1150 | |||
|
1151 | def test_show_show_should_display_prev_next_links_with_query_sort_by_user_custom_field | |||
|
1152 | cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user') | |||
|
1153 | CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2') | |||
|
1154 | CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3') | |||
|
1155 | CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3') | |||
|
1156 | CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '') | |||
|
1157 | ||||
|
1158 | query = Query.create!(:name => 'test', :is_public => true, :user_id => 1, :filters => {}, | |||
|
1159 | :sort_criteria => [["cf_#{cf.id}", 'asc'], ['id', 'asc']]) | |||
|
1160 | @request.session[:query] = {:id => query.id, :project_id => nil} | |||
|
1161 | ||||
|
1162 | get :show, :id => 3 | |||
|
1163 | assert_response :success | |||
|
1164 | ||||
|
1165 | assert_equal 2, assigns(:prev_issue_id) | |||
|
1166 | assert_equal 1, assigns(:next_issue_id) | |||
|
1167 | end | |||
|
1168 | ||||
1117 | def test_show_should_display_link_to_the_assignee |
|
1169 | def test_show_should_display_link_to_the_assignee | |
1118 | get :show, :id => 2 |
|
1170 | get :show, :id => 2 | |
1119 | assert_response :success |
|
1171 | assert_response :success |
@@ -202,4 +202,14 class CustomFieldTest < ActiveSupport::TestCase | |||||
202 | assert f.valid_field_value?(['value1', 'value2']) |
|
202 | assert f.valid_field_value?(['value1', 'value2']) | |
203 | assert !f.valid_field_value?(['value1', 'abc']) |
|
203 | assert !f.valid_field_value?(['value1', 'abc']) | |
204 | end |
|
204 | end | |
|
205 | ||||
|
206 | def test_value_class_should_return_the_class_used_for_fields_values | |||
|
207 | assert_equal User, CustomField.new(:field_format => 'user') | |||
|
208 | assert_equal Version, CustomField.new(:field_format => 'version') | |||
|
209 | end | |||
|
210 | ||||
|
211 | def test_value_class_should_return_nil_for_other_fields | |||
|
212 | assert_nil CustomField.new(:field_format => 'text') | |||
|
213 | assert_nil CustomField.new | |||
|
214 | end | |||
205 | end |
|
215 | end |
@@ -621,6 +621,20 class QueryTest < ActiveSupport::TestCase | |||||
621 | assert_nil column |
|
621 | assert_nil column | |
622 | end |
|
622 | end | |
623 |
|
623 | |||
|
624 | def test_groupable_columns_should_include_user_custom_fields | |||
|
625 | cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1], :field_format => 'user') | |||
|
626 | ||||
|
627 | q = Query.new | |||
|
628 | assert q.groupable_columns.detect {|c| c.name == "cf_#{cf.id}".to_sym} | |||
|
629 | end | |||
|
630 | ||||
|
631 | def test_groupable_columns_should_include_version_custom_fields | |||
|
632 | cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1], :field_format => 'version') | |||
|
633 | ||||
|
634 | q = Query.new | |||
|
635 | assert q.groupable_columns.detect {|c| c.name == "cf_#{cf.id}".to_sym} | |||
|
636 | end | |||
|
637 | ||||
624 | def test_grouped_with_valid_column |
|
638 | def test_grouped_with_valid_column | |
625 | q = Query.new(:group_by => 'status') |
|
639 | q = Query.new(:group_by => 'status') | |
626 | assert q.grouped? |
|
640 | assert q.grouped? |
General Comments 0
You need to be logged in to leave comments.
Login now