general: use a model to look for redirection before emitting a 404 (#20760)

This commit is contained in:
Frédéric Péters 2018-07-12 20:45:37 +02:00
parent e985190952
commit 13766c1a28
4 changed files with 72 additions and 9 deletions

View File

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.12 on 2018-07-13 06:40
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('data', '0033_auto_20180401_1300'),
]
operations = [
migrations.CreateModel(
name='Redirect',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('old_url', models.CharField(max_length=512)),
('creation_timestamp', models.DateTimeField(auto_now_add=True)),
('page', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='data.Page')),
],
options={
'ordering': ('creation_timestamp',),
},
),
]

View File

@ -409,6 +409,15 @@ class PageSnapshot(models.Model):
return page
class Redirect(models.Model):
old_url = models.CharField(max_length=512)
page = models.ForeignKey(Page)
creation_timestamp = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('creation_timestamp',)
class CellMeta(MediaDefiningClass, ModelBase):
pass

View File

@ -44,7 +44,8 @@ if 'mellon' in settings.INSTALLED_APPS:
else:
get_idps = lambda: []
from combo.data.models import CellBase, PostException, Page, ParentContentCell, TextCell, PageSnapshot
from combo.data.models import (CellBase, PostException, Page, Redirect,
ParentContentCell, TextCell, PageSnapshot)
from combo.profile.models import Profile
from combo.apps.search.models import SearchCell
from combo import utils
@ -353,16 +354,16 @@ def page(request):
except Page.DoesNotExist:
if Page.objects.count() == 0 and parts == ['index']:
return empty_site(request)
else:
if not url.endswith('/') and settings.APPEND_SLASH:
# this is useful to allow /login, /manage, and other non-page
# URLs to work.
return HttpResponsePermanentRedirect(url + '/')
raise Http404()
page = None
if page.get_online_url() != url:
if page is None or page.get_online_url() != url:
if not url.endswith('/') and settings.APPEND_SLASH:
# this is useful to allow /login, /manage, and other non-page
# URLs to work.
return HttpResponsePermanentRedirect(url + '/')
redirect = Redirect.objects.filter(old_url=url).last()
if redirect:
return HttpResponsePermanentRedirect(redirect.page.get_online_url())
raise Http404()
return publish_page(request, page)

View File

@ -16,7 +16,7 @@ from django.test.utils import CaptureQueriesContext
from combo.wsgi import application
from combo.data.models import (Page, CellBase, TextCell, ParentContentCell,
FeedCell, LinkCell, ConfigJsonCell)
FeedCell, LinkCell, ConfigJsonCell, Redirect)
from combo.apps.family.models import FamilyInfosCell
pytestmark = pytest.mark.django_db
@ -584,3 +584,28 @@ def test_synchronous_placeholder(app):
resp = app.get('/foo/', status=200)
assert resp.body.count('data-ajax-cell-must-load="true"') == 1
def test_redirects(app):
Redirect.objects.all().delete()
Page.objects.all().delete()
page = Page(title='Home', slug='index', template_name='standard')
page.save()
page2 = Page(title='Second', slug='second', template_name='standard')
page2.save()
page3 = Page(title='Third', slug='third', template_name='standard', parent=page2)
page3.save()
app.get('/whatever/', status=404)
redirect = Redirect(old_url='/whatever/', page=page3)
redirect.save()
assert app.get('/whatever/', status=301).location == '/second/third/'
assert app.get('/whatever', status=301).location == '/whatever/'
# check the most recent redirect is called
redirect = Redirect(old_url='/whatever/', page=page2)
redirect.save()
assert app.get('/whatever/', status=301).location == '/second/'