diff --git a/djangocms_rest/serializers/pageserializer.py b/djangocms_rest/serializers/pageserializer.py index ee11134..6910d99 100644 --- a/djangocms_rest/serializers/pageserializer.py +++ b/djangocms_rest/serializers/pageserializer.py @@ -1,62 +1,40 @@ - from cms.models import PageContent from django.contrib.contenttypes.models import ContentType +from django.db import models from django.urls import reverse from rest_framework import serializers from rest_framework.request import Request +from djangocms_rest.serializers.placeholder import PlaceholderRelationFieldSerializer -class RESTPage: - def __init__( - self, request: Request, page_content: PageContent - ) -> None: - host = f"{request.scheme}://{request.get_host()}" - self.title: str = page_content.title - self.page_title: str = page_content.page_title or self.title - self.menu_title: str = page_content.menu_title or self.title - self.meta_description: str = page_content.meta_description - self.redirect: str = page_content.redirect - placeholders = page_content.page.get_placeholders(page_content.language) - declared_slots = [ - placeholder.slot for placeholder in page_content.page.get_declared_placeholders() - ] - content_type_id = ContentType.objects.get_for_model( - page_content.__class__ - ).pk - self.placeholders: dict[str, str] = ( - { - placeholder.slot: host - + reverse( - "placeholder-detail", - args=( - page_content.language, - content_type_id, - page_content.pk, - placeholder.slot, - ), - ) - for placeholder in placeholders - if placeholder.slot in declared_slots - } - if page_content - else {} - ) - self.in_navigation: bool = page_content.in_navigation - self.soft_root: bool = page_content.soft_root - self.template: str = page_content.template - self.xframe_options: str = page_content.xframe_options - self.limit_visibility_in_menu: int = page_content.limit_visibility_in_menu - self.language: str = page_content.language - self.absolute_url: str = page_content.page.get_absolute_url(page_content.language) - self.path: str = page_content.page.get_path(page_content.language) +class PageTreeSerializer(serializers.ListSerializer): + def __init__(self, tree, *args, **kwargs): + self.tree = tree + super().__init__(tree.get(None, []), *args, **kwargs) - self.is_home: bool = page_content.page.is_home - self.languages: list[str] = page_content.page.languages.split(",") - super().__init__() + def tree_to_representation(self, item): + repr = self.child.to_representation(item) + if item.page.node in self.tree: + repr["children"] = [ + self.tree_to_representation(child) for child in self.tree[item.page.node] + ] + return repr + def to_representation(self, data): + """ + List of object instances -> List of dicts of primitive datatypes. + """ + # Dealing with nested relationships, data can be a Manager, + # so, first get a queryset from the Manager if needed + iterable = data.all() if isinstance(data, models.manager.BaseManager) else data -class PageSerializer(serializers.Serializer): + return [ + self.tree_to_representation(item) for item in iterable + ] + + +class PageContentSerializer(serializers.Serializer): title = serializers.CharField(max_length=255) page_title = serializers.CharField(max_length=255) menu_title = serializers.CharField(max_length=255) @@ -64,7 +42,7 @@ class PageSerializer(serializers.Serializer): redirect = serializers.CharField(max_length=2048) absolute_url = serializers.URLField(max_length=200) - placeholders = serializers.DictField() + placeholders = serializers.JSONField() path = serializers.CharField(max_length=200) is_home = serializers.BooleanField() @@ -78,3 +56,58 @@ class PageSerializer(serializers.Serializer): languages = serializers.ListSerializer( child=serializers.CharField(), allow_empty=True, required=False ) + + def __init__(self, request: Request, *args, **kwargs) -> None: + self.request = request + super().__init__(*args, **kwargs) + + @classmethod + def many_init(cls, request, instances, *args, **kwargs): + kwargs['child'] = cls(request) + if kwargs.pop("as_tree", True): + tree = {} + for instance in instances: + if instance.page.node.parent in tree: + tree[instance.page.node.parent].append(instance) + else: + tree[instance.page.node.parent] = [instance] + return PageTreeSerializer(tree, *args, **kwargs) + return serializers.ListSerializer(instances, *args, **kwargs) + + def to_representation(self, page_content): + declared_slots = [ + placeholder.slot + for placeholder in page_content.page.get_declared_placeholders() + ] + print(f"{declared_slots=}") + placeholders = [ + placeholder + for placeholder in page_content.page.get_placeholders(page_content.language) + if placeholder.slot in declared_slots + ] + + return { + "title": page_content.title, + "page_title": page_content.page_title or page_content.title, + "menu_title": page_content.menu_title or page_content.title, + "meta_description": page_content.meta_description, + "redirect": page_content.redirect, + "placeholders": PlaceholderRelationFieldSerializer( + self.request, + page_content, + placeholders, + page_content.language, + ).data, + "in_navigation": page_content.in_navigation, + "soft_root": page_content.soft_root, + "template": page_content.template, + "xframe_options": page_content.xframe_options, + "limit_visibility_in_menu": page_content.limit_visibility_in_menu, + "language": page_content.language, + "absolute_url": page_content.page.get_absolute_url( + page_content.language + ), + "path": page_content.page.get_path(page_content.language), + "is_home": page_content.page.is_home, + "languages": page_content.page.languages.split(","), + } diff --git a/djangocms_rest/serializers/placeholder.py b/djangocms_rest/serializers/placeholder.py index 3f66f42..0099d17 100644 --- a/djangocms_rest/serializers/placeholder.py +++ b/djangocms_rest/serializers/placeholder.py @@ -8,8 +8,11 @@ from cms.plugin_rendering import BaseRenderer, ContentRenderer from cms.utils.conf import get_cms_setting from cms.utils.plugins import get_plugins +from django.contrib.contenttypes.models import ContentType from django.contrib.sites.shortcuts import get_current_site +from django.db import models from django.template.defaulttags import now +from django.urls import reverse from rest_framework import serializers from rest_framework.request import Request from sekizai.context import SekizaiContext @@ -238,3 +241,37 @@ def render_html(self, request, placeholder, language): "html": content, **{key: "".join(value) for key, value in sekizai_blocks.items() if value}, } + + +class PlaceholderRelationFieldSerializer(serializers.Serializer): + def __init__(self, request: Request, instance: models.Model, placeholders, language: str, *args, **kwargs) -> None: + self.placeholders = placeholders + self.language: str = language + super().__init__(instance,*args, **kwargs) + self.host: str = f"{request.scheme}://{request.get_host()}" + + for placeholder in self.placeholders: + self.fields[placeholder.slot] = serializers.JSONField() + + def to_representation(self, instance): + content_type_id = ContentType.objects.get_for_model( + instance.__class__ + ).pk + + return ( + { + placeholder.slot: self.host + + reverse( + "placeholder-detail", + args=( + self.language, + content_type_id, + instance.pk, + placeholder.slot, + ), + ) + for placeholder in self.placeholders + } + if instance + else {} + ) diff --git a/djangocms_rest/views.py b/djangocms_rest/views.py index df07c12..78ff11c 100644 --- a/djangocms_rest/views.py +++ b/djangocms_rest/views.py @@ -8,7 +8,7 @@ from rest_framework.response import Response from rest_framework.views import APIView as DRFAPIView -from djangocms_rest.serializers.pageserializer import PageSerializer, RESTPage +from djangocms_rest.serializers.pageserializer import PageContentSerializer from djangocms_rest.serializers.placeholder import PlaceholderSerializer @@ -46,11 +46,11 @@ def get(self, request, language, format=None): if request.user.is_anonymous: qs = qs.filter(login_required=False) pages = ( - RESTPage(request, page.get_content_obj(language, fallback=True)) + page.get_content_obj(language, fallback=True) for page in qs if user_can_view_page(request.user, page) and page.get_content_obj(language, fallback=True) ) - serializer = PageSerializer(pages, many=True, read_only=True) + serializer = PageContentSerializer(request, pages, many=True, read_only=True) return Response(serializer.data)