[WEB-4544] chore: added field validations in serializer (#7460)

* chore: added field validations in serializer

* chore: added enum for roles
This commit is contained in:
Bavisetti Narayan 2025-07-25 16:50:35 +05:30 committed by GitHub
parent 27f74206a3
commit 63d025cbf4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 157 additions and 16 deletions

View file

@ -20,6 +20,7 @@ from plane.db.models import (
ProjectMember,
State,
User,
EstimatePoint,
)
from .base import BaseSerializer
@ -112,13 +113,27 @@ class IssueSerializer(BaseSerializer):
if (
data.get("parent")
and not Issue.objects.filter(
workspace_id=self.context.get("workspace_id"), pk=data.get("parent").id
workspace_id=self.context.get("workspace_id"),
project_id=self.context.get("project_id"),
pk=data.get("parent").id,
).exists()
):
raise serializers.ValidationError(
"Parent is not valid issue_id please pass a valid issue_id"
)
if (
data.get("estimate_point")
and not EstimatePoint.objects.filter(
workspace_id=self.context.get("workspace_id"),
project_id=self.context.get("project_id"),
pk=data.get("estimate_point").id,
).exists()
):
raise serializers.ValidationError(
"Estimate point is not valid please pass a valid estimate_point_id"
)
return data
def create(self, validated_data):

View file

@ -1,3 +1,5 @@
from lxml import html
# Django imports
from django.utils import timezone
@ -16,7 +18,10 @@ from plane.db.models import (
DraftIssueLabel,
DraftIssueCycle,
DraftIssueModule,
ProjectMember,
EstimatePoint,
)
from plane.app.permissions import ROLE
class DraftIssueCreateSerializer(BaseSerializer):
@ -57,14 +62,77 @@ class DraftIssueCreateSerializer(BaseSerializer):
data["label_ids"] = label_ids if label_ids else []
return data
def validate(self, data):
def validate(self, attrs):
if (
data.get("start_date", None) is not None
and data.get("target_date", None) is not None
and data.get("start_date", None) > data.get("target_date", None)
attrs.get("start_date", None) is not None
and attrs.get("target_date", None) is not None
and attrs.get("start_date", None) > attrs.get("target_date", None)
):
raise serializers.ValidationError("Start date cannot exceed target date")
return data
try:
if attrs.get("description_html", None) is not None:
parsed = html.fromstring(attrs["description_html"])
parsed_str = html.tostring(parsed, encoding="unicode")
attrs["description_html"] = parsed_str
except Exception:
raise serializers.ValidationError("Invalid HTML passed")
# Validate assignees are from project
if attrs.get("assignee_ids", []):
attrs["assignee_ids"] = ProjectMember.objects.filter(
project_id=self.context["project_id"],
role__gte=ROLE.MEMBER.value,
is_active=True,
member_id__in=attrs["assignee_ids"],
).values_list("member_id", flat=True)
# Validate labels are from project
if attrs.get("label_ids"):
label_ids = [label.id for label in attrs["label_ids"]]
attrs["label_ids"] = list(
Label.objects.filter(
project_id=self.context.get("project_id"), id__in=label_ids
).values_list("id", flat=True)
)
# # Check state is from the project only else raise validation error
if (
attrs.get("state")
and not State.objects.filter(
project_id=self.context.get("project_id"),
pk=attrs.get("state").id,
).exists()
):
raise serializers.ValidationError(
"State is not valid please pass a valid state_id"
)
# # Check parent issue is from workspace as it can be cross workspace
if (
attrs.get("parent")
and not Issue.objects.filter(
project_id=self.context.get("project_id"),
pk=attrs.get("parent").id,
).exists()
):
raise serializers.ValidationError(
"Parent is not valid issue_id please pass a valid issue_id"
)
if (
attrs.get("estimate_point")
and not EstimatePoint.objects.filter(
project_id=self.context.get("project_id"),
pk=attrs.get("estimate_point").id,
).exists()
):
raise serializers.ValidationError(
"Estimate point is not valid please pass a valid estimate_point_id"
)
return attrs
def create(self, validated_data):
assignees = validated_data.pop("assignee_ids", None)
@ -89,14 +157,14 @@ class DraftIssueCreateSerializer(BaseSerializer):
DraftIssueAssignee.objects.bulk_create(
[
DraftIssueAssignee(
assignee=user,
assignee_id=assignee_id,
draft_issue=issue,
workspace_id=workspace_id,
project_id=project_id,
created_by_id=created_by_id,
updated_by_id=updated_by_id,
)
for user in assignees
for assignee_id in assignees
],
batch_size=10,
)
@ -105,14 +173,14 @@ class DraftIssueCreateSerializer(BaseSerializer):
DraftIssueLabel.objects.bulk_create(
[
DraftIssueLabel(
label=label,
label_id=label_id,
draft_issue=issue,
project_id=project_id,
workspace_id=workspace_id,
created_by_id=created_by_id,
updated_by_id=updated_by_id,
)
for label in labels
for label_id in labels
],
batch_size=10,
)
@ -163,14 +231,14 @@ class DraftIssueCreateSerializer(BaseSerializer):
DraftIssueAssignee.objects.bulk_create(
[
DraftIssueAssignee(
assignee=user,
assignee_id=assignee_id,
draft_issue=instance,
workspace_id=workspace_id,
project_id=project_id,
created_by_id=created_by_id,
updated_by_id=updated_by_id,
)
for user in assignees
for assignee_id in assignees
],
batch_size=10,
)

View file

@ -1,3 +1,5 @@
from lxml import html
# Django imports
from django.utils import timezone
from django.core.validators import URLValidator
@ -37,6 +39,7 @@ from plane.db.models import (
IssueVersion,
IssueDescriptionVersion,
ProjectMember,
EstimatePoint,
)
@ -119,6 +122,16 @@ class IssueCreateSerializer(BaseSerializer):
):
raise serializers.ValidationError("Start date cannot exceed target date")
try:
if attrs.get("description_html", None) is not None:
parsed = html.fromstring(attrs["description_html"])
parsed_str = html.tostring(parsed, encoding="unicode")
attrs["description_html"] = parsed_str
except Exception:
raise serializers.ValidationError("Invalid HTML passed")
# Validate assignees are from project
if attrs.get("assignee_ids", []):
attrs["assignee_ids"] = ProjectMember.objects.filter(
project_id=self.context["project_id"],
@ -127,6 +140,51 @@ class IssueCreateSerializer(BaseSerializer):
member_id__in=attrs["assignee_ids"],
).values_list("member_id", flat=True)
# Validate labels are from project
if attrs.get("label_ids"):
label_ids = [label.id for label in attrs["label_ids"]]
attrs["label_ids"] = list(
Label.objects.filter(
project_id=self.context.get("project_id"),
id__in=label_ids,
).values_list("id", flat=True)
)
# Check state is from the project only else raise validation error
if (
attrs.get("state")
and not State.objects.filter(
project_id=self.context.get("project_id"),
pk=attrs.get("state").id,
).exists()
):
raise serializers.ValidationError(
"State is not valid please pass a valid state_id"
)
# Check parent issue is from workspace as it can be cross workspace
if (
attrs.get("parent")
and not Issue.objects.filter(
project_id=self.context.get("project_id"),
pk=attrs.get("parent").id,
).exists()
):
raise serializers.ValidationError(
"Parent is not valid issue_id please pass a valid issue_id"
)
if (
attrs.get("estimate_point")
and not EstimatePoint.objects.filter(
project_id=self.context.get("project_id"),
pk=attrs.get("estimate_point").id,
).exists()
):
raise serializers.ValidationError(
"Estimate point is not valid please pass a valid estimate_point_id"
)
return attrs
def create(self, validated_data):
@ -190,14 +248,14 @@ class IssueCreateSerializer(BaseSerializer):
IssueLabel.objects.bulk_create(
[
IssueLabel(
label=label,
label_id=label_id,
issue=issue,
project_id=project_id,
workspace_id=workspace_id,
created_by_id=created_by_id,
updated_by_id=updated_by_id,
)
for label in labels
for label_id in labels
],
batch_size=10,
)
@ -243,14 +301,14 @@ class IssueCreateSerializer(BaseSerializer):
IssueLabel.objects.bulk_create(
[
IssueLabel(
label=label,
label_id=label_id,
issue=instance,
project_id=project_id,
workspace_id=workspace_id,
created_by_id=created_by_id,
updated_by_id=updated_by_id,
)
for label in labels
for label_id in labels
],
batch_size=10,
ignore_conflicts=True,