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 |