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,9 +1,17 @@
import csv
import time
from datetime import datetime
from django import forms from django import forms
from django.contrib import messages
from django.db import IntegrityError, transaction
from django.db.models import Q from django.db.models import Q
from markitup.widgets import MarkItUpWidget 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): class SlotEditForm(forms.Form):
@ -40,3 +48,106 @@ class SlotEditForm(forms.Form):
"initial": self.slot.content_override, "initial": self.slot.content_override,
} }
return forms.CharField(**kwargs) 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.template import loader, Context
from django.contrib.auth.decorators import login_required 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.models import Schedule, Day, Slot, Presentation
from symposion.schedule.timetable import TimeTable from symposion.schedule.timetable import TimeTable
@ -100,11 +101,24 @@ def schedule_edit(request, slug=None):
schedule = fetch_schedule(slug) 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_qs = Day.objects.filter(schedule=schedule)
days = [TimeTable(day) for day in days_qs] days = [TimeTable(day) for day in days_qs]
ctx = { ctx = {
"schedule": schedule, "schedule": schedule,
"days": days, "days": days,
"form": form
} }
return render(request, "schedule/schedule_edit.html", ctx) return render(request, "schedule/schedule_edit.html", ctx)

View file

@ -24,7 +24,13 @@
{% include "schedule/_edit_grid.html" %} {% include "schedule/_edit_grid.html" %}
{% endfor %} {% endfor %}
</div> </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 class="modal fade hide in" id="slotEditModal"></div>
</div> </div>
{% endblock %} {% endblock %}
@ -41,5 +47,19 @@
e.preventDefault(); 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> </script>
{% endblock %} {% endblock %}