diff --git a/cms_redirects/admin.py b/cms_redirects/admin.py index 395e345..4aa92c0 100644 --- a/cms_redirects/admin.py +++ b/cms_redirects/admin.py @@ -1,6 +1,7 @@ from django.contrib import admin from cms_redirects.models import CMSRedirect + class CMSRedirectAdmin(admin.ModelAdmin): list_display = ('old_path', 'new_path', 'page', 'page_site', 'site', 'actual_response_code',) list_filter = ('site',) @@ -8,10 +9,10 @@ class CMSRedirectAdmin(admin.ModelAdmin): radio_fields = {'site': admin.VERTICAL} fieldsets = [ ('Source', { - "fields": ('site','old_path',) + "fields": ('site', 'old_path',) }), ('Destination', { - "fields": ('new_path','page', 'response_code',) + "fields": ('new_path', 'page', 'response_code',) }), ] diff --git a/cms_redirects/middleware.py b/cms_redirects/middleware.py index b296f6d..2a2caa7 100644 --- a/cms_redirects/middleware.py +++ b/cms_redirects/middleware.py @@ -13,7 +13,7 @@ def get_redirect(old_path): def remove_slash(path): - return path[:path.rfind('/')]+path[path.rfind('/')+1:] + return path[:path.rfind('/')] + path[path.rfind('/') + 1:] def remove_query(path): @@ -21,37 +21,35 @@ def remove_query(path): class RedirectFallbackMiddleware(object): + def process_exception(self, request, exception): if isinstance(exception, http.Http404): # First try the whole path. path = request.get_full_path() - r = get_redirect(path) + redirect = get_redirect(path) # It could be that we need to try without a trailing slash. - if r is None and settings.APPEND_SLASH: - r = get_redirect(remove_slash(path)) + if redirect is None and settings.APPEND_SLASH: + redirect = get_redirect(remove_slash(path)) # It could be that the redirect is defined without a query string. - if r is None and path.count('?'): - r = get_redirect(remove_query(path)) + if redirect is None and path.count('?'): + redirect = get_redirect(remove_query(path)) # It could be that we need to try without query string and without a trailing slash. - if r is None and path.count('?') and settings.APPEND_SLASH: - r = get_redirect(remove_slash(remove_query(path))) - + if redirect is None and path.count('?') and settings.APPEND_SLASH: + redirect = get_redirect(remove_slash(remove_query(path))) - if r is not None: - if r.page: - if r.response_code == '302': - return http.HttpResponseRedirect(r.page.get_absolute_url()) + if redirect is not None: + if redirect.page: + if redirect.response_code == '302': + return http.HttpResponseRedirect(redirect.page.get_absolute_url()) else: - return http.HttpResponsePermanentRedirect(r.page.get_absolute_url()) - if r.new_path == '': + return http.HttpResponsePermanentRedirect(redirect.page.get_absolute_url()) + if redirect.new_path == '': return http.HttpResponseGone() - if r.response_code == '302': - return http.HttpResponseRedirect(r.new_path) + if redirect.response_code == '302': + return http.HttpResponseRedirect(redirect.new_path) else: - return http.HttpResponsePermanentRedirect(r.new_path) - - + return http.HttpResponsePermanentRedirect(redirect.new_path) diff --git a/cms_redirects/models.py b/cms_redirects/models.py index 4ab81a1..1280a82 100644 --- a/cms_redirects/models.py +++ b/cms_redirects/models.py @@ -10,33 +10,44 @@ ('302', '302'), ) + class CMSRedirect(models.Model): - page = PageField(verbose_name=_("page"), blank=True, null=True, help_text=_("A link to a page has priority over a text link.")) + page = PageField(verbose_name=_("page"), + blank=True, + null=True, + help_text=_("A link to a page has priority over a text link.")) site = models.ForeignKey(Site) - old_path = models.CharField(_('redirect from'), max_length=200, db_index=True, - help_text=_("This should be an absolute path, excluding the domain name. Example: '/events/search/'.")) - new_path = models.CharField(_('redirect to'), max_length=200, blank=True, - help_text=_("This can be either an absolute path (as above) or a full URL starting with 'http://'.")) - response_code = models.CharField(_('response code'), max_length=3, choices=RESPONSE_CODES, default=RESPONSE_CODES[0][0], - help_text=_("This is the http response code returned if a destination is specified. If no destination is specified the response code will be 410.")) - + old_path = models.CharField(_('redirect from'), + max_length=200, + db_index=True, + help_text=_("This should be an absolute path, excluding the domain name. Example: '/events/search/'.")) + new_path = models.CharField(_('redirect to'), + max_length=200, + blank=True, + help_text=_("This can be either an absolute path (as above) or a full URL starting with 'http://'.")) + response_code = models.CharField(_('response code'), + max_length=3, + choices=RESPONSE_CODES, + default=RESPONSE_CODES[0][0], + help_text=_("This is the http response code returned if a destination is specified. If no destination is specified the response code will be 410.")) + def page_site(self): if self.page: return u'%s' % self.page.site return u'' page_site.short_description = "Page Site" - + def actual_response_code(self): if self.page or self.new_path: return self.response_code return u'410' actual_response_code.short_description = "Response Code" - + class Meta: verbose_name = _('CMS Redirect') verbose_name_plural = _('CMS Redirects') - unique_together=(('site', 'old_path'),) + unique_together = (('site', 'old_path'),) ordering = ('old_path',) - + def __unicode__(self): return "%s ---> %s" % (self.old_path, self.new_path) diff --git a/cms_redirects/tests.py b/cms_redirects/tests.py index adda137..6840520 100644 --- a/cms_redirects/tests.py +++ b/cms_redirects/tests.py @@ -1,82 +1,94 @@ -import unittest - -from django.test.client import Client +from django.test import TestCase from django.contrib.sites.models import Site from django.conf import settings +from django.contrib.auth.models import User +from django.test.utils import override_settings -from cms.models import Page, Title +from cms.api import create_page, publish_page from cms_redirects.models import CMSRedirect -class TestRedirects(unittest.TestCase): + +@override_settings(APPEND_SLASH=False) +class TestRedirects(TestCase): + def setUp(self): - settings.APPEND_SLASH = False self.site = Site.objects.get_current() - page = Page() - page.site = self.site - page.save() - page.publish() - self.page = page + self.page = create_page(title='Hello world!', + # TODO we're assuming here that at least one template exists + # in the settings file. + template=settings.CMS_TEMPLATES[0][0], + language='en' + ) + + self.user = User.objects.create_user('test_user', 'test@example.com', 'test_user') + self.user.is_superuser = True + self.user.save() - title = Title(title="Hello world!") - title.page = page - title.language = u'en' - title.save() + publish_page(self.page, self.user) def test_301_page_redirect(self): - r_301_page = CMSRedirect(site=self.site, page=self.page, old_path='/301_page.php') + r_301_page = CMSRedirect(site=self.site, + page=self.page, + old_path='/301_page.php') r_301_page.save() - c = Client() - r = c.get('/301_page.php') - self.assertEqual(r.status_code, 301) - self.assertEqual(r._headers['location'][1], 'http://testserver/') + response = self.client.get('/301_page.php') + self.assertEqual(response.status_code, 301) + self.assertEqual(response._headers['location'][1], 'http://testserver/') def test_302_page_redirect(self): - r_302_page = CMSRedirect(site=self.site, page=self.page, old_path='/302_page.php', response_code='302') + r_302_page = CMSRedirect(site=self.site, + page=self.page, + old_path='/302_page.php', + response_code='302') r_302_page.save() - c = Client() - r = c.get('/302_page.php') - self.assertEqual(r.status_code, 302) - self.assertEqual(r._headers['location'][1], 'http://testserver/') + response = self.client.get('/302_page.php') + self.assertEqual(response.status_code, 302) + self.assertEqual(response._headers['location'][1], 'http://testserver/') def test_301_path_redirect(self): - r_301_path = CMSRedirect(site=self.site, new_path='/', old_path='/301_path.php') + r_301_path = CMSRedirect(site=self.site, + new_path='/', + old_path='/301_path.php') r_301_path.save() - c = Client() - r = c.get('/301_path.php') - self.assertEqual(r.status_code, 301) - self.assertEqual(r._headers['location'][1], 'http://testserver/') + response = self.client.get('/301_path.php') + self.assertEqual(response.status_code, 301) + self.assertEqual(response._headers['location'][1], 'http://testserver/') def test_302_path_redirect(self): - r_302_path = CMSRedirect(site=self.site, new_path='/', old_path='/302_path.php', response_code='302') + r_302_path = CMSRedirect(site=self.site, + new_path='/', + old_path='/302_path.php', + response_code='302') r_302_path.save() - c = Client() - r = c.get('/302_path.php') - self.assertEqual(r.status_code, 302) - self.assertEqual(r._headers['location'][1], 'http://testserver/') + response = self.client.get('/302_path.php') + self.assertEqual(response.status_code, 302) + self.assertEqual(response._headers['location'][1], 'http://testserver/') def test_410_redirect(self): - r_410 = CMSRedirect(site=self.site, old_path='/410.php', response_code='302') + r_410 = CMSRedirect(site=self.site, + old_path='/410.php', + response_code='302') r_410.save() - c = Client() - r = c.get('/410.php') - self.assertEqual(r.status_code, 410) + response = self.client.get('/410.php') + self.assertEqual(response.status_code, 410) def test_redirect_can_ignore_query_string(self): """ Set up a redirect as in the generic 301 page case, but then try to get this page with a query string appended. Succeed nonetheless. """ - r_301_page = CMSRedirect(site=self.site, page=self.page, old_path='/301_page.php') + r_301_page = CMSRedirect(site=self.site, + page=self.page, + old_path='/301_page.php') r_301_page.save() - c = Client() - r = c.get('/301_page.php?this=is&a=query&string') - self.assertEqual(r.status_code, 301) - self.assertEqual(r._headers['location'][1], 'http://testserver') + response = self.client.get('/301_page.php?this=is&a=query&string') + self.assertEqual(response.status_code, 301) + self.assertEqual(response._headers['location'][1], 'http://testserver/')