diff options
Diffstat (limited to 'pydis_site')
| -rw-r--r-- | pydis_site/apps/home/urls.py | 8 | ||||
| -rw-r--r-- | pydis_site/apps/home/views/__init__.py | 3 | ||||
| -rw-r--r-- | pydis_site/apps/home/views/account/__init__.py | 4 | ||||
| -rw-r--r-- | pydis_site/apps/home/views/account/delete.py | 20 | ||||
| -rw-r--r-- | pydis_site/apps/home/views/account/settings.py | 20 | ||||
| -rw-r--r-- | pydis_site/templates/base/navbar.html | 2 | ||||
| -rw-r--r-- | pydis_site/templates/home/account/delete.html | 12 | ||||
| -rw-r--r-- | pydis_site/templates/home/account/settings.html | 12 | ||||
| -rw-r--r-- | pydis_site/tests/test_utils_account.py | 50 | 
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))  |