Skip to content
Open
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
25 changes: 25 additions & 0 deletions scripts/reset-db.sh
Original file line number Diff line number Diff line change
@@ -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."
9 changes: 9 additions & 0 deletions visualizer/tests/testSimple.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 """
Expand Down
21 changes: 20 additions & 1 deletion visualizer/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
'<!DOCTYPE html>'
'<html lang="en"><body style="font-family: sans-serif; text-align: center;'
' padding: 2em; color: #4a5568;">'
'<h2>Visualization Not Found</h2>'
'<p>This visualization is no longer available.<br>'
'Please re-send the election data to generate a new visualization.</p>'
'</body></html>',
content_type='text/html',
status=404,
)
patch_cache_control(response, no_store=True, no_cache=True, max_age=0)
return response

def get_context_data(self, **kwargs):
config = super().get_context_data(**kwargs)

Expand Down