Skip to content
views.py 5.02 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.shortcuts import get_object_or_404
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from django.views.generic import CreateView
from django.views.generic import DeleteView
from django.views.generic import ListView
from django.views.generic import UpdateView

import requests
from rest_framework.permissions import BasePermission
from rest_framework.response import Response as APIResponse
from rest_framework.views import APIView
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
class TokenPermission(BasePermission):
    def has_permission(self, request, view):
        return request.headers.get('Authorization') == 'token ' + settings.API_TOKEN


class InvitationApiView(APIView):
    permission_classes = [TokenPermission]
Bengfort's avatar
Bengfort committed

    def get(self, request, *args, **kwargs):
Bengfort's avatar
Bengfort committed
        invitation = get_object_or_404(Invitation, **kwargs)
        return APIResponse({
Bengfort's avatar
Bengfort committed
            '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)
        return APIResponse(status=204)
Bengfort's avatar
Bengfort committed

    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 APIResponse(status=204)