Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions makeabilitylab/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@
ALLOWED_HOSTS = ['*']

# Makeability Lab Global Variables, including Makeability Lab version
ML_WEBSITE_VERSION = "2.8.1" # Keep this updated with each release and also change the short description below
ML_WEBSITE_VERSION_DESCRIPTION = "SEO: add a dynamic sitemap.xml and advertise it in robots.txt (#1252). /sitemap.xml is generated on each request from our querysets via django.contrib.sitemaps — static listing pages (home, people, publications, projects, awards, news), visible projects, people with a position, and news items — so it stays current with no maintenance. It emits the correct per-environment domain via RequestSite, so no django.contrib.sites and no DB migration are needed. The top-level static robots.txt (served directly by Apache, not Django) now points crawlers at the sitemap. Remaining one-time step: submit the sitemap in Google Search Console once it is live on production."
ML_WEBSITE_VERSION = "2.8.2" # Keep this updated with each release and also change the short description below
ML_WEBSITE_VERSION_DESCRIPTION = "SEO: add a dynamic sitemap.xml and advertise it in robots.txt (#1252). /sitemap.xml is generated on each request from our querysets via django.contrib.sitemaps — static listing pages (home, people, publications, projects, awards, news), visible projects, people with a position, and news items — so it stays current with no maintenance. It emits the correct per-environment domain via RequestSite (no django.contrib.sites, no DB migration) and pins URLs to https so the sitemap lists canonical links rather than http URLs that 302-redirect. Validated on the test server: all 189 sitemap URLs return 200. The top-level static robots.txt (served directly by Apache, not Django) now points crawlers at the sitemap. Remaining one-time step: submit the sitemap in Google Search Console once it is live on production."
DATE_MAKEABILITYLAB_FORMED = datetime.date(2012, 1, 1) # Date Makeability Lab was formed
MAX_BANNERS = 7 # Maximum number of banners on a page

Expand Down
23 changes: 19 additions & 4 deletions website/sitemaps.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,22 @@
from website.models import Project, Person, News


class StaticViewSitemap(Sitemap):
class _HttpsSitemap(Sitemap):
"""
Base sitemap that pins generated URLs to the https scheme.

Apache terminates TLS and proxies to Django over plain HTTP, so the
request scheme Django sees is ``http``. Without this, RequestSite would
emit ``http://`` <loc> URLs that only 302-redirect to https — making the
sitemap advertise non-canonical URLs with an extra hop. Pinning the
protocol here makes every sitemap list the canonical https URLs directly.
(Cosmetic only in local dev, where the site is served over http.)
"""

protocol = "https"


class StaticViewSitemap(_HttpsSitemap):
"""Top-level listing pages that aren't tied to a single model instance."""

changefreq = "weekly"
Expand All @@ -48,7 +63,7 @@ def location(self, item):
return reverse(item)


class ProjectSitemap(Sitemap):
class ProjectSitemap(_HttpsSitemap):
"""Public project pages: /project/<short_name>/."""

changefreq = "weekly"
Expand All @@ -69,7 +84,7 @@ def lastmod(self, obj):
return obj.updated


class PersonSitemap(Sitemap):
class PersonSitemap(_HttpsSitemap):
"""Public people pages: /member/<url_name>/."""

changefreq = "monthly"
Expand All @@ -95,7 +110,7 @@ def lastmod(self, obj):
return obj.bio_datetime_modified


class NewsSitemap(Sitemap):
class NewsSitemap(_HttpsSitemap):
"""News item pages: /news/<slug>/."""

changefreq = "monthly"
Expand Down
15 changes: 15 additions & 0 deletions website/tests/test_sitemap.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
servers, not a Django view, so it isn't covered here.
"""

import re
from datetime import date

from website.tests.base import DatabaseTestCase
Expand Down Expand Up @@ -58,3 +59,17 @@ def test_sitemap_includes_news_item(self):
news = self.make_news_item(title="Big Lab News")
body = self.client.get("/sitemap.xml").content.decode()
self.assertIn(f"/news/{news.slug}/", body)

def test_sitemap_uses_https_scheme(self):
# Apache proxies to Django over plain HTTP, so without a pinned
# protocol the <loc> URLs would be http:// and only 302-redirect to
# https. Every <loc> must be canonical https. See _HttpsSitemap.
self.make_project(name="Scheme Proj", short_name="schemeproj",
is_visible=True)
body = self.client.get("/sitemap.xml").content.decode()
locs = re.findall(r"<loc>(.*?)</loc>", body)
self.assertTrue(locs) # guard against an empty sitemap passing vacuously
self.assertFalse(
[loc for loc in locs if not loc.startswith("https://")],
"all sitemap <loc> URLs should use the https scheme",
)
Loading