@@ -146,6 +146,8 class CustomField < ActiveRecord::Base | |||
|
146 | 146 | " WHERE cv_sort.customized_type='#{self.class.customized_class.base_class.name}'" + |
|
147 | 147 | " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" + |
|
148 | 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 | 151 | else |
|
150 | 152 | nil |
|
151 | 153 | end |
@@ -158,15 +160,57 class CustomField < ActiveRecord::Base | |||
|
158 | 160 | case field_format |
|
159 | 161 | when 'list', 'date', 'bool', 'int' |
|
160 | 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 | 187 | else |
|
162 | 188 | nil |
|
163 | 189 | end |
|
164 | 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 | 200 | def <=>(field) |
|
167 | 201 | position <=> field.position |
|
168 | 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 | 214 | def self.customized_class |
|
171 | 215 | self.name =~ /^(.+)CustomField$/ |
|
172 | 216 | begin; $1.constantize; rescue nil; end |
@@ -604,13 +604,11 class Query < ActiveRecord::Base | |||
|
604 | 604 | def issues(options={}) |
|
605 | 605 | order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',') |
|
606 | 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 | 608 | issues = Issue.visible.scoped(:conditions => options[:conditions]).find :all, :include => ([:status, :project] + (options[:include] || [])).uniq, |
|
611 | 609 | :conditions => statement, |
|
612 | 610 | :order => order_option, |
|
613 | :joins => joins, | |
|
611 | :joins => joins_for_order_statement(order_option), | |
|
614 | 612 | :limit => options[:limit], |
|
615 | 613 | :offset => options[:offset] |
|
616 | 614 | |
@@ -626,13 +624,11 class Query < ActiveRecord::Base | |||
|
626 | 624 | def issue_ids(options={}) |
|
627 | 625 | order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',') |
|
628 | 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 | 628 | Issue.visible.scoped(:conditions => options[:conditions]).scoped(:include => ([:status, :project] + (options[:include] || [])).uniq, |
|
633 | 629 | :conditions => statement, |
|
634 | 630 | :order => order_option, |
|
635 | :joins => joins, | |
|
631 | :joins => joins_for_order_statement(order_option), | |
|
636 | 632 | :limit => options[:limit], |
|
637 | 633 | :offset => options[:offset]).find_ids |
|
638 | 634 | rescue ::ActiveRecord::StatementInvalid => e |
@@ -895,4 +891,24 class Query < ActiveRecord::Base | |||
|
895 | 891 | def relative_date_clause(table, field, days_from, days_to) |
|
896 | 892 | date_clause(table, field, (days_from ? Date.today + days_from : nil), (days_to ? Date.today + days_to : nil)) |
|
897 | 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 | 914 | end |
@@ -254,6 +254,27 class IssuesControllerTest < ActionController::TestCase | |||
|
254 | 254 | assert_not_nil assigns(:issue_count_by_group) |
|
255 | 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 | 278 | def test_index_with_query_id_and_project_id_should_set_session_query |
|
258 | 279 | get :index, :project_id => 1, :query_id => 4 |
|
259 | 280 | assert_response :success |
@@ -619,6 +640,19 class IssuesControllerTest < ActionController::TestCase | |||
|
619 | 640 | assert_equal hours.sort.reverse, hours |
|
620 | 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 | 656 | def test_index_with_columns |
|
623 | 657 | columns = ['tracker', 'subject', 'assigned_to'] |
|
624 | 658 | get :index, :set_filter => 1, :c => columns |
@@ -1114,6 +1148,24 class IssuesControllerTest < ActionController::TestCase | |||
|
1114 | 1148 | assert_no_tag 'a', :content => /Next/ |
|
1115 | 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 | 1169 | def test_show_should_display_link_to_the_assignee |
|
1118 | 1170 | get :show, :id => 2 |
|
1119 | 1171 | assert_response :success |
@@ -202,4 +202,14 class CustomFieldTest < ActiveSupport::TestCase | |||
|
202 | 202 | assert f.valid_field_value?(['value1', 'value2']) |
|
203 | 203 | assert !f.valid_field_value?(['value1', 'abc']) |
|
204 | 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 | 215 | end |
@@ -621,6 +621,20 class QueryTest < ActiveSupport::TestCase | |||
|
621 | 621 | assert_nil column |
|
622 | 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 | 638 | def test_grouped_with_valid_column |
|
625 | 639 | q = Query.new(:group_by => 'status') |
|
626 | 640 | assert q.grouped? |
General Comments 0
You need to be logged in to leave comments.
Login now