Feature #41053 » 41053.patch
app/helpers/queries_helper.rb | ||
---|---|---|
37 | 37 |
group = query.is_a?(IssueQuery) ? :label_relations : nil |
38 | 38 |
elsif %w(member_of_group assigned_to_role).include?(field) |
39 | 39 |
group = :field_assigned_to |
40 |
elsif %(user_group user_role).include?(field) |
|
41 |
group = :field_user |
|
40 | 42 |
elsif field_options[:type] == :date_past || field_options[:type] == :date |
41 | 43 |
group = :label_date |
42 | 44 |
elsif %w(estimated_hours spent_time).include?(field) |
app/models/time_entry_query.rb | ||
---|---|---|
100 | 100 |
"activity_id", |
101 | 101 |
:type => :list, :values => activities.map {|a| [a.name, (a.parent_id || a.id).to_s]} |
102 | 102 |
) |
103 |
add_available_filter( |
|
104 |
"user_group", |
|
105 |
:type => :list_optional, |
|
106 |
:values => lambda {Group.givable.visible.pluck(:name, :id).map {|name, id| [name, id.to_s]}} |
|
107 |
) |
|
108 |
add_available_filter( |
|
109 |
"user_role", |
|
110 |
:type => :list_optional, |
|
111 |
:values => lambda {Role.givable.pluck(:name, :id).map {|name, id| [name, id.to_s]}} |
|
112 |
) |
|
103 | 113 |
add_available_filter( |
104 | 114 |
"project.status", |
105 | 115 |
:type => :list, |
... | ... | |
264 | 274 |
sql_for_field(field, operator, value, Project.table_name, "status") |
265 | 275 |
end |
266 | 276 | |
277 |
def sql_for_user_group_field(field, operator, value) |
|
278 |
if operator == '*' # Any group |
|
279 |
groups = Group.givable |
|
280 |
operator = '=' |
|
281 |
elsif operator == '!*' |
|
282 |
groups = Group.givable |
|
283 |
operator = '!' |
|
284 |
else |
|
285 |
groups = Group.where(:id => value).to_a |
|
286 |
end |
|
287 |
groups ||= [] |
|
288 | ||
289 |
members_of_groups = groups.inject([]) do |user_ids, group| |
|
290 |
user_ids + group.user_ids |
|
291 |
end.uniq.compact.sort.collect(&:to_s) |
|
292 | ||
293 |
'(' + sql_for_field('user_id', operator, members_of_groups, TimeEntry.table_name, "user_id", false) + ')' |
|
294 |
end |
|
295 | ||
296 |
def sql_for_user_role_field(field, operator, value) |
|
297 |
case operator |
|
298 |
when "*", "!*" |
|
299 |
sw = operator == "!*" ? "NOT" : "" |
|
300 |
nl = operator == "!*" ? "#{TimeEntry.table_name}.user_id IS NULL OR" : "" |
|
301 | ||
302 |
subquery = |
|
303 |
"SELECT 1" + |
|
304 |
" FROM #{Member.table_name}" + |
|
305 |
" WHERE #{TimeEntry.table_name}.project_id = #{Member.table_name}.project_id AND #{Member.table_name}.user_id = #{TimeEntry.table_name}.user_id" |
|
306 |
"(#{nl} #{sw} EXISTS (#{subquery}))" |
|
307 |
when "=", "!" |
|
308 |
role_cond = |
|
309 |
if value.any? |
|
310 |
"#{MemberRole.table_name}.role_id IN (" + value.collect{|val| "'#{self.class.connection.quote_string(val)}'"}.join(",") + ")" |
|
311 |
else |
|
312 |
"1=0" |
|
313 |
end |
|
314 |
sw = operator == "!" ? 'NOT' : '' |
|
315 |
nl = operator == "!" ? "#{TimeEntry.table_name}.user_id IS NULL OR" : '' |
|
316 |
subquery = |
|
317 |
"SELECT 1" + |
|
318 |
" FROM #{Member.table_name} inner join #{MemberRole.table_name} on members.id = member_roles.member_id" + |
|
319 |
" WHERE #{TimeEntry.table_name}.project_id = #{Member.table_name}.project_id AND #{Member.table_name}.user_id = #{TimeEntry.table_name}.user_id AND #{role_cond}" |
|
320 |
"(#{nl} #{sw} EXISTS (#{subquery}))" |
|
321 |
end |
|
322 |
end |
|
323 | ||
267 | 324 |
# Accepts :from/:to params as shortcut filters |
268 | 325 |
def build_from_params(params, defaults={}) |
269 | 326 |
super |
config/locales/en.yml | ||
---|---|---|
377 | 377 |
field_parent_issue_subject: Parent task subject |
378 | 378 |
field_member_of_group: "Assignee's group" |
379 | 379 |
field_assigned_to_role: "Assignee's role" |
380 |
field_user_group: "User's group" |
|
381 |
field_user_role: "User's role" |
|
380 | 382 |
field_text: Text field |
381 | 383 |
field_visible: Visible |
382 | 384 |
field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text" |
config/locales/ja.yml | ||
---|---|---|
335 | 335 |
field_parent_issue: 親チケット |
336 | 336 |
field_member_of_group: 担当者のグループ |
337 | 337 |
field_assigned_to_role: 担当者のロール |
338 |
field_user_group: ユーザーのグループ |
|
339 |
field_user_role: ユーザーのロール |
|
338 | 340 |
field_text: テキスト |
339 | 341 |
field_visible: 表示 |
340 | 342 |
field_warn_on_leaving_unsaved: データを保存せずにページから移動するときに警告 |
test/unit/time_entry_query_test.rb | ||
---|---|---|
136 | 136 |
assert !query.available_filters.has_key?('project.status') |
137 | 137 |
end |
138 | 138 | |
139 |
def test_user_group_filter_should_consider_spacified_groups_time_entries |
|
140 |
Group.find(10).users << User.find(2) |
|
141 |
Group.find(11).users << User.find(3) |
|
142 | ||
143 |
TimeEntry.delete_all |
|
144 |
t1 = TimeEntry.generate!(:hours => 1.0, :user_id => 2) |
|
145 |
t2 = TimeEntry.generate!(:hours => 2.0, :user_id => 2) |
|
146 |
t3 = TimeEntry.generate!(:hours => 4.0, :user_id => 3) |
|
147 | ||
148 |
query = TimeEntryQuery.new(:name => '_') |
|
149 |
result = query.base_scope.to_a |
|
150 |
assert result.include?(t1) |
|
151 |
assert result.include?(t2) |
|
152 |
assert result.include?(t3) |
|
153 |
assert_equal 7.0, query.results_scope.sum(:hours) |
|
154 | ||
155 |
query.add_filter('user_group', '=', ['10']) |
|
156 |
result = query.base_scope.to_a |
|
157 |
assert result.include?(t1) |
|
158 |
assert result.include?(t2) |
|
159 |
assert !result.include?(t3) |
|
160 |
assert_equal 3.0, query.results_scope.sum(:hours) |
|
161 | ||
162 |
query.add_filter('user_group', '=', ['10', '11']) |
|
163 |
result = query.base_scope.to_a |
|
164 |
assert result.include?(t1) |
|
165 |
assert result.include?(t2) |
|
166 |
assert result.include?(t3) |
|
167 |
assert_equal 7.0, query.results_scope.sum(:hours) |
|
168 |
end |
|
169 | ||
170 |
def test_user_role_filter_should_consider_spacified_roles_time_entries |
|
171 |
project = Project.find(1) |
|
172 |
project.members << Member.new(:user_id => 2, :roles => [Role.find(1)]) |
|
173 |
project.members << Member.new(:user_id => 3, :roles => [Role.find(2)]) |
|
174 | ||
175 |
TimeEntry.delete_all |
|
176 |
t1 = TimeEntry.generate!(:project => project, :hours => 1.0, :user_id => 2) |
|
177 |
t2 = TimeEntry.generate!(:project => project, :hours => 2.0, :user_id => 2) |
|
178 |
t3 = TimeEntry.generate!(:project => project, :hours => 4.0, :user_id => 3) |
|
179 | ||
180 |
query = TimeEntryQuery.new(:project => project, :name => '_') |
|
181 |
result = query.base_scope.to_a |
|
182 |
assert result.include?(t1) |
|
183 |
assert result.include?(t2) |
|
184 |
assert result.include?(t3) |
|
185 |
assert_equal 7.0, query.results_scope.sum(:hours) |
|
186 | ||
187 |
query.add_filter('user_role', '=', ['1']) |
|
188 |
result = query.base_scope.to_a |
|
189 |
assert result.include?(t1) |
|
190 |
assert result.include?(t2) |
|
191 |
assert !result.include?(t3) |
|
192 |
assert_equal 3.0, query.results_scope.sum(:hours) |
|
193 | ||
194 |
query.add_filter('user_role', '=', ['1', '2']) |
|
195 |
result = query.base_scope.to_a |
|
196 |
assert result.include?(t1) |
|
197 |
assert result.include?(t2) |
|
198 |
assert result.include?(t3) |
|
199 |
assert_equal 7.0, query.results_scope.sum(:hours) |
|
200 |
end |
|
201 | ||
139 | 202 |
def test_results_scope_should_be_in_the_same_order_when_paginating |
140 | 203 |
4.times {TimeEntry.generate!} |
141 | 204 |
q = TimeEntryQuery.new |