ФУНКЦИИ - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: blob-дедупликация файлов
This commit is contained in:
@@ -116,6 +116,7 @@ class FileAssetSerializer(BaseSerializer):
|
||||
"page",
|
||||
"draft_issue",
|
||||
"user",
|
||||
"blob",
|
||||
"is_deleted",
|
||||
"deleted_at",
|
||||
"storage_metadata",
|
||||
|
||||
@@ -678,6 +678,7 @@ class IssueAttachmentSerializer(BaseSerializer):
|
||||
"workspace",
|
||||
"project",
|
||||
"issue",
|
||||
"blob",
|
||||
"updated_by",
|
||||
"updated_at",
|
||||
]
|
||||
|
||||
@@ -15,7 +15,6 @@ from rest_framework.response import Response
|
||||
from drf_spectacular.utils import OpenApiExample, OpenApiRequest
|
||||
|
||||
# Module Imports
|
||||
from plane.bgtasks.storage_metadata_task import get_asset_object_metadata
|
||||
from plane.settings.storage import S3Storage
|
||||
from plane.db.models import FileAsset, User, Workspace
|
||||
from plane.api.views.base import BaseAPIView
|
||||
@@ -44,6 +43,11 @@ from plane.utils.openapi import (
|
||||
)
|
||||
from plane.utils.exception_logger import log_exception
|
||||
from plane.utils.upload_limits import resolve_workspace_upload_size_limit
|
||||
from plane.utils.file_dedup import (
|
||||
UploadedObjectMissing,
|
||||
confirm_uploaded_file_asset,
|
||||
release_file_asset_blob,
|
||||
)
|
||||
|
||||
|
||||
class UserAssetEndpoint(BaseAPIView):
|
||||
@@ -53,9 +57,11 @@ class UserAssetEndpoint(BaseAPIView):
|
||||
asset = FileAsset.objects.filter(id=asset_id).first()
|
||||
if asset is None:
|
||||
return
|
||||
if not asset.is_uploaded:
|
||||
release_file_asset_blob(asset, delete_untracked_object=True)
|
||||
asset.is_deleted = True
|
||||
asset.deleted_at = timezone.now()
|
||||
asset.save(update_fields=["is_deleted", "deleted_at"])
|
||||
asset.save(update_fields=["is_deleted", "deleted_at", "updated_at"])
|
||||
return
|
||||
|
||||
def entity_asset_delete(self, entity_type, asset, request):
|
||||
@@ -209,15 +215,17 @@ class UserAssetEndpoint(BaseAPIView):
|
||||
"""
|
||||
# get the asset id
|
||||
asset = FileAsset.objects.get(id=asset_id, user_id=request.user.id)
|
||||
# get the storage metadata
|
||||
asset.is_uploaded = True
|
||||
# get the storage metadata
|
||||
if not asset.storage_metadata:
|
||||
get_asset_object_metadata.delay(asset_id=str(asset_id))
|
||||
# update the attributes
|
||||
asset.attributes = request.data.get("attributes", asset.attributes)
|
||||
# save the asset
|
||||
asset.save(update_fields=["is_uploaded", "attributes"])
|
||||
try:
|
||||
confirm_uploaded_file_asset(
|
||||
asset,
|
||||
request=request,
|
||||
attributes=request.data.get("attributes", asset.attributes),
|
||||
)
|
||||
except UploadedObjectMissing:
|
||||
return Response(
|
||||
{"error": "The uploaded asset object was not found.", "status": False},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
@asset_docs(
|
||||
@@ -236,11 +244,13 @@ class UserAssetEndpoint(BaseAPIView):
|
||||
This performs a soft delete by marking the asset as deleted and updating the user's profile.
|
||||
"""
|
||||
asset = FileAsset.objects.get(id=asset_id, user_id=request.user.id)
|
||||
if not asset.is_uploaded:
|
||||
release_file_asset_blob(asset, request=request, delete_untracked_object=True)
|
||||
asset.is_deleted = True
|
||||
asset.deleted_at = timezone.now()
|
||||
# get the entity and save the asset id for the request field
|
||||
self.entity_asset_delete(entity_type=asset.entity_type, asset=asset, request=request)
|
||||
asset.save(update_fields=["is_deleted", "deleted_at"])
|
||||
asset.save(update_fields=["is_deleted", "deleted_at", "updated_at"])
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
|
||||
@@ -251,9 +261,11 @@ class UserServerAssetEndpoint(BaseAPIView):
|
||||
asset = FileAsset.objects.filter(id=asset_id).first()
|
||||
if asset is None:
|
||||
return
|
||||
if not asset.is_uploaded:
|
||||
release_file_asset_blob(asset, delete_untracked_object=True)
|
||||
asset.is_deleted = True
|
||||
asset.deleted_at = timezone.now()
|
||||
asset.save(update_fields=["is_deleted", "deleted_at"])
|
||||
asset.save(update_fields=["is_deleted", "deleted_at", "updated_at"])
|
||||
return
|
||||
|
||||
def entity_asset_delete(self, entity_type, asset, request):
|
||||
@@ -365,15 +377,17 @@ class UserServerAssetEndpoint(BaseAPIView):
|
||||
"""
|
||||
# get the asset id
|
||||
asset = FileAsset.objects.get(id=asset_id, user_id=request.user.id)
|
||||
# get the storage metadata
|
||||
asset.is_uploaded = True
|
||||
# get the storage metadata
|
||||
if not asset.storage_metadata:
|
||||
get_asset_object_metadata.delay(asset_id=str(asset_id))
|
||||
# update the attributes
|
||||
asset.attributes = request.data.get("attributes", asset.attributes)
|
||||
# save the asset
|
||||
asset.save(update_fields=["is_uploaded", "attributes"])
|
||||
try:
|
||||
confirm_uploaded_file_asset(
|
||||
asset,
|
||||
request=request,
|
||||
attributes=request.data.get("attributes", asset.attributes),
|
||||
)
|
||||
except UploadedObjectMissing:
|
||||
return Response(
|
||||
{"error": "The uploaded asset object was not found.", "status": False},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
@asset_docs(
|
||||
@@ -393,11 +407,13 @@ class UserServerAssetEndpoint(BaseAPIView):
|
||||
asset as deleted and updating the user's profile.
|
||||
"""
|
||||
asset = FileAsset.objects.get(id=asset_id, user_id=request.user.id)
|
||||
if not asset.is_uploaded:
|
||||
release_file_asset_blob(asset, request=request, delete_untracked_object=True)
|
||||
asset.is_deleted = True
|
||||
asset.deleted_at = timezone.now()
|
||||
# get the entity and save the asset id for the request field
|
||||
self.entity_asset_delete(entity_type=asset.entity_type, asset=asset, request=request)
|
||||
asset.save(update_fields=["is_deleted", "deleted_at"])
|
||||
asset.save(update_fields=["is_deleted", "deleted_at", "updated_at"])
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
|
||||
@@ -604,15 +620,21 @@ class GenericAssetEndpoint(BaseAPIView):
|
||||
try:
|
||||
asset = FileAsset.objects.get(id=asset_id, workspace__slug=slug, is_deleted=False)
|
||||
|
||||
# Update is_uploaded status
|
||||
asset.is_uploaded = request.data.get("is_uploaded", asset.is_uploaded)
|
||||
|
||||
# Update storage metadata if not present
|
||||
if not asset.storage_metadata:
|
||||
get_asset_object_metadata.delay(asset_id=str(asset_id))
|
||||
|
||||
asset.save(update_fields=["is_uploaded"])
|
||||
if request.data.get("is_uploaded", asset.is_uploaded):
|
||||
confirm_uploaded_file_asset(
|
||||
asset,
|
||||
request=request,
|
||||
attributes=request.data.get("attributes"),
|
||||
)
|
||||
else:
|
||||
asset.is_uploaded = False
|
||||
asset.save(update_fields=["is_uploaded", "updated_at"])
|
||||
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
except FileAsset.DoesNotExist:
|
||||
return Response({"error": "Asset not found"}, status=status.HTTP_404_NOT_FOUND)
|
||||
except UploadedObjectMissing:
|
||||
return Response(
|
||||
{"error": "The uploaded asset object was not found.", "status": False},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
@@ -82,11 +82,11 @@ from plane.db.models import (
|
||||
Workspace,
|
||||
)
|
||||
from plane.settings.storage import S3Storage
|
||||
from plane.bgtasks.storage_metadata_task import get_asset_object_metadata
|
||||
from .base import BaseAPIView
|
||||
from plane.utils.host import base_host
|
||||
from plane.utils.issue_relation_mapper import get_actual_relation
|
||||
from plane.utils.attachment_preview import attachment_object_exists, get_attachment_preview_response
|
||||
from plane.utils.file_dedup import finalize_uploaded_file_asset, release_file_asset_blob, UploadedObjectMissing
|
||||
from plane.utils.upload_limits import resolve_workspace_upload_size_limit
|
||||
from plane.bgtasks.webhook_task import model_activity
|
||||
from plane.app.permissions import ROLE
|
||||
@@ -2020,9 +2020,11 @@ class IssueAttachmentDetailAPIEndpoint(BaseAPIView):
|
||||
)
|
||||
|
||||
issue_attachment = FileAsset.objects.get(pk=pk, workspace__slug=slug, project_id=project_id)
|
||||
if not issue_attachment.is_uploaded:
|
||||
release_file_asset_blob(issue_attachment, request=request, delete_untracked_object=True)
|
||||
issue_attachment.is_deleted = True
|
||||
issue_attachment.deleted_at = timezone.now()
|
||||
issue_attachment.save()
|
||||
issue_attachment.save(update_fields=["is_deleted", "deleted_at", "updated_at"])
|
||||
|
||||
issue_activity.delay(
|
||||
type="attachment.activity.deleted",
|
||||
@@ -2036,10 +2038,6 @@ class IssueAttachmentDetailAPIEndpoint(BaseAPIView):
|
||||
origin=base_host(request=request, is_app=True),
|
||||
)
|
||||
|
||||
# Get the storage metadata
|
||||
if not issue_attachment.storage_metadata:
|
||||
get_asset_object_metadata.delay(str(issue_attachment.id))
|
||||
issue_attachment.save()
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
@issue_attachment_docs(
|
||||
@@ -2174,14 +2172,16 @@ class IssueAttachmentDetailAPIEndpoint(BaseAPIView):
|
||||
origin=base_host(request=request, is_app=True),
|
||||
)
|
||||
|
||||
# Update the attachment
|
||||
issue_attachment.is_uploaded = True
|
||||
issue_attachment.created_by = request.user
|
||||
issue_attachment.save(update_fields=["created_by", "updated_at"])
|
||||
|
||||
# Get the storage metadata
|
||||
if not issue_attachment.storage_metadata:
|
||||
get_asset_object_metadata.delay(str(issue_attachment.id))
|
||||
issue_attachment.save()
|
||||
try:
|
||||
finalize_uploaded_file_asset(issue_attachment, request=request)
|
||||
except UploadedObjectMissing:
|
||||
return Response(
|
||||
{"error": "The uploaded attachment object was not found.", "status": False},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user