aboutsummaryrefslogtreecommitdiffstats
path: root/pydis_site/apps/api
diff options
context:
space:
mode:
authorGravatar RohanJnr <[email protected]>2021-11-05 10:09:35 +0530
committerGravatar RohanJnr <[email protected]>2021-11-05 10:09:35 +0530
commit747a7b9cb465c85a064ac6e1a0444bcf8a81ec65 (patch)
tree1bb529b764bed5c727a3956b7bb432a18ec82d43 /pydis_site/apps/api
parentMerge branch 'main' into otn_softdel (diff)
parentMerge pull request #617 from python-discord/mbaruh-patch-1 (diff)
Pull from upstream/main and resolve conflicts.
Diffstat (limited to 'pydis_site/apps/api')
-rw-r--r--pydis_site/apps/api/admin.py4
-rw-r--r--pydis_site/apps/api/migrations/0072_doc_allow_blank_base_url.py19
-rw-r--r--pydis_site/apps/api/migrations/0073_otn_allow_GT_and_LT.py19
-rw-r--r--pydis_site/apps/api/models/bot/documentation_link.py1
-rw-r--r--pydis_site/apps/api/models/bot/message_deletion_context.py4
-rw-r--r--pydis_site/apps/api/models/bot/metricity.py10
-rw-r--r--pydis_site/apps/api/models/bot/off_topic_channel_name.py2
-rw-r--r--pydis_site/apps/api/models/utils.py2
-rw-r--r--pydis_site/apps/api/tests/base.py27
-rw-r--r--pydis_site/apps/api/tests/test_deleted_messages.py16
-rw-r--r--pydis_site/apps/api/tests/test_documentation_links.py50
-rw-r--r--pydis_site/apps/api/tests/test_filterlists.py16
-rw-r--r--pydis_site/apps/api/tests/test_healthcheck.py8
-rw-r--r--pydis_site/apps/api/tests/test_infractions.py104
-rw-r--r--pydis_site/apps/api/tests/test_nominations.py86
-rw-r--r--pydis_site/apps/api/tests/test_off_topic_channel_names.py54
-rw-r--r--pydis_site/apps/api/tests/test_offensive_message.py26
-rw-r--r--pydis_site/apps/api/tests/test_reminders.py48
-rw-r--r--pydis_site/apps/api/tests/test_roles.py24
-rw-r--r--pydis_site/apps/api/tests/test_rules.py12
-rw-r--r--pydis_site/apps/api/tests/test_users.py89
-rw-r--r--pydis_site/apps/api/tests/test_validators.py2
-rw-r--r--pydis_site/apps/api/urls.py2
-rw-r--r--pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py4
-rw-r--r--pydis_site/apps/api/viewsets/bot/user.py8
25 files changed, 334 insertions, 303 deletions
diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py
index 449e660e..2aca38a1 100644
--- a/pydis_site/apps/api/admin.py
+++ b/pydis_site/apps/api/admin.py
@@ -48,8 +48,8 @@ class BotSettingAdmin(admin.ModelAdmin):
class DocumentationLinkAdmin(admin.ModelAdmin):
"""Admin formatting for the DocumentationLink model."""
- fields = ("package", "base_url", "inventory_url")
- list_display = ("package", "base_url", "inventory_url")
+ fields = ("package", "inventory_url", "base_url")
+ list_display = ("package", "inventory_url", "base_url")
list_editable = ("base_url", "inventory_url")
search_fields = ("package",)
diff --git a/pydis_site/apps/api/migrations/0072_doc_allow_blank_base_url.py b/pydis_site/apps/api/migrations/0072_doc_allow_blank_base_url.py
new file mode 100644
index 00000000..d4899354
--- /dev/null
+++ b/pydis_site/apps/api/migrations/0072_doc_allow_blank_base_url.py
@@ -0,0 +1,19 @@
+# Generated by Django 3.0.14 on 2021-08-30 21:09
+
+from django.db import migrations, models
+import pydis_site.apps.api.models.bot.documentation_link
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('api', '0071_increase_message_content_4000'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='documentationlink',
+ name='base_url',
+ field=models.URLField(blank=True, help_text='The base URL from which documentation will be available for this project. Used to generate links to various symbols within this package.', validators=[pydis_site.apps.api.models.bot.documentation_link.ends_with_slash_validator]),
+ ),
+ ]
diff --git a/pydis_site/apps/api/migrations/0073_otn_allow_GT_and_LT.py b/pydis_site/apps/api/migrations/0073_otn_allow_GT_and_LT.py
new file mode 100644
index 00000000..09ad13da
--- /dev/null
+++ b/pydis_site/apps/api/migrations/0073_otn_allow_GT_and_LT.py
@@ -0,0 +1,19 @@
+# Generated by Django 3.0.14 on 2021-09-27 20:38
+
+import django.core.validators
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('api', '0072_doc_allow_blank_base_url'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='offtopicchannelname',
+ name='name',
+ field=models.CharField(help_text='The actual channel name that will be used on our Discord server.', max_length=96, primary_key=True, serialize=False, validators=[django.core.validators.RegexValidator(regex="^[a-z0-9\\U0001d5a0-\\U0001d5b9-ǃ?’'<>]+$")]),
+ ),
+ ]
diff --git a/pydis_site/apps/api/models/bot/documentation_link.py b/pydis_site/apps/api/models/bot/documentation_link.py
index 3dcc71fc..9941907c 100644
--- a/pydis_site/apps/api/models/bot/documentation_link.py
+++ b/pydis_site/apps/api/models/bot/documentation_link.py
@@ -30,6 +30,7 @@ class DocumentationLink(ModelReprMixin, models.Model):
"The base URL from which documentation will be available for this project. "
"Used to generate links to various symbols within this package."
),
+ blank=True,
validators=(ends_with_slash_validator,)
)
inventory_url = models.URLField(
diff --git a/pydis_site/apps/api/models/bot/message_deletion_context.py b/pydis_site/apps/api/models/bot/message_deletion_context.py
index 1410250a..25741266 100644
--- a/pydis_site/apps/api/models/bot/message_deletion_context.py
+++ b/pydis_site/apps/api/models/bot/message_deletion_context.py
@@ -1,5 +1,5 @@
from django.db import models
-from django_hosts.resolvers import reverse
+from django.urls import reverse
from pydis_site.apps.api.models.bot.user import User
from pydis_site.apps.api.models.mixins import ModelReprMixin
@@ -33,7 +33,7 @@ class MessageDeletionContext(ModelReprMixin, models.Model):
@property
def log_url(self) -> str:
"""Create the url for the deleted message logs."""
- return reverse('logs', host="staff", args=(self.id,))
+ return reverse('staff:logs', args=(self.id,))
class Meta:
"""Set the ordering for list views to newest first."""
diff --git a/pydis_site/apps/api/models/bot/metricity.py b/pydis_site/apps/api/models/bot/metricity.py
index 5daa5c66..33fb7ad7 100644
--- a/pydis_site/apps/api/models/bot/metricity.py
+++ b/pydis_site/apps/api/models/bot/metricity.py
@@ -10,7 +10,7 @@ EXCLUDE_CHANNELS = [
]
-class NotFound(Exception):
+class NotFoundError(Exception):
"""Raised when an entity cannot be found."""
pass
@@ -37,7 +37,7 @@ class Metricity:
values = self.cursor.fetchone()
if not values:
- raise NotFound()
+ raise NotFoundError()
return dict(zip(columns, values))
@@ -58,7 +58,7 @@ class Metricity:
values = self.cursor.fetchone()
if not values:
- raise NotFound()
+ raise NotFoundError()
return values[0]
@@ -88,7 +88,7 @@ class Metricity:
values = self.cursor.fetchone()
if not values:
- raise NotFound()
+ raise NotFoundError()
return values[0]
@@ -127,6 +127,6 @@ class Metricity:
values = self.cursor.fetchall()
if not values:
- raise NotFound()
+ raise NotFoundError()
return values
diff --git a/pydis_site/apps/api/models/bot/off_topic_channel_name.py b/pydis_site/apps/api/models/bot/off_topic_channel_name.py
index 582c069e..e9fec114 100644
--- a/pydis_site/apps/api/models/bot/off_topic_channel_name.py
+++ b/pydis_site/apps/api/models/bot/off_topic_channel_name.py
@@ -11,7 +11,7 @@ class OffTopicChannelName(ModelReprMixin, models.Model):
primary_key=True,
max_length=96,
validators=(
- RegexValidator(regex=r"^[a-z0-9\U0001d5a0-\U0001d5b9-ǃ?’']+$"),
+ RegexValidator(regex=r"^[a-z0-9\U0001d5a0-\U0001d5b9-ǃ?’'<>]+$"),
),
help_text="The actual channel name that will be used on our Discord server."
)
diff --git a/pydis_site/apps/api/models/utils.py b/pydis_site/apps/api/models/utils.py
index 107231ba..0e220a1d 100644
--- a/pydis_site/apps/api/models/utils.py
+++ b/pydis_site/apps/api/models/utils.py
@@ -142,7 +142,7 @@ def validate_embed(embed: Any) -> None:
),
MaxLengthValidator(limit_value=256)
),
- 'description': (MaxLengthValidator(limit_value=2048),),
+ 'description': (MaxLengthValidator(limit_value=4096),),
'fields': (
MaxLengthValidator(limit_value=25),
validate_embed_fields
diff --git a/pydis_site/apps/api/tests/base.py b/pydis_site/apps/api/tests/base.py
index 61c23b0f..c9f3cb7e 100644
--- a/pydis_site/apps/api/tests/base.py
+++ b/pydis_site/apps/api/tests/base.py
@@ -11,7 +11,7 @@ test_user, _created = User.objects.get_or_create(
)
-class APISubdomainTestCase(APITestCase):
+class AuthenticatedAPITestCase(APITestCase):
"""
Configures the test client.
@@ -24,14 +24,13 @@ class APISubdomainTestCase(APITestCase):
`self.client.force_authenticate(user=created_user)` to force authentication
through the created user.
- Using this performs the following niceties for you which ease writing tests:
- - setting the `HTTP_HOST` request header to `api.pythondiscord.local:8000`, and
+ Using this performs the following nicety for you which eases writing tests:
- forcing authentication for the test user.
If you don't want to force authentication (for example, to test a route's response
for an unauthenticated user), un-force authentication by using the following:
- >>> from pydis_site.apps.api.tests.base import APISubdomainTestCase
- >>> class UnauthedUserTestCase(APISubdomainTestCase):
+ >>> from pydis_site.apps.api.tests.base import AuthenticatedAPITestCase
+ >>> class UnauthedUserTestCase(AuthenticatedAPITestCase):
... def setUp(self):
... super().setUp()
... self.client.force_authentication(user=None)
@@ -42,30 +41,26 @@ class APISubdomainTestCase(APITestCase):
... resp = self.client.delete('/my-publicly-readable-endpoint/42')
... self.assertEqual(resp.status_code, 401)
- Make sure to include the `super().setUp(self)` call, otherwise, you may get
- status code 404 for some URLs due to the missing `HTTP_HOST` header.
-
## Example
Using this in a test case is rather straightforward:
- >>> from pydis_site.apps.api.tests.base import APISubdomainTestCase
- >>> class MyAPITestCase(APISubdomainTestCase):
+ >>> from pydis_site.apps.api.tests.base import AuthenticatedAPITestCase
+ >>> class MyAPITestCase(AuthenticatedAPITestCase):
... def test_that_it_works(self):
... response = self.client.get('/my-endpoint')
... self.assertEqual(response.status_code, 200)
- To reverse URLs of the API host, you need to use `django_hosts`:
+ To reverse URLs of the API host, you need to use `django.urls`:
- >>> from django_hosts.resolvers import reverse
- >>> from pydis_site.apps.api.tests.base import APISubdomainTestCase
- >>> class MyReversedTestCase(APISubdomainTestCase):
+ >>> from django.urls import reverse
+ >>> from pydis_site.apps.api.tests.base import AuthenticatedAPITestCase
+ >>> class MyReversedTestCase(AuthenticatedAPITestCase):
... def test_my_endpoint(self):
- ... url = reverse('user-detail', host='api')
+ ... url = reverse('api:user-detail')
... response = self.client.get(url)
... self.assertEqual(response.status_code, 200)
"""
def setUp(self):
super().setUp()
- self.client.defaults['HTTP_HOST'] = 'api.pythondiscord.local:8000'
self.client.force_authenticate(test_user)
diff --git a/pydis_site/apps/api/tests/test_deleted_messages.py b/pydis_site/apps/api/tests/test_deleted_messages.py
index 40450844..1eb535d8 100644
--- a/pydis_site/apps/api/tests/test_deleted_messages.py
+++ b/pydis_site/apps/api/tests/test_deleted_messages.py
@@ -1,13 +1,13 @@
from datetime import datetime
+from django.urls import reverse
from django.utils import timezone
-from django_hosts.resolvers import reverse
-from .base import APISubdomainTestCase
+from .base import AuthenticatedAPITestCase
from ..models import MessageDeletionContext, User
-class DeletedMessagesWithoutActorTests(APISubdomainTestCase):
+class DeletedMessagesWithoutActorTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.author = User.objects.create(
@@ -40,14 +40,14 @@ class DeletedMessagesWithoutActorTests(APISubdomainTestCase):
}
def test_accepts_valid_data(self):
- url = reverse('bot:messagedeletioncontext-list', host='api')
+ url = reverse('api:bot:messagedeletioncontext-list')
response = self.client.post(url, data=self.data)
self.assertEqual(response.status_code, 201)
[context] = MessageDeletionContext.objects.all()
self.assertIsNone(context.actor)
-class DeletedMessagesWithActorTests(APISubdomainTestCase):
+class DeletedMessagesWithActorTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.author = cls.actor = User.objects.create(
@@ -72,14 +72,14 @@ class DeletedMessagesWithActorTests(APISubdomainTestCase):
}
def test_accepts_valid_data_and_sets_actor(self):
- url = reverse('bot:messagedeletioncontext-list', host='api')
+ url = reverse('api:bot:messagedeletioncontext-list')
response = self.client.post(url, data=self.data)
self.assertEqual(response.status_code, 201)
[context] = MessageDeletionContext.objects.all()
self.assertEqual(context.actor.id, self.actor.id)
-class DeletedMessagesLogURLTests(APISubdomainTestCase):
+class DeletedMessagesLogURLTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.author = cls.actor = User.objects.create(
@@ -94,6 +94,6 @@ class DeletedMessagesLogURLTests(APISubdomainTestCase):
)
def test_valid_log_url(self):
- expected_url = reverse('logs', host="staff", args=(1,))
+ expected_url = reverse('staff:logs', args=(1,))
[context] = MessageDeletionContext.objects.all()
self.assertEqual(context.log_url, expected_url)
diff --git a/pydis_site/apps/api/tests/test_documentation_links.py b/pydis_site/apps/api/tests/test_documentation_links.py
index 39fb08f3..4e238cbb 100644
--- a/pydis_site/apps/api/tests/test_documentation_links.py
+++ b/pydis_site/apps/api/tests/test_documentation_links.py
@@ -1,61 +1,61 @@
-from django_hosts.resolvers import reverse
+from django.urls import reverse
-from .base import APISubdomainTestCase
+from .base import AuthenticatedAPITestCase
from ..models import DocumentationLink
-class UnauthedDocumentationLinkAPITests(APISubdomainTestCase):
+class UnauthedDocumentationLinkAPITests(AuthenticatedAPITestCase):
def setUp(self):
super().setUp()
self.client.force_authenticate(user=None)
def test_detail_lookup_returns_401(self):
- url = reverse('bot:documentationlink-detail', args=('whatever',), host='api')
+ url = reverse('api:bot:documentationlink-detail', args=('whatever',))
response = self.client.get(url)
self.assertEqual(response.status_code, 401)
def test_list_returns_401(self):
- url = reverse('bot:documentationlink-list', host='api')
+ url = reverse('api:bot:documentationlink-list')
response = self.client.get(url)
self.assertEqual(response.status_code, 401)
def test_create_returns_401(self):
- url = reverse('bot:documentationlink-list', host='api')
+ url = reverse('api:bot:documentationlink-list')
response = self.client.post(url, data={'hi': 'there'})
self.assertEqual(response.status_code, 401)
def test_delete_returns_401(self):
- url = reverse('bot:documentationlink-detail', args=('whatever',), host='api')
+ url = reverse('api:bot:documentationlink-detail', args=('whatever',))
response = self.client.delete(url)
self.assertEqual(response.status_code, 401)
-class EmptyDatabaseDocumentationLinkAPITests(APISubdomainTestCase):
+class EmptyDatabaseDocumentationLinkAPITests(AuthenticatedAPITestCase):
def test_detail_lookup_returns_404(self):
- url = reverse('bot:documentationlink-detail', args=('whatever',), host='api')
+ url = reverse('api:bot:documentationlink-detail', args=('whatever',))
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
def test_list_all_returns_empty_list(self):
- url = reverse('bot:documentationlink-list', host='api')
+ url = reverse('api:bot:documentationlink-list')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), [])
def test_delete_returns_404(self):
- url = reverse('bot:documentationlink-detail', args=('whatever',), host='api')
+ url = reverse('api:bot:documentationlink-detail', args=('whatever',))
response = self.client.delete(url)
self.assertEqual(response.status_code, 404)
-class DetailLookupDocumentationLinkAPITests(APISubdomainTestCase):
+class DetailLookupDocumentationLinkAPITests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.doc_link = DocumentationLink.objects.create(
@@ -71,27 +71,27 @@ class DetailLookupDocumentationLinkAPITests(APISubdomainTestCase):
}
def test_detail_lookup_unknown_package_returns_404(self):
- url = reverse('bot:documentationlink-detail', args=('whatever',), host='api')
+ url = reverse('api:bot:documentationlink-detail', args=('whatever',))
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
def test_detail_lookup_created_package_returns_package(self):
- url = reverse('bot:documentationlink-detail', args=(self.doc_link.package,), host='api')
+ url = reverse('api:bot:documentationlink-detail', args=(self.doc_link.package,))
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), self.doc_json)
def test_list_all_packages_shows_created_package(self):
- url = reverse('bot:documentationlink-list', host='api')
+ url = reverse('api:bot:documentationlink-list')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), [self.doc_json])
def test_create_invalid_body_returns_400(self):
- url = reverse('bot:documentationlink-list', host='api')
+ url = reverse('api:bot:documentationlink-list')
response = self.client.post(url, data={'i': 'am', 'totally': 'valid'})
self.assertEqual(response.status_code, 400)
@@ -103,7 +103,7 @@ class DetailLookupDocumentationLinkAPITests(APISubdomainTestCase):
'inventory_url': 'totally an url'
}
- url = reverse('bot:documentationlink-list', host='api')
+ url = reverse('api:bot:documentationlink-list')
response = self.client.post(url, data=body)
self.assertEqual(response.status_code, 400)
@@ -114,13 +114,13 @@ class DetailLookupDocumentationLinkAPITests(APISubdomainTestCase):
with self.subTest(package_name=case):
body = self.doc_json.copy()
body['package'] = case
- url = reverse('bot:documentationlink-list', host='api')
+ url = reverse('api:bot:documentationlink-list')
response = self.client.post(url, data=body)
self.assertEqual(response.status_code, 400)
-class DocumentationLinkCreationTests(APISubdomainTestCase):
+class DocumentationLinkCreationTests(AuthenticatedAPITestCase):
def setUp(self):
super().setUp()
@@ -130,27 +130,27 @@ class DocumentationLinkCreationTests(APISubdomainTestCase):
'inventory_url': 'https://docs.example.com'
}
- url = reverse('bot:documentationlink-list', host='api')
+ url = reverse('api:bot:documentationlink-list')
response = self.client.post(url, data=self.body)
self.assertEqual(response.status_code, 201)
def test_package_in_full_list(self):
- url = reverse('bot:documentationlink-list', host='api')
+ url = reverse('api:bot:documentationlink-list')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), [self.body])
def test_detail_lookup_works_with_package(self):
- url = reverse('bot:documentationlink-detail', args=(self.body['package'],), host='api')
+ url = reverse('api:bot:documentationlink-detail', args=(self.body['package'],))
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), self.body)
-class DocumentationLinkDeletionTests(APISubdomainTestCase):
+class DocumentationLinkDeletionTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.doc_link = DocumentationLink.objects.create(
@@ -160,13 +160,13 @@ class DocumentationLinkDeletionTests(APISubdomainTestCase):
)
def test_unknown_package_returns_404(self):
- url = reverse('bot:documentationlink-detail', args=('whatever',), host='api')
+ url = reverse('api:bot:documentationlink-detail', args=('whatever',))
response = self.client.delete(url)
self.assertEqual(response.status_code, 404)
def test_delete_known_package_returns_204(self):
- url = reverse('bot:documentationlink-detail', args=(self.doc_link.package,), host='api')
+ url = reverse('api:bot:documentationlink-detail', args=(self.doc_link.package,))
response = self.client.delete(url)
self.assertEqual(response.status_code, 204)
diff --git a/pydis_site/apps/api/tests/test_filterlists.py b/pydis_site/apps/api/tests/test_filterlists.py
index 188c0fff..5a5bca60 100644
--- a/pydis_site/apps/api/tests/test_filterlists.py
+++ b/pydis_site/apps/api/tests/test_filterlists.py
@@ -1,9 +1,9 @@
-from django_hosts.resolvers import reverse
+from django.urls import reverse
from pydis_site.apps.api.models import FilterList
-from pydis_site.apps.api.tests.base import APISubdomainTestCase
+from pydis_site.apps.api.tests.base import AuthenticatedAPITestCase
-URL = reverse('bot:filterlist-list', host='api')
+URL = reverse('api:bot:filterlist-list')
JPEG_ALLOWLIST = {
"type": 'FILE_FORMAT',
"allowed": True,
@@ -16,7 +16,7 @@ PNG_ALLOWLIST = {
}
-class UnauthenticatedTests(APISubdomainTestCase):
+class UnauthenticatedTests(AuthenticatedAPITestCase):
def setUp(self):
super().setUp()
self.client.force_authenticate(user=None)
@@ -27,7 +27,7 @@ class UnauthenticatedTests(APISubdomainTestCase):
self.assertEqual(response.status_code, 401)
-class EmptyDatabaseTests(APISubdomainTestCase):
+class EmptyDatabaseTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
FilterList.objects.all().delete()
@@ -39,7 +39,7 @@ class EmptyDatabaseTests(APISubdomainTestCase):
self.assertEqual(response.json(), [])
-class FetchTests(APISubdomainTestCase):
+class FetchTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
FilterList.objects.all().delete()
@@ -68,7 +68,7 @@ class FetchTests(APISubdomainTestCase):
self.assertEquals(api_type[1], model_type[1])
-class CreationTests(APISubdomainTestCase):
+class CreationTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
FilterList.objects.all().delete()
@@ -103,7 +103,7 @@ class CreationTests(APISubdomainTestCase):
self.assertEqual(response.status_code, 400)
-class DeletionTests(APISubdomainTestCase):
+class DeletionTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
FilterList.objects.all().delete()
diff --git a/pydis_site/apps/api/tests/test_healthcheck.py b/pydis_site/apps/api/tests/test_healthcheck.py
index b0fd71bf..650403ad 100644
--- a/pydis_site/apps/api/tests/test_healthcheck.py
+++ b/pydis_site/apps/api/tests/test_healthcheck.py
@@ -1,15 +1,15 @@
-from django_hosts.resolvers import reverse
+from django.urls import reverse
-from .base import APISubdomainTestCase
+from .base import AuthenticatedAPITestCase
-class UnauthedHealthcheckAPITests(APISubdomainTestCase):
+class UnauthedHealthcheckAPITests(AuthenticatedAPITestCase):
def setUp(self):
super().setUp()
self.client.force_authenticate(user=None)
def test_can_access_healthcheck_view(self):
- url = reverse('healthcheck', host='api')
+ url = reverse('api:healthcheck')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
diff --git a/pydis_site/apps/api/tests/test_infractions.py b/pydis_site/apps/api/tests/test_infractions.py
index 9aae16c0..b3dd16ee 100644
--- a/pydis_site/apps/api/tests/test_infractions.py
+++ b/pydis_site/apps/api/tests/test_infractions.py
@@ -4,44 +4,44 @@ from unittest.mock import patch
from urllib.parse import quote
from django.db.utils import IntegrityError
-from django_hosts.resolvers import reverse
+from django.urls import reverse
-from .base import APISubdomainTestCase
+from .base import AuthenticatedAPITestCase
from ..models import Infraction, User
from ..serializers import InfractionSerializer
-class UnauthenticatedTests(APISubdomainTestCase):
+class UnauthenticatedTests(AuthenticatedAPITestCase):
def setUp(self):
super().setUp()
self.client.force_authenticate(user=None)
def test_detail_lookup_returns_401(self):
- url = reverse('bot:infraction-detail', args=(6,), host='api')
+ url = reverse('api:bot:infraction-detail', args=(6,))
response = self.client.get(url)
self.assertEqual(response.status_code, 401)
def test_list_returns_401(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
response = self.client.get(url)
self.assertEqual(response.status_code, 401)
def test_create_returns_401(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
response = self.client.post(url, data={'reason': 'Have a nice day.'})
self.assertEqual(response.status_code, 401)
def test_partial_update_returns_401(self):
- url = reverse('bot:infraction-detail', args=(6,), host='api')
+ url = reverse('api:bot:infraction-detail', args=(6,))
response = self.client.patch(url, data={'reason': 'Have a nice day.'})
self.assertEqual(response.status_code, 401)
-class InfractionTests(APISubdomainTestCase):
+class InfractionTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.user = User.objects.create(
@@ -92,7 +92,7 @@ class InfractionTests(APISubdomainTestCase):
def test_list_all(self):
"""Tests the list-view, which should be ordered by inserted_at (newest first)."""
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
@@ -106,7 +106,7 @@ class InfractionTests(APISubdomainTestCase):
self.assertEqual(infractions[4]['id'], self.ban_hidden.id)
def test_filter_search(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
pattern = quote(r'^James(\s\w+){3},')
response = self.client.get(f'{url}?search={pattern}')
@@ -117,7 +117,7 @@ class InfractionTests(APISubdomainTestCase):
self.assertEqual(infractions[0]['id'], self.ban_inactive.id)
def test_filter_field(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
response = self.client.get(f'{url}?type=ban&hidden=true')
self.assertEqual(response.status_code, 200)
@@ -127,7 +127,7 @@ class InfractionTests(APISubdomainTestCase):
self.assertEqual(infractions[0]['id'], self.ban_hidden.id)
def test_filter_permanent_false(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
response = self.client.get(f'{url}?type=mute&permanent=false')
self.assertEqual(response.status_code, 200)
@@ -136,7 +136,7 @@ class InfractionTests(APISubdomainTestCase):
self.assertEqual(len(infractions), 0)
def test_filter_permanent_true(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
response = self.client.get(f'{url}?type=mute&permanent=true')
self.assertEqual(response.status_code, 200)
@@ -145,7 +145,7 @@ class InfractionTests(APISubdomainTestCase):
self.assertEqual(infractions[0]['id'], self.mute_permanent.id)
def test_filter_after(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
target_time = datetime.datetime.utcnow() + datetime.timedelta(hours=5)
response = self.client.get(f'{url}?type=superstar&expires_after={target_time.isoformat()}')
@@ -154,7 +154,7 @@ class InfractionTests(APISubdomainTestCase):
self.assertEqual(len(infractions), 0)
def test_filter_before(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
target_time = datetime.datetime.utcnow() + datetime.timedelta(hours=5)
response = self.client.get(f'{url}?type=superstar&expires_before={target_time.isoformat()}')
@@ -164,21 +164,21 @@ class InfractionTests(APISubdomainTestCase):
self.assertEqual(infractions[0]['id'], self.superstar_expires_soon.id)
def test_filter_after_invalid(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
response = self.client.get(f'{url}?expires_after=gibberish')
self.assertEqual(response.status_code, 400)
self.assertEqual(list(response.json())[0], "expires_after")
def test_filter_before_invalid(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
response = self.client.get(f'{url}?expires_before=000000000')
self.assertEqual(response.status_code, 400)
self.assertEqual(list(response.json())[0], "expires_before")
def test_after_before_before(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
target_time = datetime.datetime.utcnow() + datetime.timedelta(hours=4)
target_time_late = datetime.datetime.utcnow() + datetime.timedelta(hours=6)
response = self.client.get(
@@ -191,7 +191,7 @@ class InfractionTests(APISubdomainTestCase):
self.assertEqual(response.json()[0]["id"], self.superstar_expires_soon.id)
def test_after_after_before_invalid(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
target_time = datetime.datetime.utcnow() + datetime.timedelta(hours=5)
target_time_late = datetime.datetime.utcnow() + datetime.timedelta(hours=9)
response = self.client.get(
@@ -205,7 +205,7 @@ class InfractionTests(APISubdomainTestCase):
self.assertIn("expires_after", errors)
def test_permanent_after_invalid(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
target_time = datetime.datetime.utcnow() + datetime.timedelta(hours=5)
response = self.client.get(f'{url}?permanent=true&expires_after={target_time.isoformat()}')
@@ -214,7 +214,7 @@ class InfractionTests(APISubdomainTestCase):
self.assertEqual("permanent", errors[0])
def test_permanent_before_invalid(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
target_time = datetime.datetime.utcnow() + datetime.timedelta(hours=5)
response = self.client.get(f'{url}?permanent=true&expires_before={target_time.isoformat()}')
@@ -223,7 +223,7 @@ class InfractionTests(APISubdomainTestCase):
self.assertEqual("permanent", errors[0])
def test_nonpermanent_before(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
target_time = datetime.datetime.utcnow() + datetime.timedelta(hours=6)
response = self.client.get(
f'{url}?permanent=false&expires_before={target_time.isoformat()}'
@@ -234,7 +234,7 @@ class InfractionTests(APISubdomainTestCase):
self.assertEqual(response.json()[0]["id"], self.superstar_expires_soon.id)
def test_filter_manytypes(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
response = self.client.get(f'{url}?types=mute,ban')
self.assertEqual(response.status_code, 200)
@@ -242,7 +242,7 @@ class InfractionTests(APISubdomainTestCase):
self.assertEqual(len(infractions), 3)
def test_types_type_invalid(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
response = self.client.get(f'{url}?types=mute,ban&type=superstar')
self.assertEqual(response.status_code, 400)
@@ -250,7 +250,7 @@ class InfractionTests(APISubdomainTestCase):
self.assertEqual("types", errors[0])
def test_sort_expiresby(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
response = self.client.get(f'{url}?ordering=expires_at&permanent=false')
self.assertEqual(response.status_code, 200)
infractions = response.json()
@@ -261,34 +261,34 @@ class InfractionTests(APISubdomainTestCase):
self.assertEqual(infractions[2]['id'], self.ban_hidden.id)
def test_returns_empty_for_no_match(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
response = self.client.get(f'{url}?type=ban&search=poop')
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.json()), 0)
def test_ignores_bad_filters(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
response = self.client.get(f'{url}?type=ban&hidden=maybe&foo=bar')
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.json()), 2)
def test_retrieve_single_from_id(self):
- url = reverse('bot:infraction-detail', args=(self.ban_inactive.id,), host='api')
+ url = reverse('api:bot:infraction-detail', args=(self.ban_inactive.id,))
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json()['id'], self.ban_inactive.id)
def test_retrieve_returns_404_for_absent_id(self):
- url = reverse('bot:infraction-detail', args=(1337,), host='api')
+ url = reverse('api:bot:infraction-detail', args=(1337,))
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
def test_partial_update(self):
- url = reverse('bot:infraction-detail', args=(self.ban_hidden.id,), host='api')
+ url = reverse('api:bot:infraction-detail', args=(self.ban_hidden.id,))
data = {
'expires_at': '4143-02-15T21:04:31+00:00',
'active': False,
@@ -313,7 +313,7 @@ class InfractionTests(APISubdomainTestCase):
self.assertEqual(infraction.hidden, self.ban_hidden.hidden)
def test_partial_update_returns_400_for_frozen_field(self):
- url = reverse('bot:infraction-detail', args=(self.ban_hidden.id,), host='api')
+ url = reverse('api:bot:infraction-detail', args=(self.ban_hidden.id,))
data = {'user': 6}
response = self.client.patch(url, data=data)
@@ -323,7 +323,7 @@ class InfractionTests(APISubdomainTestCase):
})
-class CreationTests(APISubdomainTestCase):
+class CreationTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.user = User.objects.create(
@@ -338,7 +338,7 @@ class CreationTests(APISubdomainTestCase):
)
def test_accepts_valid_data(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
data = {
'user': self.user.id,
'actor': self.user.id,
@@ -367,7 +367,7 @@ class CreationTests(APISubdomainTestCase):
self.assertEqual(infraction.active, True)
def test_returns_400_for_missing_user(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
data = {
'actor': self.user.id,
'type': 'kick',
@@ -381,7 +381,7 @@ class CreationTests(APISubdomainTestCase):
})
def test_returns_400_for_bad_user(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
data = {
'user': 1337,
'actor': self.user.id,
@@ -396,7 +396,7 @@ class CreationTests(APISubdomainTestCase):
})
def test_returns_400_for_bad_type(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
data = {
'user': self.user.id,
'actor': self.user.id,
@@ -411,7 +411,7 @@ class CreationTests(APISubdomainTestCase):
})
def test_returns_400_for_bad_expired_at_format(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
data = {
'user': self.user.id,
'actor': self.user.id,
@@ -430,7 +430,7 @@ class CreationTests(APISubdomainTestCase):
})
def test_returns_400_for_expiring_non_expirable_type(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
for infraction_type in ('kick', 'warning'):
data = {
@@ -448,7 +448,7 @@ class CreationTests(APISubdomainTestCase):
})
def test_returns_400_for_hidden_non_hideable_type(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
for infraction_type in ('superstar', 'warning'):
data = {
@@ -466,7 +466,7 @@ class CreationTests(APISubdomainTestCase):
})
def test_returns_400_for_non_hidden_required_hidden_type(self):
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
data = {
'user': self.user.id,
@@ -484,7 +484,7 @@ class CreationTests(APISubdomainTestCase):
def test_returns_400_for_active_infraction_of_type_that_cannot_be_active(self):
"""Test if the API rejects active infractions for types that cannot be active."""
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
restricted_types = (
('note', True),
('warning', False),
@@ -511,7 +511,7 @@ class CreationTests(APISubdomainTestCase):
def test_returns_400_for_second_active_infraction_of_the_same_type(self):
"""Test if the API rejects a second active infraction of the same type for a given user."""
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
active_infraction_types = ('mute', 'ban', 'superstar')
for infraction_type in active_infraction_types:
@@ -550,7 +550,7 @@ class CreationTests(APISubdomainTestCase):
def test_returns_201_for_second_active_infraction_of_different_type(self):
"""Test if the API accepts a second active infraction of a different type than the first."""
- url = reverse('bot:infraction-list', host='api')
+ url = reverse('api:bot:infraction-list')
first_active_infraction = {
'user': self.user.id,
'actor': self.user.id,
@@ -677,7 +677,7 @@ class CreationTests(APISubdomainTestCase):
)
-class InfractionDeletionTests(APISubdomainTestCase):
+class InfractionDeletionTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.user = User.objects.create(
@@ -694,20 +694,20 @@ class InfractionDeletionTests(APISubdomainTestCase):
)
def test_delete_unknown_infraction_returns_404(self):
- url = reverse('bot:infraction-detail', args=('something',), host='api')
+ url = reverse('api:bot:infraction-detail', args=('something',))
response = self.client.delete(url)
self.assertEqual(response.status_code, 404)
def test_delete_known_infraction_returns_204(self):
- url = reverse('bot:infraction-detail', args=(self.warning.id,), host='api')
+ url = reverse('api:bot:infraction-detail', args=(self.warning.id,))
response = self.client.delete(url)
self.assertEqual(response.status_code, 204)
self.assertRaises(Infraction.DoesNotExist, Infraction.objects.get, id=self.warning.id)
-class ExpandedTests(APISubdomainTestCase):
+class ExpandedTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.user = User.objects.create(
@@ -735,7 +735,7 @@ class ExpandedTests(APISubdomainTestCase):
self.assertTrue(field in obj, msg=f'field "{field}" missing from {key}')
def test_list_expanded(self):
- url = reverse('bot:infraction-list-expanded', host='api')
+ url = reverse('api:bot:infraction-list-expanded')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
@@ -747,7 +747,7 @@ class ExpandedTests(APISubdomainTestCase):
self.check_expanded_fields(infraction)
def test_create_expanded(self):
- url = reverse('bot:infraction-list-expanded', host='api')
+ url = reverse('api:bot:infraction-list-expanded')
data = {
'user': self.user.id,
'actor': self.user.id,
@@ -762,7 +762,7 @@ class ExpandedTests(APISubdomainTestCase):
self.check_expanded_fields(response.json())
def test_retrieve_expanded(self):
- url = reverse('bot:infraction-detail-expanded', args=(self.warning.id,), host='api')
+ url = reverse('api:bot:infraction-detail-expanded', args=(self.warning.id,))
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
@@ -772,7 +772,7 @@ class ExpandedTests(APISubdomainTestCase):
self.check_expanded_fields(infraction)
def test_partial_update_expanded(self):
- url = reverse('bot:infraction-detail-expanded', args=(self.kick.id,), host='api')
+ url = reverse('api:bot:infraction-detail-expanded', args=(self.kick.id,))
data = {'active': False}
response = self.client.patch(url, data=data)
@@ -783,7 +783,7 @@ class ExpandedTests(APISubdomainTestCase):
self.check_expanded_fields(response.json())
-class SerializerTests(APISubdomainTestCase):
+class SerializerTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.user = User.objects.create(
diff --git a/pydis_site/apps/api/tests/test_nominations.py b/pydis_site/apps/api/tests/test_nominations.py
index 9cefbd8f..62b2314c 100644
--- a/pydis_site/apps/api/tests/test_nominations.py
+++ b/pydis_site/apps/api/tests/test_nominations.py
@@ -1,12 +1,12 @@
from datetime import datetime as dt, timedelta, timezone
-from django_hosts.resolvers import reverse
+from django.urls import reverse
-from .base import APISubdomainTestCase
+from .base import AuthenticatedAPITestCase
from ..models import Nomination, NominationEntry, User
-class CreationTests(APISubdomainTestCase):
+class CreationTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.user = User.objects.create(
@@ -21,7 +21,7 @@ class CreationTests(APISubdomainTestCase):
)
def test_accepts_valid_data(self):
- url = reverse('bot:nomination-list', host='api')
+ url = reverse('api:bot:nomination-list')
data = {
'actor': self.user.id,
'reason': 'Joe Dart on Fender Bass',
@@ -46,7 +46,7 @@ class CreationTests(APISubdomainTestCase):
self.assertEqual(nomination.active, True)
def test_returns_200_on_second_active_nomination_by_different_user(self):
- url = reverse('bot:nomination-list', host='api')
+ url = reverse('api:bot:nomination-list')
first_data = {
'actor': self.user.id,
'reason': 'Joe Dart on Fender Bass',
@@ -65,7 +65,7 @@ class CreationTests(APISubdomainTestCase):
self.assertEqual(response2.status_code, 201)
def test_returns_400_on_second_active_nomination_by_existing_nominator(self):
- url = reverse('bot:nomination-list', host='api')
+ url = reverse('api:bot:nomination-list')
data = {
'actor': self.user.id,
'reason': 'Joe Dart on Fender Bass',
@@ -82,7 +82,7 @@ class CreationTests(APISubdomainTestCase):
})
def test_returns_400_for_missing_user(self):
- url = reverse('bot:nomination-list', host='api')
+ url = reverse('api:bot:nomination-list')
data = {
'actor': self.user.id,
'reason': 'Joe Dart on Fender Bass',
@@ -95,7 +95,7 @@ class CreationTests(APISubdomainTestCase):
})
def test_returns_400_for_missing_actor(self):
- url = reverse('bot:nomination-list', host='api')
+ url = reverse('api:bot:nomination-list')
data = {
'user': self.user.id,
'reason': 'Joe Dart on Fender Bass',
@@ -108,7 +108,7 @@ class CreationTests(APISubdomainTestCase):
})
def test_returns_201_for_missing_reason(self):
- url = reverse('bot:nomination-list', host='api')
+ url = reverse('api:bot:nomination-list')
data = {
'user': self.user.id,
'actor': self.user.id,
@@ -118,7 +118,7 @@ class CreationTests(APISubdomainTestCase):
self.assertEqual(response.status_code, 201)
def test_returns_400_for_bad_user(self):
- url = reverse('bot:nomination-list', host='api')
+ url = reverse('api:bot:nomination-list')
data = {
'user': 1024,
'reason': 'Joe Dart on Fender Bass',
@@ -132,7 +132,7 @@ class CreationTests(APISubdomainTestCase):
})
def test_returns_400_for_bad_actor(self):
- url = reverse('bot:nomination-list', host='api')
+ url = reverse('api:bot:nomination-list')
data = {
'user': self.user.id,
'reason': 'Joe Dart on Fender Bass',
@@ -146,7 +146,7 @@ class CreationTests(APISubdomainTestCase):
})
def test_returns_400_for_end_reason_at_creation(self):
- url = reverse('bot:nomination-list', host='api')
+ url = reverse('api:bot:nomination-list')
data = {
'user': self.user.id,
'reason': 'Joe Dart on Fender Bass',
@@ -161,7 +161,7 @@ class CreationTests(APISubdomainTestCase):
})
def test_returns_400_for_ended_at_at_creation(self):
- url = reverse('bot:nomination-list', host='api')
+ url = reverse('api:bot:nomination-list')
data = {
'user': self.user.id,
'reason': 'Joe Dart on Fender Bass',
@@ -176,7 +176,7 @@ class CreationTests(APISubdomainTestCase):
})
def test_returns_400_for_inserted_at_at_creation(self):
- url = reverse('bot:nomination-list', host='api')
+ url = reverse('api:bot:nomination-list')
data = {
'user': self.user.id,
'reason': 'Joe Dart on Fender Bass',
@@ -191,7 +191,7 @@ class CreationTests(APISubdomainTestCase):
})
def test_returns_400_for_active_at_creation(self):
- url = reverse('bot:nomination-list', host='api')
+ url = reverse('api:bot:nomination-list')
data = {
'user': self.user.id,
'reason': 'Joe Dart on Fender Bass',
@@ -206,7 +206,7 @@ class CreationTests(APISubdomainTestCase):
})
-class NominationTests(APISubdomainTestCase):
+class NominationTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.user = User.objects.create(
@@ -236,7 +236,7 @@ class NominationTests(APISubdomainTestCase):
)
def test_returns_200_update_reason_on_active_with_actor(self):
- url = reverse('bot:nomination-detail', args=(self.active_nomination.id,), host='api')
+ url = reverse('api:bot:nomination-detail', args=(self.active_nomination.id,))
data = {
'reason': "He's one funky duck",
'actor': self.user.id
@@ -252,7 +252,7 @@ class NominationTests(APISubdomainTestCase):
self.assertEqual(nomination_entry.reason, data['reason'])
def test_returns_400_on_frozen_field_update(self):
- url = reverse('bot:nomination-detail', args=(self.active_nomination.id,), host='api')
+ url = reverse('api:bot:nomination-detail', args=(self.active_nomination.id,))
data = {
'user': "Theo Katzman"
}
@@ -264,7 +264,7 @@ class NominationTests(APISubdomainTestCase):
})
def test_returns_400_update_end_reason_on_active(self):
- url = reverse('bot:nomination-detail', args=(self.active_nomination.id,), host='api')
+ url = reverse('api:bot:nomination-detail', args=(self.active_nomination.id,))
data = {
'end_reason': 'He started playing jazz'
}
@@ -276,7 +276,7 @@ class NominationTests(APISubdomainTestCase):
})
def test_returns_200_update_reason_on_inactive(self):
- url = reverse('bot:nomination-detail', args=(self.inactive_nomination.id,), host='api')
+ url = reverse('api:bot:nomination-detail', args=(self.inactive_nomination.id,))
data = {
'reason': "He's one funky duck",
'actor': self.user.id
@@ -292,7 +292,7 @@ class NominationTests(APISubdomainTestCase):
self.assertEqual(nomination_entry.reason, data['reason'])
def test_returns_200_update_end_reason_on_inactive(self):
- url = reverse('bot:nomination-detail', args=(self.inactive_nomination.id,), host='api')
+ url = reverse('api:bot:nomination-detail', args=(self.inactive_nomination.id,))
data = {
'end_reason': 'He started playing jazz'
}
@@ -305,9 +305,8 @@ class NominationTests(APISubdomainTestCase):
def test_returns_200_on_valid_end_nomination(self):
url = reverse(
- 'bot:nomination-detail',
+ 'api:bot:nomination-detail',
args=(self.active_nomination.id,),
- host='api'
)
data = {
'active': False,
@@ -328,9 +327,8 @@ class NominationTests(APISubdomainTestCase):
def test_returns_400_on_invalid_field_end_nomination(self):
url = reverse(
- 'bot:nomination-detail',
+ 'api:bot:nomination-detail',
args=(self.active_nomination.id,),
- host='api'
)
data = {
'active': False,
@@ -344,9 +342,8 @@ class NominationTests(APISubdomainTestCase):
def test_returns_400_on_missing_end_reason_end_nomination(self):
url = reverse(
- 'bot:nomination-detail',
+ 'api:bot:nomination-detail',
args=(self.active_nomination.id,),
- host='api'
)
data = {
'active': False,
@@ -360,9 +357,8 @@ class NominationTests(APISubdomainTestCase):
def test_returns_400_on_invalid_use_of_active(self):
url = reverse(
- 'bot:nomination-detail',
+ 'api:bot:nomination-detail',
args=(self.inactive_nomination.id,),
- host='api'
)
data = {
'active': False,
@@ -376,9 +372,8 @@ class NominationTests(APISubdomainTestCase):
def test_returns_404_on_get_unknown_nomination(self):
url = reverse(
- 'bot:nomination-detail',
+ 'api:bot:nomination-detail',
args=(9999,),
- host='api'
)
response = self.client.get(url, data={})
@@ -389,9 +384,8 @@ class NominationTests(APISubdomainTestCase):
def test_returns_404_on_patch_unknown_nomination(self):
url = reverse(
- 'bot:nomination-detail',
+ 'api:bot:nomination-detail',
args=(9999,),
- host='api'
)
response = self.client.patch(url, data={})
@@ -401,7 +395,7 @@ class NominationTests(APISubdomainTestCase):
})
def test_returns_405_on_list_put(self):
- url = reverse('bot:nomination-list', host='api')
+ url = reverse('api:bot:nomination-list')
response = self.client.put(url, data={})
self.assertEqual(response.status_code, 405)
@@ -410,7 +404,7 @@ class NominationTests(APISubdomainTestCase):
})
def test_returns_405_on_list_patch(self):
- url = reverse('bot:nomination-list', host='api')
+ url = reverse('api:bot:nomination-list')
response = self.client.patch(url, data={})
self.assertEqual(response.status_code, 405)
@@ -419,7 +413,7 @@ class NominationTests(APISubdomainTestCase):
})
def test_returns_405_on_list_delete(self):
- url = reverse('bot:nomination-list', host='api')
+ url = reverse('api:bot:nomination-list')
response = self.client.delete(url, data={})
self.assertEqual(response.status_code, 405)
@@ -428,7 +422,7 @@ class NominationTests(APISubdomainTestCase):
})
def test_returns_405_on_detail_post(self):
- url = reverse('bot:nomination-detail', args=(self.active_nomination.id,), host='api')
+ url = reverse('api:bot:nomination-detail', args=(self.active_nomination.id,))
response = self.client.post(url, data={})
self.assertEqual(response.status_code, 405)
@@ -437,7 +431,7 @@ class NominationTests(APISubdomainTestCase):
})
def test_returns_405_on_detail_delete(self):
- url = reverse('bot:nomination-detail', args=(self.active_nomination.id,), host='api')
+ url = reverse('api:bot:nomination-detail', args=(self.active_nomination.id,))
response = self.client.delete(url, data={})
self.assertEqual(response.status_code, 405)
@@ -446,7 +440,7 @@ class NominationTests(APISubdomainTestCase):
})
def test_returns_405_on_detail_put(self):
- url = reverse('bot:nomination-detail', args=(self.active_nomination.id,), host='api')
+ url = reverse('api:bot:nomination-detail', args=(self.active_nomination.id,))
response = self.client.put(url, data={})
self.assertEqual(response.status_code, 405)
@@ -455,7 +449,7 @@ class NominationTests(APISubdomainTestCase):
})
def test_filter_returns_0_objects_unknown_user__id(self):
- url = reverse('bot:nomination-list', host='api')
+ url = reverse('api:bot:nomination-list')
response = self.client.get(
url,
@@ -470,7 +464,7 @@ class NominationTests(APISubdomainTestCase):
self.assertEqual(len(infractions), 0)
def test_filter_returns_2_objects_for_testdata(self):
- url = reverse('bot:nomination-list', host='api')
+ url = reverse('api:bot:nomination-list')
response = self.client.get(
url,
@@ -485,14 +479,14 @@ class NominationTests(APISubdomainTestCase):
self.assertEqual(len(infractions), 2)
def test_patch_nomination_set_reviewed_of_active_nomination(self):
- url = reverse('api:nomination-detail', args=(self.active_nomination.id,), host='api')
+ url = reverse('api:bot:nomination-detail', args=(self.active_nomination.id,))
data = {'reviewed': True}
response = self.client.patch(url, data=data)
self.assertEqual(response.status_code, 200)
def test_patch_nomination_set_reviewed_of_inactive_nomination(self):
- url = reverse('api:nomination-detail', args=(self.inactive_nomination.id,), host='api')
+ url = reverse('api:bot:nomination-detail', args=(self.inactive_nomination.id,))
data = {'reviewed': True}
response = self.client.patch(url, data=data)
@@ -502,7 +496,7 @@ class NominationTests(APISubdomainTestCase):
})
def test_patch_nomination_set_reviewed_and_end(self):
- url = reverse('api:nomination-detail', args=(self.active_nomination.id,), host='api')
+ url = reverse('api:bot:nomination-detail', args=(self.active_nomination.id,))
data = {'reviewed': True, 'active': False, 'end_reason': "What?"}
response = self.client.patch(url, data=data)
@@ -512,7 +506,7 @@ class NominationTests(APISubdomainTestCase):
})
def test_modifying_reason_without_actor(self):
- url = reverse('api:nomination-detail', args=(self.active_nomination.id,), host='api')
+ url = reverse('api:bot:nomination-detail', args=(self.active_nomination.id,))
data = {'reason': 'That is my reason!'}
response = self.client.patch(url, data=data)
@@ -522,7 +516,7 @@ class NominationTests(APISubdomainTestCase):
})
def test_modifying_reason_with_unknown_actor(self):
- url = reverse('api:nomination-detail', args=(self.active_nomination.id,), host='api')
+ url = reverse('api:bot:nomination-detail', args=(self.active_nomination.id,))
data = {'reason': 'That is my reason!', 'actor': 90909090909090}
response = self.client.patch(url, data=data)
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 34dde7c6..354cda9c 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
@@ -1,33 +1,33 @@
-from django_hosts.resolvers import reverse
+from django.urls import reverse
-from .base import APISubdomainTestCase
+from .base import AuthenticatedAPITestCase
from ..models import OffTopicChannelName
-class UnauthenticatedTests(APISubdomainTestCase):
+class UnauthenticatedTests(AuthenticatedAPITestCase):
def setUp(self):
super().setUp()
self.client.force_authenticate(user=None)
def test_cannot_read_off_topic_channel_name_list(self):
"""Return a 401 response when not authenticated."""
- url = reverse('bot:offtopicchannelname-list', host='api')
+ url = reverse('api:bot:offtopicchannelname-list')
response = self.client.get(url)
self.assertEqual(response.status_code, 401)
def test_cannot_read_off_topic_channel_name_list_with_random_item_param(self):
"""Return a 401 response when `random_items` provided and not authenticated."""
- url = reverse('bot:offtopicchannelname-list', host='api')
+ url = reverse('api:bot:offtopicchannelname-list')
response = self.client.get(f'{url}?random_items=no')
self.assertEqual(response.status_code, 401)
-class EmptyDatabaseTests(APISubdomainTestCase):
+class EmptyDatabaseTests(AuthenticatedAPITestCase):
def test_returns_empty_object(self):
"""Return empty list when no names in database."""
- url = reverse('bot:offtopicchannelname-list', host='api')
+ url = reverse('api:bot:offtopicchannelname-list')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
@@ -35,7 +35,7 @@ class EmptyDatabaseTests(APISubdomainTestCase):
def test_returns_empty_list_with_get_all_param(self):
"""Return empty list when no names and `random_items` param provided."""
- url = reverse('bot:offtopicchannelname-list', host='api')
+ url = reverse('api:bot:offtopicchannelname-list')
response = self.client.get(f'{url}?random_items=5')
self.assertEqual(response.status_code, 200)
@@ -43,7 +43,7 @@ class EmptyDatabaseTests(APISubdomainTestCase):
def test_returns_400_for_bad_random_items_param(self):
"""Return error message when passing not integer as `random_items`."""
- url = reverse('bot:offtopicchannelname-list', host='api')
+ url = reverse('api:bot:offtopicchannelname-list')
response = self.client.get(f'{url}?random_items=totally-a-valid-integer')
self.assertEqual(response.status_code, 400)
@@ -53,7 +53,7 @@ class EmptyDatabaseTests(APISubdomainTestCase):
def test_returns_400_for_negative_random_items_param(self):
"""Return error message when passing negative int as `random_items`."""
- url = reverse('bot:offtopicchannelname-list', host='api')
+ url = reverse('api:bot:offtopicchannelname-list')
response = self.client.get(f'{url}?random_items=-5')
self.assertEqual(response.status_code, 400)
@@ -62,7 +62,7 @@ class EmptyDatabaseTests(APISubdomainTestCase):
})
-class ListTests(APISubdomainTestCase):
+class ListTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.test_name = OffTopicChannelName.objects.create(
@@ -77,7 +77,7 @@ class ListTests(APISubdomainTestCase):
def test_returns_name_in_list(self):
"""Return all off-topic channel names."""
- url = reverse('bot:offtopicchannelname-list', host='api')
+ url = reverse('api:bot:offtopicchannelname-list')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
@@ -92,7 +92,7 @@ class ListTests(APISubdomainTestCase):
def test_returns_two_items_with_random_items_param_set_to_2(self):
"""Return not-used name instead used."""
- url = reverse('bot:offtopicchannelname-list', host='api')
+ url = reverse('api:bot:offtopicchannelname-list')
response = self.client.get(f'{url}?random_items=2')
self.assertEqual(response.status_code, 200)
@@ -101,7 +101,7 @@ class ListTests(APISubdomainTestCase):
def test_running_out_of_names_with_random_parameter(self):
"""Reset names `used` parameter to `False` when running out of names."""
- url = reverse('bot:offtopicchannelname-list', host='api')
+ url = reverse('api:bot:offtopicchannelname-list')
response = self.client.get(f'{url}?random_items=3')
self.assertEqual(response.status_code, 200)
@@ -112,7 +112,7 @@ class ListTests(APISubdomainTestCase):
def test_returns_inactive_ot_names(self):
"""Return inactive off topic names."""
- url = reverse('bot:offtopicchannelname-list', host="api")
+ url = reverse('bot:offtopicchannelname-list')
response = self.client.get(f"{url}?active=false")
self.assertEqual(response.status_code, 200)
@@ -123,7 +123,7 @@ class ListTests(APISubdomainTestCase):
def test_returns_active_ot_names(self):
"""Return active off topic names."""
- url = reverse('bot:offtopicchannelname-list', host="api")
+ url = reverse('bot:offtopicchannelname-list')
response = self.client.get(f"{url}?active=true")
self.assertEqual(response.status_code, 200)
@@ -133,18 +133,18 @@ class ListTests(APISubdomainTestCase):
)
-class CreationTests(APISubdomainTestCase):
+class CreationTests(AuthenticatedAPITestCase):
def setUp(self):
super().setUp()
- url = reverse('bot:offtopicchannelname-list', host='api')
+ url = reverse('api:bot:offtopicchannelname-list')
self.name = "abcdefghijklmnopqrstuvwxyz-0123456789"
response = self.client.post(f'{url}?name={self.name}')
self.assertEqual(response.status_code, 201)
def test_returns_201_for_unicode_chars(self):
"""Accept all valid characters."""
- url = reverse('bot:offtopicchannelname-list', host='api')
+ url = reverse('api:bot:offtopicchannelname-list')
names = (
'𝖠𝖡𝖢𝖣𝖤𝖥𝖦𝖧𝖨𝖩𝖪𝖫𝖬𝖭𝖮𝖯𝖰𝖱𝖲𝖳𝖴𝖵𝖶𝖷𝖸𝖹',
'ǃ?’',
@@ -156,7 +156,7 @@ class CreationTests(APISubdomainTestCase):
def test_returns_400_for_missing_name_param(self):
"""Return error message when name not provided."""
- url = reverse('bot:offtopicchannelname-list', host='api')
+ url = reverse('api:bot:offtopicchannelname-list')
response = self.client.post(url)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json(), {
@@ -165,7 +165,7 @@ class CreationTests(APISubdomainTestCase):
def test_returns_400_for_bad_name_param(self):
"""Return error message when invalid characters provided."""
- url = reverse('bot:offtopicchannelname-list', host='api')
+ url = reverse('api:bot:offtopicchannelname-list')
invalid_names = (
'space between words',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
@@ -180,33 +180,33 @@ class CreationTests(APISubdomainTestCase):
})
-class DeletionTests(APISubdomainTestCase):
+class DeletionTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.test_name = OffTopicChannelName.objects.create(name='lemons-lemonade-stand')
cls.test_name_2 = OffTopicChannelName.objects.create(name='bbq-with-bisk')
def test_deleting_unknown_name_returns_404(self):
- """Return 404 reponse when trying to delete unknown name."""
- url = reverse('bot:offtopicchannelname-detail', args=('unknown-name',), host='api')
+ """Return 404 response when trying to delete unknown name."""
+ url = reverse('api:bot:offtopicchannelname-detail', args=('unknown-name',))
response = self.client.delete(url)
self.assertEqual(response.status_code, 404)
def test_deleting_known_name_returns_204(self):
"""Return 204 response when deleting was successful."""
- url = reverse('bot:offtopicchannelname-detail', args=(self.test_name.name,), host='api')
+ url = reverse('api:bot:offtopicchannelname-detail', args=(self.test_name.name,))
response = self.client.delete(url)
self.assertEqual(response.status_code, 204)
def test_name_gets_deleted(self):
"""Name gets actually deleted."""
- url = reverse('bot:offtopicchannelname-detail', args=(self.test_name_2.name,), host='api')
+ url = reverse('api:bot:offtopicchannelname-detail', args=(self.test_name_2.name,))
response = self.client.delete(url)
self.assertEqual(response.status_code, 204)
- url = reverse('bot:offtopicchannelname-list', host='api')
+ url = reverse('api:bot:offtopicchannelname-list')
response = self.client.get(url)
self.assertNotIn(self.test_name_2.name, response.json())
diff --git a/pydis_site/apps/api/tests/test_offensive_message.py b/pydis_site/apps/api/tests/test_offensive_message.py
index 0f3dbffa..3cf95b75 100644
--- a/pydis_site/apps/api/tests/test_offensive_message.py
+++ b/pydis_site/apps/api/tests/test_offensive_message.py
@@ -1,14 +1,14 @@
import datetime
-from django_hosts.resolvers import reverse
+from django.urls import reverse
-from .base import APISubdomainTestCase
+from .base import AuthenticatedAPITestCase
from ..models import OffensiveMessage
-class CreationTests(APISubdomainTestCase):
+class CreationTests(AuthenticatedAPITestCase):
def test_accept_valid_data(self):
- url = reverse('bot:offensivemessage-list', host='api')
+ url = reverse('api:bot:offensivemessage-list')
delete_at = datetime.datetime.now() + datetime.timedelta(days=1)
data = {
'id': '602951077675139072',
@@ -31,7 +31,7 @@ class CreationTests(APISubdomainTestCase):
self.assertEqual(data['channel_id'], str(offensive_message.channel_id))
def test_returns_400_on_non_future_date(self):
- url = reverse('bot:offensivemessage-list', host='api')
+ url = reverse('api:bot:offensivemessage-list')
delete_at = datetime.datetime.now() - datetime.timedelta(days=1)
data = {
'id': '602951077675139072',
@@ -45,7 +45,7 @@ class CreationTests(APISubdomainTestCase):
})
def test_returns_400_on_negative_id_or_channel_id(self):
- url = reverse('bot:offensivemessage-list', host='api')
+ url = reverse('api:bot:offensivemessage-list')
delete_at = datetime.datetime.now() + datetime.timedelta(days=1)
data = {
'id': '602951077675139072',
@@ -58,7 +58,7 @@ class CreationTests(APISubdomainTestCase):
)
for field, invalid_value in cases:
- with self.subTest(fied=field, invalid_value=invalid_value):
+ with self.subTest(field=field, invalid_value=invalid_value):
test_data = data.copy()
test_data.update({field: invalid_value})
@@ -69,7 +69,7 @@ class CreationTests(APISubdomainTestCase):
})
-class ListTests(APISubdomainTestCase):
+class ListTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
delete_at = datetime.datetime.now() + datetime.timedelta(days=1)
@@ -100,7 +100,7 @@ class ListTests(APISubdomainTestCase):
cls.messages[1]['delete_date'] = delete_at.isoformat() + 'Z'
def test_get_data(self):
- url = reverse('bot:offensivemessage-list', host='api')
+ url = reverse('api:bot:offensivemessage-list')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
@@ -108,7 +108,7 @@ class ListTests(APISubdomainTestCase):
self.assertEqual(response.json(), self.messages)
-class DeletionTests(APISubdomainTestCase):
+class DeletionTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
delete_at = datetime.datetime.now(tz=datetime.timezone.utc) + datetime.timedelta(days=1)
@@ -121,7 +121,7 @@ class DeletionTests(APISubdomainTestCase):
def test_delete_data(self):
url = reverse(
- 'bot:offensivemessage-detail', host='api', args=(self.valid_offensive_message.id,)
+ 'api:bot:offensivemessage-detail', args=(self.valid_offensive_message.id,)
)
response = self.client.delete(url)
@@ -132,7 +132,7 @@ class DeletionTests(APISubdomainTestCase):
)
-class NotAllowedMethodsTests(APISubdomainTestCase):
+class NotAllowedMethodsTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
delete_at = datetime.datetime.now(tz=datetime.timezone.utc) + datetime.timedelta(days=1)
@@ -145,7 +145,7 @@ class NotAllowedMethodsTests(APISubdomainTestCase):
def test_returns_405_for_patch_and_put_requests(self):
url = reverse(
- 'bot:offensivemessage-detail', host='api', args=(self.valid_offensive_message.id,)
+ 'api:bot:offensivemessage-detail', args=(self.valid_offensive_message.id,)
)
not_allowed_methods = (self.client.patch, self.client.put)
diff --git a/pydis_site/apps/api/tests/test_reminders.py b/pydis_site/apps/api/tests/test_reminders.py
index 9dffb668..709685bc 100644
--- a/pydis_site/apps/api/tests/test_reminders.py
+++ b/pydis_site/apps/api/tests/test_reminders.py
@@ -1,52 +1,52 @@
from datetime import datetime
from django.forms.models import model_to_dict
-from django_hosts.resolvers import reverse
+from django.urls import reverse
-from .base import APISubdomainTestCase
+from .base import AuthenticatedAPITestCase
from ..models import Reminder, User
-class UnauthedReminderAPITests(APISubdomainTestCase):
+class UnauthedReminderAPITests(AuthenticatedAPITestCase):
def setUp(self):
super().setUp()
self.client.force_authenticate(user=None)
def test_list_returns_401(self):
- url = reverse('bot:reminder-list', host='api')
+ url = reverse('api:bot:reminder-list')
response = self.client.get(url)
self.assertEqual(response.status_code, 401)
def test_create_returns_401(self):
- url = reverse('bot:reminder-list', host='api')
+ url = reverse('api:bot:reminder-list')
response = self.client.post(url, data={'not': 'important'})
self.assertEqual(response.status_code, 401)
def test_delete_returns_401(self):
- url = reverse('bot:reminder-detail', args=('1234',), host='api')
+ url = reverse('api:bot:reminder-detail', args=('1234',))
response = self.client.delete(url)
self.assertEqual(response.status_code, 401)
-class EmptyDatabaseReminderAPITests(APISubdomainTestCase):
+class EmptyDatabaseReminderAPITests(AuthenticatedAPITestCase):
def test_list_all_returns_empty_list(self):
- url = reverse('bot:reminder-list', host='api')
+ url = reverse('api:bot:reminder-list')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), [])
def test_delete_returns_404(self):
- url = reverse('bot:reminder-detail', args=('1234',), host='api')
+ url = reverse('api:bot:reminder-detail', args=('1234',))
response = self.client.delete(url)
self.assertEqual(response.status_code, 404)
-class ReminderCreationTests(APISubdomainTestCase):
+class ReminderCreationTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.author = User.objects.create(
@@ -64,7 +64,7 @@ class ReminderCreationTests(APISubdomainTestCase):
'channel_id': 123,
'mentions': [8888, 9999],
}
- url = reverse('bot:reminder-list', host='api')
+ url = reverse('api:bot:reminder-list')
response = self.client.post(url, data=data)
self.assertEqual(response.status_code, 201)
self.assertIsNotNone(Reminder.objects.filter(id=1).first())
@@ -73,13 +73,13 @@ class ReminderCreationTests(APISubdomainTestCase):
data = {
'author': self.author.id, # Missing multiple required fields
}
- url = reverse('bot:reminder-list', host='api')
+ url = reverse('api:bot:reminder-list')
response = self.client.post(url, data=data)
self.assertEqual(response.status_code, 400)
self.assertRaises(Reminder.DoesNotExist, Reminder.objects.get, id=1)
-class ReminderDeletionTests(APISubdomainTestCase):
+class ReminderDeletionTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.author = User.objects.create(
@@ -97,20 +97,20 @@ class ReminderDeletionTests(APISubdomainTestCase):
)
def test_delete_unknown_reminder_returns_404(self):
- url = reverse('bot:reminder-detail', args=('something',), host='api')
+ url = reverse('api:bot:reminder-detail', args=('something',))
response = self.client.delete(url)
self.assertEqual(response.status_code, 404)
def test_delete_known_reminder_returns_204(self):
- url = reverse('bot:reminder-detail', args=(self.reminder.id,), host='api')
+ url = reverse('api:bot:reminder-detail', args=(self.reminder.id,))
response = self.client.delete(url)
self.assertEqual(response.status_code, 204)
self.assertRaises(Reminder.DoesNotExist, Reminder.objects.get, id=self.reminder.id)
-class ReminderListTests(APISubdomainTestCase):
+class ReminderListTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.author = User.objects.create(
@@ -142,28 +142,28 @@ class ReminderListTests(APISubdomainTestCase):
cls.rem_dict_two['expiration'] += 'Z' # Massaging a quirk of the response time format
def test_reminders_in_full_list(self):
- url = reverse('bot:reminder-list', host='api')
+ url = reverse('api:bot:reminder-list')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertCountEqual(response.json(), [self.rem_dict_one, self.rem_dict_two])
def test_filter_search(self):
- url = reverse('bot:reminder-list', host='api')
+ url = reverse('api:bot:reminder-list')
response = self.client.get(f'{url}?search={self.author.name}')
self.assertEqual(response.status_code, 200)
self.assertCountEqual(response.json(), [self.rem_dict_one, self.rem_dict_two])
def test_filter_field(self):
- url = reverse('bot:reminder-list', host='api')
+ url = reverse('api:bot:reminder-list')
response = self.client.get(f'{url}?active=true')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), [self.rem_dict_one])
-class ReminderRetrieveTests(APISubdomainTestCase):
+class ReminderRetrieveTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.author = User.objects.create(
@@ -181,17 +181,17 @@ class ReminderRetrieveTests(APISubdomainTestCase):
)
def test_retrieve_unknown_returns_404(self):
- url = reverse('bot:reminder-detail', args=("not_an_id",), host='api')
+ url = reverse('api:bot:reminder-detail', args=("not_an_id",))
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
def test_retrieve_known_returns_200(self):
- url = reverse('bot:reminder-detail', args=(self.reminder.id,), host='api')
+ url = reverse('api:bot:reminder-detail', args=(self.reminder.id,))
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
-class ReminderUpdateTests(APISubdomainTestCase):
+class ReminderUpdateTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.author = User.objects.create(
@@ -211,7 +211,7 @@ class ReminderUpdateTests(APISubdomainTestCase):
cls.data = {'content': 'Oops I forgot'}
def test_patch_updates_record(self):
- url = reverse('bot:reminder-detail', args=(self.reminder.id,), host='api')
+ url = reverse('api:bot:reminder-detail', args=(self.reminder.id,))
response = self.client.patch(url, data=self.data)
self.assertEqual(response.status_code, 200)
diff --git a/pydis_site/apps/api/tests/test_roles.py b/pydis_site/apps/api/tests/test_roles.py
index 4d1a430c..d39cea4d 100644
--- a/pydis_site/apps/api/tests/test_roles.py
+++ b/pydis_site/apps/api/tests/test_roles.py
@@ -1,10 +1,10 @@
-from django_hosts.resolvers import reverse
+from django.urls import reverse
-from .base import APISubdomainTestCase
+from .base import AuthenticatedAPITestCase
from ..models import Role
-class CreationTests(APISubdomainTestCase):
+class CreationTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.admins_role = Role.objects.create(
@@ -78,7 +78,7 @@ class CreationTests(APISubdomainTestCase):
def test_role_list(self):
"""Tests the GET list-view and validates the contents."""
- url = reverse('bot:role-list', host='api')
+ url = reverse('api:bot:role-list')
response = self.client.get(url)
self.assertContains(response, text="id", count=4, status_code=200)
@@ -92,7 +92,7 @@ class CreationTests(APISubdomainTestCase):
def test_role_get_detail_success(self):
"""Tests GET detail view of an existing role."""
- url = reverse('bot:role-detail', host='api', args=(self.admins_role.id, ))
+ url = reverse('api:bot:role-detail', args=(self.admins_role.id, ))
response = self.client.get(url)
self.assertContains(response, text="id", count=1, status_code=200)
@@ -107,7 +107,7 @@ class CreationTests(APISubdomainTestCase):
def test_role_post_201(self):
"""Tests creation of a role with a valid request."""
- url = reverse('bot:role-list', host='api')
+ url = reverse('api:bot:role-list')
data = {
"id": 1234567890,
"name": "Role Creation Test",
@@ -120,7 +120,7 @@ class CreationTests(APISubdomainTestCase):
def test_role_post_invalid_request_body(self):
"""Tests creation of a role with an invalid request body."""
- url = reverse('bot:role-list', host='api')
+ url = reverse('api:bot:role-list')
data = {
"name": "Role Creation Test",
"permissions": 0b01010010101,
@@ -133,7 +133,7 @@ class CreationTests(APISubdomainTestCase):
def test_role_put_200(self):
"""Tests PUT role request with valid request body."""
- url = reverse('bot:role-detail', host='api', args=(self.admins_role.id,))
+ url = reverse('api:bot:role-detail', args=(self.admins_role.id,))
data = {
"id": 123454321,
"name": "Role Put Alteration Test",
@@ -153,7 +153,7 @@ class CreationTests(APISubdomainTestCase):
def test_role_put_invalid_request_body(self):
"""Tests PUT role request with invalid request body."""
- url = reverse('bot:role-detail', host='api', args=(self.admins_role.id,))
+ url = reverse('api:bot:role-detail', args=(self.admins_role.id,))
data = {
"name": "Role Put Alteration Test",
"permissions": 255,
@@ -165,7 +165,7 @@ class CreationTests(APISubdomainTestCase):
def test_role_patch_200(self):
"""Tests PATCH role request with valid request body."""
- url = reverse('bot:role-detail', host='api', args=(self.admins_role.id,))
+ url = reverse('api:bot:role-detail', args=(self.admins_role.id,))
data = {
"name": "Owners"
}
@@ -177,13 +177,13 @@ class CreationTests(APISubdomainTestCase):
def test_role_delete_200(self):
"""Tests DELETE requests for existing role."""
- url = reverse('bot:role-detail', host='api', args=(self.admins_role.id,))
+ url = reverse('api:bot:role-detail', args=(self.admins_role.id,))
response = self.client.delete(url)
self.assertEqual(response.status_code, 204)
def test_role_detail_404_all_methods(self):
"""Tests detail view with non-existing ID."""
- url = reverse('bot:role-detail', host='api', args=(20190815,))
+ url = reverse('api:bot:role-detail', args=(20190815,))
for method in ('get', 'put', 'patch', 'delete'):
response = getattr(self.client, method)(url)
diff --git a/pydis_site/apps/api/tests/test_rules.py b/pydis_site/apps/api/tests/test_rules.py
index c94f89cc..d08c5fae 100644
--- a/pydis_site/apps/api/tests/test_rules.py
+++ b/pydis_site/apps/api/tests/test_rules.py
@@ -1,23 +1,23 @@
-from django_hosts.resolvers import reverse
+from django.urls import reverse
-from .base import APISubdomainTestCase
+from .base import AuthenticatedAPITestCase
from ..views import RulesView
-class RuleAPITests(APISubdomainTestCase):
+class RuleAPITests(AuthenticatedAPITestCase):
def setUp(self):
super().setUp()
self.client.force_authenticate(user=None)
def test_can_access_rules_view(self):
- url = reverse('rules', host='api')
+ url = reverse('api:rules')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertIsInstance(response.json(), list)
def test_link_format_query_param_produces_different_results(self):
- url = reverse('rules', host='api')
+ url = reverse('api:rules')
markdown_links_response = self.client.get(url + '?link_format=md')
html_links_response = self.client.get(url + '?link_format=html')
self.assertNotEqual(
@@ -30,6 +30,6 @@ class RuleAPITests(APISubdomainTestCase):
RulesView._format_link("a", "b", "c")
def test_get_returns_400_for_wrong_link_format(self):
- url = reverse('rules', host='api')
+ url = reverse('api:rules')
response = self.client.get(url + '?link_format=unknown')
self.assertEqual(response.status_code, 400)
diff --git a/pydis_site/apps/api/tests/test_users.py b/pydis_site/apps/api/tests/test_users.py
index c43b916a..295bcf64 100644
--- a/pydis_site/apps/api/tests/test_users.py
+++ b/pydis_site/apps/api/tests/test_users.py
@@ -1,44 +1,45 @@
from unittest.mock import patch
from django.core.exceptions import ObjectDoesNotExist
-from django_hosts.resolvers import reverse
+from django.urls import reverse
-from .base import APISubdomainTestCase
+from .base import AuthenticatedAPITestCase
from ..models import Role, User
-from ..models.bot.metricity import NotFound
+from ..models.bot.metricity import NotFoundError
+from ..viewsets.bot.user import UserListPagination
-class UnauthedUserAPITests(APISubdomainTestCase):
+class UnauthedUserAPITests(AuthenticatedAPITestCase):
def setUp(self):
super().setUp()
self.client.force_authenticate(user=None)
def test_detail_lookup_returns_401(self):
- url = reverse('bot:user-detail', args=('whatever',), host='api')
+ url = reverse('api:bot:user-detail', args=('whatever',))
response = self.client.get(url)
self.assertEqual(response.status_code, 401)
def test_list_returns_401(self):
- url = reverse('bot:user-list', host='api')
+ url = reverse('api:bot:user-list')
response = self.client.get(url)
self.assertEqual(response.status_code, 401)
def test_create_returns_401(self):
- url = reverse('bot:user-list', host='api')
+ url = reverse('api:bot:user-list')
response = self.client.post(url, data={'hi': 'there'})
self.assertEqual(response.status_code, 401)
def test_delete_returns_401(self):
- url = reverse('bot:user-detail', args=('whatever',), host='api')
+ url = reverse('api:bot:user-detail', args=('whatever',))
response = self.client.delete(url)
self.assertEqual(response.status_code, 401)
-class CreationTests(APISubdomainTestCase):
+class CreationTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.role = Role.objects.create(
@@ -57,7 +58,7 @@ class CreationTests(APISubdomainTestCase):
)
def test_accepts_valid_data(self):
- url = reverse('bot:user-list', host='api')
+ url = reverse('api:bot:user-list')
data = {
'id': 42,
'name': "Test",
@@ -78,7 +79,7 @@ class CreationTests(APISubdomainTestCase):
self.assertEqual(user.in_guild, data['in_guild'])
def test_supports_multi_creation(self):
- url = reverse('bot:user-list', host='api')
+ url = reverse('api:bot:user-list')
data = [
{
'id': 5,
@@ -103,7 +104,7 @@ class CreationTests(APISubdomainTestCase):
self.assertEqual(response.json(), [])
def test_returns_400_for_unknown_role_id(self):
- url = reverse('bot:user-list', host='api')
+ url = reverse('api:bot:user-list')
data = {
'id': 5,
'name': "test man",
@@ -117,7 +118,7 @@ class CreationTests(APISubdomainTestCase):
self.assertEqual(response.status_code, 400)
def test_returns_400_for_bad_data(self):
- url = reverse('bot:user-list', host='api')
+ url = reverse('api:bot:user-list')
data = {
'id': True,
'discriminator': "totally!"
@@ -128,7 +129,7 @@ class CreationTests(APISubdomainTestCase):
def test_returns_400_for_user_recreation(self):
"""Return 201 if User is already present in database as it skips User creation."""
- url = reverse('bot:user-list', host='api')
+ url = reverse('api:bot:user-list')
data = [{
'id': 11,
'name': 'You saw nothing.',
@@ -140,7 +141,7 @@ class CreationTests(APISubdomainTestCase):
def test_returns_400_for_duplicate_request_users(self):
"""Return 400 if 2 Users with same ID is passed in the request data."""
- url = reverse('bot:user-list', host='api')
+ url = reverse('api:bot:user-list')
data = [
{
'id': 11,
@@ -160,7 +161,7 @@ class CreationTests(APISubdomainTestCase):
def test_returns_400_for_existing_user(self):
"""Returns 400 if user is already present in DB."""
- url = reverse('bot:user-list', host='api')
+ url = reverse('api:bot:user-list')
data = {
'id': 11,
'name': 'You saw nothing part 3.',
@@ -171,7 +172,7 @@ class CreationTests(APISubdomainTestCase):
self.assertEqual(response.status_code, 400)
-class MultiPatchTests(APISubdomainTestCase):
+class MultiPatchTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.role_developer = Role.objects.create(
@@ -195,7 +196,7 @@ class MultiPatchTests(APISubdomainTestCase):
)
def test_multiple_users_patch(self):
- url = reverse("bot:user-bulk-patch", host="api")
+ url = reverse("api:bot:user-bulk-patch")
data = [
{
"id": 1,
@@ -218,7 +219,7 @@ class MultiPatchTests(APISubdomainTestCase):
self.assertEqual(user_2.name, data[1]["name"])
def test_returns_400_for_missing_user_id(self):
- url = reverse("bot:user-bulk-patch", host="api")
+ url = reverse("api:bot:user-bulk-patch")
data = [
{
"name": "I am ghost user!",
@@ -234,7 +235,7 @@ class MultiPatchTests(APISubdomainTestCase):
self.assertEqual(response.status_code, 400)
def test_returns_404_for_not_found_user(self):
- url = reverse("bot:user-bulk-patch", host="api")
+ url = reverse("api:bot:user-bulk-patch")
data = [
{
"id": 1,
@@ -252,7 +253,7 @@ class MultiPatchTests(APISubdomainTestCase):
self.assertEqual(response.status_code, 404)
def test_returns_400_for_bad_data(self):
- url = reverse("bot:user-bulk-patch", host="api")
+ url = reverse("api:bot:user-bulk-patch")
data = [
{
"id": 1,
@@ -268,7 +269,7 @@ class MultiPatchTests(APISubdomainTestCase):
self.assertEqual(response.status_code, 400)
def test_returns_400_for_insufficient_data(self):
- url = reverse("bot:user-bulk-patch", host="api")
+ url = reverse("api:bot:user-bulk-patch")
data = [
{
"id": 1,
@@ -282,7 +283,7 @@ class MultiPatchTests(APISubdomainTestCase):
def test_returns_400_for_duplicate_request_users(self):
"""Return 400 if 2 Users with same ID is passed in the request data."""
- url = reverse("bot:user-bulk-patch", host="api")
+ url = reverse("api:bot:user-bulk-patch")
data = [
{
'id': 1,
@@ -297,7 +298,7 @@ class MultiPatchTests(APISubdomainTestCase):
self.assertEqual(response.status_code, 400)
-class UserModelTests(APISubdomainTestCase):
+class UserModelTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
cls.role_top = Role.objects.create(
@@ -353,11 +354,11 @@ class UserModelTests(APISubdomainTestCase):
self.assertEqual(self.user_with_roles.username, "Test User with two roles#0001")
-class UserPaginatorTests(APISubdomainTestCase):
+class UserPaginatorTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
users = []
- for i in range(1, 10_001):
+ for i in range(1, UserListPagination.page_size + 1):
users.append(User(
id=i,
name=f"user{i}",
@@ -367,35 +368,37 @@ class UserPaginatorTests(APISubdomainTestCase):
cls.users = User.objects.bulk_create(users)
def test_returns_single_page_response(self):
- url = reverse("bot:user-list", host="api")
+ url = reverse("api:bot:user-list")
response = self.client.get(url).json()
self.assertIsNone(response["next_page_no"])
self.assertIsNone(response["previous_page_no"])
def test_returns_next_page_number(self):
+ user_id = UserListPagination.page_size + 1
User.objects.create(
- id=10_001,
- name="user10001",
+ id=user_id,
+ name=f"user{user_id}",
discriminator=1111,
in_guild=True
)
- url = reverse("bot:user-list", host="api")
+ url = reverse("api:bot:user-list")
response = self.client.get(url).json()
self.assertEqual(2, response["next_page_no"])
def test_returns_previous_page_number(self):
+ user_id = UserListPagination.page_size + 1
User.objects.create(
- id=10_001,
- name="user10001",
+ id=user_id,
+ name=f"user{user_id}",
discriminator=1111,
in_guild=True
)
- url = reverse("bot:user-list", host="api")
+ url = reverse("api:bot:user-list")
response = self.client.get(url, {"page": 2}).json()
self.assertEqual(1, response["previous_page_no"])
-class UserMetricityTests(APISubdomainTestCase):
+class UserMetricityTests(AuthenticatedAPITestCase):
@classmethod
def setUpTestData(cls):
User.objects.create(
@@ -413,7 +416,7 @@ class UserMetricityTests(APISubdomainTestCase):
self.mock_metricity_user(joined_at, total_messages, total_blocks, [])
# When
- url = reverse('bot:user-metricity-data', args=[0], host='api')
+ url = reverse('api:bot:user-metricity-data', args=[0])
response = self.client.get(url)
# Then
@@ -430,7 +433,7 @@ class UserMetricityTests(APISubdomainTestCase):
self.mock_no_metricity_user()
# When
- url = reverse('bot:user-metricity-data', args=[0], host='api')
+ url = reverse('api:bot:user-metricity-data', args=[0])
response = self.client.get(url)
# Then
@@ -441,7 +444,7 @@ class UserMetricityTests(APISubdomainTestCase):
self.mock_no_metricity_user()
# When
- url = reverse('bot:user-metricity-review-data', args=[0], host='api')
+ url = reverse('api:bot:user-metricity-review-data', args=[0])
response = self.client.get(url)
# Then
@@ -460,7 +463,7 @@ class UserMetricityTests(APISubdomainTestCase):
with patch("pydis_site.apps.api.viewsets.bot.user.Infraction.objects.get") as p:
p.side_effect = case['exception']
- url = reverse('bot:user-metricity-data', args=[0], host='api')
+ url = reverse('api:bot:user-metricity-data', args=[0])
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
@@ -475,7 +478,7 @@ class UserMetricityTests(APISubdomainTestCase):
self.mock_metricity_user(joined_at, total_messages, total_blocks, channel_activity)
# When
- url = reverse('bot:user-metricity-review-data', args=[0], host='api')
+ url = reverse('api:bot:user-metricity-review-data', args=[0])
response = self.client.get(url)
# Then
@@ -501,7 +504,7 @@ class UserMetricityTests(APISubdomainTestCase):
self.metricity = patcher.start()
self.addCleanup(patcher.stop)
self.metricity = self.metricity.return_value.__enter__.return_value
- self.metricity.user.side_effect = NotFound()
- self.metricity.total_messages.side_effect = NotFound()
- self.metricity.total_message_blocks.side_effect = NotFound()
- self.metricity.top_channel_activity.side_effect = NotFound()
+ self.metricity.user.side_effect = NotFoundError()
+ self.metricity.total_messages.side_effect = NotFoundError()
+ self.metricity.total_message_blocks.side_effect = NotFoundError()
+ self.metricity.top_channel_activity.side_effect = NotFoundError()
diff --git a/pydis_site/apps/api/tests/test_validators.py b/pydis_site/apps/api/tests/test_validators.py
index 8bb7b917..551cc2aa 100644
--- a/pydis_site/apps/api/tests/test_validators.py
+++ b/pydis_site/apps/api/tests/test_validators.py
@@ -72,7 +72,7 @@ class TagEmbedValidatorTests(TestCase):
def test_rejects_too_long_description(self):
with self.assertRaises(ValidationError):
validate_embed({
- 'description': 'd' * 2049
+ 'description': 'd' * 4097
})
def test_allows_valid_embed(self):
diff --git a/pydis_site/apps/api/urls.py b/pydis_site/apps/api/urls.py
index 2e1ef0b4..b0ab545b 100644
--- a/pydis_site/apps/api/urls.py
+++ b/pydis_site/apps/api/urls.py
@@ -16,7 +16,7 @@ from .viewsets import (
UserViewSet
)
-# http://www.django-rest-framework.org/api-guide/routers/#defaultrouter
+# https://www.django-rest-framework.org/api-guide/routers/#defaultrouter
bot_router = DefaultRouter(trailing_slash=False)
bot_router.register(
'filter-lists',
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 18ee84ea..7151d29b 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
@@ -19,7 +19,7 @@ class OffTopicChannelNameViewSet(ModelViewSet):
### GET /bot/off-topic-channel-names
Return all known off-topic channel names from the database.
If the `random_items` query parameter is given, for example using...
- $ curl api.pythondiscord.local:8000/bot/off-topic-channel-names?random_items=5
+ $ curl 127.0.0.1:8000/api/bot/off-topic-channel-names?random_items=5
... then the API will return `5` random items from the database
that is not used in current rotation.
When running out of names, API will mark all names to not used and start new rotation.
@@ -38,7 +38,7 @@ class OffTopicChannelNameViewSet(ModelViewSet):
### POST /bot/off-topic-channel-names
Create a new off-topic-channel name in the database.
The name must be given as a query parameter, for example:
- $ curl api.pythondiscord.local:8000/bot/off-topic-channel-names?name=lemons-lemonade-shop
+ $ curl 127.0.0.1:8000/api/bot/off-topic-channel-names?name=lemons-lemonade-shop
#### Status codes
- 201: returned on success
diff --git a/pydis_site/apps/api/viewsets/bot/user.py b/pydis_site/apps/api/viewsets/bot/user.py
index 25722f5a..22d13dc4 100644
--- a/pydis_site/apps/api/viewsets/bot/user.py
+++ b/pydis_site/apps/api/viewsets/bot/user.py
@@ -11,7 +11,7 @@ from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ModelViewSet
from pydis_site.apps.api.models.bot.infraction import Infraction
-from pydis_site.apps.api.models.bot.metricity import Metricity, NotFound
+from pydis_site.apps.api.models.bot.metricity import Metricity, NotFoundError
from pydis_site.apps.api.models.bot.user import User
from pydis_site.apps.api.serializers import UserSerializer
@@ -19,7 +19,7 @@ from pydis_site.apps.api.serializers import UserSerializer
class UserListPagination(PageNumberPagination):
"""Custom pagination class for the User Model."""
- page_size = 10000
+ page_size = 2500
page_size_query_param = "page_size"
def get_next_page_number(self) -> typing.Optional[int]:
@@ -275,7 +275,7 @@ class UserViewSet(ModelViewSet):
data["voice_banned"] = voice_banned
data["activity_blocks"] = metricity.total_message_blocks(user.id)
return Response(data, status=status.HTTP_200_OK)
- except NotFound:
+ except NotFoundError:
return Response(dict(detail="User not found in metricity"),
status=status.HTTP_404_NOT_FOUND)
@@ -290,6 +290,6 @@ class UserViewSet(ModelViewSet):
data["total_messages"] = metricity.total_messages(user.id)
data["top_channel_activity"] = metricity.top_channel_activity(user.id)
return Response(data, status=status.HTTP_200_OK)
- except NotFound:
+ except NotFoundError:
return Response(dict(detail="User not found in metricity"),
status=status.HTTP_404_NOT_FOUND)