aircox-radiocampus/aircox/views/page.py
2024-04-30 18:29:34 +02:00

233 lines
7.2 KiB
Python

from django.http import HttpResponse
from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView
from django.views.generic.edit import CreateView, UpdateView
from django.urls import reverse
from honeypot.decorators import check_honeypot
from aircox.conf import settings
from ..filters import PageFilters
from ..forms import CommentForm
from ..models import Comment, Category
from .base import BaseView
from .mixins import AttachedToMixin, FiltersMixin, ParentMixin
__all__ = [
"attached_views",
"attach",
"BasePageListView",
"BasePageDetailView",
"PageDetailView",
"PageListView",
"PageUpdateView",
]
attached_views = {}
"""Register views by StaticPage.Target."""
def attach(cls):
"""Add decorated view class to `attached_views`"""
attached_views[cls.attach_to_value] = cls
return cls
class CanEditMixin:
"""Add context 'can_edit' set to True when object is editable by user."""
def can_edit(self, object):
"""Return True if user can edit current page."""
return False
def get_context_data(self, **kwargs):
return super().get_context_data(can_edit=self.can_edit(self.object), **kwargs)
class BasePageMixin:
category = None
def get_queryset(self):
qs = super().get_queryset().select_subclasses().select_related("cover")
if self.request.user.is_authenticated:
return qs
return qs.published()
def get_category(self, page, **kwargs):
if page:
if getattr(page, "category_id", None):
return page.category
if getattr(page, "parent_id", None):
return self.get_category(page.parent_subclass)
if slug := self.kwargs.get("category_slug"):
return Category.objects.get(slug=slug)
return None
def get_context_data(self, *args, **kwargs):
kwargs.setdefault("category", self.category)
return super().get_context_data(*args, **kwargs)
class BasePageListView(AttachedToMixin, BasePageMixin, ParentMixin, BaseView, ListView):
"""Base view class for BasePage list."""
template_name = "aircox/basepage_list.html"
paginate_by = 30
has_headline = True
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
def get(self, *args, **kwargs):
self.category = self.get_category(self.parent)
return super().get(*args, **kwargs)
def get_queryset(self):
query = super().get_queryset()
if self.category:
query = query.filter(category=self.category)
return query
def get_context_data(self, **kwargs):
kwargs.setdefault("has_headline", self.has_headline)
context = super().get_context_data(**kwargs)
parent = context.get("parent")
if not context.get("page"):
if not context.get("title"):
model = self.model._meta.verbose_name_plural
title = _("{model}")
context["title"] = title.format(model=model, parent=parent)
if not context.get("cover") and parent and parent.cover:
context["cover"] = parent.cover.url
return context
class BasePageDetailView(BasePageMixin, BaseView, DetailView):
"""Base view class for BasePage."""
template_name = "aircox/public.html"
context_object_name = "page"
def get_context_data(self, **kwargs):
if self.object.cover:
kwargs.setdefault("cover", self.object.cover.url)
if self.object.title:
kwargs.setdefault("title", self.object.display_title)
return super().get_context_data(**kwargs)
def get_object(self):
if getattr(self, "object", None):
return self.object
obj = super().get_object()
self.category = self.get_category(obj)
return obj
def get_page(self):
return self.object
class PageListView(FiltersMixin, BasePageListView):
"""Page list view."""
filterset_class = PageFilters
template_name = None
categories = None
filters = None
def get_template_names(self):
return super().get_template_names() + ["aircox/page_list.html"]
def get_filterset(self, data, query):
# FIXME: not the most efficient, cause join then split (django filters)
data["category__id__in"] = ",".join(data.getlist("category__id__in"))
return super().get_filterset(data, query)
def get_queryset(self):
qs = super().get_queryset().select_related("category").order_by("-pub_date")
cat_ids = self.model.objects.published().values_list("category_id", flat=True)
self.categories = Category.objects.filter(id__in=cat_ids)
return qs
@classmethod
def get_secondary_nav(cls):
cat_ids = cls.model.objects.published().values_list("category_id", flat=True)
categories = Category.objects.filter(id__in=cat_ids)
return tuple(
(category.title, reverse(cls.model.list_url_name, kwargs={"category_slug": category.slug}))
for category in categories
)
def get_context_data(self, **kwargs):
kwargs["categories"] = self.categories
return super().get_context_data(**kwargs)
class PageDetailView(CanEditMixin, BasePageDetailView):
"""Base view class for pages."""
template_name = None
context_object_name = "page"
def get_template_names(self):
return super().get_template_names() + ["aircox/page_detail.html"]
def get_queryset(self):
return super().get_queryset().select_related("category")
def get_context_data(self, **kwargs):
if "comment_form" not in kwargs:
kwargs["comment_form"] = self.get_comment_form()
kwargs["comments"] = Comment.objects.filter(page=self.object).order_by("-date")
if parent_subclass := getattr(self.object, "parent_subclass", None):
kwargs["parent"] = parent_subclass
if "related_objects" not in kwargs:
related = self.get_related_queryset()
if related:
related = related[: self.related_count]
kwargs["related_objects"] = related
return super().get_context_data(**kwargs)
def get_comment_form(self):
if settings.ALLOW_COMMENTS and self.object.allow_comments:
return CommentForm()
return None
@classmethod
def as_view(cls, *args, **kwargs):
view = super(PageDetailView, cls).as_view(*args, **kwargs)
return check_honeypot(view, field_name="website")
def post(self, request, *args, **kwargs):
self.object = self.get_object()
if not self.object.allow_comments:
return HttpResponse(_("comments are not allowed"), status=503)
form = CommentForm(request.POST)
comment = form.save(commit=False)
comment.page = self.object
comment.save()
return self.get(request, *args, **kwargs)
class PageCreateView(CanEditMixin, BaseView, CreateView):
def get_page(self):
return self.object
def get_success_url(self):
return self.request.path
class PageUpdateView(CanEditMixin, BaseView, UpdateView):
def get_page(self):
return self.object
def get_success_url(self):
return self.request.path