aboutsummaryrefslogtreecommitdiffstats
path: root/pydis_site/utils
diff options
context:
space:
mode:
authorGravatar scragly <[email protected]>2020-09-18 03:33:35 +1000
committerGravatar scragly <[email protected]>2020-09-18 03:33:35 +1000
commit357b20145b2784d9334b941fc25bcb8ce7b64c11 (patch)
treeccd446b4841ad69ae22fdc91f4c246823e0f811e /pydis_site/utils
parentAdd new test for deleted message context log_url. (diff)
parentMerge pull request #390 from python-discord/allow_blank_or_null_for_nominatio... (diff)
Merge branch 'master' into admin-api-pages-improvements
# Conflicts: # pydis_site/apps/api/admin.py
Diffstat (limited to 'pydis_site/utils')
-rw-r--r--pydis_site/utils/account.py79
1 files changed, 79 insertions, 0 deletions
diff --git a/pydis_site/utils/account.py b/pydis_site/utils/account.py
new file mode 100644
index 00000000..b4e41198
--- /dev/null
+++ b/pydis_site/utils/account.py
@@ -0,0 +1,79 @@
+from typing import Any, Dict
+
+from allauth.account.adapter import DefaultAccountAdapter
+from allauth.exceptions import ImmediateHttpResponse
+from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
+from allauth.socialaccount.models import SocialLogin
+from django.contrib.auth.models import User as DjangoUser
+from django.contrib.messages import ERROR, add_message
+from django.http import HttpRequest
+from django.shortcuts import redirect
+from django.urls import reverse
+
+from pydis_site.apps.api.models import User as DiscordUser
+
+ERROR_CONNECT_DISCORD = ("You must login with Discord before connecting another account. "
+ "Your account details have not been saved.")
+ERROR_JOIN_DISCORD = ("Please join the Discord server and verify that you accept the rules and "
+ "privacy policy.")
+
+
+class AccountAdapter(DefaultAccountAdapter):
+ """An Allauth account adapter that prevents signups via form submission."""
+
+ def is_open_for_signup(self, request: HttpRequest) -> bool:
+ """
+ Checks whether or not the site is open for signups.
+
+ We override this to always return False so that users may never sign up using
+ Allauth's signup form endpoints, to be on the safe side - since we only want users
+ to sign up using their Discord account.
+ """
+ return False
+
+
+class SocialAccountAdapter(DefaultSocialAccountAdapter):
+ """An Allauth SocialAccount adapter that prevents signups via non-Discord connections."""
+
+ def is_open_for_signup(self, request: HttpRequest, social_login: SocialLogin) -> bool:
+ """
+ Checks whether or not the site is open for signups.
+
+ We override this method in order to prevent users from creating a new account using
+ a non-Discord connection, as we require this connection for our users.
+ """
+ if social_login.account.provider != "discord":
+ add_message(request, ERROR, ERROR_CONNECT_DISCORD)
+
+ raise ImmediateHttpResponse(redirect(reverse("home")))
+
+ try:
+ user = DiscordUser.objects.get(id=int(social_login.account.uid))
+ except DiscordUser.DoesNotExist:
+ add_message(request, ERROR, ERROR_JOIN_DISCORD)
+
+ raise ImmediateHttpResponse(redirect(reverse("home")))
+
+ if len(user.roles) <= 1:
+ add_message(request, ERROR, ERROR_JOIN_DISCORD)
+
+ raise ImmediateHttpResponse(redirect(reverse("home")))
+
+ return True
+
+ def populate_user(self, request: HttpRequest,
+ social_login: SocialLogin,
+ data: Dict[str, Any]) -> DjangoUser:
+ """
+ Method used to populate a Django User with data.
+
+ We override this so that the Django user is created with the username#discriminator,
+ instead of just the username, as Django users must have unique usernames. For display
+ purposes, we also set the `name` key, which is used for `first_name` in the database.
+ """
+ if social_login.account.provider == "discord":
+ discriminator = social_login.account.extra_data["discriminator"]
+ data["username"] = f"{data['username']}#{discriminator:0>4}"
+ data["name"] = data["username"]
+
+ return super().populate_user(request, social_login, data)