Model and API rewrite changes
This commit is contained in:
parent
dfeb368be5
commit
7a78cf1215
@ -4,8 +4,7 @@ import logging
|
|||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from apps.home.models import Subscription, TrackedContent
|
from apps.home.models import Subscription, TrackedContent, DiscordChannel
|
||||||
# from apps.home.models import RSSFeed, FeedChannel
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -105,6 +104,14 @@ class DynamicModelSerializer(serializers.ModelSerializer):
|
|||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
|
|
||||||
|
class DiscordChannelSerializer(DynamicModelSerializer):
|
||||||
|
"""Serializer for the Discord Channel Model."""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = DiscordChannel
|
||||||
|
fields = ("id", "creation_datetime")
|
||||||
|
|
||||||
|
|
||||||
class SubscriptionSerializer(DynamicModelSerializer):
|
class SubscriptionSerializer(DynamicModelSerializer):
|
||||||
"""Serializer for the Subscription Model."""
|
"""Serializer for the Subscription Model."""
|
||||||
|
|
||||||
@ -113,12 +120,12 @@ class SubscriptionSerializer(DynamicModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Subscription
|
model = Subscription
|
||||||
fields = (
|
fields = (
|
||||||
"uuid", "name", "url", "image", "server",
|
"uuid", "name", "rss_url", "image", "server",
|
||||||
"channels", "creation_datetime"
|
"channels", "creation_datetime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TrackedContent(DynamicModelSerializer):
|
class TrackedContentSerializer(DynamicModelSerializer):
|
||||||
"""Serializer for the TrackedContent Model."""
|
"""Serializer for the TrackedContent Model."""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -3,27 +3,32 @@
|
|||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
from rest_framework.authtoken.views import obtain_auth_token
|
from rest_framework.authtoken.views import obtain_auth_token
|
||||||
|
|
||||||
from . import views
|
from .views import (
|
||||||
|
DiscordChannel_ListView,
|
||||||
|
DiscordChannel_DetailView,
|
||||||
|
Subscription_ListView,
|
||||||
|
Subscription_DetailView,
|
||||||
|
TrackedContent_ListView,
|
||||||
|
TrackedContent_DetailView
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("api-auth/", include("rest_framework.urls", namespace="rest_framework")),
|
path("api-auth/", include("rest_framework.urls", namespace="rest_framework")),
|
||||||
path("api-token-auth/", obtain_auth_token),
|
path("api-token-auth/", obtain_auth_token),
|
||||||
|
|
||||||
|
path("channel/", include([
|
||||||
|
path("", DiscordChannel_ListView.as_view(), name="discordchannel"),
|
||||||
|
path("<int:pk>/", DiscordChannel_DetailView.as_view(), name="discordchannel-detail")
|
||||||
|
])),
|
||||||
|
|
||||||
path("subscription/", include([
|
path("subscription/", include([
|
||||||
path("", views.SubscriptionList.as_view(), name="subscription"),
|
path("", Subscription_ListView.as_view(), name="subscription"),
|
||||||
path("<str:pk>/", views.SubscriptionDetail.as_view(), name="subscription-detail")
|
path("<str:pk>/", Subscription_DetailView.as_view(), name="subscription-detail")
|
||||||
])),
|
])),
|
||||||
|
|
||||||
path("tracked/", include([
|
path("tracked/", include([
|
||||||
path("", views.TrackedContentList.as_view(), name="tracked"),
|
path("", TrackedContent_ListView.as_view(), name="tracked"),
|
||||||
path("<str:pk>/", views.TrackedContentDetail.as_view(), name="tracked-detail"),
|
path("<str:pk>/", TrackedContent_DetailView.as_view(), name="tracked-detail")
|
||||||
# path("")
|
]))
|
||||||
])),
|
|
||||||
|
|
||||||
# path("rssfeed/", include([
|
|
||||||
# path("", views.RSSFeedList.as_view(), name="rssfeed"),
|
|
||||||
# path("<str:pk>/", views.RSSFeedDetail.as_view(), name="rssfeed-detail")
|
|
||||||
# ])),
|
|
||||||
# path("feedchannel/", views.FeedChannelListApiView.as_view(), name="feedchannel")
|
|
||||||
]
|
]
|
@ -1,90 +1,123 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import base64
|
|
||||||
|
|
||||||
import httpx
|
|
||||||
from django.http import HttpResponse
|
|
||||||
from django_filters import rest_framework as rest_filters
|
|
||||||
from django.views.decorators.cache import cache_page
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
from django.core.files import File
|
|
||||||
from django.core.files.base import ContentFile
|
|
||||||
from django.core.files.temp import NamedTemporaryFile
|
|
||||||
from django.db.utils import IntegrityError
|
from django.db.utils import IntegrityError
|
||||||
from rest_framework.views import APIView
|
from django_filters import rest_framework as rest_filters
|
||||||
from rest_framework.response import Response
|
|
||||||
from rest_framework import status, permissions, filters, generics
|
from rest_framework import status, permissions, filters, generics
|
||||||
|
from rest_framework.response import Response
|
||||||
from rest_framework.pagination import PageNumberPagination
|
from rest_framework.pagination import PageNumberPagination
|
||||||
from rest_framework.authentication import SessionAuthentication, TokenAuthentication
|
from rest_framework.authentication import SessionAuthentication, TokenAuthentication
|
||||||
from rest_framework.parsers import MultiPartParser, FormParser
|
from rest_framework.parsers import MultiPartParser, FormParser
|
||||||
from asgiref.sync import async_to_sync
|
|
||||||
|
|
||||||
from apps.home.models import RSSFeed, FeedChannel
|
from apps.home.models import DiscordChannel, Subscription, TrackedContent
|
||||||
from .serializers import RssFeedSerializer, FeedChannelSerializer
|
from .serializers import DiscordChannelSerializer, SubscriptionSerializer, TrackedContentSerializer
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class RSSFeedPagination(PageNumberPagination):
|
class DefaultPagination(PageNumberPagination):
|
||||||
|
"""Default class for pagination in API views."""
|
||||||
|
|
||||||
page_size = 10
|
page_size = 10
|
||||||
page_size_query_param = "page_size"
|
page_size_query_param = "page_size"
|
||||||
max_page_size = 25
|
max_page_size = 25
|
||||||
|
|
||||||
|
|
||||||
class RSSFeedList(generics.ListAPIView, generics.CreateAPIView):
|
# Discord Channel Views
|
||||||
|
|
||||||
|
class DiscordChannel_ListView(generics.ListAPIView, generics.CreateAPIView):
|
||||||
|
""""""
|
||||||
|
|
||||||
authentication_classes = [SessionAuthentication, TokenAuthentication]
|
authentication_classes = [SessionAuthentication, TokenAuthentication]
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
|
|
||||||
pagination_class = RSSFeedPagination
|
pagination_class = DefaultPagination
|
||||||
serializer_class = RssFeedSerializer
|
serializer_class = DiscordChannelSerializer
|
||||||
queryset = RSSFeed.objects.all().order_by("created_at")
|
queryset = DiscordChannel.objects.all().order_by("-creation_datetime")
|
||||||
|
|
||||||
filter_backends = [filters.SearchFilter, rest_filters.DjangoFilterBackend, filters.OrderingFilter]
|
filter_backends = [rest_filters.DjangoFilterBackend, filters.OrderingFilter]
|
||||||
filterset_fields = ["uuid", "name", "url", "discord_server_id", "created_at"]
|
filterset_fields = ["id"]
|
||||||
search_fields = ["name"]
|
ordering_fields = ["creation_datetime"]
|
||||||
ordering_fields = ["created_at"]
|
|
||||||
|
|
||||||
def post(self, request):
|
|
||||||
serializer = self.get_serializer(data=request.data)
|
|
||||||
serializer.is_valid(raise_exception=True)
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.perform_create(serializer)
|
|
||||||
except IntegrityError:
|
|
||||||
return Response({"detail": "RSS Feed name must be unique"}, status=status.HTTP_409_CONFLICT, exception=True)
|
|
||||||
|
|
||||||
headers = self.get_success_headers(serializer.data)
|
|
||||||
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
|
|
||||||
|
|
||||||
|
|
||||||
class RSSFeedDetail(generics.RetrieveUpdateDestroyAPIView):
|
class DiscordChannel_DetailView(generics.RetrieveDestroyAPIView):
|
||||||
|
""""""
|
||||||
|
|
||||||
authentication_classes = [SessionAuthentication, TokenAuthentication]
|
authentication_classes = [SessionAuthentication, TokenAuthentication]
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
parser_classes = [MultiPartParser, FormParser]
|
parser_classes = [MultiPartParser, FormParser]
|
||||||
|
|
||||||
serializer_class = RssFeedSerializer
|
serializer_class = DiscordChannelSerializer
|
||||||
queryset = RSSFeed.objects.all().order_by("-created_at")
|
queryset = DiscordChannel.objects.all().order_by("-creation_datetime")
|
||||||
|
|
||||||
|
|
||||||
class FeedChannelListApiView(generics.ListAPIView):
|
# Subscription Views
|
||||||
|
|
||||||
|
class Subscription_ListView(generics.ListAPIView, generics.CreateAPIView):
|
||||||
|
""""""
|
||||||
|
|
||||||
authentication_classes = [SessionAuthentication, TokenAuthentication]
|
authentication_classes = [SessionAuthentication, TokenAuthentication]
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
|
|
||||||
serializer_class = FeedChannelSerializer
|
pagination_class = DefaultPagination
|
||||||
|
serializer_class = SubscriptionSerializer
|
||||||
queryset = FeedChannel.objects.all().order_by("-created_at")
|
queryset = Subscription.objects.all().order_by("-creation_datetime")
|
||||||
|
|
||||||
filter_backends = [filters.SearchFilter, rest_filters.DjangoFilterBackend, filters.OrderingFilter]
|
filter_backends = [filters.SearchFilter, rest_filters.DjangoFilterBackend, filters.OrderingFilter]
|
||||||
filterset_fields = ["uuid", "discord_channel_id", "discord_server_id", "feeds", "created_at"]
|
filterset_fields = ["uuid", "name", "rss_url", "server", "channels", "creation_datetime"]
|
||||||
search_fields = ["feeds__name"]
|
search_fields = ["name"]
|
||||||
ordering_fields = ["created_at"]
|
ordering_fields = ["creation_datetime"]
|
||||||
|
|
||||||
def post(self, request):
|
# def post(self, request):
|
||||||
|
# serializer = self.get_serializer(data=request.data)
|
||||||
|
# serializer.is_valid(raise_exception=True)
|
||||||
|
|
||||||
serializer = self.serializer_class(data=request.data)
|
# try:
|
||||||
if serializer.is_valid():
|
# self.perform_create(serializer)
|
||||||
serializer.save()
|
# except IntegrityError:
|
||||||
return Response(serializer.data, status.HTTP_201_CREATED)
|
# return Response({"detail": "RSS Feed name must be unique"}, status=status.HTTP_409_CONFLICT, exception=True)
|
||||||
|
|
||||||
return Response(serializer.errors, status.HTTP_400_BAD_REQUEST)
|
# headers = self.get_success_headers(serializer.data)
|
||||||
|
# return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
|
||||||
|
|
||||||
|
|
||||||
|
class Subscription_DetailView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
|
""""""
|
||||||
|
|
||||||
|
authentication_classes = [SessionAuthentication, TokenAuthentication]
|
||||||
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
|
parser_classes = [MultiPartParser, FormParser]
|
||||||
|
|
||||||
|
serializer_class = SubscriptionSerializer
|
||||||
|
queryset = Subscription.objects.all().order_by("-creation_datetime")
|
||||||
|
|
||||||
|
|
||||||
|
# Tracked Content Views
|
||||||
|
|
||||||
|
class TrackedContent_ListView(generics.ListAPIView, generics.CreateAPIView):
|
||||||
|
""""""
|
||||||
|
|
||||||
|
authentication_classes = [SessionAuthentication, TokenAuthentication]
|
||||||
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
|
|
||||||
|
pagination_class = DefaultPagination
|
||||||
|
serializer_class = TrackedContentSerializer
|
||||||
|
queryset = TrackedContent.objects.all().order_by("-creation_datetime")
|
||||||
|
|
||||||
|
filter_backends = [filters.SearchFilter, rest_filters.DjangoFilterBackend, filters.OrderingFilter]
|
||||||
|
filterset_fields = ["uuid", "subscription", "content_url", "creation_datetime"]
|
||||||
|
search_fields = ["name"]
|
||||||
|
ordering_fields = ["creation_datetime"]
|
||||||
|
|
||||||
|
|
||||||
|
class TrackedContent_DetailView(generics.RetrieveDestroyAPIView):
|
||||||
|
""""""
|
||||||
|
|
||||||
|
authentication_classes = [SessionAuthentication, TokenAuthentication]
|
||||||
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
|
parser_classes = [MultiPartParser, FormParser]
|
||||||
|
|
||||||
|
serializer_class = TrackedContentSerializer
|
||||||
|
queryset = TrackedContent.objects.all().order_by("-creation_datetime")
|
||||||
|
@ -2,14 +2,19 @@
|
|||||||
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from .models import RSSFeed, FeedChannel
|
from .models import DiscordChannel, Subscription, TrackedContent
|
||||||
from .models import Subscription, TrackedContent
|
|
||||||
|
|
||||||
|
class DiscordChannelAdmin(admin.ModelAdmin):
|
||||||
|
list_display = [
|
||||||
|
"id", "creation_datetime"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class SubscriptionAdmin(admin.ModelAdmin):
|
class SubscriptionAdmin(admin.ModelAdmin):
|
||||||
list_display = [
|
list_display = [
|
||||||
"uuid", "name", "url", "server",
|
"uuid", "name", "rss_url", "server",
|
||||||
"channels", "creation_datetime"
|
"creation_datetime"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -20,6 +25,7 @@ class TrackedContentAdmin(admin.ModelAdmin):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(DiscordChannel, DiscordChannelAdmin)
|
||||||
admin.site.register(Subscription, SubscriptionAdmin)
|
admin.site.register(Subscription, SubscriptionAdmin)
|
||||||
admin.site.register(TrackedContent, TrackedContentAdmin)
|
admin.site.register(TrackedContent, TrackedContentAdmin)
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# Generated by Django 5.0.1 on 2024-01-30 20:45
|
# Generated by Django 5.0.1 on 2024-02-07 23:19
|
||||||
|
|
||||||
import apps.home.models
|
import apps.home.models
|
||||||
|
import django.db.models.deletion
|
||||||
import django.utils.timezone
|
import django.utils.timezone
|
||||||
import uuid
|
import uuid
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
@ -15,40 +16,45 @@ class Migration(migrations.Migration):
|
|||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='FeedChannel',
|
name='DiscordChannel',
|
||||||
fields=[
|
fields=[
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
('id', models.PositiveBigIntegerField(editable=False, help_text='Unique identifier of the channel, provided by Discord.', primary_key=True, serialize=False, verbose_name='id')),
|
||||||
('discord_server_id', models.PositiveBigIntegerField(help_text='the discord server id of this item', verbose_name='discord server id')),
|
('creation_datetime', models.DateTimeField(default=django.utils.timezone.now, editable=False, help_text='when this instance was created.', verbose_name='creation datetime')),
|
||||||
('discord_channel_id', models.PositiveBigIntegerField(help_text='the discord channel id of this item', verbose_name='discord channel id')),
|
|
||||||
('created_at', models.DateTimeField(default=django.utils.timezone.now, editable=False, help_text='when this item was created', verbose_name='creation date & time')),
|
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Feed Channel',
|
'verbose_name': 'discord channel',
|
||||||
'verbose_name_plural': 'Feed Channels',
|
'verbose_name_plural': 'discord channels',
|
||||||
|
'get_latest_by': '-creation_datetime',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='RSSFeed',
|
name='Subscription',
|
||||||
fields=[
|
fields=[
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(help_text='a human readable nickname for this item', max_length=120, verbose_name='name')),
|
('name', models.CharField(help_text='Reference name for this subscription (max %(max_length)s chars).', max_length=32, verbose_name='name')),
|
||||||
('url', models.URLField(help_text='url to the RSS feed', verbose_name='url')),
|
('rss_url', models.URLField(help_text='URL of the subscribed to RSS feed.', verbose_name='rss url')),
|
||||||
('image', models.ImageField(blank=True, help_text='image of the RSS feed', null=True, storage=apps.home.models.OverwriteStorage(), upload_to=apps.home.models.RSSFeedIconPathGenerator(), verbose_name='image')),
|
('image', models.ImageField(blank=True, default='../static/images/defaultuser.webp', help_text='image of the RSS feed.', null=True, storage=apps.home.models.OverwriteStorage(), upload_to=apps.home.models.Subscription_IconPathGenerator(), verbose_name='image')),
|
||||||
('created_at', models.DateTimeField(default=django.utils.timezone.now, editable=False, help_text='when this item was created', verbose_name='creation date & time')),
|
('creation_datetime', models.DateTimeField(default=django.utils.timezone.now, editable=False, help_text='when this instance was created.', verbose_name='creation datetime')),
|
||||||
('discord_server_id', models.PositiveBigIntegerField(help_text='the discord server id of this item', verbose_name='discord server id')),
|
('server', models.PositiveBigIntegerField(help_text='Identifier for the discord server that owns this subscription.', verbose_name='server id')),
|
||||||
|
('channels', models.ManyToManyField(help_text='List of Discord Channels acting as targets for subscription content.', to='home.discordchannel', verbose_name='channels')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'RSS Feed',
|
'verbose_name': 'subscription',
|
||||||
'verbose_name_plural': 'RSS Feeds',
|
'verbose_name_plural': 'subscriptions',
|
||||||
|
'get_latest_by': '-creation_datetime',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.AddConstraint(
|
migrations.CreateModel(
|
||||||
model_name='rssfeed',
|
name='TrackedContent',
|
||||||
constraint=models.UniqueConstraint(fields=('name', 'discord_server_id'), name='unique name & server pair'),
|
fields=[
|
||||||
|
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
||||||
|
('content_url', models.URLField(help_text='URL of the tracked content.', verbose_name='content url')),
|
||||||
|
('creation_datetime', models.DateTimeField(default=django.utils.timezone.now, editable=False, help_text='when this instance was created.', verbose_name='creation datetime')),
|
||||||
|
('subscription', models.ForeignKey(help_text='The subscription that this content originated from.', on_delete=django.db.models.deletion.CASCADE, related_name='tracked_content', to='home.subscription', verbose_name='subscription')),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddConstraint(
|
||||||
model_name='feedchannel',
|
model_name='subscription',
|
||||||
name='feeds',
|
constraint=models.UniqueConstraint(fields=('name', 'server'), name='unique name & server pair'),
|
||||||
field=models.ManyToManyField(help_text='the feeds to include in this item', related_name='queues', to='home.rssfeed', verbose_name='feeds'),
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -38,6 +38,30 @@ class Subscription_IconPathGenerator:
|
|||||||
return os.path.join("subscriptions", str(instance.uuid), "icon.webp")
|
return os.path.join("subscriptions", str(instance.uuid), "icon.webp")
|
||||||
|
|
||||||
|
|
||||||
|
class DiscordChannel(models.Model):
|
||||||
|
"""Represents a Discord Channel."""
|
||||||
|
|
||||||
|
id = models.PositiveBigIntegerField(
|
||||||
|
verbose_name=_("id"),
|
||||||
|
help_text=_("Unique identifier of the channel, provided by Discord."),
|
||||||
|
primary_key=True
|
||||||
|
)
|
||||||
|
creation_datetime = models.DateTimeField(
|
||||||
|
verbose_name=_("creation datetime"),
|
||||||
|
help_text=_("when this instance was created."),
|
||||||
|
default=timezone.now,
|
||||||
|
editable=False
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("discord channel")
|
||||||
|
verbose_name_plural = _("discord channels")
|
||||||
|
get_latest_by = "-creation_datetime"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.id)
|
||||||
|
|
||||||
|
|
||||||
class Subscription(models.Model):
|
class Subscription(models.Model):
|
||||||
"""Stores relevant data for a user submitted RSS Feed."""
|
"""Stores relevant data for a user submitted RSS Feed."""
|
||||||
|
|
||||||
@ -76,7 +100,11 @@ class Subscription(models.Model):
|
|||||||
verbose_name=_("server id"),
|
verbose_name=_("server id"),
|
||||||
help_text=_("Identifier for the discord server that owns this subscription.")
|
help_text=_("Identifier for the discord server that owns this subscription.")
|
||||||
)
|
)
|
||||||
channels = models.ManyToManyField(int)
|
channels = models.ManyToManyField(
|
||||||
|
verbose_name=_("channels"),
|
||||||
|
help_text=_("List of Discord Channels acting as targets for subscription content."),
|
||||||
|
to=DiscordChannel,
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "subscription"
|
verbose_name = "subscription"
|
||||||
@ -84,12 +112,17 @@ class Subscription(models.Model):
|
|||||||
get_latest_by = "-creation_datetime"
|
get_latest_by = "-creation_datetime"
|
||||||
constraints = [
|
constraints = [
|
||||||
# Prevent servers from having subscriptions with duplicate names
|
# Prevent servers from having subscriptions with duplicate names
|
||||||
models.UniqueConstraint(fields=["name", "server_id"], name="unique name & server pair")
|
models.UniqueConstraint(fields=["name", "server"], name="unique name & server pair")
|
||||||
]
|
]
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
new_text = "New " if self._state.adding else ""
|
||||||
|
log.debug("%sSubscription Saved %s", new_text, self.uuid)
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class TrackedContent(models.Model):
|
class TrackedContent(models.Model):
|
||||||
"""Tracks content shared from an RSS Feed, to prevent duplicates."""
|
"""Tracks content shared from an RSS Feed, to prevent duplicates."""
|
||||||
@ -110,7 +143,7 @@ class TrackedContent(models.Model):
|
|||||||
verbose_name=_("content url"),
|
verbose_name=_("content url"),
|
||||||
help_text=_("URL of the tracked content.")
|
help_text=_("URL of the tracked content.")
|
||||||
)
|
)
|
||||||
creation_datetime = models.DatetimeField(
|
creation_datetime = models.DateTimeField(
|
||||||
verbose_name=_("creation datetime"),
|
verbose_name=_("creation datetime"),
|
||||||
help_text=_("when this instance was created."),
|
help_text=_("when this instance was created."),
|
||||||
default=timezone.now,
|
default=timezone.now,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user