Project

General

Profile

Feature #7360 » default_custom_query_trunk_r15303.patch

Takenori TAKAKI, 2016-04-07 08:42

View differences:

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
(2-2/14)