|
38 | 38 | from django.shortcuts import get_object_or_404
|
39 | 39 | from django.shortcuts import render
|
40 | 40 | from django.utils.encoding import iri_to_uri
|
| 41 | +from django.views.decorators.cache import cache_page |
41 | 42 | from django.views.static import serve
|
42 | 43 |
|
43 | 44 | from readthedocs.builds.models import Version
|
44 | 45 | from readthedocs.core.permissions import AdminPermission
|
45 | 46 | from readthedocs.core.resolver import resolve, resolve_path
|
46 | 47 | from readthedocs.core.symlink import PrivateSymlink, PublicSymlink
|
47 | 48 | from readthedocs.projects import constants
|
| 49 | +from readthedocs.projects.constants import PRIVATE |
48 | 50 | from readthedocs.projects.models import Project, ProjectRelationship
|
| 51 | +from readthedocs.projects.templatetags.projects_tags import sort_version_aware |
49 | 52 |
|
50 | 53 | log = logging.getLogger(__name__)
|
51 | 54 |
|
@@ -269,3 +272,74 @@ def robots_txt(request, project):
|
269 | 272 | return HttpResponse(open(fullpath).read(), content_type='text/plain')
|
270 | 273 |
|
271 | 274 | return HttpResponse('User-agent: *\nAllow: /\n', content_type='text/plain')
|
| 275 | + |
| 276 | + |
| 277 | +@map_project_slug |
| 278 | +# TODO: make this cache dependent on the project's slug |
| 279 | +@cache_page(60 * 60 * 24 * 3) # 3 days |
| 280 | +def sitemap_xml(request, project): |
| 281 | + |
| 282 | + def priorities_generator(): |
| 283 | + """ |
| 284 | + Generator returning ``priority`` needed by sitemap.xml. |
| 285 | +
|
| 286 | + It generates values from 1 to 0.1 by decreasing in 0.1 on each |
| 287 | + iteration. After 0.1 is reached, it will keep returning 0.1. |
| 288 | + """ |
| 289 | + priorities = [1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.3, 0.2] |
| 290 | + for p in priorities: |
| 291 | + yield p |
| 292 | + |
| 293 | + while True: |
| 294 | + yield 0.1 |
| 295 | + |
| 296 | + def changefreqs_generator(): |
| 297 | + """ |
| 298 | + Generator returning ``changefreq`` needed by sitemap.xml. |
| 299 | +
|
| 300 | + It returns ``daily`` on first iteration, then ``weekly`` and then it |
| 301 | + will return always ``monthly``. |
| 302 | + """ |
| 303 | + changefreqs = ['daily', 'weekly'] |
| 304 | + for c in changefreqs: |
| 305 | + yield c |
| 306 | + |
| 307 | + while True: |
| 308 | + yield 'monthly' |
| 309 | + |
| 310 | + sorted_versions = sort_version_aware(project.versions.filter(active=True)) |
| 311 | + |
| 312 | + versions = [] |
| 313 | + for version, priority, changefreq in zip( |
| 314 | + sorted_versions, priorities_generator(), changefreqs_generator()): |
| 315 | + element = { |
| 316 | + 'loc': version.get_subdomain_url(), |
| 317 | + 'lastmod': version.builds.order_by('-date').first().date.isoformat(), |
| 318 | + 'priority': priority, |
| 319 | + 'changefreq': changefreq, |
| 320 | + 'languages': [], |
| 321 | + } |
| 322 | + if project.translations.exists(): |
| 323 | + for translation in project.translations.all(): |
| 324 | + href = project.get_docs_url( |
| 325 | + version_slug=version.slug, |
| 326 | + lang_slug=translation.language, |
| 327 | + private=version.privacy_level == PRIVATE, |
| 328 | + ) |
| 329 | + element['languages'].append({ |
| 330 | + 'hreflang': translation.language, |
| 331 | + 'href': href, |
| 332 | + }) |
| 333 | + |
| 334 | + # add itself also as protocol requires |
| 335 | + element['languages'].append({ |
| 336 | + 'hreflang': project.language, |
| 337 | + 'href': element['loc'], |
| 338 | + }) |
| 339 | + |
| 340 | + versions.append(element) |
| 341 | + |
| 342 | + context = { |
| 343 | + 'versions': versions, |
| 344 | + } |
| 345 | + return render(request, 'sitemap.xml', context, content_type='application/xml') |
0 commit comments