84 lines
3.1 KiB
Python
84 lines
3.1 KiB
Python
from django import forms
|
|
from django.contrib.auth import (authenticate, get_user_model)
|
|
from django.contrib.auth.forms import UsernameField
|
|
from django.utils.text import capfirst
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
UserModel = get_user_model()
|
|
|
|
class OTPAuthenticationForm(forms.Form):
|
|
"""
|
|
Base class for authenticating users. Extend this to get a form that accepts
|
|
username/password logins.
|
|
"""
|
|
phone_number = UsernameField(widget=forms.TextInput(attrs={'autofocus': True}))
|
|
otp = forms.CharField(
|
|
label=_("otp"),
|
|
strip=False,
|
|
widget=forms.PasswordInput(attrs={'autocomplete': 'current-password'}),
|
|
)
|
|
|
|
error_messages = {
|
|
'invalid_login': _(
|
|
"Please enter a correct %(phone_number)s and otp. Note that both "
|
|
"fields may be case-sensitive."
|
|
),
|
|
'inactive': _("This account is inactive."),
|
|
}
|
|
|
|
def __init__(self, request=None, *args, **kwargs):
|
|
"""
|
|
The 'request' parameter is set for custom auth use by subclasses.
|
|
The form data comes in via the standard 'data' kwarg.
|
|
"""
|
|
self.request = request
|
|
self.user_cache = None
|
|
super().__init__(*args, **kwargs)
|
|
|
|
# Set the max length and label for the "username" field.
|
|
self.phone_number_field = UserModel._meta.get_field('phone_number')
|
|
phone_number_max_length = self.phone_number_field.max_length or 24
|
|
self.fields['phone_number'].max_length = phone_number_max_length
|
|
self.fields['phone_number'].widget.attrs['maxlength'] = phone_number_max_length
|
|
if self.fields['phone_number'].label is None:
|
|
self.fields['phone_number'].label = capfirst(self.phone_number_field.verbose_name)
|
|
|
|
def clean(self):
|
|
phone_number = self.cleaned_data.get('phone_number')
|
|
otp = self.cleaned_data.get('otp')
|
|
|
|
if phone_number is not None and otp:
|
|
self.user_cache = authenticate(self.request, phone_number=phone_number, otp=otp)
|
|
if self.user_cache is None:
|
|
raise self.get_invalid_login_error()
|
|
else:
|
|
self.confirm_login_allowed(self.user_cache)
|
|
|
|
return self.cleaned_data
|
|
|
|
def confirm_login_allowed(self, user):
|
|
"""
|
|
Controls whether the given User may log in. This is a policy setting,
|
|
independent of end-user authentication. This default behavior is to
|
|
allow login by active users, and reject login by inactive users.
|
|
|
|
If the given user cannot log in, this method should raise a
|
|
``forms.ValidationError``.
|
|
|
|
If the given user may log in, this method should return None.
|
|
"""
|
|
if not user.is_active:
|
|
raise forms.ValidationError(
|
|
self.error_messages['inactive'],
|
|
code='inactive',
|
|
)
|
|
|
|
def get_user(self):
|
|
return self.user_cache
|
|
|
|
def get_invalid_login_error(self):
|
|
return forms.ValidationError(
|
|
self.error_messages['invalid_login'],
|
|
code='invalid_login',
|
|
params={'phone_number': self.phone_number_field.verbose_name},
|
|
)
|