diff --git a/accounts/migrations/0009_auto_20160921_2236.py b/accounts/migrations/0009_auto_20160921_2236.py new file mode 100644 index 0000000..372dbf4 --- /dev/null +++ b/accounts/migrations/0009_auto_20160921_2236.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10 on 2016-09-21 22:36 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0008_auto_20160808_2251'), + ] + + operations = [ + migrations.AlterField( + model_name='participation', + name='video_licence', + field=models.IntegerField(choices=[(1, 'CC-Zero'), (2, 'CC-BY'), (3, 'CC-BY-SA'), (4, 'CC-BY-ND'), (5, 'CC-BY-NC'), (6, 'CC-BY-NC-SA'), (7, 'CC-BY-NC-ND')], default=2, verbose_name='Video licence'), + ), + ] diff --git a/proposals/admin.py b/proposals/admin.py index 88883a2..a6eb6c6 100644 --- a/proposals/admin.py +++ b/proposals/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from proposals.models import Conference, Talk, Topic, Event +from proposals.models import Conference, Talk, Topic, Track, Event class TalkAdmin(admin.ModelAdmin): @@ -14,10 +14,12 @@ class TalkAdmin(admin.ModelAdmin): # in fact, obj should never be none as 'add' button is disabled if obj: form.base_fields['topics'].queryset = Topic.objects.filter(site=obj.site) + form.base_fields['track'].queryset = Track.objects.filter(site=obj.site) form.base_fields['event'].queryset = Event.objects.filter(site=obj.site) return form admin.site.register(Conference) admin.site.register(Topic) +admin.site.register(Track) admin.site.register(Talk, TalkAdmin) admin.site.register(Event) diff --git a/proposals/forms.py b/proposals/forms.py index a918be2..dc49a6a 100644 --- a/proposals/forms.py +++ b/proposals/forms.py @@ -5,7 +5,7 @@ from django.utils.translation import ugettext_lazy as _ from django_select2.forms import Select2TagWidget -from proposals.models import Talk, Topic, Event, Conference +from proposals.models import Talk, Topic, Track, Event, Conference from accounts.models import Transport @@ -27,11 +27,12 @@ class TalkForm(forms.ModelForm): site = kwargs.pop('site') 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['event'].queryset = Event.objects.filter(site=site) class Meta: model = Talk - fields = ['title', 'abstract', 'description', 'topics', 'notes', 'event', 'speakers'] + fields = ['title', 'abstract', 'description', 'topics', 'track', 'notes', 'event', 'speakers'] widgets = {'topics': forms.CheckboxSelectMultiple(), 'speakers': Select2TagWidget()} help_texts = { 'abstract': _('Should be less than 255 characters'), @@ -55,7 +56,12 @@ class TalkFilterForm(forms.Form): widget=forms.CheckboxSelectMultiple, choices=[], ) - vote = forms.NullBooleanField(help_text='Filter topics you already / not yet voted for') + track = forms.MultipleChoiceField( + required=False, + widget=forms.CheckboxSelectMultiple, + choices=[], + ) + vote = forms.NullBooleanField(help_text=_('Filter topics you already / not yet voted for')) def __init__(self, *args, **kwargs): site = kwargs.pop('site') @@ -64,6 +70,8 @@ class TalkFilterForm(forms.Form): 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 SpeakerFilterForm(forms.Form): diff --git a/proposals/migrations/0011_auto_20160921_2236.py b/proposals/migrations/0011_auto_20160921_2236.py new file mode 100644 index 0000000..66b1b5b --- /dev/null +++ b/proposals/migrations/0011_auto_20160921_2236.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10 on 2016-09-21 22:36 +from __future__ import unicode_literals + +import autoslug.fields +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('sites', '0002_alter_domain_unique'), + ('proposals', '0010_auto_20160822_1010'), + ] + + operations = [ + 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')), + ('site', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sites.Site')), + ], + ), + migrations.AlterModelOptions( + name='event', + options={'ordering': ('pk',)}, + ), + migrations.AlterField( + model_name='talk', + name='event', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='proposals.Event', verbose_name='Intervention kind'), + ), + 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='track', + unique_together=set([('site', 'name')]), + ), + ] diff --git a/proposals/models.py b/proposals/models.py index ee11578..830b3c1 100644 --- a/proposals/models.py +++ b/proposals/models.py @@ -45,6 +45,21 @@ class Topic(PonyConfModel): return reverse('list-talks') + '?topic=%s' % self.slug +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')) + + class Meta: + unique_together = ('site', 'name') + + def __str__(self): + return self.name + + class Event(models.Model): site = models.ForeignKey(Site, on_delete=models.CASCADE) @@ -72,6 +87,7 @@ class Talk(PonyConfModel): 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')) + 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) diff --git a/proposals/templates/proposals/talk_detail.html b/proposals/templates/proposals/talk_detail.html index 0022ccb..b40db2c 100644 --- a/proposals/templates/proposals/talk_detail.html +++ b/proposals/templates/proposals/talk_detail.html @@ -46,10 +46,18 @@ {% if moderate_perm %} +

{% trans "Track:" %}

+ +

{% if talk.track %}{{ talk.track }}{% else %}{% trans "No assigned yet." %}{% endif %}

+ +{% endif %} +

{% trans "Notes:" %}

{% if talk.notes %}{{ talk.notes }}{% else %}{% trans "No notes." %}{% endif %}

+{% if moderate_perm %} +

{% trans "Moderation" %}

{% trans "Vote:" %}

diff --git a/proposals/templates/proposals/talk_list.html b/proposals/templates/proposals/talk_list.html index e729977..a311eb4 100644 --- a/proposals/templates/proposals/talk_list.html +++ b/proposals/templates/proposals/talk_list.html @@ -17,14 +17,15 @@
+ {% bootstrap_field filter_form.status layout="horizontal" %} + {% bootstrap_field filter_form.vote layout="horizontal" %} {% bootstrap_field filter_form.kind layout="horizontal" %}
- {% bootstrap_field filter_form.status layout="horizontal" %} - {% bootstrap_field filter_form.vote layout="horizontal" %} + {% bootstrap_field filter_form.topic layout="horizontal" %}
- {% bootstrap_field filter_form.topic layout="horizontal" %} + {% bootstrap_field filter_form.track layout="horizontal" %}
@@ -39,6 +40,7 @@ {% trans "Intervention kind" %} {% trans "Speakers" %} {% trans "Topics" %} + {% trans "Track" %} {% trans "Status" %} @@ -46,24 +48,25 @@ {% if forloop.first %} {% endif %} - - {{ talk.title }} - {{ talk.event }} - + + {{ talk.title }} + {{ talk.event }} + {% for speaker in talk.speakers.all %} {{ speaker }} {% if forloop.revcounter == 2 %} {% trans "and" %} {% elif not forloop.last %}, {% endif %} {% empty %}– {% endfor %} - + {% for topic in talk.topics.all %} {{ topic }} {% if forloop.revcounter == 2 %} {% trans "and" %} {% elif not forloop.last %}, {% endif %} {% empty %}– {% endfor %} - + {{ talk.track|default:"–" }} + {% if talk.accepted == True %} {% trans "Accepted" %} {% elif talk.accepted == False %} diff --git a/proposals/views.py b/proposals/views.py index 3423a07..8fb230c 100644 --- a/proposals/views.py +++ b/proposals/views.py @@ -17,6 +17,7 @@ from django.http import HttpResponse 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 from conversations.models import ConversationWithParticipant, ConversationAboutTalk, Message @@ -77,6 +78,25 @@ def talk_list(request): 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 + q1 = None + q2 = None + if 'none' in data['track']: + data['track'].remove('none') + q1 = Q(track__isnull=True) + if len(data['track']): + q2 = Q(track__slug__in=data['track']) + if q1 and q2: + q = q1 | q2 + elif q1: + q = q1 + elif q2: + q = q2 + else: + q = None + if q: + talks = talks.filter(q) if data['vote'] != None: if data['vote']: talks = talks.filter(vote__user=request.user) @@ -130,6 +150,8 @@ def talk_edit(request, talk=None): if not talk.is_editable_by(request.user): raise PermissionDenied() form = TalkForm(request.POST or None, instance=talk, site=get_current_site(request)) + if not is_staff(request, request.user): + form.fields.pop('track') if talk: form.fields['title'].disabled = True form.fields['topics'].disabled = True