diff --git a/app/models/principal.rb b/app/models/principal.rb index 829169ba76..bfe3ec4947 100644 --- a/app/models/principal.rb +++ b/app/models/principal.rb @@ -77,7 +77,7 @@ class Principal < ApplicationRecord scope :not_in_project, ->(project) { where.not(id: Member.of(project).select(:user_id)) } - + scope :in_group, ->(group) { within_group(group) } diff --git a/app/models/queries/principals/filters/member_filter.rb b/app/models/queries/principals/filters/member_filter.rb index f4303f76bc..1ccb596aa8 100644 --- a/app/models/queries/principals/filters/member_filter.rb +++ b/app/models/queries/principals/filters/member_filter.rb @@ -44,18 +44,21 @@ class Queries::Principals::Filters::MemberFilter < Queries::Principals::Filters: end def scope - default_scope = Principal.includes(:members) - case operator when '=' - default_scope.where(members: { project_id: values }) + Principal.in_project(values) when '!' - default_scope.where.not(members: { project_id: values }) - .or(default_scope.where(members: { project_id: nil })) + Principal.not_in_project(values) when '*' - default_scope.where.not(members: { project_id: nil }) + member_included_scope.where.not(members: { id: nil }) when '!*' - default_scope.where.not(id: Member.select(:user_id).uniq) + member_included_scope.where.not(id: Member.distinct(:user_id).select(:user_id)) end end + + private + + def member_included_scope + Principal.includes(:members) + end end diff --git a/docs/development/create-openproject-plugin/README.md b/docs/development/create-openproject-plugin/README.md index 94b4c3ba04..ce3b736636 100644 --- a/docs/development/create-openproject-plugin/README.md +++ b/docs/development/create-openproject-plugin/README.md @@ -38,6 +38,10 @@ Once you've done that install it via bundle install ``` +### Production + +To use your plugin in production you have to add it to your [docker](../../installation-and-operations/installation/docker/#openproject-plugins) container or install it in the [packaged installation](../../installation-and-operations/configuration/plugins/#adding-plugins-debrpm-packages). + ## Start coding You may have a look at some existing OpenProject plugins to get inspiration. It is possible to add new routes, views, models, … and/or overwrite existing ones. diff --git a/spec/models/queries/principals/principal_query_integrations_spec.rb b/spec/models/queries/principals/principal_query_integrations_spec.rb new file mode 100644 index 0000000000..de71305203 --- /dev/null +++ b/spec/models/queries/principals/principal_query_integrations_spec.rb @@ -0,0 +1,88 @@ +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2021 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-2013 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::Principals::PrincipalQuery, 'integration', type: :model do + let(:current_user) { FactoryBot.create(:user) } + let(:instance) { described_class.new } + + before do + login_as(current_user) + end + + context 'with a member filter' do + let(:project) { FactoryBot.create(:project) } + let(:role) { FactoryBot.create(:role) } + let(:project_user) do + FactoryBot.create(:user, + member_in_project: project, + member_through_role: role) do |u| + # Granting another membership in order to better test the "not" filter + FactoryBot.create(:member, + principal: u, + project: other_project, + roles: [role]) + end + end + let(:other_project) { FactoryBot.create(:project) } + let(:other_project_user) do + FactoryBot.create(:user, + member_in_project: other_project, + member_through_role: role) + end + + let(:users) { [current_user, project_user, other_project_user] } + + before do + users + end + + context 'with the = operator' do + before do + instance.where('member', '=', [project.id.to_s]) + end + + it 'returns all principals being member' do + expect(instance.results) + .to match_array [project_user] + end + end + + context 'with the ! operator' do + before do + instance.where('member', '!', [project.id.to_s]) + end + + it 'returns all principals not being member' do + expect(instance.results) + .to match_array [current_user, other_project_user] + end + end + end +end