Skip to content
This repository has been archived by the owner on Dec 9, 2021. It is now read-only.

Commit

Permalink
746: Add sitemap support to static site (#829)
Browse files Browse the repository at this point in the history
* 746: Add an XML sitemap

Key changes:
* Add XML sitemap generation via django.contrib.sitemap
* Wire it into the URLconf
* Expose it in the <head> of the base template
* Support rendering out the XML sitemap when building a static site - note this only works for the default site due to an issue in Wagtail (Once wagtail-nest/wagtail-bakery#37 is resolved we can ditch our custom code and use wagtail-bakery for this, potentially)

WIP on adding sitemaps - had to add the EXPORTED_SITE_URL to the .env to make it work

* 746: Add tests for sitemap generation

Not testing Django code, just testing the code that calls it
  • Loading branch information
Steve Jalim authored Nov 27, 2019
1 parent cb293ef commit e52ea43
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 3 deletions.
65 changes: 65 additions & 0 deletions developerportal/apps/bakery/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import datetime
from unittest import mock

from django.conf import settings
from django.test import TestCase, override_settings

from wagtail.contrib.redirects.models import Redirect
Expand All @@ -11,6 +12,8 @@
from developerportal.apps.bakery.views import (
CloudfrontInvalidationView,
S3RedirectManagementView,
SitemapBuildableView,
is_secure_request,
)


Expand Down Expand Up @@ -267,3 +270,65 @@ def test_post_publish__no_config_set(self, mock_client):
)
],
)


class SitemapViewTests(TestCase):
@mock.patch("developerportal.apps.bakery.views.SitemapBuildableView.get_content")
@mock.patch("developerportal.apps.bakery.views.SitemapBuildableView.prep_directory")
@mock.patch("developerportal.apps.bakery.views.SitemapBuildableView.build_file")
def test_sitemap_generation(
self, mock_build_file, mock_prep_directory, mock_get_content
):
mock_get_content.return_value = "sitemap content here"

with self.assertLogs("developerportal.apps.bakery.views", level="INFO") as cm:
SitemapBuildableView().build_method()
assert mock_prep_directory.call_count == 1
assert mock_build_file.call_count == 1
mock_build_file.assert_called_once_with(
"/app/build/sitemap.xml", "sitemap content here"
)
self.assertEqual(
cm.output,
[
"INFO:developerportal.apps.bakery.views:Building out XML sitemap.",
"INFO:developerportal.apps.bakery.views:Sitemap building complete.",
],
)


class HelpersTests(TestCase):
def test_is_secure_request(self):
site = Site.objects.first()

port_params = [(80, False), (443, True), (8000, False)]
for params in port_params:
with self.subTest(params=params):
site.port, expected_result = params
self.assertEqual(is_secure_request(site), expected_result)

settings_params = [(True, True), (False, False)]
site.port = 80
for params in settings_params:
with self.subTest(params=params):
secure_redirect, expected_result = params
with override_settings(SECURE_SSL_REDIRECT=secure_redirect):
self.assertEqual(is_secure_request(site), expected_result)


class TestPipelineContents(TestCase):
def test_build_pipeline_contains_all_required_views(self):
# Light regression check - ensure all present and in right order
self.assertEqual(
settings.BAKERY_VIEWS,
(
(
"developerportal.apps.bakery.views."
"AllPublishedPagesViewAllowingSecureRedirect"
),
"bakery.views.Buildable404View",
"developerportal.apps.bakery.views.SitemapBuildableView",
"developerportal.apps.bakery.views.S3RedirectManagementView",
"developerportal.apps.bakery.views.CloudfrontInvalidationView",
),
)
40 changes: 37 additions & 3 deletions developerportal/apps/bakery/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import logging
import os
from http import HTTPStatus
from http.client import HTTPS_PORT

from django.conf import settings
from django.db.models import Q
Expand All @@ -8,14 +10,20 @@

import boto3
from wagtail.contrib.redirects.models import Redirect
from wagtail.contrib.sitemaps.views import sitemap
from wagtail.core.models import Site

from bakery.management.commands import get_s3_client
from bakery.views import BuildableMixin
from wagtailbakery.views import AllPublishedPagesView, WagtailBakeryView

logger = logging.getLogger(__name__)


def is_secure_request(site):
return site.port == HTTPS_PORT or getattr(settings, "SECURE_SSL_REDIRECT", False)


class AllPublishedPagesViewAllowingSecureRedirect(AllPublishedPagesView):
"""Extension of `AllPublishedPagesView` that detects application-level SSL
redirection in order to avoid an issue where rendered pages end up being 0 bytes
Expand All @@ -36,9 +44,7 @@ def build_object(self, obj):
"""
site = obj.get_site()
logger.debug("Building %s" % obj)
secure_request = site.port == 443 or getattr(
settings, "SECURE_SSL_REDIRECT", False
)
secure_request = is_secure_request(site)
self.request = RequestFactory(SERVER_NAME=site.hostname).get(
self.get_url(obj), secure=secure_request
)
Expand Down Expand Up @@ -169,3 +175,31 @@ def post_publish(self, bucket):
logger.warning(
"Got an unexpected response from Cloudfront: {}".format(response)
)


class SitemapBuildableView(BuildableMixin):
# Note that this code is based on https://github.com/wagtail/wagtail-bakery/pull/38
# and ONLY builds out the default site (which is fine for our current needs
# but may change over time). Ideally wagtail-bakery will soon get this behaviour
# and we can switch to its own implementation

build_path = "sitemap.xml"

def build(self):
logger.info("Building out XML sitemap.")
default_site = Site.objects.filter(is_default_site=True).first()
secure_request = is_secure_request(default_site)
self.request = RequestFactory(SERVER_NAME=default_site.hostname).get(
self.build_path, secure=secure_request
)
path = os.path.join(settings.BUILD_DIR, self.build_path)
self.prep_directory(self.build_path)
self.build_file(path, self.get_content())
logger.info("Sitemap building complete.")

@property
def build_method(self):
return self.build

def get_content(self):
return sitemap(self.request).render().content
2 changes: 2 additions & 0 deletions developerportal/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"django.contrib.sitemaps",
"django_celery_results",
"mozilla_django_oidc", # needs to be loaded after auth
]
Expand Down Expand Up @@ -253,6 +254,7 @@
# to run last of all
"developerportal.apps.bakery.views.AllPublishedPagesViewAllowingSecureRedirect",
"bakery.views.Buildable404View",
"developerportal.apps.bakery.views.SitemapBuildableView",
"developerportal.apps.bakery.views.S3RedirectManagementView",
"developerportal.apps.bakery.views.CloudfrontInvalidationView",
)
Expand Down
1 change: 1 addition & 0 deletions developerportal/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="{% static 'css/bundle.css' %}">
<link rel="shortcut icon" href="{% static 'img/icons/favicon.ico' %}">
<link rel="sitemap" type="application/xml" href="/sitemap.xml"/>
{% comment "DISABLED FOR NOW UNTIL WE CAN EXPORT IT TO THE STATIC SITE %}
<link rel="alternate" type="application/rss+xml" href="/posts-feed/">
{% endcomment %}
Expand Down
2 changes: 2 additions & 0 deletions developerportal/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django.views.generic import TemplateView

from wagtail.admin import urls as wagtailadmin_urls
from wagtail.contrib.sitemaps.views import sitemap
from wagtail.core import urls as wagtail_urls
from wagtail.documents import urls as wagtaildocs_urls

Expand All @@ -16,6 +17,7 @@
url(r"^django-admin/", admin.site.urls),
url(r"^admin/", include(wagtailadmin_urls)),
url(r"^documents/", include(wagtaildocs_urls)),
url(r"^sitemap\.xml$", sitemap),
url(r"^posts-feed/", RssFeeds()),
url(r"^auth/", include("mozilla_django_oidc.urls")),
url(
Expand Down

0 comments on commit e52ea43

Please sign in to comment.