symposion_app/vendor/symposion/schedule/views.py
Joel Addison 252697b842 Update to Django 2.2
Upgrade site and modules to Django 2.2. Remove and replace obsolete
functionality with current equivalents. Update requirements to latest
versions where possible. Remove unused dependencies.
2020-11-22 23:58:14 +10:00

422 lines
14 KiB
Python

import json
import pytz
from django.http import Http404, HttpResponse
from django.shortcuts import render, get_object_or_404, redirect
from django.urls import reverse
from django.template import loader, Context
from django.conf import settings
from django.contrib.auth import get_user_model
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
User = get_user_model()
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,
})
ctx = {
"sections": sections,
}
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)
schedule = None
if presentation.slot:
# 1) Schedule from presentation's slot
schedule = presentation.slot.day.schedule
else:
# 2) Fall back to the schedule for this proposal
section = presentation.proposal.kind.section
if hasattr(section, 'schedule'):
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-SA",
"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,
})