Skip to content

Commit

Permalink
allow registering using oauth (#356)
Browse files Browse the repository at this point in the history
* add registering using oauth

* create oauth template, refactor logic

* update login context, fix lint

* default oauth_only to false

---------

Co-authored-by: winprn <[email protected]>
  • Loading branch information
winprn and winprn authored Dec 5, 2023
1 parent 6abfe62 commit bccb0ed
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 130 deletions.
2 changes: 2 additions & 0 deletions dmoj/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -743,3 +743,5 @@

ACE_DEFAULT_LIGHT_THEME = DMOJ_THEME_DEFAULT_ACE_THEME['light']
ACE_DEFAULT_DARK_THEME = DMOJ_THEME_DEFAULT_ACE_THEME['dark']
# Only allow OAuth login
OAUTH_ONLY = False
28 changes: 19 additions & 9 deletions judge/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,20 +432,30 @@ class Meta:
})


class CustomAuthenticationForm(AuthenticationForm):
class SocialAuthMixin:
def _has_social_auth(self, key):
return (getattr(settings, 'SOCIAL_AUTH_%s_KEY' % key, None) and
getattr(settings, 'SOCIAL_AUTH_%s_SECRET' % key, None))

@property
def has_google_auth(self):
return self._has_social_auth('GOOGLE_OAUTH2')

@property
def has_facebook_auth(self):
return self._has_social_auth('FACEBOOK')

@property
def has_github_auth(self):
return self._has_social_auth('GITHUB_SECURE')


class CustomAuthenticationForm(AuthenticationForm, SocialAuthMixin):
def __init__(self, *args, **kwargs):
super(CustomAuthenticationForm, self).__init__(*args, **kwargs)
self.fields['username'].widget.attrs.update({'placeholder': _('Username')})
self.fields['password'].widget.attrs.update({'placeholder': _('Password')})

self.has_google_auth = self._has_social_auth('GOOGLE_OAUTH2')
self.has_facebook_auth = self._has_social_auth('FACEBOOK')
self.has_github_auth = self._has_social_auth('GITHUB_SECURE')

def _has_social_auth(self, key):
return (getattr(settings, 'SOCIAL_AUTH_%s_KEY' % key, None) and
getattr(settings, 'SOCIAL_AUTH_%s_SECRET' % key, None))

def clean(self):
username = self.cleaned_data.get('username')
try:
Expand Down
4 changes: 4 additions & 0 deletions judge/views/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from registration.forms import RegistrationForm
from sortedm2m.forms import SortedMultipleChoiceField

from judge.forms import SocialAuthMixin
from judge.models import Language, Organization, Profile, TIMEZONE
from judge.utils.recaptcha import ReCaptchaField, ReCaptchaWidget
from judge.utils.subscription import Subscription, newsletter_id
Expand Down Expand Up @@ -66,6 +67,7 @@ def clean_organizations(self):
class RegistrationView(OldRegistrationView):
title = _('Register')
form_class = CustomRegistrationForm
social_auth = SocialAuthMixin()
template_name = 'registration/registration_form.html'

def get_context_data(self, **kwargs):
Expand All @@ -74,6 +76,8 @@ def get_context_data(self, **kwargs):
kwargs['TIMEZONE_MAP'] = settings.TIMEZONE_MAP
kwargs['password_validators'] = get_default_password_validators()
kwargs['tos_url'] = settings.TERMS_OF_SERVICE_URL
kwargs['oauth_only'] = settings.OAUTH_ONLY
kwargs['oauth'] = self.social_auth
return super(RegistrationView, self).get_context_data(**kwargs)

@transaction.atomic
Expand Down
5 changes: 5 additions & 0 deletions judge/views/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,11 @@ class CustomLoginView(LoginView):
authentication_form = CustomAuthenticationForm
redirect_authenticated_user = True

def get_context_data(self, **kwargs):
context = super(CustomLoginView, self).get_context_data(**kwargs)
context['oauth'] = context['form']
return context

def form_valid(self, form):
password = form.cleaned_data['password']
validator = PwnedPasswordsValidator()
Expand Down
47 changes: 1 addition & 46 deletions templates/registration/login.html
Original file line number Diff line number Diff line change
@@ -1,31 +1,5 @@
{% extends "base.html" %}

{% block media %}
<style>
h4 {
padding-top: 1em;
}

.social {
display: inline;
font-size: 2.3em;
float: none;
}

.google-icon i {
color: #DD4B38;
}

.facebook-icon i {
color: #133783;
}

.github-icon i {
color: black;
}
</style>
{% endblock %}

{% block body %}
<div class="auth-flow-form">
<form action="" method="post" class="form-area">
Expand Down Expand Up @@ -61,25 +35,6 @@
</form>
<a href="{{ url('password_reset') }}">{{ _('Forgot your password?') }}</a>

{% if form.has_google_auth or form.has_facebook_auth or form.has_github_auth %}
<h4>{{ _('Or log in with...') }}</h4>
<div>
{% if form.has_google_auth %}
<a href="{{ url('social:begin', "google-oauth2") }}?next={{ next }}" class="social google-icon">
<i class="fa fa-google-plus-square"></i>
</a>
{% endif %}
{% if form.has_facebook_auth %}
<a href="{{ url('social:begin', "facebook") }}?next={{ next }}" class="social facebook-icon">
<i class="fa fa-facebook-square"></i>
</a>
{% endif %}
{% if form.has_github_auth %}
<a href="{{ url('social:begin', "github-secure") }}?next={{ next }}" class="social github-icon">
<i class="fa fa-github-square"></i>
</a>
{% endif %}
</div>
{% endif %}
{% include "registration/oauth.html" %}
</div>
{% endblock %}
46 changes: 46 additions & 0 deletions templates/registration/oauth.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{% block media %}
<style>
h4 {
padding-top: 1em;
}

.social {
display: inline;
font-size: 2.3em;
float: none;
}

.google-icon i {
color: #DD4B38;
}

.facebook-icon i {
color: #133783;
}

.github-icon i {
color: black;
}
</style>
{% endblock %}

{% if oauth.has_google_auth or oauth.has_facebook_auth or oauth.has_github_auth %}
<h4>{{ _('Or log in with...') }}</h4>
<div>
{% if oauth.has_google_auth %}
<a href="{{ url('social:begin', "google-oauth2") }}?next={{ next }}" class="social google-icon">
<i class="fa fa-google-plus-square"></i>
</a>
{% endif %}
{% if oauth.has_facebook_auth %}
<a href="{{ url('social:begin', "facebook") }}?next={{ next }}" class="social facebook-icon">
<i class="fa fa-facebook-square"></i>
</a>
{% endif %}
{% if oauth.has_github_auth %}
<a href="{{ url('social:begin', "github-secure") }}?next={{ next }}" class="social github-icon">
<i class="fa fa-github-square"></i>
</a>
{% endif %}
</div>
{% endif %}
175 changes: 100 additions & 75 deletions templates/registration/registration_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,28 @@
.pass-req {
padding: 0;
}

h4 {
padding-top: 1em;
}

.social {
display: inline;
font-size: 2.3em;
float: none;
}

.google-icon i {
color: #DD4B38;
}

.facebook-icon i {
color: #133783;
}

.github-icon i {
color: black;
}
</style>
{% endblock %}

Expand All @@ -132,98 +154,101 @@
{% endblock %}

{% block body %}
<div id="center-float">
<form id="edit-form" action="" method="post" class="form-area">
{% csrf_token %}

<div class="block-header">{{ _('Full name') }}<small>({{ _('can be blank') }})</small></div>
<span class="fullwidth{% if form.full_name.errors %}-error{% endif %}">{{ form.full_name }}</span>
{% if form.full_name.errors %}
<div class="form-field-error">{{ form.full_name.errors }}</div>
{% endif %}
<div id="center-float">
{% if not oauth_only %}
<form id="edit-form" action="" method="post" class="form-area">
{% csrf_token %}

<div class="block-header">{{ _('Full name') }}<small>({{ _('can be blank') }})</small></div>
<span class="fullwidth{% if form.full_name.errors %}-error{% endif %}">{{ form.full_name }}</span>
{% if form.full_name.errors %}
<div class="form-field-error">{{ form.full_name.errors }}</div>
{% endif %}


<div class="block-header">{{ _('Username') }}</div>
<span class="fullwidth{% if form.username.errors %}-error{% endif %}">{{ form.username }}</span>
{% if form.username.errors %}
<div class="form-field-error">{{ form.username.errors }}</div>
{% endif %}
<div class="block-header">{{ _('Username') }}</div>
<span class="fullwidth{% if form.username.errors %}-error{% endif %}">{{ form.username }}</span>
{% if form.username.errors %}
<div class="form-field-error">{{ form.username.errors }}</div>
{% endif %}

<div class="block-header">{{ _('Email') }}<small>({{ _('please choose a popular email provider, e.g. gmail') }})</small></div>
<span class="fullwidth{% if form.email.errors %}-error{% endif %}">{{ form.email }}</span>
{% if form.email.errors %}
<div class="form-field-error">{{ form.email.errors }}</div>
{% endif %}
<div class="block-header">{{ _('Email') }}<small>({{ _('please choose a popular email provider, e.g. gmail') }})</small></div>
<span class="fullwidth{% if form.email.errors %}-error{% endif %}">{{ form.email }}</span>
{% if form.email.errors %}
<div class="form-field-error">{{ form.email.errors }}</div>
{% endif %}

<div class="block-header">{{ _('Password') -}}
<small>(<a href="#" class="pass-req-link">?</a>)</small>
</div>
<div style="display: none" class="pass-req alert alert-info">
<ul>
{% for validator in password_validators %}
<li>{{ validator.get_help_text() }}</li>
{% endfor %}
</ul>
</div>
<span class="fullwidth{% if form.password1.errors %}-error{% endif %}">{{ form.password1 }}</span>
{% if form.password1.errors %}
<div class="form-field-error">{{ form.password1.errors }}</div>
{% endif %}
<div class="block-header">{{ _('Password') }}<sup style="font-size: 0.7em;padding-left: 0.2em;">2</sup>{# -#}
<small>{{ _('(again, for confirmation)') }}</small>
</div>
<span class="fullwidth{% if form.password2.errors %}-error{% endif %}">{{ form.password2 }}</span>
{% if form.password2.errors %}
<div class="form-field-error">{{ form.password2.errors }}</div>
{% endif %}
<div class="block-header">{{ _('Password') -}}
<small>(<a href="#" class="pass-req-link">?</a>)</small>
</div>
<div style="display: none" class="pass-req alert alert-info">
<ul>
{% for validator in password_validators %}
<li>{{ validator.get_help_text() }}</li>
{% endfor %}
</ul>
</div>
<span class="fullwidth{% if form.password1.errors %}-error{% endif %}">{{ form.password1 }}</span>
{% if form.password1.errors %}
<div class="form-field-error">{{ form.password1.errors }}</div>
{% endif %}
<div class="block-header">{{ _('Password') }}<sup style="font-size: 0.7em;padding-left: 0.2em;">2</sup>{# -#}
<small>{{ _('(again, for confirmation)') }}</small>
</div>
<span class="fullwidth{% if form.password2.errors %}-error{% endif %}">{{ form.password2 }}</span>
{% if form.password2.errors %}
<div class="form-field-error">{{ form.password2.errors }}</div>
{% endif %}

<div class="block-header">{{ _('Timezone') }}<small>{{ _('(select your closest major city)') }}</small></div>
<div class="fullwidth">
<div>{{ form.timezone }}
<div style="float: right">
{{ _('or') }}
<a id="open-map" href="#" data-featherlight=".map-wrap">{{ _('pick from map') }}</a>
<div class="block-header">{{ _('Timezone') }}<small>{{ _('(select your closest major city)') }}</small></div>
<div class="fullwidth">
<div>{{ form.timezone }}
<div style="float: right">
{{ _('or') }}
<a id="open-map" href="#" data-featherlight=".map-wrap">{{ _('pick from map') }}</a>
</div>
</div>
</div>
</div>

<div class="block-header">{{ _('Default language') }}</div>
<span class="fullwidth">{{ form.language }}</span>
<div class="block-header">{{ _('Default language') }}</div>
<span class="fullwidth">{{ form.language }}</span>

<div class="block-header">{{ _('Affiliated organizations') }}<small>({{ _('can be blank') }})</small></div>
{{ form.organizations }}
{% if form.organizations.errors %}
<div class="form-field-error">{{ form.organizations.errors }}</div>
{% endif %}
<div class="block-header">{{ _('Affiliated organizations') }}<small>({{ _('can be blank') }})</small></div>
{{ form.organizations }}
{% if form.organizations.errors %}
<div class="form-field-error">{{ form.organizations.errors }}</div>
{% endif %}

{% if form.newsletter %}
<div style="padding-top: 0.5em;">{{ form.newsletter }}
<label for="id_newsletter" style="float: unset;"
class="inline-header grayed">{{ _('Notify me about upcoming contests') }}</label>
</div>
{% endif %}
{% if form.newsletter %}
<div style="padding-top: 0.5em;">{{ form.newsletter }}
<label for="id_newsletter" style="float: unset;"
class="inline-header grayed">{{ _('Notify me about upcoming contests') }}</label>
</div>
{% endif %}

{% if form.captcha %}
<div style="margin-top: 0.5em">{{ form.captcha }}</div>
{% if form.captcha.errors %}
<div class="form-field-error">{{ form.captcha.errors }}</div>
{% if form.captcha %}
<div style="margin-top: 0.5em">{{ form.captcha }}</div>
{% if form.captcha.errors %}
<div class="form-field-error">{{ form.captcha.errors }}</div>
{% endif %}
{% endif %}
{% endif %}

<hr>
<hr>
<button style="float:right;" type="submit">{{ _('Register!') }}</button>
</form>
{% endif %}
{% include "registration/oauth.html" %}
{% if tos_url %}
<span class="tos-section">
{{ (_('By registering, you agree to our [Terms & Conditions][0].') + '\n\n [0]: ' + tos_url)|markdown('default', strip_paragraphs=True) }}
</span>
{% endif %}
<button style="float:right;" type="submit">{{ _('Register!') }}</button>
</form>
</div>

<div class="map-wrap">
<div class="map-inset">
<div class="map-axis-x"></div>
<div class="map-axis-y"></div>
</div>
</div>

<div class="map-wrap">
<div class="map-inset">
<div class="map-axis-x"></div>
<div class="map-axis-y"></div>
</div>
</div>
{% endblock %}

0 comments on commit bccb0ed

Please sign in to comment.