dev: update attachments for issues

This commit is contained in:
pablohashescobar 2024-02-05 14:30:49 +05:30
parent cedc08bc08
commit 02e5e0da4b
25 changed files with 193 additions and 287 deletions

View File

@ -5,9 +5,7 @@ from .issue import (
IssueSerializer,
LabelSerializer,
IssueLinkSerializer,
IssueAttachmentSerializer,
IssueCommentSerializer,
IssueAttachmentSerializer,
IssueActivitySerializer,
IssueExpandSerializer,
)

View File

@ -17,7 +17,6 @@ from plane.db.models import (
IssueLabel,
IssueLink,
IssueComment,
IssueAttachment,
IssueActivity,
ProjectMember,
)
@ -296,22 +295,6 @@ class IssueLinkSerializer(BaseSerializer):
return IssueLink.objects.create(**validated_data)
class IssueAttachmentSerializer(BaseSerializer):
class Meta:
model = IssueAttachment
fields = "__all__"
read_only_fields = [
"id",
"workspace",
"project",
"issue",
"created_by",
"updated_by",
"created_at",
"updated_at",
]
class IssueCommentSerializer(BaseSerializer):
is_member = serializers.BooleanField(read_only=True)

View File

@ -17,7 +17,7 @@ from plane.db.models import (
Issue,
CycleIssue,
IssueLink,
IssueAttachment,
FileAsset,
)
from plane.app.permissions import ProjectEntityPermission
from plane.api.serializers import (
@ -390,8 +390,9 @@ class CycleIssueAPIEndpoint(WebhookMixin, BaseAPIView):
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
attachment_count=FileAsset.objects.filter(
entity_identifier=OuterRef("id"),
entity_type="issue_attachment",
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))

View File

@ -31,13 +31,13 @@ from plane.app.permissions import (
)
from plane.db.models import (
Issue,
IssueAttachment,
IssueLink,
Project,
Label,
ProjectMember,
IssueComment,
IssueActivity,
FileAsset,
)
from plane.bgtasks.issue_activites_task import issue_activity
from plane.api.serializers import (
@ -126,8 +126,9 @@ class IssueAPIEndpoint(WebhookMixin, BaseAPIView):
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
attachment_count=FileAsset.objects.filter(
entity_identifier=OuterRef("id"),
entity_type="issue_attachment",
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))

View File

@ -19,8 +19,8 @@ from plane.db.models import (
ModuleLink,
Issue,
ModuleIssue,
IssueAttachment,
IssueLink,
FileAsset,
)
from plane.api.serializers import (
ModuleSerializer,
@ -273,8 +273,9 @@ class ModuleIssueAPIEndpoint(WebhookMixin, BaseAPIView):
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
attachment_count=FileAsset.objects.filter(
entity_identifier=OuterRef("id"),
entity_type="issue_attachment",
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))

View File

@ -60,7 +60,6 @@ from .issue import (
IssueStateSerializer,
IssueLinkSerializer,
IssueLiteSerializer,
IssueAttachmentSerializer,
IssueSubscriberSerializer,
IssueReactionSerializer,
CommentReactionSerializer,

View File

@ -25,7 +25,7 @@ from plane.db.models import (
Module,
ModuleIssue,
IssueLink,
IssueAttachment,
FileAsset,
IssueReaction,
CommentReaction,
IssueVote,
@ -444,22 +444,6 @@ class IssueLinkSerializer(BaseSerializer):
return IssueLink.objects.create(**validated_data)
class IssueAttachmentSerializer(BaseFileSerializer):
class Meta:
model = IssueAttachment
fields = "__all__"
read_only_fields = [
"created_by",
"updated_by",
"created_at",
"updated_at",
"workspace",
"project",
"issue",
]
class IssueReactionSerializer(BaseSerializer):
actor_detail = UserLiteSerializer(read_only=True, source="actor")

View File

@ -117,12 +117,12 @@ urlpatterns = [
name="project-issue-links",
),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/issues/<uuid:issue_id>/issue-attachments/",
"workspaces/<str:slug>/projects/<uuid:project_id>/issues/<uuid:issue_id>/attachments/",
IssueAttachmentEndpoint.as_view(),
name="project-issue-attachments",
),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/issues/<uuid:issue_id>/issue-attachments/<uuid:pk>/",
"workspaces/<str:slug>/projects/<uuid:project_id>/issues/<uuid:issue_id>/attachments/<uuid:workspace_id>/<str:asset_key>/",
IssueAttachmentEndpoint.as_view(),
name="project-issue-attachments",
),

View File

@ -47,10 +47,10 @@ from plane.db.models import (
Issue,
CycleFavorite,
IssueLink,
IssueAttachment,
Label,
CycleUserProperties,
IssueSubscriber,
FileAsset,
)
from plane.bgtasks.issue_activites_task import issue_activity
from plane.utils.issue_filters import issue_filters
@ -611,7 +611,7 @@ class CycleIssueViewSet(WebhookMixin, BaseViewSet):
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
attachment_count=FileAsset.objects.filter(
issue=OuterRef("id")
)
.order_by()

View File

@ -32,7 +32,7 @@ from plane.db.models import (
Dashboard,
Project,
IssueLink,
IssueAttachment,
FileAsset,
IssueRelation,
)
from plane.app.serializers import (
@ -117,8 +117,9 @@ def dashboard_assigned_issues(self, request, slug):
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
attachment_count=FileAsset.objects.filter(
entity_identifier=OuterRef("id"),
entity_type="issue_attachment",
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
@ -229,8 +230,9 @@ def dashboard_created_issues(self, request, slug):
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
attachment_count=FileAsset.objects.filter(
entity_identifier=OuterRef("id"),
entity_type="issue_attachment",
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))

View File

@ -19,7 +19,7 @@ from plane.db.models import (
Issue,
State,
IssueLink,
IssueAttachment,
FileAsset,
ProjectMember,
)
from plane.app.serializers import (
@ -92,7 +92,7 @@ class InboxIssueViewSet(BaseViewSet):
Issue.objects.filter(
project_id=self.kwargs.get("project_id"),
workspace__slug=self.kwargs.get("slug"),
issue_inbox__inbox_id=self.kwargs.get("inbox_id")
issue_inbox__inbox_id=self.kwargs.get("inbox_id"),
)
.select_related("workspace", "project", "state", "parent")
.prefetch_related("assignees", "labels", "issue_module__module")
@ -112,8 +112,9 @@ class InboxIssueViewSet(BaseViewSet):
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
attachment_count=FileAsset.objects.filter(
entity_identifier=OuterRef("id"),
entity_type="issue_attachment",
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
@ -131,8 +132,14 @@ class InboxIssueViewSet(BaseViewSet):
def list(self, request, slug, project_id, inbox_id):
filters = issue_filters(request.query_params, "GET")
issue_queryset = self.get_queryset().filter(**filters).order_by("issue_inbox__snoozed_till", "issue_inbox__status")
issues_data = IssueSerializer(issue_queryset, expand=self.expand, many=True).data
issue_queryset = (
self.get_queryset()
.filter(**filters)
.order_by("issue_inbox__snoozed_till", "issue_inbox__status")
)
issues_data = IssueSerializer(
issue_queryset, expand=self.expand, many=True
).data
return Response(
issues_data,
status=status.HTTP_200_OK,
@ -199,7 +206,7 @@ class InboxIssueViewSet(BaseViewSet):
source=request.data.get("source", "in-app"),
)
issue = (self.get_queryset().filter(pk=issue.id).first())
issue = self.get_queryset().filter(pk=issue.id).first()
serializer = IssueSerializer(issue, expand=self.expand)
return Response(serializer.data, status=status.HTTP_200_OK)
@ -320,20 +327,23 @@ class InboxIssueViewSet(BaseViewSet):
if state is not None:
issue.state = state
issue.save()
issue = (self.get_queryset().filter(pk=issue_id).first())
issue = self.get_queryset().filter(pk=issue_id).first()
serializer = IssueSerializer(issue, expand=self.expand)
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(
serializer.errors, status=status.HTTP_400_BAD_REQUEST
)
else:
issue = (self.get_queryset().filter(pk=issue_id).first())
issue = self.get_queryset().filter(pk=issue_id).first()
serializer = IssueSerializer(issue, expand=self.expand)
return Response(serializer.data, status=status.HTTP_200_OK)
def retrieve(self, request, slug, project_id, inbox_id, issue_id):
issue = self.get_queryset().filter(pk=issue_id).first()
serializer = IssueSerializer(issue, expand=self.expand,)
serializer = IssueSerializer(
issue,
expand=self.expand,
)
return Response(serializer.data, status=status.HTTP_200_OK)
def destroy(self, request, slug, project_id, inbox_id, issue_id):

View File

@ -4,7 +4,7 @@ import random
from itertools import chain
# Django imports
from django.db import models
from django.http import HttpResponseRedirect
from django.utils import timezone
from django.db.models import (
Prefetch,
@ -29,7 +29,7 @@ from django.db import IntegrityError
# Third Party imports
from rest_framework.response import Response
from rest_framework import status
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
# Module imports
from . import BaseViewSet, BaseAPIView, WebhookMixin
@ -43,13 +43,13 @@ from plane.app.serializers import (
IssueFlatSerializer,
IssueLinkSerializer,
IssueLiteSerializer,
IssueAttachmentSerializer,
IssueSubscriberSerializer,
ProjectMemberLiteSerializer,
IssueReactionSerializer,
CommentReactionSerializer,
IssueRelationSerializer,
RelatedIssueSerializer,
FileAssetSerializer,
)
from plane.app.permissions import (
ProjectEntityPermission,
@ -58,6 +58,7 @@ from plane.app.permissions import (
ProjectLitePermission,
)
from plane.db.models import (
Workspace,
Project,
Issue,
IssueActivity,
@ -65,7 +66,7 @@ from plane.db.models import (
IssueProperty,
Label,
IssueLink,
IssueAttachment,
FileAsset,
State,
IssueSubscriber,
ProjectMember,
@ -75,10 +76,12 @@ from plane.db.models import (
IssueVote,
IssueRelation,
ProjectPublicMember,
FileAsset,
)
from plane.bgtasks.issue_activites_task import issue_activity
from plane.utils.grouper import group_results
from plane.utils.issue_filters import issue_filters
from plane.utils.presigned_url_generator import generate_download_presigned_url
from collections import defaultdict
@ -128,8 +131,9 @@ class IssueViewSet(WebhookMixin, BaseViewSet):
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
attachment_count=FileAsset.objects.filter(
entity_identifier=OuterRef("id"),
entity_type="issue_attachment",
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
@ -372,8 +376,9 @@ class UserWorkSpaceIssues(BaseAPIView):
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
attachment_count=FileAsset.objects.filter(
entity_identifier=OuterRef("id"),
entity_type="issue_attachment",
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
@ -792,8 +797,9 @@ class SubIssuesEndpoint(BaseAPIView):
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
attachment_count=FileAsset.objects.filter(
entity_identifier=OuterRef("id"),
entity_type="issue_attachment",
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
@ -1010,17 +1016,21 @@ class BulkCreateIssueLabelsEndpoint(BaseAPIView):
class IssueAttachmentEndpoint(BaseAPIView):
serializer_class = IssueAttachmentSerializer
permission_classes = [
ProjectEntityPermission,
]
model = IssueAttachment
parser_classes = (MultiPartParser, FormParser)
parser_classes = (MultiPartParser, FormParser, JSONParser,)
def post(self, request, slug, project_id, issue_id):
serializer = IssueAttachmentSerializer(data=request.data)
serializer = FileAssetSerializer(data=request.data)
workspace = Workspace.objects.get(slug=slug)
if serializer.is_valid():
serializer.save(project_id=project_id, issue_id=issue_id)
serializer.save(
workspace=workspace,
project_id=project_id,
entity_type="issue_attachment",
entity_identifier=issue_id,
)
issue_activity.delay(
type="attachment.activity.created",
requested_data=None,
@ -1038,10 +1048,19 @@ class IssueAttachmentEndpoint(BaseAPIView):
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, pk):
issue_attachment = IssueAttachment.objects.get(pk=pk)
issue_attachment.asset.delete(save=False)
issue_attachment.delete()
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,
@ -1053,14 +1072,30 @@ class IssueAttachmentEndpoint(BaseAPIView):
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):
issue_attachments = IssueAttachment.objects.filter(
issue_id=issue_id, workspace__slug=slug, project_id=project_id
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)
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 = IssueAttachmentSerializer(issue_attachments, many=True)
serializer = FileAssetSerializer(issue_attachments, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
@ -1092,8 +1127,9 @@ class IssueArchiveViewSet(BaseViewSet):
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
attachment_count=FileAsset.objects.filter(
entity_identifier=OuterRef("id"),
entity_type="issue_attachment",
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
@ -1131,10 +1167,7 @@ class IssueArchiveViewSet(BaseViewSet):
order_by_param = request.GET.get("order_by", "-created_at")
issue_queryset = (
self.get_queryset()
.filter(**filters)
)
issue_queryset = self.get_queryset().filter(**filters)
# Priority Ordering
if order_by_param == "priority" or order_by_param == "-priority":
@ -1579,15 +1612,17 @@ class IssueRelationViewSet(BaseViewSet):
issue_relation = IssueRelation.objects.bulk_create(
[
IssueRelation(
issue_id=issue
issue_id=(
issue if relation_type == "blocking" else issue_id
),
related_issue_id=(
issue_id if relation_type == "blocking" else issue
),
relation_type=(
"blocked_by"
if relation_type == "blocking"
else issue_id,
related_issue_id=issue_id
if relation_type == "blocking"
else issue,
relation_type="blocked_by"
if relation_type == "blocking"
else relation_type,
else relation_type
),
project_id=project_id,
workspace_id=project.workspace_id,
created_by=request.user,
@ -1695,8 +1730,9 @@ class IssueDraftViewSet(BaseViewSet):
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
attachment_count=FileAsset.objects.filter(
entity_identifier=OuterRef("id"),
entity_type="issue_attachment",
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
@ -1733,10 +1769,7 @@ class IssueDraftViewSet(BaseViewSet):
order_by_param = request.GET.get("order_by", "-created_at")
issue_queryset = (
self.get_queryset()
.filter(**filters)
)
issue_queryset = self.get_queryset().filter(**filters)
# Priority Ordering
if order_by_param == "priority" or order_by_param == "-priority":

View File

@ -37,7 +37,7 @@ from plane.db.models import (
ModuleLink,
ModuleFavorite,
IssueLink,
IssueAttachment,
FileAsset,
IssueSubscriber,
ModuleUserProperties,
)
@ -331,17 +331,16 @@ class ModuleIssueViewSet(WebhookMixin, BaseViewSet):
ProjectEntityPermission,
]
def get_queryset(self):
return (
Issue.objects.filter(
project_id=self.kwargs.get("project_id"),
workspace__slug=self.kwargs.get("slug"),
issue_module__module_id=self.kwargs.get("module_id")
issue_module__module_id=self.kwargs.get("module_id"),
)
.select_related("workspace", "project", "state", "parent")
.prefetch_related("labels", "assignees")
.prefetch_related('issue_module__module')
.prefetch_related("issue_module__module")
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
@ -350,8 +349,9 @@ class ModuleIssueViewSet(WebhookMixin, BaseViewSet):
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
attachment_count=FileAsset.objects.filter(
entity_identifier=OuterRef("id"),
entity_type="issue_attachment",
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
@ -420,11 +420,10 @@ class ModuleIssueViewSet(WebhookMixin, BaseViewSet):
)
for issue in issues
]
issues = (self.get_queryset().filter(pk__in=issues))
issues = self.get_queryset().filter(pk__in=issues)
serializer = IssueSerializer(issues, many=True)
return Response(serializer.data, status=status.HTTP_201_CREATED)
# create multiple module inside an issue
def create_issue_modules(self, request, slug, project_id, issue_id):
modules = request.data.get("modules", [])
@ -466,11 +465,10 @@ class ModuleIssueViewSet(WebhookMixin, BaseViewSet):
for module in modules
]
issue = (self.get_queryset().filter(pk=issue_id).first())
issue = self.get_queryset().filter(pk=issue_id).first()
serializer = IssueSerializer(issue)
return Response(serializer.data, status=status.HTTP_201_CREATED)
def destroy(self, request, slug, project_id, module_id, issue_id):
module_issue = ModuleIssue.objects.get(
workspace__slug=slug,
@ -484,7 +482,9 @@ class ModuleIssueViewSet(WebhookMixin, BaseViewSet):
actor_id=str(request.user.id),
issue_id=str(issue_id),
project_id=str(project_id),
current_instance=json.dumps({"module_name": module_issue.module.name}),
current_instance=json.dumps(
{"module_name": module_issue.module.name}
),
epoch=int(timezone.now().timestamp()),
notification=True,
origin=request.META.get("HTTP_ORIGIN"),

View File

@ -41,7 +41,7 @@ from plane.db.models import (
IssueViewFavorite,
IssueReaction,
IssueLink,
IssueAttachment,
FileAsset,
IssueSubscriber,
)
from plane.utils.issue_filters import issue_filters
@ -130,8 +130,9 @@ class GlobalViewIssuesViewSet(BaseViewSet):
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
attachment_count=FileAsset.objects.filter(
entity_identifier=OuterRef("id"),
entity_type="issue_attachment",
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))

View File

@ -66,7 +66,7 @@ from plane.db.models import (
Issue,
WorkspaceTheme,
IssueLink,
IssueAttachment,
FileAsset,
IssueSubscriber,
Project,
Label,
@ -1360,8 +1360,9 @@ class WorkspaceUserProfileIssuesEndpoint(BaseAPIView):
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
attachment_count=FileAsset.objects.filter(
entity_identifier=OuterRef("id"),
entity_type="issue_attachment",
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
@ -1558,10 +1559,14 @@ class WorkspaceLogoEndpoint(BaseAPIView):
workspace = Workspace.objects.get(slug=slug)
if serializer.is_valid():
serializer.save(workspace=workspace)
workspace.logo = f"/api/workspaces/{slug}/logo/{serializer.data['asset']}/"
workspace.logo = (
f"/api/workspaces/{slug}/logo/{serializer.data['asset']}/"
)
workspace.save()
workspace_serializer = WorkSpaceSerializer(workspace)
return Response(workspace_serializer.data, status=status.HTTP_201_CREATED)
return Response(
workspace_serializer.data, status=status.HTTP_201_CREATED
)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, slug, workspace_id, logo_key):

View File

@ -224,7 +224,8 @@ class Migration(migrations.Migration):
name="entity_type",
field=models.CharField(
choices=[
("issue", "Issue"),
("issue_attachment", "Issue Attachment"),
("issue_description", "Issue Description"),
("comment", "Comment"),
("page", "Page"),
],

View File

@ -67,7 +67,7 @@ def convert_issue_description_image_sources(apps, schema_editor):
for asset in FileAsset.objects.filter(asset__in=file_assets.keys()):
asset.project_id = file_assets[str(asset.asset)]["project_id"]
asset.entity_identifier = file_assets[str(asset.asset)]["issue_id"]
asset.entity_type = "issue"
asset.entity_type = "issue_description"
bulk_assets.append(asset)
FileAsset.objects.bulk_update(

View File

@ -4,6 +4,31 @@ from django.db import migrations, models
import django.db.models.deletion
def create_attachment_assets(apps, schema_editor):
bulk_assets = []
issue_attachments = {}
FileAsset = apps.get_model("db", "FileAsset")
IssueAttachment = apps.get_model("db", "IssueAttachment")
for issue_attachment in IssueAttachment.objects.values():
bulk_assets.append(
FileAsset(
workspace_id=issue_attachment["workspace_id"],
project_id=issue_attachment["project_id"],
entity_identifier=issue_attachment["issue_id"],
entity_type="issue_attachment",
asset=issue_attachment["asset"],
attributes=issue_attachment["attributes"],
)
)
issue_attachments[str(issue_attachment["asset"])] = str(
issue_attachment["id"]
)
FileAsset.objects.bulk_create(bulk_assets, batch_size=100)
class Migration(migrations.Migration):
@ -12,21 +37,8 @@ class Migration(migrations.Migration):
]
operations = [
migrations.AddField(
model_name="issueattachment",
name="asset_key",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="issue_assets",
to="db.fileasset",
),
),
migrations.AddField(
model_name="issueattachment",
name="type",
field=models.PositiveSmallIntegerField(
choices=[(0, "Attachment"), (1, "Description")], default=0
),
migrations.RunPython(create_attachment_assets),
migrations.DeleteModel(
name="IssueAttachment",
),
]

View File

@ -1,74 +0,0 @@
# Generated by Django 4.2.7 on 2024-02-05 07:03
from django.db import migrations
def update_attachment_assets(apps, schema_editor):
pass
def create_description_assets(apps, schema_editor):
FileAsset = apps.get_model("db", "FileAsset")
IssueAttachment = apps.get_model("db", "IssueAttachment")
bulk_issue_attachments = []
for asset in FileAsset.objects.filter(entity_type="issue").values():
bulk_issue_attachments.append(
IssueAttachment(
workspace_id=asset["workspace_id"],
project_id=asset["project_id"],
issue_id=asset["entity_identifier"],
asset_key_id=asset["id"],
type=1,
)
)
IssueAttachment.objects.bulk_create(bulk_issue_attachments, batch_size=100)
def create_attachment_assets(apps, schema_editor):
bulk_assets = []
issue_attachments = {}
FileAsset = apps.get_model("db", "FileAsset")
IssueAttachment = apps.get_model("db", "IssueAttachment")
for issue_attachment in IssueAttachment.objects.filter(type=0).values():
bulk_assets.append(
FileAsset(
workspace_id=issue_attachment["workspace_id"],
project_id=issue_attachment["project_id"],
entity_identifier=issue_attachment["issue_id"],
entity_type="issue",
asset=issue_attachment["asset"],
attributes=issue_attachment["attributes"],
)
)
issue_attachments[str(issue_attachment["asset"])] = str(issue_attachment["id"])
FileAsset.objects.bulk_create(bulk_assets, batch_size=100)
assets = FileAsset.objects.filter(asset__in=issue_attachments.keys()).values("id", "asset")
bulk_issue_attachments = []
for issue_attachment in IssueAttachment.objects.filter(type=0):
asset_key_id = [asset.get("id") for asset in assets if str(asset.get("asset")) == str(issue_attachment.asset)]
if asset_key_id:
issue_attachment.asset_key_id = str(asset_key_id[0])
bulk_issue_attachments.append(issue_attachment)
IssueAttachment.objects.bulk_update(bulk_issue_attachments, ["asset_key"], batch_size=100)
class Migration(migrations.Migration):
dependencies = [
("db", "0061_issueattachment_asset_key_issueattachment_type"),
]
operations = [
migrations.RunPython(create_description_assets),
migrations.RunPython(create_attachment_assets),
]

View File

@ -37,7 +37,6 @@ from .issue import (
IssueMention,
IssueLink,
IssueSequence,
IssueAttachment,
IssueSubscriber,
IssueReaction,
CommentReaction,

View File

@ -48,7 +48,8 @@ class FileAsset(BaseModel):
)
entity_type = models.CharField(
choices=(
("issue", "Issue"),
("issue_attachment", "Issue Attachment"),
("issue_description", "Issue Description"),
("comment", "Comment"),
("page", "Page"),
),

View File

@ -345,42 +345,6 @@ def file_size(value):
if value.size > settings.FILE_SIZE_LIMIT:
raise ValidationError("File too large. Size should not exceed 5 MB.")
class IssueAttachment(ProjectBaseModel):
attributes = models.JSONField(default=dict)
asset = models.FileField(
upload_to=get_upload_path,
validators=[
file_size,
],
)
asset_key = models.ForeignKey(
"db.FileAsset",
on_delete=models.CASCADE,
related_name="issue_assets",
null=True,
)
issue = models.ForeignKey(
"db.Issue", on_delete=models.CASCADE, related_name="issue_attachment"
)
type = models.PositiveSmallIntegerField(
choices=(
(0, "Attachment"),
(1, "Description"),
),
default=0,
)
class Meta:
verbose_name = "Issue Attachment"
verbose_name_plural = "Issue Attachments"
db_table = "issue_attachments"
ordering = ("-created_at",)
def __str__(self):
return f"{self.issue.name} {self.asset}"
class IssueActivity(ProjectBaseModel):
issue = models.ForeignKey(
Issue,

View File

@ -22,7 +22,7 @@ from plane.db.models import (
CycleIssue,
ModuleIssue,
IssueLink,
IssueAttachment,
FileAsset,
IssueReaction,
CommentReaction,
IssueVote,
@ -171,22 +171,6 @@ class IssueLinkSerializer(BaseSerializer):
)
return IssueLink.objects.create(**validated_data)
class IssueAttachmentSerializer(BaseSerializer):
class Meta:
model = IssueAttachment
fields = "__all__"
read_only_fields = [
"created_by",
"updated_by",
"created_at",
"updated_at",
"workspace",
"project",
"issue",
]
class IssueReactionSerializer(BaseSerializer):
actor_detail = UserLiteSerializer(read_only=True, source="actor")
@ -218,7 +202,6 @@ class IssueSerializer(BaseSerializer):
issue_cycle = IssueCycleDetailSerializer(read_only=True)
issue_module = IssueModuleDetailSerializer(read_only=True)
issue_link = IssueLinkSerializer(read_only=True, many=True)
issue_attachment = IssueAttachmentSerializer(read_only=True, many=True)
sub_issues_count = serializers.IntegerField(read_only=True)
issue_reactions = IssueReactionSerializer(read_only=True, many=True)

View File

@ -17,7 +17,7 @@ from plane.db.models import (
Issue,
State,
IssueLink,
IssueAttachment,
FileAsset,
ProjectDeployBoard,
)
from plane.app.serializers import (
@ -95,8 +95,9 @@ class InboxIssuePublicViewSet(BaseViewSet):
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
attachment_count=FileAsset.objects.filter(
entity_identifier=OuterRef("id"),
entity_type="issue_attachment",
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))

View File

@ -40,7 +40,7 @@ from plane.db.models import (
IssueComment,
Label,
IssueLink,
IssueAttachment,
FileAsset,
State,
ProjectMember,
IssueReaction,
@ -567,8 +567,9 @@ class ProjectIssuesPublicEndpoint(BaseAPIView):
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
attachment_count=FileAsset.objects.filter(
entity_identifier=OuterRef("id"),
entity_type="issue_attachment",
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))