-
Konrad Mohrfeldt authored
There is no point in advertising the methods by inheriting from the default CRUD viewset, if we don’t actually intend to implement them.
Konrad Mohrfeldt authoredThere is no point in advertising the methods by inheriting from the default CRUD viewset, if we don’t actually intend to implement them.
views.py 30.23 KiB
#
# steering, Programme/schedule management for AURA
#
# Copyright (C) 2011-2017, 2020, Ernesto Rico Schmidt
# Copyright (C) 2017-2019, Ingo Leindecker
#
# This program 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.
#
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
#
import json
import logging
from datetime import date, datetime, time
from rest_framework import mixins, permissions, status, viewsets
from rest_framework.pagination import LimitOffsetPagination
from rest_framework.response import Response
from django.contrib.auth.models import User
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.utils import timezone
from django.utils.translation import gettext as _
from program import filters
from program.models import (
Category,
FundingCategory,
Host,
Language,
MusicFocus,
Note,
Schedule,
Show,
TimeSlot,
Topic,
Type,
)
from program.serializers import (
CategorySerializer,
FundingCategorySerializer,
HostSerializer,
LanguageSerializer,
MusicFocusSerializer,
NoteSerializer,
ScheduleSerializer,
ShowSerializer,
TimeSlotSerializer,
TopicSerializer,
TypeSerializer,
UserSerializer,
)
from program.utils import get_pk_and_slug, get_values, parse_date
logger = logging.getLogger(__name__)
def json_day_schedule(request, year=None, month=None, day=None):
if year is None and month is None and day is None:
today = timezone.make_aware(datetime.combine(timezone.now(), time(0, 0)))
else:
today = timezone.make_aware(
datetime.combine(date(year, month, day), time(0, 0))
)
timeslots = (
TimeSlot.objects.get_24h_timeslots(today)
.select_related("schedule")
.select_related("show")
)
schedule = []
for ts in timeslots:
entry = {
"start": ts.start.strftime("%Y-%m-%d_%H:%M:%S"),
"end": ts.end.strftime("%Y-%m-%d_%H:%M:%S"),
"title": ts.show.name,
"id": ts.show.id,
}
schedule.append(entry)
return HttpResponse(
json.dumps(schedule, ensure_ascii=False).encode("utf8"),
content_type="application/json; charset=utf-8",
)
def json_playout(request):
"""
Called by
- engine (playout) to retrieve timeslots within a given timerange
Expects GET variables 'start' (date) and 'end' (date).
If start not given, it will be today
- internal calendar to retrieve all timeslots for a week
Expects GET variable 'start' (date), otherwise start will be today
If end not given, it returns all timeslots of the next 7 days
"""
if request.GET.get("start") is None:
start = timezone.make_aware(datetime.combine(timezone.now(), time(0, 0)))
else:
start = timezone.make_aware(
datetime.combine(parse_date(request.GET.get("start")), time(0, 0))
)
if request.GET.get("end") is None:
# If no end was given, return the next week
timeslots = (
TimeSlot.objects.get_7d_timeslots(start)
.select_related("schedule")
.select_related("show")
)
else:
# Otherwise return the given timerange
end = timezone.make_aware(
datetime.combine(parse_date(request.GET.get("end")), time(23, 59))
)
timeslots = (
TimeSlot.objects.get_timerange_timeslots(start, end)
.select_related("schedule")
.select_related("show")
)
schedule = []
for ts in timeslots:
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("name", flat=True))
topics = ", ".join(ts.show.topic.values_list("name", flat=True))
music_focus = ", ".join(ts.show.music_focus.values_list("name", flat=True))
languages = ", ".join(ts.show.language.values_list("name", flat=True))
funding_category = (
FundingCategory.objects.get(pk=ts.show.funding_category_id)
if ts.show.funding_category_id
else None
)
type_ = Type.objects.get(pk=ts.show.type_id)
classname = "default"
if ts.playlist_id is None or ts.playlist_id == 0:
classname = "danger"
entry = {
"id": ts.id,
"start": ts.start.strftime("%Y-%m-%dT%H:%M:%S"),
"end": ts.end.strftime("%Y-%m-%dT%H:%M:%S"),
"title": ts.show.name + is_repetition, # For JS Calendar
"schedule_id": ts.schedule.id,
"is_repetition": ts.is_repetition,
"playlist_id": ts.playlist_id,
"schedule_default_playlist_id": ts.schedule.default_playlist_id,
"show_default_playlist_id": ts.show.default_playlist_id,
"show_id": ts.show.id,
"show_name": ts.show.name + is_repetition,
"show_hosts": hosts,
"show_type": type_.name,
"show_categories": categories,
"show_topics": topics,
# TODO: replace `show_musicfocus` with `show_music_focus` when engine is updated
"show_musicfocus": music_focus,
"show_languages": languages,
# TODO: replace `show_fundingcategory` with `show_funding_category` when engine is
# updated
"show_fundingcategory": funding_category.name,
"memo": ts.memo,
"className": classname,
}
schedule.append(entry)
return HttpResponse(
json.dumps(schedule, ensure_ascii=False).encode("utf8"),
content_type="application/json; charset=utf-8",
)
class APIUserViewSet(
mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.ListModelMixin,
viewsets.GenericViewSet,
):
"""
/users returns oneself. Superusers see all users. Only superusers may create a user (GET, POST)
/users/{pk} retrieves or updates a single user. Non-superusers may only update certain fields
(GET, PUT)
Superusers may access and update all users.
"""
permission_classes = [permissions.DjangoModelPermissionsOrAnonReadOnly]
serializer_class = UserSerializer
queryset = User.objects.none()
def get_queryset(self):
"""Constrain access to oneself except for superusers"""
if self.request.user.is_superuser:
return User.objects.all()
return User.objects.filter(pk=self.request.user.id)
def retrieve(self, request, *args, **kwargs):
"""Returns a single user"""
pk = get_values(self.kwargs, "pk")
# Common users only see themselves
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)
serializer = UserSerializer(user)
return Response(serializer.data)
def create(self, request, *args, **kwargs):
"""
Create a User
Only superusers may create a user
"""
if not request.user.is_superuser:
return Response(status=status.HTTP_401_UNAUTHORIZED)
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def update(self, request, *args, **kwargs):
pk = get_values(self.kwargs, "pk")
serializer = UserSerializer(data=request.data)
# Common users may only edit themselves
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)
serializer = UserSerializer(
user, data=request.data, context={"user": request.user}
)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class APIShowViewSet(viewsets.ModelViewSet):
"""
Returns a list of available shows.
Only superusers may add and delete shows.
"""
queryset = Show.objects.all()
serializer_class = ShowSerializer
permission_classes = [permissions.DjangoModelPermissionsOrAnonReadOnly]
pagination_class = LimitOffsetPagination
filterset_class = filters.ShowFilterSet
def create(self, request, *args, **kwargs):
"""
Create a show.
Only superusers may create a show.
"""
if not request.user.is_superuser:
return Response(status=status.HTTP_401_UNAUTHORIZED)
serializer = ShowSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def retrieve(self, request, *args, **kwargs):
"""Returns a single show"""
pk, slug = get_pk_and_slug(self.kwargs)
show = (
get_object_or_404(Show, pk=pk)
if pk
else get_object_or_404(Show, slug=slug)
if slug
else None
)
serializer = ShowSerializer(show)
return Response(serializer.data)
def update(self, request, *args, **kwargs):
"""
Update a show.
Common users may only update shows they own.
"""
pk = get_values(self.kwargs, "pk")
if not request.user.is_superuser and pk not in request.user.shows.values_list(
"id", flat=True
):
return Response(status=status.HTTP_401_UNAUTHORIZED)
show = get_object_or_404(Show, pk=pk)
serializer = ShowSerializer(
show, data=request.data, context={"user": request.user}
)
if serializer.is_valid():
# Common users mustn't edit the show's name
if not request.user.is_superuser:
serializer.validated_data["name"] = show.name
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def destroy(self, request, *args, **kwargs):
"""
Delete a show.
Only superusers may delete shows.
"""
if not request.user.is_superuser:
return Response(status=status.HTTP_401_UNAUTHORIZED)
pk = get_values(self.kwargs, "pk")
Show.objects.get(pk=pk).delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class APIScheduleViewSet(viewsets.ModelViewSet):
"""
/schedules/ returns all schedules (GET)
/schedules/{pk} returns the given schedule (GET)
/shows/{show_pk}/schedules returns schedules of the show (GET, POST)
/shows/{show_pk}/schedules/{pk} returns schedules by its ID (GET, PUT, DELETE)
Only superusers may create and update schedules
"""
queryset = Schedule.objects.none()
serializer_class = ScheduleSerializer
permission_classes = [permissions.DjangoModelPermissionsOrAnonReadOnly]
def get_queryset(self):
show_pk = get_values(self.kwargs, "show_pk")
if show_pk:
return Schedule.objects.filter(show=show_pk)
return Schedule.objects.all()
def retrieve(self, request, *args, **kwargs):
pk, show_pk = get_values(self.kwargs, "pk", "show_pk")
schedule = (
get_object_or_404(Schedule, pk=pk, show=show_pk)
if show_pk
else get_object_or_404(Schedule, pk=pk)
)
serializer = ScheduleSerializer(schedule)
return Response(serializer.data)
def create(self, request, *args, **kwargs):
"""
Create a schedule, generate timeslots, test for collisions and resolve them including notes
Only superusers may add schedules
TODO: Perhaps directly insert into database if no conflicts found
"""
if not request.user.is_superuser:
return Response(status=status.HTTP_401_UNAUTHORIZED)
pk, show_pk = get_values(self.kwargs, "pk", "show_pk")
# Only allow creating when calling /shows/{show_pk}/schedules/ and with ehe `schedule` JSON
# object
if show_pk is None or "schedule" not in request.data:
return Response(status=status.HTTP_400_BAD_REQUEST)
# First create submit -> return projected timeslots and collisions
if "solutions" not in request.data:
return Response(
Schedule.make_conflicts(request.data["schedule"], pk, show_pk),
status=status.HTTP_409_CONFLICT,
)
# Otherwise try to resolve
resolution = Schedule.resolve_conflicts(request.data, pk, show_pk)
# If resolution went well
if "projected" not in resolution:
return Response(resolution, status=status.HTTP_201_CREATED)
# Otherwise return conflicts
return Response(resolution, status=status.HTTP_409_CONFLICT)
def update(self, request, *args, **kwargs):
"""
Update a schedule, generate timeslots, test for collisions and resolve them including notes
Only superusers may update schedules
"""
if not request.user.is_superuser:
return Response(status=status.HTTP_401_UNAUTHORIZED)
pk, show_pk = get_values(self.kwargs, "pk", "show_pk")
# Only allow updating when calling /shows/{show_pk}/schedules/{pk}/ and with the `schedule`
# JSON object
if show_pk is None or "schedule" not in request.data:
return Response(status=status.HTTP_400_BAD_REQUEST)
# If default playlist id or repetition are given, just update
if default_playlist_id := request.data.get("schedule").get(
"default_playlist_id"
):
schedule = get_object_or_404(Schedule, pk=pk, show=show_pk)
schedule.default_playlist_id = int(default_playlist_id)
schedule.save()
serializer = ScheduleSerializer(schedule)
return Response(serializer.data)
if is_repetition := request.data.get("schedule").get("is_repetition"):
schedule = get_object_or_404(Schedule, pk=pk, show=show_pk)
schedule.is_repetition = bool(is_repetition)
schedule.save()
serializer = ScheduleSerializer(schedule)
return Response(serializer.data)
# First update submit -> return projected timeslots and collisions
if "solutions" not in request.data:
return Response(
Schedule.make_conflicts(request.data["schedule"], pk, show_pk),
status=status.HTTP_409_CONFLICT,
)
# Otherwise try to resolve
resolution = Schedule.resolve_conflicts(request.data, pk, show_pk)
# If resolution went well
if "projected" not in resolution:
return Response(resolution)
# Otherwise return conflicts
return Response(resolution, status=status.HTTP_409_CONFLICT)
def destroy(self, request, *args, **kwargs):
"""
Delete a schedule
Only superusers may delete schedules
"""
if not request.user.is_superuser:
return Response(status=status.HTTP_401_UNAUTHORIZED)
pk, show_pk = get_values(self.kwargs, "pk", "show_pk")
# Only allow deleting when calling /shows/{show_pk}/schedules/{pk}
if show_pk is None:
return Response(status=status.HTTP_400_BAD_REQUEST)
Schedule.objects.get(pk=pk).delete()
return Response(status=status.HTTP_204_NO_CONTENT)
# TODO: Create is currently not implemented because timeslots are supposed to be inserted
# by creating or updating a schedule.
# There might be a use case for adding a single timeslot without any conflicts though.
class APITimeSlotViewSet(
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
viewsets.GenericViewSet,
):
"""
Returns a list of timeslots.
By default, only timeslots ranging from now + 60 days will be displayed.
You may override this default overriding start and/or end parameter.
Timeslots may only be added by creating/updating a schedule.
"""
permission_classes = [permissions.DjangoModelPermissionsOrAnonReadOnly]
serializer_class = TimeSlotSerializer
pagination_class = LimitOffsetPagination
queryset = TimeSlot.objects.all().order_by("-start")
filterset_class = filters.TimeSlotFilterSet
def get_queryset(self):
queryset = super().get_queryset()
# subroute filters
show_pk, schedule_pk = get_values(self.kwargs, "show_pk", "schedule_pk")
if show_pk:
queryset = queryset.filter(show=show_pk)
if schedule_pk:
queryset = queryset.filter(schedule=schedule_pk)
return queryset
def retrieve(self, request, *args, **kwargs):
pk, show_pk = get_values(self.kwargs, "pk", "show_pk")
if show_pk:
timeslot = get_object_or_404(TimeSlot, pk=pk, show=show_pk)
else:
timeslot = get_object_or_404(TimeSlot, pk=pk)
serializer = TimeSlotSerializer(timeslot)
return Response(serializer.data)
def update(self, request, *args, **kwargs):
"""Link a playlist_id to a timeslot"""
pk, show_pk, schedule_pk = get_values(
self.kwargs, "pk", "show_pk", "schedule_pk"
)
if (
not request.user.is_superuser
and show_pk not in request.user.shows.values_lis("id", flat=True)
):
return Response(status=status.HTTP_401_UNAUTHORIZED)
# 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:
return Response(status=status.HTTP_400_BAD_REQUEST)
timeslot = get_object_or_404(
TimeSlot, pk=pk, schedule=schedule_pk, show=show_pk
)
serializer = TimeSlotSerializer(timeslot, data=request.data)
if serializer.is_valid():
serializer.save()
# Return the next repetition
# We do this because the Dashboard needs to update the repetition timeslot as well
# but with another playlist containing the recording instead of the original playlist
ts = TimeSlot.objects.filter(show=show_pk, start__gt=timeslot.start)[0]
if ts.is_repetition:
serializer = TimeSlotSerializer(ts)
return Response(serializer.data)
# ...or nothing if there isn't one
return Response(status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def destroy(self, request, *args, **kwargs):
"""
Deletes a timeslot.
Only superusers may delete timeslots.
"""
if not request.user.is_superuser:
return Response(status=status.HTTP_401_UNAUTHORIZED)
pk, show_pk = get_values(self.kwargs, "pk", "show_pk")
# Only allow when calling endpoint starting with /shows/1/...
if show_pk is None:
return Response(status=status.HTTP_400_BAD_REQUEST)
TimeSlot.objects.get(pk=pk).delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class APINoteViewSet(viewsets.ModelViewSet):
"""
/notes/ returns all notes (GET)
/notes/{pk} returns a single note (if owned) (GET)
/notes/?ids={...} returns given notes (if owned) (GET)
/notes/?host={host} returns notes assigned to a given host (GET)
/notes/?owner={owner} returns notes editable by a given user (GET)
/notes/?user={user} returns notes created by a given user (GET)
/shows/{show_pk}/notes returns all notes of a show (GET)
/shows/{show_pk}/notes/{pk} returns a note by its ID (GET)
/shows/{show_pk}/timeslots/{timeslot_pk}/note/ returns a note of the timeslot (GET)
/shows/{show_pk}/timeslots/{timeslot_pk}/note/{pk} returns a note by its ID (GET)
/shows/{show_pk}/schedules/{schedule_pk}/timeslots/{timeslot_pk}/note returns a note to the
timeslot (GET, POST).
/shows/{show_pk}/schedules/{schedule_pk}/timeslots/{timeslot_pk}/note/{pk} returns a note by
its ID (GET, PUT, DELETE)
Superusers may access and update all notes
"""
queryset = Note.objects.none()
serializer_class = NoteSerializer
permission_classes = [permissions.DjangoModelPermissionsOrAnonReadOnly]
pagination_class = LimitOffsetPagination
def get_queryset(self):
timeslot_pk, show_pk = get_values(self.kwargs, "timeslot_pk", "show_pk")
# Endpoints
#
# /shows/1/schedules/1/timeslots/1/note
# /shows/1/timeslots/1/note
#
# Return a note to the timeslot
#
if show_pk and timeslot_pk:
notes = Note.objects.filter(show=show_pk, timeslot=timeslot_pk)
#
# /shows/1/notes
#
# Returns notes to the show
#
elif show_pk and timeslot_pk is None:
notes = Note.objects.filter(show=show_pk)
#
# /notes
#
# Returns all notes
#
else:
notes = Note.objects.all()
# Filters
if ids := self.request.query_params.get("ids"):
# Filter notes by their IDs
note_ids = list(map(int, ids.split(",")))
notes = notes.filter(id__in=note_ids)
if host := self.request.query_params.get("host"):
# Filter notes by host
notes = notes.filter(host=int(host))
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(owner))
notes = notes.filter(show__in=shows)
if user := self.request.query_params.get("user"):
# Filter notes by their creator
notes = notes.filter(user=int(user))
return notes
def create(self, request, *args, **kwargs):
"""Create a note"""
show_pk, schedule_pk, timeslot_pk = get_values(
self.kwargs, "show_pk", "schedule_pk", "timelost_pk"
)
if (
not request.user.is_superuser
and show_pk not in request.user.shows.values_list("id", flat=True)
):
return Response(status=status.HTTP_401_UNAUTHORIZED)
# 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:
return Response(status=status.HTTP_400_BAD_REQUEST)
serializer = NoteSerializer(
data=request.data, context={"user_id": request.user.id}
)
if serializer.is_valid():
hosts = Host.objects.filter(
shows__in=request.user.shows.values_list("id", flat=True)
)
if not request.user.is_superuser and request.data["host"] not in hosts:
serializer.validated_data["host"] = None
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def retrieve(self, request, *args, **kwargs):
"""
Returns a single note
Called by:
/notes/1
/shows/1/notes/1
/shows/1/timeslots/1/note/1
/shows/1/schedules/1/timeslots/1/note/1
"""
pk, show_pk, schedule_pk, timeslot_pk = get_values(
self.kwargs, "pk", "show_pk", "schedule_pk", "timeslot_pk"
)
#
# /shows/1/notes/1
#
# Returns a note to a show
#
if show_pk and timeslot_pk is None and schedule_pk is None:
note = get_object_or_404(Note, pk=pk, show=show_pk)
#
# /shows/1/timeslots/1/note/1
# /shows/1/schedules/1/timeslots/1/note/1
#
# Return a note to a timeslot
#
elif show_pk and timeslot_pk:
note = get_object_or_404(Note, pk=pk, show=show_pk, timeslot=timeslot_pk)
#
# /notes/1
#
# Returns the given note
#
else:
note = get_object_or_404(Note, pk=pk)
serializer = NoteSerializer(note)
return Response(serializer.data)
def update(self, request, *args, **kwargs):
pk, show_pk, schedule_pk, timeslot_pk = get_values(
self.kwargs, "pk", "show_pk", "schedule_pk", "timeslot_pk"
)
if (
not request.user.is_superuser
and show_pk not in request.user.shows.values_list("id", flat=True)
):
return Response(status=status.HTTP_401_UNAUTHORIZED)
# Allow PUT only when calling
# /shows/{show_pk}/schedules/{schedule_pk}/timeslots/{timeslot_pk}/note/{pk}
if show_pk is None or schedule_pk is None or timeslot_pk is None:
return Response(status=status.HTTP_400_BAD_REQUEST)
note = get_object_or_404(Note, pk=pk, timeslot=timeslot_pk, show=show_pk)
serializer = NoteSerializer(note, data=request.data)
if serializer.is_valid():
hosts = Host.objects.filter(
shows__in=request.user.shows.values_list("id", flat=True)
)
# Don't assign a host the user mustn't edit. Reassign the original value instead
if not request.user.is_superuser and int(request.data["host"]) not in hosts:
serializer.validated_data["host"] = Host.objects.filter(
pk=note.host_id
)[0]
serializer.save()
return Response(serializer.data)
return Response(status=status.HTTP_400_BAD_REQUEST)
def destroy(self, request, *args, **kwargs):
pk, show_pk, schedule_pk, timeslot_pk = get_values(
self.kwargs, "pk", "show_pk", "schedule_pk", "timeslot_pk"
)
if (
not request.user.is_superuser
and show_pk not in request.user.shows.values_list("id", flat=True)
):
return Response(status=status.HTTP_401_UNAUTHORIZED)
if pk is None or show_pk is None or schedule_pk is None or timeslot_pk is None:
return Response(status=status.HTTP_400_BAD_REQUEST)
Note.objects.get(pk=pk).delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class ActiveInactiveViewSet(viewsets.ModelViewSet):
permission_classes = [permissions.DjangoModelPermissionsOrAnonReadOnly]
def get_queryset(self: viewsets.ModelViewSet):
"""Filters"""
if self.request.query_params.get("active") == "true":
return self.queryset.model.objects.filter(is_active=True)
if self.request.query_params.get("active") == "false":
return self.queryset.model.objects.filter(is_active=False)
return self.queryset.model.objects.all()
class APICategoryViewSet(ActiveInactiveViewSet):
"""
/categories/ returns all categories (GET, POST)
/categories/?active=true returns all active categories (GET)
/categories/?active=false returns all inactive categories (GET)
/categories/{pk} Returns a category by its ID (GET, PUT, DELETE)
"""
queryset = Category.objects.all()
serializer_class = CategorySerializer
class APITypeViewSet(ActiveInactiveViewSet):
"""
/types/ returns all types (GET, POST)
/types/?active=true returns all active types (GET)
/types/?active=false returns all inactive types (GET)
/types/{pk} returns a type by its ID (GET, PUT, DELETE)
"""
queryset = Type.objects.all()
serializer_class = TypeSerializer
class APITopicViewSet(ActiveInactiveViewSet):
"""
/topics/: Returns all topics (GET, POST)
/topics/?active=true Returns all active topics (GET)
/topics/?active=false Returns all inactive topics (GET)
/topics/{pk}: Returns a topic by its ID (GET, PUT, DELETE)
"""
queryset = Topic.objects.all()
serializer_class = TopicSerializer
class APIMusicFocusViewSet(ActiveInactiveViewSet):
"""
/musicfocus/ returns all music focuses (GET, POST)
/musicfocus/?active=true: returns all active music focuses (GET)
/musicfocus/?active=false: returns all inactive music focuses (GET)
/musicfocus/{pk}: returns a music focus by its ID (GET, PUT, DELETE)
"""
queryset = MusicFocus.objects.all()
serializer_class = MusicFocusSerializer
class APIFundingCategoryViewSet(ActiveInactiveViewSet):
"""
/fundingcategories/: returns all funding categories (GET, POST)
/fundingcategories/?active=true returns all active funding categories (GET)
/fundingcategories/?active=false returns all inactive funding categories (GET)
/fundingcategories/{pk} returns a funding category by its ID (GET, PUT, DELETE)
"""
queryset = FundingCategory.objects.all()
serializer_class = FundingCategorySerializer
class APILanguageViewSet(ActiveInactiveViewSet):
"""
/languages/ returns all languages (GET, POST)
/languages/?active=true returns all active languages (GET)
/languages/?active=false returns all inactive languages (GET)
/languages/{pk} returns a language by its ID (GET, PUT, DELETE)
"""
queryset = Language.objects.all()
serializer_class = LanguageSerializer
class APIHostViewSet(ActiveInactiveViewSet):
"""
/hosts/ returns all hosts (GET, POST)
/hosts/?active=true returns all active hosts (GET)
/hosts/?active=false returns all inactive hosts (GET)
/hosts/{pk} returns a host by its ID (GET, PUT, DELETE)
"""
queryset = Host.objects.all()
serializer_class = HostSerializer
pagination_class = LimitOffsetPagination