From 6cbbb6bd1f76fa71cf0c1fbfe846ee8b22637474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89lie=20Bouttier?= Date: Sun, 10 Dec 2017 13:32:19 +0100 Subject: [PATCH] django 2.0 --- accounts/models.py | 4 +- accounts/urls.py | 13 +-- cfp/converters.py | 8 ++ cfp/decorators.py | 6 +- cfp/models.py | 18 +-- cfp/planning.py | 6 +- cfp/signals.py | 2 +- cfp/templates/cfp/schedule.html | 2 +- cfp/templates/cfp/staff/schedule.html | 2 +- cfp/templates/cfp/staff/talk_details.html | 10 +- cfp/tests.py | 97 ++++++++-------- cfp/urls.py | 133 +++++++++++----------- cfp/views.py | 19 ++-- mailing/models.py | 6 +- mailing/tests.py | 2 +- ponyconf/settings.py | 1 - ponyconf/urls.py | 27 +---- requirements.in | 4 +- requirements.txt | 10 +- 19 files changed, 181 insertions(+), 189 deletions(-) create mode 100644 cfp/converters.py diff --git a/accounts/models.py b/accounts/models.py index 146f0fe..072ebe2 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -1,12 +1,12 @@ from django.contrib.auth.models import User -from django.core.urlresolvers import reverse +from django.urls import reverse from django.db import models from django.utils.translation import ugettext_lazy as _ class Profile(models.Model): - user = models.OneToOneField(User) + user = models.OneToOneField(User, on_delete=models.CASCADE) phone_number = models.CharField(max_length=16, blank=True, default='', verbose_name=_('Phone number')) sms_prefered = models.BooleanField(default=False, verbose_name=_('SMS prefered')) biography = models.TextField(blank=True, verbose_name=_('Biography')) diff --git a/accounts/urls.py b/accounts/urls.py index fe35a6d..750b1dc 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -1,15 +1,12 @@ from django.conf import settings -from django.conf.urls import include, url +from django.urls import include, path from django.contrib.auth import views as auth_views from . import views urlpatterns = [ - url(r'^profile/$', views.profile, name='profile'), - url(r'accounts/login/', views.EmailLoginView.as_view(), {'extra_context': {'buttons': [views.RESET_PASSWORD_BUTTON]}}, name='login'), - #url(r'^login/$', auth_views.login, {'extra_context': {'buttons': [views.RESET_PASSWORD_BUTTON]}}, name='login'), - url(r'^logout/$', auth_views.logout, {'next_page': settings.LOGOUT_REDIRECT_URL}, name='logout'), - #url(r'^avatar/', include('avatar.urls')), - url(r'', include('django.contrib.auth.urls')), - #url(r'', include('registration.backends.default.urls')), + path('profile/', views.profile, name='profile'), + path('accounts/login/', views.EmailLoginView.as_view(), {'extra_context': {'buttons': [views.RESET_PASSWORD_BUTTON]}}, name='login'), + path('logout/', auth_views.logout, {'next_page': settings.LOGOUT_REDIRECT_URL}, name='logout'), + path('', include('django.contrib.auth.urls')), ] diff --git a/cfp/converters.py b/cfp/converters.py new file mode 100644 index 0000000..e42ef99 --- /dev/null +++ b/cfp/converters.py @@ -0,0 +1,8 @@ +class SignedIntConverter: + regex = '[+-]?[0-9]+' + + def to_python(self, value): + return int(value) + + def to_url(self, value): + return '%+d' % value diff --git a/cfp/decorators.py b/cfp/decorators.py index 5caaf20..312814f 100644 --- a/cfp/decorators.py +++ b/cfp/decorators.py @@ -19,7 +19,7 @@ def speaker_required(view_func): except ValueError: raise Http404 speaker = get_object_or_404(Participant, site=request.conference.site, token=speaker_token) - elif request.user.is_authenticated(): + elif request.user.is_authenticated: speaker = get_object_or_404(Participant, site=request.conference.site, email=request.user.email) else: raise PermissionDenied @@ -37,7 +37,7 @@ def volunteer_required(view_func): except ValueError: raise Http404 volunteer = get_object_or_404(Volunteer, site=request.conference.site, token=volunteer_token) - elif request.user.is_authenticated(): + elif request.user.is_authenticated: volunteer = get_object_or_404(Volunteer, site=request.conference.site, email=request.user.email) else: raise PermissionDenied @@ -48,7 +48,7 @@ def volunteer_required(view_func): def staff_required(view_func): def _is_staff(request, *args, **kwargs): - if not request.user.is_authenticated(): + if not request.user.is_authenticated: return login_required(view_func)(request, *args, **kwargs) elif is_staff(request, request.user): return view_func(request, *args, **kwargs) diff --git a/cfp/models.py b/cfp/models.py index e1a95d0..ff9d025 100644 --- a/cfp/models.py +++ b/cfp/models.py @@ -1,6 +1,6 @@ from django.contrib.auth.models import User from django.contrib.sites.models import Site -from django.core.urlresolvers import reverse +from django.urls import reverse from django.core.validators import MaxValueValidator, MinValueValidator from django.core.exceptions import ValidationError from django.db import models @@ -117,7 +117,7 @@ class Participant(PonyConfModel): notes = models.TextField(default='', blank=True, verbose_name=_("Notes"), help_text=_('This field is only visible by organizers.')) vip = models.BooleanField(default=False, verbose_name=_('Invited speaker')) - conversation = models.OneToOneField(MessageThread) + conversation = models.OneToOneField(MessageThread, on_delete=models.PROTECT) objects = ParticipantManager() @@ -332,14 +332,14 @@ class Talk(PonyConfModel): slug = AutoSlugField(populate_from='title', unique=True) description = models.TextField(verbose_name=_('Description of your talk'), help_text=_('This description will be visible on the program.')) - track = models.ForeignKey(Track, blank=True, null=True, verbose_name=_('Track')) + track = models.ForeignKey(Track, blank=True, null=True, verbose_name=_('Track'), on_delete=models.SET_NULL) tags = models.ManyToManyField(Tag, blank=True) notes = models.TextField(blank=True, verbose_name=_('Message to organizers'), help_text=_('If you have any constraint or if you have anything that may ' 'help you to select your talk, like a video or slides of your' ' talk, please write it down here. This field will only be ' 'visible by organizers.')) - category = models.ForeignKey(TalkCategory, verbose_name=_('Talk Category')) + category = models.ForeignKey(TalkCategory, verbose_name=_('Talk Category'), on_delete=models.PROTECT) videotaped = models.BooleanField(_("I'm ok to be recorded on video"), default=True) video_licence = models.CharField(choices=LICENCES, default='CC-BY-SA', max_length=10, verbose_name=_("Video licence")) @@ -348,13 +348,13 @@ class Talk(PonyConfModel): confirmed = models.NullBooleanField(default=None) start_date = models.DateTimeField(null=True, blank=True, default=None, verbose_name=_('Beginning date and time')) duration = models.PositiveIntegerField(default=0, verbose_name=_('Duration (min)')) - room = models.ForeignKey(Room, blank=True, null=True, default=None) + room = models.ForeignKey(Room, blank=True, null=True, default=None, on_delete=models.SET_NULL) plenary = models.BooleanField(default=False) materials = models.FileField(null=True, blank=True, upload_to=talks_materials_destination, verbose_name=_('Materials'), help_text=_('You can use this field to share some materials related to your intervention.')) video = models.URLField(max_length=1000, blank=True, default='', verbose_name='Video URL') token = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) - conversation = models.OneToOneField(MessageThread) + conversation = models.OneToOneField(MessageThread, on_delete=models.PROTECT) objects = TalkManager() @@ -445,8 +445,8 @@ class Talk(PonyConfModel): class Vote(PonyConfModel): - talk = models.ForeignKey(Talk) - user = models.ForeignKey(User) + talk = models.ForeignKey(Talk, on_delete=models.CASCADE) + user = models.ForeignKey(User, on_delete=models.CASCADE) vote = models.IntegerField(validators=[MinValueValidator(-2), MaxValueValidator(2)], default=0) class Meta: @@ -491,7 +491,7 @@ class Volunteer(PonyConfModel): notes = models.TextField(default='', blank=True, verbose_name=_('Notes'), help_text=_('If you have some constraints, you can indicate them here.')) activities = models.ManyToManyField(Activity, blank=True, related_name='volunteers', verbose_name=_('Activities')) - conversation = models.OneToOneField(MessageThread) + conversation = models.OneToOneField(MessageThread, on_delete=models.PROTECT) def get_absolute_url(self): return reverse('volunteer-details', kwargs={'volunteer_id': self.pk}) diff --git a/cfp/planning.py b/cfp/planning.py index a0268b2..24c55bb 100644 --- a/cfp/planning.py +++ b/cfp/planning.py @@ -3,7 +3,7 @@ from django.utils.safestring import mark_safe from django.utils.html import escape from django.utils.timezone import localtime, now from django.core.cache import cache -from django.core.urlresolvers import reverse +from django.urls import reverse from django.template.loader import get_template from django.conf import settings @@ -298,9 +298,9 @@ class Program: if not result: result = getattr(self, '_as_%s' % output)(**kwargs) cache.set(cache_entry, result, 3 * 60 * 60) # 3H - return mark_safe(result) + return result else: - return mark_safe(getattr(self, '_as_%s' % output)(**kwargs)) + return getattr(self, '_as_%s' % output)(**kwargs) def __str__(self): return self.render() diff --git a/cfp/signals.py b/cfp/signals.py index b582901..57cb73c 100644 --- a/cfp/signals.py +++ b/cfp/signals.py @@ -4,7 +4,7 @@ from django.contrib.sites.models import Site from django.conf import settings from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User -from django.core.urlresolvers import reverse +from django.urls import reverse from django.contrib.auth import get_user_model from ponyconf.decorators import disable_for_loaddata diff --git a/cfp/templates/cfp/schedule.html b/cfp/templates/cfp/schedule.html index 97c126d..8f9f528 100644 --- a/cfp/templates/cfp/schedule.html +++ b/cfp/templates/cfp/schedule.html @@ -8,6 +8,6 @@

{% trans "Schedule" %}

-{{ program }} +{{ program|safe }} {% endblock %} diff --git a/cfp/templates/cfp/staff/schedule.html b/cfp/templates/cfp/staff/schedule.html index dd3b5b9..e280b32 100644 --- a/cfp/templates/cfp/staff/schedule.html +++ b/cfp/templates/cfp/staff/schedule.html @@ -8,6 +8,6 @@

{% trans "Schedule" %}

-{{ program }} +{{ program|safe }} {% endblock %} diff --git a/cfp/templates/cfp/staff/talk_details.html b/cfp/templates/cfp/staff/talk_details.html index 635a869..7ab0848 100644 --- a/cfp/templates/cfp/staff/talk_details.html +++ b/cfp/templates/cfp/staff/talk_details.html @@ -88,11 +88,11 @@

- -2 - -1 - 0 - +1 - +2 + -2 + -1 + 0 + +1 + +2

{{ talk.vote_set.count }} {% trans "vote" %}{{ talk.vote_set.count|pluralize }}, {% trans "average:" %} {{ talk.score|floatformat:1 }}

diff --git a/cfp/tests.py b/cfp/tests.py index 81a20bc..872aabf 100644 --- a/cfp/tests.py +++ b/cfp/tests.py @@ -1,6 +1,6 @@ from django.contrib.auth.models import User from django.contrib.sites.models import Site -from django.core.urlresolvers import reverse +from django.urls import reverse from django.test import TestCase from django.utils import timezone from django.contrib import messages @@ -148,11 +148,12 @@ class ProposalTest(TestCase): conf.home = '**Welcome!**' conf.save() response = self.client.get(reverse('home')) - self.assertEquals(response.status_code, 200) + self.assertEqual(response.status_code, 200) self.assertContains(response, 'Welcome!') def test_proposal_closed(self): conf = Conference.objects.get(name='PonyConf') + Talk.objects.filter(site=conf.site).all().delete() TalkCategory.objects.filter(site=conf.site).all().delete() response = self.client.get(reverse('proposal-home')) self.assertEqual(response.status_code, 200) @@ -190,7 +191,7 @@ class ProposalTest(TestCase): 'description': 'PonyConf is cool.', }) speaker = Participant.objects.get(site=site, name='Jean-Mi') - self.assertEquals(speaker.email, 'jean-mi@example.org') + self.assertEqual(speaker.email, 'jean-mi@example.org') talk = Talk.objects.get(site=site, title='PonyConf') self.assertRedirects(response, reverse('proposal-talk-details', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk)), 302) self.assertTrue(speaker in talk.speakers.all()) @@ -211,9 +212,9 @@ class ProposalTest(TestCase): 'biography': 'New bio', }), reverse('proposal-dashboard', kwargs={'speaker_token': speaker.token})) speaker = Participant.objects.get(pk=speaker.pk) - self.assertEquals(speaker.name, 'New name') - self.assertEquals(speaker.email, 'new-mail@example.org') - self.assertEquals(speaker.biography, 'New bio') + self.assertEqual(speaker.name, 'New name') + self.assertEqual(speaker.email, 'new-mail@example.org') + self.assertEqual(speaker.biography, 'New bio') def test_proposal_talk_details(self): speaker1 = Participant.objects.get(name='Speaker 1') @@ -235,7 +236,7 @@ class ProposalTest(TestCase): 'description': 'Talk description', }) talk = Talk.objects.get(title='New talk') - self.assertEquals(talk.description, 'Talk description') + self.assertEqual(talk.description, 'Talk description') self.assertRedirects(response, reverse('proposal-talk-details', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk))) def test_proposal_talk_edit(self): @@ -243,14 +244,14 @@ class ProposalTest(TestCase): talk = Talk.objects.get(title='Talk 1') url = reverse('proposal-talk-edit', kwargs={'speaker_token': speaker.token, 'talk_id': talk.pk}) response = self.client.get(url) - self.assertEquals(response.status_code, 200) + self.assertEqual(response.status_code, 200) self.assertRedirects(self.client.post(url, { 'title': 'New title', 'description': 'New description', }), reverse('proposal-talk-details', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk))) talk = Talk.objects.get(pk=talk.pk) - self.assertEquals(talk.title, 'New title') - self.assertEquals(talk.description, 'New description') + self.assertEqual(talk.title, 'New title') + self.assertEqual(talk.description, 'New description') def test_proposal_speaker_add(self): speaker1 = Participant.objects.get(name='Speaker 1') @@ -271,13 +272,13 @@ class ProposalTest(TestCase): 'notify': 1, }) self.assertRedirects(response, url_talk) - self.assertEquals(talk.speakers.count(), speaker_count+1) + self.assertEqual(talk.speakers.count(), speaker_count+1) speaker5 = Participant.objects.get(name='Speaker 5') self.assertTrue(speaker5 in talk.speakers.all()) self.assertFalse(speaker4 in talk.speakers.all()) response = self.client.get(url_add_existing) self.assertRedirects(response, url_talk) - self.assertEquals(talk.speakers.count(), speaker_count+2) + self.assertEqual(talk.speakers.count(), speaker_count+2) self.assertTrue(speaker4 in talk.speakers.all()) @@ -334,11 +335,11 @@ class ProposalTest(TestCase): talk.accepted = None talk.save() for url in [confirm_url, desist_url]: - self.assertEquals(self.client.get(url).status_code, 403) + self.assertEqual(self.client.get(url).status_code, 403) talk.accepted = False talk.save() for url in [confirm_url, desist_url]: - self.assertEquals(self.client.get(url).status_code, 403) + self.assertEqual(self.client.get(url).status_code, 403) talk.accepted = True talk.save() conf.save() @@ -393,13 +394,13 @@ class StaffTest(TestCase): url = reverse('staff') self.assertRedirects(self.client.get(url), reverse('login') + '?next=' + url) self.client.login(username='admin', password='admin') - self.assertEquals(self.client.get(url).status_code, 200) + self.assertEqual(self.client.get(url).status_code, 200) def test_admin(self): url = reverse('admin') self.assertRedirects(self.client.get(url), reverse('login') + '?next=' + url) self.client.login(username='admin', password='admin') - self.assertEquals(self.client.get(url).status_code, 200) + self.assertEqual(self.client.get(url).status_code, 200) def test_volunteer_list(self): url = reverse('volunteer-list') @@ -431,14 +432,14 @@ class StaffTest(TestCase): self.assertRedirects(self.client.get(url), reverse('login') + '?next=' + url) self.client.login(username='admin', password='admin') response = self.client.get(url) - self.assertEquals(response.status_code, 200) + self.assertEqual(response.status_code, 200) def test_activity_add(self): url = reverse('activity-list') self.assertRedirects(self.client.get(url), reverse('login') + '?next=' + url) self.client.login(username='admin', password='admin') response = self.client.get(url) - self.assertEquals(response.status_code, 200) + self.assertEqual(response.status_code, 200) def test_activity_edit(self): conf = Conference.objects.get(name='PonyConf') @@ -446,13 +447,13 @@ class StaffTest(TestCase): url = reverse('activity-edit', kwargs={'slug': activity.slug}) self.assertRedirects(self.client.get(url), reverse('login') + '?next=' + url) self.client.login(username='admin', password='admin') - self.assertEquals(self.client.get(url).status_code, 200) + self.assertEqual(self.client.get(url).status_code, 200) response = self.client.post(url, { 'name': 'New activity name', }) self.assertRedirects(response, reverse('activity-list')) activity = Activity.objects.get(pk=activity.pk) - self.assertEquals(activity.name, 'New activity name') + self.assertEqual(activity.name, 'New activity name') def test_activity_remove(self): pass @@ -462,7 +463,7 @@ class StaffTest(TestCase): self.assertRedirects(self.client.get(url), reverse('login') + '?next=' + url) self.client.login(username='admin', password='admin') response = self.client.get(url) - self.assertEquals(response.status_code, 200) + self.assertEqual(response.status_code, 200) self.assertContains(response, 'Speaker 1') self.assertContains(response, 'Speaker 2') response = self.client.get(url + '?format=csv') @@ -478,7 +479,7 @@ class StaffTest(TestCase): self.assertRedirects(self.client.get(url), reverse('login') + '?next=' + url) self.client.login(username='admin', password='admin') response = self.client.get(url) - self.assertEquals(response.status_code, 200) + self.assertEqual(response.status_code, 200) self.assertContains(response, 'Speaker 1') self.assertContains(response, 'Speaker 2') self.assertNotContains(response, 'Speaker 3') @@ -491,16 +492,16 @@ class StaffTest(TestCase): self.assertRedirects(self.client.get(url), reverse('login') + '?next=' + url) self.client.login(username='admin', password='admin') response = self.client.get(url) - self.assertEquals(response.status_code, 200) + self.assertEqual(response.status_code, 200) self.assertRedirects(self.client.post(url, { 'name': 'New name', 'email': 'new-mail@example.org', 'biography': 'New bio', }), reverse('participant-details', kwargs={'participant_id': speaker.pk})) speaker = Participant.objects.get(pk=speaker.pk) - self.assertEquals(speaker.name, 'New name') - self.assertEquals(speaker.email, 'new-mail@example.org') - self.assertEquals(speaker.biography, 'New bio') + self.assertEqual(speaker.name, 'New name') + self.assertEqual(speaker.email, 'new-mail@example.org') + self.assertEqual(speaker.biography, 'New bio') def test_speaker_add_talk(self): speaker = Participant.objects.get(name='Speaker 1') @@ -508,14 +509,14 @@ class StaffTest(TestCase): self.assertRedirects(self.client.get(url), reverse('login') + '?next=' + url) self.client.login(username='admin', password='admin') response = self.client.get(url) - self.assertEquals(response.status_code, 200) + self.assertEqual(response.status_code, 200) def test_talk_list(self): url = reverse('talk-list') self.assertRedirects(self.client.get(url), reverse('login') + '?next=' + url) self.client.login(username='admin', password='admin') response = self.client.get(url) - self.assertEquals(response.status_code, 200) + self.assertEqual(response.status_code, 200) self.assertContains(response, 'Talk 1') response = self.client.get(url + '?format=csv') self.assertEqual(response.status_code, 200) @@ -527,7 +528,7 @@ class StaffTest(TestCase): self.assertRedirects(self.client.get(url), reverse('login') + '?next=' + url) self.client.login(username='admin', password='admin') response = self.client.get(url) - self.assertEquals(response.status_code, 200) + self.assertEqual(response.status_code, 200) self.assertContains(response, talk.title) def test_conference(self): @@ -536,7 +537,7 @@ class StaffTest(TestCase): self.assertRedirects(self.client.get(url), reverse('login') + '?next=' + url) self.client.login(username='admin', password='admin') response = self.client.get(url) - self.assertEquals(response.status_code, 200) + self.assertEqual(response.status_code, 200) def test_conference_opened_categories(self): # TODO cover all cases @@ -618,7 +619,7 @@ class StaffTest(TestCase): self.assertRedirects(self.client.get(accept_url), reverse('login') + '?next=' + accept_url) self.assertRedirects(self.client.get(decline_url), reverse('login') + '?next=' + decline_url) self.client.login(username='admin', password='admin') - self.assertEquals(self.client.get(accept_url).status_code, 200) + self.assertEqual(self.client.get(accept_url).status_code, 200) self.assertRedirects(self.client.post(accept_url), details_url) talk = Talk.objects.get(pk=talk.pk) self.assertTrue(talk.accepted) @@ -627,7 +628,7 @@ class StaffTest(TestCase): self.assertRedirects(self.client.post(accept_url, {'message': 'Ok'}), details_url) talk = Talk.objects.get(pk=talk.pk) self.assertTrue(talk.accepted) - self.assertEquals(self.client.get(decline_url).status_code, 200) + self.assertEqual(self.client.get(decline_url).status_code, 200) self.assertRedirects(self.client.post(decline_url), details_url) talk = Talk.objects.get(pk=talk.pk) self.assertFalse(talk.accepted) @@ -648,50 +649,50 @@ class StaffTest(TestCase): self.assertRedirects(self.client.get(confirm_url), reverse('login') + '?next=' + confirm_url) self.assertRedirects(self.client.get(desist_url), reverse('login') + '?next=' + desist_url) self.client.login(username='admin', password='admin') - self.assertEquals(self.client.get(confirm_url).status_code, 403) - self.assertEquals(self.client.get(desist_url).status_code, 403) + self.assertEqual(self.client.get(confirm_url).status_code, 403) + self.assertEqual(self.client.get(desist_url).status_code, 403) talk.accepted = False talk.save() - self.assertEquals(self.client.get(confirm_url).status_code, 403) - self.assertEquals(self.client.get(desist_url).status_code, 403) + self.assertEqual(self.client.get(confirm_url).status_code, 403) + self.assertEqual(self.client.get(desist_url).status_code, 403) talk.accepted = True talk.save() self.assertRedirects(self.client.get(confirm_url), details_url) talk = Talk.objects.get(pk=talk.pk) self.assertTrue(talk.confirmed) - self.assertEquals(self.client.get(confirm_url).status_code, 403) + self.assertEqual(self.client.get(confirm_url).status_code, 403) self.assertRedirects(self.client.get(desist_url), details_url) talk = Talk.objects.get(pk=talk.pk) self.assertFalse(talk.confirmed) - self.assertEquals(self.client.get(desist_url).status_code, 403) + self.assertEqual(self.client.get(desist_url).status_code, 403) def test_category_list(self): url = reverse('category-list') self.assertRedirects(self.client.get(url), reverse('login') + '?next=' + url) self.client.login(username='admin', password='admin') response = self.client.get(url) - self.assertEquals(response.status_code, 200) + self.assertEqual(response.status_code, 200) def test_category_add(self): url = reverse('category-add') self.assertRedirects(self.client.get(url), reverse('login') + '?next=' + url) self.client.login(username='admin', password='admin') response = self.client.get(url) - self.assertEquals(response.status_code, 200) + self.assertEqual(response.status_code, 200) def test_tag_list(self): url = reverse('tag-list') self.assertRedirects(self.client.get(url), reverse('login') + '?next=' + url) self.client.login(username='admin', password='admin') response = self.client.get(url) - self.assertEquals(response.status_code, 200) + self.assertEqual(response.status_code, 200) def test_tag_add(self): url = reverse('tag-add') self.assertRedirects(self.client.get(url), reverse('login') + '?next=' + url) self.client.login(username='admin', password='admin') response = self.client.get(url) - self.assertEquals(response.status_code, 200) + self.assertEqual(response.status_code, 200) class ScheduleTest(TestCase): @@ -719,10 +720,10 @@ class ScheduleTest(TestCase): def test_public_schedule(self): site = Site.objects.first() conf = Conference.objects.get(site=site) - self.assertEquals(self.client.get(reverse('public-schedule')).status_code, 403) + self.assertEqual(self.client.get(reverse('public-schedule')).status_code, 403) conf.schedule_publishing_date = timezone.now() - timedelta(hours=1) conf.save() - self.assertEquals(self.client.get(reverse('public-schedule')).status_code, 200) + self.assertEqual(self.client.get(reverse('public-schedule')).status_code, 200) conf.schedule_redirection_url ='http://example.net/schedule.html' conf.save() self.assertRedirects(self.client.get(reverse('public-schedule')), conf.schedule_redirection_url, status_code=302, fetch_redirect_response=False) @@ -735,7 +736,7 @@ class ScheduleTest(TestCase): def test_xml(self): self.client.login(username='admin', password='admin') response = self.client.get(reverse('staff-schedule') + 'xml/') - self.assertEquals(response.status_code, 200) + self.assertEqual(response.status_code, 200) self.assertContains(response, 'Public tag') self.assertNotContains(response, 'Private tag') ET.fromstring(response.content) @@ -743,7 +744,7 @@ class ScheduleTest(TestCase): def test_ics(self): self.client.login(username='admin', password='admin') response = self.client.get(reverse('staff-schedule') + 'ics/') - self.assertEquals(response.status_code, 200) + self.assertEqual(response.status_code, 200) Calendar.from_ical(response.content) def test_html(self): @@ -751,8 +752,8 @@ class ScheduleTest(TestCase): response = self.client.get(reverse('staff-schedule') + 'html/') self.assertContains(response, 'Staff tag') self.assertNotContains(response, 'Not staff tag') - self.assertEquals(response.status_code, 200) + self.assertEqual(response.status_code, 200) def test_inexistent_format(self): self.client.login(username='admin', password='admin') - self.assertEquals(self.client.get(reverse('staff-schedule') + 'inexistent/').status_code, 404) + self.assertEqual(self.client.get(reverse('staff-schedule') + 'inexistent/').status_code, 404) diff --git a/cfp/urls.py b/cfp/urls.py index 64b8bd3..c676c01 100644 --- a/cfp/urls.py +++ b/cfp/urls.py @@ -1,70 +1,71 @@ -from django.conf.urls import url +from django.urls import path, re_path, register_converter + +from . import views, converters + + +register_converter(converters.SignedIntConverter, 'sint') -from . import views urlpatterns = [ - url(r'^$', views.home, name='home'), -# v1.1 - url(r'^cfp/$', views.proposal_home, name='proposal-home'), - url(r'^cfp/token/$', views.proposal_mail_token, name='proposal-mail-token'), - url(r'^cfp/(?:(?P[\w\-]+)/)?dashboard/$', views.proposal_dashboard, name='proposal-dashboard'), - url(r'^cfp/(?:(?P[\w\-]+)/)?profile/$', views.proposal_speaker_edit, name='proposal-profile-edit'), - url(r'^cfp/(?:(?P[\w\-]+)/)?talk/add/$', views.proposal_talk_edit, name='proposal-talk-add'), - url(r'^cfp/(?:(?P[\w\-]+)/)?talk/(?P[0-9]+)/$', views.proposal_talk_details, name='proposal-talk-details'), - url(r'^cfp/(?:(?P[\w\-]+)/)?talk/(?P[0-9]+)/edit/$', views.proposal_talk_edit, name='proposal-talk-edit'), - url(r'^cfp/(?:(?P[\w\-]+)/)?talk/(?P[0-9]+)/speaker/add/$', views.proposal_speaker_edit, name='proposal-speaker-add'), - url(r'^cfp/(?:(?P[\w\-]+)/)?talk/(?P[0-9]+)/speaker/add/(?P[0-9]+)/$', views.proposal_speaker_add, name='proposal-speaker-add-existing'), - #url(r'^cfp(?:/(?P[\w\-]+))?/talk/(?P[0-9]+)/speaker/(?P[0-9]+)/$', views.proposal_speaker_details, name='proposal-speaker-details'), - url(r'^cfp/(?:(?P[\w\-]+)/)?talk/(?P[0-9]+)/speaker/(?P[0-9]+)/edit/$', views.proposal_speaker_edit, name='proposal-speaker-edit'), - url(r'^cfp/(?:(?P[\w\-]+)/)?talk/(?P[0-9]+)/speaker/(?P[0-9]+)/remove/$', views.proposal_speaker_remove, name='proposal-speaker-remove'), - url(r'^cfp/(?:(?P[\w\-]+)/)?talk/(?P[0-9]+)/confirm/$', views.proposal_talk_acknowledgment, {'confirm': True}, name='proposal-talk-confirm'), - url(r'^cfp/(?:(?P[\w\-]+)/)?talk/(?P[0-9]+)/desist/$', views.proposal_talk_acknowledgment, {'confirm': False}, name='proposal-talk-desist'), - url(r'^volunteer/enrole/$', views.volunteer_enrole, name='volunteer-enrole'), - url(r'^volunteer/token/$', views.volunteer_mail_token, name='volunteer-mail-token'), - url(r'^volunteer/(?:(?P[\w\-]+)/)?$', views.volunteer_dashboard, name='volunteer-dashboard'), - url(r'^volunteer/(?:(?P[\w\-]+)/)?profile/$', views.volunteer_profile, name='volunteer-profile-edit'), - url(r'^volunteer/(?:(?P[\w\-]+)/)?join/(?P[\w\-]+)/$', views.volunteer_update_activity, {'join': True}, name='volunteer-join'), - url(r'^volunteer/(?:(?P[\w\-]+)/)?quit/(?P[\w\-]+)/$', views.volunteer_update_activity, {'join': False}, name='volunteer-quit'), - #url(r'^talk/(?P[\w\-]+)/$', views.talk_show, name='show-talk'), - #url(r'^speaker/(?P[\w\-]+)/$', views.speaker_show, name='show-speaker'), - url(r'^staff/$', views.staff, name='staff'), - url(r'^staff/talks/$', views.talk_list, name='talk-list'), - url(r'^staff/talks/(?P[0-9]+)/$', views.talk_details, name='talk-details'), - url(r'^staff/talks/(?P[0-9]+)/vote/(?P[-+0-2]+)/$', views.talk_vote, name='talk-vote'), - url(r'^staff/talks/(?P[0-9]+)/accept/$', views.talk_decide, {'accept': True}, name='talk-accept'), - url(r'^staff/talks/(?P[0-9]+)/decline/$', views.talk_decide, {'accept': False}, name='talk-decline'), - url(r'^staff/talks/(?P[0-9]+)/confirm/$', views.talk_acknowledgment, {'confirm': True}, name='talk-confirm-by-staff'), - url(r'^staff/talks/(?P[0-9]+)/desist/$', views.talk_acknowledgment, {'confirm': False}, name='talk-desist-by-staff'), - url(r'^staff/talks/(?P[0-9]+)/edit/$', views.TalkUpdate.as_view(), name='talk-edit'), - url(r'^staff/speakers/$', views.participant_list, name='participant-list'), - url(r'^staff/speakers/add/$', views.ParticipantCreate.as_view(), name='participant-add'), - url(r'^staff/speakers/(?P[0-9]+)/$', views.participant_details, name='participant-details'), - url(r'^staff/speakers/(?P[0-9]+)/add-talk/$', views.participant_add_talk, name='participant-add-talk'), - url(r'^staff/speakers/(?P[0-9]+)/edit/$', views.ParticipantUpdate.as_view(), name='participant-edit'), - url(r'^staff/speakers/(?P[0-9]+)/remove/$', views.ParticipantRemove.as_view(), name='participant-remove'), - url(r'^staff/tracks/$', views.TrackList.as_view(), name='track-list'), - url(r'^staff/tracks/add/$', views.TrackCreate.as_view(), name='track-add'), - url(r'^staff/tracks/(?P[-\w]+)/edit/$', views.TrackUpdate.as_view(), name='track-edit'), - url(r'^staff/rooms/$', views.RoomList.as_view(), name='room-list'), - url(r'^staff/rooms/add/$', views.RoomCreate.as_view(), name='room-add'), - url(r'^staff/rooms/(?P[-\w]+)/$', views.RoomDetail.as_view(), name='room-details'), - url(r'^staff/rooms/(?P[-\w]+)/edit/$', views.RoomUpdate.as_view(), name='room-edit'), - url(r'^staff/volunteers/$', views.volunteer_list, name='volunteer-list'), - url(r'^staff/volunteers/(?P[\w\-]+)/$', views.volunteer_details, name='volunteer-details'), - url(r'^staff/add-user/$', views.create_user, name='create-user'), - url(r'^staff/schedule/((?P[\w]+)/)?$', views.staff_schedule, name='staff-schedule'), - url(r'^staff/select2/$', views.Select2View.as_view(), name='django_select2-json'), - url(r'^admin/$', views.admin, name='admin'), - url(r'^admin/conference/$', views.conference_edit, name='conference-edit'), - url(r'^admin/homepage/$', views.homepage_edit, name='homepage-edit'), - url(r'^admin/categories/$', views.TalkCategoryList.as_view(), name='category-list'), - url(r'^admin/categories/add/$', views.TalkCategoryCreate.as_view(), name='category-add'), - url(r'^admin/categories/(?P[0-9]+)/edit/$', views.TalkCategoryUpdate.as_view(), name='category-edit'), - url(r'^admin/tags/$', views.TagList.as_view(), name='tag-list'), - url(r'^admin/tags/add/$', views.TagCreate.as_view(), name='tag-add'), - url(r'^admin/tags/(?P[-\w]+)/edit/$', views.TagUpdate.as_view(), name='tag-edit'), - url(r'^admin/activities/$', views.ActivityList.as_view(), name='activity-list'), - url(r'^admin/activities/add/$', views.ActivityCreate.as_view(), name='activity-add'), - url(r'^admin/activities/(?P[-\w]+)/edit/$', views.ActivityUpdate.as_view(), name='activity-edit'), - url(r'^schedule/((?P[\w]+)/)?$', views.public_schedule, name='public-schedule'), + path('', views.home, name='home'), + path('cfp/', views.proposal_home, name='proposal-home'), + path('cfp/token/', views.proposal_mail_token, name='proposal-mail-token'), + re_path(r'^cfp/(?:(?P[\w\-]+)/)?dashboard/$', views.proposal_dashboard, name='proposal-dashboard'), + re_path(r'^cfp/(?:(?P[\w\-]+)/)?profile/$', views.proposal_speaker_edit, name='proposal-profile-edit'), + re_path(r'^cfp/(?:(?P[\w\-]+)/)?talk/add/$', views.proposal_talk_edit, name='proposal-talk-add'), + re_path(r'^cfp/(?:(?P[\w\-]+)/)?talk/(?P[0-9]+)/$', views.proposal_talk_details, name='proposal-talk-details'), + re_path(r'^cfp/(?:(?P[\w\-]+)/)?talk/(?P[0-9]+)/edit/$', views.proposal_talk_edit, name='proposal-talk-edit'), + re_path(r'^cfp/(?:(?P[\w\-]+)/)?talk/(?P[0-9]+)/speaker/add/$', views.proposal_speaker_edit, name='proposal-speaker-add'), + re_path(r'^cfp/(?:(?P[\w\-]+)/)?talk/(?P[0-9]+)/speaker/add/(?P[0-9]+)/$', views.proposal_speaker_add, name='proposal-speaker-add-existing'), + #re_path(r'^cfp(?:/(?P[\w\-]+))?/talk/(?P[0-9]+)/speaker/(?P[0-9]+)/$', views.proposal_speaker_details, name='proposal-speaker-details'), + re_path(r'^cfp/(?:(?P[\w\-]+)/)?talk/(?P[0-9]+)/speaker/(?P[0-9]+)/edit/$', views.proposal_speaker_edit, name='proposal-speaker-edit'), + re_path(r'^cfp/(?:(?P[\w\-]+)/)?talk/(?P[0-9]+)/speaker/(?P[0-9]+)/remove/$', views.proposal_speaker_remove, name='proposal-speaker-remove'), + re_path(r'^cfp/(?:(?P[\w\-]+)/)?talk/(?P[0-9]+)/confirm/$', views.proposal_talk_acknowledgment, {'confirm': True}, name='proposal-talk-confirm'), + re_path(r'^cfp/(?:(?P[\w\-]+)/)?talk/(?P[0-9]+)/desist/$', views.proposal_talk_acknowledgment, {'confirm': False}, name='proposal-talk-desist'), + path('volunteer/enrole', views.volunteer_enrole, name='volunteer-enrole'), + path('volunteer/token/', views.volunteer_mail_token, name='volunteer-mail-token'), + re_path(r'^volunteer/(?:(?P[\w\-]+)/)?$', views.volunteer_dashboard, name='volunteer-dashboard'), + re_path(r'^volunteer/(?:(?P[\w\-]+)/)?profile/$', views.volunteer_profile, name='volunteer-profile-edit'), + re_path(r'^volunteer/(?:(?P[\w\-]+)/)?join/(?P[\w\-]+)/$', views.volunteer_update_activity, {'join': True}, name='volunteer-join'), + re_path(r'^volunteer/(?:(?P[\w\-]+)/)?quit/(?P[\w\-]+)/$', views.volunteer_update_activity, {'join': False}, name='volunteer-quit'), + path('staff/', views.staff, name='staff'), + path('staff/talks/', views.talk_list, name='talk-list'), + path('staff/talks//', views.talk_details, name='talk-details'), + path('staff/talks//vote//', views.talk_vote, name='talk-vote'), + path('staff/talks//accept/', views.talk_decide, {'accept': True}, name='talk-accept'), + path('staff/talks//decline/', views.talk_decide, {'accept': False}, name='talk-decline'), + path('staff/talks//confirm/', views.talk_acknowledgment, {'confirm': True}, name='talk-confirm-by-staff'), + path('staff/talks//desist/', views.talk_acknowledgment, {'confirm': False}, name='talk-desist-by-staff'), + path('staff/talks//edit/', views.TalkUpdate.as_view(), name='talk-edit'), + path('staff/speakers/', views.participant_list, name='participant-list'), + path('staff/speakers/add/', views.ParticipantCreate.as_view(), name='participant-add'), + path('staff/speakers//', views.participant_details, name='participant-details'), + path('staff/speakers//add-talk/', views.participant_add_talk, name='participant-add-talk'), + path('staff/speakers//edit/', views.ParticipantUpdate.as_view(), name='participant-edit'), + path('staff/speakers//remove/', views.ParticipantRemove.as_view(), name='participant-remove'), + path('staff/tracks/', views.TrackList.as_view(), name='track-list'), + path('staff/tracks/add/', views.TrackCreate.as_view(), name='track-add'), + path('staff/tracks//edit/', views.TrackUpdate.as_view(), name='track-edit'), + path('staff/rooms/', views.RoomList.as_view(), name='room-list'), + path('staff/rooms/add/', views.RoomCreate.as_view(), name='room-add'), + path('staff/rooms//', views.RoomDetail.as_view(), name='room-details'), + path('staff/rooms//edit/', views.RoomUpdate.as_view(), name='room-edit'), + path('staff/volunteers/', views.volunteer_list, name='volunteer-list'), + path('staff/volunteers//', views.volunteer_details, name='volunteer-details'), + path('staff/add-user/', views.create_user, name='create-user'), + re_path(r'^staff/schedule/((?P[\w]+)/)?$', views.staff_schedule, name='staff-schedule'), + path('staff/select2/', views.Select2View.as_view(), name='django_select2-json'), + path('admin/', views.admin, name='admin'), + path('admin/conference/', views.conference_edit, name='conference-edit'), + path('admin/homepage/', views.homepage_edit, name='homepage-edit'), + path('admin/categories/', views.TalkCategoryList.as_view(), name='category-list'), + path('admin/categories/add/', views.TalkCategoryCreate.as_view(), name='category-add'), + path('admin/categories//edit/', views.TalkCategoryUpdate.as_view(), name='category-edit'), + path('admin/tags/', views.TagList.as_view(), name='tag-list'), + path('admin/tags/add/', views.TagCreate.as_view(), name='tag-add'), + path('admin/tags//edit/', views.TagUpdate.as_view(), name='tag-edit'), + path('admin/activities/', views.ActivityList.as_view(), name='activity-list'), + path('admin/activities/add/', views.ActivityCreate.as_view(), name='activity-add'), + path('admin/activities//edit/', views.ActivityUpdate.as_view(), name='activity-edit'), + re_path(r'^schedule/((?P[\w]+)/)?$', views.public_schedule, name='public-schedule'), ] diff --git a/cfp/views.py b/cfp/views.py index 1f46a48..d1c8854 100644 --- a/cfp/views.py +++ b/cfp/views.py @@ -1,8 +1,7 @@ from django.core.mail import send_mail -from django.core.urlresolvers import reverse_lazy from django.shortcuts import get_object_or_404, redirect, render from django.template.loader import render_to_string -from django.urls import reverse +from django.urls import reverse, reverse_lazy from django.utils.translation import ugettext_lazy as _ from django.views.generic import DeleteView, FormView, TemplateView from django.contrib import messages @@ -42,24 +41,24 @@ def home(request): def volunteer_enrole(request): - if request.user.is_authenticated() and Volunteer.objects.filter(site=request.conference.site, email=request.user.email).exists(): + if request.user.is_authenticated and Volunteer.objects.filter(site=request.conference.site, email=request.user.email).exists(): return redirect(reverse('volunteer-dashboard')) if not request.conference.volunteers_enrollment_is_open(): raise PermissionDenied initial = {} - if request.user.is_authenticated() and not request.POST: + if request.user.is_authenticated and not request.POST: initial.update({ 'name': request.user.get_full_name(), 'phone_number': request.user.profile.phone_number, 'sms_prefered': request.user.profile.sms_prefered, }) form = VolunteerForm(request.POST or None, initial=initial, conference=request.conference) - if request.user.is_authenticated(): + if request.user.is_authenticated: form.fields.pop('email') if request.method == 'POST' and form.is_valid(): volunteer = form.save(commit=False) volunteer.language = request.LANGUAGE_CODE - if request.user.is_authenticated(): + if request.user.is_authenticated: volunteer.email = request.user.email volunteer.save() form.save_m2m() @@ -205,7 +204,7 @@ def proposal_home(request): return render(request, 'cfp/closed.html') initial = {} fields = ['name', 'email', 'biography'] - if request.user.is_authenticated(): + if request.user.is_authenticated: if Participant.objects.filter(site=request.conference.site, email=request.user.email).exists(): return redirect(reverse('proposal-dashboard')) elif not request.POST: @@ -220,7 +219,7 @@ def proposal_home(request): if request.method == 'POST' and all(map(lambda f: f.is_valid(), [speaker_form, talk_form])): speaker = speaker_form.save(commit=False) speaker.site = request.conference.site - if request.user.is_authenticated(): + if request.user.is_authenticated: speaker.email = request.user.email speaker.save() talk = talk_form.save(commit=False) @@ -725,9 +724,11 @@ def talk_details(request, talk_id): @staff_required def talk_vote(request, talk_id, score): + if score not in [-2, -1, 0, 1, 2]: + raise Http404 talk = get_object_or_404(Talk, pk=talk_id, site=request.conference.site) vote, created = Vote.objects.get_or_create(talk=talk, user=request.user) - vote.vote = int(score) + vote.vote = score vote.save() messages.success(request, _('Vote successfully created') if created else _('Vote successfully updated')) return redirect(talk.get_absolute_url()) diff --git a/mailing/models.py b/mailing/models.py index 82a6455..3d023a4 100644 --- a/mailing/models.py +++ b/mailing/models.py @@ -56,9 +56,9 @@ class MessageManager(models.Manager): class Message(models.Model): created = models.DateTimeField(auto_now_add=True) - thread = models.ForeignKey(MessageThread) - author = models.ForeignKey(MessageAuthor) - in_reply_to = models.ForeignKey('self', null=True, blank=True) + thread = models.ForeignKey(MessageThread, on_delete=models.CASCADE) + author = models.ForeignKey(MessageAuthor, on_delete=models.PROTECT) + in_reply_to = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL) subject = models.CharField(max_length=1000, blank=True) content = models.TextField(blank=True) token = models.CharField(max_length=64, default=generate_message_token, unique=True) diff --git a/mailing/tests.py b/mailing/tests.py index 5b67ee3..0922f0e 100644 --- a/mailing/tests.py +++ b/mailing/tests.py @@ -1,6 +1,6 @@ from django.contrib.auth.models import User from django.contrib.sites.models import Site -from django.core.urlresolvers import reverse +from django.urls import reverse from django.test import TestCase, override_settings from django.core import mail from django.conf import settings diff --git a/ponyconf/settings.py b/ponyconf/settings.py index 49ceca3..8fd694c 100644 --- a/ponyconf/settings.py +++ b/ponyconf/settings.py @@ -66,7 +66,6 @@ MIDDLEWARE = [ 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', diff --git a/ponyconf/urls.py b/ponyconf/urls.py index 2b7f5c2..facaabb 100644 --- a/ponyconf/urls.py +++ b/ponyconf/urls.py @@ -1,19 +1,4 @@ -"""ponyconf URL Configuration - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/1.9/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') -Including another URLconf - 1. Import the include() function: from django.conf.urls import url, include - 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) -""" -from django.conf.urls import include, url +from django.urls import include, path from django.contrib import admin from django.conf import settings @@ -21,14 +6,14 @@ from . import views urlpatterns = [ - url(r'^markdown/$', views.markdown_preview, name='markdown-preview'), - url(r'^admin/django/', admin.site.urls), - url(r'^accounts/', include('accounts.urls')), - url(r'^', include('cfp.urls')), + path('markdown/', views.markdown_preview, name='markdown-preview'), + path('admin/django/', admin.site.urls), + path('accounts/', include('accounts.urls')), + path('', include('cfp.urls')), ] if settings.DEBUG and 'debug_toolbar' in settings.INSTALLED_APPS: import debug_toolbar urlpatterns += [ - url(r'^__debug__/', include(debug_toolbar.urls)), + path('__debug__/', include(debug_toolbar.urls)), ] diff --git a/requirements.in b/requirements.in index fba7670..a1a51ed 100644 --- a/requirements.in +++ b/requirements.in @@ -1,11 +1,11 @@ -django<1.12 +django<3 -django-autoslug django-bootstrap3 django-bower django-crispy-forms django-select2<6 django-colorful +-e git://github.com/nim65s/django-autoslug.git#egg=django-autoslug markdown bleach diff --git a/requirements.txt b/requirements.txt index db92898..4f7397d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,19 +4,19 @@ # # pip-compile --output-file requirements.txt requirements.in # -bleach==2.1.1 +-e git+git://github.com/nim65s/django-autoslug.git#egg=django-autoslug +bleach==2.1.2 chardet==3.0.4 django-appconf==1.0.2 # via django-select2 -django-autoslug==1.9.3 django-bootstrap3==9.1.0 django-bower==5.2.0 django-colorful==1.2 django-crispy-forms==1.7.0 django-select2==5.11.1 -django==1.11.7 -html5lib==1.0b10 # via bleach +django==2.0 +html5lib==1.0.1 # via bleach icalendar==4.0.0 -markdown==2.6.9 +markdown==2.6.10 python-dateutil==2.6.1 # via icalendar pytz==2017.3 # via django, icalendar six==1.11.0 # via bleach, django-bower, html5lib, python-dateutil