symposion_app/vendor/symposion/schedule/views.py
2019-01-16 13:55:05 +13:00

419 lines
14 KiB
Python

import json
import pytz
from django.core.urlresolvers import reverse
from django.http import Http404, HttpResponse
from django.shortcuts import render, get_object_or_404, redirect
from django.template import loader, Context
from django.conf import settings
from django.contrib.auth.models import User
from django.contrib import messages
from django.contrib.sites.models import Site
from django_ical.views import ICalFeed
from django.contrib.auth.decorators import login_required
from symposion.schedule.forms import SlotEditForm, ScheduleSectionForm
from symposion.schedule.models import Schedule, Day, Slot, Presentation, Session, SessionRole
from symposion.schedule.timetable import TimeTable
from symposion.conference.models import Conference
from pinaxcon.templatetags.lca2018_tags import speaker_photo
def fetch_schedule(slug):
qs = Schedule.objects.all()
if slug is None:
if qs.count() > 1:
raise Http404()
schedule = next(iter(qs), None)
if schedule is None:
raise Http404()
else:
schedule = get_object_or_404(qs, section__slug=slug)
return schedule
def schedule_conference(request):
if request.user.is_staff:
schedules = Schedule.objects.filter(hidden=False)
else:
schedules = Schedule.objects.filter(published=True, hidden=False)
sections = []
for schedule in schedules:
days_qs = Day.objects.filter(schedule=schedule)
days = [TimeTable(day) for day in days_qs]
sections.append({
"schedule": schedule,
"days": days,
})
day_switch = request.GET.get('day', None)
ctx = {
"sections": sections,
"day_switch": day_switch
}
return render(request, "symposion/schedule/schedule_conference.html", ctx)
def schedule_detail(request, slug=None):
schedule = fetch_schedule(slug)
if not schedule.published and not request.user.is_staff:
raise Http404()
days_qs = Day.objects.filter(schedule=schedule)
days = [TimeTable(day) for day in days_qs]
ctx = {
"schedule": schedule,
"days": days,
}
return render(request, "symposion/schedule/schedule_detail.html", ctx)
def schedule_list(request, slug=None):
schedule = fetch_schedule(slug)
if not schedule.published and not request.user.is_staff:
raise Http404()
presentations = Presentation.objects.filter(section=schedule.section)
presentations = presentations.exclude(cancelled=True)
if not request.user.is_staff:
presentations = presentations.exclude(unpublish=True)
ctx = {
"schedule": schedule,
"presentations": presentations,
}
return render(request, "symposion/schedule/schedule_list.html", ctx)
def schedule_list_csv(request, slug=None):
schedule = fetch_schedule(slug)
if not schedule.published and not request.user.is_staff:
raise Http404()
presentations = Presentation.objects.filter(section=schedule.section)
presentations = presentations.exclude(cancelled=True)
if not request.user.is_staff:
presentations = presentations.exclude(unpublish=True)
presentations = presentations.order_by("id")
response = HttpResponse(content_type="text/csv")
if slug:
file_slug = slug
else:
file_slug = "presentations"
response["Content-Disposition"] = 'attachment; filename="%s.csv"' % file_slug
response.write(loader.get_template("symposion/schedule/schedule_list.csv").render(Context({
"presentations": presentations,
})))
return response
@login_required
def schedule_edit(request, slug=None):
if not request.user.is_staff:
raise Http404()
schedule = fetch_schedule(slug)
if request.method == "POST":
form = ScheduleSectionForm(
request.POST, request.FILES, schedule=schedule, encoding=request.encoding
)
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, "symposion/schedule/schedule_edit.html", ctx)
@login_required
def schedule_slot_edit(request, slug, slot_pk):
if not request.user.is_staff:
raise Http404()
slot = get_object_or_404(Slot, day__schedule__section__slug=slug, pk=slot_pk)
if request.method == "POST":
form = SlotEditForm(request.POST, slot=slot)
if form.is_valid():
save = False
if "content_override" in form.cleaned_data:
slot.content_override = form.cleaned_data["content_override"]
save = True
if "presentation" in form.cleaned_data:
presentation = form.cleaned_data["presentation"]
if presentation is None:
slot.unassign()
else:
slot.assign(presentation)
if save:
slot.save()
return redirect("schedule_edit", slug)
else:
form = SlotEditForm(slot=slot)
ctx = {
"slug": slug,
"form": form,
"slot": slot,
}
return render(request, "symposion/schedule/_slot_edit.html", ctx)
def schedule_presentation_detail(request, pk):
presentation = get_object_or_404(Presentation, pk=pk)
if presentation.slot:
# 1) Schedule from presentation's slot
schedule = presentation.slot.day.schedule
else:
# 2) Fall back to the schedule for this proposal
schedule = presentation.proposal.kind.section.schedule
if not request.user.is_staff:
# 3) Is proposal unpublished?
if presentation.unpublish or not (schedule and schedule.published):
raise Http404()
ctx = {
"presentation": presentation,
"schedule": schedule,
}
return render(request, "symposion/schedule/presentation_detail.html", ctx)
def has_contact_perm(user):
return user.has_perm('symposion_speakers.can_view_contact_details') or user.is_staff
def make_speaker_dict(user, speaker):
return {
'name': speaker.name,
'twitter': speaker.twitter_username,
'contact': speaker.email if has_contact_perm(user) else 'redacted',
'picture_url': speaker_photo(None, speaker, 120)
}
def schedule_json(request):
slots = Slot.objects.filter(
day__schedule__published=True,
day__schedule__hidden=False
).order_by("start")
protocol = request.META.get('HTTP_X_FORWARDED_PROTO', 'http')
data = []
for slot in slots:
rooms = list(slot.rooms)
slot_data = {
"room": ", ".join(room.name for room in rooms),
"rooms": [room.name for room in rooms],
"start": slot.start_datetime.isoformat(),
"end": slot.end_datetime.isoformat(),
"duration": slot.length_in_minutes,
"kind": slot.kind.label,
"section": slot.day.schedule.section.slug,
"section_name": slot.day.schedule.section.name,
"track": None,
"conf_key": slot.pk,
# TODO: models should be changed.
# these are model features from other conferences that have forked symposion
# these have been used almost everywhere and are good candidates for
# base proposals
"license": "CC BY",
"tags": "",
"released": False,
"contact": [],
}
if hasattr(slot.content, "proposal"):
if slot.content.unpublish and not request.user.is_staff:
continue
track_name = None
if len(rooms) == 1:
track = rooms[0].track_set.filter(day=slot.day).first()
if track:
track_name = track.name
slot_data.update({
"name": slot.content.title,
"authors": [make_speaker_dict(request.user, s) for s in slot.content.speakers()],
"abstract": slot.content.abstract,
"conf_url": "%s://%s%s" % (
protocol,
Site.objects.get_current().domain,
reverse("schedule_presentation_detail", args=[slot.content.pk])
),
"cancelled": slot.content.cancelled,
"released": slot.content.proposal.recording_release,
"track": track_name,
})
if not slot.content.speaker.twitter_username == '':
slot_data["twitter_id"] = slot.content.speaker.twitter_username
else:
slot_data.update({
"name": slot.content_override if slot.content_override else "Slot",
})
data.append(slot_data)
return HttpResponse(
json.dumps({"schedule": data}, indent=2),
content_type="application/json"
)
class EventFeed(ICalFeed):
product_id = '-//linux.conf.au/schedule//EN'
timezone = settings.TIME_ZONE
filename = 'conference.ics'
def description(self):
return Conference.objects.all().first().title
def items(self):
return Slot.objects.filter(
day__schedule__published=True,
day__schedule__hidden=False
).exclude(
kind__label='shortbreak'
).order_by("start")
def item_title(self, item):
if hasattr(item.content, 'proposal'):
title = item.content.title
else:
title = item.kind if item.kind else "Slot"
return title
def item_description(self, item):
if hasattr(item.content, 'proposal'):
description = "Speaker: %s\n%s" % (
item.content.speaker, item.content.abstract)
else:
description = item.content_override if item.content_override else "No description"
return description
def item_start_datetime(self, item):
return pytz.timezone(settings.TIME_ZONE).localize(item.start_datetime)
def item_end_datetime(self, item):
return pytz.timezone(settings.TIME_ZONE).localize(item.end_datetime)
def item_location(self, item):
return ", ".join(room["name"] for room in item.rooms.values())
def item_link(self, item) -> str:
if hasattr(item.content, 'proposal'):
return (
'http://%s%s' % (Site.objects.get_current().domain,
reverse('schedule_presentation_detail', args=[item.content.pk])))
else:
return 'http://%s' % Site.objects.get_current().domain
def item_guid(self, item):
return '%d@%s' % (item.pk, Site.objects.get_current().domain)
def session_list(request):
sessions = Session.objects.all().order_by('pk')
return render(request, "symposion/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, "attendee") or not request.user.attendee.completed_registration:
response = redirect("guided_registration")
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, "symposion/schedule/session_detail.html", {
"session": session,
"chair": chair,
"chair_denied": chair_denied,
"runner": runner,
"runner_denied": runner_denied,
})