-
Notifications
You must be signed in to change notification settings - Fork 35
/
sitemaps.py
262 lines (205 loc) · 9.88 KB
/
sitemaps.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
"""
This module contains all sitemap classes which are all based on :class:`django.contrib.sitemaps.Sitemap`.
"""
from __future__ import annotations
import logging
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING
from urllib.parse import urlsplit
from django.conf import settings
from django.contrib.sitemaps import Sitemap
from ..cms.constants import status
from ..cms.models import (
EventTranslation,
OfferTemplate,
PageTranslation,
POITranslation,
)
if TYPE_CHECKING:
from datetime import datetime
from typing import Any
from django.db.models.query import QuerySet
from ..cms.models import Language, Region
from ..cms.models.abstract_content_translation import AbstractContentTranslation
logger = logging.getLogger(__name__)
class WebappSitemap(ABC, Sitemap):
"""
This is an abstract base class for all webapp sitemaps.
"""
#: The default change frequency for all sitemap's urls
changefreq: str = "monthly"
#: The default priority for all sitemap's urls
priority: float = 0.5
@property
@abstractmethod
def queryset(self) -> QuerySet[OfferTemplate | AbstractContentTranslation]:
"""
Each subclass needs at least a ``queryset`` attribute defined.
"""
def __init__(self, region: Region, language: Language) -> None:
"""
This init function sets the region and language parameters.
:param region: The region of this sitemap's urls
:param language: The language of this sitemap's urls
"""
self.region = region
self.language = language
def items(self) -> QuerySet[OfferTemplate | AbstractContentTranslation]:
"""
This functions returns the public translations contained in this sitemap.
:return: The queryset of translation objects
"""
return self.queryset
@staticmethod
def lastmod(translation: OfferTemplate | AbstractContentTranslation) -> datetime:
"""
This functions returns the date when a translation was last modified.
:param translation: The given translation
~integreat_cms.cms.models.events.event_translation.EventTranslation, or
~integreat_cms.cms.models.pois.poi_translation.POITranslation
:return: The list of urls
"""
return translation.last_updated
def _urls(self, page: int, protocol: str, domain: str) -> list[dict[str, Any]]:
"""
This is a patched version of :func:`django.contrib.sitemaps.Sitemap._urls` which adds the alternative languages
to the list of urls.
This patch is required because the inbuilt function can only deal with the i18n backend languages and not with
our custom language model.
Additionally, it overwrites the protocol and domain of the urls with
:attr:`~integreat_cms.core.settings.WEBAPP_URL` because out of the box, :doc:`django:ref/contrib/sitemaps` does only
support this functionality when used together with :doc:`django:ref/contrib/sites`.
:param page: The page for the paginator (will always be ``1`` in our case)
:param protocol: The protocol of the urls
:param domain: The domain of the urls
:return: A list of urls
"""
splitted_url = urlsplit(settings.WEBAPP_URL)
# Generate list of urls without alternative languages
urls = super()._urls(page, splitted_url.scheme, splitted_url.hostname)
for url in urls:
# Add information about alternative languages
url["alternates"] = self.sitemap_alternates(url["item"])
return urls
def sitemap_alternates(
self, obj: OfferTemplate | AbstractContentTranslation
) -> list[dict[str, str]]:
"""
This function returns the sitemap alternatives for a given object
:param obj: The object
:return: The sitemap alternates of the given object
"""
return obj.sitemap_alternates
class PageSitemap(WebappSitemap):
"""
This sitemap contains all urls to page translations for a specific region and language.
Attributes inherited from :class:`~integreat_cms.sitemap.sitemaps.WebappSitemap`:
:attribute changefreq: The usual change frequency of this sitemap's urls (see :attr:`WebappSitemap.changefreq`)
"""
#: The priority of this sitemap's urls
priority: float = 1.0
#: The :class:`~integreat_cms.cms.models.pages.page_translation.PageTranslation` :class:`~django.db.models.query.QuerySet` of this sitemap
queryset: QuerySet[PageTranslation] = PageTranslation.objects.filter(
status=status.PUBLIC
)
def __init__(self, region: Region, language: Language) -> None:
"""
This init function filters the queryset of page translation objects based on the given region and language.
:param region: The region of this sitemap's urls
:param language: The language of this sitemap's urls
"""
# Instantiate WebappSitemap
super().__init__(region, language)
# Filter queryset based on region and language
self.queryset = self.queryset.filter(
page__in=self.region.get_pages(),
language=self.language,
).distinct("page__pk")
class EventSitemap(WebappSitemap):
"""
This sitemap contains all urls to event translations for a specific region and language.
Attributes inherited from :class:`~integreat_cms.sitemap.sitemaps.WebappSitemap`:
:attribute priority: The priority of this sitemap's urls (see :attr:`WebappSitemap.priority`)
"""
#: The usual change frequency of this sitemap's urls
changefreq: str = "daily"
#: The :class:`~integreat_cms.cms.models.events.event_translation.EventTranslation` :class:`~django.db.models.query.QuerySet` of this sitemap
queryset: QuerySet[EventTranslation] = EventTranslation.objects.filter(
event__archived=False, status=status.PUBLIC
)
def __init__(self, region: Region, language: Language) -> None:
"""
This init function filters the queryset of event translation objects based on the given region and language.
:param region: The region of this sitemap's urls
:param language: The language of this sitemap's urls
"""
# Instantiate WebappSitemap
super().__init__(region, language)
# Filter queryset based on region and language
self.queryset = self.queryset.filter(
event__in=self.region.events.all(), language=self.language
).distinct("event__pk")
class POISitemap(WebappSitemap):
"""
This sitemap contains all urls to POI translations for a specific region and language.
Attributes inherited from :class:`~integreat_cms.sitemap.sitemaps.WebappSitemap`:
:attribute changefreq: The usual change frequency of this sitemap's urls (see :attr:`WebappSitemap.changefreq`)
:attribute priority: The priority of this sitemap's urls (see :attr:`WebappSitemap.priority`)
"""
#: The :class:`~integreat_cms.cms.models.pois.poi_translation.POITranslation` :class:`~django.db.models.query.QuerySet` queryset of this sitemap
queryset: QuerySet[POITranslation] = POITranslation.objects.filter(
poi__archived=False, status=status.PUBLIC
)
def __init__(self, region: Region, language: Language) -> None:
"""
This init function filters the queryset of POI translation objects based on the given region and language.
:param region: The region of this sitemap's urls
:param language: The language of this sitemap's urls
"""
# Instantiate WebappSitemap
super().__init__(region, language)
# Filter queryset based on region and language
self.queryset = self.queryset.filter(
poi__in=self.region.pois.all(), language=self.language
).distinct("poi__pk")
class OfferSitemap(WebappSitemap):
"""
This sitemap contains all urls to offers for a specific region.
Attributes inherited from :class:`~integreat_cms.sitemap.sitemaps.WebappSitemap`:
:attribute changefreq: The usual change frequency of this sitemap's urls (see :attr:`WebappSitemap.changefreq`)
"""
#: The priority of this sitemap's urls (``1.0``)
priority = 1.0
#: The :class:`~integreat_cms.cms.models.offers.offer_template.OfferTemplate` :class:`~django.db.models.query.QuerySet` queryset of this sitemap
queryset: QuerySet[OfferTemplate] = OfferTemplate.objects.all()
def __init__(self, region: Region, language: Language) -> None:
"""
This init function filters the queryset of offers objects based on the given region.
:param region: The region of this sitemap's urls
:param language: The language of this sitemap's urls
"""
# Instantiate WebappSitemap
super().__init__(region, language)
# Filter queryset based on region
self.queryset = self.queryset.filter(regions=self.region)
def location(self, item: OfferTemplate) -> str:
"""
This location function returns the absolute path for a given object returned by items().
:param item: Objects passed from items() method
:return: The absolute path of the given offer object
"""
return f"/{self.region.slug}/{self.language.slug}/offers/{item.slug}"
def sitemap_alternates(self, obj: OfferTemplate) -> list[dict[str, str]]:
"""
This sitemap_alternates function returns the language alternatives of offers for the use in sitemaps.
:param obj: Objects passed from items() method
:return: A list of dictionaries containing the alternative translations of offers
"""
return [
{
"location": f"{settings.WEBAPP_URL}/{self.region.slug}/{language.slug}/offers/{obj.slug}",
"lang_slug": language.slug,
}
for language in self.region.visible_languages
if language != self.language
]