diff options
Diffstat (limited to 'tests/admin_custom_urls')
| -rw-r--r-- | tests/admin_custom_urls/__init__.py | 1 | ||||
| -rw-r--r-- | tests/admin_custom_urls/fixtures/actions.json | 44 | ||||
| -rw-r--r-- | tests/admin_custom_urls/fixtures/users.json | 20 | ||||
| -rw-r--r-- | tests/admin_custom_urls/models.py | 80 | ||||
| -rw-r--r-- | tests/admin_custom_urls/tests.py | 141 | ||||
| -rw-r--r-- | tests/admin_custom_urls/urls.py | 8 |
6 files changed, 294 insertions, 0 deletions
diff --git a/tests/admin_custom_urls/__init__.py b/tests/admin_custom_urls/__init__.py new file mode 100644 index 0000000000..792d600548 --- /dev/null +++ b/tests/admin_custom_urls/__init__.py @@ -0,0 +1 @@ +# diff --git a/tests/admin_custom_urls/fixtures/actions.json b/tests/admin_custom_urls/fixtures/actions.json new file mode 100644 index 0000000000..7c6341d71d --- /dev/null +++ b/tests/admin_custom_urls/fixtures/actions.json @@ -0,0 +1,44 @@ +[ + { + "pk": "delete", + "model": "admin_custom_urls.action", + "fields": { + "description": "Remove things." + } + }, + { + "pk": "rename", + "model": "admin_custom_urls.action", + "fields": { + "description": "Gives things other names." + } + }, + { + "pk": "add", + "model": "admin_custom_urls.action", + "fields": { + "description": "Add things." + } + }, + { + "pk": "path/to/file/", + "model": "admin_custom_urls.action", + "fields": { + "description": "An action with '/' in its name." + } + }, + { + "pk": "path/to/html/document.html", + "model": "admin_custom_urls.action", + "fields": { + "description": "An action with a name similar to a HTML doc path." + } + }, + { + "pk": "javascript:alert('Hello world');\">Click here</a>", + "model": "admin_custom_urls.action", + "fields": { + "description": "An action with a name suspected of being a XSS attempt" + } + } +] diff --git a/tests/admin_custom_urls/fixtures/users.json b/tests/admin_custom_urls/fixtures/users.json new file mode 100644 index 0000000000..72d86d70ad --- /dev/null +++ b/tests/admin_custom_urls/fixtures/users.json @@ -0,0 +1,20 @@ +[ + { + "pk": 100, + "model": "auth.user", + "fields": { + "username": "super", + "first_name": "Super", + "last_name": "User", + "is_active": true, + "is_superuser": true, + "is_staff": true, + "last_login": "2007-05-30 13:20:10", + "groups": [], + "user_permissions": [], + "password": "sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158", + "email": "super@example.com", + "date_joined": "2007-05-30 13:20:10" + } + } +] diff --git a/tests/admin_custom_urls/models.py b/tests/admin_custom_urls/models.py new file mode 100644 index 0000000000..55fc064835 --- /dev/null +++ b/tests/admin_custom_urls/models.py @@ -0,0 +1,80 @@ +from functools import update_wrapper + +from django.contrib import admin +from django.core.urlresolvers import reverse +from django.db import models +from django.http import HttpResponseRedirect +from django.utils.encoding import python_2_unicode_compatible + + +@python_2_unicode_compatible +class Action(models.Model): + name = models.CharField(max_length=50, primary_key=True) + description = models.CharField(max_length=70) + + def __str__(self): + return self.name + + +class ActionAdmin(admin.ModelAdmin): + """ + A ModelAdmin for the Action model that changes the URL of the add_view + to '<app name>/<model name>/!add/' + The Action model has a CharField PK. + """ + + list_display = ('name', 'description') + + def remove_url(self, name): + """ + Remove all entries named 'name' from the ModelAdmin instance URL + patterns list + """ + return [url for url in super(ActionAdmin, self).get_urls() if url.name != name] + + def get_urls(self): + # Add the URL of our custom 'add_view' view to the front of the URLs + # list. Remove the existing one(s) first + from django.conf.urls import patterns, url + + def wrap(view): + def wrapper(*args, **kwargs): + return self.admin_site.admin_view(view)(*args, **kwargs) + return update_wrapper(wrapper, view) + + info = self.model._meta.app_label, self.model._meta.model_name + + view_name = '%s_%s_add' % info + + return patterns('', + url(r'^!add/$', wrap(self.add_view), name=view_name), + ) + self.remove_url(view_name) + + +class Person(models.Model): + name = models.CharField(max_length=20) + +class PersonAdmin(admin.ModelAdmin): + + def response_post_save_add(self, request, obj): + return HttpResponseRedirect( + reverse('admin:admin_custom_urls_person_history', args=[obj.pk])) + + def response_post_save_change(self, request, obj): + return HttpResponseRedirect( + reverse('admin:admin_custom_urls_person_delete', args=[obj.pk])) + + +class Car(models.Model): + name = models.CharField(max_length=20) + +class CarAdmin(admin.ModelAdmin): + + def response_add(self, request, obj, post_url_continue=None): + return super(CarAdmin, self).response_add( + request, obj, post_url_continue=reverse('admin:admin_custom_urls_car_history', args=[obj.pk])) + + +admin.site.register(Action, ActionAdmin) +admin.site.register(Person, PersonAdmin) +admin.site.register(Car, CarAdmin) diff --git a/tests/admin_custom_urls/tests.py b/tests/admin_custom_urls/tests.py new file mode 100644 index 0000000000..31c93410f4 --- /dev/null +++ b/tests/admin_custom_urls/tests.py @@ -0,0 +1,141 @@ +from __future__ import absolute_import, unicode_literals +import warnings + +from django.contrib.admin.util import quote +from django.core.urlresolvers import reverse +from django.template.response import TemplateResponse +from django.test import TestCase +from django.test.utils import override_settings + +from .models import Action, Person, Car + + +@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',)) +class AdminCustomUrlsTest(TestCase): + """ + Remember that: + * The Action model has a CharField PK. + * The ModelAdmin for Action customizes the add_view URL, it's + '<app name>/<model name>/!add/' + """ + fixtures = ['users.json', 'actions.json'] + + def setUp(self): + self.client.login(username='super', password='secret') + + def tearDown(self): + self.client.logout() + + def testBasicAddGet(self): + """ + Ensure GET on the add_view works. + """ + response = self.client.get('/custom_urls/admin/admin_custom_urls/action/!add/') + self.assertIsInstance(response, TemplateResponse) + self.assertEqual(response.status_code, 200) + + def testAddWithGETArgs(self): + """ + Ensure GET on the add_view plus specifying a field value in the query + string works. + """ + response = self.client.get('/custom_urls/admin/admin_custom_urls/action/!add/', {'name': 'My Action'}) + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'value="My Action"') + + def testBasicAddPost(self): + """ + Ensure POST on add_view works. + """ + post_data = { + '_popup': '1', + "name": 'Action added through a popup', + "description": "Description of added action", + } + response = self.client.post('/custom_urls/admin/admin_custom_urls/action/!add/', post_data) + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'dismissAddAnotherPopup') + self.assertContains(response, 'Action added through a popup') + + def testAdminUrlsNoClash(self): + """ + Test that some admin URLs work correctly. + """ + # Should get the change_view for model instance with PK 'add', not show + # the add_view + response = self.client.get('/custom_urls/admin/admin_custom_urls/action/add/') + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'Change action') + + # Ditto, but use reverse() to build the URL + url = reverse('admin:%s_action_change' % Action._meta.app_label, + args=(quote('add'),)) + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'Change action') + + # Should correctly get the change_view for the model instance with the + # funny-looking PK (the one wth a 'path/to/html/document.html' value) + url = reverse('admin:%s_action_change' % Action._meta.app_label, + args=(quote("path/to/html/document.html"),)) + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'Change action') + self.assertContains(response, 'value="path/to/html/document.html"') + + +@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',)) +class CustomRedirects(TestCase): + fixtures = ['users.json', 'actions.json'] + + def setUp(self): + self.client.login(username='super', password='secret') + + def tearDown(self): + self.client.logout() + + def test_post_save_add_redirect(self): + """ + Ensures that ModelAdmin.response_post_save_add() controls the + redirection after the 'Save' button has been pressed when adding a + new object. + Refs 8001, 18310, 19505. + """ + post_data = { 'name': 'John Doe', } + self.assertEqual(Person.objects.count(), 0) + response = self.client.post( + reverse('admin:admin_custom_urls_person_add'), post_data) + persons = Person.objects.all() + self.assertEqual(len(persons), 1) + self.assertRedirects( + response, reverse('admin:admin_custom_urls_person_history', args=[persons[0].pk])) + + def test_post_save_change_redirect(self): + """ + Ensures that ModelAdmin.response_post_save_change() controls the + redirection after the 'Save' button has been pressed when editing an + existing object. + Refs 8001, 18310, 19505. + """ + Person.objects.create(name='John Doe') + self.assertEqual(Person.objects.count(), 1) + person = Person.objects.all()[0] + post_data = { 'name': 'Jack Doe', } + response = self.client.post( + reverse('admin:admin_custom_urls_person_change', args=[person.pk]), post_data) + self.assertRedirects( + response, reverse('admin:admin_custom_urls_person_delete', args=[person.pk])) + + def test_post_url_continue(self): + """ + Ensures that the ModelAdmin.response_add()'s parameter `post_url_continue` + controls the redirection after an object has been created. + """ + post_data = { 'name': 'SuperFast', '_continue': '1' } + self.assertEqual(Car.objects.count(), 0) + response = self.client.post( + reverse('admin:admin_custom_urls_car_add'), post_data) + cars = Car.objects.all() + self.assertEqual(len(cars), 1) + self.assertRedirects( + response, reverse('admin:admin_custom_urls_car_history', args=[cars[0].pk])) diff --git a/tests/admin_custom_urls/urls.py b/tests/admin_custom_urls/urls.py new file mode 100644 index 0000000000..478390737d --- /dev/null +++ b/tests/admin_custom_urls/urls.py @@ -0,0 +1,8 @@ +from django.conf.urls import patterns, include +from django.contrib import admin + + +urlpatterns = patterns('', + (r'^admin/', include(admin.site.urls)), +) + |
