From 98dd05377bd8972a1fe5991888e4b444aec2eae8 Mon Sep 17 00:00:00 2001
From: ingo <ingo.leindecker@fro.at>
Date: Thu, 4 Jan 2018 15:59:44 +0100
Subject: [PATCH] Fixed bugs when deleting shows, schedules, timeslots and
 notes.

Changed note filters:
- ?owner=1 returns all notes a user may edit
- ?user=1 returns all notes a user created

See #22
---
 ...103_0054.py => 0012_auto_20180104_0005.py} |  2 +-
 program/templates/calendar.html               | 59 +++++++++++++++----
 program/views.py                              | 25 +++++---
 3 files changed, 65 insertions(+), 21 deletions(-)
 rename program/migrations/{0012_auto_20180103_0054.py => 0012_auto_20180104_0005.py} (99%)

diff --git a/program/migrations/0012_auto_20180103_0054.py b/program/migrations/0012_auto_20180104_0005.py
similarity index 99%
rename from program/migrations/0012_auto_20180103_0054.py
rename to program/migrations/0012_auto_20180104_0005.py
index 8ba4be8e..a60764d6 100644
--- a/program/migrations/0012_auto_20180103_0054.py
+++ b/program/migrations/0012_auto_20180104_0005.py
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Generated by Django 1.11.3 on 2018-01-02 23:54
+# Generated by Django 1.11.3 on 2018-01-03 23:05
 from __future__ import unicode_literals
 
 from django.conf import settings
diff --git a/program/templates/calendar.html b/program/templates/calendar.html
index 75b9e6ad..6f76d79b 100644
--- a/program/templates/calendar.html
+++ b/program/templates/calendar.html
@@ -128,17 +128,40 @@
     	notify.fadeOut(2000);
     }
 
+    /**
+     * Makes sure the csrftoken get submitted properly
+     * See https://stackoverflow.com/questions/35112451/forbidden-csrf-token-missing-or-incorrect-django-error
+     */
+    function getCookie(name) {
+        var cookieValue = null;
+        if (document.cookie && document.cookie != '') {
+            var cookies = document.cookie.split(';');
+            for (var i = 0; i < cookies.length; i++) {
+                var cookie = jQuery.trim(cookies[i]);
+                // Does this cookie string begin with the name we want?
+                if (cookie.substring(0, name.length + 1) == (name + '=')) {
+                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
+                    break;
+                }
+            }
+        }
+        return cookieValue;
+    }
+    var csrftoken = getCookie('csrftoken');
+    function csrfSafeMethod(method) {
+        // These HTTP methods do not require CSRF protection
+        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
+    }
 
     jQuery(document).ready( function() {
 
        jQuery("#calendar").fullCalendar({
-          // Enable theme
-          theme: true,
+          theme: true, // Enable theme
           timezone: 'Europe/Berlin',
           locale: 'de', // TODO: make an option for that
           defaultView: 'agendaWeek',
           // Event dragging & resizing
-          editable: true,
+          editable: false,
           // Header
           header: {
             left: 'prev,next today',
@@ -155,16 +178,26 @@
                 if( ! confirm( "Wollen Sie diese Episode wirklich löschen?" ) )
                    return false;
 
-                // Delete from database
-                jQuery.post( '/api/v1/timeslots/' + event._id + '/', { 'action': 'delete_timeslot', 'id': event._id } )
-                .done(function( data ) {
-                   // Remove element from DOM
-                   jQuery('#calendar').fullCalendar('removeEvents', event._id );
-                   notify( 'Time slot deleted.' );
-                   console.log(data.result);
-                })
-                .fail(function( data ) {
-                   notify( data.result );
+                jQuery.ajaxSetup({
+                  beforeSend: function(xhr, settings) {
+                    if( ! csrfSafeMethod(settings.type) && ! this.crossDomain) {
+                      xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken') );
+                    }
+                  }
+                });
+
+                jQuery.ajax({
+                  url: '/api/v1/shows/' + event.show_id + '/timeslots/' + event._id + '/',
+                  type: 'DELETE',
+                  success: function(result) {
+                    jQuery('#calendar').fullCalendar('removeEvents', event._id );
+                    notify( 'Timeslot deleted.' );
+                  },
+                  error: function(request, msg, error) {
+                    notify( 'Delete failed: ' + request.responseJSON.detail );
+                    console.log(error)
+                    console.log(request)
+                  }
                 });
 
              });
diff --git a/program/views.py b/program/views.py
index dfe7ee74..55737bb4 100644
--- a/program/views.py
+++ b/program/views.py
@@ -13,9 +13,11 @@ from django.views.generic.list import ListView
 from rest_framework import permissions, serializers, status, viewsets
 from rest_framework.views import APIView
 from rest_framework.response import Response
+from rest_framework.renderers import JSONRenderer
 from rest_framework.pagination import LimitOffsetPagination
+from rest_framework.decorators import api_view
 
-from program.models import Type, MusicFocus, Language, Note, Show, Category, RTRCategory, Topic, TimeSlot, Host, Schedule
+from program.models import Type, MusicFocus, Language, Note, Show, Category, RTRCategory, Topic, TimeSlot, Host, Schedule, RRule
 from program.serializers import TypeSerializer, LanguageSerializer, MusicFocusSerializer, NoteSerializer, ShowSerializer, ScheduleSerializer, CategorySerializer, RTRCategorySerializer, TopicSerializer, TimeSlotSerializer, HostSerializer, UserSerializer
 from program.utils import tofirstdayinisoweek, get_cached_shows
 
@@ -530,7 +532,7 @@ class APIShowViewSet(viewsets.ModelViewSet):
             return Response(status=status.HTTP_401_UNAUTHORIZED)
 
         show = get_object_or_404(Show, pk=pk)
-        Show.objects.delete(pk=pk)
+        Show.objects.get(pk=pk).delete()
 
         return Response(status=status.HTTP_204_NO_CONTENT)
 
@@ -622,7 +624,7 @@ class APIScheduleViewSet(viewsets.ModelViewSet):
             return Response(status=status.HTTP_401_UNAUTHORIZED)
 
         schedule = get_object_or_404(Schedule, pk=pk)
-        Schedule.objects.delete(pk=pk)
+        Schedule.objects.get(pk=pk).delete()
 
         return Response(status=status.HTTP_204_NO_CONTENT)
 
@@ -722,17 +724,21 @@ class APITimeSlotViewSet(viewsets.ModelViewSet):
         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
 
 
-    def destroy(self, request, pk=None):
+    def destroy(self, request, pk=None, schedule_pk=None, show_pk=None):
         """
         Delete a timeslot
         Only superusers may delete timeslots
         """
 
+        # Only allow when calling endpoint starting with /shows/1/...
+        if show_pk == None:
+            return Response(status=status.HTTP_400_BAD_REQUEST)
+
         if not request.user.is_superuser:
             return Response(status=status.HTTP_401_UNAUTHORIZED)
 
         timeslot = get_object_or_404(TimeSlot, pk=pk)
-        TimeSlot.objects.delete(pk=pk)
+        TimeSlot.objects.get(pk=pk).delete()
 
         return Response(status=status.HTTP_204_NO_CONTENT)
 
@@ -803,8 +809,13 @@ class APINoteViewSet(viewsets.ModelViewSet):
             notes = notes.filter(host=int(self.request.GET.get('host')))
 
         if self.request.GET.get('owner') != None:
+            '''Filter notes by show owner: all notes the user may edit'''
+            shows = Show.objects.filter(owners=int(self.request.GET.get('owner')))
+            notes = notes.filter(show__in=shows)
+
+        if self.request.GET.get('user') != None:
             '''Filter notes by their creator'''
-            notes = notes.filter(user=int(self.request.GET.get('owner')))
+            notes = notes.filter(user=int(self.request.GET.get('user')))
 
         return notes
 
@@ -911,7 +922,7 @@ class APINoteViewSet(viewsets.ModelViewSet):
         note = get_object_or_404(Note, pk=pk)
 
         if Note.is_editable(self, note.id):
-            Note.objects.delete(pk=pk)
+            Note.objects.get(pk=pk).delete()
             return Response(status=status.HTTP_204_NO_CONTENT)
 
         return Response(status=status.HTTP_401_UNAUTHORIZED)
-- 
GitLab