aboutsummaryrefslogtreecommitdiffstats
path: root/pydis_site/apps/home/tests
diff options
context:
space:
mode:
Diffstat (limited to 'pydis_site/apps/home/tests')
-rw-r--r--pydis_site/apps/home/tests/mock_github_api_response.json2
-rw-r--r--pydis_site/apps/home/tests/test_repodata_helpers.py2
-rw-r--r--pydis_site/apps/home/tests/test_signal_listener.py83
-rw-r--r--pydis_site/apps/home/tests/test_views.py197
4 files changed, 268 insertions, 16 deletions
diff --git a/pydis_site/apps/home/tests/mock_github_api_response.json b/pydis_site/apps/home/tests/mock_github_api_response.json
index 37dc672e..10be4f99 100644
--- a/pydis_site/apps/home/tests/mock_github_api_response.json
+++ b/pydis_site/apps/home/tests/mock_github_api_response.json
@@ -28,7 +28,7 @@
"forks_count": 31
},
{
- "full_name": "python-discord/django-crispy-bulma",
+ "full_name": "python-discord/metricity",
"description": "test",
"stargazers_count": 97,
"language": "Python",
diff --git a/pydis_site/apps/home/tests/test_repodata_helpers.py b/pydis_site/apps/home/tests/test_repodata_helpers.py
index 71bd4f2d..77b1a68d 100644
--- a/pydis_site/apps/home/tests/test_repodata_helpers.py
+++ b/pydis_site/apps/home/tests/test_repodata_helpers.py
@@ -10,7 +10,7 @@ from pydis_site.apps.home.models import RepositoryMetadata
from pydis_site.apps.home.views import HomeView
-def mocked_requests_get(*args, **kwargs) -> "MockResponse": # noqa
+def mocked_requests_get(*args, **kwargs) -> "MockResponse": # noqa: F821
"""A mock version of requests.get, so we don't need to call the API every time we run a test."""
class MockResponse:
def __init__(self, json_data, status_code):
diff --git a/pydis_site/apps/home/tests/test_signal_listener.py b/pydis_site/apps/home/tests/test_signal_listener.py
index 27fc7710..d99d81a5 100644
--- a/pydis_site/apps/home/tests/test_signal_listener.py
+++ b/pydis_site/apps/home/tests/test_signal_listener.py
@@ -67,36 +67,35 @@ class SignalListenerTests(TestCase):
cls.admin_mapping = RoleMapping.objects.create(
role=cls.admin_role,
- group=cls.admin_group
+ group=cls.admin_group,
+ is_staff=True
)
cls.moderator_mapping = RoleMapping.objects.create(
role=cls.moderator_role,
- group=cls.moderator_group
+ group=cls.moderator_group,
+ is_staff=False
)
cls.discord_user = DiscordUser.objects.create(
id=0,
name="user",
discriminator=0,
- avatar_hash=None
)
cls.discord_unmapped = DiscordUser.objects.create(
id=2,
name="unmapped",
discriminator=0,
- avatar_hash=None
)
- cls.discord_unmapped.roles.add(cls.unmapped_role)
+ cls.discord_unmapped.roles.append(cls.unmapped_role.id)
cls.discord_unmapped.save()
cls.discord_not_in_guild = DiscordUser.objects.create(
id=3,
name="not-in-guild",
discriminator=0,
- avatar_hash=None,
in_guild=False
)
@@ -104,20 +103,18 @@ class SignalListenerTests(TestCase):
id=1,
name="admin",
discriminator=0,
- avatar_hash=None
)
- cls.discord_admin.roles.set([cls.admin_role])
+ cls.discord_admin.roles = [cls.admin_role.id]
cls.discord_admin.save()
cls.discord_moderator = DiscordUser.objects.create(
id=4,
name="admin",
discriminator=0,
- avatar_hash=None
)
- cls.discord_moderator.roles.set([cls.moderator_role])
+ cls.discord_moderator.roles = [cls.moderator_role.id]
cls.discord_moderator.save()
cls.django_user_discordless = DjangoUser.objects.create(username="no-discord")
@@ -166,7 +163,7 @@ class SignalListenerTests(TestCase):
cls.django_moderator = DjangoUser.objects.create(
username="moderator",
- is_staff=True,
+ is_staff=False,
is_superuser=False
)
@@ -336,9 +333,36 @@ class SignalListenerTests(TestCase):
handler._apply_groups(self.discord_admin, self.social_admin)
self.assertEqual(self.django_user_discordless.groups.all().count(), 0)
- self.discord_admin.roles.add(self.admin_role)
+ self.discord_admin.roles.append(self.admin_role.id)
self.discord_admin.save()
+ def test_apply_groups_moderator(self):
+ """Test application of groups by role, relating to a non-`is_staff` moderator user."""
+ handler = AllauthSignalListener()
+
+ self.assertEqual(self.django_user_discordless.groups.all().count(), 0)
+
+ # Apply groups based on moderator role being present on Discord
+ handler._apply_groups(self.discord_moderator, self.social_moderator)
+ self.assertTrue(self.moderator_group in self.django_moderator.groups.all())
+
+ # Remove groups based on the user apparently leaving the server
+ handler._apply_groups(self.discord_moderator, self.social_moderator, True)
+ self.assertEqual(self.django_user_discordless.groups.all().count(), 0)
+
+ # Apply the moderator role again
+ handler._apply_groups(self.discord_moderator, self.social_moderator)
+
+ # Remove all of the roles from the user
+ self.discord_moderator.roles.clear()
+
+ # Remove groups based on the user no longer having the moderator role on Discord
+ handler._apply_groups(self.discord_moderator, self.social_moderator)
+ self.assertEqual(self.django_user_discordless.groups.all().count(), 0)
+
+ self.discord_moderator.roles.append(self.moderator_role.id)
+ self.discord_moderator.save()
+
def test_apply_groups_other(self):
"""Test application of groups by role, relating to non-standard cases."""
handler = AllauthSignalListener()
@@ -373,10 +397,25 @@ class SignalListenerTests(TestCase):
self.assertEqual(self.django_moderator.groups.all().count(), 1)
self.assertEqual(self.django_admin.groups.all().count(), 1)
+ # Test is_staff changes
+ self.admin_mapping.is_staff = False
+ self.admin_mapping.save()
+
+ self.assertFalse(self.django_moderator.is_staff)
+ self.assertFalse(self.django_admin.is_staff)
+
+ self.admin_mapping.is_staff = True
+ self.admin_mapping.save()
+
+ self.django_admin.refresh_from_db(fields=("is_staff", ))
+ self.assertTrue(self.django_admin.is_staff)
+
# Test mapping deletion
self.admin_mapping.delete()
+ self.django_admin.refresh_from_db(fields=("is_staff",))
self.assertEqual(self.django_admin.groups.all().count(), 0)
+ self.assertFalse(self.django_admin.is_staff)
# Test mapping update
self.moderator_mapping.group = self.admin_group
@@ -388,12 +427,30 @@ class SignalListenerTests(TestCase):
# Test mapping creation
new_mapping = RoleMapping.objects.create(
role=self.admin_role,
- group=self.moderator_group
+ group=self.moderator_group,
+ is_staff=True
+ )
+
+ self.assertEqual(self.django_admin.groups.all().count(), 1)
+ self.assertTrue(self.moderator_group in self.django_admin.groups.all())
+
+ self.django_admin.refresh_from_db(fields=("is_staff",))
+ self.assertTrue(self.django_admin.is_staff)
+
+ new_mapping.delete()
+
+ # Test mapping creation (without is_staff)
+ new_mapping = RoleMapping.objects.create(
+ role=self.admin_role,
+ group=self.moderator_group,
)
self.assertEqual(self.django_admin.groups.all().count(), 1)
self.assertTrue(self.moderator_group in self.django_admin.groups.all())
+ self.django_admin.refresh_from_db(fields=("is_staff",))
+ self.assertFalse(self.django_admin.is_staff)
+
# Test that nothing happens when fixtures are loaded
pre_save.send(RoleMapping, instance=new_mapping, raw=True)
diff --git a/pydis_site/apps/home/tests/test_views.py b/pydis_site/apps/home/tests/test_views.py
index 7aeaddd2..572317a7 100644
--- a/pydis_site/apps/home/tests/test_views.py
+++ b/pydis_site/apps/home/tests/test_views.py
@@ -1,5 +1,198 @@
+from allauth.socialaccount.models import SocialAccount
+from django.contrib.auth.models import User
+from django.http import HttpResponseRedirect
from django.test import TestCase
-from django_hosts.resolvers import reverse
+from django_hosts.resolvers import get_host, reverse, reverse_host
+
+
+def check_redirect_url(
+ response: HttpResponseRedirect, reversed_url: str, strip_params=True
+) -> bool:
+ """
+ Check whether a given redirect response matches a specific reversed URL.
+
+ Arguments:
+ * `response`: The HttpResponseRedirect returned by the test client
+ * `reversed_url`: The URL returned by `reverse()`
+ * `strip_params`: Whether to strip URL parameters (following a "?") from the URL given in the
+ `response` object
+ """
+ host = get_host(None)
+ hostname = reverse_host(host)
+
+ redirect_url = response.url
+
+ if strip_params and "?" in redirect_url:
+ redirect_url = redirect_url.split("?", 1)[0]
+
+ result = reversed_url == f"//{hostname}{redirect_url}"
+ return result
+
+
+class TestAccountDeleteView(TestCase):
+ def setUp(self) -> None:
+ """Create an authorized Django user for testing purposes."""
+ self.user = User.objects.create(
+ username="user#0000"
+ )
+
+ def test_redirect_when_logged_out(self):
+ """Test that the user is redirected to the homepage when not logged in."""
+ url = reverse("account_delete")
+ resp = self.client.get(url)
+ self.assertEqual(resp.status_code, 302)
+ self.assertTrue(check_redirect_url(resp, reverse("home")))
+
+ def test_get_when_logged_in(self):
+ """Test that the view returns a HTTP 200 when the user is logged in."""
+ url = reverse("account_delete")
+
+ self.client.force_login(self.user)
+ resp = self.client.get(url)
+ self.client.logout()
+
+ self.assertEqual(resp.status_code, 200)
+
+ def test_post_invalid(self):
+ """Test that the user is redirected when the form is filled out incorrectly."""
+ url = reverse("account_delete")
+
+ self.client.force_login(self.user)
+
+ resp = self.client.post(url, {})
+ self.assertEqual(resp.status_code, 302)
+ self.assertTrue(check_redirect_url(resp, url))
+
+ resp = self.client.post(url, {"username": "user"})
+ self.assertEqual(resp.status_code, 302)
+ self.assertTrue(check_redirect_url(resp, url))
+
+ self.client.logout()
+
+ def test_post_valid(self):
+ """Test that the account is deleted when the form is filled out correctly.."""
+ url = reverse("account_delete")
+
+ self.client.force_login(self.user)
+
+ resp = self.client.post(url, {"username": "user#0000"})
+ self.assertEqual(resp.status_code, 302)
+ self.assertTrue(check_redirect_url(resp, reverse("home")))
+
+ with self.assertRaises(User.DoesNotExist):
+ User.objects.get(username=self.user.username)
+
+ self.client.logout()
+
+
+class TestAccountSettingsView(TestCase):
+ def setUp(self) -> None:
+ """Create an authorized Django user for testing purposes."""
+ self.user = User.objects.create(
+ username="user#0000"
+ )
+
+ self.user_unlinked = User.objects.create(
+ username="user#9999"
+ )
+
+ self.user_unlinked_discord = User.objects.create(
+ username="user#1234"
+ )
+
+ self.user_unlinked_github = User.objects.create(
+ username="user#1111"
+ )
+
+ self.github_account = SocialAccount.objects.create(
+ user=self.user,
+ provider="github",
+ uid="0"
+ )
+
+ self.discord_account = SocialAccount.objects.create(
+ user=self.user,
+ provider="discord",
+ uid="0000"
+ )
+
+ self.github_account_secondary = SocialAccount.objects.create(
+ user=self.user_unlinked_discord,
+ provider="github",
+ uid="1"
+ )
+
+ self.discord_account_secondary = SocialAccount.objects.create(
+ user=self.user_unlinked_github,
+ provider="discord",
+ uid="1111"
+ )
+
+ def test_redirect_when_logged_out(self):
+ """Check that the user is redirected to the homepage when not logged in."""
+ url = reverse("account_settings")
+ resp = self.client.get(url)
+ self.assertEqual(resp.status_code, 302)
+ self.assertTrue(check_redirect_url(resp, reverse("home")))
+
+ def test_get_when_logged_in(self):
+ """Test that the view returns a HTTP 200 when the user is logged in."""
+ url = reverse("account_settings")
+
+ self.client.force_login(self.user)
+ resp = self.client.get(url)
+ self.client.logout()
+
+ self.assertEqual(resp.status_code, 200)
+
+ self.client.force_login(self.user_unlinked)
+ resp = self.client.get(url)
+ self.client.logout()
+
+ self.assertEqual(resp.status_code, 200)
+
+ self.client.force_login(self.user_unlinked_discord)
+ resp = self.client.get(url)
+ self.client.logout()
+
+ self.assertEqual(resp.status_code, 200)
+
+ self.client.force_login(self.user_unlinked_github)
+ resp = self.client.get(url)
+ self.client.logout()
+
+ self.assertEqual(resp.status_code, 200)
+
+ def test_post_invalid(self):
+ """Test the behaviour of invalid POST submissions."""
+ url = reverse("account_settings")
+
+ self.client.force_login(self.user_unlinked)
+
+ resp = self.client.post(url, {"provider": "discord"})
+ self.assertEqual(resp.status_code, 302)
+ self.assertTrue(check_redirect_url(resp, reverse("home")))
+
+ resp = self.client.post(url, {"provider": "github"})
+ self.assertEqual(resp.status_code, 302)
+ self.assertTrue(check_redirect_url(resp, reverse("home")))
+
+ self.client.logout()
+
+ def test_post_valid(self):
+ """Ensure that GitHub is unlinked with a valid POST submission."""
+ url = reverse("account_settings")
+
+ self.client.force_login(self.user)
+
+ resp = self.client.post(url, {"provider": "github"})
+ self.assertEqual(resp.status_code, 302)
+ self.assertTrue(check_redirect_url(resp, reverse("home")))
+
+ with self.assertRaises(SocialAccount.DoesNotExist):
+ SocialAccount.objects.get(user=self.user, provider="github")
+
+ self.client.logout()
class TestIndexReturns200(TestCase):
@@ -16,6 +209,7 @@ class TestLoginCancelledReturns302(TestCase):
url = reverse('socialaccount_login_cancelled')
resp = self.client.get(url)
self.assertEqual(resp.status_code, 302)
+ self.assertTrue(check_redirect_url(resp, reverse("home")))
class TestLoginErrorReturns302(TestCase):
@@ -24,3 +218,4 @@ class TestLoginErrorReturns302(TestCase):
url = reverse('socialaccount_login_error')
resp = self.client.get(url)
self.assertEqual(resp.status_code, 302)
+ self.assertTrue(check_redirect_url(resp, reverse("home")))