Skip to content
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
17 changes: 16 additions & 1 deletion apps/api/plane/api/serializers/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
ProjectMember,
State,
User,
EstimatePoint,
)

from .base import BaseSerializer
Expand Down Expand Up @@ -105,13 +106,27 @@ def validate(self, data):
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):
Expand Down
90 changes: 79 additions & 11 deletions apps/api/plane/app/serializers/draft.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from lxml import html

# Django imports
from django.utils import timezone

Expand All @@ -16,7 +18,10 @@
DraftIssueLabel,
DraftIssueCycle,
DraftIssueModule,
ProjectMember,
EstimatePoint,
)
from plane.app.permissions import ROLE


class DraftIssueCreateSerializer(BaseSerializer):
Expand Down Expand Up @@ -57,14 +62,77 @@ def to_representation(self, instance):
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)
Expand All @@ -89,14 +157,14 @@ def create(self, validated_data):
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,
)
Expand All @@ -105,14 +173,14 @@ def create(self, validated_data):
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,
)
Expand Down Expand Up @@ -163,14 +231,14 @@ def update(self, instance, validated_data):
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,
)
Expand Down
66 changes: 62 additions & 4 deletions apps/api/plane/app/serializers/issue.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from lxml import html

# Django imports
from django.utils import timezone
from django.core.validators import URLValidator
Expand Down Expand Up @@ -37,6 +39,7 @@
IssueVersion,
IssueDescriptionVersion,
ProjectMember,
EstimatePoint,
)


Expand Down Expand Up @@ -119,6 +122,16 @@ def validate(self, attrs):
):
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"],
Expand All @@ -127,6 +140,51 @@ def validate(self, attrs):
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):
Expand Down Expand Up @@ -190,14 +248,14 @@ def create(self, validated_data):
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,
)
Expand Down Expand Up @@ -243,14 +301,14 @@ def update(self, instance, validated_data):
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,
Expand Down