From 2fed3ee301c575c1288bed1842ce21c60892f6c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20G=C3=BCnther?= Date: Mon, 20 Jul 2020 15:49:51 +0200 Subject: [PATCH] Add filter to select only (non-) milestones --- app/models/queries/work_packages.rb | 1 + .../work_packages/filter/milestone_filter.rb | 75 ++++++++++ .../filter/milestone_filter_spec.rb | 135 ++++++++++++++++++ 3 files changed, 211 insertions(+) create mode 100644 app/models/queries/work_packages/filter/milestone_filter.rb create mode 100644 spec/models/queries/work_packages/filter/milestone_filter_spec.rb diff --git a/app/models/queries/work_packages.rb b/app/models/queries/work_packages.rb index 7487bbb1ab..65f9981afa 100644 --- a/app/models/queries/work_packages.rb +++ b/app/models/queries/work_packages.rb @@ -76,6 +76,7 @@ module Queries::WorkPackages register.filter Query, filters_module::SubjectOrIdFilter register.filter Query, filters_module::ManualSortFilter register.filter Query, filters_module::RelatableFilter + register.filter Query, filters_module::MilestoneFilter columns_module = Queries::WorkPackages::Columns diff --git a/app/models/queries/work_packages/filter/milestone_filter.rb b/app/models/queries/work_packages/filter/milestone_filter.rb new file mode 100644 index 0000000000..60630507d1 --- /dev/null +++ b/app/models/queries/work_packages/filter/milestone_filter.rb @@ -0,0 +1,75 @@ +#-- encoding: UTF-8 + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2020 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2017 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See docs/COPYRIGHT.rdoc for more details. +#++ + +class Queries::WorkPackages::Filter::MilestoneFilter < Queries::WorkPackages::Filter::WorkPackageFilter + include Queries::Filters::Shared::BooleanFilter + + def self.key + :is_milestone + end + + def available? + types.exists? + end + + def dependency_class + '::API::V3::Queries::Schemas::BooleanFilterDependencyRepresenter' + end + + def where + if positive? + "type_id IN (#{milestone_subselect})" + else + "type_id NOT IN (#{milestone_subselect})" + end + end + + def positive? + (operator == '=' && values == [OpenProject::Database::DB_VALUE_TRUE]) || + (operator == '!' && values == [OpenProject::Database::DB_VALUE_FALSE]) + end + + def human_name + I18n.t('activerecord.attributes.type.is_milestone') + end + + private + + def types + project.nil? ? ::Type.order(Arel.sql('position')) : project.rolled_up_types + end + + def milestone_subselect + Type + .where(is_milestone: true) + .select(:id) + .to_sql + end +end diff --git a/spec/models/queries/work_packages/filter/milestone_filter_spec.rb b/spec/models/queries/work_packages/filter/milestone_filter_spec.rb new file mode 100644 index 0000000000..bb758fa08c --- /dev/null +++ b/spec/models/queries/work_packages/filter/milestone_filter_spec.rb @@ -0,0 +1,135 @@ +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2020 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2017 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See docs/COPYRIGHT.rdoc for more details. +#++ + +require 'spec_helper' + +describe Queries::WorkPackages::Filter::MilestoneFilter, type: :model do + it_behaves_like 'basic query filter' do + let(:type) { :list } + let(:class_key) { :is_milestone } + + describe '#available?' do + context 'within a project' do + before do + allow(project) + .to receive_message_chain(:rolled_up_types, :exists?) + .and_return true + end + + it 'is true' do + expect(instance).to be_available + end + + it 'is false without a type' do + allow(project) + .to receive_message_chain(:rolled_up_types, :exists?) + .and_return false + + expect(instance).to_not be_available + end + end + + context 'without a project' do + let(:project) { nil } + + before do + allow(Type) + .to receive_message_chain(:order, :exists?) + .and_return true + end + + it 'is true' do + expect(instance).to be_available + end + + it 'is false without a type' do + allow(Type) + .to receive_message_chain(:order, :exists?) + .and_return false + + expect(instance).to_not be_available + end + end + end + end + + it_behaves_like 'boolean query filter', scope: false do + let(:model) { WorkPackage.unscoped } + let(:attribute) { :id } + + describe '#scope' do + context 'for the true value' do + let(:values) { [OpenProject::Database::DB_VALUE_TRUE] } + + context 'for "="' do + let(:operator) { '=' } + + it 'is the same as handwriting the query' do + expected = 'type_id IN (SELECT "types"."id" FROM "types" WHERE "types"."is_milestone" = TRUE ORDER BY position ASC)' + + expect(instance.where).to eql expected + end + end + + context 'for "!"' do + let(:operator) { '!' } + + it 'is the same as handwriting the query' do + expected = 'type_id NOT IN (SELECT "types"."id" FROM "types" WHERE "types"."is_milestone" = TRUE ORDER BY position ASC)' + + expect(instance.where).to eql expected + end + end + end + + context 'for the false value' do + let(:values) { [OpenProject::Database::DB_VALUE_FALSE] } + + context 'for "="' do + let(:operator) { '=' } + + it 'is the same as handwriting the query' do + expected = 'type_id NOT IN (SELECT "types"."id" FROM "types" WHERE "types"."is_milestone" = TRUE ORDER BY position ASC)' + + expect(instance.where).to eql expected + end + end + + context 'for "!"' do + let(:operator) { '!' } + + it 'is the same as handwriting the query' do + expected = 'type_id IN (SELECT "types"."id" FROM "types" WHERE "types"."is_milestone" = TRUE ORDER BY position ASC)' + + expect(instance.where).to eql expected + end + end + end + end + end +end