start work on speaker and talk submissions
This commit is contained in:
parent
5f9f9bb1d4
commit
334f0477fe
|
@ -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(),
|
||||||
|
|
23
src/program/migrations/0026_speaker_user.py
Normal file
23
src/program/migrations/0026_speaker_user.py
Normal 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),
|
||||||
|
),
|
||||||
|
]
|
22
src/program/migrations/0027_auto_20170307_1701.py
Normal file
22
src/program/migrations/0027_auto_20170307_1701.py
Normal 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')]),
|
||||||
|
),
|
||||||
|
]
|
25
src/program/migrations/0028_auto_20170307_2014.py
Normal file
25
src/program/migrations/0028_auto_20170307_2014.py
Normal 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),
|
||||||
|
),
|
||||||
|
]
|
25
src/program/migrations/0029_auto_20170307_2042.py
Normal file
25
src/program/migrations/0029_auto_20170307_2042.py
Normal 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),
|
||||||
|
),
|
||||||
|
]
|
|
@ -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})
|
||||||
|
|
||||||
|
|
||||||
|
|
14
src/program/templates/speaker_form.html
Normal file
14
src/program/templates/speaker_form.html
Normal 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 %}
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue