aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pydis_site/apps/home/urls.py8
-rw-r--r--pydis_site/apps/home/views/__init__.py3
-rw-r--r--pydis_site/apps/home/views/account/__init__.py4
-rw-r--r--pydis_site/apps/home/views/account/delete.py20
-rw-r--r--pydis_site/apps/home/views/account/settings.py20
-rw-r--r--pydis_site/templates/base/navbar.html2
-rw-r--r--pydis_site/templates/home/account/delete.html12
-rw-r--r--pydis_site/templates/home/account/settings.html12
-rw-r--r--pydis_site/tests/test_utils_account.py50
9 files changed, 126 insertions, 5 deletions
diff --git a/pydis_site/apps/home/urls.py b/pydis_site/apps/home/urls.py
index 211a7ad1..70a41177 100644
--- a/pydis_site/apps/home/urls.py
+++ b/pydis_site/apps/home/urls.py
@@ -1,5 +1,4 @@
from allauth.account.views import LogoutView
-from allauth.socialaccount.views import ConnectionsView
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
@@ -7,7 +6,7 @@ from django.contrib.messages import ERROR
from django.urls import include, path
from pydis_site.utils.views import MessageRedirectView
-from .views import HomeView
+from .views import AccountDeleteView, AccountSettingsView, HomeView
app_name = 'home'
urlpatterns = [
@@ -15,6 +14,7 @@ urlpatterns = [
path('pages/', include('wiki.urls')),
path('accounts/', include('allauth.socialaccount.providers.discord.urls')),
+ path('accounts/', include('allauth.socialaccount.providers.github.urls')),
path(
'accounts/login/cancelled', MessageRedirectView.as_view(
@@ -28,7 +28,9 @@ urlpatterns = [
), name='socialaccount_login_error'
),
- path('connections', ConnectionsView.as_view()),
+ path('accounts/settings', AccountSettingsView.as_view(), name="account_settings"),
+ path('accounts/delete', AccountDeleteView.as_view(), name="account_delete"),
+
path('logout', LogoutView.as_view(), name="logout"),
path('admin/', admin.site.urls),
diff --git a/pydis_site/apps/home/views/__init__.py b/pydis_site/apps/home/views/__init__.py
index 971d73a3..801fd398 100644
--- a/pydis_site/apps/home/views/__init__.py
+++ b/pydis_site/apps/home/views/__init__.py
@@ -1,3 +1,4 @@
+from .account import DeleteView as AccountDeleteView, SettingsView as AccountSettingsView
from .home import HomeView
-__all__ = ["HomeView"]
+__all__ = ["AccountDeleteView", "AccountSettingsView", "HomeView"]
diff --git a/pydis_site/apps/home/views/account/__init__.py b/pydis_site/apps/home/views/account/__init__.py
new file mode 100644
index 00000000..3b3250ea
--- /dev/null
+++ b/pydis_site/apps/home/views/account/__init__.py
@@ -0,0 +1,4 @@
+from .delete import DeleteView
+from .settings import SettingsView
+
+__all__ = ["DeleteView", "SettingsView"]
diff --git a/pydis_site/apps/home/views/account/delete.py b/pydis_site/apps/home/views/account/delete.py
new file mode 100644
index 00000000..f80089d5
--- /dev/null
+++ b/pydis_site/apps/home/views/account/delete.py
@@ -0,0 +1,20 @@
+from django.contrib.auth.mixins import LoginRequiredMixin
+from django.http import HttpRequest, HttpResponse
+from django.shortcuts import render
+from django.urls import reverse
+from django.views import View
+
+
+class DeleteView(LoginRequiredMixin, View):
+ """Account deletion view, for removing linked user accounts from the DB."""
+
+ def __init__(self, *args, **kwargs):
+ self.login_url = reverse("home")
+ super().__init__(*args, **kwargs)
+
+ def get(self, request: HttpRequest) -> HttpResponse:
+ """HTTP GET: Return the view template."""
+ return render(request, "home/account/delete.html")
+
+ def post(self, request: HttpRequest) -> HttpResponse:
+ """HTTP POST: Process the deletion, as requested by the user."""
diff --git a/pydis_site/apps/home/views/account/settings.py b/pydis_site/apps/home/views/account/settings.py
new file mode 100644
index 00000000..aa272552
--- /dev/null
+++ b/pydis_site/apps/home/views/account/settings.py
@@ -0,0 +1,20 @@
+from django.contrib.auth.mixins import LoginRequiredMixin
+from django.http import HttpRequest, HttpResponse
+from django.shortcuts import render
+from django.urls import reverse
+from django.views import View
+
+
+class SettingsView(LoginRequiredMixin, View):
+ """Account settings view, for managing and deleting user accounts and connections."""
+
+ def __init__(self, *args, **kwargs):
+ self.login_url = reverse("home")
+ super().__init__(*args, **kwargs)
+
+ def get(self, request: HttpRequest) -> HttpResponse:
+ """HTTP GET: Return the view template."""
+ return render(request, "home/account/settings.html")
+
+ def post(self, request: HttpRequest) -> HttpResponse:
+ """HTTP POST: Process account changes, as requested by the user."""
diff --git a/pydis_site/templates/base/navbar.html b/pydis_site/templates/base/navbar.html
index f1a3f928..bd0bab40 100644
--- a/pydis_site/templates/base/navbar.html
+++ b/pydis_site/templates/base/navbar.html
@@ -105,7 +105,7 @@
<div class="field navbar-item is-paddingless is-fullwidth is-grouped">
<button type="submit" class="button is-white is-inline is-fullwidth has-text-left is-size-navbar-menu has-text-grey-dark">Logout</button>
- <a title="Settings" class="button is-white is-inline has-text-right is-size-navbar-menu has-text-grey-dark" href="#">
+ <a title="Settings" class="button is-white is-inline has-text-right is-size-navbar-menu has-text-grey-dark" href="{% url "account_settings" %}">
<span class="is-icon">
<i class="fas fa-cog"></i>
</span>
diff --git a/pydis_site/templates/home/account/delete.html b/pydis_site/templates/home/account/delete.html
new file mode 100644
index 00000000..8d68a0e3
--- /dev/null
+++ b/pydis_site/templates/home/account/delete.html
@@ -0,0 +1,12 @@
+{% extends 'base/base.html' %}
+{% load static %}
+
+{% block title %}Delete Account{% endblock %}
+
+{% block content %}
+ {% include "base/navbar.html" %}
+
+ <section class="section">
+
+ </section>
+{% endblock %}
diff --git a/pydis_site/templates/home/account/settings.html b/pydis_site/templates/home/account/settings.html
new file mode 100644
index 00000000..ba1d38a2
--- /dev/null
+++ b/pydis_site/templates/home/account/settings.html
@@ -0,0 +1,12 @@
+{% extends 'base/base.html' %}
+{% load static %}
+
+{% block title %}My Account{% endblock %}
+
+{% block content %}
+ {% include "base/navbar.html" %}
+
+ <section class="section">
+
+ </section>
+{% endblock %}
diff --git a/pydis_site/tests/test_utils_account.py b/pydis_site/tests/test_utils_account.py
new file mode 100644
index 00000000..91c2808c
--- /dev/null
+++ b/pydis_site/tests/test_utils_account.py
@@ -0,0 +1,50 @@
+from unittest.mock import patch
+
+from allauth.exceptions import ImmediateHttpResponse
+from allauth.socialaccount.models import SocialAccount, SocialLogin
+from django.contrib.auth.models import User
+from django.contrib.messages.storage.base import BaseStorage
+from django.http import HttpRequest
+from django.test import TestCase
+
+from pydis_site.utils.account import AccountAdapter, SocialAccountAdapter
+
+
+class AccountUtilsTests(TestCase):
+ def setUp(self):
+ self.django_user = User.objects.create(username="user")
+
+ self.discord_account = SocialAccount.objects.create(
+ user=self.django_user, provider="discord", uid=0
+ )
+
+ self.github_account = SocialAccount.objects.create(
+ user=self.django_user, provider="github", uid=0
+ )
+
+ def test_account_adapter(self):
+ """Test that our Allauth account adapter functions correctly."""
+ adapter = AccountAdapter()
+
+ self.assertFalse(adapter.is_open_for_signup(HttpRequest()))
+
+ def test_social_account_adapter(self):
+ """Test that our Allauth social account adapter functions correctly."""
+ adapter = SocialAccountAdapter()
+
+ discord_login = SocialLogin(account=self.discord_account)
+ github_login = SocialLogin(account=self.github_account)
+
+ messages_request = HttpRequest()
+ messages_request._messages = BaseStorage(messages_request)
+
+ with patch("pydis_site.utils.account.reverse") as mock_reverse:
+ with patch("pydis_site.utils.account.redirect") as mock_redirect:
+ with self.assertRaises(ImmediateHttpResponse):
+ adapter.is_open_for_signup(messages_request, github_login)
+
+ self.assertEqual(len(messages_request._messages._queued_messages), 1)
+ self.assertEqual(mock_redirect.call_count, 1)
+ self.assertEqual(mock_reverse.call_count, 1)
+
+ self.assertTrue(adapter.is_open_for_signup(HttpRequest(), discord_login))