digitalfabrik/integreat-cms

View on GitHub
integreat_cms/cms/views/pages/page_tree_view.py

Summary

Maintainability
A
0 mins
Test Coverage
A
97%
from __future__ import annotations

import logging
from typing import TYPE_CHECKING

from django.conf import settings
from django.contrib import messages
from django.shortcuts import redirect, render
from django.utils.decorators import method_decorator
from django.utils.html import format_html, format_html_join
from django.utils.translation import gettext_lazy as _
from django.views.generic import TemplateView

from ...decorators import permission_required
from ...forms import PageFilterForm
from ...models import PageTranslation
from ..mixins import MachineTranslationContextMixin
from .page_context_mixin import PageContextMixin

if TYPE_CHECKING:
    from typing import Any

    from django.http import HttpRequest, HttpResponse

logger = logging.getLogger(__name__)


@method_decorator(permission_required("cms.view_page"), name="dispatch")
class PageTreeView(TemplateView, PageContextMixin, MachineTranslationContextMixin):
    """
    View for showing the page tree
    """

    #: Template for list of non-archived pages
    template = "pages/page_tree.html"
    #: Template for list of archived pages
    template_archived = "pages/page_tree_archived.html"
    #: Whether or not to show archived pages
    archived = False
    #: The translation model of this list view (used to determine whether machine translations are permitted)
    translation_model = PageTranslation

    @property
    def template_name(self) -> str:
        """
        Select correct HTML template, depending on :attr:`~integreat_cms.cms.views.pages.page_tree_view.PageTreeView.archived` flag
        (see :class:`~django.views.generic.base.TemplateResponseMixin`)

        :return: Path to HTML template
        """

        return self.template_archived if self.archived else self.template

    def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
        r"""
        Render page tree

        :param request: The current request
        :param \*args: The supplied arguments
        :param \**kwargs: The supplied keyword arguments
        :return: The rendered template response
        """

        # current region
        region = request.region

        # current language
        if language_slug := kwargs.get("language_slug"):
            language = region.get_language_or_404(language_slug, only_active=True)
        elif region.default_language:
            return redirect(
                "pages",
                **{
                    "region_slug": region.slug,
                    "language_slug": region.default_language.slug,
                },
            )
        else:
            messages.error(
                request,
                _("Please create at least one language node before creating pages."),
            )
            return redirect(
                "languagetreenodes",
                **{
                    "region_slug": region.slug,
                },
            )

        if not request.user.has_perm("cms.change_page"):
            access_granted_pages = request.user.access_granted_pages(request.region)
            if len(access_granted_pages) > 0:
                messages.info(
                    request,
                    format_html(
                        "{}<ul class='list-disc pl-4'>{}</ul>",
                        _("You can edit only those pages: "),
                        format_html_join(
                            "\n",
                            "<li><a href='{}' class='underline hover:no-underline'>{}</a></li>",
                            [
                                (
                                    page.best_translation.backend_edit_link,
                                    page.best_translation.title,
                                )
                                for page in access_granted_pages
                            ],
                        ),
                    ),
                )
            else:
                messages.warning(
                    request, _("You don't have the permission to edit or create pages.")
                )

        # Initialize page filter form
        filter_form = PageFilterForm(data=request.GET)

        page_queryset = (
            # If filters are applied or only archived pages are requested, fetch all elements from the database
            region.pages.all()
            if filter_form.is_enabled or self.archived
            # Else, only fetch the root pages and load the subpages dynamically via ajax
            else region.pages.filter(lft=1)
        )

        # Cache tree structure to reduce database queries
        pages = (
            page_queryset.prefetch_major_translations()
            .prefetch_related("mirroring_pages")
            .cache_tree(archived=self.archived)
        )

        # Filter pages according to given filters, if any
        pages = filter_form.apply(pages, language_slug)

        return render(
            request,
            self.template_name,
            {
                **self.get_context_data(**kwargs),
                "pages": pages,
                "language": language,
                "source_language": region.get_source_language(language.slug),
                "content_type": "page",
                "languages": region.active_languages,
                "textlab_languages": settings.TEXTLAB_API_LANGUAGES,
                "filter_form": filter_form,
                "XLIFF_EXPORT_VERSION": settings.XLIFF_EXPORT_VERSION,
                "hix_threshold": settings.HIX_REQUIRED_FOR_MT,
                "has_pages_in_translation": PageTranslation.objects.filter(
                    page__in=request.region.non_archived_pages,
                    language=language,
                    currently_in_translation=True,
                ).count()
                > 0,
            },
        )