aboutsummaryrefslogtreecommitdiffstats
path: root/pydis_site/apps/api
diff options
context:
space:
mode:
authorGravatar wookie184 <[email protected]>2024-04-02 19:44:49 +0100
committerGravatar GitHub <[email protected]>2024-04-02 19:44:49 +0100
commita70ad816199a3e3a59d7db8e060e24c4c8e9ff88 (patch)
treebd024ea80c503e22a03821052a70b1c6da8f44a1 /pydis_site/apps/api
parentSet elidable on RunPython operations in migrations (diff)
parentMerge pull request #1279 from python-discord/add-test-case-drf-3.15-regression (diff)
Merge branch 'main' into set-elidable-on-run-python-operations-in-migrations
Diffstat (limited to 'pydis_site/apps/api')
-rw-r--r--pydis_site/apps/api/migrations/0095_user_display_name.py18
-rw-r--r--pydis_site/apps/api/models/bot/user.py5
-rw-r--r--pydis_site/apps/api/serializers.py4
-rw-r--r--pydis_site/apps/api/tests/test_filters.py47
-rw-r--r--pydis_site/apps/api/tests/test_github_webhook_filter.py23
-rw-r--r--pydis_site/apps/api/tests/test_users.py13
-rw-r--r--pydis_site/apps/api/views.py23
-rw-r--r--pydis_site/apps/api/viewsets/bot/user.py14
8 files changed, 132 insertions, 15 deletions
diff --git a/pydis_site/apps/api/migrations/0095_user_display_name.py b/pydis_site/apps/api/migrations/0095_user_display_name.py
new file mode 100644
index 00000000..82381830
--- /dev/null
+++ b/pydis_site/apps/api/migrations/0095_user_display_name.py
@@ -0,0 +1,18 @@
+# Generated by Django 5.0.3 on 2024-04-01 12:21
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("api", "0094_migrate_mailing_listdata"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="user",
+ name="display_name",
+ field=models.CharField(blank=True, help_text="The display name, taken from Discord.", max_length=32),
+ ),
+ migrations.RunSQL("UPDATE api_user SET display_name = name;", elidable=True),
+ ]
diff --git a/pydis_site/apps/api/models/bot/user.py b/pydis_site/apps/api/models/bot/user.py
index afc5ba1e..1cb10988 100644
--- a/pydis_site/apps/api/models/bot/user.py
+++ b/pydis_site/apps/api/models/bot/user.py
@@ -33,6 +33,11 @@ class User(ModelReprMixin, models.Model):
max_length=32,
help_text="The username, taken from Discord.",
)
+ display_name = models.CharField(
+ max_length=32,
+ blank=True,
+ help_text="The display name, taken from Discord.",
+ )
discriminator = models.PositiveSmallIntegerField(
validators=(
MaxValueValidator(
diff --git a/pydis_site/apps/api/serializers.py b/pydis_site/apps/api/serializers.py
index ea94214f..60d3637c 100644
--- a/pydis_site/apps/api/serializers.py
+++ b/pydis_site/apps/api/serializers.py
@@ -434,7 +434,7 @@ class FilterListSerializer(ModelSerializer):
schema = {name: getattr(instance, name) for name in BASE_FILTERLIST_FIELDS}
schema['filters'] = [
FilterSerializer(many=False).to_representation(instance=item)
- for item in Filter.objects.filter(filter_list=instance.id)
+ for item in Filter.objects.filter(filter_list=instance.id).prefetch_related('filter_list')
]
settings = {name: getattr(instance, name) for name in BASE_SETTINGS_FIELDS}
@@ -673,7 +673,7 @@ class UserSerializer(ModelSerializer):
"""Metadata defined for the Django REST Framework."""
model = User
- fields = ('id', 'name', 'discriminator', 'roles', 'in_guild')
+ fields = ('id', 'name', 'display_name', 'discriminator', 'roles', 'in_guild')
depth = 1
list_serializer_class = UserListSerializer
diff --git a/pydis_site/apps/api/tests/test_filters.py b/pydis_site/apps/api/tests/test_filters.py
index 4cef1c8f..96b3a65c 100644
--- a/pydis_site/apps/api/tests/test_filters.py
+++ b/pydis_site/apps/api/tests/test_filters.py
@@ -6,7 +6,7 @@ from typing import Any
from django.db.models import Model
from django.urls import reverse
-from pydis_site.apps.api.models.bot.filters import Filter, FilterList
+from pydis_site.apps.api.models.bot.filters import Filter, FilterList, FilterListType
from pydis_site.apps.api.tests.base import AuthenticatedAPITestCase
@@ -350,3 +350,48 @@ class FilterValidationTests(AuthenticatedAPITestCase):
response = self.client.post(test_filter.url(), data=clean_test_json(test_filter.object))
self.assertEqual(response.status_code, 400)
+
+
+class FilterCreationMissingOptionalFieldsTestCase(AuthenticatedAPITestCase):
+ @classmethod
+ def setUpTestData(cls):
+ cls.filter_list = FilterList.objects.create(
+ name="Ingsoc",
+ list_type=FilterListType.ALLOW,
+ dm_content="But if thought corrupts language, language can also corrupt thought.",
+ dm_embed="",
+ infraction_type="timeout",
+ infraction_duration=timedelta(days=80 * 365),
+ infraction_reason="Thoughtcrime",
+ infraction_channel=1,
+ guild_pings=["@BigBrother"],
+ filter_dm=False,
+ dm_pings=["@BigBrother"],
+ remove_context=True,
+ bypass_roles=[],
+ enabled=True,
+ send_alert=True,
+ enabled_channels=[],
+ disabled_channels=[],
+ enabled_categories=[],
+ disabled_categories=[],
+ )
+
+ def test_creation_missing_optional_fields(self) -> None:
+ data = {
+ "filter_list": self.filter_list.id,
+ "content": "1234567",
+ "description": "Guild \"Python\" - Phishing",
+ "additional_settings": {},
+ "guild_pings": [],
+ "infraction_type": "BAN",
+ "infraction_channel": 1,
+ "infraction_duration": 345600.0,
+ "infraction_reason": (
+ "The creatures outside looked from pig to man, and from man to pig, "
+ "and from pig to man again; but already it was impossible to say which was which"
+ )
+ }
+ endpoint = reverse('api:bot:filter-list')
+ response = self.client.post(endpoint, data=data)
+ self.assertEqual(response.status_code, 201)
diff --git a/pydis_site/apps/api/tests/test_github_webhook_filter.py b/pydis_site/apps/api/tests/test_github_webhook_filter.py
index 8ca60511..d64e1a13 100644
--- a/pydis_site/apps/api/tests/test_github_webhook_filter.py
+++ b/pydis_site/apps/api/tests/test_github_webhook_filter.py
@@ -1,3 +1,4 @@
+import io
from unittest import mock
from urllib.error import HTTPError
@@ -44,8 +45,10 @@ class GitHubWebhookFilterAPITests(APITestCase):
context_mock.read.return_value = b'{"status": "ok"}'
response = self.client.post(url, data=payload, headers=headers)
- self.assertEqual(response.status_code, context_mock.status)
- self.assertEqual(response.headers.get('X-Clacks-Overhead'), 'Joe Armstrong')
+ response_body = response.json()
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(response_body.get("headers", {}).get("X-Clacks-Overhead"), 'Joe Armstrong')
+ self.assertEqual(response_body.get("original_status"), 299)
def test_rate_limit_is_logged_to_sentry(self):
url = reverse('api:github-webhook-filter', args=('id', 'token'))
@@ -56,6 +59,22 @@ class GitHubWebhookFilterAPITests(APITestCase):
mock.patch.object(GitHubWebhookFilterView, "logger") as logger,
):
urlopen.side_effect = HTTPError(None, 429, 'Too Many Requests', {}, None)
+ urlopen.side_effect.fp = io.BytesIO()
+ logger.warning = mock.PropertyMock()
+ self.client.post(url, data=payload, headers=headers)
+
+ logger.warning.assert_called_once()
+
+ def test_other_error_is_logged(self):
+ url = reverse('api:github-webhook-filter', args=('id', 'token'))
+ payload = {}
+ headers = {'X-GitHub-Event': 'pull_request_review'}
+ with (
+ mock.patch('urllib.request.urlopen') as urlopen,
+ mock.patch.object(GitHubWebhookFilterView, "logger") as logger,
+ ):
+ urlopen.side_effect = HTTPError(None, 451, 'Unavailable For Legal Reasons', {}, None)
+ urlopen.side_effect.fp = io.BytesIO()
logger.warning = mock.PropertyMock()
self.client.post(url, data=payload, headers=headers)
diff --git a/pydis_site/apps/api/tests/test_users.py b/pydis_site/apps/api/tests/test_users.py
index cff4a825..5dda6344 100644
--- a/pydis_site/apps/api/tests/test_users.py
+++ b/pydis_site/apps/api/tests/test_users.py
@@ -61,7 +61,8 @@ class CreationTests(AuthenticatedAPITestCase):
url = reverse('api:bot:user-list')
data = {
'id': 42,
- 'name': "Test",
+ 'name': "test",
+ 'display_name': "Test Display",
'discriminator': 42,
'roles': [
self.role.id
@@ -75,6 +76,7 @@ class CreationTests(AuthenticatedAPITestCase):
user = User.objects.get(id=42)
self.assertEqual(user.name, data['name'])
+ self.assertEqual(user.display_name, data['display_name'])
self.assertEqual(user.discriminator, data['discriminator'])
self.assertEqual(user.in_guild, data['in_guild'])
@@ -83,7 +85,8 @@ class CreationTests(AuthenticatedAPITestCase):
data = [
{
'id': 5,
- 'name': "test man",
+ 'name': "testman",
+ 'display_name': "Test Display 1",
'discriminator': 42,
'roles': [
self.role.id
@@ -92,7 +95,8 @@ class CreationTests(AuthenticatedAPITestCase):
},
{
'id': 8,
- 'name': "another test man",
+ 'name': "anothertestman",
+ 'display_name': "Test Display 2",
'discriminator': 555,
'roles': [],
'in_guild': False
@@ -200,7 +204,8 @@ class MultiPatchTests(AuthenticatedAPITestCase):
data = [
{
"id": 1,
- "name": "User 1 patched!",
+ "name": "user1patched",
+ "display_name": "User 1 Patched",
"discriminator": 1010,
"roles": [self.role_developer.id],
"in_guild": False
diff --git a/pydis_site/apps/api/views.py b/pydis_site/apps/api/views.py
index 1fa3efc2..a3b0016c 100644
--- a/pydis_site/apps/api/views.py
+++ b/pydis_site/apps/api/views.py
@@ -303,9 +303,26 @@ class GitHubWebhookFilterView(APIView):
(response_status, headers, body) = self.send_webhook(
webhook_id, webhook_token, request.data, dict(request.headers),
)
- headers.pop('Connection', None)
- headers.pop('Content-Length', None)
- return Response(data=body, headers=headers, status=response_status)
+
+ body_decoded = body.decode("utf-8")
+
+ if (
+ not (status.HTTP_200_OK <= response_status < status.HTTP_300_MULTIPLE_CHOICES)
+ and response_status != status.HTTP_429_TOO_MANY_REQUESTS
+ ):
+ self.logger.warning(
+ "Failed to send GitHub webhook to Discord. Response code %d, body: %s",
+ response_status,
+ body_decoded,
+ )
+
+ response_body = {
+ "original_status": response_status,
+ "data": body_decoded,
+ "headers": headers,
+ }
+
+ return Response(response_body)
def send_webhook(
self,
diff --git a/pydis_site/apps/api/viewsets/bot/user.py b/pydis_site/apps/api/viewsets/bot/user.py
index 77378336..d06eb868 100644
--- a/pydis_site/apps/api/viewsets/bot/user.py
+++ b/pydis_site/apps/api/viewsets/bot/user.py
@@ -64,7 +64,8 @@ class UserViewSet(ModelViewSet):
... 'results': [
... {
... 'id': 409107086526644234,
- ... 'name': "Python",
+ ... 'name': "python",
+ ... 'display_name': "Python",
... 'discriminator': 4329,
... 'roles': [
... 352427296948486144,
@@ -79,6 +80,7 @@ class UserViewSet(ModelViewSet):
#### Optional Query Parameters
- username: username to search for
+ - display_name: display name to search for
- discriminator: discriminator to search for
- page_size: number of Users in one page, defaults to 10,000
- page: page number
@@ -92,7 +94,8 @@ class UserViewSet(ModelViewSet):
#### Response format
>>> {
... 'id': 409107086526644234,
- ... 'name': "Python",
+ ... 'name': "python",
+ ... 'display_name': "Python",
... 'discriminator': 4329,
... 'roles': [
... 352427296948486144,
@@ -170,6 +173,7 @@ class UserViewSet(ModelViewSet):
>>> {
... 'id': int,
... 'name': str,
+ ... 'display_name': str,
... 'discriminator': int,
... 'roles': List[int],
... 'in_guild': bool
@@ -192,6 +196,7 @@ class UserViewSet(ModelViewSet):
>>> {
... 'id': int,
... 'name': str,
+ ... 'display_name': str,
... 'discriminator': int,
... 'roles': List[int],
... 'in_guild': bool
@@ -210,6 +215,7 @@ class UserViewSet(ModelViewSet):
>>> {
... 'id': int,
... 'name': str,
+ ... 'display_name': str,
... 'discriminator': int,
... 'roles': List[int],
... 'in_guild': bool
@@ -229,6 +235,7 @@ class UserViewSet(ModelViewSet):
... {
... 'id': int,
... 'name': str,
+ ... 'display_name': str,
... 'discriminator': int,
... 'roles': List[int],
... 'in_guild': bool
@@ -236,6 +243,7 @@ class UserViewSet(ModelViewSet):
... {
... 'id': int,
... 'name': str,
+ ... 'display_name': str,
... 'discriminator': int,
... 'roles': List[int],
... 'in_guild': bool
@@ -260,7 +268,7 @@ class UserViewSet(ModelViewSet):
queryset = User.objects.all().order_by("id")
pagination_class = UserListPagination
filter_backends = (DjangoFilterBackend,)
- filterset_fields = ('name', 'discriminator')
+ filterset_fields = ('name', 'discriminator', 'display_name')
def get_serializer(self, *args, **kwargs) -> ModelSerializer:
"""Set Serializer many attribute to True if request body contains a list."""