From e8dba362844b05818b9bb4c671ea19538f41f8d0 Mon Sep 17 00:00:00 2001 From: Fabian Braun Date: Sat, 25 May 2024 00:58:54 +0200 Subject: [PATCH] Respect page viewing permissions --- djangocms_rest/serializers/placeholder.py | 33 ++++++++++++++------ djangocms_rest/views.py | 38 +++++++++++++++++++---- 2 files changed, 56 insertions(+), 15 deletions(-) diff --git a/djangocms_rest/serializers/placeholder.py b/djangocms_rest/serializers/placeholder.py index 983ec11..3f66f42 100644 --- a/djangocms_rest/serializers/placeholder.py +++ b/djangocms_rest/serializers/placeholder.py @@ -9,10 +9,11 @@ from cms.utils.conf import get_cms_setting from cms.utils.plugins import get_plugins from django.contrib.sites.shortcuts import get_current_site -from django.template.context import Context from django.template.defaulttags import now from rest_framework import serializers from rest_framework.request import Request +from sekizai.context import SekizaiContext +from sekizai.helpers import get_varname def _get_placeholder_cache_version(placeholder, lang, site_id): @@ -183,6 +184,7 @@ class Meta: exclude = ( "id", "placeholder", + "language", "position", "creation_date", "changed_date", @@ -212,14 +214,27 @@ def __init__( use_cache=True, ) if request.GET.get("html", False): - content_renderer = ContentRenderer(request) - placeholder.html = content_renderer.render_placeholder( - placeholder, - context=Context({"request": request, "LANGUAGE_CODE": language}), - language=language, - use_cache=True, - ) - self.fields["html"] = serializers.CharField() + html = self.render_html(request, placeholder, language) + for key, value in html.items(): + if not hasattr(placeholder, key): + setattr(placeholder, key, value) + self.fields[key] = serializers.CharField() placeholder.label = placeholder.get_label() placeholder.language = language super().__init__(placeholder, *args, **kwargs) + + def render_html(self, request, placeholder, language): + content_renderer = ContentRenderer(request) + context = SekizaiContext({"request": request, "LANGUAGE_CODE": language}) + content = content_renderer.render_placeholder( + placeholder, + context=context, + language=language, + use_cache=True, + ) + sekizai_blocks = context[get_varname()] + + return { + "html": content, + **{key: "".join(value) for key, value in sekizai_blocks.items() if value}, + } diff --git a/djangocms_rest/views.py b/djangocms_rest/views.py index f2f0c82..b27aab3 100644 --- a/djangocms_rest/views.py +++ b/djangocms_rest/views.py @@ -1,6 +1,7 @@ -from cms.models import Page, PageUrl, Placeholder +from cms.models import Page, PageUrl, Placeholder, PageContent from cms.utils.conf import get_languages from cms.utils.i18n import get_language_tuple +from cms.utils.page_permissions import user_can_view_page from django.contrib.sites.shortcuts import get_current_site from django.http import Http404 from django.urls import reverse @@ -12,6 +13,7 @@ class APIView(DRFAPIView): + # This is a base class for all API views. It sets the allowed methods to GET and OPTIONS. http_method_names = ("get", "options") @@ -30,9 +32,7 @@ def get(self, request, format=None): class PageList(APIView): - """ - List of all pages on this site for a given language. - """ + """List of all pages on this site for a given language.""" def get(self, request, language, format=None): site = get_current_site(request) @@ -42,7 +42,11 @@ def get(self, request, language, format=None): qs = Page.objects.filter(node__site=site) if request.user.is_anonymous: qs = qs.filter(login_required=False) - pages = (RESTPage(request, page, language=language) for page in qs) + pages = ( + RESTPage(request, page, language=language) + for page in qs + if user_can_view_page(request.user, page) + ) serializer = PageSerializer(pages, many=True, read_only=True) return Response(serializer.data) @@ -74,6 +78,11 @@ def get(self, request, language, path="", format=None): if language not in allowed_languages: raise Http404 page = self.get_object(site, path) + + # Check if the user has permission to view the page + if not user_can_view_page(request.user, page): + raise Http404 + serializer = PageSerializer( RESTPage(request, page, language=language), read_only=True ) @@ -81,7 +90,19 @@ def get(self, request, language, path="", format=None): class PlaceholderDetail(APIView): - """Placeholder contain the dynamic content.""" + """Placeholder contain the dynamic content. This view retrieves the content as a + structured nested object. + + Attributes: + + - "slot": The slot name of the placeholder. + - "content": The content of the placeholder as a nested JSON tree + - "language": The language of the content + - "label": The verbose label of the placeholder + + Optional (if the get parameter `?html=1` is added to the API url): + - "html": The content rendered as html. Sekizai blocks such as "js" or "css" will be added + as separate attributes""" def get_placeholder(self, content_type_id, object_id, slot): try: @@ -103,6 +124,11 @@ def get(self, request, language, content_type_id, object_id, slot, format=None): ) if source is None: raise Http404 + # Check if the user has permission to view the page (should the placeholder be on a page) + if isinstance(source, PageContent) and not user_can_view_page( + request.user, source.page + ): + raise Http404 serializer = PlaceholderSerializer( request, placeholder, language, read_only=True )