Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: page labels and favorites #487

Merged
merged 3 commits into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 62 additions & 10 deletions apiserver/plane/api/serializers/page.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,87 @@

# Module imports
from .base import BaseSerializer
from .issue import IssueFlatSerializer
from plane.db.models import Page, PageBlock, PageFavorite
from .issue import IssueFlatSerializer, LabelSerializer
from plane.db.models import Page, PageBlock, PageFavorite, PageLabel, Label


class PageSerializer(BaseSerializer):
is_favorite = serializers.BooleanField(read_only=True)
class PageBlockSerializer(BaseSerializer):
issue_detail = IssueFlatSerializer(source="issue", read_only=True)

class Meta:
model = Page
model = PageBlock
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"owned_by",
"page",
]


class PageBlockSerializer(BaseSerializer):
issue_detail = IssueFlatSerializer(source="issue", read_only=True)
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 = PageBlock
model = Page
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"page",
"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):
page_detail = PageSerializer(source="page", read_only=True)
Expand Down
6 changes: 6 additions & 0 deletions apiserver/plane/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
PageBlockViewSet,
PageFavoriteViewSet,
CreateIssueFromPageBlockEndpoint,
MyPagesEndpoint,
## End Pages
# Api Tokens
ApiTokenEndpoint,
Expand Down Expand Up @@ -978,6 +979,11 @@
CreateIssueFromPageBlockEndpoint.as_view(),
name="page-block-issues",
),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/user/pages/",
MyPagesEndpoint.as_view(),
name="my-pages",
),
## End Pages
# API Tokens
path("api-tokens/", ApiTokenEndpoint.as_view(), name="api-tokens"),
Expand Down
10 changes: 8 additions & 2 deletions apiserver/plane/api/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,13 @@
ImportServiceEndpoint,
UpdateServiceImportStatusEndpoint,
BulkImportIssuesEndpoint,
BulkImportModulesEndpoint
BulkImportModulesEndpoint,
)

from .page import PageViewSet, PageBlockViewSet, PageFavoriteViewSet, CreateIssueFromPageBlockEndpoint
from .page import (
PageViewSet,
PageBlockViewSet,
PageFavoriteViewSet,
CreateIssueFromPageBlockEndpoint,
MyPagesEndpoint,
)
37 changes: 36 additions & 1 deletion apiserver/plane/api/views/page.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
PageFavorite,
Issue,
IssueAssignee,
IssueActivity,
)
from plane.api.serializers import (
PageSerializer,
Expand Down Expand Up @@ -51,6 +50,7 @@ def get_queryset(self):
.select_related("workspace")
.select_related("owned_by")
.annotate(is_favorite=Exists(subquery))
.prefetch_related("labels")
.distinct()
)

Expand All @@ -59,6 +59,25 @@ def perform_create(self, serializer):
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):
serializer_class = PageBlockSerializer
Expand Down Expand Up @@ -182,3 +201,19 @@ def post(self, request, slug, project_id, page_id, page_block_id):
{"error": "Something went wrong please try again later"},
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,
)
2 changes: 1 addition & 1 deletion apiserver/plane/db/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,4 @@

from .importer import Importer

from .page import Page, PageBlock, PageFavorite
from .page import Page, PageBlock, PageFavorite, PageLabel
21 changes: 21 additions & 0 deletions apiserver/plane/db/models/page.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ class Page(ProjectBaseModel):
access = models.PositiveSmallIntegerField(
choices=((0, "Public"), (1, "Private")), default=0
)
labels = models.ManyToManyField(
"db.Label", blank=True, related_name="pages", through="db.PageLabel"
)

class Meta:
verbose_name = "Page"
Expand Down Expand Up @@ -71,3 +74,21 @@ class Meta:
def __str__(self):
"""Return user and the page"""
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}"