dev: optimize cycle endpoints

This commit is contained in:
pablohashescobar 2024-02-19 17:13:15 +05:30
parent c3ef3ca9dc
commit 199d50da0f
2 changed files with 172 additions and 94 deletions

View File

@ -26,13 +26,14 @@ class CycleWriteSerializer(BaseSerializer):
class Meta:
model = Cycle
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"owned_by",
]
class CycleSerializer(BaseSerializer):
# workspace and project ids
workspace_id = serializers.PrimaryKeyRelatedField(read_only=True)
project_id = serializers.PrimaryKeyRelatedField(read_only=True)
owned_by_id = serializers.PrimaryKeyRelatedField(read_only=True)
# favorite
is_favorite = serializers.BooleanField(read_only=True)
total_issues = serializers.IntegerField(read_only=True)
@ -42,33 +43,10 @@ class CycleSerializer(BaseSerializer):
started_issues = serializers.IntegerField(read_only=True)
unstarted_issues = serializers.IntegerField(read_only=True)
backlog_issues = serializers.IntegerField(read_only=True)
#TODO: Remove once confirmed # estimates
# total_estimates = serializers.IntegerField(read_only=True)
# completed_estimates = serializers.IntegerField(read_only=True)
# started_estimates = serializers.IntegerField(read_only=True)
# method fields
assignees = serializers.SerializerMethodField(read_only=True)
# active | draft | upcoming | completed
status = serializers.CharField(read_only=True)
def get_assignees(self, obj):
# Get all the members
members = [
{
"id": assignee.id,
"display_name": assignee.display_name,
"avatar": assignee.avatar,
}
for issue_cycle in obj.issue_cycle.prefetch_related(
"issue__assignees"
).all()
for assignee in issue_cycle.issue.assignees.all()
]
# Convert the set back to a list of dictionaries
unique_list = [dict(item) for item in {frozenset(item.items()) for item in members}]
return unique_list
class Meta:
model = Cycle
@ -96,10 +74,6 @@ class CycleSerializer(BaseSerializer):
"started_issues",
"unstarted_issues",
"backlog_issues",
# "total_estimates",
# "completed_estimates",
# "started_estimates",
"assignees",
"status",
]
read_only_fields = fields

View File

@ -20,7 +20,10 @@ from django.core import serializers
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.views.decorators.gzip import gzip_page
from django.core.serializers.json import DjangoJSONEncoder
from django.contrib.postgres.aggregates import ArrayAgg
from django.contrib.postgres.fields import ArrayField
from django.db.models import Value, UUIDField
from django.db.models.functions import Coalesce
# Third party imports
from rest_framework.response import Response
@ -160,29 +163,6 @@ class CycleViewSet(WebhookMixin, BaseViewSet):
),
)
)
# .annotate(
# total_estimates=Sum("issue_cycle__issue__estimate_point")
# )
# .annotate(
# completed_estimates=Sum(
# "issue_cycle__issue__estimate_point",
# filter=Q(
# issue_cycle__issue__state__group="completed",
# issue_cycle__issue__archived_at__isnull=True,
# issue_cycle__issue__is_draft=False,
# ),
# )
# )
# .annotate(
# started_estimates=Sum(
# "issue_cycle__issue__estimate_point",
# filter=Q(
# issue_cycle__issue__state__group="started",
# issue_cycle__issue__archived_at__isnull=True,
# issue_cycle__issue__is_draft=False,
# ),
# )
# )
.annotate(
status=Case(
When(
@ -202,6 +182,18 @@ class CycleViewSet(WebhookMixin, BaseViewSet):
output_field=CharField(),
)
)
.annotate(
assignee_ids=Coalesce(
ArrayAgg(
"issue_cycle__issue__assignees__id",
distinct=True,
filter=~Q(
issue_cycle__issue__assignees__id__isnull=True
),
),
Value([], output_field=ArrayField(UUIDField())),
)
)
.order_by("-is_favorite", "name")
.distinct()
)
@ -220,7 +212,33 @@ class CycleViewSet(WebhookMixin, BaseViewSet):
end_date__gte=timezone.now(),
)
data = CycleSerializer(queryset, many=True).data
data = queryset.values(
# necessary fields
"id",
"workspace_id",
"project_id",
# model fields
"name",
"description",
"start_date",
"end_date",
"owned_by_id",
"view_props",
"sort_order",
"external_source",
"external_id",
"progress_snapshot",
# meta fields
"is_favorite",
"total_issues",
"cancelled_issues",
"completed_issues",
"started_issues",
"unstarted_issues",
"backlog_issues",
"assignee_ids",
"status",
)
if data:
assignee_distribution = (
@ -318,8 +336,34 @@ class CycleViewSet(WebhookMixin, BaseViewSet):
return Response(data, status=status.HTTP_200_OK)
cycles = CycleSerializer(queryset, many=True).data
return Response(cycles, status=status.HTTP_200_OK)
data = queryset.values(
# necessary fields
"id",
"workspace_id",
"project_id",
# model fields
"name",
"description",
"start_date",
"end_date",
"owned_by_id",
"view_props",
"sort_order",
"external_source",
"external_id",
"progress_snapshot",
# meta fields
"is_favorite",
"total_issues",
"cancelled_issues",
"completed_issues",
"started_issues",
"unstarted_issues",
"backlog_issues",
"assignee_ids",
"status",
)
return Response(data, status=status.HTTP_200_OK)
def create(self, request, slug, project_id):
if (
@ -329,7 +373,7 @@ class CycleViewSet(WebhookMixin, BaseViewSet):
request.data.get("start_date", None) is not None
and request.data.get("end_date", None) is not None
):
serializer = CycleSerializer(data=request.data)
serializer = CycleWriteSerializer(data=request.data)
if serializer.is_valid():
serializer.save(
project_id=project_id,
@ -338,12 +382,36 @@ class CycleViewSet(WebhookMixin, BaseViewSet):
cycle = (
self.get_queryset()
.filter(pk=serializer.data["id"])
.values(
# necessary fields
"id",
"workspace_id",
"project_id",
# model fields
"name",
"description",
"start_date",
"end_date",
"owned_by_id",
"view_props",
"sort_order",
"external_source",
"external_id",
"progress_snapshot",
# meta fields
"is_favorite",
"total_issues",
"cancelled_issues",
"completed_issues",
"started_issues",
"unstarted_issues",
"backlog_issues",
"assignee_ids",
"status",
)
.first()
)
serializer = CycleSerializer(cycle)
return Response(
serializer.data, status=status.HTTP_201_CREATED
)
return Response(cycle, status=status.HTTP_201_CREATED)
return Response(
serializer.errors, status=status.HTTP_400_BAD_REQUEST
)
@ -356,10 +424,11 @@ class CycleViewSet(WebhookMixin, BaseViewSet):
)
def partial_update(self, request, slug, project_id, pk):
cycle = Cycle.objects.get(
workspace__slug=slug, project_id=project_id, pk=pk
queryset = (
self.get_queryset()
.filter(workspace__slug=slug, project_id=project_id, pk=pk)
)
cycle = queryset.first()
request_data = request.data
if (
@ -386,12 +455,71 @@ class CycleViewSet(WebhookMixin, BaseViewSet):
)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
cycle = queryset.values(
# necessary fields
"id",
"workspace_id",
"project_id",
# model fields
"name",
"description",
"start_date",
"end_date",
"owned_by_id",
"view_props",
"sort_order",
"external_source",
"external_id",
"progress_snapshot",
# meta fields
"is_favorite",
"total_issues",
"cancelled_issues",
"completed_issues",
"started_issues",
"unstarted_issues",
"backlog_issues",
"assignee_ids",
"status",
).first()
return Response(cycle, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def retrieve(self, request, slug, project_id, pk):
queryset = self.get_queryset().get(pk=pk)
queryset = self.get_queryset().filter(pk=pk)
data = (
self.get_queryset()
.filter(pk=pk)
.values(
# necessary fields
"id",
"workspace_id",
"project_id",
# model fields
"name",
"description",
"start_date",
"end_date",
"owned_by_id",
"view_props",
"sort_order",
"external_source",
"external_id",
"progress_snapshot",
# meta fields
"is_favorite",
"total_issues",
"cancelled_issues",
"completed_issues",
"started_issues",
"unstarted_issues",
"backlog_issues",
"assignee_ids",
"status",
)
.first()
)
queryset = queryset.first()
# Assignee Distribution
assignee_distribution = (
Issue.objects.filter(
@ -480,7 +608,6 @@ class CycleViewSet(WebhookMixin, BaseViewSet):
.order_by("label_name")
)
data = CycleSerializer(queryset).data
data["distribution"] = {
"assignees": assignee_distribution,
"labels": label_distribution,
@ -889,29 +1016,6 @@ class TransferCycleIssueEndpoint(BaseAPIView):
),
)
)
# .annotate(
# total_estimates=Sum("issue_cycle__issue__estimate_point")
# )
# .annotate(
# completed_estimates=Sum(
# "issue_cycle__issue__estimate_point",
# filter=Q(
# issue_cycle__issue__state__group="completed",
# issue_cycle__issue__archived_at__isnull=True,
# issue_cycle__issue__is_draft=False,
# ),
# )
# )
# .annotate(
# started_estimates=Sum(
# "issue_cycle__issue__estimate_point",
# filter=Q(
# issue_cycle__issue__state__group="started",
# issue_cycle__issue__archived_at__isnull=True,
# issue_cycle__issue__is_draft=False,
# ),
# )
# )
)
# Pass the new_cycle queryset to burndown_plot
@ -961,7 +1065,7 @@ class TransferCycleIssueEndpoint(BaseAPIView):
)
.order_by("display_name")
)
# assignee distribution serialized
# assignee distribution serialized
assignee_distribution_data = [
{
"display_name": item["display_name"],