From 4fedb5bee81016b1241351996d3b3ead88dbbe58 Mon Sep 17 00:00:00 2001 From: Christophe Bliard Date: Thu, 9 Jan 2025 15:33:14 +0100 Subject: [PATCH] [60479] Only show relations the user has permission to see --- .../work_package_relations_controller.rb | 11 +-- .../work_package_relations_tab_controller.rb | 3 +- config/initializers/menus.rb | 2 +- .../relations/primerized_relations_spec.rb | 78 ++++++++++++++++--- .../components/work_packages/relations.rb | 4 +- 5 files changed, 81 insertions(+), 17 deletions(-) diff --git a/app/controllers/work_package_relations_controller.rb b/app/controllers/work_package_relations_controller.rb index 837e4e10a190..6be607a1669d 100644 --- a/app/controllers/work_package_relations_controller.rb +++ b/app/controllers/work_package_relations_controller.rb @@ -62,8 +62,8 @@ def create if service_result.success? @work_package.reload component = WorkPackageRelationsTab::IndexComponent.new(work_package: @work_package, - relations: @work_package.relations, - children: @work_package.children) + relations: @work_package.relations.visible, + children: @work_package.children.visible) replace_via_turbo_stream(component:) respond_with_turbo_streams else @@ -80,8 +80,8 @@ def update if service_result.success? @work_package.reload component = WorkPackageRelationsTab::IndexComponent.new(work_package: @work_package, - relations: @work_package.relations, - children: @work_package.children) + relations: @work_package.relations.visible, + children: @work_package.children.visible) replace_via_turbo_stream(component:) respond_with_turbo_streams else @@ -93,11 +93,12 @@ def destroy service_result = Relations::DeleteService.new(user: current_user, model: @relation).call if service_result.success? - @children = WorkPackage.where(parent_id: @work_package.id) + @children = WorkPackage.where(parent_id: @work_package.id).visible @relations = @work_package .relations .reload .includes(:to, :from) + .visible component = WorkPackageRelationsTab::IndexComponent.new(work_package: @work_package, relations: @relations, diff --git a/app/controllers/work_package_relations_tab_controller.rb b/app/controllers/work_package_relations_tab_controller.rb index c8d9ab9ad75b..f457a67fd936 100644 --- a/app/controllers/work_package_relations_tab_controller.rb +++ b/app/controllers/work_package_relations_tab_controller.rb @@ -33,9 +33,10 @@ class WorkPackageRelationsTabController < ApplicationController before_action :authorize_global def index - @children = WorkPackage.where(parent_id: @work_package.id) + @children = WorkPackage.where(parent_id: @work_package.id).visible @relations = @work_package .relations + .visible .includes(:to, :from) component = WorkPackageRelationsTab::IndexComponent.new( diff --git a/config/initializers/menus.rb b/config/initializers/menus.rb index 33bdb9cd0d25..b8a026f54822 100644 --- a/config/initializers/menus.rb +++ b/config/initializers/menus.rb @@ -675,7 +675,7 @@ { tab: :relations }, skip_permissions_check: true, badge: ->(work_package:, **) { - work_package.relations.count + work_package.children.count + work_package.relations.visible.count + work_package.children.visible.count }, caption: :"js.work_packages.tabs.relations" menu.push :watchers, diff --git a/spec/features/work_packages/details/relations/primerized_relations_spec.rb b/spec/features/work_packages/details/relations/primerized_relations_spec.rb index ea86ee42cb9a..e15ff4192ccb 100644 --- a/spec/features/work_packages/details/relations/primerized_relations_spec.rb +++ b/spec/features/work_packages/details/relations/primerized_relations_spec.rb @@ -32,8 +32,16 @@ :js, :with_cuprite do include Components::Autocompleter::NgSelectAutocompleteHelpers - shared_let(:user) { create(:admin) } shared_let(:project) { create(:project) } + shared_let(:user) do + create(:user, + member_with_permissions: { + project => %i[add_work_packages + manage_subtasks + manage_work_package_relations + view_work_packages] + }) + end before_all do set_factory_default(:user, user) @@ -41,17 +49,17 @@ set_factory_default(:project_with_types, project) end - shared_let(:parent_work_package) { create(:work_package, subject: "parent") } - shared_let(:work_package) { create(:work_package, subject: "main", parent: parent_work_package) } + shared_let(:parent_work_package) { create(:work_package, subject: "parent_work_package") } + shared_let(:work_package) { create(:work_package, subject: "work_package (main)", parent: parent_work_package) } shared_let(:type1) { create(:type) } shared_let(:type2) { create(:type) } shared_let(:wp_predecessor) do - create(:work_package, type: type1, subject: "predecessor of main", + create(:work_package, type: type1, subject: "wp_predecessor", start_date: Date.current, due_date: Date.current + 1.week) end - shared_let(:wp_related) { create(:work_package, type: type2, subject: "related to main") } - shared_let(:wp_blocker) { create(:work_package, type: type1, subject: "blocks main") } + shared_let(:wp_related) { create(:work_package, type: type2, subject: "wp_related") } + shared_let(:wp_blocker) { create(:work_package, type: type1, subject: "wp_blocker") } shared_let(:relation_follows) do create(:relation, @@ -73,16 +81,39 @@ end shared_let(:child_wp) do create(:work_package, + subject: "child_wp", parent: work_package, type: type1, project: project) end - shared_let(:not_yet_child_wp) do + shared_let(:not_child_yet_wp) do create(:work_package, + subject: "not_child_yet_wp", type: type1, project:) end + # The user should not be able to see any relations to work packages from this + # project because the user does not have the permissions to view this project + shared_let(:restricted_project) { create(:project) } + shared_let(:restricted_work_package) do + create(:work_package, + subject: "restricted_work_package", + project: restricted_project) + end + shared_let(:restricted_child_work_package) do + create(:work_package, + subject: "restricted_child_work_package", + parent: work_package, + project: restricted_project) + end + shared_let(:restricted_relation_relates) do + create(:relation, + from: work_package, + to: restricted_work_package, + relation_type: Relation::TYPE_RELATES) + end + let(:full_wp_view) { Pages::FullWorkPackage.new(work_package) } let(:relations_tab) { Components::WorkPackages::Relations.new(work_package) } let(:relations_panel_selector) { ".detail-panel--relations" } @@ -116,6 +147,10 @@ def label_for_relation_type(relation_type) relations_tab.expect_relation(relation_follows) relations_tab.expect_relation(relation_relates) relations_tab.expect_relation(relation_blocked) + + # Relations not visible due to lack of permissions on the project + relations_tab.expect_no_relation(restricted_relation_relates) + relations_tab.expect_no_relation(restricted_child_work_package) end end @@ -130,6 +165,10 @@ def label_for_relation_type(relation_type) expect { relation_follows.reload }.to raise_error(ActiveRecord::RecordNotFound) tabs.expect_counter("relations", 3) + + # Relations not visible due to lack of permissions on the project + relations_tab.expect_no_relation(restricted_relation_relates) + relations_tab.expect_no_relation(restricted_child_work_package) end it "can delete children" do @@ -141,6 +180,10 @@ def label_for_relation_type(relation_type) expect(child_wp.reload.parent).to be_nil tabs.expect_counter("relations", 3) + + # Relations not visible due to lack of permissions on the project + relations_tab.expect_no_relation(restricted_relation_relates) + relations_tab.expect_no_relation(restricted_child_work_package) end end @@ -159,6 +202,8 @@ def label_for_relation_type(relation_type) # Unchanged tabs.expect_counter("relations", 4) + relations_tab.expect_no_relation(restricted_relation_relates) + relations_tab.expect_no_relation(restricted_child_work_package) # Edit again relations_tab.edit_relation_description(relation_follows, "And they can be edited!") @@ -168,6 +213,10 @@ def label_for_relation_type(relation_type) # Unchanged tabs.expect_counter("relations", 4) + + # Relations not visible due to lack of permissions on the project + relations_tab.expect_no_relation(restricted_relation_relates) + relations_tab.expect_no_relation(restricted_child_work_package) end it "does not have an edit action for children" do @@ -231,6 +280,10 @@ def label_for_relation_type(relation_type) tabs.expect_counter("relations", 5) # Relation is created expect(Relation.follows.where(from: wp_successor, to: work_package)).to exist + + # Relations not visible due to lack of permissions on the project + relations_tab.expect_no_relation(restricted_relation_relates) + relations_tab.expect_no_relation(restricted_child_work_package) end it "does not autocomplete unrelatable work packages" do @@ -263,11 +316,18 @@ def label_for_relation_type(relation_type) tabs.expect_counter("relations", 4) - relations_tab.add_existing_child(not_yet_child_wp) - relations_tab.expect_child(not_yet_child_wp) + relations_tab.add_existing_child(not_child_yet_wp) + relations_tab.expect_child(not_child_yet_wp) # Bumped by one tabs.expect_counter("relations", 5) + + # Child relation is created + expect(not_child_yet_wp.reload.parent).to eq work_package + + # Relations not visible due to lack of permissions on the project + relations_tab.expect_no_relation(restricted_relation_relates) + relations_tab.expect_no_relation(restricted_child_work_package) end it "doesn't autocomplete parent, children, and WP itself" do diff --git a/spec/support/components/work_packages/relations.rb b/spec/support/components/work_packages/relations.rb index 79ee9f1274ac..425b376a716d 100644 --- a/spec/support/components/work_packages/relations.rb +++ b/spec/support/components/work_packages/relations.rb @@ -77,7 +77,9 @@ def expect_row(work_package) def expect_no_row(relatable) actual_relatable = find_relatable(relatable) - expect(page).not_to have_test_selector("op-relation-row-#{actual_relatable.id}") + expect(page).not_to have_test_selector("op-relation-row-#{actual_relatable.id}"), + "expected no relation row for work package " \ + "##{actual_relatable.id} #{actual_relatable.subject.inspect}" end def select_relation_type(relation_type)