From b2819a4cfe04b893d5cd638407e48ff6bd501a20 Mon Sep 17 00:00:00 2001 From: RohanJnr Date: Wed, 19 May 2021 13:16:21 +0530 Subject: Use ModelViewSet to add support for PUT and PATCH request. --- pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'pydis_site/apps/api/viewsets') diff --git a/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py b/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py index 826ad25e..194e96d2 100644 --- a/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py +++ b/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py @@ -3,16 +3,15 @@ from django.db.models.query import QuerySet from django.http.request import HttpRequest from django.shortcuts import get_object_or_404 from rest_framework.exceptions import ParseError -from rest_framework.mixins import DestroyModelMixin from rest_framework.response import Response from rest_framework.status import HTTP_201_CREATED -from rest_framework.viewsets import ViewSet +from rest_framework.viewsets import ModelViewSet from pydis_site.apps.api.models.bot.off_topic_channel_name import OffTopicChannelName from pydis_site.apps.api.serializers import OffTopicChannelNameSerializer -class OffTopicChannelNameViewSet(DestroyModelMixin, ViewSet): +class OffTopicChannelNameViewSet(ModelViewSet): """ View of off-topic channel names used by the bot to rotate our off-topic names on a daily basis. @@ -73,7 +72,7 @@ class OffTopicChannelNameViewSet(DestroyModelMixin, ViewSet): """Returns a queryset that covers the entire OffTopicChannelName table.""" return OffTopicChannelName.objects.all() - def create(self, request: HttpRequest) -> Response: + def create(self, request: HttpRequest, *args, **kwargs) -> Response: """ DRF method for creating a new OffTopicChannelName. @@ -91,7 +90,7 @@ class OffTopicChannelNameViewSet(DestroyModelMixin, ViewSet): 'name': ["This query parameter is required."] }) - def list(self, request: HttpRequest) -> Response: + def list(self, request: HttpRequest, *args, **kwargs) -> Response: """ DRF method for listing OffTopicChannelName entries. @@ -133,6 +132,4 @@ class OffTopicChannelNameViewSet(DestroyModelMixin, ViewSet): serialized = self.serializer_class(queryset, many=True) return Response(serialized.data) - queryset = self.get_queryset() - serialized = self.serializer_class(queryset, many=True) - return Response(serialized.data) + return super().list(self, request) -- cgit v1.2.3 From 87e25f77cbc900024e86d439abd9fde71181800d Mon Sep 17 00:00:00 2001 From: RohanJnr Date: Fri, 4 Jun 2021 21:46:54 +0530 Subject: Query off topic names based on Active attribute. --- .../apps/api/viewsets/bot/off_topic_channel_name.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'pydis_site/apps/api/viewsets') diff --git a/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py b/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py index 194e96d2..0caf8088 100644 --- a/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py +++ b/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py @@ -1,9 +1,11 @@ +import json + from django.db.models import Case, Value, When from django.db.models.query import QuerySet -from django.http.request import HttpRequest from django.shortcuts import get_object_or_404 from rest_framework.exceptions import ParseError from rest_framework.response import Response +from rest_framework.request import Request from rest_framework.status import HTTP_201_CREATED from rest_framework.viewsets import ModelViewSet @@ -68,11 +70,11 @@ class OffTopicChannelNameViewSet(ModelViewSet): name = self.kwargs[self.lookup_field] return get_object_or_404(queryset, name=name) - def get_queryset(self) -> QuerySet: + def get_queryset(self, active=True) -> QuerySet: """Returns a queryset that covers the entire OffTopicChannelName table.""" - return OffTopicChannelName.objects.all() + return OffTopicChannelName.objects.filter(active=True) - def create(self, request: HttpRequest, *args, **kwargs) -> Response: + def create(self, request: Request, *args, **kwargs) -> Response: """ DRF method for creating a new OffTopicChannelName. @@ -90,7 +92,7 @@ class OffTopicChannelNameViewSet(ModelViewSet): 'name': ["This query parameter is required."] }) - def list(self, request: HttpRequest, *args, **kwargs) -> Response: + def list(self, request: Request, *args, **kwargs) -> Response: """ DRF method for listing OffTopicChannelName entries. @@ -132,4 +134,6 @@ class OffTopicChannelNameViewSet(ModelViewSet): serialized = self.serializer_class(queryset, many=True) return Response(serialized.data) - return super().list(self, request) + queryset = self.get_queryset(active=bool(request.query_params.get("active", True))) + serialized = self.serializer_class(queryset, many=True) + return Response(serialized.data) -- cgit v1.2.3 From f0534b8e1ed55c18416372f23bb5a1f2e0862e38 Mon Sep 17 00:00:00 2001 From: RohanJnr Date: Thu, 10 Jun 2021 02:09:22 +0530 Subject: Fix bug: Do not force active param. --- .../apps/api/viewsets/bot/off_topic_channel_name.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'pydis_site/apps/api/viewsets') diff --git a/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py b/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py index 0caf8088..18ee84ea 100644 --- a/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py +++ b/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py @@ -1,11 +1,9 @@ -import json - from django.db.models import Case, Value, When from django.db.models.query import QuerySet from django.shortcuts import get_object_or_404 from rest_framework.exceptions import ParseError -from rest_framework.response import Response from rest_framework.request import Request +from rest_framework.response import Response from rest_framework.status import HTTP_201_CREATED from rest_framework.viewsets import ModelViewSet @@ -70,9 +68,9 @@ class OffTopicChannelNameViewSet(ModelViewSet): name = self.kwargs[self.lookup_field] return get_object_or_404(queryset, name=name) - def get_queryset(self, active=True) -> QuerySet: + def get_queryset(self, **kwargs) -> QuerySet: """Returns a queryset that covers the entire OffTopicChannelName table.""" - return OffTopicChannelName.objects.filter(active=True) + return OffTopicChannelName.objects.filter(**kwargs) def create(self, request: Request, *args, **kwargs) -> Response: """ @@ -134,6 +132,11 @@ class OffTopicChannelNameViewSet(ModelViewSet): serialized = self.serializer_class(queryset, many=True) return Response(serialized.data) - queryset = self.get_queryset(active=bool(request.query_params.get("active", True))) + params = {} + + if active_param := request.query_params.get("active"): + params["active"] = active_param.lower() == "true" + + queryset = self.get_queryset(**params) serialized = self.serializer_class(queryset, many=True) return Response(serialized.data) -- cgit v1.2.3 From 6e1d38d6ceb97f287f0d347e974bc795dda38ffe Mon Sep 17 00:00:00 2001 From: RohanJnr Date: Fri, 5 Nov 2021 10:56:34 +0530 Subject: Use framework defination of method. --- pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'pydis_site/apps/api/viewsets') diff --git a/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py b/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py index 7151d29b..27eabec9 100644 --- a/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py +++ b/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py @@ -70,7 +70,7 @@ class OffTopicChannelNameViewSet(ModelViewSet): def get_queryset(self, **kwargs) -> QuerySet: """Returns a queryset that covers the entire OffTopicChannelName table.""" - return OffTopicChannelName.objects.filter(**kwargs) + return OffTopicChannelName.objects.all() def create(self, request: Request, *args, **kwargs) -> Response: """ @@ -137,6 +137,6 @@ class OffTopicChannelNameViewSet(ModelViewSet): if active_param := request.query_params.get("active"): params["active"] = active_param.lower() == "true" - queryset = self.get_queryset(**params) + queryset = self.get_queryset().filter(**params) serialized = self.serializer_class(queryset, many=True) return Response(serialized.data) -- cgit v1.2.3 From 4377c6d960e3fbf3a416230d1ad7de972019898e Mon Sep 17 00:00:00 2001 From: RohanJnr Date: Sat, 6 Nov 2021 14:43:17 +0530 Subject: Remove get_queryset() and add new class variable . --- pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'pydis_site/apps/api/viewsets') diff --git a/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py b/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py index 27eabec9..78f8c340 100644 --- a/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py +++ b/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py @@ -57,6 +57,7 @@ class OffTopicChannelNameViewSet(ModelViewSet): lookup_field = 'name' serializer_class = OffTopicChannelNameSerializer + queryset = OffTopicChannelName.objects.all() def get_object(self) -> OffTopicChannelName: """ @@ -64,11 +65,10 @@ class OffTopicChannelNameViewSet(ModelViewSet): If it doesn't, a HTTP 404 is returned by way of throwing an exception. """ - queryset = self.get_queryset() name = self.kwargs[self.lookup_field] - return get_object_or_404(queryset, name=name) + return get_object_or_404(self.queryset, name=name) - def get_queryset(self, **kwargs) -> QuerySet: + def get_queryset(self) -> QuerySet: """Returns a queryset that covers the entire OffTopicChannelName table.""" return OffTopicChannelName.objects.all() @@ -108,13 +108,13 @@ class OffTopicChannelNameViewSet(ModelViewSet): 'random_items': ["Must be a positive integer."] }) - queryset = self.get_queryset().order_by('used', '?')[:random_count] + queryset = self.queryset.order_by('used', '?')[:random_count] # When any name is used in our listing then this means we reached end of round # and we need to reset all other names `used` to False if any(offtopic_name.used for offtopic_name in queryset): # These names that we just got have to be excluded from updating used to False - self.get_queryset().update( + self.queryset.update( used=Case( When( name__in=(offtopic_name.name for offtopic_name in queryset), @@ -125,7 +125,7 @@ class OffTopicChannelNameViewSet(ModelViewSet): ) else: # Otherwise mark selected names `used` to True - self.get_queryset().filter( + self.queryset.filter( name__in=(offtopic_name.name for offtopic_name in queryset) ).update(used=True) @@ -137,6 +137,6 @@ class OffTopicChannelNameViewSet(ModelViewSet): if active_param := request.query_params.get("active"): params["active"] = active_param.lower() == "true" - queryset = self.get_queryset().filter(**params) + queryset = self.queryset.filter(**params) serialized = self.serializer_class(queryset, many=True) return Response(serialized.data) -- cgit v1.2.3 From 7353e1ed7003a1198fb00a1e40251b95cf2fdf7e Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Wed, 17 Nov 2021 14:27:45 +0400 Subject: Adds Redirect Filter List Adds a new filter list for URLs which should be treated as redirects and unfurled. Signed-off-by: Hassan Abouelela --- .../apps/api/migrations/0075_add_redirects_filter.py | 18 ++++++++++++++++++ pydis_site/apps/api/models/bot/filter_list.py | 1 + pydis_site/apps/api/viewsets/bot/filter_list.py | 3 ++- 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 pydis_site/apps/api/migrations/0075_add_redirects_filter.py (limited to 'pydis_site/apps/api/viewsets') diff --git a/pydis_site/apps/api/migrations/0075_add_redirects_filter.py b/pydis_site/apps/api/migrations/0075_add_redirects_filter.py new file mode 100644 index 00000000..23dc176f --- /dev/null +++ b/pydis_site/apps/api/migrations/0075_add_redirects_filter.py @@ -0,0 +1,18 @@ +# Generated by Django 3.0.14 on 2021-11-17 10:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0074_reminder_failures'), + ] + + operations = [ + migrations.AlterField( + model_name='filterlist', + name='type', + field=models.CharField(choices=[('GUILD_INVITE', 'Guild Invite'), ('FILE_FORMAT', 'File Format'), ('DOMAIN_NAME', 'Domain Name'), ('FILTER_TOKEN', 'Filter Token'), ('REDIRECT', 'Redirect')], help_text='The type of allowlist this is on.', max_length=50), + ), + ] diff --git a/pydis_site/apps/api/models/bot/filter_list.py b/pydis_site/apps/api/models/bot/filter_list.py index d279e137..d30f7213 100644 --- a/pydis_site/apps/api/models/bot/filter_list.py +++ b/pydis_site/apps/api/models/bot/filter_list.py @@ -12,6 +12,7 @@ class FilterList(ModelTimestampMixin, ModelReprMixin, models.Model): 'FILE_FORMAT ' 'DOMAIN_NAME ' 'FILTER_TOKEN ' + 'REDIRECT ' ) type = models.CharField( max_length=50, diff --git a/pydis_site/apps/api/viewsets/bot/filter_list.py b/pydis_site/apps/api/viewsets/bot/filter_list.py index 2cb21ab9..4b05acee 100644 --- a/pydis_site/apps/api/viewsets/bot/filter_list.py +++ b/pydis_site/apps/api/viewsets/bot/filter_list.py @@ -59,7 +59,8 @@ class FilterListViewSet(ModelViewSet): ... ["GUILD_INVITE","Guild Invite"], ... ["FILE_FORMAT","File Format"], ... ["DOMAIN_NAME","Domain Name"], - ... ["FILTER_TOKEN","Filter Token"] + ... ["FILTER_TOKEN","Filter Token"], + ... ["REDIRECT", "Redirect"] ... ] #### Status codes -- cgit v1.2.3 From 855bf5e7c7e54e9f8e4544545026c47092b52a11 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Mon, 22 Nov 2021 20:36:21 +0000 Subject: Only calc activity blocks when <1k messages We only truly care about how many activity blocks a user has when they have a small number of messages, as we only use this for the voice gate. If a user has more than say 1k messages, then we really don't need to calculate their activity blocks, as it's quite an expensive query with many messages. --- pydis_site/apps/api/viewsets/bot/user.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'pydis_site/apps/api/viewsets') diff --git a/pydis_site/apps/api/viewsets/bot/user.py b/pydis_site/apps/api/viewsets/bot/user.py index 22d13dc4..ed661323 100644 --- a/pydis_site/apps/api/viewsets/bot/user.py +++ b/pydis_site/apps/api/viewsets/bot/user.py @@ -271,9 +271,15 @@ class UserViewSet(ModelViewSet): with Metricity() as metricity: try: data = metricity.user(user.id) + data["total_messages"] = metricity.total_messages(user.id) + if data["total_messages"] < 1000: + # Only calculate and return activity_blocks if the user has a small amount + # of messages, as calculating activity_blocks is expensive. + # 1000 message chosen as an arbitrarily large number. + data["activity_blocks"] = metricity.total_message_blocks(user.id) + data["voice_banned"] = voice_banned - data["activity_blocks"] = metricity.total_message_blocks(user.id) return Response(data, status=status.HTTP_200_OK) except NotFoundError: return Response(dict(detail="User not found in metricity"), -- cgit v1.2.3 From 1e3725d8f6ef1a601c12054db3d913e447b51866 Mon Sep 17 00:00:00 2001 From: Izan Date: Fri, 12 Nov 2021 14:31:52 +0000 Subject: Update documentation to include `dm_sent` field --- pydis_site/apps/api/viewsets/bot/infraction.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'pydis_site/apps/api/viewsets') diff --git a/pydis_site/apps/api/viewsets/bot/infraction.py b/pydis_site/apps/api/viewsets/bot/infraction.py index f8b0cb9d..8a48ed1f 100644 --- a/pydis_site/apps/api/viewsets/bot/infraction.py +++ b/pydis_site/apps/api/viewsets/bot/infraction.py @@ -70,7 +70,8 @@ class InfractionViewSet( ... 'actor': 125435062127820800, ... 'type': 'ban', ... 'reason': 'He terk my jerb!', - ... 'hidden': True + ... 'hidden': True, + ... 'dm_sent': True ... } ... ] @@ -100,7 +101,8 @@ class InfractionViewSet( ... 'hidden': True, ... 'type': 'ban', ... 'reason': 'He terk my jerb!', - ... 'user': 172395097705414656 + ... 'user': 172395097705414656, + ... 'dm_sent': False ... } #### Response format @@ -118,7 +120,8 @@ class InfractionViewSet( >>> { ... 'active': True, ... 'expires_at': '4143-02-15T21:04:31+00:00', - ... 'reason': 'durka derr' + ... 'reason': 'durka derr', + ... 'dm_sent': True ... } #### Response format -- cgit v1.2.3 From 59e4a5c8316464e116630a329064decac4c2a075 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Thu, 16 Dec 2021 22:29:11 +0000 Subject: Always include metricity message blocks Thanks to a recent database maintenance (https://pythondiscord.freshstatus.io/incident/139811) querying out metricity message data is far cheaper. So there is no longer a reason to only fetch blocks if the member has a low message count. --- pydis_site/apps/api/tests/test_users.py | 21 +-------------------- pydis_site/apps/api/viewsets/bot/user.py | 6 +----- 2 files changed, 2 insertions(+), 25 deletions(-) (limited to 'pydis_site/apps/api/viewsets') diff --git a/pydis_site/apps/api/tests/test_users.py b/pydis_site/apps/api/tests/test_users.py index 81bfd43b..9b91380b 100644 --- a/pydis_site/apps/api/tests/test_users.py +++ b/pydis_site/apps/api/tests/test_users.py @@ -408,7 +408,7 @@ class UserMetricityTests(AuthenticatedAPITestCase): in_guild=True, ) - def test_get_metricity_data_under_1k(self): + def test_get_metricity_data(self): # Given joined_at = "foo" total_messages = 1 @@ -428,25 +428,6 @@ class UserMetricityTests(AuthenticatedAPITestCase): "activity_blocks": total_blocks }) - def test_get_metricity_data_over_1k(self): - # Given - joined_at = "foo" - total_messages = 1001 - total_blocks = 1001 - self.mock_metricity_user(joined_at, total_messages, total_blocks, []) - - # When - url = reverse('api:bot:user-metricity-data', args=[0]) - response = self.client.get(url) - - # Then - self.assertEqual(response.status_code, 200) - self.assertCountEqual(response.json(), { - "joined_at": joined_at, - "total_messages": total_messages, - "voice_banned": False, - }) - def test_no_metricity_user(self): # Given self.mock_no_metricity_user() diff --git a/pydis_site/apps/api/viewsets/bot/user.py b/pydis_site/apps/api/viewsets/bot/user.py index ed661323..1a5e79f8 100644 --- a/pydis_site/apps/api/viewsets/bot/user.py +++ b/pydis_site/apps/api/viewsets/bot/user.py @@ -273,11 +273,7 @@ class UserViewSet(ModelViewSet): data = metricity.user(user.id) data["total_messages"] = metricity.total_messages(user.id) - if data["total_messages"] < 1000: - # Only calculate and return activity_blocks if the user has a small amount - # of messages, as calculating activity_blocks is expensive. - # 1000 message chosen as an arbitrarily large number. - data["activity_blocks"] = metricity.total_message_blocks(user.id) + data["activity_blocks"] = metricity.total_message_blocks(user.id) data["voice_banned"] = voice_banned return Response(data, status=status.HTTP_200_OK) -- cgit v1.2.3 From 3e10b0cf19916f10be0aed9c8d60c9dfd7a016a5 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Thu, 27 Jan 2022 20:30:16 +0000 Subject: Use voice_mute and voice_ban to determine voice_gate Previously only voice_ban was used, but now having either of these infractions should mean the user is blocked from reciving the role. --- pydis_site/apps/api/viewsets/bot/user.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'pydis_site/apps/api/viewsets') diff --git a/pydis_site/apps/api/viewsets/bot/user.py b/pydis_site/apps/api/viewsets/bot/user.py index 1a5e79f8..a867a80f 100644 --- a/pydis_site/apps/api/viewsets/bot/user.py +++ b/pydis_site/apps/api/viewsets/bot/user.py @@ -1,7 +1,7 @@ import typing from collections import OrderedDict -from django.core.exceptions import ObjectDoesNotExist +from django.db.models import Q from rest_framework import status from rest_framework.decorators import action from rest_framework.pagination import PageNumberPagination @@ -261,12 +261,10 @@ class UserViewSet(ModelViewSet): """Request handler for metricity_data endpoint.""" user = self.get_object() - try: - Infraction.objects.get(user__id=user.id, active=True, type="voice_ban") - except ObjectDoesNotExist: - voice_banned = False - else: - voice_banned = True + has_voice_infraction = Infraction.objects.filter( + Q(user__id=user.id, active=True), + Q(type="voice_ban") | Q(type="voice_mute") + ).exists() with Metricity() as metricity: try: @@ -275,7 +273,7 @@ class UserViewSet(ModelViewSet): data["total_messages"] = metricity.total_messages(user.id) data["activity_blocks"] = metricity.total_message_blocks(user.id) - data["voice_banned"] = voice_banned + data["voice_gate_blocked"] = has_voice_infraction return Response(data, status=status.HTTP_200_OK) except NotFoundError: return Response(dict(detail="User not found in metricity"), -- cgit v1.2.3 From 6c9fb075dc52d5674f90698cb74138712f7d99e1 Mon Sep 17 00:00:00 2001 From: Johannes Christ Date: Sun, 30 Jan 2022 15:34:04 +0100 Subject: Allow searching users by username and discriminator A test case is added to demonstrate this functionality. Closes #578. Co-authored-by: Boris Muratov <8bee278@gmail.com> --- pydis_site/apps/api/tests/test_users.py | 43 ++++++++++++++++++++++++++++++++ pydis_site/apps/api/viewsets/bot/user.py | 5 ++++ 2 files changed, 48 insertions(+) (limited to 'pydis_site/apps/api/viewsets') diff --git a/pydis_site/apps/api/tests/test_users.py b/pydis_site/apps/api/tests/test_users.py index e21bb32b..5d10069d 100644 --- a/pydis_site/apps/api/tests/test_users.py +++ b/pydis_site/apps/api/tests/test_users.py @@ -1,3 +1,4 @@ +import random from unittest.mock import Mock, patch from django.urls import reverse @@ -520,3 +521,45 @@ class UserMetricityTests(AuthenticatedAPITestCase): self.metricity.total_messages.side_effect = NotFoundError() self.metricity.total_message_blocks.side_effect = NotFoundError() self.metricity.top_channel_activity.side_effect = NotFoundError() + + +class UserViewSetTests(AuthenticatedAPITestCase): + @classmethod + def setUpTestData(cls): + cls.searched_user = User.objects.create( + id=12095219, + name=f"Test user {random.randint(100, 1000)}", + discriminator=random.randint(1, 9999), + in_guild=True, + ) + cls.other_user = User.objects.create( + id=18259125, + name=f"Test user {random.randint(100, 1000)}", + discriminator=random.randint(1, 9999), + in_guild=True, + ) + + def test_search_lookup_of_wanted_user(self) -> None: + """Searching a user by name and discriminator should return that user.""" + url = reverse('api:bot:user-list') + params = { + 'username': self.searched_user.name, + 'discriminator': self.searched_user.discriminator, + } + response = self.client.get(url, params) + result = response.json() + self.assertEqual(result['count'], 1) + [user] = result['results'] + self.assertEqual(user['id'], self.searched_user.id) + + def test_search_lookup_of_unknown_user(self) -> None: + """Searching an unknown user should return no results.""" + url = reverse('api:bot:user-list') + params = { + 'username': "f-string enjoyer", + 'discriminator': 1245, + } + response = self.client.get(url, params) + result = response.json() + self.assertEqual(result['count'], 0) + self.assertEqual(result['results'], []) diff --git a/pydis_site/apps/api/viewsets/bot/user.py b/pydis_site/apps/api/viewsets/bot/user.py index a867a80f..3318b2b9 100644 --- a/pydis_site/apps/api/viewsets/bot/user.py +++ b/pydis_site/apps/api/viewsets/bot/user.py @@ -2,6 +2,7 @@ import typing from collections import OrderedDict from django.db.models import Q +from django_filters.rest_framework import DjangoFilterBackend from rest_framework import status from rest_framework.decorators import action from rest_framework.pagination import PageNumberPagination @@ -77,6 +78,8 @@ class UserViewSet(ModelViewSet): ... } #### Optional Query Parameters + - username: username to search for + - discriminator: discriminator to search for - page_size: number of Users in one page, defaults to 10,000 - page: page number @@ -233,6 +236,8 @@ class UserViewSet(ModelViewSet): serializer_class = UserSerializer queryset = User.objects.all().order_by("id") pagination_class = UserListPagination + filter_backends = (DjangoFilterBackend,) + filter_fields = ('name', 'discriminator') def get_serializer(self, *args, **kwargs) -> ModelSerializer: """Set Serializer many attribute to True if request body contains a list.""" -- cgit v1.2.3 From 15cac33dd74219a762d3c066efca383552f666b0 Mon Sep 17 00:00:00 2001 From: Rohan Reddy Alleti Date: Thu, 17 Feb 2022 02:55:28 +0530 Subject: Return random off topic names which are Active only (#644) Co-authored-by: Xithrius <15021300+Xithrius@users.noreply.github.com> --- .../apps/api/tests/test_off_topic_channel_names.py | 35 +++++++++++++++++----- .../api/viewsets/bot/off_topic_channel_name.py | 3 +- 2 files changed, 29 insertions(+), 9 deletions(-) (limited to 'pydis_site/apps/api/viewsets') diff --git a/pydis_site/apps/api/tests/test_off_topic_channel_names.py b/pydis_site/apps/api/tests/test_off_topic_channel_names.py index 2d273756..34098c92 100644 --- a/pydis_site/apps/api/tests/test_off_topic_channel_names.py +++ b/pydis_site/apps/api/tests/test_off_topic_channel_names.py @@ -74,6 +74,9 @@ class ListTests(AuthenticatedAPITestCase): cls.test_name_3 = OffTopicChannelName.objects.create( name="frozen-with-iceman", used=True, active=False ) + cls.test_name_4 = OffTopicChannelName.objects.create( + name="xith-is-cool", used=True, active=True + ) def test_returns_name_in_list(self): """Return all off-topic channel names.""" @@ -86,28 +89,46 @@ class ListTests(AuthenticatedAPITestCase): { self.test_name.name, self.test_name_2.name, - self.test_name_3.name + self.test_name_3.name, + self.test_name_4.name } ) - def test_returns_two_items_with_random_items_param_set_to_2(self): - """Return not-used name instead used.""" + def test_returns_two_active_items_with_random_items_param_set_to_2(self): + """Return not-used active names instead used.""" url = reverse('api:bot:offtopicchannelname-list') response = self.client.get(f'{url}?random_items=2') self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 2) - self.assertEqual(set(response.json()), {self.test_name.name, self.test_name_2.name}) + self.assertTrue( + all( + item in (self.test_name.name, self.test_name_2.name, self.test_name_4.name) + for item in response.json() + ) + ) + + def test_returns_three_active_items_with_random_items_param_set_to_3(self): + """Return not-used active names instead used.""" + url = reverse('api:bot:offtopicchannelname-list') + response = self.client.get(f'{url}?random_items=3') + + self.assertEqual(response.status_code, 200) + self.assertEqual(len(response.json()), 3) + self.assertEqual( + set(response.json()), + {self.test_name.name, self.test_name_2.name, self.test_name_4.name} + ) def test_running_out_of_names_with_random_parameter(self): - """Reset names `used` parameter to `False` when running out of names.""" + """Reset names `used` parameter to `False` when running out of active names.""" url = reverse('api:bot:offtopicchannelname-list') response = self.client.get(f'{url}?random_items=3') self.assertEqual(response.status_code, 200) self.assertEqual( set(response.json()), - {self.test_name.name, self.test_name_2.name, self.test_name_3.name} + {self.test_name.name, self.test_name_2.name, self.test_name_4.name} ) def test_returns_inactive_ot_names(self): @@ -129,7 +150,7 @@ class ListTests(AuthenticatedAPITestCase): self.assertEqual(response.status_code, 200) self.assertEqual( set(response.json()), - {self.test_name.name, self.test_name_2.name} + {self.test_name.name, self.test_name_2.name, self.test_name_4.name} ) diff --git a/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py b/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py index 78f8c340..d0519e86 100644 --- a/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py +++ b/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py @@ -108,7 +108,7 @@ class OffTopicChannelNameViewSet(ModelViewSet): 'random_items': ["Must be a positive integer."] }) - queryset = self.queryset.order_by('used', '?')[:random_count] + queryset = self.queryset.filter(active=True).order_by('used', '?')[:random_count] # When any name is used in our listing then this means we reached end of round # and we need to reset all other names `used` to False @@ -133,7 +133,6 @@ class OffTopicChannelNameViewSet(ModelViewSet): return Response(serialized.data) params = {} - if active_param := request.query_params.get("active"): params["active"] = active_param.lower() == "true" -- cgit v1.2.3