diff --git app/controllers/issues_controller.rb app/controllers/issues_controller.rb
index 5199954..544de34 100644
--- app/controllers/issues_controller.rb
+++ app/controllers/issues_controller.rb
@@ -24,6 +24,7 @@ class IssuesController < ApplicationController
before_filter :authorize, :except => [:index, :new, :create]
before_filter :find_optional_project, :only => [:index, :new, :create]
before_filter :build_new_issue_from_params, :only => [:new, :create]
+ before_filter :with_default_query, only: [:index]
accept_rss_auth :index, :show
accept_api_auth :index, :show, :create, :update, :destroy
@@ -353,6 +354,28 @@ class IssuesController < ApplicationController
private
+ def with_default_query
+ return if params[:query_id].present?
+ return if api_request?
+ return if params[:set_filter] && params.key?(:op) && params.key?(:f)
+ params[:set_filter] = 1 and return if params[:without_default].present?
+ apply_default_query! and return if params[:set_filter] && [:op, :f].all? {|k| !params.key?(k) }
+ if session[:query]
+ query_id, project_id = session[:query].values_at(:id, :project_id)
+ unless query_id && (project_id == @project.id) && IssueQuery.available_query?(@project.id, query_id)
+ apply_default_query!
+ end
+ else
+ apply_default_query!
+ end
+ end
+
+ def apply_default_query!
+ if default_query = find_default_query
+ params[:query_id] = default_query.id
+ end
+ end
+
def retrieve_previous_and_next_issue_ids
if params[:prev_issue_id].present? || params[:next_issue_id].present?
@prev_issue_id = params[:prev_issue_id].presence.try(:to_i)
diff --git app/helpers/projects_helper.rb app/helpers/projects_helper.rb
index 6e409f2..c6886cc 100644
--- app/helpers/projects_helper.rb
+++ app/helpers/projects_helper.rb
@@ -95,6 +95,17 @@ module ProjectsHelper
version_options_for_select(versions, project.default_version)
end
+ def project_default_query_options(project)
+ grouped = Hash.new {|h,k| h[k] = []}
+ IssueQuery.only_public.where(project_id: nil).each do |query|
+ grouped[l('label_default_queries.for_all_projects')] << [query.name, query.id]
+ end
+ project.queries.only_public.each do |query|
+ grouped[l('label_default_queries.for_current_project')] << [query.name, query.id]
+ end
+ grouped_options_for_select(grouped, project.default_query_id)
+ end
+
def format_version_sharing(sharing)
sharing = 'none' unless Version::VERSION_SHARINGS.include?(sharing)
l("label_version_sharing_#{sharing}")
diff --git app/helpers/queries_helper.rb app/helpers/queries_helper.rb
index 4b71d08..921c9e7 100644
--- app/helpers/queries_helper.rb
+++ app/helpers/queries_helper.rb
@@ -241,9 +241,17 @@ module QueriesHelper
@query.project = @project
end
@query
+ else
+ @query = find_default_query
end
end
+ private
+
+ def find_default_query
+ @project.default_query if @project.is_a?(Project)
+ end
+
# Returns the query definition as hidden field tags
def query_as_hidden_field_tags(query)
tags = hidden_field_tag("set_filter", "1", :id => nil)
diff --git app/models/issue_query.rb app/models/issue_query.rb
index c97de0a..e696750 100644
--- app/models/issue_query.rb
+++ app/models/issue_query.rb
@@ -16,7 +16,6 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class IssueQuery < Query
-
self.queried_class = Issue
self.available_columns = [
@@ -46,6 +45,10 @@ class IssueQuery < Query
QueryColumn.new(:description, :inline => false)
]
+ has_many :projects, :foreign_key => 'default_query_id'
+ after_update { self.projects.clear unless self.public_visibility? }
+ after_destroy { self.projects.clear }
+
scope :visible, lambda {|*args|
user = args.shift || User.current
base = Project.allowed_to_condition(user, :view_issues, *args)
@@ -71,6 +74,16 @@ class IssueQuery < Query
end
}
+ scope :only_public, -> {
+ where(:visibility => VISIBILITY_PUBLIC)
+ }
+
+ def self.available_query?(project_id, query_id)
+ self.only_public
+ .where('project_id is null or project_id = ?', project_id)
+ .where(id: query_id).exists?
+ end
+
def initialize(attributes=nil, *args)
super attributes
self.filters ||= { 'status_id' => {:operator => "o", :values => [""]} }
@@ -102,6 +115,10 @@ class IssueQuery < Query
!is_private?
end
+ def public_visibility?
+ visibility == VISIBILITY_PUBLIC
+ end
+
def draw_relations
r = options[:draw_relations]
r.nil? || r == '1'
diff --git app/models/project.rb app/models/project.rb
index 2e3a106..a3c819c 100644
--- app/models/project.rb
+++ app/models/project.rb
@@ -55,6 +55,8 @@ class Project < ActiveRecord::Base
:class_name => 'IssueCustomField',
:join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}",
:association_foreign_key => 'custom_field_id'
+ # Default Custom Query
+ belongs_to :default_query, :class_name => 'IssueQuery'
acts_as_attachable :view_permission => :view_files,
:edit_permission => :manage_files,
@@ -692,7 +694,8 @@ class Project < ActiveRecord::Base
'tracker_ids',
'issue_custom_field_ids',
'parent_id',
- 'default_version_id'
+ 'default_version_id',
+ 'default_query_id'
safe_attributes 'enabled_module_names',
:if => lambda {|project, user| project.new_record? || user.allowed_to?(:select_project_modules, project) }
diff --git app/views/issues/_sidebar.html.erb app/views/issues/_sidebar.html.erb
index df9f43b..53279f8 100644
--- app/views/issues/_sidebar.html.erb
+++ app/views/issues/_sidebar.html.erb
@@ -1,7 +1,7 @@
<%= l(:label_issue_plural) %>
-- <%= link_to l(:label_issue_view_all), _project_issues_path(@project, :set_filter => 1) %>
+- <%= link_to l(:label_issue_view_all), _project_issues_path(@project, :set_filter => 1, :without_default => 1) %>
<% if @project %>
- <%= link_to l(:field_summary), project_issues_report_path(@project) %>
<% end %>
diff --git app/views/projects/_form.html.erb app/views/projects/_form.html.erb
index b75ce82..361552f 100644
--- app/views/projects/_form.html.erb
+++ app/views/projects/_form.html.erb
@@ -24,6 +24,13 @@
<%= f.select :default_version_id, project_default_version_options(@project), :include_blank => true %>
<% end %>
+<% if @project.safe_attribute?('default_query_id') && project_default_query_options(@project).present? %>
+
+ <%= f.select :default_query_id, project_default_query_options(@project), :include_blank => true %>
+ <%=l 'text_allowed_queries_to_select' %>
+
+<% end %>
+
<%= wikitoolbar_for 'project_description' %>
<% @project.custom_field_values.each do |value| %>
diff --git config/locales/en.yml config/locales/en.yml
index c198851..14001bd 100644
--- config/locales/en.yml
+++ config/locales/en.yml
@@ -360,6 +360,7 @@ en:
field_time_entries_visibility: Time logs visibility
field_total_estimated_hours: Total estimated time
field_default_version: Default version
+ field_default_query: Default Query
field_remote_ip: IP address
setting_app_title: Application title
@@ -988,6 +989,9 @@ en:
label_api: API
label_field_format_enumeration: Key/value list
label_default_values_for_new_users: Default values for new users
+ label_default_queries:
+ for_all_projects: For all projects
+ for_current_project: For current project
button_login: Login
button_submit: Submit
@@ -1181,3 +1185,4 @@ en:
description_date_from: Enter start date
description_date_to: Enter end date
text_repository_identifier_info: 'Only lower case letters (a-z), numbers, dashes and underscores are allowed.
Once saved, the identifier cannot be changed.'
+ text_allowed_queries_to_select: Public (to any users) queries only selectable
diff --git config/locales/fr.yml config/locales/fr.yml
index 1bb7bd4..1c46de3 100644
--- config/locales/fr.yml
+++ config/locales/fr.yml
@@ -1201,3 +1201,9 @@ fr:
mail_body_security_notification_notify_enabled: Les notifications ont été activées pour l'adresse %{value}
mail_body_security_notification_notify_disabled: Les notifications ont été désactivées pour l'adresse %{value}
field_remote_ip: Adresse IP
+
+ field_default_query: Rapport par défaut
+ label_default_queries:
+ for_all_projects: Pour tous les projets
+ for_current_project: Pour le projet en cours
+ text_allowed_queries_to_select: Seuls les rapports publics (pour tous les utilisateurs) sont sélectionnables
diff --git config/locales/ja.yml config/locales/ja.yml
index 4a98032..8ddd5af 100644
--- config/locales/ja.yml
+++ config/locales/ja.yml
@@ -1207,3 +1207,9 @@ ja:
mail_body_security_notification_notify_disabled: メールアドレス %{value} には今後は通知が送信されません。
mail_body_settings_updated: ! '下記の設定が変更されました:'
field_remote_ip: IPアドレス
+
+ field_default_query: デフォルトクエリー
+ label_default_queries:
+ for_all_projects: 全プロジェクト向け
+ for_current_project: 現在プロジェクト
+ text_allowed_queries_to_select: 公開クエリ(すべてのユーザ)のみ選択可能
diff --git config/locales/ru.yml config/locales/ru.yml
index 3c2506b..3950ea9 100644
--- config/locales/ru.yml
+++ config/locales/ru.yml
@@ -1297,3 +1297,9 @@ ru:
receives notifications.
mail_body_settings_updated: ! 'The following settings were changed:'
field_remote_ip: IP address
+
+ field_default_query: Выбор запроса по умолчанию
+ label_default_queries:
+ for_all_projects: Для всех проектов
+ for_current_project: Для текущего прооекта
+ text_allowed_queries_to_select: Для выбора доступны только публичные запросы (фильтры задач)
diff --git config/locales/tr.yml config/locales/tr.yml
index 4917bbf..b469448 100644
--- config/locales/tr.yml
+++ config/locales/tr.yml
@@ -1203,3 +1203,9 @@ tr:
receives notifications.
mail_body_settings_updated: ! 'The following settings were changed:'
field_remote_ip: IP address
+
+ field_default_query: Öntanımlı özel sorgu
+ label_default_queries:
+ for_all_projects: Tüm birimler için
+ for_current_project: Simdiki birim için
+ text_allowed_queries_to_select: Herkese açık (tüm kullanıcılar) sorgular sadece seçilebilir
diff --git db/migrate/20160404094730_add_projects_default_query_id.rb db/migrate/20160404094730_add_projects_default_query_id.rb
new file mode 100644
index 0000000..2e78339
--- /dev/null
+++ db/migrate/20160404094730_add_projects_default_query_id.rb
@@ -0,0 +1,11 @@
+class AddProjectsDefaultQueryId < ActiveRecord::Migration
+ def self.up
+ unless column_exists?(:projects, :default_query_id, :integer)
+ add_column :projects, :default_query_id, :integer, :default => nil
+ end
+ end
+
+ def self.down
+ remove_column :projects, :default_query_id
+ end
+end
diff --git test/functional/issues_controller_test.rb test/functional/issues_controller_test.rb
index 3021d0f..27a15ad 100644
--- test/functional/issues_controller_test.rb
+++ test/functional/issues_controller_test.rb
@@ -431,6 +431,117 @@ class IssuesControllerTest < ActionController::TestCase
assert_response :success
end
+ def test_default_query_should_be_available_when_default_query_spacified
+ project = Project.find(1)
+ default_query = IssueQuery.create!(:name => "default_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
+ project.default_query_id = default_query.id
+ project.save!
+
+ @request.session[:user_id] = 3
+
+ get :index, :project_id => 1
+ assert_response :success
+ assert_select 'h2', text: default_query.name
+ assert_select 'ul.queries a.selected', text: default_query.name
+ end
+
+ def test_default_query_should_be_unavailable_when_default_query_does_not_spacified
+ project = Project.find(1)
+ project.default_query_id = nil
+ project.save!
+
+ @request.session[:user_id] = 3
+
+ get :index, :project_id => 1
+ assert_response :success
+ assert_select 'h2', text: l(:label_issue_plural)
+ assert_select 'ul.queries a.selected', false
+ end
+
+ def test_default_query_should_be_unavailable_when_default_query_spacified_but_params_query_id_spacifired
+ project = Project.find(1)
+ default_query = IssueQuery.create!(:name => "default_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
+ project.default_query_id = default_query.id
+ project.save!
+ other_query = IssueQuery.create!(:name => "other_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
+
+ @request.session[:user_id] = 3
+
+ get :index, :project_id => 1, :query_id => other_query.id
+ assert_response :success
+ assert_select 'h2', text: other_query.name
+ assert_select 'ul.queries a.selected', text: other_query.name
+ end
+
+ def test_default_query_should_be_unavailable_when_default_query_spacified_but_other_available_query_spacified_in_session
+ project = Project.find(1)
+ default_query = IssueQuery.create!(:name => "default_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
+ project.default_query_id = default_query.id
+ project.save!
+ other_query = IssueQuery.create!(:name => "other_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
+
+ @request.session[:user_id] = 3
+ @request.session[:query] = {}
+ @request.session[:query][:id] = other_query.id
+ @request.session[:query][:project_id] = 1
+
+ get :index, :project_id => 1
+ assert_response :success
+ assert_select 'h2', text: other_query.name
+ assert_select 'ul.queries a.selected', text: other_query.name
+ end
+
+ def test_default_query_should_be_unavailable_when_param_without_default_spacified
+ project = Project.find(1)
+
+ default_query = IssueQuery.create!(:name => "default_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
+ project.default_query_id = default_query.id
+ project.save!
+
+ @request.session[:user_id] = 3
+
+ get :index, :project_id => 1, :without_default => 1
+ assert_response :success
+ assert_select 'h2', text: l(:label_issue_plural)
+ assert_select 'ul.queries a.selected', false
+ end
+
+ def test_default_query_should_be_unavailable_when_params_set_filter_and_op_and_f_spacified
+ project = Project.find(1)
+
+ default_query = IssueQuery.create!(:name => "default_custom_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
+ project.default_query_id = default_query.id
+ project.save!
+
+ @request.session[:user_id] = 3
+
+ get :index, :project_id => 1, :set_filter => 1, :op => 'op', :f => 'f'
+ assert_response :success
+ assert_select 'h2', text: l(:label_issue_plural)
+ assert_select 'ul.queries a.selected', false
+ end
+
+ def test_default_query_should_be_available_when_default_query_spacified_and_other_unavailable_query_spacified_in_session
+ project = Project.find(1)
+ default_query = IssueQuery.create!(:name => "default_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
+ project.default_query_id = default_query.id
+ project.save!
+ other_query = IssueQuery.create!(:name => "other_query", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
+
+ @request.session[:user_id] = 3
+ @request.session[:query] = {}
+ @request.session[:query][:id] = other_query.id
+ @request.session[:query][:project_id] = 1
+
+ other_query.visibility = IssueQuery::VISIBILITY_PRIVATE
+ other_query.save!
+
+ get :index, :project_id => 1
+ assert_response :success
+ assert_select 'h2', text: default_query.name
+ assert_select 'ul.queries a.selected', text: default_query.name
+ end
+
def test_index_should_omit_page_param_in_export_links
get :index, :page => 2
assert_response :success
diff --git test/unit/helpers/projects_helper_test.rb test/unit/helpers/projects_helper_test.rb
index 8a06a24..60e6803 100644
--- test/unit/helpers/projects_helper_test.rb
+++ test/unit/helpers/projects_helper_test.rb
@@ -82,4 +82,14 @@ class ProjectsHelperTest < ActionView::TestCase
assert_equal '', version_options_for_select([])
assert_equal '', version_options_for_select([], Version.find(1))
end
+
+ def test_project_default_query_options
+ project = Project.find(2)
+ options = project_default_query_options(project)
+
+ assert_includes options, l('label_default_queries.for_all_projects')
+ assert_includes options, options_for_select(IssueQuery.only_public.where(:project_id => nil).collect{|q|[q.name, q.id]})
+ assert_includes options, l('label_default_queries.for_current_project')
+ assert_includes options, options_for_select(project.queries.only_public.collect {|o| [o.name, o.id]})
+ end
end
diff --git test/unit/project_test.rb test/unit/project_test.rb
index 5c305f7..faafb9f 100644
--- test/unit/project_test.rb
+++ test/unit/project_test.rb
@@ -1000,4 +1000,13 @@ class ProjectTest < ActiveSupport::TestCase
Project.uniq.visible.to_a
end
end
+
+ def test_default_query
+ query = IssueQuery.create!(:name => "test", :user_id => 1, :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => @project)
+ project = Project.find(1)
+ project.default_query_id = query.id
+ project.save!
+
+ assert_equal query, project.default_query
+ end
end
diff --git test/unit/query_test.rb test/unit/query_test.rb
index 4336918..105000c 100644
--- test/unit/query_test.rb
+++ test/unit/query_test.rb
@@ -999,6 +999,24 @@ class QueryTest < ActiveSupport::TestCase
end
end
+ def test_available_query_should_return_true_when_public_query_existed_on_project
+ project = Project.find(1)
+ IssueQuery.only_public.destroy_all
+ public_issue_query_on_project = IssueQuery.create!(:name => "q", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => project)
+ public_issue_query_nil_project = IssueQuery.create!(:name => "q", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
+ assert IssueQuery.available_query?(project.id, public_issue_query_on_project.id)
+ assert IssueQuery.available_query?(project.id, public_issue_query_nil_project.id)
+ end
+
+ def test_available_query_should_return_false_when_public_query_does_not_existed_on_project
+ project = Project.find(1)
+ IssueQuery.only_public.destroy_all
+ private_issue_query_on_project = IssueQuery.create!(:name => "q", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PRIVATE, :project => project)
+ public_issue_query_on_other = IssueQuery.create!(:name => "q", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => Project.find(2))
+ assert_equal false, IssueQuery.available_query?(project.id, private_issue_query_on_project.id)
+ assert_equal false, IssueQuery.available_query?(project.id, public_issue_query_on_other.id)
+ end
+
def test_default_columns
q = IssueQuery.new
assert q.columns.any?
@@ -1484,6 +1502,34 @@ class QueryTest < ActiveSupport::TestCase
assert_nil IssueQuery.visible(User.find(1)).find_by_id(q.id)
end
+ def test_project_default_query_should_clear_when_default_query_chenged_public_to_other
+ q = IssueQuery.create!(:name => 'DefaultQuery', :visibility => IssueQuery::VISIBILITY_PUBLIC, :user => User.find(7))
+ projects = [Project.find(1), Project.find(2)]
+ projects.each { |p| p.update_attributes!(:default_query_id => q.id) }
+
+ q.update_attributes!(:visibility => IssueQuery::VISIBILITY_PRIVATE)
+ projects.each { |p| assert_nil p.reload.default_query }
+
+ q.update_attributes!(:visibility => IssueQuery::VISIBILITY_PUBLIC)
+ projects.each do |p|
+ p.update_attributes!(:default_query_id => q.id)
+ assert_equal q, p.default_query
+ end
+
+ q.update_attributes!(:visibility => IssueQuery::VISIBILITY_ROLES, :role_ids => [1, 2])
+ projects.each { |p| assert_nil p.reload.default_query }
+ end
+
+ def test_project_default_query_should_clear_when_destroied_default_query
+ q = IssueQuery.create!(:name => 'DefaultQuery', :visibility => IssueQuery::VISIBILITY_PUBLIC, :user => User.find(7))
+ projects = [Project.find(1), Project.find(2)]
+ projects.each { |p| p.update_attributes!(:default_query_id => q.id) }
+
+ q.destroy
+
+ projects.each { |p| assert_nil p.reload.default_query }
+ end
+
test "#available_filters should include users of visible projects in cross-project view" do
users = IssueQuery.new.available_filters["assigned_to_id"]
assert_not_nil users