From 0c37bec6c68339507a0896db06c88beeb606fe0c Mon Sep 17 00:00:00 2001
From: Ernesto Rico Schmidt <ernesto@helsinki.at>
Date: Sun, 22 Nov 2020 22:48:39 -0400
Subject: [PATCH] Clean-up code

Python 3.8 is minimal version now
---
 README.rst       |   2 +-
 program/views.py | 178 ++++++++++++++++++++++++-----------------------
 2 files changed, 92 insertions(+), 88 deletions(-)

diff --git a/README.rst b/README.rst
index 8d14dcf6..bf24008c 100644
--- a/README.rst
+++ b/README.rst
@@ -16,7 +16,7 @@ To get setup you must have the following installed:
 
 * PostgresSQL or MySQL client development libraries
 * JPEG library development files
-* Python 3 including development files
+* Python 3.8 or later including development files
 
 In Debian or Ubuntu (or derivatives) you should be able to achieve this with this command:
 
diff --git a/program/views.py b/program/views.py
index ea9158ce..715774cb 100644
--- a/program/views.py
+++ b/program/views.py
@@ -73,7 +73,7 @@ def json_playout(request):
     schedule = []
     for ts in timeslots:
 
-        is_repetition = ' ' + _('REP') if ts.schedule.is_repetition is 1 else ''
+        is_repetition = ' ' + _('REP') if ts.schedule.is_repetition is True else ''
 
         hosts = ', '.join(ts.show.hosts.values_list('name', flat=True))
         categories = ', '.join(ts.show.category.values_list('category', flat=True))
@@ -81,7 +81,7 @@ def json_playout(request):
         musicfocus = ', '.join(ts.show.musicfocus.values_list('focus', flat=True))
         languages = ', '.join(ts.show.language.values_list('name', flat=True))
         fdcategory = None
-        if ts.show.fundingcategory_id is not None:
+        if ts.show.fundingcategory_id:
             fundingcategory = FundingCategory.objects.get(pk=ts.show.fundingcategory_id)
             fdcategory = fundingcategory.fundingcategory
 
@@ -143,7 +143,7 @@ def json_timeslots_specials(request):
             if specials[automation_id]['pv_start'] < start:
                 continue
 
-        specials[automation_id]['pv_id'] = int(ts.show.id)
+        specials[automation_id]['pv_id'] = ts.show.id
         specials[automation_id]['pv_name'] = ts.show.name
         specials[automation_id]['pv_start'] = start
         specials[automation_id]['pv_end'] = end
@@ -152,6 +152,10 @@ def json_timeslots_specials(request):
                         content_type="application/json; charset=utf-8")
 
 
+def int_or_none(key, kwargs):
+    return int(kwargs[key]) if key in kwargs else None
+
+
 class APIUserViewSet(viewsets.ModelViewSet):
     """
     `/users` returns oneself. Superusers see all users. Only superusers may create a user (GET, POST)
@@ -178,10 +182,10 @@ class APIUserViewSet(viewsets.ModelViewSet):
 
     def retrieve(self, request, *args, **kwargs):
         """Returns a single user"""
-        pk = kwargs.get('pk')
+        pk = int_or_none('pk', self.kwargs)
 
         # Common users only see themselves
-        if not request.user.is_superuser and int(pk) != request.user.id:
+        if not request.user.is_superuser and pk != request.user.id:
             return Response(status=status.HTTP_401_UNAUTHORIZED)
 
         user = get_object_or_404(User, pk=pk)
@@ -206,11 +210,11 @@ class APIUserViewSet(viewsets.ModelViewSet):
         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
 
     def update(self, request, *args, **kwargs):
-        pk = kwargs.get('pk')
+        pk = int_or_none('pk', self.kwargs)
 
         serializer = UserSerializer(data=request.data)
         # Common users may only edit themselves
-        if not request.user.is_superuser and int(pk) != request.user.id:
+        if not request.user.is_superuser and pk != request.user.id:
             return Response(serializer.initial_data, status=status.HTTP_401_UNAUTHORIZED)
 
         user = get_object_or_404(User, pk=pk)
@@ -259,7 +263,7 @@ class APIShowViewSet(viewsets.ModelViewSet):
         shows = Show.objects.all()
 
         # Filters
-        if self.request.GET.get('active') == 'true' or self.request.GET.get('active') == 'false':
+        if self.request.query_params.get('active') == 'true' or self.request.query_params.get('active') == 'false':
             # Filter currently running shows
             # Get currently running schedules to filter by first
             # For single dates we test if there'll be one in the future (and ignore the until date)
@@ -276,25 +280,25 @@ class APIShowViewSet(viewsets.ModelViewSet):
             # Even if there are future timeslots but is_active=True the show will be considered as inactive
             shows = Show.objects.filter(id__in=show_ids, is_active=True)
 
-        if self.request.GET.get('active') == 'false':
+        if self.request.query_params.get('active') == 'false':
             # Return all shows except those which are running
             shows = Show.objects.exclude(id__in=show_ids, is_active=True)
 
-        if self.request.GET.get('public') == 'true':
+        if self.request.query_params.get('public') == 'true':
             # Return all public shows
             shows = shows.filter(is_public=True)
 
-        if self.request.GET.get('public') == 'false':
+        if self.request.query_params.get('public') == 'false':
             # Return all public shows
             shows = shows.filter(is_public=False)
 
-        if self.request.GET.get('owner') is not None:
+        if owner := self.request.query_params.get('owner'):
             # Filter shows by owner
-            shows = shows.filter(owners__in=[int(self.request.GET.get('owner'))])
+            shows = shows.filter(owners__in=[int(owner)])
 
-        if self.request.GET.get('host') is not None:
+        if host := self.request.query_params.get('host'):
             # Filter shows by host
-            shows = shows.filter(hosts__in=[int(self.request.GET.get('host'))])
+            shows = shows.filter(hosts__in=[int(host)])
 
         return shows
 
@@ -318,7 +322,7 @@ class APIShowViewSet(viewsets.ModelViewSet):
     def retrieve(self, request, *args, **kwargs):
         """Returns a single show"""
 
-        pk = kwargs.get('pk')
+        pk = int_or_none('pk', self.kwargs)
 
         show = get_object_or_404(Show, pk=pk)
         serializer = ShowSerializer(show)
@@ -331,7 +335,7 @@ class APIShowViewSet(viewsets.ModelViewSet):
         Common users may only update shows they own
         """
 
-        pk = kwargs.get('pk')
+        pk = int_or_none('pk', self.kwargs)
 
         if not Show.is_editable(self, pk):
             return Response(status=status.HTTP_401_UNAUTHORIZED)
@@ -381,9 +385,9 @@ class APIScheduleViewSet(viewsets.ModelViewSet):
     permission_classes = [permissions.DjangoModelPermissionsOrAnonReadOnly]
 
     def get_queryset(self):
-        show_pk = self.kwargs.get('show_pk')
+        show_pk = int_or_none('show_pk', self.kwargs)
 
-        if show_pk is not None:
+        if show_pk:
             return Schedule.objects.filter(show=show_pk)
 
         return Schedule.objects.all()
@@ -396,10 +400,10 @@ class APIScheduleViewSet(viewsets.ModelViewSet):
         return Response(serializer.data)
 
     def retrieve(self, request, *args, **kwargs):
-        pk = kwargs.get('pk')
-        show_pk = kwargs.get('show_pk')
+        pk = int_or_none('pk', self.kwargs)
+        show_pk = int_or_none('show_pk', self.kwargs)
 
-        if show_pk is not None:
+        if show_pk:
             schedule = get_object_or_404(Schedule, pk=pk, show=show_pk)
         else:
             schedule = get_object_or_404(Schedule, pk=pk)
@@ -414,8 +418,8 @@ class APIScheduleViewSet(viewsets.ModelViewSet):
         Only superusers may add schedules
         TODO: Perhaps directly insert into database if no conflicts found
         """
-        pk = kwargs.get('pk')
-        show_pk = kwargs.get('show_pk')
+        pk = int_or_none('pk', self.kwargs)
+        show_pk = int_or_none('show_pk', self.kwargs)
 
         # Only allow creating when calling /shows/1/schedules/
         if show_pk is None or not request.user.is_superuser:
@@ -445,8 +449,8 @@ class APIScheduleViewSet(viewsets.ModelViewSet):
 
         Only superusers may update schedules
         """
-        pk = kwargs.get('pk')
-        show_pk = kwargs.get('show_pk')
+        pk = int_or_none('pk', self.kwargs)
+        show_pk = int_or_none('show_pk', self.kwargs)
 
         # Only allow updating when calling /shows/1/schedules/1
         if show_pk is None or not request.user.is_superuser:
@@ -476,8 +480,8 @@ class APIScheduleViewSet(viewsets.ModelViewSet):
         Delete a schedule
         Only superusers may delete schedules
         """
-        pk = kwargs.get('pk')
-        show_pk = kwargs.get('show_pk')
+        pk = int_or_none('pk', self.kwargs)
+        show_pk = self.kwargs.get('show_pk')
 
         # Only allow deleting when calling /shows/1/schedules/1
         if show_pk is None or not request.user.is_superuser:
@@ -507,8 +511,8 @@ class APITimeSlotViewSet(viewsets.ModelViewSet):
     queryset = TimeSlot.objects.none()
 
     def get_queryset(self):
-        show_pk = self.kwargs.get('show_pk')
-        schedule_pk = self.kwargs.get('schedule_pk')
+        show_pk = int_or_none('show_pk', self.kwargs)
+        schedule_pk = int_or_none('schedule_pk', self.kwargs)
 
         # Filters
 
@@ -516,9 +520,9 @@ class APITimeSlotViewSet(viewsets.ModelViewSet):
         start = datetime.combine(date.today(), time(0, 0))
         end = start + timedelta(days=60)
 
-        if self.request.GET.get('start') and self.request.GET.get('end'):
-            start = datetime.combine(datetime.strptime(self.request.GET.get('start'), '%Y-%m-%d').date(), time(0, 0))
-            end = datetime.combine(datetime.strptime(self.request.GET.get('end'), '%Y-%m-%d').date(), time(23, 59))
+        if (start := self.request.query_params.get('start')) and (end := self.request.query_params.get('end')):
+            start = datetime.combine(datetime.strptime(start, '%Y-%m-%d').date(), time(0, 0))
+            end = datetime.combine(datetime.strptime(end, '%Y-%m-%d').date(), time(23, 59))
 
         # Endpoints
 
@@ -527,7 +531,7 @@ class APITimeSlotViewSet(viewsets.ModelViewSet):
         #
         #     Returns timeslots of the given show and schedule
         #
-        if show_pk is not None and schedule_pk is not None:
+        if show_pk and schedule_pk:
             return TimeSlot.objects.filter(show=show_pk, schedule=schedule_pk, start__gte=start, end__lte=end).order_by('start')
 
         #
@@ -535,7 +539,7 @@ class APITimeSlotViewSet(viewsets.ModelViewSet):
         #
         #     Returns timeslots of the show
         #
-        elif show_pk is not None and schedule_pk is None:
+        elif show_pk and schedule_pk is None:
             return TimeSlot.objects.filter(show=show_pk, start__gte=start, end__lte=end).order_by('start')
 
         #
@@ -547,10 +551,10 @@ class APITimeSlotViewSet(viewsets.ModelViewSet):
             return TimeSlot.objects.filter(start__gte=start, end__lte=end).order_by('start')
 
     def retrieve(self, request, *args, **kwargs):
-        pk = kwargs.get('pk')
-        show_pk = kwargs.get('show_pk')
+        pk = int_or_none('pk', self.kwargs)
+        show_pk = int_or_none('show_pk', self.kwargs)
 
-        if show_pk is not None:
+        if show_pk:
             timeslot = get_object_or_404(TimeSlot, pk=pk, show=show_pk)
         else:
             timeslot = get_object_or_404(TimeSlot, pk=pk)
@@ -567,9 +571,9 @@ class APITimeSlotViewSet(viewsets.ModelViewSet):
 
     def update(self, request, *args, **kwargs):
         """Link a playlist_id to a timeslot"""
-        pk = kwargs.get('pk')
-        show_pk = kwargs.get('show_pk')
-        schedule_pk = kwargs.get('schedule_pk')
+        pk = int_or_none('pk', self.kwargs)
+        show_pk = int_or_none('show_pk', self.kwargs)
+        schedule_pk = int_or_none('schedule_pk', self.kwargs)
 
         # Update is only allowed when calling /shows/1/schedules/1/timeslots/1 and if user owns the show
         if schedule_pk is None or show_pk is None or not Show.is_editable(self, show_pk):
@@ -599,8 +603,8 @@ class APITimeSlotViewSet(viewsets.ModelViewSet):
         Delete a timeslot
         Only superusers may delete timeslots
         """
-        pk = kwargs.get('pk')
-        show_pk = kwargs.get('show_pk')
+        pk = int_or_none('pk', self.kwargs)
+        show_pk = int_or_none('show_pk', self.kwargs)
 
         # Only allow when calling endpoint starting with /shows/1/...
         if show_pk is None:
@@ -638,8 +642,8 @@ class APINoteViewSet(viewsets.ModelViewSet):
     pagination_class = LimitOffsetPagination
 
     def get_queryset(self):
-        timeslot_pk = self.kwargs.get('timeslot_pk')
-        show_pk = self.kwargs.get('show_pk')
+        timeslot_pk = int_or_none('timeslot_pk', self.kwargs)
+        show_pk = int_or_none('show_pk', self.kwargs)
 
         # Endpoints
 
@@ -649,7 +653,7 @@ class APINoteViewSet(viewsets.ModelViewSet):
         #
         #     Return a note to the timeslot
         #
-        if show_pk is not None and timeslot_pk is not None:
+        if show_pk and timeslot_pk:
             notes = Note.objects.filter(show=show_pk, timeslot=timeslot_pk)
 
         #
@@ -657,7 +661,7 @@ class APINoteViewSet(viewsets.ModelViewSet):
         #
         #     Returns notes to the show
         #
-        elif show_pk is not None and timeslot_pk is None:
+        elif show_pk and timeslot_pk is None:
             notes = Note.objects.filter(show=show_pk)
 
         #
@@ -670,31 +674,31 @@ class APINoteViewSet(viewsets.ModelViewSet):
 
         # Filters
 
-        if self.request.GET.get('ids') is not None:
+        if ids := self.request.query_params.get('ids'):
             # Filter notes by their IDs
-            note_ids = self.request.GET.get('ids').split(',')
+            note_ids = list(map(int, ids.split(',')))
             notes = notes.filter(id__in=note_ids)
 
-        if self.request.GET.get('host') is not None:
+        if host := self.request.query_params.get('host'):
             # Filter notes by host
-            notes = notes.filter(host=int(self.request.GET.get('host')))
+            notes = notes.filter(host=int(host))
 
-        if self.request.GET.get('owner') is not None:
+        if owner := self.request.query_params.get('owner'):
             # Filter notes by show owner: all notes the user may edit
-            shows = Show.objects.filter(owners=int(self.request.GET.get('owner')))
+            shows = Show.objects.filter(owners=int(owner))
             notes = notes.filter(show__in=shows)
 
-        if self.request.GET.get('user') is not None:
+        if user := self.request.query_params.get('user'):
             # Filter notes by their creator
-            notes = notes.filter(user=int(self.request.GET.get('user')))
+            notes = notes.filter(user=int(user))
 
         return notes
 
     def create(self, request, *args, **kwargs):
         """Create a note"""
-        show_pk = kwargs.get('show_pk')
-        schedule_pk = kwargs.get('schedule_pk')
-        timeslot_pk = kwargs.get('timeslot_pk')
+        show_pk = int_or_none('show_pk', self.kwargs)
+        schedule_pk = int_or_none('schedule_pk', self.kwargs)
+        timeslot_pk = int_or_none('timeslot_pk', self.kwargs)
 
         # Only create a note if show_id, timeslot_id and schedule_id is given
         if show_pk is None or schedule_pk is None or timeslot_pk is None:
@@ -726,17 +730,17 @@ class APINoteViewSet(viewsets.ModelViewSet):
         /shows/1/timeslots/1/note/1
         /shows/1/schedules/1/timeslots/1/note/1
         """
-        pk = kwargs.get('pk')
-        show_pk = kwargs.get('show_pk')
-        schedule_pk = kwargs.get('schedule_pk')
-        timeslot_pk = kwargs.get('timeslot_pk')
+        pk = int_or_none('pk', self.kwargs)
+        show_pk = int_or_none('show_pk', self.kwargs)
+        schedule_pk = int_or_none('schedule_pk', self.kwargs)
+        timeslot_pk = int_or_none('timeslot_pk', self.kwargs)
 
         #
         #      /shows/1/notes/1
         #
         #      Returns a note to a show
         #
-        if show_pk is not None and timeslot_pk is None and schedule_pk is None:
+        if show_pk and timeslot_pk is None and schedule_pk is None:
             note = get_object_or_404(Note, pk=pk, show=show_pk)
 
         #
@@ -745,7 +749,7 @@ class APINoteViewSet(viewsets.ModelViewSet):
         #
         #     Return a note to a timeslot
         #
-        elif show_pk is not None and timeslot_pk is not None:
+        elif show_pk and timeslot_pk:
             note = get_object_or_404(Note, pk=pk, show=show_pk, timeslot=timeslot_pk)
 
         #
@@ -760,10 +764,10 @@ class APINoteViewSet(viewsets.ModelViewSet):
         return Response(serializer.data)
 
     def update(self, request, *args, **kwargs):
-        pk = kwargs.get('pk')
-        show_pk = kwargs.get('show_pk')
-        schedule_pk = kwargs.get('schedule_pk')
-        timeslot_pk = kwargs.get('timeslot_pk')
+        pk = int_or_none('pk', self.kwargs)
+        show_pk = int_or_none('show_pk', self.kwargs)
+        schedule_pk = int_or_none('schedule_pk', self.kwargs)
+        timeslot_pk = int_or_none('timeslot_pk', self.kwargs)
 
         # Allow PUT only when calling /shows/1/schedules/1/timeslots/1/note/1
         if show_pk is None or schedule_pk is None or timeslot_pk is None:
@@ -780,7 +784,7 @@ class APINoteViewSet(viewsets.ModelViewSet):
         if serializer.is_valid():
 
             # Don't assign a host the user mustn't edit. Reassign the original value instead
-            if not Host.is_editable(self, request.data['host']) and request.data['host'] is not None:
+            if not Host.is_editable(self, request.data['host']) and request.data['host']:
                 serializer.validated_data['host'] = Host.objects.filter(pk=note.host_id)[0]
 
             serializer.save()
@@ -790,10 +794,10 @@ class APINoteViewSet(viewsets.ModelViewSet):
 
     def destroy(self, request, *args, **kwargs):
         # Allow DELETE only when calling /shows/1/schedules/1/timeslots/1/note/1
-        pk = kwargs.get('pk')
-        show_pk = kwargs.get('show_pk')
-        schedule_pk = kwargs.get('schedule_pk')
-        timeslot_pk = kwargs.get('timeslot_pk')
+        pk = int_or_none('pk', self.kwargs)
+        show_pk = int_or_none('show_pk', self.kwargs)
+        schedule_pk = int_or_none('schedule_pk', self.kwargs)
+        timeslot_pk = int_or_none('timeslot_pk', self.kwargs)
 
         if show_pk is None or schedule_pk is None or timeslot_pk is None:
             return Response(status=status.HTTP_400_BAD_REQUEST)
@@ -822,10 +826,10 @@ class APICategoryViewSet(viewsets.ModelViewSet):
     def get_queryset(self):
         """Filters"""
 
-        if self.request.GET.get('active') == 'true':
+        if self.request.query_params.get('active') == 'true':
             return Category.objects.filter(is_active=True)
 
-        if self.request.GET.get('active') == 'false':
+        if self.request.query_params.get('active') == 'false':
             return Category.objects.filter(is_active=False)
 
         return Category.objects.all()
@@ -846,10 +850,10 @@ class APITypeViewSet(viewsets.ModelViewSet):
     def get_queryset(self):
         """Filters"""
 
-        if self.request.GET.get('active') == 'true':
+        if self.request.query_params.get('active') == 'true':
             return Type.objects.filter(is_active=True)
 
-        if self.request.GET.get('active') == 'false':
+        if self.request.query_params.get('active') == 'false':
             return Type.objects.filter(is_active=False)
 
         return Type.objects.all()
@@ -869,10 +873,10 @@ class APITopicViewSet(viewsets.ModelViewSet):
     def get_queryset(self):
         """Filters"""
 
-        if self.request.GET.get('active') == 'true':
+        if self.request.query_params.get('active') == 'true':
             return Topic.objects.filter(is_active=True)
 
-        if self.request.GET.get('active') == 'false':
+        if self.request.query_params.get('active') == 'false':
             return Topic.objects.filter(is_active=False)
 
         return Topic.objects.all()
@@ -893,10 +897,10 @@ class APIMusicFocusViewSet(viewsets.ModelViewSet):
     def get_queryset(self):
         """Filters"""
 
-        if self.request.GET.get('active') == 'true':
+        if self.request.query_params.get('active') == 'true':
             return MusicFocus.objects.filter(is_active=True)
 
-        if self.request.GET.get('active') == 'false':
+        if self.request.query_params.get('active') == 'false':
             return MusicFocus.objects.filter(is_active=False)
 
         return MusicFocus.objects.all()
@@ -917,10 +921,10 @@ class APIFundingCategoryViewSet(viewsets.ModelViewSet):
     def get_queryset(self):
         """Filters"""
 
-        if self.request.GET.get('active') == 'true':
+        if self.request.query_params.get('active') == 'true':
             return FundingCategory.objects.filter(is_active=True)
 
-        if self.request.GET.get('active') == 'false':
+        if self.request.query_params.get('active') == 'false':
             return FundingCategory.objects.filter(is_active=False)
 
         return FundingCategory.objects.all()
@@ -941,10 +945,10 @@ class APILanguageViewSet(viewsets.ModelViewSet):
     def get_queryset(self):
         """Filters"""
 
-        if self.request.GET.get('active') == 'true':
+        if self.request.query_params.get('active') == 'true':
             return Language.objects.filter(is_active=True)
 
-        if self.request.GET.get('active') == 'false':
+        if self.request.query_params.get('active') == 'false':
             return Language.objects.filter(is_active=False)
 
         return Language.objects.all()
@@ -966,10 +970,10 @@ class APIHostViewSet(viewsets.ModelViewSet):
     def get_queryset(self):
         """Filters"""
 
-        if self.request.GET.get('active') == 'true':
+        if self.request.query_params.get('active') == 'true':
             return Host.objects.filter(is_active=True)
 
-        if self.request.GET.get('active') == 'false':
+        if self.request.query_params.get('active') == 'false':
             return Host.objects.filter(is_active=False)
 
         return Host.objects.all()
-- 
GitLab