From bd58931690e5dd99645fa9cf4b3cbfbc34d266a7 Mon Sep 17 00:00:00 2001 From: NarayanBavisetti Date: Tue, 4 Jun 2024 17:45:42 +0530 Subject: [PATCH] chore: migration fixes --- apiserver/plane/api/views/project.py | 4 +- apiserver/plane/app/serializers/__init__.py | 2 +- apiserver/plane/app/serializers/project.py | 6 +- apiserver/plane/app/urls/project.py | 6 +- apiserver/plane/app/views/__init__.py | 2 +- apiserver/plane/app/views/project/base.py | 16 +- .../db/migrations/0067_auto_20240604_1155.py | 156 ++++++++++++++++++ apiserver/plane/db/models/__init__.py | 2 +- apiserver/plane/db/models/deploy_board.py | 53 ++++++ apiserver/plane/space/views/inbox.py | 14 +- apiserver/plane/space/views/issue.py | 34 ++-- apiserver/plane/space/views/project.py | 10 +- 12 files changed, 257 insertions(+), 48 deletions(-) create mode 100644 apiserver/plane/db/migrations/0067_auto_20240604_1155.py create mode 100644 apiserver/plane/db/models/deploy_board.py diff --git a/apiserver/plane/api/views/project.py b/apiserver/plane/api/views/project.py index 019ab704e..408e14fed 100644 --- a/apiserver/plane/api/views/project.py +++ b/apiserver/plane/api/views/project.py @@ -22,7 +22,7 @@ from plane.db.models import ( IssueProperty, Module, Project, - ProjectDeployBoard, + DeployBoard, ProjectMember, State, Workspace, @@ -99,7 +99,7 @@ class ProjectAPIEndpoint(BaseAPIView): ) .annotate( is_deployed=Exists( - ProjectDeployBoard.objects.filter( + DeployBoard.objects.filter( project_id=OuterRef("pk"), workspace__slug=self.kwargs.get("slug"), ) diff --git a/apiserver/plane/app/serializers/__init__.py b/apiserver/plane/app/serializers/__init__.py index bdcdf6c0d..d8364f931 100644 --- a/apiserver/plane/app/serializers/__init__.py +++ b/apiserver/plane/app/serializers/__init__.py @@ -30,7 +30,7 @@ from .project import ( ProjectIdentifierSerializer, ProjectLiteSerializer, ProjectMemberLiteSerializer, - ProjectDeployBoardSerializer, + DeployBoardSerializer, ProjectMemberAdminSerializer, ProjectPublicMemberSerializer, ProjectMemberRoleSerializer, diff --git a/apiserver/plane/app/serializers/project.py b/apiserver/plane/app/serializers/project.py index 96d92f340..d9ea99f1e 100644 --- a/apiserver/plane/app/serializers/project.py +++ b/apiserver/plane/app/serializers/project.py @@ -13,7 +13,7 @@ from plane.db.models import ( ProjectMember, ProjectMemberInvite, ProjectIdentifier, - ProjectDeployBoard, + DeployBoard, ProjectPublicMember, ) @@ -206,14 +206,14 @@ class ProjectMemberLiteSerializer(BaseSerializer): read_only_fields = fields -class ProjectDeployBoardSerializer(BaseSerializer): +class DeployBoardSerializer(BaseSerializer): project_details = ProjectLiteSerializer(read_only=True, source="project") workspace_detail = WorkspaceLiteSerializer( read_only=True, source="workspace" ) class Meta: - model = ProjectDeployBoard + model = DeployBoard fields = "__all__" read_only_fields = [ "workspace", diff --git a/apiserver/plane/app/urls/project.py b/apiserver/plane/app/urls/project.py index 7ea636df8..0807c7616 100644 --- a/apiserver/plane/app/urls/project.py +++ b/apiserver/plane/app/urls/project.py @@ -2,6 +2,7 @@ from django.urls import path from plane.app.views import ( ProjectViewSet, + DeployBoardViewSet, ProjectInvitationsViewset, ProjectMemberViewSet, ProjectMemberUserEndpoint, @@ -12,7 +13,6 @@ from plane.app.views import ( ProjectFavoritesViewSet, UserProjectInvitationsViewset, ProjectPublicCoverImagesEndpoint, - ProjectDeployBoardViewSet, UserProjectRolesEndpoint, ProjectArchiveUnarchiveEndpoint, ) @@ -157,7 +157,7 @@ urlpatterns = [ ), path( "workspaces//projects//project-deploy-boards/", - ProjectDeployBoardViewSet.as_view( + DeployBoardViewSet.as_view( { "get": "list", "post": "create", @@ -167,7 +167,7 @@ urlpatterns = [ ), path( "workspaces//projects//project-deploy-boards//", - ProjectDeployBoardViewSet.as_view( + DeployBoardViewSet.as_view( { "get": "retrieve", "patch": "partial_update", diff --git a/apiserver/plane/app/views/__init__.py b/apiserver/plane/app/views/__init__.py index 0c489593d..592d897e0 100644 --- a/apiserver/plane/app/views/__init__.py +++ b/apiserver/plane/app/views/__init__.py @@ -4,7 +4,7 @@ from .project.base import ( ProjectUserViewsEndpoint, ProjectFavoritesViewSet, ProjectPublicCoverImagesEndpoint, - ProjectDeployBoardViewSet, + DeployBoardViewSet, ProjectArchiveUnarchiveEndpoint, ) diff --git a/apiserver/plane/app/views/project/base.py b/apiserver/plane/app/views/project/base.py index 39db11871..67198a60c 100644 --- a/apiserver/plane/app/views/project/base.py +++ b/apiserver/plane/app/views/project/base.py @@ -28,7 +28,7 @@ from plane.app.views.base import BaseViewSet, BaseAPIView from plane.app.serializers import ( ProjectSerializer, ProjectListSerializer, - ProjectDeployBoardSerializer, + DeployBoardSerializer, ) from plane.app.permissions import ( @@ -46,7 +46,7 @@ from plane.db.models import ( Module, Cycle, Inbox, - ProjectDeployBoard, + DeployBoard, IssueProperty, Issue, ) @@ -138,7 +138,7 @@ class ProjectViewSet(BaseViewSet): ) .annotate( is_deployed=Exists( - ProjectDeployBoard.objects.filter( + DeployBoard.objects.filter( project_id=OuterRef("pk"), workspace__slug=self.kwargs.get("slug"), ) @@ -639,12 +639,12 @@ class ProjectPublicCoverImagesEndpoint(BaseAPIView): return Response(files, status=status.HTTP_200_OK) -class ProjectDeployBoardViewSet(BaseViewSet): +class DeployBoardViewSet(BaseViewSet): permission_classes = [ ProjectMemberPermission, ] - serializer_class = ProjectDeployBoardSerializer - model = ProjectDeployBoard + serializer_class = DeployBoardSerializer + model = DeployBoard def get_queryset(self): return ( @@ -673,7 +673,7 @@ class ProjectDeployBoardViewSet(BaseViewSet): }, ) - project_deploy_board, _ = ProjectDeployBoard.objects.get_or_create( + project_deploy_board, _ = DeployBoard.objects.get_or_create( anchor=f"{slug}/{project_id}", project_id=project_id, ) @@ -685,5 +685,5 @@ class ProjectDeployBoardViewSet(BaseViewSet): project_deploy_board.save() - serializer = ProjectDeployBoardSerializer(project_deploy_board) + serializer = DeployBoardSerializer(project_deploy_board) return Response(serializer.data, status=status.HTTP_200_OK) diff --git a/apiserver/plane/db/migrations/0067_auto_20240604_1155.py b/apiserver/plane/db/migrations/0067_auto_20240604_1155.py new file mode 100644 index 000000000..95bbdcdf2 --- /dev/null +++ b/apiserver/plane/db/migrations/0067_auto_20240604_1155.py @@ -0,0 +1,156 @@ +# # Generated by Django 4.2.7 on 2024-05-24 09:47 +# Python imports +import uuid +from uuid import uuid4 +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models +import plane.db.models.deploy_board + + +def populate_deploy_board(apps, schema_editor): + DeployBoard = apps.get_model("db", "DeployBoard") + ProjectDeployBoard = apps.get_model("db", "ProjectDeployBoard") + + DeployBoard.objects.bulk_create( + [ + DeployBoard( + entity_identifier=deploy_board.project_id, + project_id=deploy_board.project_id, + entity_name="project", + anchor=uuid4().hex, + comments=deploy_board.comments, + reactions=deploy_board.reactions, + inbox=deploy_board.inbox, + votes=deploy_board.votes, + view_props=deploy_board.views, + workspace_id=deploy_board.workspace_id, + created_at=deploy_board.created_at, + updated_at=deploy_board.updated_at, + created_by_id=deploy_board.created_by_id, + updated_by_id=deploy_board.updated_by_id, + ) + for deploy_board in ProjectDeployBoard.objects.all() + ], + batch_size=100, + ) + + +class Migration(migrations.Migration): + + dependencies = [ + ("db", "0066_account_id_token_cycle_logo_props_module_logo_props"), + ] + + operations = [ + migrations.CreateModel( + name="DeployBoard", + fields=[ + ( + "created_at", + models.DateTimeField( + auto_now_add=True, verbose_name="Created At" + ), + ), + ( + "updated_at", + models.DateTimeField( + auto_now=True, verbose_name="Last Modified At" + ), + ), + ( + "id", + models.UUIDField( + db_index=True, + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + unique=True, + ), + ), + ("entity_identifier", models.UUIDField(null=True)), + ( + "entity_name", + models.CharField( + choices=[ + ("project", "Project"), + ("issue", "Issue"), + ("module", "Module"), + ("cycle", "Task"), + ("page", "Page"), + ("view", "View"), + ], + max_length=30, + ), + ), + ( + "anchor", + models.CharField( + db_index=True, + default=plane.db.models.deploy_board.get_anchor, + max_length=255, + unique=True, + ), + ), + ("comments", models.BooleanField(default=False)), + ("reactions", models.BooleanField(default=False)), + ("votes", models.BooleanField(default=False)), + ("view_props", models.JSONField(default=dict)), + ( + "created_by", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="%(class)s_created_by", + to=settings.AUTH_USER_MODEL, + verbose_name="Created By", + ), + ), + ( + "inbox", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="board_inbox", + to="db.inbox", + ), + ), + ( + "project", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="project_%(class)s", + to="db.project", + ), + ), + ( + "updated_by", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="%(class)s_updated_by", + to=settings.AUTH_USER_MODEL, + verbose_name="Last Modified By", + ), + ), + ( + "workspace", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="workspace_%(class)s", + to="db.workspace", + ), + ), + ], + options={ + "verbose_name": "Deploy Board", + "verbose_name_plural": "Deploy Boards", + "db_table": "deploy_boards", + "ordering": ("-created_at",), + "unique_together": {("entity_name", "entity_identifier")}, + }, + ), + migrations.RunPython(populate_deploy_board), + ] diff --git a/apiserver/plane/db/models/__init__.py b/apiserver/plane/db/models/__init__.py index b11ce7aa3..0e31d4daf 100644 --- a/apiserver/plane/db/models/__init__.py +++ b/apiserver/plane/db/models/__init__.py @@ -53,13 +53,13 @@ from .page import Page, PageFavorite, PageLabel, PageLog from .project import ( Project, ProjectBaseModel, - ProjectDeployBoard, ProjectFavorite, ProjectIdentifier, ProjectMember, ProjectMemberInvite, ProjectPublicMember, ) +from .deploy_board import DeployBoard from .session import Session from .social_connection import SocialLoginConnection from .state import State diff --git a/apiserver/plane/db/models/deploy_board.py b/apiserver/plane/db/models/deploy_board.py new file mode 100644 index 000000000..102d437f9 --- /dev/null +++ b/apiserver/plane/db/models/deploy_board.py @@ -0,0 +1,53 @@ +# Python imports +from uuid import uuid4 + +# Django imports +from django.db import models + +# Module imports +from .workspace import WorkspaceBaseModel + + +def get_anchor(): + return uuid4().hex + + +class DeployBoard(WorkspaceBaseModel): + TYPE_CHOICES = ( + ("project", "Project"), + ("issue", "Issue"), + ("module", "Module"), + ("cycle", "Task"), + ("page", "Page"), + ("view", "View"), + ) + + entity_identifier = models.UUIDField(null=True) + entity_name = models.CharField( + max_length=30, + choices=TYPE_CHOICES, + ) + anchor = models.CharField( + max_length=255, default=get_anchor, unique=True, db_index=True + ) + comments = models.BooleanField(default=False) + reactions = models.BooleanField(default=False) + inbox = models.ForeignKey( + "db.Inbox", + related_name="board_inbox", + on_delete=models.SET_NULL, + null=True, + ) + votes = models.BooleanField(default=False) + view_props = models.JSONField(default=dict) + + def __str__(self): + """Return name of the deploy board""" + return f"{self.entity_identifier} <{self.entity_name}>" + + class Meta: + unique_together = ["entity_name", "entity_identifier"] + verbose_name = "Deploy Board" + verbose_name_plural = "Deploy Boards" + db_table = "deploy_boards" + ordering = ("-created_at",) diff --git a/apiserver/plane/space/views/inbox.py b/apiserver/plane/space/views/inbox.py index 9f681c160..d15e7aa39 100644 --- a/apiserver/plane/space/views/inbox.py +++ b/apiserver/plane/space/views/inbox.py @@ -18,7 +18,7 @@ from plane.db.models import ( State, IssueLink, IssueAttachment, - ProjectDeployBoard, + DeployBoard, ) from plane.app.serializers import ( IssueSerializer, @@ -39,7 +39,7 @@ class InboxIssuePublicViewSet(BaseViewSet): ] def get_queryset(self): - project_deploy_board = ProjectDeployBoard.objects.get( + project_deploy_board = DeployBoard.objects.get( workspace__slug=self.kwargs.get("slug"), project_id=self.kwargs.get("project_id"), ) @@ -59,7 +59,7 @@ class InboxIssuePublicViewSet(BaseViewSet): return InboxIssue.objects.none() def list(self, request, slug, project_id, inbox_id): - project_deploy_board = ProjectDeployBoard.objects.get( + project_deploy_board = DeployBoard.objects.get( workspace__slug=slug, project_id=project_id ) if project_deploy_board.inbox is None: @@ -118,7 +118,7 @@ class InboxIssuePublicViewSet(BaseViewSet): ) def create(self, request, slug, project_id, inbox_id): - project_deploy_board = ProjectDeployBoard.objects.get( + project_deploy_board = DeployBoard.objects.get( workspace__slug=slug, project_id=project_id ) if project_deploy_board.inbox is None: @@ -189,7 +189,7 @@ class InboxIssuePublicViewSet(BaseViewSet): return Response(serializer.data, status=status.HTTP_200_OK) def partial_update(self, request, slug, project_id, inbox_id, pk): - project_deploy_board = ProjectDeployBoard.objects.get( + project_deploy_board = DeployBoard.objects.get( workspace__slug=slug, project_id=project_id ) if project_deploy_board.inbox is None: @@ -256,7 +256,7 @@ class InboxIssuePublicViewSet(BaseViewSet): ) def retrieve(self, request, slug, project_id, inbox_id, pk): - project_deploy_board = ProjectDeployBoard.objects.get( + project_deploy_board = DeployBoard.objects.get( workspace__slug=slug, project_id=project_id ) if project_deploy_board.inbox is None: @@ -280,7 +280,7 @@ class InboxIssuePublicViewSet(BaseViewSet): return Response(serializer.data, status=status.HTTP_200_OK) def destroy(self, request, slug, project_id, inbox_id, pk): - project_deploy_board = ProjectDeployBoard.objects.get( + project_deploy_board = DeployBoard.objects.get( workspace__slug=slug, project_id=project_id ) if project_deploy_board.inbox is None: diff --git a/apiserver/plane/space/views/issue.py b/apiserver/plane/space/views/issue.py index 8c4d6e150..7ffdf0911 100644 --- a/apiserver/plane/space/views/issue.py +++ b/apiserver/plane/space/views/issue.py @@ -44,7 +44,7 @@ from plane.db.models import ( ProjectMember, IssueReaction, CommentReaction, - ProjectDeployBoard, + DeployBoard, IssueVote, ProjectPublicMember, ) @@ -76,7 +76,7 @@ class IssueCommentPublicViewSet(BaseViewSet): def get_queryset(self): try: - project_deploy_board = ProjectDeployBoard.objects.get( + project_deploy_board = DeployBoard.objects.get( workspace__slug=self.kwargs.get("slug"), project_id=self.kwargs.get("project_id"), ) @@ -103,11 +103,11 @@ class IssueCommentPublicViewSet(BaseViewSet): .distinct() ).order_by("created_at") return IssueComment.objects.none() - except ProjectDeployBoard.DoesNotExist: + except DeployBoard.DoesNotExist: return IssueComment.objects.none() def create(self, request, slug, project_id, issue_id): - project_deploy_board = ProjectDeployBoard.objects.get( + project_deploy_board = DeployBoard.objects.get( workspace__slug=slug, project_id=project_id ) @@ -151,7 +151,7 @@ class IssueCommentPublicViewSet(BaseViewSet): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) def partial_update(self, request, slug, project_id, issue_id, pk): - project_deploy_board = ProjectDeployBoard.objects.get( + project_deploy_board = DeployBoard.objects.get( workspace__slug=slug, project_id=project_id ) @@ -184,7 +184,7 @@ class IssueCommentPublicViewSet(BaseViewSet): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) def destroy(self, request, slug, project_id, issue_id, pk): - project_deploy_board = ProjectDeployBoard.objects.get( + project_deploy_board = DeployBoard.objects.get( workspace__slug=slug, project_id=project_id ) @@ -221,7 +221,7 @@ class IssueReactionPublicViewSet(BaseViewSet): def get_queryset(self): try: - project_deploy_board = ProjectDeployBoard.objects.get( + project_deploy_board = DeployBoard.objects.get( workspace__slug=self.kwargs.get("slug"), project_id=self.kwargs.get("project_id"), ) @@ -236,11 +236,11 @@ class IssueReactionPublicViewSet(BaseViewSet): .distinct() ) return IssueReaction.objects.none() - except ProjectDeployBoard.DoesNotExist: + except DeployBoard.DoesNotExist: return IssueReaction.objects.none() def create(self, request, slug, project_id, issue_id): - project_deploy_board = ProjectDeployBoard.objects.get( + project_deploy_board = DeployBoard.objects.get( workspace__slug=slug, project_id=project_id ) @@ -280,7 +280,7 @@ class IssueReactionPublicViewSet(BaseViewSet): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) def destroy(self, request, slug, project_id, issue_id, reaction_code): - project_deploy_board = ProjectDeployBoard.objects.get( + project_deploy_board = DeployBoard.objects.get( workspace__slug=slug, project_id=project_id ) @@ -319,7 +319,7 @@ class CommentReactionPublicViewSet(BaseViewSet): def get_queryset(self): try: - project_deploy_board = ProjectDeployBoard.objects.get( + project_deploy_board = DeployBoard.objects.get( workspace__slug=self.kwargs.get("slug"), project_id=self.kwargs.get("project_id"), ) @@ -334,11 +334,11 @@ class CommentReactionPublicViewSet(BaseViewSet): .distinct() ) return CommentReaction.objects.none() - except ProjectDeployBoard.DoesNotExist: + except DeployBoard.DoesNotExist: return CommentReaction.objects.none() def create(self, request, slug, project_id, comment_id): - project_deploy_board = ProjectDeployBoard.objects.get( + project_deploy_board = DeployBoard.objects.get( workspace__slug=slug, project_id=project_id ) @@ -380,7 +380,7 @@ class CommentReactionPublicViewSet(BaseViewSet): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) def destroy(self, request, slug, project_id, comment_id, reaction_code): - project_deploy_board = ProjectDeployBoard.objects.get( + project_deploy_board = DeployBoard.objects.get( workspace__slug=slug, project_id=project_id ) if not project_deploy_board.reactions: @@ -421,7 +421,7 @@ class IssueVotePublicViewSet(BaseViewSet): def get_queryset(self): try: - project_deploy_board = ProjectDeployBoard.objects.get( + project_deploy_board = DeployBoard.objects.get( workspace__slug=self.kwargs.get("slug"), project_id=self.kwargs.get("project_id"), ) @@ -434,7 +434,7 @@ class IssueVotePublicViewSet(BaseViewSet): .filter(project_id=self.kwargs.get("project_id")) ) return IssueVote.objects.none() - except ProjectDeployBoard.DoesNotExist: + except DeployBoard.DoesNotExist: return IssueVote.objects.none() def create(self, request, slug, project_id, issue_id): @@ -513,7 +513,7 @@ class ProjectIssuesPublicEndpoint(BaseAPIView): ] def get(self, request, slug, project_id): - if not ProjectDeployBoard.objects.filter( + if not DeployBoard.objects.filter( workspace__slug=slug, project_id=project_id ).exists(): return Response( diff --git a/apiserver/plane/space/views/project.py b/apiserver/plane/space/views/project.py index 10a3c3879..2cace08da 100644 --- a/apiserver/plane/space/views/project.py +++ b/apiserver/plane/space/views/project.py @@ -11,10 +11,10 @@ from rest_framework.permissions import AllowAny # Module imports from .base import BaseAPIView -from plane.app.serializers import ProjectDeployBoardSerializer +from plane.app.serializers import DeployBoardSerializer from plane.db.models import ( Project, - ProjectDeployBoard, + DeployBoard, ) @@ -24,10 +24,10 @@ class ProjectDeployBoardPublicSettingsEndpoint(BaseAPIView): ] def get(self, request, slug, project_id): - project_deploy_board = ProjectDeployBoard.objects.get( + project_deploy_board = DeployBoard.objects.get( workspace__slug=slug, project_id=project_id ) - serializer = ProjectDeployBoardSerializer(project_deploy_board) + serializer = DeployBoardSerializer(project_deploy_board) return Response(serializer.data, status=status.HTTP_200_OK) @@ -41,7 +41,7 @@ class WorkspaceProjectDeployBoardEndpoint(BaseAPIView): Project.objects.filter(workspace__slug=slug) .annotate( is_public=Exists( - ProjectDeployBoard.objects.filter( + DeployBoard.objects.filter( workspace__slug=slug, project_id=OuterRef("pk") ) )