Filter model and api

This commit is contained in:
Corban-Lee Jones 2024-04-30 01:11:47 +01:00
parent 7b2999fb81
commit cfe7962f14
4 changed files with 143 additions and 7 deletions

View File

@ -4,7 +4,7 @@ import logging
from rest_framework import serializers
from apps.home.models import SubChannel, Subscription, SavedGuilds
from apps.home.models import SubChannel, Filter, Subscription, SavedGuilds
log = logging.getLogger(__name__)
@ -118,6 +118,16 @@ class SubChannelSerializer(DynamicModelSerializer):
fields = ("id", "channel_id", "subscription")
class FilterSerializer(DynamicModelSerializer):
"""
Serializer for the Filter Model.
"""
class Meta:
model = Filter
fields = ("id", "name", "keywords", "regex", "guild_id")
class SubscriptionSerializer(DynamicModelSerializer):
"""
Serializer for the Subscription Model.

View File

@ -6,6 +6,8 @@ from rest_framework.authtoken.views import obtain_auth_token
from .views import (
SubChannel_ListView,
SubChannel_DetailView,
Filter_ListView,
Filter_DetailView,
Subscription_ListView,
Subscription_DetailView,
Subscription_SubChannelView,
@ -13,7 +15,6 @@ from .views import (
SavedGuild_DetailView
)
urlpatterns = [
path("api-auth/", include("rest_framework.urls", namespace="rest_framework")),
path("api-token-auth/", obtain_auth_token),
@ -23,6 +24,11 @@ urlpatterns = [
path("<str:pk>/", SubChannel_DetailView.as_view(), name="subchannel-detail")
])),
path("filter/", include([
path("", Filter_ListView.as_view(), name="filter"),
path("<str:pk>/", Filter_DetailView.as_view(), name="filter-detail")
])),
path("subscription/", include([
path("", Subscription_ListView.as_view(), name="subscription"),
path("<str:pk>/", include([
@ -35,4 +41,4 @@ urlpatterns = [
path("", SavedGuild_ListView.as_view(), name="saved-guilds"),
path("<int:pk>/", SavedGuild_DetailView.as_view(), name="saved-guilds-detail")
])),
]
]

View File

@ -11,9 +11,10 @@ from rest_framework.pagination import PageNumberPagination
from rest_framework.authentication import SessionAuthentication, TokenAuthentication
from rest_framework.parsers import MultiPartParser, FormParser
from apps.home.models import SubChannel, Subscription, SavedGuilds
from apps.home.models import SubChannel, Filter, Subscription, SavedGuilds
from .serializers import (
SubChannelSerializer,
FilterSerializer,
SubscriptionSerializer,
SavedGuildSerializer
)
@ -83,6 +84,76 @@ class SubChannel_DetailView(generics.RetrieveUpdateDestroyAPIView):
queryset = SubChannel.objects.all().order_by("id")
# =================================================================================================
# Filter Views
class Filter_ListView(generics.ListCreateAPIView):
"""
View to provide a list of Filter model instances.
Can also be used to create a new instance.
Supports: GET, POST
"""
authentication_classes = [SessionAuthentication, TokenAuthentication]
permission_classes = [permissions.IsAuthenticated]
pagination_class = DefaultPagination
serializer_class = FilterSerializer
filter_backends = [filters.SearchFilter, rest_filters.DjangoFilterBackend, filters.OrderingFilter]
filterset_fields = ["id", "name", "keywords", "regex", "guild_id"]
search_fields = ["name", "keywords", "regex"]
def get_queryset(self):
saved_guild_ids = SavedGuilds.objects \
.filter(added_by=self.request.user.id) \
.values("guild_id")
return Filter.objects \
.filter(guild_id__in=Subquery(saved_guild_ids)) \
.order_by("id")
def post(self, request):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
try:
self.perform_create(serializer)
except IntegrityError as err:
return Response(
{"detail": str(err)},
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
exception=True
)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
class Filter_DetailView(generics.RetrieveUpdateDestroyAPIView):
"""
View to provide details on a particular Filter model instances.
Supports: GET, PUT, PATCH, DELETE
"""
authentication_classes = [SessionAuthentication, TokenAuthentication]
permission_classes = [permissions.IsAuthenticated]
parser_classes = [MultiPartParser, FormParser]
serializer_class = FilterSerializer
def get_queryset(self):
saved_guild_ids = SavedGuilds.objects \
.filter(added_by=self.request.user.id) \
.values("guild_id")
return Filter.objects \
.filter(guild_id__in=Subquery(saved_guild_ids)) \
.order_by("id")
# =================================================================================================
# Subscription Views

View File

@ -5,10 +5,8 @@ from uuid import uuid4
from pathlib import Path
from django.db import models
from django.db.models import Q
from django.utils import timezone
from django.dispatch import receiver
from django.db.utils import IntegrityError
from django.db.models.signals import pre_save
from django.utils.translation import gettext_lazy as _
from django.core.files.storage import FileSystemStorage
from django.utils.deconstruct import deconstructible
@ -144,6 +142,57 @@ class SubChannel(models.Model):
]
class Filter(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(
max_length=32,
null=False,
blank=False
)
keywords = models.CharField(
maxlength=128,
null=True,
blank=True
)
regex = models.CharField(
max_length=128,
null=True,
blank=True
)
# Have to use charfield instead of positiveBigIntegerField due to an Sqlite
# issue that rounds down the value
# https://github.com/sequelize/sequelize/issues/9335
guild_id = models.CharField(
max_length=128
)
class Meta:
"""
Metadata for the Filter Model.
"""
verbose_name = "filter"
verbose_name_plural = "filters"
get_latest_by = "id"
constaints = [
models.CheckConstraint(
check=(
(Q(keywords__isnull=False) & Q(regex__isnull=True)) |
(Q(keywords__isnull=True) & Q(regex__isnull=False))
),
name="either keywords or regex null, other not null"
),
models.UniqueConstraint(
fields=["name", "guild_id"],
name="unique name & server pair")
]
class Subscription(models.Model):
id = models.AutoField(primary_key=True)