diff --git a/signup/forms.py b/signup/forms.py
new file mode 100644
index 0000000..9a5a67d
--- /dev/null
+++ b/signup/forms.py
@@ -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')
diff --git a/signup/jinja2/signup/index.html b/signup/jinja2/signup/index.html
index 5bb27a8..504cfe8 100644
--- a/signup/jinja2/signup/index.html
+++ b/signup/jinja2/signup/index.html
@@ -1,24 +1,10 @@
{% extends "base.html" %}
{% block title %}Sign up a new account{% endblock %}
{% block content %}
-
Sign up
-
-
Username rules:
-
- - Must be between 3 and 20 characters
- - Can only contain ASCII letters (case sensitive) and numbers
-
-
Password rules:
-
- - Must be between 8 and 1024 characters
-
-
-
+ Sign up
+
{% endblock %}
diff --git a/signup/views.py b/signup/views.py
index a714690..7094cd3 100644
--- a/signup/views.py
+++ b/signup/views.py
@@ -2,9 +2,10 @@
"""
/signup app views.
"""
+# TODO: make unique username validation be case insensitive
from django.shortcuts import redirect, render
-from users.models import User
+from .forms import SignupForm
def index(request):
"""
@@ -12,7 +13,11 @@ def index(request):
"""
if request.user.is_authenticated:
return redirect('homepage:index')
- if request.method == "GET":
- context = {}
- return render(request, 'signup/index.html', context)
-
+ if request.method == 'POST':
+ form = SignupForm(request.POST)
+ if form.is_valid():
+ form.save()
+ return redirect('login:index')
+ else:
+ form = SignupForm()
+ return render(request, 'signup/index.html', {'form': form})
diff --git a/titivillus/settings.py b/titivillus/settings.py
index 0ae81a6..550ce1e 100644
--- a/titivillus/settings.py
+++ b/titivillus/settings.py
@@ -98,9 +98,6 @@ DATABASES = {
# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
- {
- 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
- },
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
'OPTIONS': {
@@ -108,11 +105,11 @@ AUTH_PASSWORD_VALIDATORS = [
}
},
{
- 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
- },
- {
- 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
- },
+ 'NAME': 'users.validators.MaximumLengthValidator',
+ 'OPTIONS': {
+ 'max_length': 1024,
+ }
+ }
]
@@ -123,9 +120,9 @@ LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'America/New_York'
-USE_I18N = True
+USE_I18N = False
-USE_L10N = True
+USE_L10N = False
USE_TZ = True
diff --git a/users/models.py b/users/models.py
index 137f697..90a3f61 100644
--- a/users/models.py
+++ b/users/models.py
@@ -2,29 +2,44 @@
"""
A custom user model.
"""
+import string
+
from django.db import models
from django.contrib.auth.models import AbstractUser
-from django.utils.translation import gettext_lazy as _
-from django.contrib.auth.validators import UnicodeUsernameValidator
+from django.core.validators import MinLengthValidator, MaxLengthValidator
+
+from .validators import CharValidator
class User(AbstractUser):
"""
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'),
+ 'username',
max_length=20,
unique=True,
- help_text=_("Required. 20 characters or fewer. "
- + "Letters, digits and @/./+/-/_ only."),
- validators=[username_validator],
+ help_text="Must be between 3 and 20 characters. " \
+ + "Letters and digits only.",
+ validators=[username_char, username_min, username_max],
error_messages={
- 'unique': _("A user with that username already exists."),
- },)
+ 'unique': "A user with that username already exists.",
+ },
+ )
first_name = None
last_name = None
- email = models.EmailField(_('email address'))
+ email = models.EmailField('email address')
def get_full_name(self):
return None
diff --git a/users/validators.py b/users/validators.py
new file mode 100644
index 0000000..e08b073
--- /dev/null
+++ b/users/validators.py
@@ -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