You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

200 lines
6.8 KiB

from rest_framework import serializers
from django.core.files.uploadedfile import SimpleUploadedFile
from utils.image_compression import maybe_compress_uploaded_file
from .models import Article, ArticleCategory, ArticleContent, ContentPart, TextSection
class AbsoluteImageField(serializers.ImageField):
def to_internal_value(self, data):
uploaded = super().to_internal_value(data)
compressed_bytes = maybe_compress_uploaded_file(uploaded)
if compressed_bytes is None:
return uploaded
return SimpleUploadedFile(
name=getattr(uploaded, "name", "image"),
content=compressed_bytes,
content_type=getattr(uploaded, "content_type", None),
)
def to_representation(self, value):
if not value:
return None
request = self.context.get("request")
url = value.url if hasattr(value, "url") else str(value)
if request:
return request.build_absolute_uri(url)
return url
class AbsoluteFileField(serializers.FileField):
def to_representation(self, value):
if not value:
return None
request = self.context.get("request")
url = value.url if hasattr(value, "url") else str(value)
if request:
return request.build_absolute_uri(url)
return url
class AdminArticleCategorySerializer(serializers.ModelSerializer):
class Meta:
model = ArticleCategory
fields = ["id", "title", "slug", "status", "order"]
class AdminArticleListSerializer(serializers.ModelSerializer):
thumbnail = AbsoluteImageField(required=False, allow_null=True)
article_file = AbsoluteFileField(required=False, allow_null=True)
categories = AdminArticleCategorySerializer(many=True, read_only=True)
class Meta:
model = Article
fields = [
"id",
"title",
"slug",
"thumbnail",
"description",
"article_file",
"view_count",
"download_count",
"status",
"created_at",
"updated_at",
"categories",
]
read_only_fields = ["id", "view_count", "download_count", "created_at", "updated_at"]
class AdminArticleDetailSerializer(serializers.ModelSerializer):
thumbnail = AbsoluteImageField(required=False, allow_null=True)
article_file = AbsoluteFileField(required=False, allow_null=True)
categories = serializers.PrimaryKeyRelatedField(
queryset=ArticleCategory.objects.all(),
many=True,
required=False,
)
categories_detail = AdminArticleCategorySerializer(source="categories", many=True, read_only=True)
remove_thumbnail = serializers.BooleanField(write_only=True, required=False, default=False)
remove_article_file = serializers.BooleanField(write_only=True, required=False, default=False)
class Meta:
model = Article
fields = [
"id",
"title",
"slug",
"thumbnail",
"description",
"content",
"article_file",
"view_count",
"download_count",
"status",
"created_at",
"updated_at",
"categories",
"categories_detail",
"embedded_in",
"remove_thumbnail",
"remove_article_file",
]
read_only_fields = ["id", "view_count", "download_count", "created_at", "updated_at"]
def create(self, validated_data):
validated_data.pop("remove_thumbnail", False)
validated_data.pop("remove_article_file", False)
categories = validated_data.pop("categories", [])
article = super().create(validated_data)
if categories:
article.categories.set(categories)
return article
def update(self, instance, validated_data):
remove_thumbnail = validated_data.pop("remove_thumbnail", False)
remove_article_file = validated_data.pop("remove_article_file", False)
categories = validated_data.pop("categories", None)
if remove_thumbnail and instance.thumbnail:
instance.thumbnail.delete(save=False)
instance.thumbnail = None
if remove_article_file and instance.article_file:
instance.article_file.delete(save=False)
instance.article_file = None
article = super().update(instance, validated_data)
if categories is not None:
article.categories.set(categories)
return article
class AdminTextSectionSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
class Meta:
model = TextSection
fields = ["id", "arabic_text", "translation", "order"]
class AdminContentPartSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
text_sections = AdminTextSectionSerializer(many=True, required=False)
class Meta:
model = ContentPart
fields = ["id", "order", "text_sections"]
class AdminArticleContentSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
parts = AdminContentPartSerializer(many=True, required=False)
class Meta:
model = ArticleContent
fields = [
"id",
"article",
"title",
"content",
"priority",
"status",
"created_at",
"updated_at",
"parts",
]
read_only_fields = ["created_at", "updated_at"]
def _sync_parts(self, article_content, parts_data):
article_content.parts.all().delete()
for part_index, part_data in enumerate(parts_data, start=1):
text_sections_data = part_data.pop("text_sections", [])
part = ContentPart.objects.create(
article_content=article_content,
order=part_data.get("order") or part_index,
)
for section_index, section_data in enumerate(text_sections_data, start=1):
TextSection.objects.create(
content_part=part,
arabic_text=section_data.get("arabic_text", ""),
translation=section_data.get("translation", ""),
order=section_data.get("order") or section_index,
)
def create(self, validated_data):
parts_data = validated_data.pop("parts", [])
article_content = super().create(validated_data)
self._sync_parts(article_content, parts_data)
return article_content
def update(self, instance, validated_data):
parts_data = validated_data.pop("parts", None)
article_content = super().update(instance, validated_data)
if parts_data is not None:
self._sync_parts(article_content, parts_data)
return article_content