-
Notifications
You must be signed in to change notification settings - Fork 35
/
views.py
139 lines (109 loc) · 5.64 KB
/
views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
"""
This module contains views for generating the sitemap dynamically.
The views are class-based patches of the inbuilt views :func:`~django.contrib.sitemaps.views.index` and
:func:`~django.contrib.sitemaps.views.sitemap` of the :mod:`django.contrib.sitemaps` :doc:`django:ref/contrib/sitemaps`.
"""
from __future__ import annotations
import logging
from typing import TYPE_CHECKING
from django.conf import settings
from django.contrib.sites.shortcuts import get_current_site
from django.http import Http404
from django.shortcuts import get_object_or_404
from django.urls import reverse
from django.utils.http import http_date
from django.views.generic.base import TemplateResponseMixin, View
from ..cms.constants import region_status
from ..cms.models import Region
from .utils import get_sitemaps
if TYPE_CHECKING:
from typing import Any
from django.http import HttpRequest
from django.template.response import TemplateResponse
logger = logging.getLogger(__name__)
class SitemapIndexView(TemplateResponseMixin, View):
"""
This view allows to generate a sitemap index dynamically.
It is a patched version of :func:`django.contrib.sitemaps.views.index` with the following changes:
* Sitemaps dynamically queried on each request, not on the application startup
* :attr:`~integreat_cms.core.settings.WEBAPP_URL` is used for the domain instead of the host of the sitemap
* Empty sitemaps are not included in the index
"""
#: The template to render (see :class:`~django.views.generic.base.TemplateResponseMixin`)
template_name: str = "sitemap_index.xml"
#: The content type to use for the response (see :class:`~django.views.generic.base.TemplateResponseMixin`)
content_type: str = "application/xml"
def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> TemplateResponse:
r"""
This function handles a get request
:param request: The current request
:param \*args: The supplied args
:param \**kwargs: The supplied keyword args
:return: The rendered template response
"""
logger.debug("Sitemap index requested with args %r and kwargs %r", args, kwargs)
sitemaps = []
# Only add active regions to the sitemap index
for region in Region.objects.filter(status=region_status.ACTIVE):
# Only add visible languages to the sitemap index
for language in region.visible_languages:
# Only add sitemaps with actual content (empty list evaluates to False)
if get_sitemaps(region, language):
sitemap_url = reverse(
"sitemap:region_language",
kwargs={
"region_slug": region.slug,
"language_slug": language.slug,
},
)
absolute_url = f"{settings.WEBAPP_URL}{sitemap_url}"
sitemaps.append({"location": absolute_url})
logger.debug("Sitemap index: %r", sitemaps)
return self.render_to_response({"sitemaps": sitemaps})
class SitemapView(TemplateResponseMixin, View):
"""
This view allows to generate a sitemap dynamically.
A sitemap contains the urls of multiple :class:`~integreat_cms.sitemap.sitemaps.WebappSitemap` instances, one for each content type.
It is a patched version of :func:`django.contrib.sitemaps.views.sitemap` with the following changes:
* Sitemaps dynamically queried on each request, not on the application startup
* HTTP 404 returned if sitemap is empty
* Support for pagination was dropped (only needed with more than 50000 urls per region and language)
"""
#: The template to render (see :class:`~django.views.generic.base.TemplateResponseMixin`)
template_name: str = "sitemap.xml"
#: The content type to use for the response (see :class:`~django.views.generic.base.TemplateResponseMixin`)
content_type: str = "application/xml"
def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> TemplateResponse:
r"""
This function handles a get request
:param request: The current request
:param \*args: The supplied args
:param \**kwargs: The supplied keyword args (should contain ``region_slug`` and ``language_slug``)
:raises ~django.http.Http404: Raises a HTTP 404 if the either the region or language does not exist or is invalid
or if the sitemap is empty.
:return: The rendered template response
"""
logger.debug("Sitemap requested with args %r and kwargs %r", args, kwargs)
# Only return a sitemap if the region is active
region = get_object_or_404(
Region, slug=kwargs.get("region_slug"), status=region_status.ACTIVE
)
# Only return a sitemap if the language is active
language = region.get_language_or_404(
kwargs.get("language_slug"),
only_visible=True,
)
# Only return a sitemap if it contains any elements
if not (sitemaps := get_sitemaps(region, language)):
raise Http404
# Join the lists of all urls of all sitemaps
urls: list[dict[str, Any]] = sum(
(sitemap.get_urls(site=get_current_site(request)) for sitemap in sitemaps),
[],
)
# Pick the latest last_modified if all sitemaps
last_modified = max(sitemap.latest_lastmod for sitemap in sitemaps)
logger.debug("Sitemap urls %r", urls)
response = self.render_to_response({"urlset": urls})
response["Last-Modified"] = http_date(last_modified.timestamp())
return response