Project

General

Profile

Feature #7360 » default_custom_trunk_r17417.patch

Mizuki ISHIKAWA, 2018-06-26 09:46

View differences:

app/controllers/issues_controller.rb
23 23
  before_action :authorize, :except => [:index, :new, :create]
24 24
  before_action :find_optional_project, :only => [:index, :new, :create]
25 25
  before_action :build_new_issue_from_params, :only => [:new, :create]
26
  before_action :with_default_query, only: [:index]
26 27
  accept_rss_auth :index, :show
27 28
  accept_api_auth :index, :show, :create, :update, :destroy
28 29

  
......
414 415

  
415 416
  private
416 417

  
418
  def with_default_query
419
    return if params[:query_id].present?
420
    return if api_request?
421
    return if  params[:set_filter] && params.key?(:op) && params.key?(:f)
422
    params[:set_filter] = 1 and return if params[:without_default].present?
423
    apply_default_query! and return if params[:set_filter] && [:op, :f].all? {|k| !params.key?(k) }
424
    if session[:issue_query]
425
      query_id, project_id = session[:issue_query].values_at(:id, :project_id)
426
      unless query_id && (project_id == @project.id) && IssueQuery.available_query?(@project.id, query_id)
427
        apply_default_query!
428
      end
429
    else
430
      apply_default_query!
431
    end
432
  end
433

  
434
  def apply_default_query!
435
    if default_query = find_default_query
436
      params[:query_id] = default_query.id
437
    end
438
  end
439

  
417 440
  def retrieve_previous_and_next_issue_ids
418 441
    if params[:prev_issue_id].present? || params[:next_issue_id].present?
419 442
      @prev_issue_id = params[:prev_issue_id].presence.try(:to_i)
app/helpers/projects_helper.rb
95 95
    principals_options_for_select(assignable_users, project.default_assigned_to)
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
    IssueQuery.only_public.where(project: project).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
335 335
        @query.project = @project
336 336
      end
337 337
      @query
338
    else
339
      @query = find_default_query
338 340
    end
339 341
  end
340 342

  
343
  private
344

  
345
  def find_default_query
346
    @project.default_query if @project.is_a?(Project)
347
  end
348

  
341 349
  # Returns the query definition as hidden field tags
342 350
  def query_as_hidden_field_tags(query)
343 351
    tags = hidden_field_tag("set_filter", "1", :id => nil)
app/models/issue_query.rb
50 50
    QueryColumn.new(:last_notes, :caption => :label_last_notes, :inline => false)
51 51
  ]
52 52

  
53
  has_many :projects, :foreign_key => 'default_query_id'
54
  after_update { self.projects.clear unless self.public_visibility? }
55
  after_destroy { self.projects.clear }
56

  
57
  scope :only_public, -> {
58
    where(:visibility => VISIBILITY_PUBLIC)
59
  }
60

  
61
  def self.available_query?(project_id, query_id)
62
    self.only_public
63
        .where('project_id is null or project_id = ?', project_id)
64
        .where(id: query_id).exists?
65
  end
66

  
53 67
  def initialize(attributes=nil, *args)
54 68
    super attributes
55 69
    self.filters ||= { 'status_id' => {:operator => "o", :values => [""]} }
56 70
  end
57 71

  
72
  def public_visibility?
73
    visibility == VISIBILITY_PUBLIC
74
  end
75

  
58 76
  def draw_relations
59 77
    r = options[:draw_relations]
60 78
    r.nil? || r == '1'
app/models/project.rb
56 56
                          :class_name => 'IssueCustomField',
57 57
                          :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}",
58 58
                          :association_foreign_key => 'custom_field_id'
59
  # Default Custom Query
60
  belongs_to :default_query, :class_name => 'IssueQuery'
59 61

  
60 62
  acts_as_attachable :view_permission => :view_files,
61 63
                     :edit_permission => :manage_files,
......
756 758
    'issue_custom_field_ids',
757 759
    'parent_id',
758 760
    'default_version_id',
759
    'default_assigned_to_id'
761
    'default_assigned_to_id',
762
    'default_query_id'
760 763

  
761 764
  safe_attributes 'enabled_module_names',
762 765
    :if => lambda {|project, user|
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
23 23
<p><%= f.check_box :inherit_members %></p>
24 24
<% end %>
25 25

  
26
<% if @project.safe_attribute?('default_query_id') && project_default_query_options(@project).present? %>
27
  <p>
28
    <%= f.select :default_query_id, project_default_query_options(@project), :include_blank => true %>
29
    <em class="info"><%=l 'text_allowed_queries_to_select' %></em>
30
  </p>
31
<% end %>
32

  
26 33
<%= wikitoolbar_for 'project_description' %>
27 34

  
28 35
<% @project.custom_field_values.each do |value| %>
app/views/projects/copy.html.erb
27 27

  
28 28
<%= submit_tag l(:button_copy) %>
29 29
<% end %>
30

  
31
<%= javascript_tag do %>
32
  $('input[value="queries"]').change(function() {
33
    if ($(this).prop('checked')){
34
      $('select#project_default_query_id optgroup[label="For current project"] option').prop("disabled", false);
35
    }else{
36
      $('select#project_default_query_id optgroup[label="For current project"] option').prop("disabled", true);
37
    }
38
  });
39
<% end %>
config/locales/en.yml
371 371
  field_time_entries_visibility: Time logs visibility
372 372
  field_total_estimated_hours: Total estimated time
373 373
  field_default_version: Default version
374
  field_default_query: Default Query
374 375
  field_remote_ip: IP address
375 376
  field_textarea_font: Font used for text areas
376 377
  field_updated_by: Updated by
......
1026 1027
  label_font_monospace: Monospaced font
1027 1028
  label_font_proportional: Proportional font
1028 1029
  label_last_notes: Last notes
1030
  label_default_queries:
1031
    for_all_projects: For all projects
1032
    for_current_project: For current project
1029 1033

  
1030 1034
  button_login: Login
1031 1035
  button_submit: Submit
......
1217 1221
  description_issue_category_reassign: Choose issue category
1218 1222
  description_wiki_subpages_reassign: Choose new parent page
1219 1223
  text_repository_identifier_info: 'Only lower case letters (a-z), numbers, dashes and underscores are allowed.<br />Once saved, the identifier cannot be changed.'
1224
  text_allowed_queries_to_select: Public (to any users) queries only selectable
1220 1225
  text_login_required_html: When not requiring authentication, public projects and their contents are openly available on the network. You can <a href="%{anonymous_role_path}">edit the applicable permissions</a>.
1221 1226
  label_login_required_yes: "Yes"
1222 1227
  label_login_required_no: "No, allow anonymous access to public projects"
config/locales/fr.yml
1228 1228
  mail_body_security_notification_notify_enabled: Les notifications ont été activées pour l'adresse %{value}
1229 1229
  mail_body_security_notification_notify_disabled: Les notifications ont été désactivées pour l'adresse %{value}
1230 1230
  field_remote_ip: Adresse IP
1231

  
1232
  field_default_query: Rapport par défaut
1233
  label_default_queries:
1234
    for_all_projects: Pour tous les projets
1235
    for_current_project: Pour le projet en cours
1236
  text_allowed_queries_to_select: Seuls les rapports publics (pour tous les utilisateurs) sont sélectionnables
1231 1237
  label_no_preview: Aucun aperçu disponible
1232 1238
  label_no_preview_alternative_html: Aucun aperçu disponible. Veuillez %{link} le fichier.
1233 1239
  label_no_preview_download: télécharger
config/locales/ru.yml
1284 1284
    получает уведомления.
1285 1285
  mail_body_settings_updated: ! 'Следующие настройки были изменены:'
1286 1286
  field_remote_ip: IP адрес
1287

  
1288
  field_default_query: Выбор запроса по умолчанию
1289
  label_default_queries:
1290
    for_all_projects: Для всех проектов
1291
    for_current_project: Для текущего прооекта
1292
  text_allowed_queries_to_select: Для выбора доступны только публичные запросы (фильтры задач)
1287 1293
  label_wiki_page_new: Новая wiki-страница
1288 1294
  label_relations: Связи
1289 1295
  button_filter: Фильтр
config/locales/tr.yml
1192 1192
    receives notifications.
1193 1193
  mail_body_settings_updated: ! 'The following settings were changed:'
1194 1194
  field_remote_ip: IP address
1195

  
1196
  field_default_query: Öntanımlı özel sorgu
1197
  label_default_queries:
1198
    for_all_projects: Tüm birimler için
1199
    for_current_project: Simdiki birim için
1200
  text_allowed_queries_to_select: Herkese açık (tüm kullanıcılar) sorgular sadece seçilebilir
1201

  
1195 1202
  label_wiki_page_new: New wiki page
1196 1203
  label_relations: Relations
1197 1204
  button_filter: Filter
db/migrate/20160404094730_add_projects_default_query_id.rb
1
class AddProjectsDefaultQueryId < ActiveRecord::Migration[4.2]
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
508 508
    assert_response :success
509 509
  end
510 510

  
511
  def test_default_query_should_be_available_when_default_query_spacified
512
    project = Project.find(1)
513
    default_query = IssueQuery.create!(:name => "default_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
514
    project.default_query_id = default_query.id
515
    project.save!
516

  
517
    @request.session[:user_id] = 3
518

  
519
    get :index, :params => {
520
      :project_id => 1
521
    }
522
    assert_response :success
523
    assert_select 'h2', text: default_query.name
524
    assert_select 'ul.queries a.selected', text: default_query.name
525
  end
526

  
527
  def test_default_query_should_be_unavailable_when_default_query_does_not_spacified
528
    project = Project.find(1)
529
    project.default_query_id = nil
530
    project.save!
531

  
532
    @request.session[:user_id] = 3
533

  
534
    get :index, :params => {
535
      :project_id => 1
536
    }
537
    assert_response :success
538
    assert_select 'h2', text: l(:label_issue_plural)
539
    assert_select 'ul.queries a.selected', false
540
  end
541

  
542
  def test_default_query_should_be_unavailable_when_default_query_spacified_but_params_query_id_spacifired
543
    project = Project.find(1)
544
    default_query = IssueQuery.create!(:name => "default_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
545
    project.default_query_id = default_query.id
546
    project.save!
547
    other_query = IssueQuery.create!(:name => "other_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
548

  
549
    @request.session[:user_id] = 3
550

  
551
    get :index, :params => {
552
      :project_id => 1, :query_id => other_query.id
553
    }
554
    assert_response :success
555
    assert_select 'h2', text: other_query.name
556
    assert_select 'ul.queries a.selected', text: other_query.name
557
  end
558

  
559
  def test_default_query_should_be_unavailable_when_default_query_spacified_but_other_available_query_spacified_in_session
560
    project = Project.find(1)
561
    default_query = IssueQuery.create!(:name => "default_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
562
    project.default_query_id = default_query.id
563
    project.save!
564
    other_query = IssueQuery.create!(:name => "other_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
565

  
566
    @request.session[:user_id] = 3
567
    @request.session[:issue_query] = {}
568
    @request.session[:issue_query][:id] = other_query.id
569
    @request.session[:issue_query][:project_id] = 1
570

  
571
    get :index, :params => {
572
      :project_id => 1
573
    }
574
    assert_response :success
575
    assert_select 'h2', text: other_query.name
576
    assert_select 'ul.queries a.selected', text: other_query.name
577
  end
578

  
579
  def test_default_query_should_be_unavailable_when_param_without_default_spacified
580
    project = Project.find(1)
581

  
582
    default_query = IssueQuery.create!(:name => "default_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
583
    project.default_query_id = default_query.id
584
    project.save!
585

  
586
    @request.session[:user_id] = 3
587

  
588
    get :index, :params => {
589
      :project_id => 1, :without_default => 1
590
    }
591
    assert_response :success
592
    assert_select 'h2', text: l(:label_issue_plural)
593
    assert_select 'ul.queries a.selected', false
594
  end
595

  
596
  def test_default_query_should_be_unavailable_when_params_set_filter_and_op_and_f_spacified
597
    project = Project.find(1)
598

  
599
    default_query = IssueQuery.create!(:name => "default_custom_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
600
    project.default_query_id = default_query.id
601
    project.save!
602

  
603
    @request.session[:user_id] = 3
604

  
605
    get :index, :params => {
606
      :project_id => 1, :set_filter => 1,
607
      :f => ['start_date'],
608
      :op => {
609
        :start_date => '='
610
      }
611
    }
612
    assert_response :success
613
    assert_select 'h2', text: l(:label_issue_plural)
614
    assert_select 'ul.queries a.selected', false
615
  end
616

  
617
  def test_default_query_should_be_available_when_default_query_spacified_and_other_unavailable_query_spacified_in_session
618
    project = Project.find(1)
619
    default_query = IssueQuery.create!(:name => "default_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
620
    project.default_query_id = default_query.id
621
    project.save!
622
    other_query = IssueQuery.create!(:name => "other_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
623

  
624
    @request.session[:user_id] = 3
625
    @request.session[:issue_query] = {}
626
    @request.session[:issue_query][:id] = other_query.id
627
    @request.session[:issue_query][:project_id] = 1
628

  
629
    other_query.visibility = IssueQuery::VISIBILITY_PRIVATE
630
    other_query.save!
631

  
632
    get :index, :params => {
633
      :project_id => 1
634
    }
635
    assert_response :success
636
    assert_select 'h2', text: default_query.name
637
    assert_select 'ul.queries a.selected', text: default_query.name
638
  end
639

  
511 640
  def test_index_should_omit_page_param_in_export_links
512 641
    get :index, :params => {
513 642
        :page => 2
test/helpers/projects_helper_test.rb
75 75
    assert_equal '', version_options_for_select([])
76 76
    assert_equal '', version_options_for_select([], Version.find(1))
77 77
  end
78

  
79
  def test_project_default_query_options
80
    project = Project.find(2)
81
    options = project_default_query_options(project)
82
    assert_includes options, l('label_default_queries.for_all_projects')
83

  
84
    assert_includes options, options_for_select(IssueQuery.only_public.where(:project_id => nil).collect{|q|[q.name, q.id]})
85
    assert_includes options, l('label_default_queries.for_current_project')
86
    assert_includes options, options_for_select(IssueQuery.only_public.where(project: project).collect {|o| [o.name, o.id]})
87
  end
78 88
end
test/unit/project_test.rb
1028 1028
      Project.distinct.visible.to_a
1029 1029
    end
1030 1030
  end
1031

  
1032
  def test_default_query
1033
    query = IssueQuery.create!(:name => "test", :user_id => 1, :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => @project)
1034
    project = Project.find(1)
1035
    project.default_query_id = query.id
1036
    project.save!
1037

  
1038
    assert_equal query, project.default_query
1039
  end
1031 1040
end
test/unit/query_test.rb
1285 1285
    end
1286 1286
  end
1287 1287

  
1288
  def test_available_query_should_return_true_when_public_query_existed_on_project
1289
    project = Project.find(1)
1290
    IssueQuery.only_public.destroy_all
1291
    public_issue_query_on_project = IssueQuery.create!(:name => "q", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => project)
1292
    public_issue_query_nil_project = IssueQuery.create!(:name => "q", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
1293
    assert IssueQuery.available_query?(project.id, public_issue_query_on_project.id)
1294
    assert IssueQuery.available_query?(project.id, public_issue_query_nil_project.id)
1295
  end
1296

  
1297
  def test_available_query_should_return_false_when_public_query_does_not_existed_on_project
1298
    project = Project.find(1)
1299
    IssueQuery.only_public.destroy_all
1300
    private_issue_query_on_project = IssueQuery.create!(:name => "q", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PRIVATE, :project => project)
1301
    public_issue_query_on_other = IssueQuery.create!(:name => "q", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => Project.find(2))
1302
    assert_equal false, IssueQuery.available_query?(project.id, private_issue_query_on_project.id)
1303
    assert_equal false, IssueQuery.available_query?(project.id, public_issue_query_on_other.id)
1304
  end
1305

  
1288 1306
  def test_default_columns
1289 1307
    q = IssueQuery.new
1290 1308
    assert q.columns.any?
......
1835 1853
    assert_nil IssueQuery.visible(User.find(1)).find_by_id(q.id)
1836 1854
  end
1837 1855

  
1856
  def test_project_default_query_should_clear_when_default_query_chenged_public_to_other
1857
    q = IssueQuery.create!(:name => 'DefaultQuery', :visibility => IssueQuery::VISIBILITY_PUBLIC, :user => User.find(7))
1858
    projects = [Project.find(1), Project.find(2)]
1859
    projects.each { |p| p.update_attributes!(:default_query_id => q.id) }
1860

  
1861
    q.update_attributes!(:visibility => IssueQuery::VISIBILITY_PRIVATE)
1862
    projects.each { |p| assert_nil p.reload.default_query }
1863

  
1864
    q.update_attributes!(:visibility => IssueQuery::VISIBILITY_PUBLIC)
1865
    projects.each do |p|
1866
      p.update_attributes!(:default_query_id => q.id)
1867
      assert_equal q, p.default_query
1868
    end
1869

  
1870
    q.update_attributes!(:visibility => IssueQuery::VISIBILITY_ROLES, :role_ids => [1, 2])
1871
    projects.each { |p| assert_nil p.reload.default_query }
1872
  end
1873

  
1874
  def test_project_default_query_should_clear_when_destroied_default_query
1875
    q = IssueQuery.create!(:name => 'DefaultQuery', :visibility => IssueQuery::VISIBILITY_PUBLIC, :user => User.find(7))
1876
    projects = [Project.find(1), Project.find(2)]
1877
    projects.each { |p| p.update_attributes!(:default_query_id => q.id) }
1878

  
1879
    q.destroy
1880

  
1881
    projects.each { |p| assert_nil p.reload.default_query }
1882
  end
1883

  
1838 1884
  test "#available_filters should include users of visible projects in cross-project view" do
1839 1885
    users = IssueQuery.new.available_filters["assigned_to_id"]
1840 1886
    assert_not_nil users
(5-5/14)