/signup page works and validates correctly

This commit is contained in:
iou1name 2018-08-12 14:52:05 -04:00
parent 03ba297122
commit d48cf18566
6 changed files with 111 additions and 45 deletions

18
signup/forms.py Normal file
View File

@ -0,0 +1,18 @@
#/usr/bin/env python3
"""
Form(s) for the signup app.
"""
from django import forms
from django.contrib.auth.forms import UserCreationForm
from users.models import User
class SignupForm(UserCreationForm):
"""
The form for the signup page.
"""
email = forms.EmailField(max_length=254, help_text="Must be a valid email address.")
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')

View File

@ -2,23 +2,9 @@
{% block title %}Sign up a new account{% endblock %} {% block title %}Sign up a new account{% endblock %}
{% block content %} {% block content %}
<h1>Sign up</h1> <h1>Sign up</h1>
<div id="namePassRules">
<p>Username rules:
<ul>
<li>Must be between 3 and 20 characters</li>
<li>Can only contain ASCII letters (case sensitive) and numbers</li>
</ul>
<p>Password rules:
<ul>
<li>Must be between 8 and 1024 characters</li>
</ul>
</div>
<form method="post" action="{{ url('signup:index') }}"> <form method="post" action="{{ url('signup:index') }}">
{{ csrf_input }} {{ csrf_input }}
<input type="text" placeholder="Username" name="username" maxlength="20" required/><br /> {{ form.as_p() }}
<input type="text" placeholder="Email" name="email" maxlength="20" required/><br />
<input type="password" placeholder="Password" name="password" maxlength="1024" required/><br />
<input type="password" placeholder="Verify password" name="password_verify" maxlength="1024" required/><br />
<input type="submit" value="Sign up" name="submit"/> <input type="submit" value="Sign up" name="submit"/>
</form> </form>
{% endblock %} {% endblock %}

View File

@ -2,9 +2,10 @@
""" """
/signup app views. /signup app views.
""" """
# TODO: make unique username validation be case insensitive
from django.shortcuts import redirect, render from django.shortcuts import redirect, render
from users.models import User from .forms import SignupForm
def index(request): def index(request):
""" """
@ -12,7 +13,11 @@ def index(request):
""" """
if request.user.is_authenticated: if request.user.is_authenticated:
return redirect('homepage:index') return redirect('homepage:index')
if request.method == "GET": if request.method == 'POST':
context = {} form = SignupForm(request.POST)
return render(request, 'signup/index.html', context) if form.is_valid():
form.save()
return redirect('login:index')
else:
form = SignupForm()
return render(request, 'signup/index.html', {'form': form})

View File

@ -98,9 +98,6 @@ DATABASES = {
# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [ AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{ {
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
'OPTIONS': { 'OPTIONS': {
@ -108,11 +105,11 @@ AUTH_PASSWORD_VALIDATORS = [
} }
}, },
{ {
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 'NAME': 'users.validators.MaximumLengthValidator',
}, 'OPTIONS': {
{ 'max_length': 1024,
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }
}, }
] ]
@ -123,9 +120,9 @@ LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'America/New_York' TIME_ZONE = 'America/New_York'
USE_I18N = True USE_I18N = False
USE_L10N = True USE_L10N = False
USE_TZ = True USE_TZ = True

View File

@ -2,29 +2,44 @@
""" """
A custom user model. A custom user model.
""" """
import string
from django.db import models from django.db import models
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
from django.utils.translation import gettext_lazy as _ from django.core.validators import MinLengthValidator, MaxLengthValidator
from django.contrib.auth.validators import UnicodeUsernameValidator
from .validators import CharValidator
class User(AbstractUser): class User(AbstractUser):
""" """
A custom user model. A custom user model.
""" """
username_validator = UnicodeUsernameValidator() username_char = CharValidator(
string.ascii_letters + string.digits,
"Username must only contain alphanumeric characters."
)
username_min = MinLengthValidator(
3,
"Username must contain more than 3 characters."
)
username_max = MaxLengthValidator(
20,
"Username must contain less than 20 characters."
)
username = models.CharField( username = models.CharField(
_('username'), 'username',
max_length=20, max_length=20,
unique=True, unique=True,
help_text=_("Required. 20 characters or fewer. " help_text="Must be between 3 and 20 characters. " \
+ "Letters, digits and @/./+/-/_ only."), + "Letters and digits only.",
validators=[username_validator], validators=[username_char, username_min, username_max],
error_messages={ error_messages={
'unique': _("A user with that username already exists."), 'unique': "A user with that username already exists.",
},) },
)
first_name = None first_name = None
last_name = None last_name = None
email = models.EmailField(_('email address')) email = models.EmailField('email address')
def get_full_name(self): def get_full_name(self):
return None return None

45
users/validators.py Normal file
View File

@ -0,0 +1,45 @@
#!/usr/bin/env python3
"""
Some custom validators for the user model.
"""
from django.core.validators import BaseValidator
from django.core.exceptions import ValidationError
class MaximumLengthValidator:
"""
Validate whether the password exceeds a maximum length.
"""
def __init__(self, max_length=1024):
self.max_length = max_length
def validate(self, password, user=None):
if len(password) > self.max_length:
raise ValidationError(
"This password is too long. It must contain at most " \
+ f"{self.max_length} characters.",
code="password_too_long",
params={'max_length': self.max_length}
)
def get_help_text(self):
msg = f"Your password must contain less than {self.max_length} " \
+ "characters."
return msg
class CharValidator(BaseValidator):
"""
Raises a ValidationError with a code of 'invalid_chars' if value is not
a string or contains letters which are not also within limit_value.
"""
message = 'Ensure this value only contains the characters "%(limit_value)s".'
code = 'invalid_chars'
def compare(self, value, limit_value):
assert type(limit_value) == str
if type(value) != str:
return True
for c in value:
if c not in limit_value:
return True
return False