From d00ccd5dfc33077fa2648e9beb54a769ad33bc16 Mon Sep 17 00:00:00 2001 From: Marius BALTEANU Date: Mon, 6 Sep 2021 23:55:39 +0300 Subject: [PATCH] Option to set default project query at global and user level diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 36f0261f9..6ec522dd5 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -51,6 +51,7 @@ class ProjectsController < ApplicationController return end + retrieve_default_query retrieve_project_query scope = project_scope @@ -323,4 +324,19 @@ class ProjectsController < ApplicationController def retrieve_project_query retrieve_query(ProjectQuery, false, :defaults => @default_columns_names) end + + def retrieve_default_query + return if params[:query_id].present? + return if api_request? + return if params[:set_filter] && (params.key?(:op) || params.key?(:f)) + + if params[:without_default].present? + params[:set_filter] = 1 + return + end + + if default_query = ProjectQuery.default + params[:query_id] = default_query.id + end + end end diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb index c3b8e7a25..a6563a4fb 100644 --- a/app/helpers/settings_helper.rb +++ b/app/helpers/settings_helper.rb @@ -170,6 +170,10 @@ module SettingsHelper [[l(:label_none), '']] + IssueQuery.only_public.where(project_id: nil).pluck(:name, :id) end + def default_global_project_query_options + [[l(:label_none), '']] + ProjectQuery.only_public.pluck(:name, :id) + end + def cross_project_subtasks_options options = [ [:label_disabled, ''], diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index 5c1c964f0..f8ff66a81 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -41,6 +41,18 @@ module UsersHelper grouped_options_for_select(grouped, user.pref.default_issue_query) end + def default_project_query_options(user) + global_queries = ProjectQuery + global_public_queries = global_queries.only_public + global_user_queries = global_queries.where(user_id: user.id).where.not(id: global_public_queries.ids) + label = user == User.current ? 'label_my_queries' : 'label_default_queries.for_this_user' + grouped = { + l('label_default_queries.for_all_users') => global_public_queries.pluck(:name, :id), + l(".#{label}") => global_user_queries.pluck(:name, :id), + } + grouped_options_for_select(grouped, user.pref.default_project_query) + end + def textarea_font_options [[l(:label_font_default), '']] + UserPreference::TEXTAREA_FONT_OPTIONS.map {|o| [l("label_font_#{o}"), o]} end diff --git a/app/models/issue_query.rb b/app/models/issue_query.rb index efd0ad0f1..1ba3c5a2c 100644 --- a/app/models/issue_query.rb +++ b/app/models/issue_query.rb @@ -75,7 +75,6 @@ class IssueQuery < Query has_many :projects, foreign_key: 'default_issue_query_id', dependent: :nullify, inverse_of: 'default_issue_query' after_update { projects.clear unless visibility == VISIBILITY_PUBLIC } - scope :only_public, ->{ where(visibility: VISIBILITY_PUBLIC) } scope :for_all_projects, ->{ where(project_id: nil) } def self.default(project: nil, user: User.current) diff --git a/app/models/project_query.rb b/app/models/project_query.rb index a99dce5e2..df70dc2bc 100644 --- a/app/models/project_query.rb +++ b/app/models/project_query.rb @@ -37,6 +37,14 @@ class ProjectQuery < Query QueryColumn.new(:created_on, :sortable => "#{Project.table_name}.created_on", :default_order => 'desc') ] + def self.default(project: nil, user: User.current) + query = nil + if user&.logged? + query = find_by_id user.pref.default_project_query + end + query || find_by_id(Setting.default_project_query) + end + def initialize(attributes=nil, *args) super attributes self.filters ||= {'status' => {:operator => "=", :values => ['1']}} diff --git a/app/models/query.rb b/app/models/query.rb index c49e4f4d1..95081e373 100644 --- a/app/models/query.rb +++ b/app/models/query.rb @@ -339,6 +339,7 @@ class Query < ActiveRecord::Base end) scope :sorted, lambda {order(:name, :id)} + scope :only_public, ->{ where(visibility: VISIBILITY_PUBLIC) } # to be implemented in subclasses that have a way to determine a default # query for the given options diff --git a/app/models/user_preference.rb b/app/models/user_preference.rb index 1675fb0ae..e5c1a390c 100644 --- a/app/models/user_preference.rb +++ b/app/models/user_preference.rb @@ -38,6 +38,7 @@ class UserPreference < ActiveRecord::Base 'recently_used_projects', 'history_default_tab', 'default_issue_query', + 'default_project_query', 'toolbar_language_options') TEXTAREA_FONT_OPTIONS = ['monospace', 'proportional'] @@ -120,6 +121,9 @@ class UserPreference < ActiveRecord::Base def default_issue_query; self[:default_issue_query] end def default_issue_query=(value); self[:default_issue_query]=value; end + def default_project_query; self[:default_project_query] end + def default_project_query=(value); self[:default_project_query]=value; end + # Returns the names of groups that are displayed on user's page # Example: # preferences.my_page_groups diff --git a/app/views/settings/_projects.html.erb b/app/views/settings/_projects.html.erb index d6c51a7f1..15f83f3a8 100644 --- a/app/views/settings/_projects.html.erb +++ b/app/views/settings/_projects.html.erb @@ -28,6 +28,8 @@

<%= render_query_columns_selection(query, :name => 'settings[project_list_defaults][column_names]') %> + +

<%= setting_select :default_project_query, default_global_project_query_options %>

diff --git a/app/views/users/_preferences.html.erb b/app/views/users/_preferences.html.erb index 8074cb569..acc646913 100644 --- a/app/views/users/_preferences.html.erb +++ b/app/views/users/_preferences.html.erb @@ -8,4 +8,5 @@

<%= pref_fields.select :history_default_tab, history_default_tab_options %>

<%= pref_fields.text_area :toolbar_language_options, :rows => 4 %>

<%= pref_fields.select :default_issue_query, default_issue_query_options(@user), include_blank: l(:label_none) %>

+

<%= pref_fields.select :default_project_query, default_project_query_options(@user), include_blank: l(:label_none) %>

<% end %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 8fd84ff13..4c33f187b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -510,6 +510,7 @@ en: setting_project_list_defaults: Projects list defaults setting_twofa: Two-factor authentication setting_default_issue_query: Default Query + setting_default_project_query: Default Query permission_add_project: Create project permission_add_subprojects: Create subprojects diff --git a/config/settings.yml b/config/settings.yml index 64209bdfd..211d58087 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -249,6 +249,8 @@ project_list_defaults: - name - identifier - short_description +default_project_query: + default: '' issue_done_ratio: default: 'issue_field' default_projects_public: diff --git a/test/fixtures/queries.yml b/test/fixtures/queries.yml index 1b169baca..15c52c389 100644 --- a/test/fixtures/queries.yml +++ b/test/fixtures/queries.yml @@ -182,4 +182,37 @@ queries_010: --- - - spent_on - desc +queries_011: + id: 11 + type: ProjectQuery + visibility: 2 + name: Projects as list + filters: | + --- + id: + :values: + - "mine" + :operator: = + column_names: + group_by: + sort_criteria: + options: | + --- + :display_type: list +queries_012: + id: 12 + type: ProjectQuery + visibility: 1 + name: My bookmarks + filters: | + --- + id: + :values: + - "bookmarks" + :operator: = + + user_id: 1 + options: | + --- + :display_type: board diff --git a/test/functional/projects_controller_test.rb b/test/functional/projects_controller_test.rb index f7d2dee26..a26793a20 100644 --- a/test/functional/projects_controller_test.rb +++ b/test/functional/projects_controller_test.rb @@ -25,7 +25,8 @@ class ProjectsControllerTest < Redmine::ControllerTest :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages, :attachments, :custom_fields, :custom_values, :time_entries, - :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions + :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, + :roles, :queries include Redmine::I18n @@ -248,6 +249,28 @@ class ProjectsControllerTest < Redmine::ControllerTest assert_select ".total-for-cf-#{field.id} span.value", :text => '9' end + def test_index_should_retrieve_default_query + query = ProjectQuery.find(11) + ProjectQuery.stubs(:default).returns query + + [nil, 1].each do |user_id| + @request.session[:user_id] = user_id + get :index + assert_select 'h2', text: query.name + end + end + + def test_index_should_ignore_default_query_with_without_default + query = ProjectQuery.find(11) + ProjectQuery.stubs(:default).returns query + + [nil, 1].each do |user_id| + @request.session[:user_id] = user_id + get :index, params: { set_filter: '1', without_default: '1' } + assert_select 'h2', text: I18n.t(:label_project_plural) + end + end + def test_autocomplete_js get( :autocomplete, diff --git a/test/integration/api_test/projects_test.rb b/test/integration/api_test/projects_test.rb index 0785aecb5..789847db7 100644 --- a/test/integration/api_test/projects_test.rb +++ b/test/integration/api_test/projects_test.rb @@ -22,7 +22,8 @@ require File.expand_path('../../../test_helper', __FILE__) class Redmine::ApiTest::ProjectsTest < Redmine::ApiTest::Base fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details, :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages, - :attachments, :custom_fields, :custom_values, :custom_fields_projects, :time_entries, :issue_categories + :attachments, :custom_fields, :custom_values, :custom_fields_projects, :time_entries, :issue_categories, + :queries def setup super @@ -212,6 +213,18 @@ class Redmine::ApiTest::ProjectsTest < Redmine::ApiTest::Base assert_equal version.name, json['project']['default_version']['name'] end + def test_get_project_should_not_load_default_query + query = ProjectQuery.find(11) + ProjectQuery.stubs(:default).returns query + + get '/projects.json' + + assert results = JSON.parse(@response.body)['projects'] + + assert_equal 4, results.count + assert results.detect{ |i| i['name'] == "eCookbook"} + end + test "POST /projects.xml with valid parameters should create the project" do with_settings :default_projects_modules => ['issue_tracking', 'repository'] do assert_difference('Project.count') do diff --git a/test/unit/project_query_test.rb b/test/unit/project_query_test.rb index fa914ce4e..8267057a3 100644 --- a/test/unit/project_query_test.rb +++ b/test/unit/project_query_test.rb @@ -25,7 +25,8 @@ class ProjectQueryTest < ActiveSupport::TestCase :issue_categories, :enumerations, :groups_users, :enabled_modules, - :custom_fields, :custom_values + :custom_fields, :custom_values, + :queries include Redmine::I18n @@ -69,4 +70,38 @@ class ProjectQueryTest < ActiveSupport::TestCase end end end + + def test_should_determine_default_project_query + user = User.find(1) + query = ProjectQuery.find(11) + user_query = ProjectQuery.find(12) + + [nil, user, User.anonymous].each do |u| + assert_nil IssueQuery.default(user: u) + end + + # only global default is set + with_settings :default_project_query => query.id do + [nil, user, User.anonymous].each do |u| + assert_equal query, ProjectQuery.default(user: u) + end + end + + # user default, overrides global default + user.pref.default_project_query = user_query.id + user.pref.save + + with_settings :default_project_query => query.id do + assert_equal user_query, ProjectQuery.default(user: user) + end + end + + def test_project_query_default_should_return_nil_if_default_query_destroyed + query = ProjectQuery.find(11) + + Setting.default_project_query = query.id + query.destroy + + assert_nil ProjectQuery.default + end end -- 2.22.0