diff --git a/app/models/work_package_custom_fields/scopes/on_visible_type_and_project.rb b/app/models/work_package_custom_fields/scopes/on_visible_type_and_project.rb index 27aa76d8885..c584f539204 100644 --- a/app/models/work_package_custom_fields/scopes/on_visible_type_and_project.rb +++ b/app/models/work_package_custom_fields/scopes/on_visible_type_and_project.rb @@ -34,12 +34,10 @@ module WorkPackageCustomFields::Scopes class_methods do def on_visible_type_and_project(user = User.current) - with( - visible_projects: Project.visible(user) - ).where(<<~SQL.squish) + where(<<~SQL.squish) EXISTS ( SELECT 1 - FROM visible_projects vp + FROM (#{Project.visible(user).select(:id).to_sql}) vp JOIN projects_types pt ON pt.project_id = vp.id JOIN custom_fields_types cft diff --git a/docs/api/apiv3/paths/custom_field_item.yml b/docs/api/apiv3/paths/custom_field_item.yml index c1ac90dda38..5eabd3fba64 100644 --- a/docs/api/apiv3/paths/custom_field_item.yml +++ b/docs/api/apiv3/paths/custom_field_item.yml @@ -36,7 +36,10 @@ get: errorIdentifier: urn:openproject-org:api:v3:errors:MissingPermission message: You are not authorized to access this resource. '404': - description: Returned if the custom field item does not exist or the user is not logged in. + description: |- + Returned if the custom field item does not exist or the user lacks permission to see it. + + The permission required to view the item depends on the custom field it belongs to. content: application/hal+json: schema: diff --git a/docs/api/apiv3/paths/custom_field_item_branch.yml b/docs/api/apiv3/paths/custom_field_item_branch.yml index 9b84412b585..3518a98be46 100644 --- a/docs/api/apiv3/paths/custom_field_item_branch.yml +++ b/docs/api/apiv3/paths/custom_field_item_branch.yml @@ -38,7 +38,7 @@ get: errorIdentifier: urn:openproject-org:api:v3:errors:MissingPermission message: You are not authorized to access this resource. '404': - description: Returned if the custom field does not exist. + description: Returned if the custom field does not exist or the user lacks permission to view it. content: application/hal+json: schema: diff --git a/docs/api/apiv3/paths/custom_field_items.yml b/docs/api/apiv3/paths/custom_field_items.yml index e51e9e3bffe..01fe867ef90 100644 --- a/docs/api/apiv3/paths/custom_field_items.yml +++ b/docs/api/apiv3/paths/custom_field_items.yml @@ -62,7 +62,7 @@ get: errorIdentifier: urn:openproject-org:api:v3:errors:MissingPermission message: You are not authorized to access this resource. '404': - description: Returned if the custom field does not exist. + description: Returned if the custom field does not exist or the user lacks the permission to view it. content: application/hal+json: schema: diff --git a/lib/api/v3/custom_fields/custom_fields_api.rb b/lib/api/v3/custom_fields/custom_fields_api.rb index 64cc6b6514b..90b7a31fdaa 100644 --- a/lib/api/v3/custom_fields/custom_fields_api.rb +++ b/lib/api/v3/custom_fields/custom_fields_api.rb @@ -35,7 +35,7 @@ module API after_validation do authorize_logged_in - @custom_field = CustomField.find(params[:id]) + @custom_field = CustomField.visible.find(params[:id]) end mount Hierarchy::ItemsAPI diff --git a/lib/api/v3/custom_fields/hierarchy/item_api.rb b/lib/api/v3/custom_fields/hierarchy/item_api.rb index ab2574ec16b..a4ea81c1b64 100644 --- a/lib/api/v3/custom_fields/hierarchy/item_api.rb +++ b/lib/api/v3/custom_fields/hierarchy/item_api.rb @@ -37,6 +37,9 @@ module API authorize_logged_in @custom_field_item = CustomField::Hierarchy::Item.find(params[:id]) + + # Only for checking the authorization. + CustomField.visible.find(@custom_field_item.root.custom_field_id) end get &::API::V3::Utilities::Endpoints::Show diff --git a/spec/requests/api/v3/custom_fields/hierarchy/item_api_spec.rb b/spec/requests/api/v3/custom_fields/hierarchy/item_api_spec.rb index 39e72aafe49..2ab1e8ff3e5 100644 --- a/spec/requests/api/v3/custom_fields/hierarchy/item_api_spec.rb +++ b/spec/requests/api/v3/custom_fields/hierarchy/item_api_spec.rb @@ -33,7 +33,9 @@ require "spec_helper" RSpec.describe "API v3 custom field items", :webmock, content_type: :json, with_ee: [:custom_field_hierarchies] do include API::V3::Utilities::PathHelper - let(:custom_field) { create(:custom_field, field_format: "hierarchy", hierarchy_root: nil) } + shared_let(:project) { create(:project) } + + let(:custom_field) { create(:wp_custom_field, field_format: "hierarchy", hierarchy_root: nil) } let(:service) { CustomFields::Hierarchy::HierarchicalItemService.new } let!(:root) { service.generate_root(custom_field).value! } let(:contract_class) { CustomFields::Hierarchy::InsertListItemContract } @@ -52,8 +54,14 @@ RSpec.describe "API v3 custom field items", :webmock, content_type: :json, with_ it_behaves_like "unauthenticated access" end - context "if user is logged in" do - before { login_as create(:user) } + context "if user is logged in but lacks permissions" do + current_user { create(:user, member_with_permissions: { project => [] }) } + + it_behaves_like "not found" + end + + context "if user is logged in with the necessary permissions" do + current_user { create(:user, member_with_permissions: { project => [:select_custom_fields] }) } it_behaves_like "successful response" @@ -78,8 +86,14 @@ RSpec.describe "API v3 custom field items", :webmock, content_type: :json, with_ it_behaves_like "unauthenticated access" end - context "if user is logged in" do - before { login_as create(:user) } + context "if user is logged in but lacks permissions" do + current_user { create(:user, member_with_permissions: { project => [] }) } + + it_behaves_like "not found" + end + + context "if user is logged in with the necessary permissions" do + current_user { create(:user, member_with_permissions: { project => [:select_custom_fields] }) } it_behaves_like "API V3 collection response", 4, 4, "HierarchyItem", "Collection" do let(:elements) { [root, luke, r2d2, mouse] } diff --git a/spec/requests/api/v3/custom_fields/hierarchy/items_api_spec.rb b/spec/requests/api/v3/custom_fields/hierarchy/items_api_spec.rb index 4907ef5557b..11060112c83 100644 --- a/spec/requests/api/v3/custom_fields/hierarchy/items_api_spec.rb +++ b/spec/requests/api/v3/custom_fields/hierarchy/items_api_spec.rb @@ -34,7 +34,9 @@ RSpec.describe "API v3 custom field hierarchy items", :webmock, content_type: :j include API::V3::Utilities::PathHelper describe "GET /api/v3/custom_fields/:id/items" do - let(:custom_field) { create(:custom_field, field_format: "hierarchy", hierarchy_root: nil) } + shared_let(:project) { create(:project) } + + let(:custom_field) { create(:wp_custom_field, field_format: "hierarchy", hierarchy_root: nil) } let!(:root) { service.generate_root(custom_field).value! } let(:contract_class) { CustomFields::Hierarchy::InsertListItemContract } let!(:luke) { service.insert_item(contract_class:, parent: root, label: "Luke", short: "LS").value! } @@ -52,8 +54,14 @@ RSpec.describe "API v3 custom field hierarchy items", :webmock, content_type: :j it_behaves_like "unauthenticated access" end - context "if user is logged in" do - before { login_as create(:user) } + context "if the user is not allowed to view the custom field" do + current_user { create(:user, member_with_permissions: { project => [] }) } + + it_behaves_like "not found" + end + + context "if user is logged in with the necessary permissions" do + current_user { create(:user, member_with_permissions: { project => [:select_custom_fields] }) } it_behaves_like "API V3 collection response", 6, 6, "HierarchyItem", "Collection" do let(:elements) { [root, luke, r2d2, mouse, c3po, mara] }