├── Gemfile
├── test
├── database.travis.yml
├── factories
│ ├── member.rb
│ ├── default_query.rb
│ ├── enabled_module.rb
│ ├── project.rb
│ ├── user.rb
│ ├── issue_query.rb
│ └── role.rb
├── test_helper.rb
└── integration
│ ├── manage_default_query_test.rb
│ └── issues_with_default_query_test.rb
├── config
├── routes.rb
└── locales
│ ├── zh.yml
│ ├── ja.yml
│ ├── en.yml
│ ├── tr.yml
│ ├── fr.yml
│ └── ru.yml
├── app
├── hooks
│ └── issues_controller_hook.rb
├── patches
│ ├── models
│ │ ├── query_patch.rb
│ │ ├── issue_query_patch.rb
│ │ └── project_patch.rb
│ ├── helpers
│ │ └── projects_helper_patch.rb
│ └── controllers
│ │ └── issues_controller_patch.rb
├── controllers
│ └── default_custom_query_setting_controller.rb
├── helpers
│ └── default_custom_query_helper.rb
├── views
│ ├── default_custom_query_setting
│ │ └── _form.html.erb
│ └── issues
│ │ └── _sidebar_issues_bottom.html.erb
└── models
│ └── projects_default_query.rb
├── docker-compose.yml
├── Dockerfile
├── db
└── migrate
│ └── 001_create_projects_default_queries.rb
├── init.rb
├── lib
└── default_custom_query.rb
├── .travis.yml
├── CHANGELOG.md
├── MIT-LICENSE
└── README.md
/Gemfile:
--------------------------------------------------------------------------------
1 | group :test do
2 | gem 'factory_girl'
3 | gem 'rails-controller-testing'
4 | end
5 |
--------------------------------------------------------------------------------
/test/database.travis.yml:
--------------------------------------------------------------------------------
1 | test:
2 | adapter: sqlite3
3 | database: db/test.sqlite3
4 | timeout: 500
5 |
--------------------------------------------------------------------------------
/test/factories/member.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :member do
3 | mail_notification 0
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/test/factories/default_query.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :default_query, class: ProjectsDefaultQuery do
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/test/factories/enabled_module.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :enabled_module do
3 | factory :default_custom_query_module do
4 | name 'default_custom_query'
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | RedmineApp::Application.routes.draw do
2 | put ':project_id/default_custom_query/update', :controller => 'default_custom_query_setting', action: 'update', as: 'default_custom_query_setting_update'
3 | end
4 |
--------------------------------------------------------------------------------
/app/hooks/issues_controller_hook.rb:
--------------------------------------------------------------------------------
1 | module DefaultCustomQuery
2 | class IssuesControllerViewHooks < Redmine::Hook::ViewListener
3 | render_on :view_issues_sidebar_issues_bottom, partial: 'issues/sidebar_issues_bottom'
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "2"
2 | services:
3 | app:
4 | build:
5 | context: .
6 | ports:
7 | - "3000:3000"
8 | command: bash -i -c 'bundle exec rails server -p 3000 -b 0.0.0.0'
9 | container_name: redmine
10 | restart: always
11 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM hidakatsuya/redmine-base:3.1
2 |
3 | COPY . plugins/redmine_default_custom_query
4 |
5 | RUN bundle install
6 | RUN bundle exec rake generate_secret_token
7 | RUN bundle exec rake db:migrate
8 | RUN bundle exec rake redmine:plugins:migrate
9 |
10 | RUN REDMINE_LANG=en bundle exec rake redmine:load_default_data
11 |
--------------------------------------------------------------------------------
/test/factories/project.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :project do
3 | sequence(:name) {|n| "Project#{n}"}
4 | sequence(:identifier) {|n| "project-#{n}"}
5 |
6 | trait :with_default_custom_query do
7 | after(:create) do |project|
8 | create :default_custom_query_module, project: project
9 | end
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/app/patches/models/query_patch.rb:
--------------------------------------------------------------------------------
1 | require_dependency 'query'
2 |
3 | module DefaultCustomQuery
4 | module QueryPatch
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | scope :only_public, -> { where(visibility: Query::VISIBILITY_PUBLIC) }
9 | end
10 | end
11 | end
12 |
13 | DefaultCustomQuery::QueryPatch.tap do |mod|
14 | Query.send :include, mod unless Query.include?(mod)
15 | end
16 |
--------------------------------------------------------------------------------
/db/migrate/001_create_projects_default_queries.rb:
--------------------------------------------------------------------------------
1 | class CreateProjectsDefaultQueries < ActiveRecord::Migration[4.2]
2 | def change
3 | create_table :projects_default_queries do |t|
4 | t.belongs_to :project
5 | t.belongs_to :query
6 |
7 | t.timestamps null: false
8 | end
9 | add_index :projects_default_queries, :project_id, unique: true
10 | add_index :projects_default_queries, :query_id
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/test/factories/user.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :user do
3 | sequence(:login, '000') {|n| "user#{n}"}
4 | sequence(:lastname, '0000')
5 |
6 | firstname 'User'
7 | status 1
8 | language 'ja'
9 | mail {|u| "#{u.login}@example.co.jp" }
10 | mail_notification 'only_my_events'
11 | password '12345678'
12 | password_confirmation {|u| u.password }
13 | admin false
14 | type 'User'
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/config/locales/zh.yml:
--------------------------------------------------------------------------------
1 | zh:
2 | project_module_default_custom_query: 默认自定义查询
3 | permission_manage_default_query: 管理默认查询
4 |
5 | # Labels for projects_default_queries column
6 | field_query: 默认自定义查询
7 |
8 | default_custom_query:
9 | label_setting: 默认自定义查询
10 | label_view_default_issues: 查看默认问题列表
11 | label_queries_for_all_projects: 适用于所有项目
12 | label_queries_for_current_project: 适用于当前项目
13 |
14 | text_allowed_queries: 公共查询(仅供选择)
--------------------------------------------------------------------------------
/config/locales/ja.yml:
--------------------------------------------------------------------------------
1 | ja:
2 | project_module_default_custom_query: デフォルトカスタムクエリ
3 | permission_manage_default_query: デフォルトカスタムクエリの管理
4 |
5 | # Labels for projects_default_queries column
6 | field_query: デフォルトクエリ
7 |
8 | default_custom_query:
9 | label_setting: デフォルトカスタムクエリ
10 | label_view_default_issues: デフォルトチケット一覧を見る
11 | label_queries_for_all_projects: 全プロジェクト向け
12 | label_queries_for_current_project: 現在プロジェクト
13 |
14 | text_allowed_queries: 公開クエリ(すべてのユーザ)のみ選択可能
--------------------------------------------------------------------------------
/app/controllers/default_custom_query_setting_controller.rb:
--------------------------------------------------------------------------------
1 | class DefaultCustomQuerySettingController < ApplicationController
2 |
3 | before_action :find_project_by_project_id
4 | before_action :authorize
5 |
6 | def update
7 | settings = params[:settings]
8 |
9 | @default_query = ProjectsDefaultQuery.initialize_for(@project.id)
10 | @default_query.query_id = settings[:query_id]
11 |
12 | if @default_query.save
13 | session[:query] = nil
14 | end
15 |
16 | render partial: 'form'
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/app/patches/models/issue_query_patch.rb:
--------------------------------------------------------------------------------
1 | require_dependency 'issue_query'
2 |
3 | module DefaultCustomQuery
4 | module IssueQueryPatch
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | has_many :projects_default_queries, dependent: :nullify, foreign_key: :query_id
9 | end
10 |
11 | def public_visibility?
12 | visibility == Query::VISIBILITY_PUBLIC
13 | end
14 | end
15 | end
16 |
17 | DefaultCustomQuery::IssueQueryPatch.tap do |mod|
18 | IssueQuery.send :include, mod unless IssueQuery.include?(mod)
19 | end
20 |
--------------------------------------------------------------------------------
/test/factories/issue_query.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :issue_query do
3 | sequence(:name) {|n| "IssueQuery#{n}"}
4 |
5 | user_id { User.current.id }
6 |
7 | trait :private do
8 | visibility ::Query::VISIBILITY_PRIVATE
9 | end
10 |
11 | trait :roles do
12 | visibility ::Query::VISIBILITY_ROLES
13 |
14 | before(:create) do |query|
15 | query.roles << create(:role)
16 | end
17 | end
18 |
19 | trait :public do
20 | visibility ::Query::VISIBILITY_PUBLIC
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | en:
2 | project_module_default_custom_query: Default custom query
3 | permission_manage_default_query: Manage default query
4 |
5 | # Labels for projects_default_queries column
6 | field_query: Default custom query
7 |
8 | default_custom_query:
9 | label_setting: Default custom query
10 | label_view_default_issues: View default issues
11 | label_queries_for_all_projects: For all projects
12 | label_queries_for_current_project: For current project
13 |
14 | text_allowed_queries: Public (to any users) queries only selectable
--------------------------------------------------------------------------------
/config/locales/tr.yml:
--------------------------------------------------------------------------------
1 | tr:
2 | project_module_default_custom_query: Öntanımlı özel sorgu
3 | permission_manage_default_query: Öntanımlı sorguyu yönet
4 |
5 | # Labels for projects_default_queries column
6 | field_query: Öntanımlı özel sorgu
7 |
8 | default_custom_query:
9 | label_setting: Öntanımlı özel sorgu
10 | label_view_default_issues: Öntanımlı işleri gör
11 | label_queries_for_all_projects: Tüm birimler için
12 | label_queries_for_current_project: Simdiki birim için
13 |
14 | text_allowed_queries: Herkese açık (tüm kullanıcılar) sorgular sadece seçilebilir
15 |
--------------------------------------------------------------------------------
/config/locales/fr.yml:
--------------------------------------------------------------------------------
1 | fr:
2 | project_module_default_custom_query: Rapport par défaut
3 | permission_manage_default_query: Gérer le rapport par défaut
4 |
5 | # Labels for projects_default_queries column
6 | field_query: Rapport par défaut
7 |
8 | default_custom_query:
9 | label_setting: Rapport par défaut
10 | label_view_default_issues: Voir les demandes par défaut
11 | label_queries_for_all_projects: Pour tous les projets
12 | label_queries_for_current_project: Pour le projet en cours
13 |
14 | text_allowed_queries: Seuls les rapports publics (pour tous les utilisateurs) sont sélectionnables
15 |
--------------------------------------------------------------------------------
/config/locales/ru.yml:
--------------------------------------------------------------------------------
1 | ru:
2 | project_module_default_custom_query: Выбор запроса по умолчанию (фильтр задач)
3 | permission_manage_default_query: Manage default query
4 |
5 | # Labels for projects_default_queries column
6 | field_query: Выбор запроса по умолчанию
7 |
8 | default_custom_query:
9 | label_setting: Выбор запроса по умолчанию
10 | label_view_default_issues: Просматривать запросы по умолчанию
11 | label_queries_for_all_projects: Для всех проектов
12 | label_queries_for_current_project: Для текущего прооекта
13 |
14 | text_allowed_queries: Для выбора доступны только публичные запросы (фильтры задач)
--------------------------------------------------------------------------------
/init.rb:
--------------------------------------------------------------------------------
1 | Redmine::Plugin.register :redmine_default_custom_query do
2 | name 'Redmine Default Custom Query'
3 | author 'Katsuya Hidaka'
4 | description 'Redmine plugin for setting default custom query of Issues for each project'
5 | version '1.5.0'
6 | requires_redmine '4.0'
7 | url 'https://github.com/hidakatsuya/redmine_default_custom_query'
8 | author_url 'https://twitter.com/hidakatsuya'
9 |
10 | project_module :default_custom_query do
11 | permission :manage_default_query, { default_custom_query_setting: [ :update ] }, require: :member
12 | end
13 | end
14 |
15 | require_relative 'lib/default_custom_query'
16 |
--------------------------------------------------------------------------------
/app/patches/models/project_patch.rb:
--------------------------------------------------------------------------------
1 | require_dependency 'project'
2 |
3 | module DefaultCustomQuery
4 | module ProjectPatch
5 |
6 | extend ActiveSupport::Concern
7 |
8 | included do
9 | has_many :default_queries, dependent: :delete_all, class_name: 'ProjectsDefaultQuery'
10 | end
11 |
12 | def default_query
13 | default_queries.first.try :query
14 | end
15 |
16 | def init_default_query
17 | default_queries.first || default_queries.new
18 | end
19 | end
20 | end
21 |
22 | DefaultCustomQuery::ProjectPatch.tap do |mod|
23 | Project.send :include, mod unless Project.include?(mod)
24 | end
25 |
--------------------------------------------------------------------------------
/app/helpers/default_custom_query_helper.rb:
--------------------------------------------------------------------------------
1 | module DefaultCustomQueryHelper
2 | def options_for_selectable_queries(project)
3 | options_groups = []
4 |
5 | queries = IssueQuery.only_public.where(project_id: nil)
6 | if queries.any?
7 | options_groups << [l('default_custom_query.label_queries_for_all_projects'), queries]
8 | end
9 |
10 | queries = project.queries.only_public
11 | if queries.any?
12 | options_groups << [l('default_custom_query.label_queries_for_current_project'), queries]
13 | end
14 |
15 | options_groups.map do |group, options|
16 | [group, options.collect {|o| [o.name, o.id] }]
17 | end
18 | end
19 | end
--------------------------------------------------------------------------------
/lib/default_custom_query.rb:
--------------------------------------------------------------------------------
1 | require 'pathname'
2 |
3 | module DefaultCustomQuery
4 | def self.root
5 | @root ||= Pathname.new File.expand_path('..', File.dirname(__FILE__))
6 | end
7 | end
8 |
9 | Rails.configuration.to_prepare do
10 | # Load patches for Redmine
11 | Dir[DefaultCustomQuery.root.join('app/patches/**/*_patch.rb')].each {|f| require_dependency f }
12 |
13 | # Load application helper
14 | ::DefaultCustomQueryHelper.tap do |mod|
15 | ActionView::Base.send :include, mod unless ActionView::Base.include?(mod)
16 | end
17 | end
18 |
19 | # Load hooks
20 | Dir[DefaultCustomQuery.root.join('app/hooks/*_hook.rb')].each {|f| require_dependency f }
21 |
--------------------------------------------------------------------------------
/test/factories/role.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :role, aliases: [:role_with_manage_default_query] do
3 | sequence(:name) {|n| "Role#{n}"}
4 | sequence(:position)
5 | assignable 1
6 | builtin 0
7 | issues_visibility 'all'
8 | permissions {
9 | perms = Redmine::AccessControl.permissions -
10 | Redmine::AccessControl.public_permissions
11 | perms.map &:name
12 | }
13 |
14 | factory :role_without_manage_default_query do
15 | permissions {
16 | perms = Redmine::AccessControl.permissions -
17 | Redmine::AccessControl.public_permissions
18 | perms.map(&:name) - [:manage_default_query]
19 | }
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/app/patches/helpers/projects_helper_patch.rb:
--------------------------------------------------------------------------------
1 | require_dependency 'projects_helper'
2 |
3 | module DefaultCustomQuery
4 | module ProjectsHelperPatch
5 |
6 | def project_settings_tabs
7 | tabs = super
8 | if User.current.allowed_to?(:manage_default_query, @project) &&
9 | @project.module_enabled?(:default_custom_query)
10 | tabs << {
11 | name: 'default_custom_query',
12 | action: :manage_default_query,
13 | partial: 'default_custom_query_setting/form',
14 | label: :'default_custom_query.label_setting'
15 | }
16 | end
17 | tabs
18 | end
19 | end
20 | end
21 |
22 | ProjectsController.send :helper, DefaultCustomQuery::ProjectsHelperPatch
23 |
--------------------------------------------------------------------------------
/app/views/default_custom_query_setting/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= labelled_form_for @default_query ||= @project.init_default_query,
2 | as: :settings,
3 | url: default_custom_query_setting_update_path(@project),
4 | remote: true, method: :put, html: { id: 'default-query-setting' } do |f| %>
5 |
6 | <%= error_messages_for @default_query %>
7 |
8 |
9 |
10 | <%= f.select :query_id, options_for_selectable_queries(@project), include_blank: true %>
11 | <%=l 'default_custom_query.text_allowed_queries' %>
12 |
13 |
14 | <%= submit_tag l(:button_save) %>
15 | <% end %>
16 |
17 |
22 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 |
3 | rvm:
4 | - 2.2
5 | - 2.3
6 | - 2.4
7 | - 2.5
8 | - 2.6
9 |
10 | env:
11 | - REDMINE_REPOS=branches/4.0-stable
12 |
13 | before_install:
14 | - export PLUGIN_NAME=redmine_default_custom_query
15 | - export DB=sqlite
16 | - export NOKOGIRI_USE_SYSTEM_LIBRARIES=true
17 | - export REDMINE_PATH=$HOME/redmine
18 | - export BUNDLE_GEMFILE=$REDMINE_PATH/Gemfile
19 | - svn co http://svn.redmine.org/redmine/$REDMINE_REPOS $REDMINE_PATH
20 | - ln -s $TRAVIS_BUILD_DIR $REDMINE_PATH/plugins/$PLUGIN_NAME
21 | - cp test/database.travis.yml $REDMINE_PATH/config/database.yml
22 | - cd $REDMINE_PATH
23 | - bundle update
24 |
25 | before_script:
26 | - bundle exec rake db:migrate
27 | - bundle exec rake redmine:plugins:migrate
28 |
29 | script:
30 | - bundle exec rake redmine:plugins:test NAME=$PLUGIN_NAME
31 |
32 | branches:
33 | only:
34 | - master
35 |
--------------------------------------------------------------------------------
/app/views/issues/_sidebar_issues_bottom.html.erb:
--------------------------------------------------------------------------------
1 | <% if @project && @project.module_enabled?(:default_custom_query) && @project.default_query.present? %>
2 | <%= javascript_tag id: 'add-default-issues-button' do %>
3 | (function() {
4 | var allIssuesPath = '<%=j project_issues_path(@project, set_filter: 1) %>';
5 |
6 | var showIssuesButton = $('#sidebar a[href="' + allIssuesPath + '"]');
7 | if (showIssuesButton.size() > 0) {
8 | showIssuesButton.attr('href', allIssuesPath + '&without_default=1');
9 | }
10 |
11 | var defaultIssuePath = '<%=j project_issues_path(@project, query_id: @project.default_query.id) %>';
12 |
13 | var showDefaultIssuesButton = $('').attr('href', defaultIssuePath)
14 | .text('<%=j l('default_custom_query.label_view_default_issues') %>');
15 | showIssuesButton.before(showDefaultIssuesButton).before('
');
16 | })();
17 | <% end %>
18 | <% end %>
19 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 1.4.0
2 |
3 | - Support only Redmine 4.0 (@marius-balteanu). For older Redmine versions, please use version 1.3.0.
4 | - Support Ruby 2.5 and 2.6 (@marius-balteanu)
5 |
6 | ## 1.3.0
7 |
8 | - Support Redmine 3.4 (@maeda-m, @pboese)
9 | - Support Ruby 2.4 (@maeda-m)
10 |
11 |
12 | ## 1.2.0
13 |
14 | - Bug: Fixed CSV export when custom query is used #19 (@sdwolf)
15 | - Feature: Support Chinese translation #24 (@archonwang)
16 | - Drop support Redmine 2.6 and supports 3.1,3.2 #23 (@hidakatsuya)
17 | - Drop support Ruby 1.9.3 and supports 2.3 #22 (@hidakatsuya)
18 |
19 | ## 1.1.2
20 |
21 | - Feature: Support French locale #14
22 |
23 | ## 1.1.1
24 |
25 | - Feature: Russian translation #13 (@insspb)
26 |
27 | ## 1.1.0
28 |
29 | - Feature: Support v3.0 and drop v2.5 or less support #8 (@hidakatsuya)
30 |
31 | ## 1.0.1
32 |
33 | - Bug: First view don't show selected query #7 (@AntonJa, @hidakatsuya)
34 |
35 | ## 1.0.0
36 |
37 | - Allow select a global query #5 [Katsuya Hidaka]
38 | - Test code and Improvements by testing #1 [Katsuya Hidaka]
39 |
--------------------------------------------------------------------------------
/MIT-LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014 Katsuya Hidaka.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/app/models/projects_default_query.rb:
--------------------------------------------------------------------------------
1 | class ProjectsDefaultQuery < ActiveRecord::Base
2 |
3 | belongs_to :project
4 | belongs_to :query, class_name: 'IssueQuery'
5 |
6 | validates :project_id, :query_id, numericality: { allow_nil: true }
7 | validates :project_id, uniqueness: true, presence: true
8 | validate :query_must_be_selectable
9 |
10 | def self.initialize_for(project_id)
11 | default_query = where(project_id: project_id).first
12 |
13 | unless default_query
14 | default_query = self.new
15 | default_query.project_id = project_id
16 | end
17 | default_query
18 | end
19 |
20 | def query
21 | return unless super
22 |
23 | unless new_record? || selectable_query?(super)
24 | update_attribute :query_id, nil
25 | end
26 | super
27 | end
28 |
29 | private
30 |
31 | def query_must_be_selectable
32 | return if errors.any? || query_id.blank? || !query_id_changed?
33 |
34 | issue_query = IssueQuery.where(id: query_id).first
35 |
36 | unless selectable_query?(issue_query)
37 | errors.add :query_id, :invalid
38 | end
39 | end
40 |
41 | def selectable_query?(query)
42 | query && query.public_visibility? &&
43 | (query.project.nil? || query.project == project)
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path(File.dirname(__FILE__) + '/../../../test/test_helper')
2 |
3 | Dir[DefaultCustomQuery.root.join('test/factories/*.rb')].each {|f| require f }
4 |
5 | module DefaultCustomQuery
6 | module TestHelper
7 | include FactoryGirl::Syntax::Methods
8 | include Redmine::I18n
9 |
10 | def create_member(project, user, role)
11 | create(:member, project: project, user: user, roles: [role])
12 | end
13 | alias_method :add_member, :create_member
14 |
15 | def create_project_and_member_with_default_query
16 | user = create(:user)
17 | project = create(:project, :with_default_custom_query)
18 | add_member project, user, create(:role_with_manage_default_query)
19 |
20 | [project, user]
21 | end
22 |
23 | def set_default_query(project, query)
24 | create(:default_query, project: project, query: query)
25 | end
26 |
27 | def logged_in(user)
28 | log_user user.login, attributes_for(:user)[:password]
29 | end
30 |
31 | def assert_apply_query(query)
32 | assert_select 'h2', text: query.name
33 | assert_select 'ul.queries a.selected', text: query.name
34 | end
35 |
36 | def assert_not_applied_query
37 | assert_select 'h2', text: l(:label_issue_plural)
38 | assert_select 'ul.queries a.selected', false
39 | end
40 | end
41 | end
42 |
43 | Redmine::IntegrationTest.send :include, DefaultCustomQuery::TestHelper
44 |
--------------------------------------------------------------------------------
/app/patches/controllers/issues_controller_patch.rb:
--------------------------------------------------------------------------------
1 | require_dependency 'issues_controller'
2 |
3 | module DefaultCustomQuery
4 | module IssuesControllerPatch
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | before_action :with_default_query, only: [:index], if: :default_query_module_enabled?
9 |
10 | alias_method :retrieve_query_from_session_without_default_custom_query, :retrieve_query_from_session
11 | alias_method :retrieve_query_from_session, :retrieve_query_from_session_with_default_custom_query
12 | end
13 |
14 | def with_default_query
15 | case
16 | when params[:query_id].present?
17 | # Nothing to do
18 | when api_request? || csv_request?
19 | # Nothing to do
20 | when show_all_issues?
21 | params[:set_filter] = 1
22 | when filter_applied?
23 | # Nothing to do
24 | when filter_cleared?
25 | apply_default_query!
26 | when session[:query]
27 | query_id, project_id = session[:query].values_at(:id, :project_id)
28 | unless query_id && (project_id == @project.id) && available_query?(query_id)
29 | apply_default_query!
30 | end
31 | else
32 | apply_default_query!
33 | end
34 | end
35 |
36 | def retrieve_query_from_session_with_default_custom_query
37 | if default_query_module_enabled?
38 | if session[:query]
39 | retrieve_query_from_session_without_default_custom_query
40 | else
41 | @query = find_default_query
42 | end
43 | else
44 | retrieve_query_from_session_without_default_custom_query
45 | end
46 | end
47 |
48 | private
49 |
50 | def find_default_query
51 | @project.default_query
52 | end
53 |
54 | def apply_default_query!
55 | default_query = find_default_query
56 | if default_query
57 | params[:query_id] = default_query.id
58 | end
59 | end
60 |
61 | def filter_applied?
62 | params[:set_filter]
63 | end
64 |
65 | def filter_cleared?
66 | params[:set_filter] && [:op, :f].all? {|k| !params.key?(k) }
67 | end
68 |
69 | def show_all_issues?
70 | params[:without_default]
71 | end
72 |
73 | def default_query_module_enabled?
74 | @project && @project.module_enabled?(:default_custom_query)
75 | end
76 |
77 | def available_query?(query_id)
78 | IssueQuery.only_public
79 | .where('project_id is null or project_id = ?', @project.id)
80 | .where(id: query_id).exists?
81 | end
82 |
83 | def csv_request?
84 | params[:format] == 'csv'
85 | end
86 | end
87 | end
88 |
89 | DefaultCustomQuery::IssuesControllerPatch.tap do |mod|
90 | IssuesController.send :include, mod unless IssuesController.include?(mod)
91 | end
92 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Redmine Default Custom Query [](https://gitter.im/hidakatsuya/redmine_default_custom_query?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
2 |
3 |
4 | [](https://travis-ci.org/hidakatsuya/redmine_default_custom_query)
5 | [](https://codeclimate.com/github/hidakatsuya/redmine_default_custom_query)
6 |
7 | Redmine plugin for setting the default custom query of Issues for each project.
8 |
9 | 
10 |
11 | 
12 |
13 | ## Usage
14 |
15 | 1. Enable the Default Custom Query module in your project
16 | 2. Select a custom query to set to default in setting for your project
17 |
18 | ## Supported versions
19 |
20 | * Redmine 4.0
21 | * Ruby 2.2, 2.3, 2.4, 2.5, 2.6
22 |
23 | ## Install
24 |
25 | `git clone` or copy an unarchived plugin(archived file is [here](https://github.com/hidakatsuya/redmine_default_custom_query/releases)) to `plugins/redmine_default_custom_query` on your Redmine path.
26 |
27 | ```
28 | $ git clone https://github.com/hidakatsuya/redmine_default_custom_query.git /path/to/your-redmine/plugins/redmine_default_custom_query
29 | ```
30 |
31 | Install dependencies:
32 |
33 | ```
34 | $ bundle install
35 | ```
36 |
37 | Then, migrate:
38 |
39 | ```
40 | $ cd /path/to/your-redmine
41 | $ rake redmine:plugins:migrate NAME=redmine_default_custom_query RAILS_ENV=production
42 | ```
43 |
44 | That's all.
45 |
46 | ## Uninstall
47 |
48 | At first, rollback schema:
49 |
50 | ```
51 | $ cd /path/to/your-redmine
52 | $ rake redmine:plugins:migrate NAME=redmine_default_custom_query VERSION=0 RAILS_ENV=production
53 | ```
54 |
55 | Then, remove `plugins/redmine_default_custom_query` directory.
56 |
57 | ## Contribute
58 |
59 | ### How to test
60 |
61 | ```
62 | $ cd /path/to/redmine
63 | $ bundle install
64 | $ bundle exec rake redmine:plugins:test NAME=redmine_default_custom_query
65 | ```
66 |
67 | ### Pull Request
68 |
69 | 1. Fork it
70 | 2. Create your feature branch: `git checkout -b new-feature`
71 | 3. Commit your changes: `git commit -am 'add some new feature'`
72 | 4. Push to the branch: `git push origin new-feature`
73 | 5. Create new Pull Request
74 |
75 | ### Report bugs
76 |
77 | Please report from [here](https://github.com/hidakatsuya/redmine_default_custom_query/issues/new).
78 |
79 | ## Copyright
80 |
81 | © Katsuya Hidaka. See MIT-LICENSE for further details.
82 |
--------------------------------------------------------------------------------
/test/integration/manage_default_query_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../test_helper', __FILE__)
2 |
3 | class ManageDefaultQueryTest < Redmine::IntegrationTest
4 | def setup
5 | @user = create(:user)
6 | @project = create(:project, :with_default_custom_query)
7 | logged_in @user
8 | end
9 |
10 | def test_logged_user_has_not_manage_default_query_permission
11 | add_member @project, @user, create(:role_without_manage_default_query)
12 |
13 | # show
14 | get settings_project_path(@project)
15 |
16 | assert_response :success
17 | assert_select '#tab-default_custom_query', false
18 |
19 | # update
20 | put default_custom_query_setting_update_path(@project)
21 |
22 | assert_response :forbidden
23 | end
24 |
25 | def test_logged_user_has_manage_default_query_permission
26 | add_member @project, @user, create(:role_with_manage_default_query)
27 |
28 | @queries = [
29 | create(:issue_query, :public, project: @project),
30 | # Global query
31 | create(:issue_query, :public)
32 | ]
33 | @unselectable_queries = [
34 | create(:issue_query, :private, project: @project),
35 | create(:issue_query, :roles, project: @project)
36 | ]
37 |
38 | get settings_project_path(@project, tab: 'default_custom_query')
39 |
40 | # Render
41 | assert_response :success
42 | assert_template partial: 'default_custom_query_setting/_form'
43 |
44 | assert_select 'select#settings_query_id optgroup option', count: @queries.count
45 | assert_select 'select#settings_query_id' do
46 | @queries.each do |query|
47 | assert_select 'option', text: query.name
48 | end
49 | end
50 |
51 | # New setting
52 | assert_difference -> { @project.default_queries.count }, 1 do
53 | put default_custom_query_setting_update_path(@project), params: {
54 | settings: { query_id: @queries.first.id },
55 | xhr: true
56 | }
57 | end
58 |
59 | assert_equal @project.default_query, @queries.first
60 | assert_response :success
61 | assert_template partial: 'default_custom_query_setting/_form'
62 |
63 | # Update
64 | assert_no_difference -> { @project.default_queries.count } do
65 | put default_custom_query_setting_update_path(@project), params: {
66 | settings: { query_id: @queries.last.id },
67 | xhr: true
68 | }
69 | end
70 |
71 | assert_equal @project.default_query, @queries.last
72 | assert_response :success
73 | assert_template partial: 'default_custom_query_setting/_form'
74 |
75 | # Clear
76 | assert_no_difference -> { @project.default_queries.count } do
77 | put default_custom_query_setting_update_path(@project), params: {
78 | settings: { query_id: '' },
79 | xhr: true
80 | }
81 | end
82 |
83 | assert_nil @project.default_query
84 | assert_response :success
85 | assert_template partial: 'default_custom_query_setting/_form'
86 |
87 | # Update to unselectable query
88 | put default_custom_query_setting_update_path(@project), params: {
89 | settings: { query_id: @unselectable_queries.first.id },
90 | xhr: true
91 | }
92 |
93 | assert_response :success
94 | assert_template partial: 'default_custom_query_setting/_form'
95 | assert_nil @project.default_query
96 |
97 | # should be rendered the error message
98 | assert_select '#errorExplanation li', 1
99 | end
100 | end
101 |
--------------------------------------------------------------------------------
/test/integration/issues_with_default_query_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../test_helper', __FILE__)
2 |
3 | class IssuesWithDefaultQueryTest < Redmine::IntegrationTest
4 | def setup
5 | @project, @user = create_project_and_member_with_default_query
6 | logged_in @user
7 |
8 | @default_query, @query = create_list(:issue_query, 2, :public, project: @project)
9 | end
10 |
11 | def test_basic_features_when_default_query_is_not_set_in_project
12 | get project_issues_path(@project)
13 |
14 | assert_response :success
15 | assert_select 'script#add-default-issues-button', false
16 |
17 | get project_issues_path(@project)
18 |
19 | assert_response :success
20 | assert_not_applied_query
21 | end
22 |
23 | def test_basic_features_when_default_query_is_set_in_project
24 | set_default_query @project, @default_query
25 |
26 | get project_issues_path(@project)
27 |
28 | # should be rendered the "Show default issues" button
29 | assert_response :success
30 | assert_select 'script#add-default-issues-button'
31 |
32 | get project_issues_path(@project)
33 |
34 | assert_response :success
35 | assert_apply_query @default_query
36 | end
37 |
38 | def test_click_view_all_issues_button
39 | set_default_query @project, @default_query
40 |
41 | # click "View all issues" button
42 | get project_issues_path(@project, set_filter: 1, without_default: 1)
43 |
44 | assert_response :success
45 | assert_not_applied_query
46 | end
47 |
48 | def test_select_other_query
49 | set_default_query @project, @default_query
50 |
51 | get project_issues_path(@project, query_id: @query.id)
52 |
53 | assert_response :success
54 | assert_apply_query @query
55 | end
56 |
57 | def test_default_query_has_been_deleted
58 | set_default_query @project, @default_query
59 |
60 | delete query_path(@default_query)
61 |
62 | assert_nil @project.default_query
63 | assert_response :redirect
64 | end
65 |
66 | def test_visibility_of_default_query_has_been_changed_to_PRIVATE
67 | set_default_query @project, @default_query
68 |
69 | @default_query.update_attribute :visibility, Query::VISIBILITY_PRIVATE
70 |
71 | get project_issues_path(@project)
72 |
73 | assert_response :success
74 | assert_nil @project.default_query
75 | end
76 |
77 | def test_visibility_of_default_query_has_been_changed_to_ROLES
78 | set_default_query @project, @default_query
79 |
80 | @default_query.visibility = Query::VISIBILITY_ROLES
81 | @default_query.roles << create(:role)
82 | @default_query.save!
83 |
84 | get project_issues_path(@project)
85 |
86 | assert_response :success
87 | assert_nil @project.default_query
88 | end
89 |
90 | def test_initial_default_query
91 | set_default_query @project, @default_query
92 |
93 | @other_project = create(:project, :with_default_custom_query)
94 | add_member @other_project, @user, create(:role_with_manage_default_query)
95 |
96 | # @other_project's global query
97 | @global_query = create(:issue_query, :public, project: nil)
98 |
99 | # select @global_query in @other_project
100 | get project_issues_path(@other_project, query_id: @global_query.id)
101 | get project_issues_path(@project)
102 |
103 | assert_response :success
104 | assert_apply_query @default_query
105 | end
106 |
107 | def test_select_project_overview_query
108 | set_default_query @project, @default_query
109 |
110 | get project_issues_path(@project, set_filter: 1, tracker_id: 1)
111 |
112 | assert_response :success
113 | assert_not_applied_query
114 | end
115 |
116 | def test_select_multiple_issues_query
117 | set_default_query @project, @default_query
118 |
119 | get issues_path(set_filter: 1, issue_id: '1,2,3')
120 |
121 | assert_response :success
122 | assert_not_applied_query
123 | end
124 |
125 | def test_select_only_columns_query
126 | set_default_query @project, @default_query
127 |
128 | get project_issues_path(@project, set_filter: 1,
129 | f: [], c: [ 'subject', 'assigned_to', 'due_date' ])
130 |
131 | assert_response :success
132 | assert_not_applied_query
133 | end
134 | end
135 |
--------------------------------------------------------------------------------