Skip to content

Commit

Permalink
Rework accounts
Browse files Browse the repository at this point in the history
Entirely rework the accounts front-end to simplify things and align
better with built-in Django:
 - Use Bootstrap infrastructure to render forms plainly in templates
   (see previous commit).
 - Rename forms and views to correspond to the builtin ones, but
   ensure that the builtin ones can't accidentally be imported.
 - Use a base template for all account-related pages to ensure
   consistency.
 - Reuse the exact wording in Django templates in more places to be
   able to reuse Django translations seamlessly.
 - Avoid duplicate URLs that can be confusing if you hit the wrong one.
  • Loading branch information
friedelwolff committed Aug 29, 2024
1 parent 31d187d commit cbf8c96
Show file tree
Hide file tree
Showing 20 changed files with 227 additions and 284 deletions.
49 changes: 21 additions & 28 deletions app/accounts/forms.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
from django import forms
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
from django.contrib.auth.forms import AuthenticationForm as _AuthenticationForm
from django.contrib.auth.forms import PasswordChangeForm as _PasswordChangeForm
from django.contrib.auth.forms import PasswordResetForm as _PasswordResetForm
from django.contrib.auth.forms import SetPasswordForm as _SetPasswordForm
from django.contrib.auth.forms import UserCreationForm as _UserCreationForm
from django.utils.translation import gettext_lazy as _

from users.models import CustomUser
Expand All @@ -16,38 +20,27 @@ def __init__(self, *args, **kwargs):
field.widget.attrs["class"] = "form-control"


class CustomUserCreationForm(UserCreationForm):
email = forms.EmailField(
required=True,
help_text=_("Required. Add a valid email address."),
)
username = forms.CharField(
required=True,
help_text=_("Required. Add a valid username."),
)
first_name = forms.CharField(
required=True,
help_text=_("Required. Add a valid first name."),
)
last_name = forms.CharField(
required=True,
)
class UserCreationForm(BoostrapFormMixin, _UserCreationForm):
email = forms.EmailField(label=_("E-mail address"), required=True)
first_name = forms.CharField(label=_("First name"), required=True)
last_name = forms.CharField(label=_("Last name"), required=True)

class Meta:
model = CustomUser
fields = ("username", "email", "first_name", "last_name")

def __init__(self, *args, **kwargs):
super(CustomUserCreationForm, self).__init__(*args, **kwargs)
for field_name, field in self.fields.items():
field.widget.attrs["class"] = "form-control"

class AuthenticationForm(BoostrapFormMixin, _AuthenticationForm):
pass

class CustomAuthenticationForm(AuthenticationForm):
username = forms.CharField(label=_("Username"), help_text=_("Required. Enter your username."))
password = forms.CharField(label=_("Password"), help_text=_("Required. Enter your password."))

def __init__(self, *args, **kwargs):
super(CustomAuthenticationForm, self).__init__(*args, **kwargs)
for field in self.fields.values():
field.widget.attrs.update({"class": "form-control"})
class PasswordChangeForm(BoostrapFormMixin, _PasswordChangeForm):
pass


class PasswordResetForm(BoostrapFormMixin, _PasswordResetForm):
pass


class SetPasswordForm(BoostrapFormMixin, _SetPasswordForm):
pass
12 changes: 6 additions & 6 deletions app/accounts/tests/test_signup_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

from django.test import TestCase

from accounts.forms import CustomUserCreationForm
from accounts.forms import UserCreationForm


class CustomUserCreationFormTest(TestCase):
class UserCreationFormTest(TestCase):
def setUp(self):
self.username = "testuser"
self.email = "[email protected]"
Expand All @@ -15,7 +15,7 @@ def setUp(self):
self.password2 = "sadilar2024"

def test_valid_data(self):
form = CustomUserCreationForm(
form = UserCreationForm(
{
"username": self.username,
"email": self.email,
Expand All @@ -29,7 +29,7 @@ def test_valid_data(self):
self.assertTrue(form.is_valid())

def test_blank_data(self):
form = CustomUserCreationForm({})
form = UserCreationForm({})
self.assertFalse(form.is_valid())

self.assertEqual(
Expand All @@ -45,7 +45,7 @@ def test_blank_data(self):
)

def test_invalid_email(self):
form = CustomUserCreationForm(
form = UserCreationForm(
{
"username": self.username,
"email": "not a valid email",
Expand All @@ -64,7 +64,7 @@ def test_invalid_email(self):
)

def test_passwords_do_not_match(self):
form = CustomUserCreationForm(
form = UserCreationForm(
{
"username": self.username,
"email": self.email,
Expand Down
20 changes: 11 additions & 9 deletions app/accounts/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,31 @@

urlpatterns = [
path("register/", views.register, name="accounts_register"),
path("login/", auth_views.LoginView.as_view(template_name="accounts/login.html"), name="login"),
path("login/", views.LoginView.as_view(), name="login"),
path("logout/", auth_views.LogoutView.as_view(), name="logout"),
path(
"password_change/",
views.PasswordChangeView.as_view(),
name="password_change",
),
path(
"password_reset/",
auth_views.PasswordResetView.as_view(template_name="accounts/password_reset_form.html"),
views.PasswordResetView.as_view(),
name="password_reset",
),
path(
"password_reset/done/",
auth_views.PasswordResetDoneView.as_view(template_name="accounts/password_reset_done.html"),
auth_views.PasswordResetDoneView.as_view(),
name="password_reset_done",
),
path(
"reset/<uidb64>/<token>/",
auth_views.PasswordResetConfirmView.as_view(
template_name="accounts/password_reset_confirm.html"
),
views.PasswordResetConfirmView.as_view(),
name="password_reset_confirm",
),
path(
"reset/done/",
auth_views.PasswordResetCompleteView.as_view(
template_name="accounts/password_reset_complete.html"
),
auth_views.PasswordResetCompleteView.as_view(),
name="password_reset_complete",
),
]
51 changes: 37 additions & 14 deletions app/accounts/views.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,55 @@
from django.contrib.auth import authenticate
from django.contrib.auth import login as auth_login
from django.contrib.auth.views import LoginView as _LoginView
from django.contrib.auth.views import PasswordChangeView as _PasswordChangeView
from django.contrib.auth.views import (
PasswordResetConfirmView as _PasswordResetConfirmView,
)
from django.contrib.auth.views import PasswordResetView as _PasswordResetView
from django.shortcuts import redirect, render

from .forms import CustomAuthenticationForm, CustomUserCreationForm
from .forms import (
AuthenticationForm,
PasswordChangeForm,
PasswordResetForm,
SetPasswordForm,
UserCreationForm,
)


def register(request):
if request.method == "POST":
form = CustomUserCreationForm(request.POST)
form = UserCreationForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.is_staff = True
user.save()
auth_login(request, user)
return redirect("home")
else:
form = CustomUserCreationForm()
return render(request, "accounts/register.html", {"form": form})
form = UserCreationForm()
return render(request, "registration/register.html", {"form": form})


def user_login(request):
if request.method == "POST":
form = CustomAuthenticationForm(request, data=request.POST)
if form.is_valid():
user = form.get_user()
auth_login(request, user)
return redirect("home")
else:
form = CustomAuthenticationForm()
# We subclass the builtin views where we want to supply our own forms. We
# (mostly) stick to the expected template names, and they are therefore
# automatically picked up, even in views where we don't subclass the builtin
# views.
class LoginView(_LoginView):
form_class = AuthenticationForm


class PasswordChangeView(_PasswordChangeView):
form_class = PasswordChangeForm
# The builtin view expects password_change_form.html, but so does the admin
# interface, and we don't want to replace that one as well, so we use a
# custom name.
template_name = "registration/password_change_form2.html"


class PasswordResetView(_PasswordResetView):
form_class = PasswordResetForm


return render(request, "accounts/login.html", {"form": form})
class PasswordResetConfirmView(_PasswordResetConfirmView):
form_class = SetPasswordForm
1 change: 0 additions & 1 deletion app/app/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
path("search/", views.search, name="search"),
path("i18n/", include("django.conf.urls.i18n")),
path("accounts/", include("accounts.urls")),
path("accounts/", include("django.contrib.auth.urls")),
]

if settings.DEBUG:
Expand Down
76 changes: 0 additions & 76 deletions app/templates/accounts/login.html

This file was deleted.

50 changes: 0 additions & 50 deletions app/templates/accounts/password_reset_confirm.html

This file was deleted.

19 changes: 0 additions & 19 deletions app/templates/accounts/password_reset_done.html

This file was deleted.

Loading

0 comments on commit cbf8c96

Please sign in to comment.