Coverage for app/venv/lib/python3.14/site-packages/weblate/sitemaps.py: 67%
51 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 07:15 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 07:15 +0000
1# Copyright © Michal Čihař <michal@weblate.org>
2#
3# SPDX-License-Identifier: GPL-3.0-or-later
5from itertools import chain
6from typing import NoReturn
8from django.contrib.sitemaps import Sitemap
9from django.urls import reverse
11from weblate.trans.models import Change, Component, Project, Translation
12from weblate.utils.stats import prefetch_stats
15class PagesSitemap(Sitemap):
16 def items(self):
17 return (
18 ("/", 1.0, "daily"),
19 ("/about/", 0.4, "weekly"),
20 ("/keys/", 0.4, "weekly"),
21 )
23 def location(self, obj):
24 return obj[0]
26 def lastmod(self, item):
27 try:
28 return Change.objects.values_list("timestamp", flat=True).latest(
29 "timestamp"
30 )
31 except Change.DoesNotExist:
32 return None
34 def priority(self, item):
35 return item[1]
37 def changefreq(self, item):
38 return item[2]
41class WeblateSitemap(Sitemap):
42 priority = 0.0
43 changefreq = None
45 def items(self) -> NoReturn:
46 raise NotImplementedError
48 def lastmod(self, item):
49 return item.stats.last_changed
51 def get_latest_lastmod(self) -> None:
52 # Finding latest lastmod is expensive as it needs fetching
53 # stats for all objects
54 return None
57class ProjectSitemap(WeblateSitemap):
58 priority = 0.8
60 def items(self):
61 return prefetch_stats(
62 Project.objects.filter(access_control__lt=Project.ACCESS_PRIVATE).order_by(
63 "id"
64 )
65 )
68class ComponentSitemap(WeblateSitemap):
69 priority = 0.6
71 def items(self):
72 return prefetch_stats(
73 Component.objects.prefetch_related("project")
74 .filter(project__access_control__lt=Project.ACCESS_PRIVATE)
75 .order_by("id")
76 )
79class TranslationSitemap(WeblateSitemap):
80 priority = 0.2
82 def items(self):
83 return prefetch_stats(
84 Translation.objects.prefetch_related(
85 "component",
86 "component__project",
87 "language",
88 )
89 .filter(component__project__access_control__lt=Project.ACCESS_PRIVATE)
90 .order_by("id")
91 )
94class EngageSitemap(ProjectSitemap):
95 """Wrapper around ProjectSitemap to point to engage page."""
97 priority = 1.0
99 def location(self, obj):
100 return reverse("engage", kwargs={"path": obj.get_url_path()})
103class EngageLangSitemap(EngageSitemap):
104 """Wrapper to generate sitemap for all per language engage pages."""
106 priority = 0.9
108 def items(self):
109 """Return list of existing project, language tuples."""
110 projects = (
111 Project.objects.filter(access_control__lt=Project.ACCESS_PRIVATE)
112 .order_by("id")
113 .prefetch_languages()
114 )
115 return prefetch_stats(
116 chain.from_iterable(
117 project.project_languages.preload() for project in projects
118 )
119 )
122SITEMAPS = {
123 "project": ProjectSitemap(),
124 "engage": EngageSitemap(),
125 "engagelang": EngageLangSitemap(),
126 "component": ComponentSitemap(),
127 "translation": TranslationSitemap(),
128 "pages": PagesSitemap(),
129}