work on #6, needs tests

This commit is contained in:
David Ray 2014-02-28 10:55:54 -05:00
parent 2f75033dc5
commit 4d1e9cf78e
3 changed files with 152 additions and 7 deletions

View file

@ -1,13 +1,21 @@
import csv
import time
from datetime import datetime
from django import forms
from django.contrib import messages
from django.db import IntegrityError, transaction
from django.db.models import Q
from markitup.widgets import MarkItUpWidget
from symposion.schedule.models import Presentation
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)
@ -16,7 +24,7 @@ class SlotEditForm(forms.Form):
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()
@ -31,7 +39,7 @@ class SlotEditForm(forms.Form):
kwargs["required"] = True
kwargs["queryset"] = queryset
return forms.ModelChoiceField(**kwargs)
def build_content_override_field(self):
kwargs = {
"label": "Content",
@ -40,3 +48,106 @@ class SlotEditForm(forms.Form):
"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"
start_time = time.strptime(data[self.START_KEY], '%I:%M %p')
start = datetime(100, 1, 1, start_time.tm_hour, start_time.tm_min, 00)
end_time = time.strptime(data[self.END_KEY], '%I:%M %p')
end = datetime(100, 1, 1, end_time.tm_hour, end_time.tm_min, 00)
return start.time(), end.time()
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:
date = datetime.strptime(day, "%m/%d/%Y")
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:
SlotRoom.objects.create(slot=slot, room=room)
except IntegrityError:
transaction.rollback()
# 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.'

View file

@ -3,8 +3,9 @@ from django.shortcuts import render, get_object_or_404, redirect
from django.template import loader, Context
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from symposion.schedule.forms import SlotEditForm
from symposion.schedule.forms import SlotEditForm, ScheduleSectionForm
from symposion.schedule.models import Schedule, Day, Slot, Presentation
from symposion.schedule.timetable import TimeTable
@ -100,11 +101,24 @@ def schedule_edit(request, slug=None):
schedule = fetch_schedule(slug)
if request.method == "POST":
form = ScheduleSectionForm(
request.POST, request.FILES, schedule=schedule
)
if form.is_valid():
if 'submit' in form.data:
msg = form.build_schedule()
elif 'delete' in form.data:
msg = form.delete_schedule()
messages.add_message(request, msg[0], msg[1])
else:
form = ScheduleSectionForm(schedule=schedule)
days_qs = Day.objects.filter(schedule=schedule)
days = [TimeTable(day) for day in days_qs]
ctx = {
"schedule": schedule,
"days": days,
"form": form
}
return render(request, "schedule/schedule_edit.html", ctx)

View file

@ -18,13 +18,19 @@
<div class="row">
<div class="span12">
<h1>Schedule Edit</h1>
{% for timetable in days %}
<h2>{{ timetable.day.date }}</h2>
{% include "schedule/_edit_grid.html" %}
{% endfor %}
</div>
{% if request.user.is_staff %}
<form id="schedule-builder" action="." method="post" enctype="multipart/form-data">{% csrf_token %}
{{ form.as_p }}
<input type="submit" name="submit" value="Submit" />
<input type="submit" id="delete" name="delete" value="Delete Schedule" />
</form>
{% endif %}
<div class="modal fade hide in" id="slotEditModal"></div>
</div>
{% endblock %}
@ -41,5 +47,19 @@
e.preventDefault();
});
});
$(function() {
//submit event handler
$("form#schedule-builder :submit").click(function(e) {
var name = this.name;
if(name == 'delete') {
if (!confirm("Are you sure you want to delete the schedule?"))
{
e.preventDefault();
return;
}
}
});
});
</script>
{% endblock %}