diff --git a/ponyconf/settings.py b/ponyconf/settings.py
index f6664dd..7f34d22 100644
--- a/ponyconf/settings.py
+++ b/ponyconf/settings.py
@@ -41,16 +41,13 @@ INSTALLED_APPS = [
'ponyconf',
'cfp',
'mailing',
- #'proposals',
#'planning',
#'volunteers',
# external apps
'djangobower',
'bootstrap3',
- #'registration',
'django_select2',
- #'avatar',
'crispy_forms',
# build-in apps
diff --git a/proposals/__init__.py b/proposals/__init__.py
deleted file mode 100644
index b83842a..0000000
--- a/proposals/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-default_app_config = 'proposals.apps.ProposalsConfig'
diff --git a/proposals/admin.py b/proposals/admin.py
deleted file mode 100644
index 7e2253e..0000000
--- a/proposals/admin.py
+++ /dev/null
@@ -1,47 +0,0 @@
-from django.contrib import admin
-from django.contrib.sites.shortcuts import get_current_site
-
-from proposals.models import Conference, Talk, Topic, Track, Event, Attendee
-from planning.models import Room
-
-from ponyconf.admin import SiteAdminMixin
-
-
-
-class TalkAdmin(SiteAdminMixin, admin.ModelAdmin):
- def get_form(self, request, obj=None, **kwargs):
- form = super(TalkAdmin, self).get_form(request, obj, **kwargs)
- site = get_current_site(request)
- form.base_fields['topics'].queryset = Topic.objects.filter(site=site)
- form.base_fields['track'].queryset = Track.objects.filter(site=site)
- form.base_fields['event'].queryset = Event.objects.filter(site=site)
- form.base_fields['room'].queryset = Room.objects.filter(site=site)
- return form
-
-
-class TopicAdmin(SiteAdminMixin, admin.ModelAdmin):
- def get_form(self, request, obj=None, **kwargs):
- form = super().get_form(request, obj, **kwargs)
- site = get_current_site(request)
- form.base_fields['track'].queryset = Track.objects.filter(site=site)
- return form
-
-
-class TrackAdmin(SiteAdminMixin, admin.ModelAdmin):
- pass
-
-
-class EventAdmin(SiteAdminMixin, admin.ModelAdmin):
- pass
-
-
-class AttendeeAdmin(admin.ModelAdmin):
- list_display = ('get_name', 'get_email')
-
-
-admin.site.register(Conference)
-admin.site.register(Topic, TopicAdmin)
-admin.site.register(Track, TrackAdmin)
-admin.site.register(Talk, TalkAdmin)
-admin.site.register(Event, EventAdmin)
-admin.site.register(Attendee, AttendeeAdmin)
diff --git a/proposals/apps.py b/proposals/apps.py
deleted file mode 100644
index 6245495..0000000
--- a/proposals/apps.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from django.apps import AppConfig
-from django.db.models.signals import post_migrate
-
-
-class ProposalsConfig(AppConfig):
- name = 'proposals'
-
- def ready(self):
- import proposals.signals # noqa
- post_migrate.connect(proposals.signals.call_first_site_post_save, sender=self)
diff --git a/proposals/context_processors.py b/proposals/context_processors.py
deleted file mode 100644
index 8871920..0000000
--- a/proposals/context_processors.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from django.conf import settings
-from django.contrib.sites.shortcuts import get_current_site
-
-from .models import Conference
-
-
-def conference(request):
- conference = Conference.objects.get(site=get_current_site(request))
- return {'conference': conference}
diff --git a/proposals/forms.py b/proposals/forms.py
deleted file mode 100644
index 40db163..0000000
--- a/proposals/forms.py
+++ /dev/null
@@ -1,209 +0,0 @@
-from django import forms
-from django.db.utils import OperationalError
-from django.forms.models import modelform_factory
-from django.utils.translation import ugettext_lazy as _
-
-from django_select2.forms import Select2TagWidget
-
-from accounts.models import User, Participation, Transport
-from proposals.models import Conference, Event, Talk, Topic, Track
-from planning.models import Room
-
-STATUS_CHOICES = [
- ('pending', 'Pending decision'),
- ('accepted', 'Accepted'),
- ('declined', 'Declined'),
-]
-STATUS_VALUES = [
- ('pending', None),
- ('accepted', True),
- ('declined', False),
-]
-
-
-class TalkForm(forms.ModelForm):
- def __init__(self, *args, **kwargs):
- site = kwargs.pop('site')
- staff = kwargs.pop('staff')
- super(TalkForm, self).__init__(*args, **kwargs)
- self.fields['topics'].queryset = Topic.objects.filter(site=site)
- self.fields['track'].queryset = Track.objects.filter(site=site)
- self.fields['materials'].required = False
- if staff:
- self.fields['event'].queryset = Event.objects.filter(site=site)
- else:
- self.fields['event'].queryset = Conference.objects.get(site=site).opened_events
- for field in ['track', 'duration', 'start_date', 'room', 'registration_required', 'attendees_limit']:
- self.fields.pop(field)
- if self.instance.pk is not None:
- self.fields['title'].disabled = True
-
- class Meta:
- model = Talk
- fields = ['title', 'abstract', 'description', 'topics', 'track', 'notes', 'event', 'speakers', 'materials', 'video', 'duration', 'start_date', 'room', 'registration_required', 'attendees_limit']
- widgets = {'topics': forms.CheckboxSelectMultiple(), 'speakers': Select2TagWidget()}
- help_texts = {
- 'abstract': _('Should be less than 255 characters'),
- 'notes': _('If you want to add some precisions for the organizers.'),
- }
-
-
-class TalkFilterForm(forms.Form):
- kind = forms.MultipleChoiceField(
- required=False,
- widget=forms.CheckboxSelectMultiple,
- choices=[],
- )
- status = forms.MultipleChoiceField(
- required=False,
- widget=forms.CheckboxSelectMultiple,
- choices=STATUS_CHOICES,
- )
- topic = forms.MultipleChoiceField(
- required=False,
- widget=forms.CheckboxSelectMultiple,
- choices=[],
- )
- track = forms.MultipleChoiceField(
- required=False,
- widget=forms.CheckboxSelectMultiple,
- choices=[],
- )
- vote = forms.NullBooleanField(help_text=_('Filter talks you already / not yet voted for'))
- room = forms.NullBooleanField(help_text=_('Filter talks already / not yet affected to a room'))
- scheduled = forms.NullBooleanField(help_text=_('Filter talks already / not yet scheduled'))
- materials = forms.NullBooleanField(help_text=_('Filter talks with / without materials'))
- video = forms.NullBooleanField(help_text=_('Filter talks with / without video'))
-
- def __init__(self, *args, **kwargs):
- site = kwargs.pop('site')
- super().__init__(*args, **kwargs)
- events = Event.objects.filter(site=site)
- self.fields['kind'].choices = events.values_list('pk', 'name')
- topics = Topic.objects.filter(site=site)
- self.fields['topic'].choices = topics.values_list('slug', 'name')
- tracks = Track.objects.filter(site=site)
- self.fields['track'].choices = [('none', 'Not assigned')] + list(tracks.values_list('slug', 'name'))
-
-
-class TalkActionForm(forms.Form):
- talks = forms.MultipleChoiceField(choices=[])
- decision = forms.NullBooleanField(label=_('Accept talk?'))
- track = forms.ChoiceField(required=False, choices=[], label=_('Assign to a track'))
- room = forms.ChoiceField(required=False, choices=[], label=_('Put in a room'))
-
- def __init__(self, *args, **kwargs):
- site = kwargs.pop('site')
- talks = kwargs.pop('talks')
- super().__init__(*args, **kwargs)
- self.fields['talks'].choices = [(talk.slug, None) for talk in talks.all()]
- tracks = Track.objects.filter(site=site)
- self.fields['track'].choices = [(None, "---------")] + list(tracks.values_list('slug', 'name'))
- rooms = Room.objects.filter(site=site)
- self.fields['room'].choices = [(None, "---------")] + list(rooms.values_list('slug', 'name'))
-
-
-def get_options(option):
- try:
- options = list(option.objects.values_list('pk', 'name'))
- except OperationalError:
- # happens when db doesn't exist yet
- options = []
- return options
-
-
-class SpeakerFilterForm(forms.Form):
- status = forms.MultipleChoiceField(
- required=False,
- widget=forms.CheckboxSelectMultiple,
- choices=STATUS_CHOICES,
- )
- topic = forms.MultipleChoiceField(
- required=False,
- widget=forms.CheckboxSelectMultiple,
- choices=[],
- )
- track = forms.MultipleChoiceField(
- required=False,
- widget=forms.CheckboxSelectMultiple,
- choices=[],
- )
- transport = forms.MultipleChoiceField(
- required=False,
- widget=forms.CheckboxSelectMultiple,
- choices=[('unanswered', 'Not answered'), ('unspecified', 'Not specified')] + get_options(Transport),
- )
- transport_booked = forms.NullBooleanField()
- accommodation= forms.MultipleChoiceField(
- required=False,
- widget=forms.CheckboxSelectMultiple,
- choices=[('unknown', 'Not specified')] + list(Participation.ACCOMMODATION_CHOICES),
- )
- accommodation_booked = forms.NullBooleanField()
- sound = forms.NullBooleanField()
-
- def __init__(self, *args, **kwargs):
- site = kwargs.pop('site')
- super().__init__(*args, **kwargs)
- topics = Topic.objects.filter(site=site)
- self.fields['topic'].choices = topics.values_list('slug', 'name')
- tracks = Track.objects.filter(site=site)
- self.fields['track'].choices = [('none', 'Not assigned')] + list(tracks.values_list('slug', 'name'))
-
-
-class TopicForm(forms.ModelForm):
- def __init__(self, *args, **kwargs):
- self.site = kwargs.pop('site')
- super().__init__(*args, **kwargs)
- self.fields['track'].queryset = Track.objects.filter(site=self.site)
-
- class Meta:
- model = Topic
- fields = ['name', 'description', 'reviewers', 'track']
- widgets = {'reviewers': Select2TagWidget()}
-
- def clean_name(self):
- name = self.cleaned_data['name']
- if self.instance and name != self.instance.name and Topic.objects.filter(site=self.site, name=name).exists():
- raise self.instance.unique_error_message(self._meta.model, ['name'])
- return name
-
-
-class TrackForm(forms.ModelForm):
- def __init__(self, *args, **kwargs):
- self.site = kwargs.pop('site')
- super().__init__(*args, **kwargs)
- if 'instance' in kwargs:
- reviewers = User.objects.filter(topic__track=kwargs['instance'])
- if reviewers.exists():
- self.fields['managers'].help_text = 'Suggestion: ' + ', '.join([str(u) for u in reviewers.all()])
-
- class Meta:
- model = Track
- fields = ['name', 'description', 'managers']
- widgets = {'managers': Select2TagWidget()}
-
- def clean_name(self):
- name = self.cleaned_data['name']
- if self.instance and name != self.instance.name and Track.objects.filter(site=self.site, name=name).exists():
- raise self.instance.unique_error_message(self._meta.model, ['name'])
- return name
-
-
-class SubscribeForm(forms.Form):
- email = forms.EmailField()
- name = forms.CharField(max_length=128, label=_('Name or nickname'))
- captcha = forms.IntegerField(label=_('How much is 3+4?'), help_text=_('Anti-bot'))
-
- def clean_captcha(self):
- value = self.cleaned_data['captcha']
- if value != 7:
- raise forms.ValidationError(_("Please re-do the maths."))
- return value
-
-
-ConferenceForm = modelform_factory(Conference,
- fields=['subscriptions_open', 'venue', 'city', 'home'],
- widgets={
- 'venue': forms.Textarea(attrs={'rows': 4}),
- })
diff --git a/proposals/migrations/0001_initial.py b/proposals/migrations/0001_initial.py
deleted file mode 100644
index 8cb8222..0000000
--- a/proposals/migrations/0001_initial.py
+++ /dev/null
@@ -1,163 +0,0 @@
-# -*- coding: utf-8 -*-
-# Generated by Django 1.10.3 on 2017-01-13 10:49
-from __future__ import unicode_literals
-
-import autoslug.fields
-import colorful.fields
-from django.conf import settings
-import django.core.validators
-from django.db import migrations, models
-import django.db.models.deletion
-import proposals.models
-
-
-class Migration(migrations.Migration):
-
- initial = True
-
- dependencies = [
- migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ('planning', '0001_initial'),
- ('sites', '0002_alter_domain_unique'),
- ]
-
- operations = [
- migrations.CreateModel(
- name='Attendee',
- fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('created', models.DateTimeField(auto_now_add=True)),
- ('updated', models.DateTimeField(auto_now=True)),
- ('name', models.CharField(blank=True, default='', max_length=64)),
- ('email', models.EmailField(blank=True, default='', max_length=254)),
- ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
- ],
- options={
- 'abstract': False,
- },
- ),
- migrations.CreateModel(
- name='Conference',
- fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('home', models.TextField(blank=True, default='')),
- ('venue', models.TextField(blank=True, default='')),
- ('city', models.CharField(blank=True, default='', max_length=64)),
- ('subscriptions_open', models.BooleanField(default=False)),
- ('site', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
- ],
- ),
- migrations.CreateModel(
- name='Event',
- fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('name', models.CharField(max_length=64)),
- ('duration', models.PositiveIntegerField(default=0, verbose_name='Default duration (min)')),
- ('color', colorful.fields.RGBColorField(default='#ffffff', verbose_name='Color on program')),
- ('label', models.CharField(blank=True, default='', max_length=64, verbose_name='Label on program')),
- ('opening_date', models.DateTimeField(blank=True, default=None, null=True)),
- ('closing_date', models.DateTimeField(blank=True, default=None, null=True)),
- ('site', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
- ],
- options={
- 'ordering': ('pk',),
- },
- ),
- migrations.CreateModel(
- name='Talk',
- fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('created', models.DateTimeField(auto_now_add=True)),
- ('updated', models.DateTimeField(auto_now=True)),
- ('title', models.CharField(help_text='After submission, title can only be changed by the staff.', max_length=128, verbose_name='Title')),
- ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='title', unique=True)),
- ('abstract', models.CharField(blank=True, max_length=255, verbose_name='Abstract')),
- ('description', models.TextField(blank=True, verbose_name='Description')),
- ('notes', models.TextField(blank=True, verbose_name='Notes')),
- ('accepted', models.NullBooleanField(default=None)),
- ('start_date', models.DateTimeField(blank=True, default=None, null=True)),
- ('duration', models.PositiveIntegerField(default=0, verbose_name='Duration (min)')),
- ('plenary', models.BooleanField(default=False)),
- ('registration_required', models.BooleanField(default=False)),
- ('attendees_limit', models.PositiveIntegerField(default=0, verbose_name='Max. number of attendees')),
- ('materials', models.FileField(help_text='You can use this field to share some materials related to your intervention.', null=True, upload_to=proposals.models.talk_materials_destination, verbose_name='Materials')),
- ('attendees', models.ManyToManyField(to='proposals.Attendee', verbose_name='Attendees')),
- ('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='proposals.Event', verbose_name='Intervention kind')),
- ('proposer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to=settings.AUTH_USER_MODEL)),
- ('room', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='planning.Room')),
- ('site', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
- ('speakers', models.ManyToManyField(to=settings.AUTH_USER_MODEL, verbose_name='Speakers')),
- ],
- options={
- 'ordering': ('event__id',),
- },
- ),
- migrations.CreateModel(
- name='Topic',
- fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('created', models.DateTimeField(auto_now_add=True)),
- ('updated', models.DateTimeField(auto_now=True)),
- ('name', models.CharField(max_length=128, verbose_name='Name')),
- ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='name', unique=True)),
- ('description', models.TextField(blank=True, verbose_name='Description')),
- ('reviewers', models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Reviewers')),
- ('site', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
- ],
- ),
- migrations.CreateModel(
- name='Track',
- fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('created', models.DateTimeField(auto_now_add=True)),
- ('updated', models.DateTimeField(auto_now=True)),
- ('name', models.CharField(max_length=128, verbose_name='Name')),
- ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='name')),
- ('description', models.TextField(blank=True, verbose_name='Description')),
- ('managers', models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Managers')),
- ('site', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
- ],
- ),
- migrations.CreateModel(
- name='Vote',
- fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('created', models.DateTimeField(auto_now_add=True)),
- ('updated', models.DateTimeField(auto_now=True)),
- ('vote', models.IntegerField(default=0, validators=[django.core.validators.MinValueValidator(-2), django.core.validators.MaxValueValidator(2)])),
- ('talk', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='proposals.Talk')),
- ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
- ],
- ),
- migrations.AddField(
- model_name='topic',
- name='track',
- field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='proposals.Track', verbose_name='Destination track'),
- ),
- migrations.AddField(
- model_name='talk',
- name='topics',
- field=models.ManyToManyField(blank=True, help_text='The topics can not be changed after submission.', to='proposals.Topic', verbose_name='Topics'),
- ),
- migrations.AddField(
- model_name='talk',
- name='track',
- field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='proposals.Track', verbose_name='Track'),
- ),
- migrations.AlterUniqueTogether(
- name='vote',
- unique_together=set([('talk', 'user')]),
- ),
- migrations.AlterUniqueTogether(
- name='track',
- unique_together=set([('site', 'name')]),
- ),
- migrations.AlterUniqueTogether(
- name='topic',
- unique_together=set([('site', 'name')]),
- ),
- migrations.AlterUniqueTogether(
- name='event',
- unique_together=set([('site', 'name')]),
- ),
- ]
diff --git a/proposals/migrations/0002_talk_video.py b/proposals/migrations/0002_talk_video.py
deleted file mode 100644
index 5c085cb..0000000
--- a/proposals/migrations/0002_talk_video.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# -*- coding: utf-8 -*-
-# Generated by Django 1.10.5 on 2017-01-16 21:47
-from __future__ import unicode_literals
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('proposals', '0001_initial'),
- ]
-
- operations = [
- migrations.AddField(
- model_name='talk',
- name='video',
- field=models.URLField(blank=True, default='', max_length=1000, verbose_name='URL vidéo'),
- ),
- ]
diff --git a/proposals/migrations/__init__.py b/proposals/migrations/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/proposals/models.py b/proposals/models.py
deleted file mode 100644
index 9ee3d53..0000000
--- a/proposals/models.py
+++ /dev/null
@@ -1,264 +0,0 @@
-from enum import IntEnum
-from datetime import timedelta
-from os.path import join, basename
-
-from django.contrib.auth.models import User
-from django.contrib.sites.models import Site
-from django.core.urlresolvers import reverse
-from django.core.validators import MaxValueValidator, MinValueValidator
-from django.db import models
-from django.db.models import Q
-from django.utils.translation import ugettext_lazy as _
-from django.utils.translation import ugettext
-from django.utils import timezone
-
-from autoslug import AutoSlugField
-from colorful.fields import RGBColorField
-
-from accounts.models import Participation
-from ponyconf.utils import PonyConfModel, enum_to_choices
-from planning.models import Room
-
-from .utils import query_sum
-
-
-class Conference(models.Model):
-
- site = models.OneToOneField(Site, on_delete=models.CASCADE)
- home = models.TextField(blank=True, default="")
- venue = models.TextField(blank=True, default="")
- city = models.CharField(max_length=64, blank=True, default="")
- subscriptions_open = models.BooleanField(default=False) # workshop subscription
-
- def cfp_is_open(self):
- events = Event.objects.filter(site=self.site)
- return any(map(lambda x: x.is_open(), events))
-
- @property
- def opened_events(self):
- now = timezone.now()
- return Event.objects.filter(site=self.site)\
- .filter(Q(opening_date__isnull=True) | Q(opening_date__lte=now))\
- .filter(Q(closing_date__isnull=True) | Q(closing_date__gte=now))
-
- def __str__(self):
- return str(self.site)
-
-
-class Track(PonyConfModel):
-
- site = models.ForeignKey(Site, on_delete=models.CASCADE)
-
- name = models.CharField(max_length=128, verbose_name=_('Name'))
- slug = AutoSlugField(populate_from='name')
- description = models.TextField(blank=True, verbose_name=_('Description'))
-
- managers = models.ManyToManyField(User, blank=True, verbose_name=_('Managers'))
-
- class Meta:
- unique_together = ('site', 'name')
-
- def estimated_duration(self):
- return sum([talk.estimated_duration for talk in self.talk_set.all()])
-
- def __str__(self):
- return self.name
-
- def get_absolute_url(self):
- return reverse('list-talks') + '?track=%s' % self.slug
-
-
-class Topic(PonyConfModel):
-
- site = models.ForeignKey(Site, on_delete=models.CASCADE)
-
- name = models.CharField(max_length=128, verbose_name=_('Name'))
- slug = AutoSlugField(populate_from='name', unique=True)
- description = models.TextField(blank=True, verbose_name=_('Description'))
- track = models.ForeignKey(Track, blank=True, null=True, verbose_name=_('Destination track'))
-
- reviewers = models.ManyToManyField(User, blank=True, verbose_name=_('Reviewers'))
-
- class Meta:
- unique_together = ('site', 'name')
-
- def __str__(self):
- return self.name
-
- def get_absolute_url(self):
- return reverse('list-talks') + '?topic=%s' % self.slug
-
-
-class Event(models.Model):
-
- site = models.ForeignKey(Site, on_delete=models.CASCADE)
- name = models.CharField(max_length=64)
- duration = models.PositiveIntegerField(default=0, verbose_name=_('Default duration (min)'))
- color = RGBColorField(default='#ffffff', verbose_name=_("Color on program"))
- label = models.CharField(max_length=64, verbose_name=_("Label on program"), blank=True, default="")
- opening_date = models.DateTimeField(null=True, blank=True, default=None)
- closing_date = models.DateTimeField(null=True, blank=True, default=None)
-
- def is_open(self):
- now = timezone.now()
- if self.opening_date and now < self.opening_date:
- return False
- if self.closing_date and now > self.closing_date:
- return False
- return True
-
- class Meta:
- unique_together = ('site', 'name')
- ordering = ('pk',)
-
- def __str__(self):
- return ugettext(self.name)
-
- def get_absolute_url(self):
- return reverse('list-talks') + '?kind=%d' % self.pk
-
-
-class Attendee(PonyConfModel):
-
- user = models.ForeignKey(User, null=True)
- name = models.CharField(max_length=64, blank=True, default="")
- email = models.EmailField(blank=True, default="")
-
- def get_name(self):
- if self.user:
- return str(self.user.profile)
- else:
- return self.name
- get_name.short_description = _('Name')
-
- def get_email(self):
- if self.user:
- return self.user.email
- else:
- return self.email
- get_email.short_description = _('Email')
-
- def __str__(self):
- return self.get_name()
-
-
-def talk_materials_destination(talk, filename):
- return join(talk.site.name, talk.slug, filename)
-
-
-class Talk(PonyConfModel):
-
- site = models.ForeignKey(Site, on_delete=models.CASCADE)
-
- proposer = models.ForeignKey(User, related_name='+')
- speakers = models.ManyToManyField(User, verbose_name=_('Speakers'))
- title = models.CharField(max_length=128, verbose_name=_('Title'), help_text=_('After submission, title can only be changed by the staff.'))
- slug = AutoSlugField(populate_from='title', unique=True)
- abstract = models.CharField(max_length=255, blank=True, verbose_name=_('Abstract'))
- description = models.TextField(blank=True, verbose_name=_('Description'))
- topics = models.ManyToManyField(Topic, blank=True, verbose_name=_('Topics'), help_text=_('The topics can not be changed after submission.'))
- track = models.ForeignKey(Track, blank=True, null=True, verbose_name=_('Track'))
- notes = models.TextField(blank=True, verbose_name=_('Notes'))
- event = models.ForeignKey(Event, verbose_name=_('Intervention kind'))
- accepted = models.NullBooleanField(default=None)
- start_date = models.DateTimeField(null=True, blank=True, default=None)
- duration = models.PositiveIntegerField(default=0, verbose_name=_('Duration (min)'))
- room = models.ForeignKey(Room, blank=True, null=True, default=None)
- plenary = models.BooleanField(default=False)
- registration_required = models.BooleanField(default=False)
- attendees = models.ManyToManyField(Attendee, verbose_name=_('Attendees'))
- attendees_limit = models.PositiveIntegerField(default=0, verbose_name=_('Max. number of attendees'))
- materials = models.FileField(null=True, upload_to=talk_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='URL vidéo')
-
- class Meta:
- ordering = ('title',)
-
- def __str__(self):
- return self.title
-
- def get_speakers_str(self):
- speakers = [str(Participation.objects.get(site=self.site, user=speaker)) for speaker in self.speakers.all()]
- if len(speakers) == 0:
- return 'superman'
- elif len(speakers) == 1:
- return speakers[0]
- else:
- return ', '.join(speakers[:-1]) + ' & ' + str(speakers[-1])
-
- @property
- def estimated_duration(self):
- return self.duration or self.event.duration
-
- def get_absolute_url(self):
- return reverse('show-talk', kwargs={'slug': self.slug})
-
- def is_moderable_by(self, user):
- if user.is_superuser:
- return True
- try:
- participation = Participation.objects.get(site=self.site, user=user)
- except Participation.DoesNotExists:
- return False
- if participation.orga:
- return True
- if self.topics.filter(reviewers=user).exists():
- return True
- if self.track and user in self.track.managers.all():
- return True
- return False
-
- def is_editable_by(self, user):
- return user == self.proposer or user in self.speakers.all() or self.is_moderable_by(user)
-
- def score(self):
- if self.vote_set.exists():
- return query_sum(self.vote_set, 'vote') / len(self.vote_set.all())
- else:
- return 0
-
- @property
- def end_date(self):
- if self.estimated_duration:
- return self.start_date + timedelta(minutes=self.estimated_duration)
- else:
- return None
-
- @property
- def remaining_attendees(self):
- if self.registration_required and self.attendees_limit:
- return self.attendees_limit - self.attendees.count()
- else:
- return None # = infinity \o/
-
- @property
- def dtstart(self):
- return self.start_date.strftime('%Y%m%dT%H%M%SZ')
-
- @property
- def dtend(self):
- return self.end_date.strftime('%Y%m%dT%H%M%SZ')
-
- @property
- def materials_name(self):
- return basename(self.materials.name)
-
- class Meta:
- ordering = ('event__id',)
-
-
-class Vote(PonyConfModel):
-
- talk = models.ForeignKey(Talk)
- user = models.ForeignKey(User)
- vote = models.IntegerField(validators=[MinValueValidator(-2), MaxValueValidator(2)], default=0)
-
- class Meta:
- unique_together = ('talk', 'user')
-
- def __str__(self):
- return "%+i by %s for %s" % (self.vote, self.user, self.talk)
-
- def get_absolute_url(self):
- return self.talk.get_absolute_url()
diff --git a/proposals/signals.py b/proposals/signals.py
deleted file mode 100644
index a7e8b16..0000000
--- a/proposals/signals.py
+++ /dev/null
@@ -1,55 +0,0 @@
-from django.db.models.signals import m2m_changed, post_save
-from django.dispatch import Signal, receiver
-from django.contrib.sites.models import Site
-from django.utils.translation import ugettext_noop
-from django.conf import settings
-
-from ponyconf.decorators import disable_for_loaddata
-from accounts.models import Participation
-
-from .models import Conference, Talk, Topic, Event
-
-
-talk_added = Signal(providing_args=["sender", "instance", "author"])
-talk_edited = Signal(providing_args=["sender", "instance", "author"])
-
-
-@receiver(post_save, sender=Site, dispatch_uid="Create Conference for Site")
-@disable_for_loaddata
-def create_conference(sender, instance, **kwargs):
- Conference.objects.get_or_create(site=instance)
-
-
-@receiver(post_save, sender=Site, dispatch_uid="Create default events type for Site")
-@disable_for_loaddata
-def create_events(sender, instance, **kwargs):
- if not Event.objects.filter(site=instance).exists():
- Event.objects.bulk_create([
- Event(site=instance, name=ugettext_noop('conference (short)')),
- Event(site=instance, name=ugettext_noop('conference (long)')),
- Event(site=instance, name=ugettext_noop('workshop')),
- Event(site=instance, name=ugettext_noop('stand')),
- Event(site=instance, name=ugettext_noop('other')),
- ])
-
-
-def call_first_site_post_save(apps, **kwargs):
- site = Site.objects.filter(id=getattr(settings, 'SITE_ID', 1))
- if site.exists():
- site.first().save()
-
-
-@receiver(m2m_changed, sender=Talk.speakers.through, dispatch_uid="Create Participation for speakers")
-def create_participation_for_speakers(sender, instance, action, reverse, model, pk_set, using, **kwargs):
- if action != "pre_add":
- pass
- for speaker in instance.speakers.all():
- Participation.objects.get_or_create(user=speaker, site=instance.site)
-
-
-@receiver(m2m_changed, sender=Topic.reviewers.through, dispatch_uid="Create Participation for reviewers")
-def create_participation_for_reviewers(sender, instance, action, reverse, model, pk_set, using, **kwargs):
- if action != "pre_add":
- pass
- for reviewer in instance.reviewers.all():
- Participation.objects.get_or_create(user=reviewer, site=instance.site)
diff --git a/proposals/static/js/markdown-preview.js b/proposals/static/js/markdown-preview.js
deleted file mode 100644
index b40abe9..0000000
--- a/proposals/static/js/markdown-preview.js
+++ /dev/null
@@ -1,25 +0,0 @@
-var csrftoken = $.cookie('csrftoken');
-
-function csrfSafeMethod(method) {
- // these HTTP methods do not require CSRF protection
- return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
-}
-$.ajaxSetup({
- beforeSend: function(xhr, settings) {
- if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
- xhr.setRequestHeader("X-CSRFToken", csrftoken);
- }
- }
-});
-
-$('a[href="#preview"]').on("show.bs.tab", function (e) {
- $('#preview-content').html('Loading preview...');
- var data = $('#markdown-content').val();
- $.post(markdown_preview_url, {'data': data})
- .done(function(data, textStatus) {
- $('#preview-content').html(data);
- })
- .fail(function () {
- $('#preview-content').html('Sorry, an error occured.');
- });
-})
diff --git a/proposals/templates/proposals/_talk_list.html b/proposals/templates/proposals/_talk_list.html
deleted file mode 100644
index acbbd6c..0000000
--- a/proposals/templates/proposals/_talk_list.html
+++ /dev/null
@@ -1,24 +0,0 @@
-{% load i18n %}
- {% regroup talk_list by event as event_list %}
- {% for event in event_list %}
-
{{ event.list.0.event }}
- {% for talk in event.list %}
-
- {{ talk.get_link }}
- {% trans "by" %}
- {% for speaker in talk.speakers.all %}
- {{ speaker }}
- {% if forloop.revcounter == 2 %} {% trans "and" %} {% elif not forloop.last %}, {% endif %}
- {% endfor %}
- {% if talk.topics.exists %}
- {% trans "in" %}
- {% for topic in talk.topics.all %}
- {{ topic }}
- {% if forloop.revcounter == 2 %} {% trans "and" %} {% elif not forloop.last %}, {% endif %}
- {% endfor %}
- {% endif %}
-
- {% endfor %}
-
- {% empty %}{% trans "No talks" %}
- {% endfor %}
diff --git a/proposals/templates/proposals/conference.html b/proposals/templates/proposals/conference.html
deleted file mode 100644
index 56e6453..0000000
--- a/proposals/templates/proposals/conference.html
+++ /dev/null
@@ -1,53 +0,0 @@
-{% extends 'staff.html' %}
-
-{% load bootstrap3 staticfiles i18n %}
-
-{% block conferencetab %} class=active{% endblock %}
-
-{% block content %}
-
-
-
-
{% trans "Home page" %}
-
-
-
-
-{% endblock %}
-
-{% block css %}
-{{ block.super }}
-{{ form.media.css }}
-{% endblock css %}
-
-{% block js_end %}
-{{ block.super }}
-{{ form.media.js }}
-
-
-{% endblock js_end %}
diff --git a/proposals/templates/proposals/home.html b/proposals/templates/proposals/home.html
deleted file mode 100644
index b91fd71..0000000
--- a/proposals/templates/proposals/home.html
+++ /dev/null
@@ -1,11 +0,0 @@
-{% extends 'base.html' %}
-
-{% load proposals_tags i18n %}
-
-{% block hometab %} class="active"{% endblock %}
-
-{% block content %}
-
-{% markdown site.conference.home %}
-
-{% endblock %}
diff --git a/proposals/templates/proposals/participate.html b/proposals/templates/proposals/participate.html
deleted file mode 100644
index ccc93ac..0000000
--- a/proposals/templates/proposals/participate.html
+++ /dev/null
@@ -1,35 +0,0 @@
-{% extends 'base.html' %}
-
-{% load accounts_tags i18n %}
-
-{% block exhibitortab %} class="active"{% endblock %}
-
-{% block content %}
-
-{% trans "Participate" %}
-
-{% if my_talks %}
-{% trans "My talks:" %}
-{% include "proposals/_talk_list.html" with talk_list=my_talks %}
-{% endif %}
-
-{% if proposed_talks %}
-{% trans "Proposed talks for others speakers:" %}
-{% include "proposals/_talk_list.html" with talk_list=proposed_talks %}
-{% endif %}
-
-
-{% if conference.cfp_is_open %}
-{% trans "The Call for Participation is currently open for following categories:" %}
-{% for event in conference.opened_events.all %}
-{% if forloop.first %}{% endif %}
- {{ event }}{% if event.closing_date %} ({% blocktrans with closing_date=event.closing_date|date:"DATETIME_FORMAT" %}until {{ closing_date }}{% endblocktrans %}){% endif %}
-{% if forloop.last %} {% endif %}
-{% endfor %}
-
-{% trans "Propose a talk" %}
-{% else %}
-{% trans "Sorry, the Call for Participation is closed." %}
-{% endif %}
-
-{% endblock %}
diff --git a/proposals/templates/proposals/speaker_list.html b/proposals/templates/proposals/speaker_list.html
deleted file mode 100644
index 055d72c..0000000
--- a/proposals/templates/proposals/speaker_list.html
+++ /dev/null
@@ -1,117 +0,0 @@
-{% extends 'staff.html' %}
-
-{% load bootstrap3 i18n %}
-
-{% block speakerstab %} class="active"{% endblock %}
-
-{% block content %}
-
-{% trans "Speakers" %}
-
-{% trans "Show filtering options…" %}
-
-
-
-
-
-
-
-
- {% bootstrap_field filter_form.transport layout="horizontal" %}
- {% bootstrap_field filter_form.transport_booked layout="horizontal" %}
- {% bootstrap_field filter_form.sound layout="horizontal" %}
-
-
- {% bootstrap_field filter_form.accommodation layout="horizontal" %}
- {% bootstrap_field filter_form.accommodation_booked layout="horizontal" %}
- {% bootstrap_field filter_form.status layout="horizontal" %}
-
-
-
-
- {% bootstrap_field filter_form.topic layout="horizontal" %}
-
-
- {% bootstrap_field filter_form.track layout="horizontal" %}
-
-
-
-
-
-
-
-
- {% trans "Total:" %} {{ speaker_list|length }} {% trans "speaker" %}{{ speaker_list|length|pluralize }}
-
-
-
- {% trans "Username" %}
- {% trans "Fullname" %}
- {% trans "Talk count" %}
- {% blocktrans context "table column title" %}Need transport?{% endblocktrans %}
- {% blocktrans context "table column title" %}Need accommodation?{% endblocktrans %}
- {% trans "Need sound?" %}
-
-
-
-
-
- {% trans "Contact:" %} {% trans "link" %}
-
-
- {% for speaker in speaker_list %}
- {% if forloop.first %}
-
- {% endif %}
-
- {{ speaker.user.username }}
- {{ speaker.user.get_full_name }}
- {{ speaker.not_refused_talk_set.count }}{% if speaker.pending_talk_set.count %} ({{ speaker.pending_talk_set.count }} pending){% endif %}
- {% if speaker.need_transport %}
-
- {% for transport in speaker.transport.all %}
- {% if not forloop.first %}, {% endif %}
- {{ transport }}
- {% empty %}
- Yes
- {% endfor %}
-
- {% elif speaker.need_transport is None %}
- ?
- {% else %}
- No
- {% endif %}
-
- {% if speaker.accommodation is None %}
- ?
- {% else %}
- {{ speaker.get_accommodation_display }}
- {% endif %}
-
- {% if speaker.sound %}
- Yes
- {% else %}
- No
- {% endif %}
-
- {% trans "Contact" %}
-
-
- {% if forloop.last %}
-
- {% endif %}
- {% endfor %}
-
-
-{% endblock %}
-
-{% block js_end %}
-
-{% endblock %}
diff --git a/proposals/templates/proposals/talk_decide.html b/proposals/templates/proposals/talk_decide.html
deleted file mode 100644
index 5df73f6..0000000
--- a/proposals/templates/proposals/talk_decide.html
+++ /dev/null
@@ -1,26 +0,0 @@
-{% extends 'base.html' %}
-
-{% load i18n %}
-
-{% block listingtab %} active{% endblock %}
-
-{% block content %}
-
-{% if accept %}{% trans "Are you sure to accept this proposals?" %}{% else %}{% trans "Are you sure to decline this proposals?" %}{% endif %}
-
-{% trans "Information about the proposals" %}
-{% trans "Title:" %} {{ talk.title }}
-{% trans "Kind:" %} {{ talk.event }}
-
-{% trans "Information for the proposer" %}
-
- {% csrf_token %}
-
- {% trans "If you want to send a message to the proposer, please enter it below. Remember to indicate which talk your message is reffering." %}
-
-
- {% if accept %}{% trans "Accept the proposal" %}{% else %}{% trans "Decline the proposal" %}{% endif %}
- {% trans "Cancel" %}
-
-
-{% endblock %}
diff --git a/proposals/templates/proposals/talk_detail.html b/proposals/templates/proposals/talk_detail.html
deleted file mode 100644
index e95e19d..0000000
--- a/proposals/templates/proposals/talk_detail.html
+++ /dev/null
@@ -1,153 +0,0 @@
-{% extends base_template %}
-
-{% if staff %}
-{% block talkstab %} class="active"{% endblock %}
-{% else %}
-{% block exhibitortab %} class="active"{% endblock %}
-{% endif %}
-
-{% load i18n %}
-
-{% block content %}
-
-{{ talk.title }}
-
-{% if edit_perm %}
-{% trans "Edit" %}
-{% endif %}
-
-{% if talk.abstract %}{{ talk.abstract }}{% else %}{% trans "No abstract provided." %} {% endif %}
-
-{% if moderate_perm %}
-
-
- {% trans "Format" %}
- {{ talk.event }}
- {% trans "Topics" %}
- {% for topic in talk.topics.all %}
- {{ topic }} {% if not forloop.last %}, {% endif %}
- {% empty %}
- {% trans "No topics." %}
- {% endfor %}
-
- {% trans "Track" %}
- {% if talk.track %}
- {{ talk.track }}
- {% else %}
- {% trans "No assigned yet." %}
- {% endif %}
-
- Horaire
- {% if talk.start_date %}
- {{ talk.start_date|date:"l d b" }} ,
- {{ talk.start_date|date:"H:i" }} – {% if talk.end_date %}{{ talk.end_date|date:"H:i" }}{% else %}?{% endif %}
- {% else %}{% trans "not defined" %}
- {% endif %}
-
- Salle
- {% if talk.room %}
-
- {{ talk.room }}
-
- {% else %}{% trans "not defined" %}
- {% endif %}
-
- {% if talk.registration_required %}
- {% trans "Registrations" %}
- {% if talk.attendees_limit %}{{ talk.attendees.count }} / {{ talk.attendees_limit }}{% else %}{% trans "required but unlimited" %}{% endif %}
- {% endif %}
- {% if talk.materials %}
- {% trans "Materials" %}
- {{ talk.materials_name }}
- {% endif %}
- {% if talk.video %}
- {% trans "Video" %}
- {% trans "download" %}
- {% endif %}
-
-
-
-{% endif %}
-
-{% trans "Description" %}
-
-{% if talk.description %}{{ talk.description|linebreaksbr }}{% else %}{% trans "No description provided." %} {% endif %}
-
-{% trans "Speakers" %}
-
-{% for speaker in talk.speakers.all %}
-{% if forloop.first %}{% endif %}
-{% empty %}
-{% trans "No speakers." %}
-{% endfor %}
-
-{% if moderate_perm %}
-
-{% if not talk.track %}
-{% trans "Track" %}
-{% trans "No assigned yet." %}
- {% for topic in talk.topics.distinct %}
- {% if forloop.first %}{% endif %}
- {% if topic.track %}
- {% trans "Assign to" %} {{ topic.track }}
- {% endif %}
- {% if forloop.last %}
{% endif %}
- {% endfor %}
-{% endif %}
-
-{% endif %}
-
-{% trans "Notes" %}
-
-{% if talk.notes %}{{ talk.notes|linebreaksbr }}{% else %}{% trans "No notes." %} {% endif %}
-
-{% if moderate_perm %}
-
-{% trans "Moderation" %}
-
-{% trans "Status" %}
-
-{{ talk.accepted|yesno:"Accepted,Declined,Pending decision" }}
-
-{% if talk.accepted == None %}
-{% trans "Vote" %}
-
-
-{{ talk.vote_set.all|length }} {% trans "vote" %}{{ talk.vote_set.all|length|pluralize }}, {% trans "average:" %} {{ talk.score|floatformat:1 }}
-
-Accept
-Decline
-{% endif %}
-
-{% if talk.registration_required %}
-{% trans "Attendees" %}
-
-{% for attendee in talk.attendees.all %}
-{% if forloop.first %}{% endif %}
- {{ attendee.get_name }}
-{% if forloop.last %} {% endif %}
-{% empty %}
-{% trans "No attendees yet." %}
-{% endfor %}
-
-{% endif %}
-
-{% trans "Messages" %}
-{% trans "These messages are for organization team only." %}
-{% for message in talk.conversation.messages.all %}
-{% include 'conversations/_message_detail.html' %}
-{% endfor %}
-
-{% include 'conversations/_message_form.html' %}
-
-{% endif %}
-
-{% endblock %}
diff --git a/proposals/templates/proposals/talk_edit.html b/proposals/templates/proposals/talk_edit.html
deleted file mode 100644
index 4091a7b..0000000
--- a/proposals/templates/proposals/talk_edit.html
+++ /dev/null
@@ -1,37 +0,0 @@
-{% extends base_template %}
-
-{% load i18n %}
-
-{% block talkstab %}{% if base_template == 'staff.html' %} class="active"{% endif %}{% endblock %}
-{% block exhibitortab %}{% if base_template == 'base.html' %} class="active"{% endif %}{% endblock %}
-
-{% block content %}
-
-{% if talk %}{% trans "Edit a talk" %}{% else %}{% trans "Propose a talk" %}{% endif %}
-
-{% include "_form.html" with multipart=True %}
-
-{% endblock %}
-
-{% block css %}
-{{ block.super }}
-{{ form.media.css }}
-{% endblock css %}
-
-{% block js_end %}
-{{ block.super }}
-{{ form.media.js }}
-
-{% endblock js_end %}
diff --git a/proposals/templates/proposals/talk_list.html b/proposals/templates/proposals/talk_list.html
deleted file mode 100644
index 4a12d8f..0000000
--- a/proposals/templates/proposals/talk_list.html
+++ /dev/null
@@ -1,122 +0,0 @@
-{% extends 'staff.html' %}
-
-{% load bootstrap3 i18n accounts_tags %}
-
-{% block talkstab %} class="active"{% endblock %}
-
-{% block content %}
-
-{% trans "Talks" %}
-
-{% trans "Show filtering options…" %}
-
-
-
-
-
-
-
-
- {% bootstrap_field filter_form.status layout="horizontal" %}
- {% bootstrap_field filter_form.kind layout="horizontal" %}
- {% bootstrap_field filter_form.vote layout="horizontal" %}
- {% bootstrap_field filter_form.room layout="horizontal" %}
- {% bootstrap_field filter_form.scheduled layout="horizontal" %}
- {% bootstrap_field filter_form.materials layout="horizontal" %}
- {% bootstrap_field filter_form.video layout="horizontal" %}
-
-
- {% bootstrap_field filter_form.topic layout="horizontal" %}
-
-
- {% bootstrap_field filter_form.track layout="horizontal" %}
-
-
-
-
-
-
-
-
-
-
-
-{% if action_form %}
-
-
-
{% trans "For selected talks:" %}
- {% csrf_token %}
- {% bootstrap_field action_form.decision %}
- {% if request|orga %}
- {% bootstrap_field action_form.track %}
- {% bootstrap_field action_form.room %}
- {% endif %}
- {% buttons %}
- {% trans "Apply" %}
- {% endbuttons %}
-
-
-{% endif %}
-
-
-
-{% endblock %}
-
-{% block js_end %}
-
-{% endblock %}
diff --git a/proposals/templates/proposals/talk_register.html b/proposals/templates/proposals/talk_register.html
deleted file mode 100644
index 5c1e535..0000000
--- a/proposals/templates/proposals/talk_register.html
+++ /dev/null
@@ -1,29 +0,0 @@
-{% extends 'base.html' %}
-
-{% load bootstrap3 i18n %}
-
-{% block wsregtab %} class="active"{% endblock %}
-
-{% block css %}
-{{ block.super }}
-{{ form.media.css }}
-{% endblock %}
-
-{% block content %}
-
-{% trans "Register for a workshop" %}{{ talk.title }}
-
-
-
-{% include "_form.html" %}
-
-
- {% trans "Login to register with your account" %}
-
-
-{% endblock %}
-
-{% block js_end %}
-{{ block.super }}
-{{ form.media.js }}
-{% endblock %}
diff --git a/proposals/templates/proposals/talk_registrable_list.html b/proposals/templates/proposals/talk_registrable_list.html
deleted file mode 100644
index b38d26c..0000000
--- a/proposals/templates/proposals/talk_registrable_list.html
+++ /dev/null
@@ -1,36 +0,0 @@
-{% extends 'base.html' %}
-
-{% load accounts_tags i18n %}
-
-{% block wsregtab %} class="active"{% endblock %}
-
-{% block content %}
-
-{% trans "Register to a workshop" %}
-
-{% for talk in talks %}
-{% if forloop.first %}{% endif %}
-
-
{{ talk.title }}
-
-
{{ talk.description }}
- {% if talk.attendees_limit %}
-
{% blocktrans count remaining=talk.remaining_attendees %}{{ remaining }} remaining seat{% plural %}{{ remaining }} remaining seats{% endblocktrans %}
- {% endif %}
- {% if talk.remaining_attendees != 0 or attendee in talk.attendees.all %}
-
- {% if attendee in talk.attendees.all %}
- {% trans "Unregister" %}
- {% else %}
- {% trans "Register" %}
- {% endif %}
-
- {% endif %}
-
-
-{% if forloop.last %}
{% endif %}
-{% empty %}
-{% trans "There are no workshops requiring registration for now … come back later!" %}
-{% endfor %}
-
-{% endblock %}
diff --git a/proposals/templates/proposals/topic_form.html b/proposals/templates/proposals/topic_form.html
deleted file mode 100644
index 5e50057..0000000
--- a/proposals/templates/proposals/topic_form.html
+++ /dev/null
@@ -1,23 +0,0 @@
-{% extends 'staff.html' %}
-
-{% load bootstrap3 i18n %}
-
-{% block topicstab %} class="active"{% endblock %}
-
-{% block css %}
-{{ block.super }}
-{{ form.media.css }}
-{% endblock %}
-
-{% block content %}
-
-{% trans "Topic" %}
-
-{% include "_form.html" %}
-
-{% endblock %}
-
-{% block js_end %}
-{{ block.super }}
-{{ form.media.js }}
-{% endblock %}
diff --git a/proposals/templates/proposals/topic_list.html b/proposals/templates/proposals/topic_list.html
deleted file mode 100644
index d55caa7..0000000
--- a/proposals/templates/proposals/topic_list.html
+++ /dev/null
@@ -1,35 +0,0 @@
-{% extends 'staff.html' %}
-
-{% load bootstrap3 accounts_tags i18n %}
-
-{% block topicstab %} class="active"{% endblock %}
-
-{% block content %}
-
-{% trans "Topics" %}
-
-{% if request|orga %}
-{% trans "Add a topic" %}
-{% endif %}
-
-
- {% for topic in topic_list %}
-
- {% cycle '' '
' %}
- {% cycle '' '' '
' %}
- {% empty %}
-
{% trans "No topics." %}
- {% endfor %}
-
-
-{% endblock %}
diff --git a/proposals/templates/proposals/track_form.html b/proposals/templates/proposals/track_form.html
deleted file mode 100644
index 8fc12db..0000000
--- a/proposals/templates/proposals/track_form.html
+++ /dev/null
@@ -1,23 +0,0 @@
-{% extends 'staff.html' %}
-
-{% load bootstrap3 i18n %}
-
-{% block trackstab %} class="active"{% endblock %}
-
-{% block css %}
-{{ block.super }}
-{{ form.media.css }}
-{% endblock %}
-
-{% block content %}
-
-{% trans "Track" %}
-
-{% include "_form.html" %}
-
-{% endblock %}
-
-{% block js_end %}
-{{ block.super }}
-{{ form.media.js }}
-{% endblock %}
diff --git a/proposals/templates/proposals/track_list.html b/proposals/templates/proposals/track_list.html
deleted file mode 100644
index 924cc19..0000000
--- a/proposals/templates/proposals/track_list.html
+++ /dev/null
@@ -1,37 +0,0 @@
-{% extends 'staff.html' %}
-
-{% load bootstrap3 accounts_tags proposals_tags i18n %}
-
-{% block trackstab %} class="active"{% endblock %}
-
-{% block content %}
-
-{% trans "Tracks" %}
-
-{% if request|orga %}
-{% trans "Add a track" %}
-{% endif %}
-
-
- {% for track in track_list %}
-
- {% cycle '' '
' %}
- {% cycle '' '' '
' %}
- {% empty %}
-
{% trans "No tracks." %}
- {% endfor %}
-
-
-{% endblock %}
diff --git a/proposals/templatetags/proposals_tags.py b/proposals/templatetags/proposals_tags.py
deleted file mode 100644
index 2656151..0000000
--- a/proposals/templatetags/proposals_tags.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from django import template
-
-from proposals.utils import markdown_to_html
-
-
-register = template.Library()
-
-
-@register.simple_tag
-def markdown(value):
- return markdown_to_html(value)
-
-@register.filter('duration_format')
-def duration_format(value):
- value = int(value)
- hours = int(value/60)
- minutes = value%60
- return '%d h %02d' % (hours, minutes)
diff --git a/proposals/tests.py b/proposals/tests.py
deleted file mode 100644
index 12885ac..0000000
--- a/proposals/tests.py
+++ /dev/null
@@ -1,95 +0,0 @@
-from django.contrib.auth.models import User
-from django.contrib.sites.models import Site
-from django.core.urlresolvers import reverse
-from django.test import TestCase
-
-from accounts.models import Participation
-
-from .models import Talk, Topic, Vote
-
-
-class ProposalsTests(TestCase):
- def setUp(self):
- a, b, c = (User.objects.create_user(guy, email='%s@example.org' % guy, password=guy) for guy in 'abc')
- Topic.objects.create(name='topipo', description='super topic', site=Site.objects.first())
- c.is_superuser = True
- c.save()
-
- def test_everything(self):
- # talk-edit
- self.client.login(username='a', password='a')
- self.client.post(reverse('add-talk'),
- {'title': 'super talk',
- 'abstract': 'super',
- 'description': 'this is my super talk',
- 'notes': 'you can watch my previous talk videos',
- 'event': 1,
- 'topics': 1,
- 'speakers': 1})
- talk = Talk.objects.first()
- self.assertEqual(str(talk), 'super talk')
- self.assertEqual(talk.abstract, 'super')
- self.assertEqual(talk.description, 'this is my super talk')
- self.assertEqual(talk.notes, 'you can watch my previous talk videos')
- response = self.client.post(reverse('edit-talk', kwargs={'talk': 'super-talk'}),
- {'title': 'mega talk', 'description': 'mega',
- 'event': 1, 'speakers': 1, 'duration': 60,
- 'registration_required': False, 'attendees_limit': 0})
- self.assertEqual(str(talk), 'super talk') # title is read only there
- talk = Talk.objects.first()
- self.assertEqual(talk.description, 'mega')
-
- # Status Code
- for view in ['home', 'participate-as-speaker', 'add-talk', 'list-topics']:
- self.assertEqual(self.client.get(reverse(view)).status_code, 200)
- for view in ['list-talks', 'list-speakers']:
- self.assertEqual(self.client.get(reverse(view)).status_code, 403)
- self.assertEqual(self.client.get(reverse('list-speakers')).status_code, 403)
- self.assertEqual(self.client.get(reverse('edit-talk', kwargs={'talk': talk.slug})).status_code, 200)
- self.assertEqual(self.client.get(reverse('show-talk', kwargs={'slug': talk.slug})).status_code, 200)
- self.assertEqual(self.client.get(reverse('show-participant', kwargs={'username': 'a'})).status_code, 200)
-
- self.client.login(username='b', password='b')
- self.assertEqual(self.client.post(reverse('edit-talk', kwargs={'talk': 'super-talk'}),
- {'title': 'mega talk', 'description': 'mega', 'event': 1}).status_code, 403)
- self.assertEqual(self.client.get(reverse('participate-as-speaker')).status_code, 200)
-
- # Vote
- self.assertEqual(talk.score(), 0)
- self.assertEqual(self.client.get(reverse('vote', kwargs={'talk': talk.slug, 'score': 2})).status_code, 403)
- self.client.login(username='c', password='c')
- self.assertEqual(self.client.get(reverse('vote', kwargs={'talk': talk.slug, 'score': 2})).status_code, 302)
- self.assertEqual(talk.score(), 2)
-
- # Models str & get_asbolute_url
- for model in [Talk, Topic, Vote]:
- item = model.objects.first()
- self.assertEqual(self.client.get(item.get_absolute_url()).status_code, 200)
- self.assertTrue(str(item))
-
- # Talk.is_{editable,moderable}_by
- a, b, c = User.objects.all()
- self.assertTrue(talk.is_editable_by(c)) # c is superuser
- self.assertTrue(talk.is_moderable_by(c)) # c is superuser
- self.assertFalse(talk.is_editable_by(b)) # b is not speaker
- self.assertFalse(talk.is_moderable_by(b)) # b is not orga
- self.client.login(username='a', password='a')
- self.client.post(reverse('edit-talk', kwargs={'talk': 'super-talk'}),
- {'title': 'mega talk', 'description': 'mega', 'event': 1,
- 'speakers': (a.pk, b.pk), 'duration': 60,
- 'registration_required': False, 'attendees_limit': 0})
- talk = Talk.objects.get(slug='super-talk')
- self.assertTrue(b in talk.speakers.all())
- self.assertTrue(talk.is_editable_by(b)) # b is speaker now
- self.assertFalse(talk.is_moderable_by(b)) # b is not orga
-
- def test_topic_edition_permissions(self):
- # Only orga and superuser can edit topics
- self.client.login(username='b', password='b')
- self.assertFalse(Participation.objects.get(user__username='b').orga)
- self.assertEqual(self.client.get(reverse('edit-topic', kwargs={'slug': 'topipo'})).status_code, 302)
- Participation.objects.filter(user__username='b').update(orga=True)
- self.assertEqual(self.client.get(reverse('edit-topic', kwargs={'slug': 'topipo'})).status_code, 200)
- self.client.login(username='c', password='c') # superuser
- self.assertEqual(self.client.get(reverse('edit-topic', kwargs={'slug': 'topipo'})).status_code, 200)
- self.assertEqual(self.client.get(reverse('list-topics')).status_code, 200)
diff --git a/proposals/urls.py b/proposals/urls.py
deleted file mode 100644
index 9d25dce..0000000
--- a/proposals/urls.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from django.conf.urls import url
-
-from proposals import views
-
-urlpatterns = [
- url(r'^markdown/$', views.markdown_preview, name='markdown'),
- url(r'^$', views.home, name='home'),
- url(r'^staff/$', views.staff, name='staff'),
- url(r'^conference/$', views.conference, name='edit-conference'),
- url(r'^talk/propose/$', views.participate, name='participate-as-speaker'),
- url(r'^talk/$', views.talk_list, name='list-talks'),
- url(r'^talk/add/$', views.talk_edit, name='add-talk'),
- url(r'^talk/edit/(?P[-\w]+)$', views.talk_edit, name='edit-talk'),
- url(r'^talk/vote/(?P[-\w]+)/(?P[-0-2]+)$', views.vote, name='vote'),
- url(r'^talk/details/(?P[-\w]+)$', views.TalkDetail.as_view(), name='show-talk'),
- url(r'^talk/accept/(?P[-\w]+)/$', views.talk_decide, {'accepted': True}, name='accept-talk'),
- url(r'^talk/decline/(?P[-\w]+)/$', views.talk_decide, {'accepted': False}, name='decline-talk'),
- url(r'^talk/assign-to-track/(?P[-\w]+)/(?P[-\w]+)/$', views.talk_assign_to_track, name='assign-talk-to-track'),
- url(r'^topic/$', views.TopicList.as_view(), name='list-topics'),
- url(r'^topic/add/$', views.TopicCreate.as_view(), name='add-topic'),
- url(r'^topic/(?P[-\w]+)/edit/$', views.TopicUpdate.as_view(), name='edit-topic'),
- url(r'^track/$', views.TrackList.as_view(), name='list-tracks'),
- url(r'^track/add/$', views.TrackCreate.as_view(), name='add-track'),
- url(r'^track/(?P[-\w]+)/edit/$', views.TrackUpdate.as_view(), name='edit-track'),
- url(r'^speakers/$', views.speaker_list, name='list-speakers'),
- url(r'^register/$', views.talk_registrable_list, name='list-registrable-talks'),
- url(r'^register/(?P[-\w]+)$', views.talk_register, name='register-for-a-talk'),
-]
diff --git a/proposals/utils.py b/proposals/utils.py
deleted file mode 100644
index a6a44c5..0000000
--- a/proposals/utils.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from django.contrib.sites.shortcuts import get_current_site
-from django.db.models import Q, Sum
-from django.db.models.functions import Coalesce
-from django.utils.safestring import mark_safe
-
-from accounts.models import Participation
-
-from markdown import markdown
-import bleach
-
-
-def query_sum(queryset, field):
- return queryset.aggregate(s=Coalesce(Sum(field), 0))['s']
-
-
-def allowed_talks(talks, request):
- if not Participation.objects.get(site=get_current_site(request), user=request.user).is_orga():
- talks = talks.filter(Q(topics__reviewers=request.user) | Q(speakers=request.user) | Q(proposer=request.user))
- return talks.distinct()
-
-def markdown_to_html(md):
- html = markdown(md)
- allowed_tags = bleach.ALLOWED_TAGS + ['p', 'pre', 'span' ] + ['h%d' % i for i in range(1, 7) ]
- html = bleach.clean(html, tags=allowed_tags)
- return mark_safe(html)
diff --git a/proposals/views.py b/proposals/views.py
deleted file mode 100644
index e6bcfea..0000000
--- a/proposals/views.py
+++ /dev/null
@@ -1,459 +0,0 @@
-from functools import reduce
-
-from django.contrib import messages
-from django.contrib.auth.decorators import login_required
-from django.contrib.auth.mixins import LoginRequiredMixin
-from django.contrib.auth.models import User
-from django.contrib.sites.shortcuts import get_current_site
-from django.core.exceptions import PermissionDenied
-from django.core.urlresolvers import reverse
-from django.db.models import Q, Count
-from django.shortcuts import get_object_or_404, redirect, render
-from django.views.generic import CreateView, DetailView, ListView, UpdateView
-from django.utils.translation import ugettext_lazy as _
-from django.utils.translation import ungettext_lazy
-from django.views.decorators.http import require_http_methods
-from django.http import HttpResponse, Http404
-
-from ponyconf.mixins import OnSiteFormMixin
-
-from accounts.models import Participation
-from accounts.mixins import OrgaRequiredMixin, StaffRequiredMixin
-from accounts.decorators import orga_required, staff_required
-from accounts.utils import is_staff, is_orga
-
-from conversations.models import ConversationWithParticipant, ConversationAboutTalk, Message
-
-from planning.models import Room
-
-from .forms import TalkForm, TopicForm, TrackForm, ConferenceForm, TalkFilterForm, STATUS_VALUES, SpeakerFilterForm, TalkActionForm, SubscribeForm
-from .models import Talk, Track, Topic, Vote, Conference, Attendee
-from .signals import talk_added, talk_edited
-from .utils import markdown_to_html
-
-
-@login_required
-@require_http_methods(["POST"])
-def markdown_preview(request):
- content = request.POST.get('data', '')
- return HttpResponse(markdown_to_html(content))
-
-
-def home(request):
- return render(request, 'proposals/home.html')
-
-
-@staff_required
-def staff(request):
- return render(request, 'staff.html')
-
-
-@orga_required
-def conference(request):
- conference = Conference.objects.get(site=get_current_site(request))
- form = ConferenceForm(request.POST or None, instance=conference)
- if request.method == 'POST' and form.is_valid():
- form.save()
- messages.success(request, 'Conference updated!')
- return redirect(reverse('edit-conference'))
- return render(request, 'proposals/conference.html', {
- 'form': form,
- })
-
-@login_required
-def participate(request):
- site = get_current_site(request)
- talks = Talk.objects.filter(site=site)
- my_talks = talks.filter(speakers=request.user)
- proposed_talks = talks.exclude(speakers=request.user).filter(proposer=request.user)
- return render(request, 'proposals/participate.html', {
- 'my_talks': my_talks,
- 'proposed_talks': proposed_talks,
- })
-
-@staff_required
-def talk_list(request):
- show_filters = False
- talks = Talk.objects.filter(site=get_current_site(request))
- filter_form = TalkFilterForm(request.GET or None, site=get_current_site(request))
- # Filtering
- if filter_form.is_valid():
- data = filter_form.cleaned_data
- if len(data['kind']):
- show_filters = True
- talks = talks.filter(reduce(lambda x, y: x | y, [Q(event__pk=pk) for pk in data['kind']]))
- if len(data['status']):
- show_filters = True
- talks = talks.filter(reduce(lambda x, y: x | y, [Q(accepted=dict(STATUS_VALUES)[status]) for status in data['status']]))
- if len(data['topic']):
- show_filters = True
- talks = talks.filter(reduce(lambda x, y: x | y, [Q(topics__slug=topic) for topic in data['topic']]))
- if len(data['track']):
- show_filters = True
- q = Q()
- if 'none' in data['track']:
- data['track'].remove('none')
- q |= Q(track__isnull=True)
- if len(data['track']):
- q |= Q(track__slug__in=data['track'])
- talks = talks.filter(q)
- if data['vote'] != None:
- show_filters = True
- if data['vote']:
- talks = talks.filter(vote__user=request.user)
- else:
- talks = talks.exclude(vote__user=request.user)
- if data['room'] != None:
- show_filters = True
- talks = talks.filter(room__isnull=not data['room'])
- if data['scheduled'] != None:
- show_filters = True
- talks = talks.filter(start_date__isnull=not data['scheduled'])
- if data['materials'] != None:
- show_filters = True
- talks = talks.filter(materials__isnull=not data['materials'])
- if data['video'] != None:
- show_filters = True
- if data['video']:
- talks = talks.exclude(video__exact='')
- else:
- talks = talks.filter(video__exact='')
- # Action
- action_form = TalkActionForm(request.POST or None, talks=talks, site=get_current_site(request))
- if not is_orga(request, request.user):
- action_form.fields.pop('track')
- action_form.fields.pop('room')
- if request.method == 'POST':
- if action_form.is_valid():
- data = action_form.cleaned_data
- permission_error = False
- for talk in data['talks']:
- talk = Talk.objects.get(site=get_current_site(request), slug=talk)
- if data['decision'] != None:
- if not talk.is_moderable_by(request.user):
- permission_error = True
- continue
- # TODO: merge with talk_decide code
- conversation = ConversationAboutTalk.objects.get(talk=talk)
- if data['decision']:
- note = "The talk has been accepted."
- else:
- note = "The talk has been declined."
- Message.objects.create(conversation=conversation, author=request.user, content=note)
- talk.accepted = data['decision']
- if data['track']:
- talk.track = Track.objects.get(site=get_current_site(request), slug=data['track'])
- if data['room']:
- talk.room = Room.objects.get(site=get_current_site(request), slug=data['room'])
- talk.save()
- if permission_error:
- messages.warning(request, 'Some actions were ignored due to missing permissions.')
- return redirect(request.get_full_path())
- # Sorting
- if request.GET.get('order') == 'desc':
- reverse = True
- else:
- reverse = False
- SORT_MAPPING = {
- 'title': 'title',
- 'kind': 'event',
- 'status': 'accepted',
- }
- sort = request.GET.get('sort')
- if sort in SORT_MAPPING.keys():
- if reverse:
- talks = talks.order_by('-' + SORT_MAPPING[sort])
- else:
- talks = talks.order_by(SORT_MAPPING[sort])
- # Sorting URLs
- sort_urls = dict()
- sort_glyphicons = dict()
- for c in SORT_MAPPING.keys():
- url = request.GET.copy()
- url['sort'] = c
- if c == sort:
- if reverse:
- del url['order']
- glyphicon = 'sort-by-attributes-alt'
- else:
- url['order'] = 'desc'
- glyphicon = 'sort-by-attributes'
- else:
- glyphicon = 'sort'
- sort_urls[c] = url.urlencode()
- sort_glyphicons[c] = glyphicon
- return render(request, 'proposals/talk_list.html', {
- 'show_filters': show_filters,
- 'talk_list': talks,
- 'filter_form': filter_form,
- 'action_form': action_form,
- 'sort_urls': sort_urls,
- 'sort_glyphicons': sort_glyphicons,
- })
-
-@login_required
-def talk_edit(request, talk=None):
- site = get_current_site(request)
- if talk: # edit existing talk
- talk = get_object_or_404(Talk, slug=talk, site=site)
- if not talk.is_editable_by(request.user):
- raise PermissionDenied
- else: # add new talk
- conf = Conference.objects.get(site=site)
- if not is_orga(request, request.user) and not conf.cfp_is_open():
- raise PermissionDenied
- staff = talk.is_moderable_by(request.user) if talk else is_orga(request, request.user)
- form = TalkForm(request.POST or None, request.FILES or None, instance=talk, site=site, staff=staff)
- if talk:
- form.fields['topics'].disabled = True
- if 'duration' in form.fields and talk.event.duration:
- form.fields['duration'].help_text = 'Default value if zero: %d min' % talk.duration
- if 'attendees_limit' in form.fields and talk.is_editable_by(request.user) and talk.room and talk.room.capacity:
- form.fields['attendees_limit'].help_text=ungettext_lazy(
- "Note: the room %(room)s has %(capacity)s seat.",
- "Note: the room %(room)s has %(capacity)s seats.",
- talk.room.capacity) % {'room': talk.room.name, 'capacity': talk.room.capacity}
- else:
- form.fields.pop('materials')
- form.fields.pop('video')
- form.fields['speakers'].initial = [request.user]
- if request.method == 'POST' and form.is_valid():
- if hasattr(talk, 'id'):
- talk = form.save()
- if request.user == talk.proposer or request.user in talk.speakers.all():
- talk_edited.send(talk.__class__, instance=talk, author=request.user)
- messages.success(request, _('Talk modified successfully!'))
- else:
- form.instance.site = get_current_site(request)
- form.instance.proposer = request.user
- talk = form.save()
- talk_added.send(talk.__class__, instance=talk, author=request.user)
- messages.success(request, _('Talk proposed successfully!'))
- return redirect(talk.get_absolute_url())
- return render(request, 'proposals/talk_edit.html', {
- 'base_template': 'staff.html' if staff else 'base.html',
- 'talk': talk,
- 'form': form,
- })
-
-
-@login_required
-def talk_assign_to_track(request, talk, track):
- talk = get_object_or_404(Talk, slug=talk, site=get_current_site(request))
- if not talk.is_moderable_by(request.user):
- raise PermissionDenied
- track = get_object_or_404(Track, slug=track, site=get_current_site(request))
- talk.track = track
- talk.save()
- messages.success(request, _('Talk assigned to track successfully!'))
- next_url = request.GET.get('next') or reverse('show-talk', kwargs={'slug': talk.slug})
- return redirect(next_url)
-
-
-class TalkDetail(LoginRequiredMixin, DetailView):
- def get_queryset(self):
- return Talk.objects.filter(site=get_current_site(self.request)).all()
-
- def get_context_data(self, **ctx):
- if self.object.is_moderable_by(self.request.user):
- vote = Vote.objects.filter(talk=self.object, user=self.request.user).first()
- ctx.update(edit_perm=True, moderate_perm=True, vote=vote,
- form_url=reverse('talk-conversation', kwargs={'talk': self.object.slug}))
- else:
- ctx['edit_perm'] = self.object.is_editable_by(self.request.user)
- if is_staff(self.request, self.request.user):
- ctx.update(base_template='staff.html')
- else:
- ctx.update(base_template='base.html')
- return super().get_context_data(**ctx)
-
-
-class TopicMixin(object):
- def get_queryset(self):
- return Topic.objects.filter(site=get_current_site(self.request)).all()
-
-
-class TopicFormMixin(OnSiteFormMixin):
- form_class = TopicForm
-
-
-class TopicList(LoginRequiredMixin, TopicMixin, ListView):
- pass
-
-
-class TopicCreate(OrgaRequiredMixin, TopicMixin, TopicFormMixin, CreateView):
- model = Topic
-
-
-class TopicUpdate(OrgaRequiredMixin, TopicMixin, TopicFormMixin, UpdateView):
- pass
-
-
-class TrackFormMixin(OnSiteFormMixin):
- form_class = TrackForm
-
-
-class TrackMixin(object):
- def get_queryset(self):
- return Track.objects.filter(site=get_current_site(self.request)).all()
-
-
-class TrackList(LoginRequiredMixin, TrackMixin, ListView):
- pass
-
-
-class TrackCreate(OrgaRequiredMixin, TrackMixin, TrackFormMixin, CreateView):
- model = Track
-
-
-class TrackUpdate(OrgaRequiredMixin, TrackMixin, TrackFormMixin, UpdateView):
- pass
-
-
-@login_required
-def vote(request, talk, score):
- talk = get_object_or_404(Talk, site=get_current_site(request), slug=talk)
- if not talk.is_moderable_by(request.user):
- raise PermissionDenied
- vote, created = Vote.objects.get_or_create(talk=talk, user=request.user)
- vote.vote = int(score)
- vote.save()
- messages.success(request, _('Vote successfully created') if created else _('Vote successfully updated'))
- return redirect(talk.get_absolute_url())
-
-
-@login_required
-def talk_decide(request, talk, accepted):
- site = get_current_site(request)
- talk = get_object_or_404(Talk, site=site, slug=talk)
- if not talk.is_moderable_by(request.user):
- raise PermissionDenied
- if request.method == 'POST':
- # Does we need to send a notification to the proposer?
- m = request.POST.get('message', '').strip()
- if m:
- participation = Participation.objects.get(site=site, user=talk.proposer)
- conversation = ConversationWithParticipant.objects.get(participation=participation)
- Message.objects.create(conversation=conversation, author=request.user, content=m)
- # Save the decision in the talk's conversation
- conversation = ConversationAboutTalk.objects.get(talk=talk)
- if accepted:
- note = "The talk has been accepted."
- else:
- note = "The talk has been declined."
- Message.objects.create(conversation=conversation, author=request.user, content=note)
- talk.accepted = accepted
- talk.save()
- messages.success(request, _('Decision taken in account'))
- return redirect('show-talk', slug=talk.slug)
- return render(request, 'proposals/talk_decide.html', {
- 'talk': talk,
- 'accept': accepted,
- })
-
-
-@staff_required
-def speaker_list(request):
- show_filters = False
- site = get_current_site(request)
- filter_form = SpeakerFilterForm(request.GET or None, site=site)
- talks = Talk.objects.filter(site=site)
- # Filtering
- if filter_form.is_valid():
- data = filter_form.cleaned_data
- if len(data['status']):
- show_filters = True
- talks = talks.filter(reduce(lambda x, y: x | y, [Q(accepted=dict(STATUS_VALUES)[status]) for status in data['status']]))
- if len(data['topic']):
- show_filters = True
- talks = talks.filter(reduce(lambda x, y: x | y, [Q(topics__slug=topic) for topic in data['topic']]))
- if len(data['track']):
- show_filters = True
- q = Q()
- if 'none' in data['track']:
- data['track'].remove('none')
- q |= Q(track__isnull=True)
- if len(data['track']):
- q |= Q(track__slug__in=data['track'])
- talks = talks.filter(q)
- speakers = Participation.objects.filter(site=site,user__talk__in=talks).order_by('pk').distinct()
- if filter_form.is_valid():
- data = filter_form.cleaned_data
- if len(data['transport']):
- show_filters = True
- q = Q()
- if 'unanswered' in data['transport']:
- data['transport'].remove('unanswered')
- q |= Q(need_transport=None)
- if 'unspecified' in data['transport']:
- data['transport'].remove('unspecified')
- speakers = speakers.annotate(transport_count=Count('transport'))
- q |= Q(need_transport=True, transport_count=0)
- if len(data['transport']):
- q |= (Q(need_transport=True) & Q(reduce(lambda x, y: x | y, [Q(transport__pk=pk) for pk in data['transport']])))
- speakers = speakers.filter(q)
- if len(data['accommodation']):
- show_filters = True
- accommodations = list(map(lambda x: None if x == 'unknown' else x, data['accommodation']))
- speakers = speakers.filter(reduce(lambda x, y: x | y, [Q(accommodation=value) for value in accommodations]))
- if data['sound'] != None:
- show_filters = True
- speakers = speakers.filter(sound=data['sound'])
- if data['transport_booked'] != None:
- show_filters = True
- speakers = speakers.filter(need_transport=True).filter(transport_booked=data['transport_booked'])
- if data['accommodation_booked'] != None:
- show_filters = True
- speakers = speakers.exclude(accommodation=Participation.ACCOMMODATION_NO).filter(accommodation_booked=data['accommodation_booked'])
- contact_link = 'mailto:' + ','.join([speaker.user.email for speaker in speakers.all() if speaker.user.email])
- return render(request, 'proposals/speaker_list.html', {
- 'speaker_list': speakers,
- 'filter_form': filter_form,
- 'show_filters': show_filters,
- 'contact_link': contact_link,
- })
-
-
-def talk_registrable_list(request):
- site = get_current_site(request)
- if not Conference.objects.get(site=site).subscriptions_open:
- raise Http404
- talks = Talk.objects.filter(site=site, registration_required=True)
- if request.user.is_authenticated():
- attendee = Attendee.objects.filter(user=request.user).first() # None if it does not exists
- else:
- attendee = None
- return render(request, 'proposals/talk_registrable_list.html', {
- 'talks': talks,
- 'attendee': attendee,
- })
-
-
-def talk_register(request, talk):
- talk = get_object_or_404(Talk, site=get_current_site(request), registration_required=True, slug=talk)
-
- form = SubscribeForm(request.POST or None)
-
- if request.user.is_authenticated() or (request.method == 'POST' and form.is_valid()):
- if request.user.is_authenticated():
- attendee, created = Attendee.objects.get_or_create(user=request.user)
- else:
- attendee, created = Attendee.objects.get_or_create(email=form.cleaned_data['email'], name=form.cleaned_data['name'])
- if attendee in talk.attendees.all():
- if request.user.is_authenticated():
- talk.attendees.remove(attendee)
- messages.success(request, _("Unregistered :-("))
- else:
- messages.error(request, _("Already registered!"))
- elif talk.remaining_attendees == 0:
- raise PermissionDenied
- else:
- talk.attendees.add(attendee)
- messages.success(request, _("Registered!"))
- talk.save()
- return redirect('list-registrable-talks')
-
- return render(request, 'proposals/talk_register.html', {
- 'talk': talk,
- 'form': form,
- })