Files
@ a4c4e6953c3d
Branch filter:
Location: symposion_app/symposion/schedule/forms.py - annotation
a4c4e6953c3d
5.9 KiB
text/x-python
Merge pull request #63 from codersquid/flake8scheduleform
flake8 fixes for the schedule edit form.
flake8 fixes for the schedule edit form.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | ee1f4d92a531 ee1f4d92a531 ee1f4d92a531 ee1f4d92a531 6d2cc584cfae ee1f4d92a531 ee1f4d92a531 7c102aefa3a5 6d2cc584cfae c09f887e7245 c09f887e7245 ee1f4d92a531 6d2cc584cfae 6d2cc584cfae 6d2cc584cfae 36ab6d599ffc 7c102aefa3a5 19d826ad00de 7c102aefa3a5 c582b2b3e23e c582b2b3e23e 19d826ad00de 19d826ad00de 19d826ad00de 36ab6d599ffc 19d826ad00de 19d826ad00de 19d826ad00de 19d826ad00de 19d826ad00de 19d826ad00de 19d826ad00de 19d826ad00de 19d826ad00de 7c102aefa3a5 7c102aefa3a5 19d826ad00de 19d826ad00de 19d826ad00de 36ab6d599ffc 19d826ad00de 19d826ad00de 19d826ad00de c09f887e7245 19d826ad00de 19d826ad00de 19d826ad00de 19d826ad00de 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 ee1f4d92a531 ee1f4d92a531 ee1f4d92a531 ee1f4d92a531 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 650ddd2bcc36 | import csv
import time
from datetime import datetime
from django import forms
from django.contrib import messages
from django.db import IntegrityError
from django.db.models import Q
from markitup.widgets import MarkItUpWidget
from symposion.schedule.models import (Day, Presentation, Room, SlotKind, Slot, SlotRoom)
class SlotEditForm(forms.Form):
def __init__(self, *args, **kwargs):
self.slot = kwargs.pop("slot")
super(SlotEditForm, self).__init__(*args, **kwargs)
# @@@ TODO - Make this configurable
if self.slot.kind.label in ["talk", "tutorial", "keynote"]:
self.fields["presentation"] = self.build_presentation_field()
else:
self.fields["content_override"] = self.build_content_override_field()
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)
kwargs["required"] = True
kwargs["queryset"] = queryset
return forms.ModelChoiceField(**kwargs)
def build_content_override_field(self):
kwargs = {
"label": "Content",
"widget": MarkItUpWidget(),
"required": False,
"initial": self.slot.content_override,
}
return forms.CharField(**kwargs)
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:
# @@@ TODO - upgrade Django, use atomic transactions
# with transaction.atomic():
# SlotRoom.objects.create(slot=slot, room=room)
SlotRoom.objects.create(slot=slot, room=room)
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.'
|