Skip to content
views.py 5.19 KiB
Newer Older
Bengfort's avatar
Bengfort committed
# (c) 2020 MPIB <https://www.mpib-berlin.mpg.de/>,
#
# This file is part of castellum-scheduler.
#
# castellum-scheduler is free software; you can redistribute it and/or
# modify it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation; either version 3 of the
# License, or (at your option) any later version.
#
# Castellum is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License along with Castellum. If not, see
# <http://www.gnu.org/licenses/>.

from collections import OrderedDict

Bengfort's avatar
Bengfort committed
from django.conf import settings
Bengfort's avatar
Bengfort committed
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from django.db import models
Bengfort's avatar
Bengfort committed
from django.core.exceptions import PermissionDenied
from django.http import HttpResponse
from django.http import JsonResponse
Bengfort's avatar
Bengfort committed
from django.shortcuts import get_object_or_404
from django.urls import reverse
Bengfort's avatar
Bengfort committed
from django.utils.decorators import method_decorator
Bengfort's avatar
Bengfort committed
from django.utils.translation import gettext_lazy as _
Bengfort's avatar
Bengfort committed
from django.views.decorators.csrf import csrf_exempt
Bengfort's avatar
Bengfort committed
from django.views.generic import CreateView
from django.views.generic import DeleteView
from django.views.generic import ListView
from django.views.generic import UpdateView
Bengfort's avatar
Bengfort committed
from django.views.generic import View
Bengfort's avatar
Bengfort committed

import requests

Bengfort's avatar
Bengfort committed
from .forms import ScheduleForm
from .models import Invitation
from .models import Schedule


class ScheduleListView(LoginRequiredMixin, ListView):
    model = Schedule
Bengfort's avatar
Bengfort committed
    paginate_by = 20
Bengfort's avatar
Bengfort committed


class ScheduleFormMixin(LoginRequiredMixin):
    model = Schedule
    form_class = ScheduleForm

    def get_success_url(self):
        return reverse('schedule-update', args=[self.object.uuid])
Bengfort's avatar
Bengfort committed

    def form_valid(self, form, *args):
        messages.success(self.request, _('Data has been saved.'))
        return super().form_valid(form, *args)


class ScheduleCreateView(ScheduleFormMixin, CreateView):
    pass


class ScheduleUpdateView(ScheduleFormMixin, UpdateView):
    slug_field = 'uuid'
    slug_url_kwarg = 'uuid'
Bengfort's avatar
Bengfort committed


class ScheduleDeleteView(LoginRequiredMixin, DeleteView):
    model = Schedule
    slug_field = 'uuid'
    slug_url_kwarg = 'uuid'
Bengfort's avatar
Bengfort committed

    def get_success_url(self):
        return reverse('index')


class InvitationUpdateView(UpdateView):
    model = Invitation
    slug_field = 'token'
    slug_url_kwarg = 'token'
    fields = ['timeslot']

    def get_object(self):
Bengfort's avatar
Bengfort committed
        return get_object_or_404(Invitation, **self.kwargs)
Bengfort's avatar
Bengfort committed

    def get_success_url(self):
        return reverse('invitation', args=[self.object.schedule.uuid, self.object.token])

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        timeslots = list(self.object.schedule.timeslot_set.filter(
            models.Q(invitation=None) | models.Q(invitation=self.object)
        ))

        dates = []
        times = []
        for timeslot in timeslots:
            dates.append(timeslot.date)
            times.append(timeslot.time)

        dates = sorted(set(dates))
        times = sorted(set(times))

        table = OrderedDict()
        for date in dates:
            table[date] = OrderedDict()
            for time in times:
                table[date][time] = 0
        for timeslot in timeslots:
            table[timeslot.date][timeslot.time] = timeslot.id

        context['table'] = {
            'timeslots': table,
            'times': times,
        }

        return context

    def form_valid(self, form, *args):
        ok = True
        response = super().form_valid(form, *args)
        if settings.PING_URL:
            r = requests.post(settings.PING_URL.format(
                schedule_id=self.object.schedule.id,
                token=self.object.token,
            ))
            ok = r.ok
        if ok:
Bengfort's avatar
Bengfort committed
            messages.success(self.request, _('Your booking has been saved.'))
        else:
            self.object.timeslot = None
            self.object.save()
            messages.error(self.request, _('An error occured.'))
        return response
Bengfort's avatar
Bengfort committed


@method_decorator(csrf_exempt, 'dispatch')
class InvitationApiView(View):
    def dispatch(self, request, *args, **kwargs):
        if request.headers.get('Authorization') != 'token ' + settings.API_TOKEN:
            raise PermissionDenied
        return super().dispatch(request, *args, **kwargs)

    def get(self, request, *args, **kwargs):
Bengfort's avatar
Bengfort committed
        invitation = get_object_or_404(Invitation, **kwargs)
Bengfort's avatar
Bengfort committed
        return JsonResponse({
            'datetime': invitation.timeslot.datetime if invitation.timeslot else None,
        })

    def put(self, request, *args, **kwargs):
Bengfort's avatar
Bengfort committed
        if 'schedule__uuid' in kwargs:
            schedule = get_object_or_404(Schedule, uuid=kwargs.pop('schedule__uuid'))
            kwargs['schedule_id'] = schedule.id
Bengfort's avatar
Bengfort committed
        invitation, _ = Invitation.objects.get_or_create(**kwargs)
Bengfort's avatar
Bengfort committed
        return HttpResponse(status=204)

    def delete(self, request, *args, **kwargs):
Bengfort's avatar
Bengfort committed
        invitation = get_object_or_404(Invitation, **kwargs)
Bengfort's avatar
Bengfort committed
        invitation.delete()
        return HttpResponse(status=204)