Source code for web.views.base

# SPDX-License-Identifier: AGPL-3.0-or-later
#
# Eonvelope - a open-source self-hostable email archiving server
# Copyright (C) 2024 David Aderbauer & The Eonvelope Contributors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

"""Module with baseviews for the Eonvelope webapp."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any, override

from django.core.exceptions import ImproperlyConfigured
from django.views.generic import DetailView
from django.views.generic.edit import DeletionMixin, UpdateView
from django_filters.views import FilterView

from web.mixins import PageSizeMixin

if TYPE_CHECKING:
    from django.http import HttpRequest, HttpResponse
    from django_stubs_ext import StrOrPromise


[docs] class FilterPageView(PageSizeMixin, FilterView): """An extended :class:`django_filters.views.FilterView` with fixed pagination."""
[docs] @override def get_context_data(self, **kwargs: Any) -> dict[str, Any]: """Extended method to pass the query parameters to the context. References: https://jeffpohlmeyer.com/django-filters-with-pagination Returns: The view's context with added query parameters. """ context = super().get_context_data(**kwargs) context["query"] = {} for query_param, query_value in context["filter"].data.items(): if not query_param.startswith("page"): context["query"][query_param] = query_value return context
[docs] class DetailWithDeleteView(DetailView, DeletionMixin): """A view for model details with an option to delete."""
[docs] class UpdateOrDeleteView(UpdateView, DeletionMixin): """A view that implements both updating and deleting.""" delete_success_url: StrOrPromise | None = None """The URL to redirect to after deletion. Must be set.""" success_url: StrOrPromise | None = None """The URL to redirect to after form submission. If this is not set, the models get_absolute_url method is used. """
[docs] @override def get_success_url(self) -> str: """Overridden method to redirect to filter-list after `delete` else to detail.""" if "delete" in self.request.POST: if self.delete_success_url: url = self.delete_success_url.format(**self.object.__dict__) else: try: url = self.get_delete_success_url() except AttributeError as error: raise ImproperlyConfigured( "No URL to redirect to. Either provide a delete_success_url or define" " a get_delete_success_url method." ) from error return url return UpdateView.get_success_url(self)
[docs] @override def post(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: """Overridden method to distinguish the `delete` button.""" if "delete" in request.POST: return DeletionMixin.post(self, request, *args, **kwargs) return UpdateView.post(self, request, *args, **kwargs)