feat: page labels and favorites (#487)

* dev: initiate page labels

* dev: page labels

* dev: my pages endpoint
This commit is contained in:
pablohashescobar 2023-03-22 23:41:30 +05:30 committed by GitHub
parent cd26b2e096
commit 4e3c9397ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 139 additions and 19 deletions

View File

@ -3,21 +3,8 @@ from rest_framework import serializers
# Module imports # Module imports
from .base import BaseSerializer from .base import BaseSerializer
from .issue import IssueFlatSerializer from .issue import IssueFlatSerializer, LabelSerializer
from plane.db.models import Page, PageBlock, PageFavorite from plane.db.models import Page, PageBlock, PageFavorite, PageLabel, Label
class PageSerializer(BaseSerializer):
is_favorite = serializers.BooleanField(read_only=True)
class Meta:
model = Page
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"owned_by",
]
class PageBlockSerializer(BaseSerializer): class PageBlockSerializer(BaseSerializer):
@ -33,6 +20,71 @@ class PageBlockSerializer(BaseSerializer):
] ]
class PageSerializer(BaseSerializer):
is_favorite = serializers.BooleanField(read_only=True)
label_details = LabelSerializer(read_only=True, source="labels", many=True)
labels_list = serializers.ListField(
child=serializers.PrimaryKeyRelatedField(queryset=Label.objects.all()),
write_only=True,
required=False,
)
class Meta:
model = Page
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"owned_by",
]
def create(self, validated_data):
labels = validated_data.pop("labels_list", None)
project_id = self.context["project_id"]
owned_by_id = self.context["owned_by_id"]
page = Page.objects.create(
**validated_data, project_id=project_id, owned_by_id=owned_by_id
)
if labels is not None:
PageLabel.objects.bulk_create(
[
PageLabel(
label=label,
page=page,
project_id=project_id,
workspace_id=page.workspace_id,
created_by_id=page.created_by_id,
updated_by_id=page.updated_by_id,
)
for label in labels
],
batch_size=10,
)
return page
def update(self, instance, validated_data):
labels = validated_data.pop("labels_list", None)
if labels is not None:
PageLabel.objects.filter(issue=instance).delete()
PageLabel.objects.bulk_create(
[
PageLabel(
label=label,
page=instance,
project_id=instance.project_id,
workspace_id=instance.workspace_id,
created_by_id=instance.created_by_id,
updated_by_id=instance.updated_by_id,
)
for label in labels
],
batch_size=10,
)
return super().update(instance, validated_data)
class PageFavoriteSerializer(BaseSerializer): class PageFavoriteSerializer(BaseSerializer):
page_detail = PageSerializer(source="page", read_only=True) page_detail = PageSerializer(source="page", read_only=True)

View File

@ -106,6 +106,7 @@ from plane.api.views import (
PageBlockViewSet, PageBlockViewSet,
PageFavoriteViewSet, PageFavoriteViewSet,
CreateIssueFromPageBlockEndpoint, CreateIssueFromPageBlockEndpoint,
MyPagesEndpoint,
## End Pages ## End Pages
# Api Tokens # Api Tokens
ApiTokenEndpoint, ApiTokenEndpoint,
@ -978,6 +979,11 @@ urlpatterns = [
CreateIssueFromPageBlockEndpoint.as_view(), CreateIssueFromPageBlockEndpoint.as_view(),
name="page-block-issues", name="page-block-issues",
), ),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/user/pages/",
MyPagesEndpoint.as_view(),
name="my-pages",
),
## End Pages ## End Pages
# API Tokens # API Tokens
path("api-tokens/", ApiTokenEndpoint.as_view(), name="api-tokens"), path("api-tokens/", ApiTokenEndpoint.as_view(), name="api-tokens"),

View File

@ -108,7 +108,13 @@ from .importer import (
ImportServiceEndpoint, ImportServiceEndpoint,
UpdateServiceImportStatusEndpoint, UpdateServiceImportStatusEndpoint,
BulkImportIssuesEndpoint, BulkImportIssuesEndpoint,
BulkImportModulesEndpoint BulkImportModulesEndpoint,
) )
from .page import PageViewSet, PageBlockViewSet, PageFavoriteViewSet, CreateIssueFromPageBlockEndpoint from .page import (
PageViewSet,
PageBlockViewSet,
PageFavoriteViewSet,
CreateIssueFromPageBlockEndpoint,
MyPagesEndpoint,
)

View File

@ -16,7 +16,6 @@ from plane.db.models import (
PageFavorite, PageFavorite,
Issue, Issue,
IssueAssignee, IssueAssignee,
IssueActivity,
) )
from plane.api.serializers import ( from plane.api.serializers import (
PageSerializer, PageSerializer,
@ -51,6 +50,7 @@ class PageViewSet(BaseViewSet):
.select_related("workspace") .select_related("workspace")
.select_related("owned_by") .select_related("owned_by")
.annotate(is_favorite=Exists(subquery)) .annotate(is_favorite=Exists(subquery))
.prefetch_related("labels")
.distinct() .distinct()
) )
@ -59,6 +59,25 @@ class PageViewSet(BaseViewSet):
project_id=self.kwargs.get("project_id"), owned_by=self.request.user project_id=self.kwargs.get("project_id"), owned_by=self.request.user
) )
def create(self, request, slug, project_id):
try:
serializer = PageSerializer(
data=request.data,
context={"project_id": project_id, "owned_by_id": request.user.id},
)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
print(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class PageBlockViewSet(BaseViewSet): class PageBlockViewSet(BaseViewSet):
serializer_class = PageBlockSerializer serializer_class = PageBlockSerializer
@ -182,3 +201,19 @@ class CreateIssueFromPageBlockEndpoint(BaseAPIView):
{"error": "Something went wrong please try again later"}, {"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST, status=status.HTTP_400_BAD_REQUEST,
) )
class MyPagesEndpoint(BaseAPIView):
def get(self, request, slug, project_id):
try:
pages = Page.objects.filter(
workspace__slug=slug, project_id=project_id, owned_by=request.user
)
serializer = PageSerializer(pages, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@ -61,4 +61,4 @@ from .integration import (
from .importer import Importer from .importer import Importer
from .page import Page, PageBlock, PageFavorite from .page import Page, PageBlock, PageFavorite, PageLabel

View File

@ -17,6 +17,9 @@ class Page(ProjectBaseModel):
access = models.PositiveSmallIntegerField( access = models.PositiveSmallIntegerField(
choices=((0, "Public"), (1, "Private")), default=0 choices=((0, "Public"), (1, "Private")), default=0
) )
labels = models.ManyToManyField(
"db.Label", blank=True, related_name="pages", through="db.PageLabel"
)
class Meta: class Meta:
verbose_name = "Page" verbose_name = "Page"
@ -71,3 +74,21 @@ class PageFavorite(ProjectBaseModel):
def __str__(self): def __str__(self):
"""Return user and the page""" """Return user and the page"""
return f"{self.user.email} <{self.page.name}>" return f"{self.user.email} <{self.page.name}>"
class PageLabel(ProjectBaseModel):
label = models.ForeignKey(
"db.Label", on_delete=models.CASCADE, related_name="page_labels"
)
page = models.ForeignKey(
"db.Page", on_delete=models.CASCADE, related_name="page_labels"
)
class Meta:
verbose_name = "Page Label"
verbose_name_plural = "Page Labels"
db_table = "page_labels"
ordering = ("-created_at",)
def __str__(self):
return f"{self.page.name} {self.label.name}"