Commit e94b557f8fb0fd8e7272e0168a688083086d21ce

Authored by Tim Graham
1 parent b93836dd

Dropped support for Django < 1.11

1 1 language: python
2 2 env:
3   -- TOXENV=py27-django18
4   -- TOXENV=py34-django18
5   -- TOXENV=py27-django19
6   -- TOXENV=py34-django19
7   -- TOXENV=py27-django110
8   -- TOXENV=py34-django110
9 3 - TOXENV=py27-django111
10 4 - TOXENV=py34-django111
11 5 - TOXENV=py34-django20
12 6 matrix:
13 7 include:
14 8 - python: 3.5
15   - env: TOXENV=py35-django-18
16   - - python: 3.5
17   - env: TOXENV=py35-django-19
18   - - python: 3.5
19   - env: TOXENV=py35-django-110
20   - - python: 3.5
21 9 env: TOXENV=py35-django-111
22 10 - python: 3.5
23 11 env: TOXENV=py35-django-20
... ...
... ... @@ -8,6 +8,7 @@ X.Y.Z (YYYY-MM-DD)
8 8
9 9 * Added testing for Python 3.6.
10 10 * Confirmed support for Django 2.0.
  11 +* Dropped support for Django < 1.11.
11 12
12 13 1.8.0 (2017-02-03)
13 14 ------------------
... ...
... ... @@ -3,10 +3,7 @@ from importlib import import_module
3 3 from django.apps import apps
4 4 from django.conf import settings
5 5 from django.core.exceptions import ImproperlyConfigured
6   -try:
7   - from django.urls import reverse
8   -except ImportError:
9   - from django.core.urlresolvers import reverse # Django < 1.10
  6 +from django.urls import reverse
10 7
11 8
12 9 DEFAULT_COMMENTS_APP = 'django_comments'
... ...
... ... @@ -5,13 +5,10 @@ from django.contrib.contenttypes.fields import GenericForeignKey
5 5 from django.contrib.contenttypes.models import ContentType
6 6 from django.contrib.sites.models import Site
7 7 from django.db import models
  8 +from django.urls import reverse
8 9 from django.utils import timezone
9 10 from django.utils.encoding import python_2_unicode_compatible
10 11 from django.utils.translation import ugettext_lazy as _
11   -try:
12   - from django.urls import reverse
13   -except ImportError:
14   - from django.core.urlresolvers import reverse # Django < 1.10
15 12
16 13 from .managers import CommentManager
17 14
... ... @@ -61,9 +58,7 @@ class CommentAbstractModel(BaseCommentAbstractModel):
61 58 blank=True, null=True, related_name="%(class)s_comments",
62 59 on_delete=models.SET_NULL)
63 60 user_name = models.CharField(_("user's name"), max_length=50, blank=True)
64   - # Explicit `max_length` to apply both to Django 1.7 and 1.8+.
65   - user_email = models.EmailField(_("user's email address"), max_length=254,
66   - blank=True)
  61 + user_email = models.EmailField(_("user's email address"), blank=True)
67 62 user_url = models.URLField(_("user's URL"), blank=True)
68 63
69 64 comment = models.TextField(_('comment'), max_length=COMMENT_MAX_LENGTH)
... ...
... ... @@ -40,11 +40,7 @@ def post_comment(request, next=None, using=None):
40 40 """
41 41 # Fill out some initial data fields from an authenticated user, if present
42 42 data = request.POST.copy()
43   - try:
44   - user_is_authenticated = request.user.is_authenticated()
45   - except TypeError: # Django >= 1.11
46   - user_is_authenticated = request.user.is_authenticated
47   - if user_is_authenticated:
  43 + if request.user.is_authenticated:
48 44 if not data.get('name', ''):
49 45 data["name"] = request.user.get_full_name() or request.user.get_username()
50 46 if not data.get('email', ''):
... ... @@ -107,7 +103,7 @@ def post_comment(request, next=None, using=None):
107 103 # Otherwise create the comment
108 104 comment = form.get_comment_object(site_id=get_current_site(request).id)
109 105 comment.ip_address = request.META.get("REMOTE_ADDR", None) or None
110   - if user_is_authenticated:
  106 + if request.user.is_authenticated:
111 107 comment.user = request.user
112 108
113 109 # Signal that the comment is about to be saved
... ...
... ... @@ -28,7 +28,7 @@ def next_redirect(request, fallback, **get_kwargs):
28 28 Returns an ``HttpResponseRedirect``.
29 29 """
30 30 next = request.POST.get('next')
31   - if not is_safe_url(url=next, host=request.get_host()):
  31 + if not is_safe_url(url=next, allowed_hosts={request.get_host()}):
32 32 next = resolve_url(fallback)
33 33
34 34 if get_kwargs:
... ...
... ... @@ -23,9 +23,6 @@ setup(
23 23 'Development Status :: 5 - Production/Stable',
24 24 'Environment :: Web Environment',
25 25 'Framework :: Django',
26   - 'Framework :: Django :: 1.8',
27   - 'Framework :: Django :: 1.9',
28   - 'Framework :: Django :: 1.10',
29 26 'Framework :: Django :: 1.11',
30 27 'Framework :: Django :: 2.0',
31 28 'Intended Audience :: Developers',
... ... @@ -42,5 +39,5 @@ setup(
42 39 packages=find_packages(exclude=['tests', 'tests.*']),
43 40 include_package_data=True,
44 41 test_suite='tests.runtests.main',
45   - install_requires=['Django>=1.8']
  42 + install_requires=['Django>=1.11']
46 43 )
... ...
1   -try:
2   - from django.urls import reverse
3   -except ImportError:
4   - from django.core.urlresolvers import reverse # Django < 1.10
  1 +from django.urls import reverse
5 2
6 3 from . import views
7 4 from .forms import CustomCommentForm
... ...
... ... @@ -30,11 +30,6 @@ settings.configure(
30 30 'django.contrib.auth.middleware.AuthenticationMiddleware',
31 31 'django.contrib.messages.middleware.MessageMiddleware',
32 32 ),
33   - MIDDLEWARE_CLASSES=(
34   - 'django.contrib.sessions.middleware.SessionMiddleware',
35   - 'django.contrib.auth.middleware.AuthenticationMiddleware',
36   - 'django.contrib.messages.middleware.MessageMiddleware',
37   - ), # Django < 1.10
38 33 ROOT_URLCONF='testapp.urls',
39 34 TEMPLATES=[
40 35 {
... ...
1 1 from __future__ import absolute_import
2 2
3   -from django import VERSION
4 3 from django.contrib.auth.models import User
5 4 from django.contrib.contenttypes.models import ContentType
6 5 from django.contrib.sites.models import Site
... ... @@ -91,12 +90,3 @@ class CommentTestCase(TestCase):
91 90 d = self.getData()
92 91 d.update(f.initial)
93 92 return d
94   -
95   - def assertRedirects(self, response, expected_url, **kwargs):
96   - """
97   - Wrapper for assertRedirects to handle Django pre-1.9.
98   - """
99   - if VERSION >= (1, 9) and expected_url.startswith('http://testserver'):
100   - expected_url = expected_url[len('http://testserver'):]
101   - return super(CommentTestCase, self).assertRedirects(
102   - response, expected_url, **kwargs)
... ...
1 1 from __future__ import absolute_import, unicode_literals
2 2
3   -import re
4   -
5 3 from django.conf import settings
6 4 from django.contrib.auth.models import User
7 5
... ... @@ -12,10 +10,6 @@ from . import CommentTestCase
12 10 from testapp.models import Article, Book
13 11
14 12
15   -# Before Django 1.9, the response contained the scheme/netloc parts
16   -post_redirect_re = re.compile(r'^(http://testserver)?/posted/\?c=(?P<pk>\d+$)')
17   -
18   -
19 13 class CommentViewTests(CommentTestCase):
20 14
21 15 def testPostCommentHTTPMethods(self):
... ... @@ -263,35 +257,38 @@ class CommentViewTests(CommentTestCase):
263 257 a = Article.objects.get(pk=1)
264 258 data = self.getValidData(a)
265 259 response = self.client.post("/post/", data)
266   - location = response["Location"]
267   - match = post_redirect_re.match(location)
268   - self.assertIsNotNone(match, "Unexpected redirect location: %s" % location)
269   -
  260 + self.assertRedirects(
  261 + response,
  262 + '/posted/?c=%s' % Comment.objects.latest('id').pk,
  263 + fetch_redirect_response=False,
  264 + )
270 265 data["next"] = "/somewhere/else/"
271 266 data["comment"] = "This is another comment"
272 267 response = self.client.post("/post/", data)
273   - location = response["Location"]
274   - match = re.search(r"^(http://testserver)?/somewhere/else/\?c=\d+$", location)
275   - self.assertIsNotNone(match, "Unexpected redirect location: %s" % location)
276   -
  268 + self.assertRedirects(
  269 + response,
  270 + '/somewhere/else/?c=%s' % Comment.objects.latest('id').pk,
  271 + fetch_redirect_response=False,
  272 + )
277 273 data["next"] = "http://badserver/somewhere/else/"
278 274 data["comment"] = "This is another comment with an unsafe next url"
279 275 response = self.client.post("/post/", data)
280   - location = response["Location"]
281   - match = post_redirect_re.match(location)
282   - self.assertIsNotNone(match, "Unsafe redirection to: %s" % location)
  276 + self.assertRedirects(
  277 + response,
  278 + '/posted/?c=%s' % Comment.objects.latest('id').pk,
  279 + fetch_redirect_response=False,
  280 + )
283 281
284 282 def testCommentDoneView(self):
285 283 a = Article.objects.get(pk=1)
286 284 data = self.getValidData(a)
287 285 response = self.client.post("/post/", data)
288   - location = response["Location"]
289   - match = post_redirect_re.match(location)
290   - self.assertIsNotNone(match, "Unexpected redirect location: %s" % location)
291   - pk = int(match.group('pk'))
  286 + comment = Comment.objects.latest('id')
  287 + location = '/posted/?c=%s' % comment.pk
  288 + self.assertRedirects(response, location, fetch_redirect_response=False)
292 289 response = self.client.get(location)
293 290 self.assertTemplateUsed(response, "comments/posted.html")
294   - self.assertEqual(response.context["comment"], Comment.objects.get(pk=pk))
  291 + self.assertEqual(response.context["comment"], comment)
295 292
296 293 def testCommentNextWithQueryString(self):
297 294 """
... ... @@ -302,9 +299,11 @@ class CommentViewTests(CommentTestCase):
302 299 data["next"] = "/somewhere/else/?foo=bar"
303 300 data["comment"] = "This is another comment"
304 301 response = self.client.post("/post/", data)
305   - location = response["Location"]
306   - match = re.search(r"^(http://testserver)?/somewhere/else/\?foo=bar&c=\d+$", location)
307   - self.assertIsNotNone(match, "Unexpected redirect location: %s" % location)
  302 + self.assertRedirects(
  303 + response,
  304 + '/somewhere/else/?foo=bar&c=%s' % Comment.objects.latest('id').pk,
  305 + fetch_redirect_response=False,
  306 + )
308 307
309 308 def testCommentPostRedirectWithInvalidIntegerPK(self):
310 309 """
... ... @@ -331,9 +330,11 @@ class CommentViewTests(CommentTestCase):
331 330 data["next"] = "/somewhere/else/?foo=bar#baz"
332 331 data["comment"] = "This is another comment"
333 332 response = self.client.post("/post/", data)
334   - location = response["Location"]
335   - match = re.search(r"^(http://testserver)?/somewhere/else/\?foo=bar&c=\d+#baz$", location)
336   - self.assertIsNotNone(match, "Unexpected redirect location: %s" % location)
  333 + self.assertRedirects(
  334 + response,
  335 + '/somewhere/else/?foo=bar&c=%s#baz' % Comment.objects.latest('id').pk,
  336 + fetch_redirect_response=False,
  337 + )
337 338
338 339 # Without a query string
339 340 a = Article.objects.get(pk=1)
... ... @@ -341,6 +342,8 @@ class CommentViewTests(CommentTestCase):
341 342 data["next"] = "/somewhere/else/#baz"
342 343 data["comment"] = "This is another comment"
343 344 response = self.client.post("/post/", data)
344   - location = response["Location"]
345   - match = re.search(r"^(http://testserver)?/somewhere/else/\?c=\d+#baz$", location)
346   - self.assertIsNotNone(match, "Unexpected redirect location: %s" % location)
  345 + self.assertRedirects(
  346 + response,
  347 + '/somewhere/else/?c=%s#baz' % Comment.objects.latest('id').pk,
  348 + fetch_redirect_response=False,
  349 + )
... ...
... ... @@ -27,7 +27,7 @@ class FlagViewTests(CommentTestCase):
27 27 pk = comments[0].pk
28 28 self.client.login(username="normaluser", password="normaluser")
29 29 response = self.client.post("/flag/%d/" % pk)
30   - self.assertRedirects(response, "http://testserver/flagged/?c=%d" % pk)
  30 + self.assertRedirects(response, "/flagged/?c=%d" % pk)
31 31 c = Comment.objects.get(pk=pk)
32 32 self.assertEqual(c.flags.filter(flag=CommentFlag.SUGGEST_REMOVAL).count(), 1)
33 33 return c
... ... @@ -40,8 +40,7 @@ class FlagViewTests(CommentTestCase):
40 40 pk = comments[0].pk
41 41 self.client.login(username="normaluser", password="normaluser")
42 42 response = self.client.post("/flag/%d/" % pk, {'next': "/go/here/"})
43   - self.assertRedirects(response,
44   - "http://testserver/go/here/?c=%d" % pk, fetch_redirect_response=False)
  43 + self.assertRedirects(response, "/go/here/?c=%d" % pk, fetch_redirect_response=False)
45 44
46 45 def testFlagPostUnsafeNext(self):
47 46 """
... ... @@ -53,8 +52,7 @@ class FlagViewTests(CommentTestCase):
53 52 self.client.login(username="normaluser", password="normaluser")
54 53 response = self.client.post("/flag/%d/" % pk,
55 54 {'next': "http://elsewhere/bad"})
56   - self.assertRedirects(response,
57   - "http://testserver/flagged/?c=%d" % pk)
  55 + self.assertRedirects(response, "/flagged/?c=%d" % pk)
58 56
59 57 def testFlagPostTwice(self):
60 58 """Users don't get to flag comments more than once."""
... ... @@ -69,11 +67,11 @@ class FlagViewTests(CommentTestCase):
69 67 pk = comments[0].pk
70 68 response = self.client.get("/flag/%d/" % pk)
71 69 self.assertRedirects(response,
72   - "http://testserver/accounts/login/?next=/flag/%d/" % pk,
  70 + "/accounts/login/?next=/flag/%d/" % pk,
73 71 fetch_redirect_response=False)
74 72 response = self.client.post("/flag/%d/" % pk)
75 73 self.assertRedirects(response,
76   - "http://testserver/accounts/login/?next=/flag/%d/" % pk,
  74 + "/accounts/login/?next=/flag/%d/" % pk,
77 75 fetch_redirect_response=False)
78 76
79 77 def testFlaggedView(self):
... ... @@ -118,7 +116,7 @@ class DeleteViewTests(CommentTestCase):
118 116 self.client.login(username="normaluser", password="normaluser")
119 117 response = self.client.get("/delete/%d/" % pk)
120 118 self.assertRedirects(response,
121   - "http://testserver/accounts/login/?next=/delete/%d/" % pk,
  119 + "/accounts/login/?next=/delete/%d/" % pk,
122 120 fetch_redirect_response=False)
123 121
124 122 makeModerator("normaluser")
... ... @@ -132,7 +130,7 @@ class DeleteViewTests(CommentTestCase):
132 130 makeModerator("normaluser")
133 131 self.client.login(username="normaluser", password="normaluser")
134 132 response = self.client.post("/delete/%d/" % pk)
135   - self.assertRedirects(response, "http://testserver/deleted/?c=%d" % pk)
  133 + self.assertRedirects(response, "/deleted/?c=%d" % pk)
136 134 c = Comment.objects.get(pk=pk)
137 135 self.assertTrue(c.is_removed)
138 136 self.assertEqual(c.flags.filter(flag=CommentFlag.MODERATOR_DELETION, user__username="normaluser").count(), 1)
... ... @@ -147,8 +145,7 @@ class DeleteViewTests(CommentTestCase):
147 145 makeModerator("normaluser")
148 146 self.client.login(username="normaluser", password="normaluser")
149 147 response = self.client.post("/delete/%d/" % pk, {'next': "/go/here/"})
150   - self.assertRedirects(response,
151   - "http://testserver/go/here/?c=%d" % pk, fetch_redirect_response=False)
  148 + self.assertRedirects(response, "/go/here/?c=%d" % pk, fetch_redirect_response=False)
152 149
153 150 def testDeletePostUnsafeNext(self):
154 151 """
... ... @@ -161,8 +158,7 @@ class DeleteViewTests(CommentTestCase):
161 158 self.client.login(username="normaluser", password="normaluser")
162 159 response = self.client.post("/delete/%d/" % pk,
163 160 {'next': "http://elsewhere/bad"})
164   - self.assertRedirects(response,
165   - "http://testserver/deleted/?c=%d" % pk)
  161 + self.assertRedirects(response, "/deleted/?c=%d" % pk)
166 162
167 163 def testDeleteSignals(self):
168 164 def receive(sender, **kwargs):
... ... @@ -195,7 +191,7 @@ class ApproveViewTests(CommentTestCase):
195 191 response = self.client.get("/approve/%d/" % pk)
196 192 self.assertRedirects(
197 193 response,
198   - "http://testserver/accounts/login/?next=/approve/%d/" % pk,
  194 + "/accounts/login/?next=/approve/%d/" % pk,
199 195 fetch_redirect_response=False
200 196 )
201 197
... ... @@ -212,7 +208,7 @@ class ApproveViewTests(CommentTestCase):
212 208 makeModerator("normaluser")
213 209 self.client.login(username="normaluser", password="normaluser")
214 210 response = self.client.post("/approve/%d/" % c1.pk)
215   - self.assertRedirects(response, "http://testserver/approved/?c=%d" % c1.pk)
  211 + self.assertRedirects(response, "/approved/?c=%d" % c1.pk)
216 212 c = Comment.objects.get(pk=c1.pk)
217 213 self.assertTrue(c.is_public)
218 214 self.assertEqual(c.flags.filter(flag=CommentFlag.MODERATOR_APPROVAL, user__username="normaluser").count(), 1)
... ... @@ -230,9 +226,7 @@ class ApproveViewTests(CommentTestCase):
230 226 self.client.login(username="normaluser", password="normaluser")
231 227 response = self.client.post("/approve/%d/" % c1.pk,
232 228 {'next': "/go/here/"})
233   - self.assertRedirects(response,
234   - "http://testserver/go/here/?c=%d" % c1.pk,
235   - fetch_redirect_response=False)
  229 + self.assertRedirects(response, "/go/here/?c=%d" % c1.pk, fetch_redirect_response=False)
236 230
237 231 def testApprovePostUnsafeNext(self):
238 232 """
... ... @@ -247,8 +241,7 @@ class ApproveViewTests(CommentTestCase):
247 241 self.client.login(username="normaluser", password="normaluser")
248 242 response = self.client.post("/approve/%d/" % c1.pk,
249 243 {'next': "http://elsewhere/bad"})
250   - self.assertRedirects(response,
251   - "http://testserver/approved/?c=%d" % c1.pk)
  244 + self.assertRedirects(response, "/approved/?c=%d" % c1.pk)
252 245
253 246 def testApproveSignals(self):
254 247 def receive(sender, **kwargs):
... ...
1 1 from django.conf.urls import include, url
2   -from django.contrib.auth.views import login, logout
  2 +from django.contrib.auth.views import LoginView, LogoutView
3 3
4 4
5 5 urlpatterns = [
6 6 url(r'^', include('django_comments.urls')),
7 7
8 8 # Provide the auth system login and logout views
9   - url(r'^accounts/login/$', login, {'template_name': 'login.html'}),
10   - url(r'^accounts/logout/$', logout),
  9 + url(r'^accounts/login/$', LoginView.as_view(template_name='login.html')),
  10 + url(r'^accounts/logout/$', LogoutView.as_view()),
11 11 ]
... ...
1 1 [tox]
2 2 envlist =
3   - py{27,34,35}-django1{8,9,10,11}
  3 + py{27,34,35,36}-django111
4 4 py{34,35,36}-django20
5   - py36-django111
6 5 py{35,36}-master
7 6
8 7 [testenv]
... ... @@ -15,9 +14,6 @@ commands = {envpython} setup.py test
15 14 setenv=
16 15 PYTHONWARNINGS=default
17 16 deps=
18   - django-18: Django>=1.8,<1.9
19   - django-19: Django>=1.9a1,<1.10
20   - django-110: Django>=1.10,<1.11
21 17 django-111: Django>=1.11a1,<2.0
22 18 django-20: Django>=2.0a1,<2.1
23 19 django-master: https://github.com/django/django/archive/master.tar.gz
... ...
Please register or login to post a comment