symposion_app/symposion/schedule/forms.py

163 lines
5.9 KiB
Python
Raw Normal View History

from __future__ import unicode_literals
import csv
import time
2014-02-28 15:55:54 +00:00
from datetime import datetime
2012-08-31 03:24:08 +00:00
from django import forms
from django.contrib import messages
2014-02-28 15:55:54 +00:00
from django.db import IntegrityError, transaction
from django.db.models import Q
2012-08-31 03:24:08 +00:00
from markitup.widgets import MarkItUpWidget
2014-02-28 15:55:54 +00:00
from symposion.schedule.models import (Day, Presentation, Room, SlotKind, Slot,
SlotRoom)
2012-08-31 03:24:08 +00:00
class SlotEditForm(forms.Form):
2014-07-30 18:19:26 +00:00
def __init__(self, *args, **kwargs):
2012-10-26 21:32:03 +00:00
self.slot = kwargs.pop("slot")
super(SlotEditForm, self).__init__(*args, **kwargs)
# @@@ TODO - Make this configurable
if self.slot.kind.label in ["talk", "tutorial", "keynote"]:
2012-10-26 21:32:03 +00:00
self.fields["presentation"] = self.build_presentation_field()
else:
self.fields["content_override"] = self.build_content_override_field()
2014-07-30 18:19:26 +00:00
2012-10-26 21:32:03 +00:00
def build_presentation_field(self):
kwargs = {}
queryset = Presentation.objects.all()
queryset = queryset.exclude(cancelled=True)
queryset = queryset.order_by("proposal_base__pk")
if self.slot.content:
queryset = queryset.filter(Q(slot=None) | Q(pk=self.slot.content.pk))
kwargs["required"] = False
kwargs["initial"] = self.slot.content
else:
queryset = queryset.filter(slot=None)
2012-10-26 21:32:03 +00:00
kwargs["required"] = True
kwargs["queryset"] = queryset
return forms.ModelChoiceField(**kwargs)
2014-07-30 18:19:26 +00:00
2012-10-26 21:32:03 +00:00
def build_content_override_field(self):
kwargs = {
"label": "Content",
"widget": MarkItUpWidget(),
2012-10-26 21:32:03 +00:00
"required": False,
"initial": self.slot.content_override,
}
return forms.CharField(**kwargs)
2014-03-03 18:47:46 +00:00
class ScheduleSectionForm(forms.Form):
ROOM_KEY = 'room'
DATE_KEY = 'date'
START_KEY = 'time_start'
END_KEY = 'time_end'
KIND = 'kind'
filename = forms.FileField(
label='Select a CSV file to import:',
required=False
)
def __init__(self, *args, **kwargs):
self.schedule = kwargs.pop("schedule")
super(ScheduleSectionForm, self).__init__(*args, **kwargs)
def clean_filename(self):
if 'submit' in self.data:
fname = self.cleaned_data.get('filename')
if not fname or not fname.name.endswith('.csv'):
raise forms.ValidationError(u'Please upload a .csv file')
return fname
def _get_start_end_times(self, data):
"Return start and end time objects"
times = []
for x in [data[self.START_KEY], data[self.END_KEY]]:
try:
time_obj = time.strptime(x, '%I:%M %p')
except:
return messages.ERROR, u'Malformed time found: %s.' % x
time_obj = datetime(100, 1, 1, time_obj.tm_hour, time_obj.tm_min, 00)
times.append(time_obj.time())
return times
def _build_rooms(self, data):
"Get or Create Rooms based on schedule type and set of Tracks"
created_rooms = []
rooms = sorted(set([x[self.ROOM_KEY] for x in data]))
for i, room in enumerate(rooms):
room, created = Room.objects.get_or_create(
schedule=self.schedule, name=room, order=i
)
if created:
created_rooms.append(room)
return created_rooms
def _build_days(self, data):
"Get or Create Days based on schedule type and set of Days"
created_days = []
days = set([x[self.DATE_KEY] for x in data])
for day in days:
try:
date = datetime.strptime(day, "%m/%d/%Y")
except ValueError:
[x.delete() for x in created_days]
return messages.ERROR, u'Malformed data found: %s.' % day
day, created = Day.objects.get_or_create(
schedule=self.schedule, date=date
)
if created:
created_days.append(day)
return created_days
def build_schedule(self):
created_items = []
reader = csv.DictReader(self.cleaned_data.get('filename'))
data = [dict((k.strip(), v.strip()) for k, v in x.items()) for x in reader]
# build rooms
created_items.extend(self._build_rooms(data))
# build_days
created_items.extend(self._build_days(data))
# build Slot -> SlotRoom
for row in data:
room = Room.objects.get(
schedule=self.schedule, name=row[self.ROOM_KEY]
)
date = datetime.strptime(row[self.DATE_KEY], "%m/%d/%Y")
day = Day.objects.get(schedule=self.schedule, date=date)
start, end = self._get_start_end_times(row)
slot_kind, created = SlotKind.objects.get_or_create(
label=row[self.KIND], schedule=self.schedule
)
if created:
created_items.append(slot_kind)
if row[self.KIND] == 'plenary':
slot, created = Slot.objects.get_or_create(
kind=slot_kind, day=day, start=start, end=end
)
if created:
created_items.append(slot)
else:
slot = Slot.objects.create(
kind=slot_kind, day=day, start=start, end=end
)
created_items.append(slot)
try:
2014-03-03 18:47:46 +00:00
with transaction.atomic():
SlotRoom.objects.create(slot=slot, room=room)
2014-03-03 18:47:46 +00:00
except IntegrityError:
# delete all created objects and report error
for x in created_items:
x.delete()
return messages.ERROR, u'An overlap occurred; the import was cancelled.'
return messages.SUCCESS, u'Your schedule has been imported.'
def delete_schedule(self):
self.schedule.day_set.all().delete()
return messages.SUCCESS, u'Your schedule has been deleted.'