Merge pull request #247 from finnlabs/fix/adapt_filter_to_core

adapt backlogs type filter to core changes
pull/6827/head
ulferts 8 years ago committed by GitHub
commit b5ac7b8c29
  1. 62
      lib/api/v3/backlogs_types/backlogs_type_representer.rb
  2. 44
      lib/api/v3/queries/schemas/backlogs_type_dependency_representer.rb
  3. 11
      lib/open_project/backlogs/engine.rb
  4. 119
      lib/open_project/backlogs/work_package_filter.rb
  5. 116
      spec/features/work_packages/filter_spec.rb

@ -0,0 +1,62 @@
#-- copyright
# OpenProject Backlogs Plugin
#
# Copyright (C)2013-2014 the OpenProject Foundation (OPF)
# Copyright (C)2011 Stephan Eckardt, Tim Felgentreff, Marnen Laibow-Koser, Sandro Munda
# Copyright (C)2010-2011 friflaj
# Copyright (C)2010 Maxime Guilbot, Andrew Vit, Joakim Kolsjö, ibussieres, Daniel Passos, Jason Vasquez, jpic, Emiliano Heyns
# Copyright (C)2009-2010 Mark Maglana
# Copyright (C)2009 Joe Heck, Nate Lowrie
#
# 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 Backlogs is a derivative work based on ChiliProject Backlogs.
# The copyright follows:
# Copyright (C) 2010-2011 - Emiliano Heyns, Mark Maglana, friflaj
# Copyright (C) 2011 - Jens Ulferts, Gregor Schmidt - Finn GmbH - Berlin, Germany
#
# 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 doc/COPYRIGHT.rdoc for more details.
#++
module API
module V3
module BacklogsTypes
class BacklogsTypeRepresenter < ::API::Decorators::Single
self_link path: :backlogs_type,
id_attribute: ->(*) { represented.last },
title_getter: ->(*) { represented.first }
property :id,
exec_context: :decorator
property :name,
exec_context: :decorator
private
def id
represented.last
end
def name
represented.first
end
end
end
end
end

@ -1,14 +1,20 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
# OpenProject Backlogs Plugin
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
# Copyright (C)2013-2014 the OpenProject Foundation (OPF)
# Copyright (C)2011 Stephan Eckardt, Tim Felgentreff, Marnen Laibow-Koser, Sandro Munda
# Copyright (C)2010-2011 friflaj
# Copyright (C)2010 Maxime Guilbot, Andrew Vit, Joakim Kolsjö, ibussieres, Daniel Passos, Jason Vasquez, jpic, Emiliano Heyns
# Copyright (C)2009-2010 Mark Maglana
# Copyright (C)2009 Joe Heck, Nate Lowrie
#
# 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
# OpenProject Backlogs is a derivative work based on ChiliProject Backlogs.
# The copyright follows:
# Copyright (C) 2010-2011 - Emiliano Heyns, Mark Maglana, friflaj
# Copyright (C) 2011 - Jens Ulferts, Gregor Schmidt - Finn GmbH - Berlin, Germany
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@ -34,12 +40,32 @@ module API
class BacklogsTypeDependencyRepresenter <
FilterDependencyRepresenter
schema_with_allowed_collection :values,
type: ->(*) { type },
writable: true,
has_default: false,
required: true,
visibility: false,
values_callback: ->(*) {
represented.allowed_values
},
value_representer: BacklogsTypes::BacklogsTypeRepresenter,
link_factory: ->(value) {
{
href: api_v3_paths.backlogs_type(value.last),
title: value.first
}
},
show_if: ->(*) {
value_required?
}
def href_callback; end
private
def type
'[]String'
'[1]BacklogsType'
end
end
end

@ -243,12 +243,13 @@ module OpenProject::Backlogs
end
end
initializer 'backlogs.register_hooks' do
require 'open_project/backlogs/hooks'
add_api_path :backlogs_type do |id|
# There is no api endpoint for this url
"#{root}/backlogs_types/#{id}"
end
initializer 'backlogs.register_query_filter' do
Queries::Register.filter Query, OpenProject::Backlogs::WorkPackageFilter
initializer 'backlogs.register_hooks' do
require 'open_project/backlogs/hooks'
end
config.to_prepare do
@ -267,6 +268,8 @@ module OpenProject::Backlogs
end
::Type.add_default_mapping(:estimates_and_time, :story_points, :remaining_time)
Queries::Register.filter Query, OpenProject::Backlogs::WorkPackageFilter
end
end
end

@ -37,11 +37,7 @@ require 'story'
require 'task'
module OpenProject::Backlogs
class WorkPackageFilter < ::Queries::Filters::Base
alias :project :context
alias :project= :context=
class WorkPackageFilter < ::Queries::WorkPackages::Filter::WorkPackageFilter
def allowed_values
[[I18n.t(:story, scope: [:backlogs]), 'story'],
[I18n.t(:task, scope: [:backlogs]), 'task'],
@ -58,41 +54,8 @@ module OpenProject::Backlogs
:backlogs_work_package_type
end
def self.sql_for_field(values, db_table, _db_field)
sql = []
selected_values = ['story', 'task'] if values.include?('any')
story_types = Story.types.map(&:to_s).join(',')
all_types = (Story.types + [Task.type]).map(&:to_s).join(',')
selected_values.each do |val|
case val
when 'story'
sql << "(#{db_table}.type_id IN (#{story_types}))"
when 'task'
sql << "(#{db_table}.type_id = #{Task.type} AND NOT #{db_table}.parent_id IS NULL)"
when 'impediment'
sql << "(#{db_table}.id IN (
select from_id
FROM relations ir
JOIN work_packages blocked
ON
blocked.id = ir.to_id
AND blocked.type_id IN (#{all_types})
WHERE ir.relation_type = 'blocks'
) AND #{db_table}.parent_id IS NULL)"
end
case operator
when '='
sql = sql.join(' OR ')
when '!'
sql = 'NOT (' + sql.join(' OR ') + ')'
end
end
sql
def where
sql_for_field(values)
end
def order
@ -111,6 +74,16 @@ module OpenProject::Backlogs
'::API::V3::Queries::Schemas::BacklogsTypeDependencyRepresenter'
end
def ar_object_filter?
true
end
def value_objects
allowed_values
.select { |av| values.include?(av.last) }
.map { |value| BacklogsType.new(*value) }
end
private
def backlogs_configured?
@ -120,5 +93,71 @@ module OpenProject::Backlogs
def backlogs_enabled?
project.nil? || project.module_enabled?(:backlogs)
end
def sql_for_field(values)
selected_values = if values.include?('any')
['story', 'task']
else
values
end
sql_parts = selected_values.map do |val|
case val
when 'story'
sql_for_story
when 'task'
sql_for_task
when 'impediment'
sql_for_impediment
end
end
case operator
when '='
sql_parts.join(' OR ')
when '!'
'NOT (' + sql_parts.join(' OR ') + ')'
end
end
def db_table
WorkPackage.table_name
end
def sql_for_story
story_types = Story.types.map(&:to_s).join(',')
"(#{db_table}.type_id IN (#{story_types}))"
end
def sql_for_task
"(#{db_table}.type_id = #{Task.type} AND NOT #{db_table}.parent_id IS NULL)"
end
def sql_for_impediment
all_types = (Story.types + [Task.type]).map(&:to_s).join(',')
"(#{db_table}.id IN (
select from_id
FROM relations ir
JOIN work_packages blocked
ON
blocked.id = ir.to_id
AND blocked.type_id IN (#{all_types})
WHERE ir.relation_type = 'blocks'
) AND #{db_table}.parent_id IS NULL)"
end
end
# Need to be conformant to the interface required
# by api/v3/queries/filters/query_filter_instance_representer.rb
class BacklogsType
attr_accessor :id,
:name
def initialize(name, id)
self.id = id
self.name = name
end
end
end

@ -0,0 +1,116 @@
#-- copyright
# OpenProject Backlogs Plugin
#
# Copyright (C)2013-2014 the OpenProject Foundation (OPF)
# Copyright (C)2011 Stephan Eckardt, Tim Felgentreff, Marnen Laibow-Koser, Sandro Munda
# Copyright (C)2010-2011 friflaj
# Copyright (C)2010 Maxime Guilbot, Andrew Vit, Joakim Kolsjö, ibussieres, Daniel Passos, Jason Vasquez, jpic, Emiliano Heyns
# Copyright (C)2009-2010 Mark Maglana
# Copyright (C)2009 Joe Heck, Nate Lowrie
#
# 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 Backlogs is a derivative work based on ChiliProject Backlogs.
# The copyright follows:
# Copyright (C) 2010-2011 - Emiliano Heyns, Mark Maglana, friflaj
# Copyright (C) 2011 - Jens Ulferts, Gregor Schmidt - Finn GmbH - Berlin, Germany
#
# 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 doc/COPYRIGHT.rdoc for more details.
#++
require 'spec_helper'
describe 'Filter by backlog type', js: true do
let(:story_type) do
type = FactoryGirl.create(:type_feature)
project.types << type
type
end
let(:task_type) do
type = FactoryGirl.create(:type_task)
project.types << type
type
end
let(:user) { FactoryGirl.create :admin }
let(:project) { FactoryGirl.create :project }
let(:wp_table) { ::Pages::WorkPackagesTable.new(project) }
let(:filters) { ::Components::WorkPackages::Filters.new }
let(:member) do
FactoryGirl.create(:member,
user: user,
project: project,
roles: [FactoryGirl.create(:role)])
end
let(:work_package_with_story_type) do
FactoryGirl.create(:work_package,
type: story_type,
project: project)
end
let(:work_package_with_task_type) do
FactoryGirl.create(:work_package,
type: task_type,
project: project)
end
before do
login_as(user)
work_package_with_task_type
work_package_with_story_type
allow(Setting)
.to receive(:plugin_openproject_backlogs)
.and_return('story_types' => [story_type.id.to_s],
'task_type' => task_type.id.to_s)
wp_table.visit!
end
it 'allows filtering, saving and retaining the filter' do
filters.open
filters.add_filter_by('Backlog type', 'is', 'Story', 'backlogsWorkPackageType')
expect(wp_table).to have_work_packages_listed [work_package_with_story_type]
expect(wp_table).not_to have_work_packages_listed [work_package_with_task_type]
wp_table.save_as('Some query name')
filters.remove_filter 'backlogsWorkPackageType'
expect(wp_table).to have_work_packages_listed [work_package_with_story_type, work_package_with_task_type]
last_query = Query.last
wp_table.visit_query(last_query)
expect(wp_table).to have_work_packages_listed [work_package_with_story_type]
expect(wp_table).not_to have_work_packages_listed [work_package_with_task_type]
filters.open
filters.expect_filter_by('Backlog type', 'is', 'Story', 'backlogsWorkPackageType')
end
end
Loading…
Cancel
Save