bornhack-website/src/program/views.py

334 lines
13 KiB
Python
Raw Normal View History

import datetime
import logging
import os
from django.views.generic import ListView, TemplateView, DetailView, View
from django.views.generic.edit import CreateView, UpdateView
from django.conf import settings
from django.views.decorators.http import require_safe
2017-03-12 14:43:41 +00:00
from django.http import Http404, HttpResponse
from django.utils.decorators import method_decorator
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from django.urls import reverse
2017-08-13 22:50:54 +00:00
from django.db.models import Q
2017-08-22 11:00:42 +00:00
from django.template import Engine, Context
import icalendar
2017-03-12 14:43:41 +00:00
from camps.mixins import CampViewMixin
from .mixins import (
CreateProposalMixin,
EnsureUnapprovedProposalMixin,
EnsureUserOwnsProposalMixin,
EnsureWritableCampMixin,
PictureViewMixin,
EnsureCFSOpenMixin
)
from .email import (
add_speakerproposal_updated_email,
add_eventproposal_updated_email
)
2017-03-12 14:43:41 +00:00
from . import models
logger = logging.getLogger("bornhack.%s" % __name__)
2017-03-31 17:25:48 +00:00
############## ical calendar ########################################################
class ICSView(CampViewMixin, View):
2017-03-31 17:25:48 +00:00
def get(self, request, *args, **kwargs):
2017-04-13 12:01:50 +00:00
eventinstances = models.EventInstance.objects.filter(event__camp=self.camp)
2017-08-13 22:50:54 +00:00
# Type query
type_query = request.GET.get('type', None)
if type_query:
type_slugs = type_query.split(',')
types = models.EventType.objects.filter(
slug__in=type_slugs
)
eventinstances = eventinstances.filter(event__event_type__in=types)
# Location query
location_query = request.GET.get('location', None)
if location_query:
location_slugs = location_query.split(',')
locations = models.EventLocation.objects.filter(
slug__in=location_slugs,
camp=self.camp,
)
eventinstances = eventinstances.filter(location__in=locations)
# Video recording query
video_query = request.GET.get('video', None)
if video_query:
video_states = video_query.split(',')
query_kwargs = {}
if 'has-recording' in video_states:
query_kwargs['event__video_url__isnull'] = False
if 'to-be-recorded' in video_states:
query_kwargs['event__video_recording'] = True
if 'not-to-be-recorded' in video_states:
if 'event__video_recording' in query_kwargs:
del query_kwargs['event__video_recording']
else:
query_kwargs['event__video_recording'] = False
eventinstances = eventinstances.filter(**query_kwargs)
cal = icalendar.Calendar()
for event_instance in eventinstances:
cal.add_component(event_instance.get_ics_event())
2017-04-13 12:14:44 +00:00
response = HttpResponse(cal.to_ical())
response['Content-Type'] = 'text/calendar'
response['Content-Disposition'] = 'inline; filename={}.ics'.format(self.camp.slug)
return response
############## proposals ########################################################
2017-03-12 14:43:41 +00:00
class ProposalListView(LoginRequiredMixin, CampViewMixin, ListView):
model = models.SpeakerProposal
template_name = 'proposal_list.html'
context_object_name = 'speakerproposal_list'
2017-03-12 14:43:41 +00:00
def get_queryset(self, **kwargs):
# only show speaker proposals for the current user
2017-03-12 14:43:41 +00:00
return super().get_queryset().filter(user=self.request.user)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
2017-03-14 17:06:23 +00:00
# also add eventproposals to the context
context['eventproposal_list'] = models.EventProposal.objects.filter(camp=self.camp, user=self.request.user)
2017-03-12 14:43:41 +00:00
return context
class SpeakerProposalCreateView(LoginRequiredMixin, CampViewMixin, CreateProposalMixin, EnsureWritableCampMixin, EnsureCFSOpenMixin, CreateView):
model = models.SpeakerProposal
2017-07-15 13:56:32 +00:00
fields = ['name', 'biography', 'picture_small', 'picture_large', 'submission_notes']
template_name = 'speakerproposal_form.html'
2017-03-12 14:43:41 +00:00
2017-03-14 17:06:23 +00:00
def get_success_url(self):
return reverse('proposal_list', kwargs={'camp_slug': self.camp.slug})
2017-03-12 14:43:41 +00:00
class SpeakerProposalUpdateView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsProposalMixin, EnsureWritableCampMixin, EnsureCFSOpenMixin, UpdateView):
model = models.SpeakerProposal
2017-07-15 13:56:32 +00:00
fields = ['name', 'biography', 'picture_small', 'picture_large', 'submission_notes']
template_name = 'speakerproposal_form.html'
2017-03-12 14:43:41 +00:00
def get_success_url(self):
return reverse('proposal_list', kwargs={'camp_slug': self.camp.slug})
2017-03-12 14:43:41 +00:00
def form_valid(self, form):
if form.instance.proposal_status == models.UserSubmittedModel.PROPOSAL_PENDING:
2017-04-01 19:45:43 +00:00
messages.warning(self.request, "Your speaker proposal has been reverted to status draft. Please submit it again when you are ready.")
form.instance.proposal_status = models.UserSubmittedModel.PROPOSAL_DRAFT
if form.instance.proposal_status == models.UserSubmittedModel.PROPOSAL_APPROVED:
messages.warning(self.request, "Your speaker proposal has been set to modified after approval. Please await approval of the changes.")
form.instance.proposal_status = models.UserSubmittedModel.PROPOSAL_MODIFIED_AFTER_APPROVAL
if not add_speakerproposal_updated_email(form.instance):
logger.error(
'Unable to add update email to queue for speaker: {}'.format(form.instance)
)
return super().form_valid(form)
class SpeakerProposalSubmitView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsProposalMixin, EnsureUnapprovedProposalMixin, EnsureWritableCampMixin, EnsureCFSOpenMixin, UpdateView):
model = models.SpeakerProposal
fields = []
template_name = 'speakerproposal_submit.html'
def get_success_url(self):
return reverse('proposal_list', kwargs={'camp_slug': self.camp.slug})
def form_valid(self, form):
form.instance.proposal_status = models.UserSubmittedModel.PROPOSAL_PENDING
messages.info(self.request, "Your proposal has been submitted and is now pending approval")
return super().form_valid(form)
class SpeakerProposalDetailView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsProposalMixin, DetailView):
model = models.SpeakerProposal
template_name = 'speakerproposal_detail.html'
2017-03-12 14:43:41 +00:00
@method_decorator(require_safe, name='dispatch')
class SpeakerProposalPictureView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsProposalMixin, PictureViewMixin, DetailView):
model = models.SpeakerProposal
def get(self, request, *args, **kwargs):
2017-03-14 17:06:23 +00:00
# is the proposal owned by current user?
if self.get_object().user != request.user:
2017-03-12 14:43:41 +00:00
raise Http404()
# get and return the response
2017-03-29 22:20:14 +00:00
response = self.get_picture_response('/public/speakerproposals/%(campslug)s/%(proposaluuid)s/%(filename)s' % {
'campslug': self.camp.slug,
'proposaluuid': self.get_object().uuid,
'filename': os.path.basename(self.picture.name),
})
2017-03-12 14:43:41 +00:00
return response
class EventProposalCreateView(LoginRequiredMixin, CampViewMixin, CreateProposalMixin, EnsureWritableCampMixin, EnsureCFSOpenMixin, CreateView):
model = models.EventProposal
2017-07-15 13:56:32 +00:00
fields = ['title', 'abstract', 'event_type', 'speakers', 'allow_video_recording', 'submission_notes']
template_name = 'eventproposal_form.html'
2017-03-12 14:43:41 +00:00
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'].fields['speakers'].queryset = models.SpeakerProposal.objects.filter(camp=self.camp, user=self.request.user)
2017-03-12 15:16:24 +00:00
context['form'].fields['event_type'].queryset = models.EventType.objects.filter(public=True)
2017-03-12 14:43:41 +00:00
return context
class EventProposalUpdateView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsProposalMixin, EnsureWritableCampMixin, EnsureCFSOpenMixin, UpdateView):
model = models.EventProposal
fields = ['title', 'abstract', 'event_type', 'speakers', 'allow_video_recording', 'submission_notes']
template_name = 'eventproposal_form.html'
def get_success_url(self):
return reverse('proposal_list', kwargs={'camp_slug': self.camp.slug})
2017-03-12 15:16:24 +00:00
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'].fields['speakers'].queryset = models.SpeakerProposal.objects.filter(camp=self.camp, user=self.request.user)
context['form'].fields['event_type'].queryset = models.EventType.objects.filter(public=True)
return context
def form_valid(self, form):
if form.instance.proposal_status == models.UserSubmittedModel.PROPOSAL_PENDING:
2017-04-01 19:45:43 +00:00
messages.warning(self.request, "Your event proposal has been reverted to status draft. Please submit it again when you are ready.")
form.instance.proposal_status = models.UserSubmittedModel.PROPOSAL_DRAFT
if form.instance.proposal_status == models.UserSubmittedModel.PROPOSAL_APPROVED:
messages.warning(self.request, "Your event proposal has been set to status modified after approval. Please await approval of the changes.")
form.instance.proposal_status = models.UserSubmittedModel.PROPOSAL_MODIFIED_AFTER_APPROVAL
if not add_eventproposal_updated_email(form.instance):
logger.error(
'Unable to add update email to queue for event: {}'.format(form.instance)
)
return super().form_valid(form)
class EventProposalSubmitView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsProposalMixin, EnsureUnapprovedProposalMixin, EnsureWritableCampMixin, EnsureCFSOpenMixin, UpdateView):
model = models.EventProposal
fields = []
template_name = 'eventproposal_submit.html'
def get_success_url(self):
return reverse('proposal_list', kwargs={'camp_slug': self.camp.slug})
def form_valid(self, form):
form.instance.proposal_status = models.UserSubmittedModel.PROPOSAL_PENDING
messages.info(self.request, "Your proposal has been submitted and is now pending approval")
return super().form_valid(form)
class EventProposalDetailView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsProposalMixin, DetailView):
model = models.EventProposal
template_name = 'eventproposal_detail.html'
2017-03-12 14:43:41 +00:00
################## speakers ###############################################
@method_decorator(require_safe, name='dispatch')
class SpeakerPictureView(CampViewMixin, PictureViewMixin, DetailView):
model = models.Speaker
def get(self, request, *args, **kwargs):
2017-03-29 22:20:14 +00:00
# get and return the response
response = self.get_picture_response(path='/public/speakers/%(campslug)s/%(slug)s/%(filename)s' % {
'campslug': self.camp.slug,
'slug': self.get_object().slug,
'filename': os.path.basename(self.picture.name),
})
return response
2016-07-13 20:37:20 +00:00
2016-08-08 17:45:32 +00:00
class SpeakerDetailView(CampViewMixin, DetailView):
2016-08-08 17:45:32 +00:00
model = models.Speaker
template_name = 'speaker_detail.html'
class SpeakerListView(CampViewMixin, ListView):
2016-08-08 17:36:13 +00:00
model = models.Speaker
template_name = 'speaker_list.html'
2017-03-12 14:43:41 +00:00
################## events ##############################################
2017-01-23 17:57:30 +00:00
class EventListView(CampViewMixin, ListView):
2016-08-08 17:36:13 +00:00
model = models.Event
template_name = 'event_list.html'
2016-07-13 20:37:20 +00:00
2017-03-12 14:43:41 +00:00
class EventDetailView(CampViewMixin, DetailView):
model = models.Event
template_name = 'schedule_event_detail.html'
################## schedule #############################################
class NoScriptScheduleView(CampViewMixin, TemplateView):
template_name = "noscript_schedule_view.html"
2016-07-13 20:37:20 +00:00
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(**kwargs)
context['eventinstances'] = models.EventInstance.objects.filter(event__camp=self.camp).order_by('when')
return context
2017-01-23 22:58:41 +00:00
class ScheduleView(CampViewMixin, TemplateView):
template_name = 'schedule_overview.html'
2017-01-23 22:58:41 +00:00
def get_context_data(self, *args, **kwargs):
context = super(ScheduleView, self).get_context_data(**kwargs)
2017-04-26 22:23:03 +00:00
context['schedule_midnight_offset_hours'] = settings.SCHEDULE_MIDNIGHT_OFFSET_HOURS;
return context
2016-08-07 13:49:30 +00:00
class CallForSpeakersView(CampViewMixin, TemplateView):
def get_template_names(self):
return '%s_call_for_speakers.html' % self.camp.slug
################## control center #############################################
class ProgramControlCenter(CampViewMixin, TemplateView):
template_name = "control/index.html"
@method_decorator(staff_member_required)
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(**kwargs)
proposals = models.EventProposal.objects.filter(
camp=self.camp
).select_related('user', 'event')
context['proposals'] = proposals
2017-08-22 11:00:42 +00:00
engine = Engine.get_default()
template = engine.get_template('control/proposal_overview.csv')
csv = template.render(Context(context))
context['csv'] = csv
return context