diff --git a/symposion/schedule/admin.py b/symposion/schedule/admin.py index 04aee8aa..50f252c3 100644 --- a/symposion/schedule/admin.py +++ b/symposion/schedule/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from symposion.schedule.models import Schedule, Day, Room, SlotKind, Slot, SlotRoom, Presentation +from symposion.schedule.models import Schedule, Day, Room, SlotKind, Slot, SlotRoom, Presentation, Session, SessionRole admin.site.register(Schedule) @@ -15,4 +15,6 @@ admin.site.register( SlotRoom, list_display=("slot", "room") ) +admin.site.register(Session) +admin.site.register(SessionRole) admin.site.register(Presentation) diff --git a/symposion/schedule/models.py b/symposion/schedule/models.py index 14ea87e4..5be16eb8 100644 --- a/symposion/schedule/models.py +++ b/symposion/schedule/models.py @@ -1,6 +1,7 @@ import datetime from django.core.exceptions import ObjectDoesNotExist +from django.contrib.auth.models import User from django.db import models from markitup.fields import MarkupField @@ -180,3 +181,62 @@ class Presentation(models.Model): class Meta: ordering = ["slot"] + + +class Session(models.Model): + + day = models.ForeignKey(Day, related_name="sessions") + slots = models.ManyToManyField(Slot, related_name="sessions") + + def sorted_slots(self): + return self.slots.order_by("start") + + def start(self): + slots = self.sorted_slots() + if slots: + return list(slots)[0].start + else: + return None + + def end(self): + slots = self.sorted_slots() + if slots: + return list(slots)[-1].end + else: + return None + + def __unicode__(self): + start = self.start() + end = self.end() + if start and end: + return u"%s: %s - %s" % ( + self.day.date.strftime("%a"), + start.strftime("%X"), + end.strftime("%X") + ) + return u"" + + +class SessionRole(models.Model): + + SESSION_ROLE_CHAIR = 1 + SESSION_ROLE_RUNNER = 2 + + SESSION_ROLE_TYPES = [ + (SESSION_ROLE_CHAIR, "Session Chair"), + (SESSION_ROLE_RUNNER, "Session Runner"), + ] + + session = models.ForeignKey(Session) + user = models.ForeignKey(User) + role = models.IntegerField(choices=SESSION_ROLE_TYPES) + status = models.NullBooleanField() + + submitted = models.DateTimeField(default=datetime.datetime.now) + + class Meta: + unique_together = [("session", "user", "role")] + + def __unicode__(self): + return u"%s %s: %s" % (self.user, self.session, + self.SESSION_ROLE_TYPES[self.role - 1][1]) diff --git a/symposion/schedule/tests/test_views_session.py b/symposion/schedule/tests/test_views_session.py new file mode 100644 index 00000000..02c2f180 --- /dev/null +++ b/symposion/schedule/tests/test_views_session.py @@ -0,0 +1,58 @@ +from datetime import date + +from django.conf import settings +from django.contrib.auth.models import User +from django.core.urlresolvers import reverse +from django.test import TestCase + +from symposion.conference.models import Section, current_conference, Conference +from symposion.schedule.models import Day, Schedule, Session + + +class TestScheduleViews(TestCase): + username = "user@example.com" + first_name = "Sam" + last_name = "McGillicuddy" + + def setUp(self): + self.user = User.objects.create_user(self.username, + password="pass", + email=self.username) + self.user.first_name = self.first_name + self.user.last_name = self.last_name + self.user.save() + + def test_session_list(self): + # Really minimal test for session list + rsp = self.client.get(reverse("schedule_session_list")) + self.assertEqual(200, rsp.status_code) + + def test_session_staff_email(self): + # login and staff required + self.user.is_staff = True + self.user.save() + assert self.client.login(username=self.username, password="pass") + + url = reverse("schedule_session_staff_email") + rsp = self.client.get(url) + self.assertEqual(200, rsp.status_code) + + def test_session_detail(self): + # really minimal test + Conference.objects.get_or_create(id=settings.CONFERENCE_ID) + section = Section.objects.create( + conference=current_conference(), + ) + schedule = Schedule.objects.create( + section=section, + ) + day = Day.objects.create( + schedule=schedule, + date=date.today(), + ) + session = Session.objects.create( + day=day, + ) + url = reverse("schedule_session_detail", args=(session.pk,)) + rsp = self.client.get(url) + self.assertEqual(200, rsp.status_code) diff --git a/symposion/schedule/urls.py b/symposion/schedule/urls.py index 74064ba8..b0e07189 100644 --- a/symposion/schedule/urls.py +++ b/symposion/schedule/urls.py @@ -17,4 +17,7 @@ urlpatterns = patterns( url(r"^([\w\-]+)/edit/slot/(\d+)/", "schedule_slot_edit", name="schedule_slot_edit"), url(r"^conference.json", "schedule_json", name="schedule_json"), + url(r"^sessions/staff.txt$", "session_staff_email", name="schedule_session_staff_email"), + url(r"^sessions/$", "session_list", name="schedule_session_list"), + url(r"^session/(\d+)/$", "session_detail", name="schedule_session_detail"), ) diff --git a/symposion/schedule/views.py b/symposion/schedule/views.py index b82505d1..1307e5e5 100644 --- a/symposion/schedule/views.py +++ b/symposion/schedule/views.py @@ -6,11 +6,12 @@ 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.auth.models import User from django.contrib import messages from django.contrib.sites.models import Site 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, Session, SessionRole from symposion.schedule.timetable import TimeTable @@ -231,3 +232,83 @@ def schedule_json(request): json.dumps({'schedule': data}), content_type="application/json" ) + + +def session_list(request): + sessions = Session.objects.all().order_by('pk') + + return render(request, "schedule/session_list.html", { + "sessions": sessions, + }) + + +@login_required +def session_staff_email(request): + + if not request.user.is_staff: + return redirect("schedule_session_list") + + data = "\n".join(user.email for user in User.objects.filter(sessionrole__isnull=False).distinct()) + + return HttpResponse(data, content_type="text/plain;charset=UTF-8") + + +def session_detail(request, session_id): + + session = get_object_or_404(Session, id=session_id) + + chair = None + chair_denied = False + chairs = SessionRole.objects.filter(session=session, role=SessionRole.SESSION_ROLE_CHAIR).exclude(status=False) + if chairs: + chair = chairs[0].user + else: + if request.user.is_authenticated(): + # did the current user previously try to apply and got rejected? + if SessionRole.objects.filter(session=session, user=request.user, role=SessionRole.SESSION_ROLE_CHAIR, status=False): + chair_denied = True + + runner = None + runner_denied = False + runners = SessionRole.objects.filter(session=session, role=SessionRole.SESSION_ROLE_RUNNER).exclude(status=False) + if runners: + runner = runners[0].user + else: + if request.user.is_authenticated(): + # did the current user previously try to apply and got rejected? + if SessionRole.objects.filter(session=session, user=request.user, role=SessionRole.SESSION_ROLE_RUNNER, status=False): + runner_denied = True + + if request.method == "POST" and request.user.is_authenticated(): + if not hasattr(request.user, "profile") or not request.user.profile.is_complete: + response = redirect("profile_edit") + response["Location"] += "?next=%s" % request.path + return response + + role = request.POST.get("role") + if role == "chair": + if chair is None and not chair_denied: + SessionRole(session=session, role=SessionRole.SESSION_ROLE_CHAIR, user=request.user).save() + elif role == "runner": + if runner is None and not runner_denied: + SessionRole(session=session, role=SessionRole.SESSION_ROLE_RUNNER, user=request.user).save() + elif role == "un-chair": + if chair == request.user: + session_role = SessionRole.objects.filter(session=session, role=SessionRole.SESSION_ROLE_CHAIR, user=request.user) + if session_role: + session_role[0].delete() + elif role == "un-runner": + if runner == request.user: + session_role = SessionRole.objects.filter(session=session, role=SessionRole.SESSION_ROLE_RUNNER, user=request.user) + if session_role: + session_role[0].delete() + + return redirect("schedule_session_detail", session_id) + + return render(request, "schedule/session_detail.html", { + "session": session, + "chair": chair, + "chair_denied": chair_denied, + "runner": runner, + "runner_denied": runner_denied, + })