mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
Merge branch 'update-file-uploads' of github.com:makeplane/plane into update-file-uploads
This commit is contained in:
commit
14c6cc1420
@ -26,3 +26,31 @@ def delete_file_asset():
|
|||||||
file_asset.asset.delete(save=False)
|
file_asset.asset.delete(save=False)
|
||||||
# Delete the file object
|
# Delete the file object
|
||||||
file_asset.delete()
|
file_asset.delete()
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task
|
||||||
|
def file_asset_size(slug, email, members, issue_count, cycle_count, module_count):
|
||||||
|
asset_size = []
|
||||||
|
# s3_client = boto3.client('s3')
|
||||||
|
assets_to_update = []
|
||||||
|
|
||||||
|
# for asset in FileAsset.objects.filter(size__isnull=True):
|
||||||
|
# try:
|
||||||
|
# key = f"{workspace_id}/{asset_key}"
|
||||||
|
# response = s3_client.head_object(Bucket=settings.AWS_STORAGE_BUCKET_NAME, Key=key)
|
||||||
|
# size = response['ContentLength']
|
||||||
|
# asset.size = size
|
||||||
|
# assets_to_update.append(asset)
|
||||||
|
# except Exception as e:
|
||||||
|
# # Handle exceptions such as S3 object not found
|
||||||
|
# print(f"Error updating asset size for {asset.asset.key}: {e}")
|
||||||
|
|
||||||
|
# # Bulk update only objects that need updating
|
||||||
|
# FileAsset.objects.bulk_update(assets_to_update, ["size"], batch_size=50)
|
||||||
|
|
||||||
|
for asset in FileAsset.objects.filter(size__isnull=True):
|
||||||
|
asset.size = asset.asset.size
|
||||||
|
asset_size.append(asset)
|
||||||
|
|
||||||
|
FileAsset.objects.bulk_update(asset_size, ["size"], batch_size=50)
|
||||||
|
print("File asset size updated successfully")
|
||||||
|
23
apiserver/plane/db/management/commands/file_asset_size.py
Normal file
23
apiserver/plane/db/management/commands/file_asset_size.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Python imports
|
||||||
|
import getpass
|
||||||
|
|
||||||
|
# Django imports
|
||||||
|
from django.core.management import BaseCommand
|
||||||
|
|
||||||
|
# Module imports
|
||||||
|
from plane.db.models import User
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = "Check the file asset size of the file"
|
||||||
|
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
|
||||||
|
from plane.bgtasks.file_asset_task import file_asset_size
|
||||||
|
|
||||||
|
file_asset_size.delay()
|
||||||
|
|
||||||
|
self.stdout.write(
|
||||||
|
self.style.SUCCESS(f"File asset size pushed to queue")
|
||||||
|
)
|
@ -33,7 +33,7 @@ def convert_issue_description_image_sources(apps, schema_editor):
|
|||||||
src = img.get("src", "")
|
src = img.get("src", "")
|
||||||
if src and (src.startswith(prefix1)):
|
if src and (src.startswith(prefix1)):
|
||||||
img["src"] = (
|
img["src"] = (
|
||||||
f"/api/workspaces/{issue.workspace.slug}/projects/{issue.project_id}/issues/{issue.id}/attachments/{src[len(prefix1): ]}"
|
f"{src[len(prefix1): ]}"
|
||||||
)
|
)
|
||||||
file_assets[src[len(prefix1) :]] = {
|
file_assets[src[len(prefix1) :]] = {
|
||||||
"project_id": str(issue.project_id),
|
"project_id": str(issue.project_id),
|
||||||
@ -45,7 +45,7 @@ def convert_issue_description_image_sources(apps, schema_editor):
|
|||||||
# prefix 2
|
# prefix 2
|
||||||
if not settings.USE_MINIO and src and src.startswith(prefix2):
|
if not settings.USE_MINIO and src and src.startswith(prefix2):
|
||||||
img["src"] = (
|
img["src"] = (
|
||||||
f"/api/workspaces/{issue.workspace.slug}/projects/{issue.project_id}/issues/{issue.id}/attachments/{src[len(prefix2): ]}"
|
f"{src[len(prefix2): ]}"
|
||||||
)
|
)
|
||||||
file_assets[src[len(prefix2) :]] = {
|
file_assets[src[len(prefix2) :]] = {
|
||||||
"project_id": str(issue.project_id),
|
"project_id": str(issue.project_id),
|
||||||
@ -109,7 +109,7 @@ def convert_page_image_sources(apps, schema_editor):
|
|||||||
src = img.get("src", "")
|
src = img.get("src", "")
|
||||||
if src and (src.startswith(prefix1)):
|
if src and (src.startswith(prefix1)):
|
||||||
img["src"] = (
|
img["src"] = (
|
||||||
f"/api/workspaces/{page.workspace.slug}/projects/{page.project_id}/issues/{page.id}/attachments/{src[len(prefix1): ]}/"
|
f"{src[len(prefix1): ]}/"
|
||||||
)
|
)
|
||||||
file_assets[src[len(prefix1) :]] = {
|
file_assets[src[len(prefix1) :]] = {
|
||||||
"project_id": str(page.project_id),
|
"project_id": str(page.project_id),
|
||||||
@ -121,7 +121,7 @@ def convert_page_image_sources(apps, schema_editor):
|
|||||||
# prefix 2
|
# prefix 2
|
||||||
if not settings.USE_MINIO and src and src.startswith(prefix2):
|
if not settings.USE_MINIO and src and src.startswith(prefix2):
|
||||||
img["src"] = (
|
img["src"] = (
|
||||||
f"/api/workspaces/{page.workspace.slug}/projects/{page.project_id}/issues/{page.id}/attachments/{src[len(prefix2): ]}/"
|
f"{src[len(prefix2): ]}/"
|
||||||
)
|
)
|
||||||
file_assets[src[len(prefix2) :]] = {
|
file_assets[src[len(prefix2) :]] = {
|
||||||
"project_id": str(page.project_id),
|
"project_id": str(page.project_id),
|
||||||
@ -181,7 +181,7 @@ def convert_comment_image_sources(apps, schema_editor):
|
|||||||
src = img.get("src", "")
|
src = img.get("src", "")
|
||||||
if src and (src.startswith(prefix1)):
|
if src and (src.startswith(prefix1)):
|
||||||
img["src"] = (
|
img["src"] = (
|
||||||
f"/api/workspaces/{comment.workspace.slug}/projects/{comment.project_id}/issues/{comment.id}/attachments/{src[len(prefix1): ]}/"
|
f"{src[len(prefix1): ]}/"
|
||||||
)
|
)
|
||||||
file_assets[src[len(prefix1) :]] = {
|
file_assets[src[len(prefix1) :]] = {
|
||||||
"project_id": str(comment.project_id),
|
"project_id": str(comment.project_id),
|
||||||
@ -193,7 +193,7 @@ def convert_comment_image_sources(apps, schema_editor):
|
|||||||
# prefix 2
|
# prefix 2
|
||||||
if not settings.USE_MINIO and src and src.startswith(prefix2):
|
if not settings.USE_MINIO and src and src.startswith(prefix2):
|
||||||
img["src"] = (
|
img["src"] = (
|
||||||
f"/api/workspaces/{comment.workspace.slug}/projects/{comment.project_id}/issues/{comment.id}/attachments/{src[len(prefix2): ]}/"
|
f"{src[len(prefix2): ]}/"
|
||||||
)
|
)
|
||||||
file_assets[src[len(prefix2) :]] = {
|
file_assets[src[len(prefix2) :]] = {
|
||||||
"project_id": str(comment.project_id),
|
"project_id": str(comment.project_id),
|
||||||
|
@ -3,3 +3,5 @@ from .user import UserLiteSerializer
|
|||||||
from .issue import LabelLiteSerializer, StateLiteSerializer
|
from .issue import LabelLiteSerializer, StateLiteSerializer
|
||||||
|
|
||||||
from .state import StateSerializer, StateLiteSerializer
|
from .state import StateSerializer, StateLiteSerializer
|
||||||
|
|
||||||
|
from .asset import FileAssetSerializer
|
15
apiserver/plane/space/serializer/asset.py
Normal file
15
apiserver/plane/space/serializer/asset.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
from .base import BaseFileSerializer
|
||||||
|
from plane.db.models import FileAsset
|
||||||
|
|
||||||
|
|
||||||
|
class FileAssetSerializer(BaseFileSerializer):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = FileAsset
|
||||||
|
fields = "__all__"
|
||||||
|
read_only_fields = [
|
||||||
|
"created_by",
|
||||||
|
"updated_by",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
]
|
@ -56,3 +56,22 @@ class DynamicBaseSerializer(BaseSerializer):
|
|||||||
self.fields.pop(field_name)
|
self.fields.pop(field_name)
|
||||||
|
|
||||||
return self.fields
|
return self.fields
|
||||||
|
|
||||||
|
|
||||||
|
class BaseFileSerializer(DynamicBaseSerializer):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True # Make this serializer abstract
|
||||||
|
|
||||||
|
def to_representation(self, instance):
|
||||||
|
"""
|
||||||
|
Object instance -> Dict of primitive datatypes.
|
||||||
|
"""
|
||||||
|
response = super().to_representation(instance)
|
||||||
|
response[
|
||||||
|
"asset"
|
||||||
|
] = (
|
||||||
|
instance.asset.name
|
||||||
|
) # Ensure 'asset' field is consistently serialized
|
||||||
|
# Apply custom method to get download URL
|
||||||
|
return response
|
@ -36,6 +36,26 @@ urlpatterns = [
|
|||||||
),
|
),
|
||||||
name="issue-comments-project-board",
|
name="issue-comments-project-board",
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"workspaces/<str:slug>/projects/<uuid:project_id>/issues/<uuid:issue_id>/attachments/",
|
||||||
|
IssueAttachmentPublicEndpoint.as_view(),
|
||||||
|
name="project-issue-attachments",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"workspaces/<str:slug>/projects/<uuid:project_id>/issues/<uuid:issue_id>/attachments/<uuid:workspace_id>/<str:asset_key>/",
|
||||||
|
IssueAttachmentPublicEndpoint.as_view(),
|
||||||
|
name="project-issue-attachments",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"workspaces/<str:slug>/projects/<uuid:project_id>/comments/<uuid:comment_id>/attachments/",
|
||||||
|
CommentAssetPublicEndpoint.as_view(),
|
||||||
|
name="issue-comments-project-board-attachments",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"workspaces/<str:slug>/projects/<uuid:project_id>/comments/<uuid:comment_id>/attachments/<uuid:workspace_id>/<str:asset_key>/",
|
||||||
|
CommentAssetPublicEndpoint.as_view(),
|
||||||
|
name="issue-comments-project-board-attachments",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"workspaces/<str:slug>/project-boards/<uuid:project_id>/issues/<uuid:issue_id>/reactions/",
|
"workspaces/<str:slug>/project-boards/<uuid:project_id>/issues/<uuid:issue_id>/reactions/",
|
||||||
IssueReactionPublicViewSet.as_view(
|
IssueReactionPublicViewSet.as_view(
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
# Python imports
|
# Python imports
|
||||||
import json
|
import json
|
||||||
|
|
||||||
# Django imports
|
|
||||||
from django.core.serializers.json import DjangoJSONEncoder
|
from django.core.serializers.json import DjangoJSONEncoder
|
||||||
from django.db.models import (
|
from django.db.models import (
|
||||||
Case,
|
Case,
|
||||||
@ -18,10 +17,13 @@ from django.db.models import (
|
|||||||
When,
|
When,
|
||||||
)
|
)
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
|
|
||||||
|
# Django imports
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
# Third Party imports
|
# Third Party imports
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
|
from rest_framework.parsers import FormParser, JSONParser, MultiPartParser
|
||||||
from rest_framework.permissions import AllowAny, IsAuthenticated
|
from rest_framework.permissions import AllowAny, IsAuthenticated
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
@ -34,6 +36,7 @@ from plane.app.serializers import (
|
|||||||
IssueReactionSerializer,
|
IssueReactionSerializer,
|
||||||
IssueVoteSerializer,
|
IssueVoteSerializer,
|
||||||
)
|
)
|
||||||
|
from plane.app.views.base import BaseAPIView, BaseViewSet
|
||||||
from plane.bgtasks.issue_activites_task import issue_activity
|
from plane.bgtasks.issue_activites_task import issue_activity
|
||||||
from plane.db.models import (
|
from plane.db.models import (
|
||||||
CommentReaction,
|
CommentReaction,
|
||||||
@ -48,13 +51,12 @@ from plane.db.models import (
|
|||||||
ProjectMember,
|
ProjectMember,
|
||||||
ProjectPublicMember,
|
ProjectPublicMember,
|
||||||
State,
|
State,
|
||||||
|
Workspace,
|
||||||
)
|
)
|
||||||
from plane.utils.grouper import group_results
|
from plane.utils.grouper import group_results
|
||||||
from plane.utils.issue_filters import issue_filters
|
from plane.utils.issue_filters import issue_filters
|
||||||
from plane.utils.presigned_url_generator import generate_download_presigned_url
|
from plane.utils.presigned_url_generator import generate_download_presigned_url
|
||||||
|
|
||||||
from .base import BaseAPIView, BaseViewSet
|
|
||||||
|
|
||||||
|
|
||||||
class IssueCommentPublicViewSet(BaseViewSet):
|
class IssueCommentPublicViewSet(BaseViewSet):
|
||||||
serializer_class = IssueCommentSerializer
|
serializer_class = IssueCommentSerializer
|
||||||
@ -218,6 +220,182 @@ class IssueCommentPublicViewSet(BaseViewSet):
|
|||||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||||
|
|
||||||
|
|
||||||
|
class IssueAttachmentPublicEndpoint(BaseAPIView):
|
||||||
|
def get_permissions(self):
|
||||||
|
if self.action in ["get"]:
|
||||||
|
self.permission_classes = [
|
||||||
|
AllowAny,
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
self.permission_classes = [
|
||||||
|
IsAuthenticated,
|
||||||
|
]
|
||||||
|
|
||||||
|
return super(IssueAttachmentPublicEndpoint, self).get_permissions()
|
||||||
|
|
||||||
|
parser_classes = (
|
||||||
|
MultiPartParser,
|
||||||
|
FormParser,
|
||||||
|
JSONParser,
|
||||||
|
)
|
||||||
|
|
||||||
|
def post(self, request, slug, project_id, issue_id):
|
||||||
|
serializer = FileAssetSerializer(data=request.data)
|
||||||
|
workspace = Workspace.objects.get(slug=slug)
|
||||||
|
if serializer.is_valid():
|
||||||
|
serializer.save(
|
||||||
|
workspace=workspace,
|
||||||
|
project_id=project_id,
|
||||||
|
entity_identifier=issue_id,
|
||||||
|
)
|
||||||
|
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=request.META.get("HTTP_ORIGIN"),
|
||||||
|
)
|
||||||
|
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||||
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
def delete(
|
||||||
|
self, request, slug, project_id, issue_id, workspace_id, asset_key
|
||||||
|
):
|
||||||
|
key = f"{workspace_id}/{asset_key}"
|
||||||
|
asset = FileAsset.objects.get(
|
||||||
|
asset=key,
|
||||||
|
entity_identifier=issue_id,
|
||||||
|
entity_type="issue_attachment",
|
||||||
|
workspace__slug=slug,
|
||||||
|
project_id=project_id,
|
||||||
|
)
|
||||||
|
asset.is_deleted = True
|
||||||
|
asset.save()
|
||||||
|
issue_activity.delay(
|
||||||
|
type="attachment.activity.deleted",
|
||||||
|
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=None,
|
||||||
|
epoch=int(timezone.now().timestamp()),
|
||||||
|
notification=True,
|
||||||
|
origin=request.META.get("HTTP_ORIGIN"),
|
||||||
|
)
|
||||||
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||||
|
|
||||||
|
def get(
|
||||||
|
self,
|
||||||
|
request,
|
||||||
|
slug,
|
||||||
|
project_id,
|
||||||
|
issue_id,
|
||||||
|
workspace_id=None,
|
||||||
|
asset_key=None,
|
||||||
|
):
|
||||||
|
if workspace_id and asset_key:
|
||||||
|
key = f"{workspace_id}/{asset_key}"
|
||||||
|
url = generate_download_presigned_url(
|
||||||
|
key=key,
|
||||||
|
host=request.get_host(),
|
||||||
|
scheme=request.scheme,
|
||||||
|
)
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
# For listing
|
||||||
|
issue_attachments = FileAsset.objects.filter(
|
||||||
|
entity_type="issue_attachment",
|
||||||
|
entity_identifier=issue_id,
|
||||||
|
workspace__slug=slug,
|
||||||
|
project_id=project_id,
|
||||||
|
)
|
||||||
|
serializer = FileAssetSerializer(issue_attachments, many=True)
|
||||||
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
|
|
||||||
|
class CommentAssetPublicEndpoint(BaseAPIView):
|
||||||
|
def get_permissions(self):
|
||||||
|
if self.action in ["get"]:
|
||||||
|
self.permission_classes = [
|
||||||
|
AllowAny,
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
self.permission_classes = [
|
||||||
|
IsAuthenticated,
|
||||||
|
]
|
||||||
|
|
||||||
|
return super(CommentAssetPublicEndpoint, self).get_permissions()
|
||||||
|
|
||||||
|
parser_classes = (
|
||||||
|
MultiPartParser,
|
||||||
|
FormParser,
|
||||||
|
JSONParser,
|
||||||
|
)
|
||||||
|
|
||||||
|
def post(self, request, slug, project_id, comment_id):
|
||||||
|
serializer = FileAssetSerializer(data=request.data)
|
||||||
|
workspace = Workspace.objects.get(slug=slug)
|
||||||
|
if serializer.is_valid():
|
||||||
|
serializer.save(
|
||||||
|
workspace=workspace,
|
||||||
|
project_id=project_id,
|
||||||
|
entity_type="comment",
|
||||||
|
entity_identifier=comment_id,
|
||||||
|
)
|
||||||
|
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||||
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
def delete(
|
||||||
|
self, request, slug, project_id, comment_id, workspace_id, asset_key
|
||||||
|
):
|
||||||
|
key = f"{workspace_id}/{asset_key}"
|
||||||
|
asset = FileAsset.objects.get(
|
||||||
|
asset=key,
|
||||||
|
entity_identifier=comment_id,
|
||||||
|
entity_type="comment",
|
||||||
|
workspace__slug=slug,
|
||||||
|
project_id=project_id,
|
||||||
|
)
|
||||||
|
asset.is_deleted = True
|
||||||
|
asset.save()
|
||||||
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||||
|
|
||||||
|
def get(
|
||||||
|
self,
|
||||||
|
request,
|
||||||
|
slug,
|
||||||
|
project_id,
|
||||||
|
comment_id,
|
||||||
|
workspace_id=None,
|
||||||
|
asset_key=None,
|
||||||
|
):
|
||||||
|
if workspace_id and asset_key:
|
||||||
|
key = f"{workspace_id}/{asset_key}"
|
||||||
|
url = generate_download_presigned_url(
|
||||||
|
key=key,
|
||||||
|
host=request.get_host(),
|
||||||
|
scheme=request.scheme,
|
||||||
|
)
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
# For listing
|
||||||
|
comment_assets = FileAsset.objects.filter(
|
||||||
|
entity_type="comment",
|
||||||
|
entity_identifier=comment_id,
|
||||||
|
workspace__slug=slug,
|
||||||
|
project_id=project_id,
|
||||||
|
)
|
||||||
|
serializer = FileAssetSerializer(comment_assets, many=True)
|
||||||
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
|
|
||||||
class IssueReactionPublicViewSet(BaseViewSet):
|
class IssueReactionPublicViewSet(BaseViewSet):
|
||||||
serializer_class = IssueReactionSerializer
|
serializer_class = IssueReactionSerializer
|
||||||
model = IssueReaction
|
model = IssueReaction
|
||||||
@ -690,73 +868,3 @@ class ProjectIssuesPublicEndpoint(BaseAPIView):
|
|||||||
},
|
},
|
||||||
status=status.HTTP_200_OK,
|
status=status.HTTP_200_OK,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class IssueAttachmentPublicEndpoint(BaseAPIView):
|
|
||||||
|
|
||||||
permission_classes = [
|
|
||||||
AllowAny,
|
|
||||||
]
|
|
||||||
|
|
||||||
def get(
|
|
||||||
self,
|
|
||||||
request,
|
|
||||||
slug,
|
|
||||||
project_id,
|
|
||||||
issue_id,
|
|
||||||
workspace_id=None,
|
|
||||||
asset_key=None,
|
|
||||||
):
|
|
||||||
if workspace_id and asset_key:
|
|
||||||
key = f"{workspace_id}/{asset_key}"
|
|
||||||
url = generate_download_presigned_url(
|
|
||||||
key=key,
|
|
||||||
host=request.get_host(),
|
|
||||||
scheme=request.scheme,
|
|
||||||
)
|
|
||||||
return HttpResponseRedirect(url)
|
|
||||||
|
|
||||||
# For listing
|
|
||||||
issue_attachments = FileAsset.objects.filter(
|
|
||||||
entity_type="issue_attachment",
|
|
||||||
entity_identifier=issue_id,
|
|
||||||
workspace__slug=slug,
|
|
||||||
project_id=project_id,
|
|
||||||
)
|
|
||||||
serializer = FileAssetSerializer(issue_attachments, many=True)
|
|
||||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
|
|
||||||
class CommentAssetPublicEndpoint(BaseAPIView):
|
|
||||||
|
|
||||||
permission_classes = [
|
|
||||||
AllowAny,
|
|
||||||
]
|
|
||||||
|
|
||||||
def get(
|
|
||||||
self,
|
|
||||||
request,
|
|
||||||
slug,
|
|
||||||
project_id,
|
|
||||||
comment_id,
|
|
||||||
workspace_id=None,
|
|
||||||
asset_key=None,
|
|
||||||
):
|
|
||||||
if workspace_id and asset_key:
|
|
||||||
key = f"{workspace_id}/{asset_key}"
|
|
||||||
url = generate_download_presigned_url(
|
|
||||||
key=key,
|
|
||||||
host=request.get_host(),
|
|
||||||
scheme=request.scheme,
|
|
||||||
)
|
|
||||||
return HttpResponseRedirect(url)
|
|
||||||
|
|
||||||
# For listing
|
|
||||||
comment_assets = FileAsset.objects.filter(
|
|
||||||
entity_type="comment",
|
|
||||||
entity_identifier=comment_id,
|
|
||||||
workspace__slug=slug,
|
|
||||||
project_id=project_id,
|
|
||||||
)
|
|
||||||
serializer = FileAssetSerializer(comment_assets, many=True)
|
|
||||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
|
||||||
|
Loading…
Reference in New Issue
Block a user