Some checks failed
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Admin Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Codespell / Check for spelling errors (push) Has been cancelled
Sync Repositories / sync_changes (push) Has been cancelled
Synced from upstream: 8853637e981ed7d8a6cff32bd98e7afe20f54362
198 lines
8.7 KiB
Python
198 lines
8.7 KiB
Python
from rest_framework import serializers
|
|
|
|
|
|
class BaseSerializer(serializers.ModelSerializer):
|
|
id = serializers.PrimaryKeyRelatedField(read_only=True)
|
|
|
|
|
|
class DynamicBaseSerializer(BaseSerializer):
|
|
def __init__(self, *args, **kwargs):
|
|
# If 'fields' is provided in the arguments, remove it and store it separately.
|
|
# This is done so as not to pass this custom argument up to the superclass.
|
|
fields = kwargs.pop("fields", [])
|
|
self.expand = kwargs.pop("expand", []) or []
|
|
fields = self.expand
|
|
|
|
# Call the initialization of the superclass.
|
|
super().__init__(*args, **kwargs)
|
|
# If 'fields' was provided, filter the fields of the serializer accordingly.
|
|
if fields is not None:
|
|
self.fields = self._filter_fields(fields)
|
|
|
|
def _filter_fields(self, fields):
|
|
"""
|
|
Adjust the serializer's fields based on the provided 'fields' list.
|
|
|
|
:param fields: List or dictionary specifying which fields to include in the serializer.
|
|
:return: The updated fields for the serializer.
|
|
"""
|
|
# Check each field_name in the provided fields.
|
|
for field_name in fields:
|
|
# If the field is a dictionary (indicating nested fields),
|
|
# loop through its keys and values.
|
|
if isinstance(field_name, dict):
|
|
for key, value in field_name.items():
|
|
# If the value of this nested field is a list,
|
|
# perform a recursive filter on it.
|
|
if isinstance(value, list):
|
|
self._filter_fields(self.fields[key], value)
|
|
|
|
# Create a list to store allowed fields.
|
|
allowed = []
|
|
for item in fields:
|
|
# If the item is a string, it directly represents a field's name.
|
|
if isinstance(item, str):
|
|
allowed.append(item)
|
|
# If the item is a dictionary, it represents a nested field.
|
|
# Add the key of this dictionary to the allowed list.
|
|
elif isinstance(item, dict):
|
|
allowed.append(list(item.keys())[0])
|
|
|
|
for field in allowed:
|
|
if field not in self.fields:
|
|
from . import (
|
|
WorkspaceLiteSerializer,
|
|
ProjectLiteSerializer,
|
|
UserLiteSerializer,
|
|
StateLiteSerializer,
|
|
IssueSerializer,
|
|
LabelSerializer,
|
|
CycleIssueSerializer,
|
|
IssueLiteSerializer,
|
|
IssueRelationSerializer,
|
|
IntakeIssueLiteSerializer,
|
|
IssueReactionLiteSerializer,
|
|
IssueLinkLiteSerializer,
|
|
RelatedIssueSerializer,
|
|
)
|
|
|
|
# Expansion mapper
|
|
expansion = {
|
|
"user": UserLiteSerializer,
|
|
"workspace": WorkspaceLiteSerializer,
|
|
"project": ProjectLiteSerializer,
|
|
"default_assignee": UserLiteSerializer,
|
|
"project_lead": UserLiteSerializer,
|
|
"state": StateLiteSerializer,
|
|
"created_by": UserLiteSerializer,
|
|
"issue": IssueSerializer,
|
|
"actor": UserLiteSerializer,
|
|
"owned_by": UserLiteSerializer,
|
|
"members": UserLiteSerializer,
|
|
"assignees": UserLiteSerializer,
|
|
"labels": LabelSerializer,
|
|
"issue_cycle": CycleIssueSerializer,
|
|
"parent": IssueLiteSerializer,
|
|
"issue_relation": IssueRelationSerializer,
|
|
"issue_intake": IntakeIssueLiteSerializer,
|
|
"issue_related": RelatedIssueSerializer,
|
|
"issue_reactions": IssueReactionLiteSerializer,
|
|
"issue_link": IssueLinkLiteSerializer,
|
|
"sub_issues": IssueLiteSerializer,
|
|
}
|
|
|
|
if field not in self.fields and field in expansion:
|
|
self.fields[field] = expansion[field](
|
|
many=(
|
|
True
|
|
if field
|
|
in [
|
|
"members",
|
|
"assignees",
|
|
"labels",
|
|
"issue_cycle",
|
|
"issue_relation",
|
|
"issue_intake",
|
|
"issue_reactions",
|
|
"issue_attachment",
|
|
"issue_link",
|
|
"sub_issues",
|
|
"issue_related",
|
|
]
|
|
else False
|
|
)
|
|
)
|
|
|
|
return self.fields
|
|
|
|
def to_representation(self, instance):
|
|
response = super().to_representation(instance)
|
|
|
|
# Ensure 'expand' is iterable before processing
|
|
if self.expand:
|
|
for expand in self.expand:
|
|
if expand in self.fields:
|
|
# Import all the expandable serializers
|
|
from . import (
|
|
WorkspaceLiteSerializer,
|
|
ProjectLiteSerializer,
|
|
UserLiteSerializer,
|
|
StateLiteSerializer,
|
|
IssueSerializer,
|
|
LabelSerializer,
|
|
CycleIssueSerializer,
|
|
IssueRelationSerializer,
|
|
IntakeIssueLiteSerializer,
|
|
IssueLiteSerializer,
|
|
IssueReactionLiteSerializer,
|
|
IssueAttachmentLiteSerializer,
|
|
IssueLinkLiteSerializer,
|
|
RelatedIssueSerializer,
|
|
)
|
|
|
|
# Expansion mapper
|
|
expansion = {
|
|
"user": UserLiteSerializer,
|
|
"workspace": WorkspaceLiteSerializer,
|
|
"project": ProjectLiteSerializer,
|
|
"default_assignee": UserLiteSerializer,
|
|
"project_lead": UserLiteSerializer,
|
|
"state": StateLiteSerializer,
|
|
"created_by": UserLiteSerializer,
|
|
"issue": IssueSerializer,
|
|
"actor": UserLiteSerializer,
|
|
"owned_by": UserLiteSerializer,
|
|
"members": UserLiteSerializer,
|
|
"assignees": UserLiteSerializer,
|
|
"labels": LabelSerializer,
|
|
"issue_cycle": CycleIssueSerializer,
|
|
"parent": IssueLiteSerializer,
|
|
"issue_relation": IssueRelationSerializer,
|
|
"issue_intake": IntakeIssueLiteSerializer,
|
|
"issue_related": RelatedIssueSerializer,
|
|
"issue_reactions": IssueReactionLiteSerializer,
|
|
"issue_attachment": IssueAttachmentLiteSerializer,
|
|
"issue_link": IssueLinkLiteSerializer,
|
|
"sub_issues": IssueLiteSerializer,
|
|
}
|
|
# Check if field in expansion then expand the field
|
|
if expand in expansion:
|
|
if isinstance(response.get(expand), list):
|
|
exp_serializer = expansion[expand](getattr(instance, expand), many=True)
|
|
else:
|
|
exp_serializer = expansion[expand](getattr(instance, expand))
|
|
response[expand] = exp_serializer.data
|
|
else:
|
|
# You might need to handle this case differently
|
|
response[expand] = getattr(instance, f"{expand}_id", None)
|
|
|
|
# Check if issue_attachments is in fields or expand
|
|
if "issue_attachments" in self.fields or "issue_attachments" in self.expand:
|
|
# Import the model here to avoid circular imports
|
|
from plane.db.models import FileAsset
|
|
|
|
issue_id = getattr(instance, "id", None)
|
|
|
|
if issue_id:
|
|
# Fetch related issue_attachments
|
|
issue_attachments = FileAsset.objects.filter(
|
|
issue_id=issue_id,
|
|
entity_type=FileAsset.EntityTypeContext.ISSUE_ATTACHMENT,
|
|
)
|
|
# Serialize issue_attachments and add them to the response
|
|
response["issue_attachments"] = IssueAttachmentLiteSerializer(issue_attachments, many=True).data
|
|
else:
|
|
response["issue_attachments"] = []
|
|
|
|
return response
|