Feature #7360 » default_custom_query_trunk_r15303.patch
app/controllers/issues_controller.rb | ||
---|---|---|
24 | 24 |
before_filter :authorize, :except => [:index, :new, :create] |
25 | 25 |
before_filter :find_optional_project, :only => [:index, :new, :create] |
26 | 26 |
before_filter :build_new_issue_from_params, :only => [:new, :create] |
27 |
before_filter :with_default_query, only: [:index] |
|
27 | 28 |
accept_rss_auth :index, :show |
28 | 29 |
accept_api_auth :index, :show, :create, :update, :destroy |
29 | 30 | |
... | ... | |
353 | 354 | |
354 | 355 |
private |
355 | 356 | |
357 |
def with_default_query |
|
358 |
return if params[:query_id].present? |
|
359 |
return if api_request? |
|
360 |
return if params[:set_filter] && params.key?(:op) && params.key?(:f) |
|
361 |
params[:set_filter] = 1 and return if params[:without_default].present? |
|
362 |
apply_default_query! and return if params[:set_filter] && [:op, :f].all? {|k| !params.key?(k) } |
|
363 |
if session[:query] |
|
364 |
query_id, project_id = session[:query].values_at(:id, :project_id) |
|
365 |
unless query_id && (project_id == @project.id) && IssueQuery.available_query?(@project.id, query_id) |
|
366 |
apply_default_query! |
|
367 |
end |
|
368 |
else |
|
369 |
apply_default_query! |
|
370 |
end |
|
371 |
end |
|
372 | ||
373 |
def apply_default_query! |
|
374 |
if default_query = find_default_query |
|
375 |
params[:query_id] = default_query.id |
|
376 |
end |
|
377 |
end |
|
378 | ||
356 | 379 |
def retrieve_previous_and_next_issue_ids |
357 | 380 |
if params[:prev_issue_id].present? || params[:next_issue_id].present? |
358 | 381 |
@prev_issue_id = params[:prev_issue_id].presence.try(:to_i) |
app/helpers/projects_helper.rb | ||
---|---|---|
95 | 95 |
version_options_for_select(versions, project.default_version) |
96 | 96 |
end |
97 | 97 | |
98 |
def project_default_query_options(project) |
|
99 |
grouped = Hash.new {|h,k| h[k] = []} |
|
100 |
IssueQuery.only_public.where(project_id: nil).each do |query| |
|
101 |
grouped[l('label_default_queries.for_all_projects')] << [query.name, query.id] |
|
102 |
end |
|
103 |
project.queries.only_public.each do |query| |
|
104 |
grouped[l('label_default_queries.for_current_project')] << [query.name, query.id] |
|
105 |
end |
|
106 |
grouped_options_for_select(grouped, project.default_query_id) |
|
107 |
end |
|
108 | ||
98 | 109 |
def format_version_sharing(sharing) |
99 | 110 |
sharing = 'none' unless Version::VERSION_SHARINGS.include?(sharing) |
100 | 111 |
l("label_version_sharing_#{sharing}") |
app/helpers/queries_helper.rb | ||
---|---|---|
241 | 241 |
@query.project = @project |
242 | 242 |
end |
243 | 243 |
@query |
244 |
else |
|
245 |
@query = find_default_query |
|
244 | 246 |
end |
245 | 247 |
end |
246 | 248 | |
249 |
private |
|
250 | ||
251 |
def find_default_query |
|
252 |
@project.default_query if @project.is_a?(Project) |
|
253 |
end |
|
254 | ||
247 | 255 |
# Returns the query definition as hidden field tags |
248 | 256 |
def query_as_hidden_field_tags(query) |
249 | 257 |
tags = hidden_field_tag("set_filter", "1", :id => nil) |
app/models/issue_query.rb | ||
---|---|---|
16 | 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | 17 | |
18 | 18 |
class IssueQuery < Query |
19 | ||
20 | 19 |
self.queried_class = Issue |
21 | 20 | |
22 | 21 |
self.available_columns = [ |
... | ... | |
46 | 45 |
QueryColumn.new(:description, :inline => false) |
47 | 46 |
] |
48 | 47 | |
48 |
has_many :projects, :foreign_key => 'default_query_id' |
|
49 |
after_update { self.projects.clear unless self.public_visibility? } |
|
50 |
after_destroy { self.projects.clear } |
|
51 | ||
49 | 52 |
scope :visible, lambda {|*args| |
50 | 53 |
user = args.shift || User.current |
51 | 54 |
base = Project.allowed_to_condition(user, :view_issues, *args) |
... | ... | |
71 | 74 |
end |
72 | 75 |
} |
73 | 76 | |
77 |
scope :only_public, -> { |
|
78 |
where(:visibility => VISIBILITY_PUBLIC) |
|
79 |
} |
|
80 | ||
81 |
def self.available_query?(project_id, query_id) |
|
82 |
self.only_public |
|
83 |
.where('project_id is null or project_id = ?', project_id) |
|
84 |
.where(id: query_id).exists? |
|
85 |
end |
|
86 | ||
74 | 87 |
def initialize(attributes=nil, *args) |
75 | 88 |
super attributes |
76 | 89 |
self.filters ||= { 'status_id' => {:operator => "o", :values => [""]} } |
... | ... | |
102 | 115 |
!is_private? |
103 | 116 |
end |
104 | 117 | |
118 |
def public_visibility? |
|
119 |
visibility == VISIBILITY_PUBLIC |
|
120 |
end |
|
121 | ||
105 | 122 |
def draw_relations |
106 | 123 |
r = options[:draw_relations] |
107 | 124 |
r.nil? || r == '1' |
app/models/project.rb | ||
---|---|---|
55 | 55 |
:class_name => 'IssueCustomField', |
56 | 56 |
:join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}", |
57 | 57 |
:association_foreign_key => 'custom_field_id' |
58 |
# Default Custom Query |
|
59 |
belongs_to :default_query, :class_name => 'IssueQuery' |
|
58 | 60 | |
59 | 61 |
acts_as_attachable :view_permission => :view_files, |
60 | 62 |
:edit_permission => :manage_files, |
... | ... | |
692 | 694 |
'tracker_ids', |
693 | 695 |
'issue_custom_field_ids', |
694 | 696 |
'parent_id', |
695 |
'default_version_id' |
|
697 |
'default_version_id', |
|
698 |
'default_query_id' |
|
696 | 699 | |
697 | 700 |
safe_attributes 'enabled_module_names', |
698 | 701 |
:if => lambda {|project, user| project.new_record? || user.allowed_to?(:select_project_modules, project) } |
app/views/issues/_sidebar.html.erb | ||
---|---|---|
1 | 1 |
<h3><%= l(:label_issue_plural) %></h3> |
2 | 2 | |
3 | 3 |
<ul> |
4 |
<li><%= link_to l(:label_issue_view_all), _project_issues_path(@project, :set_filter => 1) %></li> |
|
4 |
<li><%= link_to l(:label_issue_view_all), _project_issues_path(@project, :set_filter => 1, :without_default => 1) %></li>
|
|
5 | 5 |
<% if @project %> |
6 | 6 |
<li><%= link_to l(:field_summary), project_issues_report_path(@project) %></li> |
7 | 7 |
<% end %> |
app/views/projects/_form.html.erb | ||
---|---|---|
24 | 24 |
<p><%= f.select :default_version_id, project_default_version_options(@project), :include_blank => true %></p> |
25 | 25 |
<% end %> |
26 | 26 | |
27 |
<% if @project.safe_attribute?('default_query_id') && project_default_query_options(@project).present? %> |
|
28 |
<p> |
|
29 |
<%= f.select :default_query_id, project_default_query_options(@project), :include_blank => true %> |
|
30 |
<em class="info"><%=l 'text_allowed_queries_to_select' %></em> |
|
31 |
</p> |
|
32 |
<% end %> |
|
33 | ||
27 | 34 |
<%= wikitoolbar_for 'project_description' %> |
28 | 35 | |
29 | 36 |
<% @project.custom_field_values.each do |value| %> |
config/locales/en.yml | ||
---|---|---|
360 | 360 |
field_time_entries_visibility: Time logs visibility |
361 | 361 |
field_total_estimated_hours: Total estimated time |
362 | 362 |
field_default_version: Default version |
363 |
field_default_query: Default Query |
|
363 | 364 |
field_remote_ip: IP address |
364 | 365 | |
365 | 366 |
setting_app_title: Application title |
... | ... | |
988 | 989 |
label_api: API |
989 | 990 |
label_field_format_enumeration: Key/value list |
990 | 991 |
label_default_values_for_new_users: Default values for new users |
992 |
label_default_queries: |
|
993 |
for_all_projects: For all projects |
|
994 |
for_current_project: For current project |
|
991 | 995 | |
992 | 996 |
button_login: Login |
993 | 997 |
button_submit: Submit |
... | ... | |
1181 | 1185 |
description_date_from: Enter start date |
1182 | 1186 |
description_date_to: Enter end date |
1183 | 1187 |
text_repository_identifier_info: 'Only lower case letters (a-z), numbers, dashes and underscores are allowed.<br />Once saved, the identifier cannot be changed.' |
1188 |
text_allowed_queries_to_select: Public (to any users) queries only selectable |
config/locales/fr.yml | ||
---|---|---|
1201 | 1201 |
mail_body_security_notification_notify_enabled: Les notifications ont été activées pour l'adresse %{value} |
1202 | 1202 |
mail_body_security_notification_notify_disabled: Les notifications ont été désactivées pour l'adresse %{value} |
1203 | 1203 |
field_remote_ip: Adresse IP |
1204 | ||
1205 |
field_default_query: Rapport par défaut |
|
1206 |
label_default_queries: |
|
1207 |
for_all_projects: Pour tous les projets |
|
1208 |
for_current_project: Pour le projet en cours |
|
1209 |
text_allowed_queries_to_select: Seuls les rapports publics (pour tous les utilisateurs) sont sélectionnables |
config/locales/ja.yml | ||
---|---|---|
1207 | 1207 |
mail_body_security_notification_notify_disabled: メールアドレス %{value} には今後は通知が送信されません。 |
1208 | 1208 |
mail_body_settings_updated: ! '下記の設定が変更されました:' |
1209 | 1209 |
field_remote_ip: IPアドレス |
1210 | ||
1211 |
field_default_query: デフォルトクエリー |
|
1212 |
label_default_queries: |
|
1213 |
for_all_projects: 全プロジェクト向け |
|
1214 |
for_current_project: 現在プロジェクト |
|
1215 |
text_allowed_queries_to_select: 公開クエリ(すべてのユーザ)のみ選択可能 |
config/locales/ru.yml | ||
---|---|---|
1297 | 1297 |
receives notifications. |
1298 | 1298 |
mail_body_settings_updated: ! 'The following settings were changed:' |
1299 | 1299 |
field_remote_ip: IP address |
1300 | ||
1301 |
field_default_query: Выбор запроса по умолчанию |
|
1302 |
label_default_queries: |
|
1303 |
for_all_projects: Для всех проектов |
|
1304 |
for_current_project: Для текущего прооекта |
|
1305 |
text_allowed_queries_to_select: Для выбора доступны только публичные запросы (фильтры задач) |
config/locales/tr.yml | ||
---|---|---|
1203 | 1203 |
receives notifications. |
1204 | 1204 |
mail_body_settings_updated: ! 'The following settings were changed:' |
1205 | 1205 |
field_remote_ip: IP address |
1206 | ||
1207 |
field_default_query: Öntanımlı özel sorgu |
|
1208 |
label_default_queries: |
|
1209 |
for_all_projects: Tüm birimler için |
|
1210 |
for_current_project: Simdiki birim için |
|
1211 |
text_allowed_queries_to_select: Herkese açık (tüm kullanıcılar) sorgular sadece seçilebilir |
db/migrate/20160404094730_add_projects_default_query_id.rb | ||
---|---|---|
1 |
class AddProjectsDefaultQueryId < ActiveRecord::Migration |
|
2 |
def self.up |
|
3 |
unless column_exists?(:projects, :default_query_id, :integer) |
|
4 |
add_column :projects, :default_query_id, :integer, :default => nil |
|
5 |
end |
|
6 |
end |
|
7 | ||
8 |
def self.down |
|
9 |
remove_column :projects, :default_query_id |
|
10 |
end |
|
11 |
end |
test/functional/issues_controller_test.rb | ||
---|---|---|
431 | 431 |
assert_response :success |
432 | 432 |
end |
433 | 433 | |
434 |
def test_default_query_should_be_available_when_default_query_spacified |
|
435 |
project = Project.find(1) |
|
436 |
default_query = IssueQuery.create!(:name => "default_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil) |
|
437 |
project.default_query_id = default_query.id |
|
438 |
project.save! |
|
439 | ||
440 |
@request.session[:user_id] = 3 |
|
441 | ||
442 |
get :index, :project_id => 1 |
|
443 |
assert_response :success |
|
444 |
assert_select 'h2', text: default_query.name |
|
445 |
assert_select 'ul.queries a.selected', text: default_query.name |
|
446 |
end |
|
447 | ||
448 |
def test_default_query_should_be_unavailable_when_default_query_does_not_spacified |
|
449 |
project = Project.find(1) |
|
450 |
project.default_query_id = nil |
|
451 |
project.save! |
|
452 | ||
453 |
@request.session[:user_id] = 3 |
|
454 | ||
455 |
get :index, :project_id => 1 |
|
456 |
assert_response :success |
|
457 |
assert_select 'h2', text: l(:label_issue_plural) |
|
458 |
assert_select 'ul.queries a.selected', false |
|
459 |
end |
|
460 | ||
461 |
def test_default_query_should_be_unavailable_when_default_query_spacified_but_params_query_id_spacifired |
|
462 |
project = Project.find(1) |
|
463 |
default_query = IssueQuery.create!(:name => "default_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil) |
|
464 |
project.default_query_id = default_query.id |
|
465 |
project.save! |
|
466 |
other_query = IssueQuery.create!(:name => "other_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil) |
|
467 | ||
468 |
@request.session[:user_id] = 3 |
|
469 | ||
470 |
get :index, :project_id => 1, :query_id => other_query.id |
|
471 |
assert_response :success |
|
472 |
assert_select 'h2', text: other_query.name |
|
473 |
assert_select 'ul.queries a.selected', text: other_query.name |
|
474 |
end |
|
475 | ||
476 |
def test_default_query_should_be_unavailable_when_default_query_spacified_but_other_available_query_spacified_in_session |
|
477 |
project = Project.find(1) |
|
478 |
default_query = IssueQuery.create!(:name => "default_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil) |
|
479 |
project.default_query_id = default_query.id |
|
480 |
project.save! |
|
481 |
other_query = IssueQuery.create!(:name => "other_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil) |
|
482 | ||
483 |
@request.session[:user_id] = 3 |
|
484 |
@request.session[:query] = {} |
|
485 |
@request.session[:query][:id] = other_query.id |
|
486 |
@request.session[:query][:project_id] = 1 |
|
487 | ||
488 |
get :index, :project_id => 1 |
|
489 |
assert_response :success |
|
490 |
assert_select 'h2', text: other_query.name |
|
491 |
assert_select 'ul.queries a.selected', text: other_query.name |
|
492 |
end |
|
493 | ||
494 |
def test_default_query_should_be_unavailable_when_param_without_default_spacified |
|
495 |
project = Project.find(1) |
|
496 | ||
497 |
default_query = IssueQuery.create!(:name => "default_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil) |
|
498 |
project.default_query_id = default_query.id |
|
499 |
project.save! |
|
500 | ||
501 |
@request.session[:user_id] = 3 |
|
502 | ||
503 |
get :index, :project_id => 1, :without_default => 1 |
|
504 |
assert_response :success |
|
505 |
assert_select 'h2', text: l(:label_issue_plural) |
|
506 |
assert_select 'ul.queries a.selected', false |
|
507 |
end |
|
508 | ||
509 |
def test_default_query_should_be_unavailable_when_params_set_filter_and_op_and_f_spacified |
|
510 |
project = Project.find(1) |
|
511 | ||
512 |
default_query = IssueQuery.create!(:name => "default_custom_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil) |
|
513 |
project.default_query_id = default_query.id |
|
514 |
project.save! |
|
515 | ||
516 |
@request.session[:user_id] = 3 |
|
517 | ||
518 |
get :index, :project_id => 1, :set_filter => 1, :op => 'op', :f => 'f' |
|
519 |
assert_response :success |
|
520 |
assert_select 'h2', text: l(:label_issue_plural) |
|
521 |
assert_select 'ul.queries a.selected', false |
|
522 |
end |
|
523 | ||
524 |
def test_default_query_should_be_available_when_default_query_spacified_and_other_unavailable_query_spacified_in_session |
|
525 |
project = Project.find(1) |
|
526 |
default_query = IssueQuery.create!(:name => "default_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil) |
|
527 |
project.default_query_id = default_query.id |
|
528 |
project.save! |
|
529 |
other_query = IssueQuery.create!(:name => "other_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil) |
|
530 | ||
531 |
@request.session[:user_id] = 3 |
|
532 |
@request.session[:query] = {} |
|
533 |
@request.session[:query][:id] = other_query.id |
|
534 |
@request.session[:query][:project_id] = 1 |
|
535 | ||
536 |
other_query.visibility = IssueQuery::VISIBILITY_PRIVATE |
|
537 |
other_query.save! |
|
538 | ||
539 |
get :index, :project_id => 1 |
|
540 |
assert_response :success |
|
541 |
assert_select 'h2', text: default_query.name |
|
542 |
assert_select 'ul.queries a.selected', text: default_query.name |
|
543 |
end |
|
544 | ||
434 | 545 |
def test_index_should_omit_page_param_in_export_links |
435 | 546 |
get :index, :page => 2 |
436 | 547 |
assert_response :success |
test/unit/helpers/projects_helper_test.rb | ||
---|---|---|
82 | 82 |
assert_equal '', version_options_for_select([]) |
83 | 83 |
assert_equal '', version_options_for_select([], Version.find(1)) |
84 | 84 |
end |
85 | ||
86 |
def test_project_default_query_options |
|
87 |
project = Project.find(2) |
|
88 |
options = project_default_query_options(project) |
|
89 |
|
|
90 |
assert_includes options, l('label_default_queries.for_all_projects') |
|
91 |
assert_includes options, options_for_select(IssueQuery.only_public.where(:project_id => nil).collect{|q|[q.name, q.id]}) |
|
92 |
assert_includes options, l('label_default_queries.for_current_project') |
|
93 |
assert_includes options, options_for_select(project.queries.only_public.collect {|o| [o.name, o.id]}) |
|
94 |
end |
|
85 | 95 |
end |
test/unit/project_test.rb | ||
---|---|---|
1000 | 1000 |
Project.uniq.visible.to_a |
1001 | 1001 |
end |
1002 | 1002 |
end |
1003 | ||
1004 |
def test_default_query |
|
1005 |
query = IssueQuery.create!(:name => "test", :user_id => 1, :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => @project) |
|
1006 |
project = Project.find(1) |
|
1007 |
project.default_query_id = query.id |
|
1008 |
project.save! |
|
1009 | ||
1010 |
assert_equal query, project.default_query |
|
1011 |
end |
|
1003 | 1012 |
end |
test/unit/query_test.rb | ||
---|---|---|
999 | 999 |
end |
1000 | 1000 |
end |
1001 | 1001 | |
1002 |
def test_available_query_should_return_true_when_public_query_existed_on_project |
|
1003 |
project = Project.find(1) |
|
1004 |
IssueQuery.only_public.destroy_all |
|
1005 |
public_issue_query_on_project = IssueQuery.create!(:name => "q", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => project) |
|
1006 |
public_issue_query_nil_project = IssueQuery.create!(:name => "q", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil) |
|
1007 |
assert IssueQuery.available_query?(project.id, public_issue_query_on_project.id) |
|
1008 |
assert IssueQuery.available_query?(project.id, public_issue_query_nil_project.id) |
|
1009 |
end |
|
1010 | ||
1011 |
def test_available_query_should_return_false_when_public_query_does_not_existed_on_project |
|
1012 |
project = Project.find(1) |
|
1013 |
IssueQuery.only_public.destroy_all |
|
1014 |
private_issue_query_on_project = IssueQuery.create!(:name => "q", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PRIVATE, :project => project) |
|
1015 |
public_issue_query_on_other = IssueQuery.create!(:name => "q", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => Project.find(2)) |
|
1016 |
assert_equal false, IssueQuery.available_query?(project.id, private_issue_query_on_project.id) |
|
1017 |
assert_equal false, IssueQuery.available_query?(project.id, public_issue_query_on_other.id) |
|
1018 |
end |
|
1019 | ||
1002 | 1020 |
def test_default_columns |
1003 | 1021 |
q = IssueQuery.new |
1004 | 1022 |
assert q.columns.any? |
... | ... | |
1484 | 1502 |
assert_nil IssueQuery.visible(User.find(1)).find_by_id(q.id) |
1485 | 1503 |
end |
1486 | 1504 | |
1505 |
def test_project_default_query_should_clear_when_default_query_chenged_public_to_other |
|
1506 |
q = IssueQuery.create!(:name => 'DefaultQuery', :visibility => IssueQuery::VISIBILITY_PUBLIC, :user => User.find(7)) |
|
1507 |
projects = [Project.find(1), Project.find(2)] |
|
1508 |
projects.each { |p| p.update_attributes!(:default_query_id => q.id) } |
|
1509 | ||
1510 |
q.update_attributes!(:visibility => IssueQuery::VISIBILITY_PRIVATE) |
|
1511 |
projects.each { |p| assert_nil p.reload.default_query } |
|
1512 | ||
1513 |
q.update_attributes!(:visibility => IssueQuery::VISIBILITY_PUBLIC) |
|
1514 |
projects.each do |p| |
|
1515 |
p.update_attributes!(:default_query_id => q.id) |
|
1516 |
assert_equal q, p.default_query |
|
1517 |
end |
|
1518 | ||
1519 |
q.update_attributes!(:visibility => IssueQuery::VISIBILITY_ROLES, :role_ids => [1, 2]) |
|
1520 |
projects.each { |p| assert_nil p.reload.default_query } |
|
1521 |
end |
|
1522 | ||
1523 |
def test_project_default_query_should_clear_when_destroied_default_query |
|
1524 |
q = IssueQuery.create!(:name => 'DefaultQuery', :visibility => IssueQuery::VISIBILITY_PUBLIC, :user => User.find(7)) |
|
1525 |
projects = [Project.find(1), Project.find(2)] |
|
1526 |
projects.each { |p| p.update_attributes!(:default_query_id => q.id) } |
|
1527 |
|
|
1528 |
q.destroy |
|
1529 | ||
1530 |
projects.each { |p| assert_nil p.reload.default_query } |
|
1531 |
end |
|
1532 | ||
1487 | 1533 |
test "#available_filters should include users of visible projects in cross-project view" do |
1488 | 1534 |
users = IssueQuery.new.available_filters["assigned_to_id"] |
1489 | 1535 |
assert_not_nil users |