mirror of
https://github.com/makeplane/plane.git
synced 2026-07-11 04:51:55 +02:00
[WEB-8066] refactor: return bool from asset access helper, build Response in views
Address review (Saurabhkmr98): rename project_membership_denied -> has_project_asset_access, returning a boolean (True = allowed) instead of a Response. Each of get/patch/delete now builds the 403 Response based on the returned value. Behaviour is unchanged (same 403 + message; workspace-level assets with project_id=None still allowed). Co-authored-by: Plane AI <noreply@plane.so>
This commit is contained in:
@@ -312,35 +312,29 @@ class WorkspaceFileAssetEndpoint(BaseAPIView):
|
||||
else:
|
||||
return
|
||||
|
||||
def project_membership_denied(self, request, asset):
|
||||
"""Enforce project-level access on a workspace-scoped asset lookup.
|
||||
def has_project_asset_access(self, request, asset):
|
||||
"""Return whether the user may access a workspace-scoped asset.
|
||||
|
||||
This endpoint is authorized at the WORKSPACE level, so a workspace
|
||||
member/guest could otherwise reach an asset that belongs to a project
|
||||
they are not a member of. For project-bound assets, require an active
|
||||
ProjectMember of the asset's project. Workspace-level entity types
|
||||
(WORKSPACE_LOGO, USER_AVATAR, USER_COVER) have project_id=None and are
|
||||
exempt. Returns a 403 Response when access is denied, else None.
|
||||
always allowed.
|
||||
"""
|
||||
if asset.project_id is None:
|
||||
return None
|
||||
return True
|
||||
# Scope the membership lookup to the asset's workspace as well as its
|
||||
# project, mirroring allow_permission's PROJECT branch. This prevents a
|
||||
# member of the same project in a different workspace from passing the
|
||||
# check should an asset row ever be inconsistent (asset.workspace_id !=
|
||||
# asset.project.workspace_id).
|
||||
is_project_member = ProjectMember.objects.filter(
|
||||
return ProjectMember.objects.filter(
|
||||
member=request.user,
|
||||
workspace_id=asset.workspace_id,
|
||||
project_id=asset.project_id,
|
||||
is_active=True,
|
||||
).exists()
|
||||
if not is_project_member:
|
||||
return Response(
|
||||
{"error": "You don't have access to this asset."},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
return None
|
||||
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST], level="WORKSPACE")
|
||||
def post(self, request, slug):
|
||||
@@ -424,9 +418,11 @@ class WorkspaceFileAssetEndpoint(BaseAPIView):
|
||||
# get the asset id
|
||||
asset = FileAsset.objects.get(id=asset_id, workspace__slug=slug)
|
||||
# enforce project-level access for project-bound assets
|
||||
denied = self.project_membership_denied(request, asset)
|
||||
if denied is not None:
|
||||
return denied
|
||||
if not self.has_project_asset_access(request, asset):
|
||||
return Response(
|
||||
{"error": "You don't have access to this asset."},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
# get the storage metadata
|
||||
asset.is_uploaded = True
|
||||
# get the storage metadata
|
||||
@@ -449,9 +445,11 @@ class WorkspaceFileAssetEndpoint(BaseAPIView):
|
||||
def delete(self, request, slug, asset_id):
|
||||
asset = FileAsset.objects.get(id=asset_id, workspace__slug=slug)
|
||||
# enforce project-level access for project-bound assets
|
||||
denied = self.project_membership_denied(request, asset)
|
||||
if denied is not None:
|
||||
return denied
|
||||
if not self.has_project_asset_access(request, asset):
|
||||
return Response(
|
||||
{"error": "You don't have access to this asset."},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
asset.is_deleted = True
|
||||
asset.deleted_at = timezone.now()
|
||||
# get the entity and save the asset id for the request field
|
||||
@@ -464,9 +462,11 @@ class WorkspaceFileAssetEndpoint(BaseAPIView):
|
||||
# get the asset id
|
||||
asset = FileAsset.objects.get(id=asset_id, workspace__slug=slug)
|
||||
# enforce project-level access for project-bound assets
|
||||
denied = self.project_membership_denied(request, asset)
|
||||
if denied is not None:
|
||||
return denied
|
||||
if not self.has_project_asset_access(request, asset):
|
||||
return Response(
|
||||
{"error": "You don't have access to this asset."},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
|
||||
# Check if the asset is uploaded
|
||||
if not asset.is_uploaded:
|
||||
|
||||
Reference in New Issue
Block a user