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