From a908b9aa3a18222f296c0e4bd67d815f48ada5af Mon Sep 17 00:00:00 2001 From: Johannes Christ Date: Wed, 13 Dec 2023 09:07:08 +0100 Subject: Migrate mailing lists to their own API endpoints Add a new model for the bot to store its mailing list state in, as opposed to the current JSON blob in the BotSetting table. Migrate the existing settings from the BotSetting table into the new model. --- pydis_site/apps/api/viewsets/__init__.py | 7 +- pydis_site/apps/api/viewsets/bot/__init__.py | 10 +-- pydis_site/apps/api/viewsets/bot/mailing_list.py | 97 ++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 9 deletions(-) create mode 100644 pydis_site/apps/api/viewsets/bot/mailing_list.py (limited to 'pydis_site/apps/api/viewsets') diff --git a/pydis_site/apps/api/viewsets/__init__.py b/pydis_site/apps/api/viewsets/__init__.py index 1dae9be1..a28fa8e3 100644 --- a/pydis_site/apps/api/viewsets/__init__.py +++ b/pydis_site/apps/api/viewsets/__init__.py @@ -1,17 +1,18 @@ # flake8: noqa from .bot import ( + AocAccountLinkViewSet, + AocCompletionistBlockViewSet, BotSettingViewSet, BumpedThreadViewSet, DeletedMessageViewSet, DocumentationLinkViewSet, FilterListViewSet, - InfractionViewSet, FilterListViewSet, FilterViewSet, + InfractionViewSet, + MailingListViewSet, NominationViewSet, OffensiveMessageViewSet, - AocAccountLinkViewSet, - AocCompletionistBlockViewSet, OffTopicChannelNameViewSet, ReminderViewSet, RoleViewSet, diff --git a/pydis_site/apps/api/viewsets/bot/__init__.py b/pydis_site/apps/api/viewsets/bot/__init__.py index 33b65009..bb26cb11 100644 --- a/pydis_site/apps/api/viewsets/bot/__init__.py +++ b/pydis_site/apps/api/viewsets/bot/__init__.py @@ -1,18 +1,16 @@ # flake8: noqa -from .filters import ( - FilterListViewSet, - FilterViewSet -) +from .aoc_completionist_block import AocCompletionistBlockViewSet +from .aoc_link import AocAccountLinkViewSet from .bot_setting import BotSettingViewSet from .bumped_thread import BumpedThreadViewSet from .deleted_message import DeletedMessageViewSet from .documentation_link import DocumentationLinkViewSet +from .filters import FilterListViewSet, FilterViewSet from .infraction import InfractionViewSet +from .mailing_list import MailingListViewSet from .nomination import NominationViewSet from .off_topic_channel_name import OffTopicChannelNameViewSet from .offensive_message import OffensiveMessageViewSet -from .aoc_link import AocAccountLinkViewSet -from .aoc_completionist_block import AocCompletionistBlockViewSet from .reminder import ReminderViewSet from .role import RoleViewSet from .user import UserViewSet diff --git a/pydis_site/apps/api/viewsets/bot/mailing_list.py b/pydis_site/apps/api/viewsets/bot/mailing_list.py new file mode 100644 index 00000000..e46dfd4c --- /dev/null +++ b/pydis_site/apps/api/viewsets/bot/mailing_list.py @@ -0,0 +1,97 @@ +from django.db import IntegrityError +from rest_framework import status +from rest_framework.decorators import action +from rest_framework.exceptions import ParseError +from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.viewsets import GenericViewSet + +from pydis_site.apps.api.serializers import MailingListSerializer +from pydis_site.apps.api.models import MailingList, MailingListSeenItem + + +class MailingListViewSet(GenericViewSet, CreateModelMixin, ListModelMixin, RetrieveModelMixin): + """ + View providing management and updates of mailing lists and their seen items. + + ## Routes + + ### GET /bot/mailing-lists + Returns all the mailing lists and their seen items. + + #### Response format + >>> [ + ... { + ... 'id': 1, + ... 'name': 'python-dev', + ... 'seen_items': [ + ... 'd81gg90290la8', + ... ... + ... ] + ... }, + ... ... + ... ] + + ### POST /bot/mailing-lists + Create a new mailing list. + + #### Request format + >>> { + ... 'name': str + ... } + + #### Status codes + - 201: when the mailing list was created successfully + - 400: if the request data was invalid + + ### GET /bot/mailing-lists/ + Retrieve a single mailing list and its seen items. + + #### Response format + >>> { + ... 'id': 1, + ... 'name': 'python-dev', + ... 'seen_items': [ + ... 'd81gg90290la8', + ... ... + ... ] + ... } + + ### POST /bot/mailing-lists//seen-items + Add a single seen item to the given mailing list. The request body should + be the hash of the seen item to add, as a plain string. + + #### Request body + >>> str + + #### Response format + Empty response. + + #### Status codes + - 204: on successful creation of the seen item + - 400: if the request data was invalid + - 404: when the mailing list with the given name could not be found + """ + + lookup_field = 'name' + serializer_class = MailingListSerializer + queryset = MailingList.objects.prefetch_related('seen_items') + + @action(detail=True, methods=["POST"], + name="Add a seen item for a mailing list", url_name='seen-items', url_path='seen-items') + def add_seen_item(self, request: Request, name: str) -> Response: + """Add a single seen item to the given mailing list.""" + if not isinstance(request.data, str): + raise ParseError(detail={'non_field_errors': ["The request body must be a string"]}) + + list_ = self.get_object() + seen_item = MailingListSeenItem(list=list_, hash=request.data) + try: + seen_item.save() + except IntegrityError as err: + if err.__cause__.diag.constraint_name == 'unique_list_and_hash': + raise ParseError(detail={'non_field_errors': ["Seen item already known."]}) + raise # pragma: no cover + + return Response(status=status.HTTP_204_NO_CONTENT) -- cgit v1.2.3