diff --git a/scripts/reset-db.sh b/scripts/reset-db.sh new file mode 100755 index 00000000..24f378fa --- /dev/null +++ b/scripts/reset-db.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# Reset the SQLite database and re-run all migrations. +# Use after switching branches with incompatible migration history. +set -e + +source venv/bin/activate +source .env + +rm -f db.sqlite3 +python manage.py migrate + +# Create API-enabled admin user (matches docker-entrypoint.sh) +python manage.py shell -c " +from django.contrib.auth import get_user_model +User = get_user_model() +if not User.objects.filter(username='skaphan').exists(): + user = User.objects.create_superuser('skaphan', 'sjk@kaphan.org', 'rcvisacc0unt') + user.userprofile.canUseApi = True + user.userprofile.save() + print('Created API user skaphan with API access') +else: + print('API user skaphan already exists') +" + +echo "Database reset complete." diff --git a/visualizer/tests/testSimple.py b/visualizer/tests/testSimple.py index f5df1319..139cb4d4 100644 --- a/visualizer/tests/testSimple.py +++ b/visualizer/tests/testSimple.py @@ -293,6 +293,15 @@ def test_embedly_translation(self): response = self.client.get(visualizeUrl) self.assertRedirects(response, expectedBaseURL + 'barchart-interactive', status_code=301) + def test_embedded_404_returns_friendly_page(self): + """ + When an embedded visualization slug doesn't exist, return a friendly + HTML page with a 404 status, so it displays nicely in iframes. + """ + response = self.client.get('/ve/nonexistent-slug') + self.assertEqual(response.status_code, 404) + self.assertIn(b'Visualization Not Found', response.content) + @patch('visualizer.wikipedia.wikipedia.WikipediaExport._get_todays_date_string') def test_wikicode(self, mockGetDateString): """ Validate that the wikicode can be generated and hasn't inadvertently changed """ diff --git a/visualizer/views.py b/visualizer/views.py index d1b51011..2059b8fd 100644 --- a/visualizer/views.py +++ b/visualizer/views.py @@ -12,12 +12,13 @@ from django.contrib.auth import get_user_model from django.contrib.auth.mixins import LoginRequiredMixin from django.core.cache import cache -from django.http import JsonResponse, HttpResponse +from django.http import Http404, JsonResponse, HttpResponse from django.shortcuts import render from django.templatetags.static import static from django.urls import Resolver404 from django.urls import resolve from django.urls import reverse +from django.utils.cache import patch_cache_control from django.utils.decorators import method_decorator from django.views import View from django.views.decorators.clickjacking import xframe_options_exempt @@ -207,6 +208,24 @@ class VisualizeEmbedded(DetailView): model = JsonConfig template_name = 'visualizer/visualize-embedded.html' + def get(self, request, *args, **kwargs): + try: + return super().get(request, *args, **kwargs) + except Http404: + response = HttpResponse( + '' + '
' + 'This visualization is no longer available.
'
+ 'Please re-send the election data to generate a new visualization.