django 2.0

This commit is contained in:
Élie Bouttier 2017-12-10 13:32:19 +01:00
parent c5af037435
commit 6cbbb6bd1f
19 changed files with 181 additions and 189 deletions

View File

@ -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'))

View File

@ -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')),
]

8
cfp/converters.py Normal file
View File

@ -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

View File

@ -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)

View File

@ -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})

View File

@ -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()

View File

@ -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

View File

@ -8,6 +8,6 @@
<h1>{% trans "Schedule" %}</h1>
{{ program }}
{{ program|safe }}
{% endblock %}

View File

@ -8,6 +8,6 @@
<h1>{% trans "Schedule" %}</h1>
{{ program }}
{{ program|safe }}
{% endblock %}

View File

@ -88,11 +88,11 @@
<p>
<div class="btn-group" role="group" aria-label="vote">
<a class="btn {% if vote == -2 %} active {% endif %}btn-danger" href="{% url 'talk-vote' talk.pk '-2' %}">-2</a>
<a class="btn {% if vote == -1 %} active {% endif %}btn-warning" href="{% url 'talk-vote' talk.pk '-1' %}">-1</a>
<a class="btn {% if vote == 0 %} active {% endif %}btn-default" href="{% url 'talk-vote' talk.pk '0' %}"> 0</a>
<a class="btn {% if vote == 1 %} active {% endif %}btn-info" href="{% url 'talk-vote' talk.pk '+1' %}">+1</a>
<a class="btn {% if vote == 2 %} active {% endif %}btn-success" href="{% url 'talk-vote' talk.pk '+2' %}">+2</a>
<a class="btn {% if vote == -2 %} active {% endif %}btn-danger" href="{% url 'talk-vote' talk.pk -2 %}">-2</a>
<a class="btn {% if vote == -1 %} active {% endif %}btn-warning" href="{% url 'talk-vote' talk.pk -1 %}">-1</a>
<a class="btn {% if vote == 0 %} active {% endif %}btn-default" href="{% url 'talk-vote' talk.pk 0 %}"> 0</a>
<a class="btn {% if vote == 1 %} active {% endif %}btn-info" href="{% url 'talk-vote' talk.pk 1 %}">+1</a>
<a class="btn {% if vote == 2 %} active {% endif %}btn-success" href="{% url 'talk-vote' talk.pk 2 %}">+2</a>
</div>
</p>
<p>{{ talk.vote_set.count }} {% trans "vote" %}{{ talk.vote_set.count|pluralize }}, {% trans "average:" %} {{ talk.score|floatformat:1 }}</p>

View File

@ -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, '<strong>Welcome!</strong>')
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)

View File

@ -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<speaker_token>[\w\-]+)/)?dashboard/$', views.proposal_dashboard, name='proposal-dashboard'),
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?profile/$', views.proposal_speaker_edit, name='proposal-profile-edit'),
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/add/$', views.proposal_talk_edit, name='proposal-talk-add'),
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/$', views.proposal_talk_details, name='proposal-talk-details'),
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/edit/$', views.proposal_talk_edit, name='proposal-talk-edit'),
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/speaker/add/$', views.proposal_speaker_edit, name='proposal-speaker-add'),
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/speaker/add/(?P<speaker_id>[0-9]+)/$', views.proposal_speaker_add, name='proposal-speaker-add-existing'),
#url(r'^cfp(?:/(?P<speaker_token>[\w\-]+))?/talk/(?P<talk_id>[0-9]+)/speaker/(?P<co_speaker_id>[0-9]+)/$', views.proposal_speaker_details, name='proposal-speaker-details'),
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/speaker/(?P<co_speaker_id>[0-9]+)/edit/$', views.proposal_speaker_edit, name='proposal-speaker-edit'),
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/speaker/(?P<co_speaker_id>[0-9]+)/remove/$', views.proposal_speaker_remove, name='proposal-speaker-remove'),
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/confirm/$', views.proposal_talk_acknowledgment, {'confirm': True}, name='proposal-talk-confirm'),
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[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<volunteer_token>[\w\-]+)/)?$', views.volunteer_dashboard, name='volunteer-dashboard'),
url(r'^volunteer/(?:(?P<volunteer_token>[\w\-]+)/)?profile/$', views.volunteer_profile, name='volunteer-profile-edit'),
url(r'^volunteer/(?:(?P<volunteer_token>[\w\-]+)/)?join/(?P<activity>[\w\-]+)/$', views.volunteer_update_activity, {'join': True}, name='volunteer-join'),
url(r'^volunteer/(?:(?P<volunteer_token>[\w\-]+)/)?quit/(?P<activity>[\w\-]+)/$', views.volunteer_update_activity, {'join': False}, name='volunteer-quit'),
#url(r'^talk/(?P<talk_id>[\w\-]+)/$', views.talk_show, name='show-talk'),
#url(r'^speaker/(?P<participant_id>[\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<talk_id>[0-9]+)/$', views.talk_details, name='talk-details'),
url(r'^staff/talks/(?P<talk_id>[0-9]+)/vote/(?P<score>[-+0-2]+)/$', views.talk_vote, name='talk-vote'),
url(r'^staff/talks/(?P<talk_id>[0-9]+)/accept/$', views.talk_decide, {'accept': True}, name='talk-accept'),
url(r'^staff/talks/(?P<talk_id>[0-9]+)/decline/$', views.talk_decide, {'accept': False}, name='talk-decline'),
url(r'^staff/talks/(?P<talk_id>[0-9]+)/confirm/$', views.talk_acknowledgment, {'confirm': True}, name='talk-confirm-by-staff'),
url(r'^staff/talks/(?P<talk_id>[0-9]+)/desist/$', views.talk_acknowledgment, {'confirm': False}, name='talk-desist-by-staff'),
url(r'^staff/talks/(?P<talk_id>[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<participant_id>[0-9]+)/$', views.participant_details, name='participant-details'),
url(r'^staff/speakers/(?P<participant_id>[0-9]+)/add-talk/$', views.participant_add_talk, name='participant-add-talk'),
url(r'^staff/speakers/(?P<participant_id>[0-9]+)/edit/$', views.ParticipantUpdate.as_view(), name='participant-edit'),
url(r'^staff/speakers/(?P<participant_id>[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<slug>[-\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<slug>[-\w]+)/$', views.RoomDetail.as_view(), name='room-details'),
url(r'^staff/rooms/(?P<slug>[-\w]+)/edit/$', views.RoomUpdate.as_view(), name='room-edit'),
url(r'^staff/volunteers/$', views.volunteer_list, name='volunteer-list'),
url(r'^staff/volunteers/(?P<volunteer_id>[\w\-]+)/$', views.volunteer_details, name='volunteer-details'),
url(r'^staff/add-user/$', views.create_user, name='create-user'),
url(r'^staff/schedule/((?P<program_format>[\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<pk>[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<slug>[-\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<slug>[-\w]+)/edit/$', views.ActivityUpdate.as_view(), name='activity-edit'),
url(r'^schedule/((?P<program_format>[\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<speaker_token>[\w\-]+)/)?dashboard/$', views.proposal_dashboard, name='proposal-dashboard'),
re_path(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?profile/$', views.proposal_speaker_edit, name='proposal-profile-edit'),
re_path(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/add/$', views.proposal_talk_edit, name='proposal-talk-add'),
re_path(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/$', views.proposal_talk_details, name='proposal-talk-details'),
re_path(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/edit/$', views.proposal_talk_edit, name='proposal-talk-edit'),
re_path(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/speaker/add/$', views.proposal_speaker_edit, name='proposal-speaker-add'),
re_path(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/speaker/add/(?P<speaker_id>[0-9]+)/$', views.proposal_speaker_add, name='proposal-speaker-add-existing'),
#re_path(r'^cfp(?:/(?P<speaker_token>[\w\-]+))?/talk/(?P<talk_id>[0-9]+)/speaker/(?P<co_speaker_id>[0-9]+)/$', views.proposal_speaker_details, name='proposal-speaker-details'),
re_path(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/speaker/(?P<co_speaker_id>[0-9]+)/edit/$', views.proposal_speaker_edit, name='proposal-speaker-edit'),
re_path(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/speaker/(?P<co_speaker_id>[0-9]+)/remove/$', views.proposal_speaker_remove, name='proposal-speaker-remove'),
re_path(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/confirm/$', views.proposal_talk_acknowledgment, {'confirm': True}, name='proposal-talk-confirm'),
re_path(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[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<volunteer_token>[\w\-]+)/)?$', views.volunteer_dashboard, name='volunteer-dashboard'),
re_path(r'^volunteer/(?:(?P<volunteer_token>[\w\-]+)/)?profile/$', views.volunteer_profile, name='volunteer-profile-edit'),
re_path(r'^volunteer/(?:(?P<volunteer_token>[\w\-]+)/)?join/(?P<activity>[\w\-]+)/$', views.volunteer_update_activity, {'join': True}, name='volunteer-join'),
re_path(r'^volunteer/(?:(?P<volunteer_token>[\w\-]+)/)?quit/(?P<activity>[\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/<int:talk_id>/', views.talk_details, name='talk-details'),
path('staff/talks/<int:talk_id>/vote/<sint:score>/', views.talk_vote, name='talk-vote'),
path('staff/talks/<int:talk_id>/accept/', views.talk_decide, {'accept': True}, name='talk-accept'),
path('staff/talks/<int:talk_id>/decline/', views.talk_decide, {'accept': False}, name='talk-decline'),
path('staff/talks/<int:talk_id>/confirm/', views.talk_acknowledgment, {'confirm': True}, name='talk-confirm-by-staff'),
path('staff/talks/<int:talk_id>/desist/', views.talk_acknowledgment, {'confirm': False}, name='talk-desist-by-staff'),
path('staff/talks/<int:talk_id>/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/<int:participant_id>/', views.participant_details, name='participant-details'),
path('staff/speakers/<int:participant_id>/add-talk/', views.participant_add_talk, name='participant-add-talk'),
path('staff/speakers/<int:participant_id>/edit/', views.ParticipantUpdate.as_view(), name='participant-edit'),
path('staff/speakers/<int:participant_id>/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/<slug:slug>/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/<slug:slug>/', views.RoomDetail.as_view(), name='room-details'),
path('staff/rooms/<slug:slug>/edit/', views.RoomUpdate.as_view(), name='room-edit'),
path('staff/volunteers/', views.volunteer_list, name='volunteer-list'),
path('staff/volunteers/<int:volunteer_id>/', views.volunteer_details, name='volunteer-details'),
path('staff/add-user/', views.create_user, name='create-user'),
re_path(r'^staff/schedule/((?P<program_format>[\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/<int:pk>/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/<slug:slug>/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/<slug:slug>/edit/', views.ActivityUpdate.as_view(), name='activity-edit'),
re_path(r'^schedule/((?P<program_format>[\w]+)/)?$', views.public_schedule, name='public-schedule'),
]

View File

@ -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())

View File

@ -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)

View File

@ -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

View File

@ -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',

View File

@ -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)),
]

View File

@ -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

View File

@ -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