NDOJ/judge/social_auth.py

138 lines
4.3 KiB
Python
Raw Permalink Normal View History

2020-01-21 06:35:58 +00:00
import logging
import re
from operator import itemgetter
from urllib.parse import quote
from django import forms
from django.contrib.auth.models import User
from django.db import transaction
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
from django.utils.translation import gettext as _
2020-01-21 06:35:58 +00:00
from requests import HTTPError
from reversion import revisions
from social_core.backends.github import GithubOAuth2
from social_core.exceptions import InvalidEmail, SocialAuthBaseException
from social_core.pipeline.partial import partial
2022-05-14 17:57:27 +00:00
from social_django.middleware import (
SocialAuthExceptionMiddleware as OldSocialAuthExceptionMiddleware,
)
2020-01-21 06:35:58 +00:00
from judge.forms import ProfileForm
from judge.models import Language, Profile
2022-05-14 17:57:27 +00:00
logger = logging.getLogger("judge.social_auth")
2020-01-21 06:35:58 +00:00
class GitHubSecureEmailOAuth2(GithubOAuth2):
2022-05-14 17:57:27 +00:00
name = "github-secure"
2020-01-21 06:35:58 +00:00
def user_data(self, access_token, *args, **kwargs):
data = self._user_data(access_token)
try:
2022-05-14 17:57:27 +00:00
emails = self._user_data(access_token, "/emails")
2020-01-21 06:35:58 +00:00
except (HTTPError, ValueError, TypeError):
emails = []
2022-05-14 17:57:27 +00:00
emails = [
(e.get("email"), e.get("primary"), 0)
for e in emails
if isinstance(e, dict) and e.get("verified")
]
2020-01-21 06:35:58 +00:00
emails.sort(key=itemgetter(1), reverse=True)
emails = list(map(itemgetter(0), emails))
if emails:
2022-05-14 17:57:27 +00:00
data["email"] = emails[0]
2020-01-21 06:35:58 +00:00
else:
2022-05-14 17:57:27 +00:00
data["email"] = None
2020-01-21 06:35:58 +00:00
return data
2022-05-14 17:57:27 +00:00
def slugify_username(username, renotword=re.compile(r"[^\w]")):
return renotword.sub("", username.replace("-", "_"))
2020-01-21 06:35:58 +00:00
def verify_email(backend, details, *args, **kwargs):
2022-05-14 17:57:27 +00:00
if not details["email"]:
2020-01-21 06:35:58 +00:00
raise InvalidEmail(backend)
class UsernameForm(forms.Form):
2022-05-14 17:57:27 +00:00
username = forms.RegexField(
regex=r"^\w+$",
max_length=30,
label="Username",
error_messages={
"invalid": _("A username must contain letters, numbers, or underscores")
2022-05-14 17:57:27 +00:00
},
)
2020-01-21 06:35:58 +00:00
def clean_username(self):
2022-05-14 17:57:27 +00:00
if User.objects.filter(username=self.cleaned_data["username"]).exists():
raise forms.ValidationError(_("Sorry, the username is taken."))
2022-05-14 17:57:27 +00:00
return self.cleaned_data["username"]
2020-01-21 06:35:58 +00:00
@partial
def choose_username(backend, user, username=None, *args, **kwargs):
if not user:
request = backend.strategy.request
if request.POST:
form = UsernameForm(request.POST)
if form.is_valid():
2022-05-14 17:57:27 +00:00
return {"username": form.cleaned_data["username"]}
2020-01-21 06:35:58 +00:00
else:
2022-05-14 17:57:27 +00:00
form = UsernameForm(initial={"username": username})
return render(
request,
"registration/username_select.html",
{
"title": _("Choose a username"),
2022-05-14 17:57:27 +00:00
"form": form,
},
)
2020-01-21 06:35:58 +00:00
@partial
def make_profile(backend, user, response, is_new=False, *args, **kwargs):
if is_new:
2022-05-14 17:57:27 +00:00
if not hasattr(user, "profile"):
2020-01-21 06:35:58 +00:00
profile = Profile(user=user)
2021-07-08 21:03:51 +00:00
profile.language = Language.get_default_language()
2022-05-14 17:57:27 +00:00
logger.info("Info from %s: %s", backend.name, response)
2020-01-21 06:35:58 +00:00
profile.save()
form = ProfileForm(instance=profile, user=user)
else:
data = backend.strategy.request_data()
logger.info(data)
form = ProfileForm(data, instance=user.profile, user=user)
if form.is_valid():
with transaction.atomic(), revisions.create_revision():
form.save()
revisions.set_user(user)
2022-05-14 17:57:27 +00:00
revisions.set_comment("Updated on registration")
2020-01-21 06:35:58 +00:00
return
2022-05-14 17:57:27 +00:00
return render(
backend.strategy.request,
"registration/profile_creation.html",
{
"title": _("Create your profile"),
2022-05-14 17:57:27 +00:00
"form": form,
},
)
2020-01-21 06:35:58 +00:00
class SocialAuthExceptionMiddleware(OldSocialAuthExceptionMiddleware):
def process_exception(self, request, exception):
if isinstance(exception, SocialAuthBaseException):
2022-05-14 17:57:27 +00:00
return HttpResponseRedirect(
"%s?message=%s"
% (
reverse("social_auth_error"),
quote(self.get_message(request, exception)),
)
)