start work on speaker and talk submissions

This commit is contained in:
Thomas Steen Rasmussen 2017-03-08 00:00:17 +01:00
parent 5f9f9bb1d4
commit 334f0477fe
9 changed files with 236 additions and 7 deletions

View file

@ -135,6 +135,16 @@ urlpatterns = [
SpeakerListView.as_view(), SpeakerListView.as_view(),
name='speaker_index' name='speaker_index'
), ),
url(
r'^speakers/create/$',
SpeakerCreateView.as_view(),
name='speaker_create'
),
url(
r'^speakers/(?P<slug>[-_\w+]+)/edit/$',
SpeakerEditView.as_view(),
name='speaker_edit'
),
url( url(
r'^speakers/(?P<slug>[-_\w+]+)/$', r'^speakers/(?P<slug>[-_\w+]+)/$',
SpeakerDetailView.as_view(), SpeakerDetailView.as_view(),

View file

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-03-06 19:20
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('program', '0025_auto_20170306_1938'),
]
operations = [
migrations.AddField(
model_name='speaker',
name='user',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL),
),
]

View file

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-03-07 16:01
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('camps', '0019_auto_20170131_1849'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('program', '0026_speaker_user'),
]
operations = [
migrations.AlterUniqueTogether(
name='speaker',
unique_together=set([('camp', 'user'), ('camp', 'slug'), ('camp', 'name')]),
),
]

View file

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-03-07 19:14
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('program', '0027_auto_20170307_1701'),
]
operations = [
migrations.AddField(
model_name='event',
name='submission_status',
field=models.CharField(choices=[('pending', 'Pending approval'), ('approved', 'Approved'), ('rejected', 'Rejected')], default='pending', max_length=50),
),
migrations.AddField(
model_name='speaker',
name='submission_status',
field=models.CharField(choices=[('pending', 'Pending approval'), ('approved', 'Approved'), ('rejected', 'Rejected')], default='pending', max_length=50),
),
]

View file

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-03-07 19:42
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('program', '0028_auto_20170307_2014'),
]
operations = [
migrations.AlterField(
model_name='event',
name='submission_status',
field=models.CharField(choices=[('draft', 'Draft'), ('pending', 'Pending approval'), ('approved', 'Approved'), ('rejected', 'Rejected')], default='draft', max_length=50),
),
migrations.AlterField(
model_name='speaker',
name='submission_status',
field=models.CharField(choices=[('draft', 'Draft'), ('pending', 'Pending approval'), ('approved', 'Approved'), ('rejected', 'Rejected')], default='draft', max_length=50),
),
]

View file

@ -6,6 +6,37 @@ from django.utils.translation import ugettext_lazy as _
from utils.models import CreatedUpdatedModel from utils.models import CreatedUpdatedModel
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from datetime import timedelta from datetime import timedelta
from django.core.urlresolvers import reverse_lazy
class UserSubmittedModel(CreatedUpdatedModel):
class Meta:
abstract = True
SUBMISSION_DRAFT = 'draft'
SUBMISSION_PENDING = 'pending'
SUBMISSION_APPROVED = 'approved'
SUBMISSION_REJECTED = 'rejected'
SUBMISSION_STATUSES = [
SUBMISSION_DRAFT,
SUBMISSION_PENDING,
SUBMISSION_APPROVED,
SUBMISSION_REJECTED
]
SUBMISSION_STATUS_CHOICES = [
(SUBMISSION_DRAFT, 'Draft'),
(SUBMISSION_PENDING, 'Pending approval'),
(SUBMISSION_APPROVED, 'Approved'),
(SUBMISSION_REJECTED, 'Rejected'),
]
submission_status = models.CharField(
max_length=50,
choices=SUBMISSION_STATUS_CHOICES,
default=SUBMISSION_DRAFT,
)
class EventLocation(CreatedUpdatedModel): class EventLocation(CreatedUpdatedModel):
@ -34,7 +65,7 @@ class EventType(CreatedUpdatedModel):
return self.name return self.name
class Event(CreatedUpdatedModel): class Event(UserSubmittedModel):
""" Something that is on the program one or more times. """ """ Something that is on the program one or more times. """
title = models.CharField(max_length=255) title = models.CharField(max_length=255)
slug = models.SlugField(blank=True, max_length=255) slug = models.SlugField(blank=True, max_length=255)
@ -71,6 +102,9 @@ class Event(CreatedUpdatedModel):
return ", ".join(self.speakers.all().values_list('name', flat=True)) return ", ".join(self.speakers.all().values_list('name', flat=True))
return False return False
def get_absolute_url(self):
return reverse_lazy('event_detail', kwargs={'camp_slug': self.camp.slug, 'slug': self.slug})
class EventInstance(CreatedUpdatedModel): class EventInstance(CreatedUpdatedModel):
""" An instance of an event """ """ An instance of an event """
@ -123,7 +157,7 @@ def get_speaker_picture_upload_path(instance, filename):
} }
class Speaker(CreatedUpdatedModel): class Speaker(UserSubmittedModel):
""" A Person anchoring an event. """ """ A Person anchoring an event. """
name = models.CharField(max_length=150) name = models.CharField(max_length=150)
biography = models.TextField() biography = models.TextField()
@ -136,9 +170,16 @@ class Speaker(CreatedUpdatedModel):
blank=True, blank=True,
) )
user = models.ForeignKey(
'auth.User',
on_delete=models.PROTECT,
null=True,
blank=True
)
class Meta: class Meta:
ordering = ['name'] ordering = ['name']
unique_together = (('camp', 'name'), ('camp', 'slug')) unique_together = (('camp', 'name'), ('camp', 'slug'), ('camp', 'user'))
def __str__(self): def __str__(self):
return '%s (%s)' % (self.name, self.camp) return '%s (%s)' % (self.name, self.camp)
@ -148,4 +189,7 @@ class Speaker(CreatedUpdatedModel):
self.slug = slugify(self.name) self.slug = slugify(self.name)
super(Speaker, self).save(**kwargs) super(Speaker, self).save(**kwargs)
def get_absolute_url(self):
return reverse_lazy('speaker_detail', kwargs={'camp_slug': self.camp.slug, 'slug': self.slug})

View file

@ -0,0 +1,14 @@
{% extends 'program_base.html' %}
{% load bootstrap3 %}
{% block program_content %}
<h3>{% if object %}Update{% else %}Create{% endif %} speaker biography</h3>
<form method="POST">
{% csrf_token %}
{% bootstrap_form form %}
{% bootstrap_button "Save as draft" button_type="submit" button_class="btn-primary" %}
{% bootstrap_button "Save and submit" button_type="submit" button_class="btn-primary" %}
</form>
{% endblock program_content %}

View file

@ -1,6 +1,7 @@
from collections import OrderedDict from collections import OrderedDict
import datetime import datetime
from django.views.generic import ListView, TemplateView, DetailView from django.views.generic import ListView, TemplateView, DetailView
from django.views.generic.edit import CreateView, UpdateView
from camps.mixins import CampViewMixin from camps.mixins import CampViewMixin
from . import models from . import models
from django.http import Http404 from django.http import Http404
@ -11,6 +12,75 @@ from django.views.decorators.http import require_safe
from django.http import Http404 from django.http import Http404
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.http import HttpResponse from django.http import HttpResponse
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from django.shortcuts import redirect
from django.urls import reverse
class SpeakerCreateView(LoginRequiredMixin, CampViewMixin, CreateView):
model = models.Speaker
fields = ['name', 'biography', 'picture_small', 'picture_large']
template_name = 'speaker_form.html'
def get(self, request, *args, **kwargs):
# first make sure we don't already have a speaker for this user for this camp
try:
speaker = models.Speaker.objects.get(user=request.user, camp=self.camp)
except models.Speaker.DoesNotExist:
# no speaker exists, just show the create speaker form
return super(SpeakerCreateView, self).get(request, *args, **kwargs)
# speaker already exists, where do we want to redirect?
if speaker.submission_status == models.Speaker.SUBMISSION_DRAFT:
messages.info(request, "You already have a draft speaker profile for %s, you can modify and submit it here" % self.camp.title)
return redirect('speaker_edit', camp_slug=self.camp.slug, slug=speaker.slug)
elif speaker.submission_status == models.Speaker.SUBMISSION_PENDING:
messages.info(request, "You already have a pending speaker profile for %s, you can modify and resubmit it here" % self.camp.title)
return redirect('speaker_edit', camp_slug=self.camp.slug, slug=speaker.slug)
elif speaker.submission_status == models.Speaker.SUBMISSION_REJECTED:
messages.info(request, "You already have a rejected speaker profile for %s, you can modify and resubmit it here" % self.camp.title)
return redirect('speaker_edit', camp_slug=self.camp.slug, slug=speaker.slug)
elif speaker.submission_status == models.Speaker.SUBMISSION_APPROVED:
messages.info(request, "You already have an accepted speaker profile for %s, please contact the organisers if you want to modify it." % self.camp.title)
return redirect('speaker_detail', camp_slug=self.camp.slug, slug=speaker.slug)
else:
# unknown submission status!
return
def form_valid(self, form):
# set camp before saving
form.instance.camp = self.camp
form.instance.user = self.request.user
speaker = form.save()
return redirect(reverse('speaker_detail', kwargs={'camp_slug': speaker.camp.slug, 'slug': speaker.slug}))
class SpeakerEditView(LoginRequiredMixin, CampViewMixin, UpdateView):
model = models.Speaker
fields = ['name', 'biography', 'picture_small', 'picture_large']
template_name = 'speaker_form.html'
def dispatch(self, request, *args, **kwargs):
# call super dispatch now because it ets self.camp which is needed below
response = super(SpeakerEditView, self).dispatch(request, *args, **kwargs)
# first make sure that this speaker belongs to the logged in user
if self.get_object().user.username != request.user.username:
messages.error(request, "No thanks")
return redirect(reverse('speaker_detail', kwargs={'camp_slug': self.get_object().camp.slug, 'slug': self.get_object().slug}))
if self.get_object().submission_status == models.Speaker.SUBMISSION_PENDING:
messages.info(request, "Your speaker profile for %s has already been submitted. If you modify it you will have to resubmit it." % self.get_object().camp.title)
elif self.get_object().submission_status == models.Speaker.SUBMISSION_REJECTED:
messages.info(request, "When you are done editing you will have to resubmit your speaker profile." % self.get_object().camp.title)
elif self.get_object().submission_status == models.Speaker.SUBMISSION_APPROVED:
messages.error(request, "Your speaker profile for %s has already been approved. Please contact the organisers if you want to modify it." % self.get_object().camp.title)
return redirect(reverse('speaker_detail', kwargs={'camp_slug': self.get_object().camp.slug, 'slug': self.get_object().slug}))
# alright, render the form
return super(SpeakerEditView, self).dispatch(request, *args, **kwargs)
@method_decorator(require_safe, name='dispatch') @method_decorator(require_safe, name='dispatch')
class SpeakerPictureView(CampViewMixin, DetailView): class SpeakerPictureView(CampViewMixin, DetailView):

View file

@ -1,11 +1,7 @@
from django.core.urlresolvers import reverse_lazy from django.core.urlresolvers import reverse_lazy
from django.db import models from django.db import models
from django.utils.text import slugify from django.utils.text import slugify
from utils.models import CreatedUpdatedModel, UUIDModel from utils.models import CreatedUpdatedModel, UUIDModel
from .managers import VillageQuerySet from .managers import VillageQuerySet