rewrite models and api

This commit is contained in:
Corban-Lee Jones 2024-09-19 12:25:18 +01:00
parent 454ba77908
commit 345f70d30f
6 changed files with 586 additions and 48 deletions

View File

@ -12,7 +12,16 @@ from apps.home.models import (
TrackedContent,
ArticleMutator,
GuildSettings,
UniqueContentRule
UniqueContentRule,
#rewrite
r_Server,
r_ContentFilter,
r_MessageMutator,
r_MessageStyle,
r_Subscription,
r_Content,
r_UniqueContentRule
)
log = logging.getLogger(__name__)
@ -248,3 +257,89 @@ class TrackedContentSerializer_POST(DynamicModelSerializer):
class Meta:
model = TrackedContent
fields = ("id", "guid", "title", "url", "subscription", "channel_id", "message_id", "blocked", "creation_datetime")
# rewrite
class r_ServerSerialiszer(DynamicModelSerializer):
class Meta:
model = r_Server
fields = ("id", "name", "icon_hash", "active")
class r_ContentFilterSerializer(DynamicModelSerializer):
class Meta:
model = r_ContentFilter
fields = (
"id",
"server",
"name",
"match",
"matching_algorithm",
"is_insensitive",
"is_whitelist"
)
class r_MessageMutatorSerializer(DynamicModelSerializer):
class Meta:
model = r_MessageMutator
fields = ("id", "name", "value")
class r_MessageStyleSerializer(DynamicModelSerializer):
class Meta:
model = r_MessageStyle
fields = (
"id",
"server",
"is_embed",
"is_hyperlinked",
"show_author",
"show_timestamp",
"show_images",
"fetch_images",
"title_mutator",
"description_mutator"
)
class r_SubscriptionSerializer(DynamicModelSerializer):
class Meta:
model = r_Subscription
fields = (
"id",
"server",
"name",
"url",
"created_at",
"updated_at",
"extra_notes",
"active",
"filters",
"message_style"
)
class r_ContentSerializer(DynamicModelSerializer):
class Meta:
model = r_Content
fields = (
"id",
"subscription",
"item_id",
"item_guid",
"item_url",
"item_title",
"item_content_hash"
)
class r_UniqueContentRuleSerializer(DynamicModelSerializer):
class Meta:
model = r_UniqueContentRule
fields = ("id", "name", "value")

View File

@ -20,7 +20,23 @@ from .views import (
GuildSettings_ListView,
GuildSettings_DetailView,
UniqueContentRule_ListView,
UniqueContentRule_DetailView
UniqueContentRule_DetailView,
#rewrite
r_Server_ListView,
r_Server_DetailView,
r_ContentFilter_ListView,
r_ContentFilter_DetailView,
r_MessageMutator_ListView,
r_MessageMutator_DetailView,
r_MessageStyle_ListView,
r_MessageStyle_DetailView,
r_Subscription_ListView,
r_Subscription_DetailView,
r_Content_ListView,
r_Content_DetailView,
r_UniqueContentRule_ListView,
r_UniqueContentRule_DetailView
)
urlpatterns = [
@ -69,4 +85,41 @@ urlpatterns = [
path("", UniqueContentRule_ListView.as_view(), name="unique-content-rule"),
path("<int:pk>/", UniqueContentRule_DetailView.as_view(), name="unique-content-rule-detail")
])),
#region rewrite
path("r_servers/", include([
path("", r_Server_ListView.as_view()),
path("<int:pk>/", r_Server_DetailView.as_view())
])),
# path("r_content-filters/", include([
# path(""),
# path("<int:pk>/")
# ])),
# path("r_message-mutators/", include([
# path(""),
# path("<int:pk>/")
# ])),
# path("r_message-styles/", include([
# path(""),
# path("<int:pk>/")
# ])),
# path("r_subscriptions/", include([
# path(""),
# path("<int:pk>/")
# ])),
# path("r_content/", include([
# path(""),
# path("<int:pk>/")
# ])),
# path("r_unique-content-rules/", include([
# path(""),
# path("<int:pk>/")
# ]))
]

View File

@ -11,7 +11,25 @@ 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, Filter, Subscription, SavedGuilds, TrackedContent, ArticleMutator, GuildSettings, UniqueContentRule
from apps.home.models import (
SubChannel,
Filter,
Subscription,
SavedGuilds,
TrackedContent,
ArticleMutator,
GuildSettings,
UniqueContentRule,
#rewrite
r_Server,
r_ContentFilter,
r_MessageMutator,
r_MessageStyle,
r_Subscription,
r_Content,
r_UniqueContentRule
)
from apps.authentication.models import DiscordUser
from .metadata import ExpandedMetadata
from .serializers import (
@ -24,7 +42,16 @@ from .serializers import (
TrackedContentSerializer_POST,
ArticleMutatorSerializer,
GuildSettingsSerializer,
UniqueContentRuleSerializer
UniqueContentRuleSerializer,
#rewrite
r_ServerSerialiszer,
r_ContentFilterSerializer,
r_MessageMutatorSerializer,
r_MessageStyleSerializer,
r_SubscriptionSerializer,
r_ContentSerializer,
r_UniqueContentRuleSerializer
)
log = logging.getLogger(__name__)
@ -642,3 +669,159 @@ class ArticleMutator_DetailView(generics.RetrieveAPIView):
serializer_class = ArticleMutatorSerializer
queryset = ArticleMutator.objects.all().order_by("id")
#region rewrite
class ListView(generics.ListAPIView):
authentication_classes = [SessionAuthentication, TokenAuthentication]
permission_classes = [permissions.IsAuthenticated]
pagination_class = DefaultPagination
metadata_class = ExpandedMetadata
filter_backends = [filters.SearchFilter, rest_filters.DjangoFilterBackend, filters.OrderingFilter]
class ListCreateView(generics.ListCreateAPIView):
authentication_classes = [SessionAuthentication, TokenAuthentication]
permission_classes = [permissions.IsAuthenticated]
pagination_class = DefaultPagination
metadata_class = ExpandedMetadata
filter_backends = [filters.SearchFilter, rest_filters.DjangoFilterBackend, filters.OrderingFilter]
class DetailView(generics.RetrieveAPIView):
authentication_classes = [SessionAuthentication, TokenAuthentication]
permission_classes = [permissions.IsAuthenticated]
parser_classes = [MultiPartParser, FormParser]
class ChangableDetailView(generics.RetrieveUpdateDestroyAPIView):
authentication_classes = [SessionAuthentication, TokenAuthentication]
permission_classes = [permissions.IsAuthenticated]
parser_classes = [MultiPartParser, FormParser]
class DeletableDetailView(generics.RetrieveDestroyAPIView):
authentication_classes = [SessionAuthentication, TokenAuthentication]
permission_classes = [permissions.IsAuthenticated]
parser_classes = [MultiPartParser, FormParser]
class r_Server_ListView(ListCreateView): # maybe change to ListView only later, and create through secure backend means?
filterset_fields = []
search_fields = []
ordering_fields = []
serializer_class = r_ServerSerialiszer
def get_queryset(self):
return r_Server.objects.all()
class r_Server_DetailView(ChangableDetailView): # maybe change to ListView only later, and create through secure backend means?
serializer_class = r_ServerSerialiszer
def get_queryset(self):
return r_Server.objects.all()
class r_ContentFilter_ListView(ListCreateView):
filterset_fields = []
search_fields = []
ordering_fields = []
serializer_class = r_ContentFilterSerializer
def get_queryset(self):
return r_ContentFilter.objects.all()
class r_ContentFilter_DetailView(ChangableDetailView):
serializer_class = r_ContentFilterSerializer
def get_queryset(self):
return r_ContentFilter.objects.all()
class r_MessageMutator_ListView(): # instances of this one are pre-defined ONLY
filterset_fields = []
search_fields = []
ordering_fields = []
serializer_class = r_MessageMutatorSerializer
def get_queryset(self):
return r_MessageMutator.objects.all()
class r_MessageMutator_DetailView(DetailView):
serializer_class = r_MessageMutatorSerializer
def get_queryset(self):
return r_MessageMutator.objects.all()
class r_MessageStyle_ListView(ListCreateView):
filterset_fields = []
search_fields = []
ordering_fields = []
serializer_class = r_MessageStyleSerializer
def get_queryset(self):
return r_MessageStyle.objects.all()
class r_MessageStyle_DetailView(ChangableDetailView):
serializer_class = r_MessageStyleSerializer
def get_queryset(self):
return r_MessageStyle.objects.all()
class r_Subscription_ListView(ListCreateView):
filterset_fields = []
search_fields = []
ordering_fields = []
serializer_class = r_SubscriptionSerializer
def get_queryset(self):
return r_Subscription.objects.all()
class r_Subscription_DetailView(ChangableDetailView):
serializer_class = r_SubscriptionSerializer
def get_queryset(self):
return r_Subscription.objects.all()
class r_Content_ListView(ListCreateView):
filterset_fields = []
search_fields = []
ordering_fields = []
serializer_class = r_ContentSerializer
def get_queryset(self):
return r_Content.objects.all()
class r_Content_DetailView(ChangableDetailView):
serializer_class = r_ContentSerializer
def get_queryset(self):
return r_Content.objects.all()
class r_UniqueContentRule_ListView(ListCreateView):
filterset_fields = []
search_fields = []
ordering_fields = []
serializer_class = r_UniqueContentRuleSerializer
def get_queryset(self):
return r_UniqueContentRule.objects.all()
class r_UniqueContentRule_DetailView(ChangableDetailView):
serializer_class = r_UniqueContentRuleSerializer
def get_queryset(self):
return r_UniqueContentRule.objects.all()

View File

@ -2,7 +2,24 @@
from django.contrib import admin
from .models import Subscription, SavedGuilds, Filter, SubChannel, TrackedContent, ArticleMutator, GuildSettings
from .models import (
Subscription,
SavedGuilds,
Filter,
SubChannel,
TrackedContent,
ArticleMutator,
GuildSettings,
# temp rewrite
r_Server,
r_ContentFilter,
r_MessageMutator,
r_MessageStyle,
r_Subscription,
r_Content,
r_UniqueContentRule
)
@admin.register(Subscription)
@ -51,3 +68,41 @@ class GuildSettingsAdmin(admin.ModelAdmin):
list_display = [
"id", "guild_id", "default_embed_colour", "active"
]
#region rewrite
@admin.register(r_Server)
class r_ServerAdmin(admin.ModelAdmin):
pass
@admin.register(r_ContentFilter)
class r_ContentFilterAdmin(admin.ModelAdmin):
pass
@admin.register(r_MessageMutator)
class r_MessageMutatorAdmin(admin.ModelAdmin):
pass
@admin.register(r_MessageStyle)
class r_MessageStyleAdmin(admin.ModelAdmin):
pass
@admin.register(r_Subscription)
class r_Subscription(admin.ModelAdmin):
pass
@admin.register(r_Content)
class r_ContentAdmin(admin.ModelAdmin):
pass
@admin.register(r_UniqueContentRule)
class r_UniqueContentRule(admin.ModelAdmin):
pass

View File

@ -0,0 +1,104 @@
# Generated by Django 5.0.4 on 2024-09-18 20:26
import django.db.models.deletion
import django.utils.timezone
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('home', '0025_set_uniquerules'),
]
operations = [
migrations.CreateModel(
name='r_MessageMutator',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=64)),
('value', models.CharField(max_length=32)),
],
),
migrations.CreateModel(
name='r_Server',
fields=[
('id', models.PositiveIntegerField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=128)),
('icon_hash', models.CharField(max_length=128)),
('active', models.BooleanField(default=True)),
],
),
migrations.CreateModel(
name='r_UniqueContentRule',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=64)),
('value', models.CharField(max_length=32)),
],
),
migrations.CreateModel(
name='r_MessageStyle',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('is_embed', models.BooleanField(default=True)),
('is_hyperlinked', models.BooleanField()),
('show_author', models.BooleanField()),
('show_timestamp', models.BooleanField()),
('show_images', models.BooleanField()),
('fetch_images', models.BooleanField()),
('description_mutator', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='desc_mutated_messagestyle', to='home.r_messagemutator')),
('title_mutator', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='title_mutated_messagestyle', to='home.r_messagemutator')),
('server', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='home.r_server')),
],
),
migrations.CreateModel(
name='r_ContentFilter',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=32)),
('match', models.CharField(max_length=256)),
('matching_algorithm', models.PositiveIntegerField(choices=[(0, 'None'), (1, 'Any: Item contains any of these words (space separated)'), (2, 'All: Item contains all of these words (space separated)'), (3, 'Exact: Item contains this string'), (4, 'Regular expression: Item matches this regex'), (5, 'Fuzzy: Item contains a word similar to this word')])),
('is_insensitive', models.BooleanField()),
('is_whitelist', models.BooleanField()),
('server', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='home.r_server')),
],
),
migrations.CreateModel(
name='BotLogicLogs',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('level', models.CharField(max_length=32)),
('message', models.CharField(max_length=256)),
('created_at', models.DateTimeField(default=django.utils.timezone.now, editable=False)),
('server', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='home.r_server')),
],
),
migrations.CreateModel(
name='r_Subscription',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=32)),
('url', models.URLField()),
('created_at', models.DateTimeField(default=django.utils.timezone.now, editable=False)),
('updated_at', models.DateTimeField(default=django.utils.timezone.now)),
('extra_notes', models.CharField(blank=True, default='', max_length=250)),
('active', models.BooleanField(default=True)),
('filters', models.ManyToManyField(blank=True, to='home.r_contentfilter')),
('message_style', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='home.r_messagestyle')),
('server', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='home.r_server')),
],
),
migrations.CreateModel(
name='r_Content',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('item_id', models.CharField(max_length=1024)),
('item_guid', models.CharField(max_length=1024)),
('item_url', models.CharField(max_length=1024)),
('item_title', models.CharField(max_length=1024)),
('item_content_hash', models.CharField(max_length=1024)),
('subscription', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='home.r_subscription')),
],
),
]

View File

@ -1,12 +1,10 @@
# -*- encoding: utf-8 -*-
import logging
from pathlib import Path
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.core.validators import MaxValueValidator, MinValueValidator
from django.core.exceptions import ValidationError
log = logging.getLogger(__name__)
@ -420,7 +418,7 @@ class UniqueContentRule(models.Model):
#region Rewrite - - - - - - - -
class _Server(models.Model):
class r_Server(models.Model):
id = models.PositiveIntegerField(primary_key=True)
name = models.CharField(max_length=128)
icon_hash = models.CharField(max_length=128)
@ -430,25 +428,13 @@ class _Server(models.Model):
def icon_url(self):
return f"https://cdn.discordapp.com/icons/{self.id}/{self.icon_hash}.webp?size=80"
def __str__(self):
return self.name
class _Subscription(models.Model):
class r_ContentFilter(models.Model):
id = models.AutoField(primary_key=True)
server = models.ForeignKey(to=_Server, on_delete=models.CASCADE)
name = models.CharField(max_length=32, blank=False)
url = models.URLField()
created_at = models.DateTimeField(default=timezone.now, editable=False)
updated_at = models.DateTimeField(default=timezone.now)
extra_notes = models.CharField(max_length=250, default="", blank=True)
active = models.BooleanField(default=True)
filters = models.ManyToManyField(to=_ContentFilter, blank=True)
message_style = models.ForeignKey(to=_MessageStyle, blank=False)
class _ContentFilter(models.Model):
id = models.AutoField(primary_key=True)
server = models.ForeignKey(to=_Server)
server = models.ForeignKey(to=r_Server, on_delete=models.CASCADE)
MATCH_NONE = 0
MATCH_ANY = 1
@ -473,22 +459,23 @@ class _ContentFilter(models.Model):
is_insensitive = models.BooleanField()
is_whitelist = models.BooleanField()
def __str__(self):
return self.name
class _Content(models.Model):
# Instances of this model are predefined only
class r_MessageMutator(models.Model):
id = models.AutoField(primary_key=True)
subscription = models.ForeignKey(to=_Subscription, on_delete=models.CASCADE)
name = models.CharField(max_length=64)
value = models.CharField(max_length=32)
# 'item_' prefix is to differentiate between the internal identifiers and the stored data
item_id = models.CharField(max_length=1024)
item_guid = models.CharField(max_length=1024)
item_url = models.CharField(max_length=1024)
item_title = models.CharField(max_length=1024)
item_content_hash = models.CharField(max_length=1024)
def __str__(self):
return self.name
class _MessageStyle(models.Model):
class r_MessageStyle(models.Model):
id = models.AutoField(primary_key=True)
server = models.ForeignKey(to=_Server, on_delete=models.CASCADE)
server = models.ForeignKey(to=r_Server, on_delete=models.CASCADE)
is_embed = models.BooleanField(default=True)
is_hyperlinked = models.BooleanField() # title only
@ -497,29 +484,90 @@ class _MessageStyle(models.Model):
show_images = models.BooleanField()
fetch_images = models.BooleanField() # if not included with RSS item
title_mutator = models.ForeignKey(to=_MessageMutator, on_delete=models.SET_NULL)
description_mutator = models.ForeignKey(to=_MessageMutator, on_delete=models.SET_NULL)
title_mutator = models.ForeignKey(
to=r_MessageMutator,
related_name="title_mutated_messagestyle",
on_delete=models.SET_NULL,
null=True,
blank=True
)
description_mutator = models.ForeignKey(
to=r_MessageMutator,
related_name="desc_mutated_messagestyle",
on_delete=models.SET_NULL,
null=True,
blank=True
)
def __str__(self):
return f"{self.server.name} - {self.id}"
class r_Subscription(models.Model):
id = models.AutoField(primary_key=True)
server = models.ForeignKey(to=r_Server, on_delete=models.CASCADE, blank=False)
name = models.CharField(max_length=32, blank=False)
url = models.URLField()
created_at = models.DateTimeField(default=timezone.now, editable=False)
updated_at = models.DateTimeField(default=timezone.now)
extra_notes = models.CharField(max_length=250, default="", blank=True)
active = models.BooleanField(default=True)
filters = models.ManyToManyField(to=r_ContentFilter, blank=True)
message_style = models.ForeignKey(to=r_MessageStyle, on_delete=models.SET_NULL, null=True, blank=True)
def clean(self):
if self.message_style and self.message_style.server != self.server:
raise ValidationError("Cannot use any Message Style of another server.")
if any(fltr.server != self.server for fltr in self.filters.all()):
raise ValidationError("Cannot use any Content Filter of another server.")
def save(self, *args, **kwargs):
if not self.pk:
super().save(*args, **kwargs)
self.clean()
super().save(*args, **kwargs)
def __str__(self):
return self.name
class r_Content(models.Model):
id = models.AutoField(primary_key=True)
subscription = models.ForeignKey(to=r_Subscription, on_delete=models.CASCADE)
# 'item_' prefix is to differentiate between the internal identifiers and the stored data
item_id = models.CharField(max_length=1024)
item_guid = models.CharField(max_length=1024)
item_url = models.CharField(max_length=1024)
item_title = models.CharField(max_length=1024)
item_content_hash = models.CharField(max_length=1024)
def __str__(self):
return f"{self.subscription.name} - {self.id}"
# Instances of this model are predefined only
class _MessageMutator(models.Model):
class r_UniqueContentRule(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=64)
value = models.CharField(max_length=32)
# Instances of this model are predefined only
class _UniqueContentRule(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=64)
value = models.CharField(max_length=32)
def __str__(self):
return self.name
# Relevant logs from the bot logic
class BotLogicLogs(models.Model):
id = models.AutoField(primary_key=True)
server = models.ForeignKey(to=_Server, on_delete=models.CASCADE)
server = models.ForeignKey(to=r_Server, on_delete=models.CASCADE)
level = models.CharField()
message = models.CharField() # todo
level = models.CharField(max_length=32)
message = models.CharField(max_length=256)
created_at = models.DateTimeField(default=timezone.now, editable=False)
def __str__(self):
return f"{self.server.name} - {self.id}"