ARCH - TASKER BIM: серверный CAD-шлюз и независимый просмотр из Ops

This commit is contained in:
DCCONSTRUCTIONS
2026-07-30 07:35:23 +03:00
parent 24481ea432
commit ad04910209
10 changed files with 1252 additions and 499 deletions
@@ -27,6 +27,7 @@ from plane.utils.host import base_host
from plane.utils.upload_limits import get_project_storage_quota_response, resolve_workspace_upload_size_limit
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.nodedc_bim_gateway import BimGatewayError, bim_gateway_request, get_bim_registry_identity
class IssueAttachmentEndpoint(BaseAPIView):
@@ -109,12 +110,6 @@ class IssueAttachmentV2Endpoint(BaseAPIView):
name = request.data.get("name")
type = request.data.get("type", False)
size = int(request.data.get("size", settings.FILE_SIZE_LIMIT))
beam_viewer = request.data.get("beamViewer")
is_beam_viewer_reference = (
isinstance(beam_viewer, dict)
and beam_viewer.get("src")
and beam_viewer.get("downloadUrl")
)
if not type or type not in settings.ATTACHMENT_MIME_TYPES:
return Response(
@@ -126,45 +121,6 @@ class IssueAttachmentV2Endpoint(BaseAPIView):
workspace = Workspace.objects.get(slug=slug)
project = Project.objects.get(id=project_id, workspace=workspace)
if is_beam_viewer_reference:
asset = FileAsset.objects.create(
attributes={
"name": name,
"type": type,
"size": size,
"beamViewer": beam_viewer,
},
asset=f"{workspace.id}/beam-viewer/{uuid.uuid4().hex}-{name}",
size=0,
workspace_id=workspace.id,
created_by=request.user,
issue_id=issue_id,
project_id=project_id,
entity_type=FileAsset.EntityTypeContext.ISSUE_ATTACHMENT,
is_uploaded=True,
external_source="beam-viewer",
)
serializer = IssueAttachmentSerializer(asset)
issue_activity.delay(
type="attachment.activity.created",
requested_data=None,
actor_id=str(self.request.user.id),
issue_id=str(self.kwargs.get("issue_id", None)),
project_id=str(self.kwargs.get("project_id", None)),
current_instance=json.dumps(serializer.data, cls=DjangoJSONEncoder),
epoch=int(timezone.now().timestamp()),
notification=True,
origin=base_host(request=request, is_app=True),
)
return Response(
{
"asset_id": str(asset.id),
"attachment": serializer.data,
"asset_url": asset.asset_url,
},
status=status.HTTP_200_OK,
)
# asset key
asset_key = f"{workspace.id}/{uuid.uuid4().hex}-{name}"
@@ -205,7 +161,32 @@ class IssueAttachmentV2Endpoint(BaseAPIView):
@allow_permission([ROLE.ADMIN], creator=True, model=FileAsset)
def delete(self, request, slug, project_id, issue_id, pk):
issue_attachment = FileAsset.objects.get(pk=pk, workspace__slug=slug, project_id=project_id)
issue_attachment = FileAsset.objects.select_related("created_by").get(
pk=pk,
workspace__slug=slug,
project_id=project_id,
issue_id=issue_id,
)
attributes = issue_attachment.attributes if isinstance(issue_attachment.attributes, dict) else {}
beam_viewer = attributes.get("beamViewer")
if issue_attachment.external_source == "beam-viewer" and isinstance(beam_viewer, dict):
try:
bim_gateway_request(
"DELETE",
"/api/uploads/asset",
identity=get_bim_registry_identity(issue_attachment, beam_viewer),
json_payload=beam_viewer,
)
except BimGatewayError as error:
return Response(
{
"ok": False,
"error": error.code,
"message": error.message,
**({"upstream_status": error.upstream_status} if error.upstream_status else {}),
},
status=error.status_code,
)
if not issue_attachment.is_uploaded:
release_file_asset_blob(issue_attachment, request=request, delete_untracked_object=True)
issue_attachment.is_deleted = True
@@ -256,28 +237,22 @@ class IssueAttachmentV2Endpoint(BaseAPIView):
@allow_permission([ROLE.ADMIN, ROLE.MEMBER])
def patch(self, request, slug, project_id, issue_id, pk):
issue_attachment = FileAsset.objects.get(pk=pk, workspace__slug=slug, project_id=project_id)
issue_attachment = FileAsset.objects.get(
pk=pk,
workspace__slug=slug,
project_id=project_id,
issue_id=issue_id,
entity_type=FileAsset.EntityTypeContext.ISSUE_ATTACHMENT,
)
beam_viewer = request.data.get("beamViewer")
if isinstance(beam_viewer, dict):
attributes = issue_attachment.attributes or {}
existing_beam_viewer = attributes.get("beamViewer")
if not isinstance(existing_beam_viewer, dict):
return Response(
{"error": "The attachment is not a BIM Viewer reference.", "status": False},
status=status.HTTP_400_BAD_REQUEST,
)
attributes["beamViewer"] = {
**existing_beam_viewer,
**beam_viewer,
}
for attribute_key in ("name", "size", "type", "version"):
if attribute_key in request.data:
attributes[attribute_key] = request.data.get(attribute_key)
issue_attachment.attributes = attributes
issue_attachment.is_uploaded = True
issue_attachment.save(update_fields=["attributes", "is_uploaded", "updated_at"])
return Response(IssueAttachmentSerializer(issue_attachment).data, status=status.HTTP_200_OK)
return Response(
{
"error": "BIM attachments are managed by the Ops BIM gateway.",
"status": False,
},
status=status.HTTP_400_BAD_REQUEST,
)
serializer = IssueAttachmentSerializer(issue_attachment)
if not attachment_object_exists(issue_attachment):