core: remove redundant views/forms

This commit is contained in:
Jens Langhammer 2020-05-11 00:49:48 +02:00
parent 5b2bf7519a
commit 69120da45c
12 changed files with 43 additions and 138 deletions

View File

@ -19,7 +19,7 @@ class AdministrationOverviewView(AdminRequiredMixin, TemplateView):
"""Handle post (clear cache from modal)"""
if "clear" in self.request.POST:
cache.clear()
return redirect(reverse("passbook_core:auth-login"))
return redirect(reverse("passbook_flows:default-auth"))
return self.get(*args, **kwargs)
def get_context_data(self, **kwargs):

View File

@ -94,9 +94,10 @@ class UserPasswordResetView(LoginRequiredMixin, PermissionRequiredMixin, DetailV
def get(self, request, *args, **kwargs):
"""Create nonce for user and return link"""
super().get(request, *args, **kwargs)
# TODO: create plan for user, get token
nonce = Nonce.objects.create(user=self.object)
link = request.build_absolute_uri(
reverse("passbook_core:auth-password-reset", kwargs={"nonce": nonce.uuid})
reverse("passbook_flows:default-recovery", kwargs={"nonce": nonce.uuid})
)
messages.success(
request, _("Password reset link: <pre>%(link)s</pre>" % {"link": link})

View File

@ -1,8 +1,6 @@
"""passbook core user forms"""
from django import forms
from django.forms import ValidationError
from django.utils.translation import gettext_lazy as _
from passbook.core.models import User
@ -15,28 +13,3 @@ class UserDetailForm(forms.ModelForm):
model = User
fields = ["username", "name", "email"]
widgets = {"name": forms.TextInput}
class PasswordChangeForm(forms.Form):
"""Form to update password"""
password = forms.CharField(
label=_("Password"),
widget=forms.PasswordInput(
attrs={"placeholder": _("New Password"), "autocomplete": "new-password"}
),
)
password_repeat = forms.CharField(
label=_("Repeat Password"),
widget=forms.PasswordInput(
attrs={"placeholder": _("Repeat Password"), "autocomplete": "new-password"}
),
)
def clean_password_repeat(self):
"""Check if Password adheres to filter and if passwords matche"""
password = self.cleaned_data.get("password")
password_repeat = self.cleaned_data.get("password_repeat")
if password != password_repeat:
raise ValidationError(_("Passwords don't match"))
return self.cleaned_data.get("password_repeat")

View File

@ -208,9 +208,8 @@ class Invitation(ExportModelOperationsMixin("invitation"), UUIDModel):
@property
def link(self):
"""Get link to use invitation"""
return (
reverse_lazy("passbook_core:auth-sign-up") + f"?invitation={self.uuid.hex}"
)
qs = f"?invitation={self.uuid.hex}"
return reverse_lazy("passbook_flows:default-enrollment") + qs
def __str__(self):
return f"Invitation {self.uuid.hex} created by {self.created_by}"

View File

@ -37,7 +37,7 @@
{{ user.username }}
</div>
<div class="right">
<a href="{% url 'passbook_core:auth-login' %}">{% trans 'Not you?' %}</a>
<a href="{% url 'passbook_flows:default-auth' %}">{% trans 'Not you?' %}</a>
</div>
</div>
</div>

View File

@ -5,7 +5,6 @@ from random import SystemRandom
from django.shortcuts import reverse
from django.test import TestCase
from passbook.core.forms.users import PasswordChangeForm
from passbook.core.models import User
@ -37,21 +36,3 @@ class TestUserViews(TestCase):
)
self.assertEqual(User.objects.filter(username="unittest user").exists(), False)
self.setUp()
def test_user_change_password(self):
"""Test UserChangePasswordView"""
form_data = {"password": "test2", "password_repeat": "test2"}
form = PasswordChangeForm(data=form_data)
self.assertTrue(form.is_valid())
self.assertEqual(
self.client.get(reverse("passbook_core:user-change-password")).status_code,
200,
)
self.assertEqual(
self.client.post(
reverse("passbook_core:user-change-password"), data=form_data
).status_code,
302,
)
self.user.refresh_from_db()
self.assertTrue(self.user.check_password("test2"))

View File

@ -2,35 +2,13 @@
from django.urls import path
from passbook.core.views import authentication, overview, user
from passbook.flows.models import FlowDesignation
from passbook.flows.views import ToDefaultFlow
urlpatterns = [
# Authentication views
path(
"auth/login/",
ToDefaultFlow.as_view(designation=FlowDesignation.AUTHENTICATION),
name="auth-login",
),
path("auth/logout/", authentication.LogoutView.as_view(), name="auth-logout"),
path(
"auth/sign_up/",
ToDefaultFlow.as_view(designation=FlowDesignation.ENROLLMENT),
name="auth-sign-up",
),
path(
"auth/password/reset/<uuid:nonce_uuid>/",
authentication.PasswordResetView.as_view(),
name="auth-password-reset",
),
# User views
path("-/user/", user.UserSettingsView.as_view(), name="user-settings"),
path("-/user/delete/", user.UserDeleteView.as_view(), name="user-delete"),
path(
"-/user/change_password/",
user.UserChangePasswordView.as_view(),
name="user-change-password",
),
# Overview
path("", overview.OverviewView.as_view(), name="overview"),
]

View File

@ -1,15 +1,13 @@
"""passbook core authentication views"""
from django.contrib import messages
from django.contrib.auth import login, logout
from django.contrib.auth import logout
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpRequest, HttpResponse
from django.shortcuts import get_object_or_404, redirect, reverse
from django.shortcuts import redirect, reverse
from django.utils.translation import ugettext as _
from django.views import View
from structlog import get_logger
from passbook.core.models import Nonce
LOGGER = get_logger()
@ -20,21 +18,4 @@ class LogoutView(LoginRequiredMixin, View):
"""Log current user out"""
logout(request)
messages.success(request, _("You've successfully been logged out."))
return redirect(reverse("passbook_core:auth-login"))
class PasswordResetView(View):
"""Temporarily authenticate User and allow them to reset their password"""
def get(self, request: HttpRequest, nonce_uuid: str) -> HttpResponse:
"""Authenticate user with nonce and redirect to password change view"""
# 3. (Optional) Trap user in password change view
nonce = get_object_or_404(Nonce, uuid=nonce_uuid)
# Workaround: hardcoded reference to ModelBackend, needs testing
nonce.user.backend = "django.contrib.auth.backends.ModelBackend"
login(request, nonce.user)
nonce.delete()
messages.success(
request, _(("Temporarily authenticated, please change your password")),
)
return redirect("passbook_core:user-change-password")
return redirect(reverse("passbook_flows:default-auth"))

View File

@ -1,16 +1,14 @@
"""passbook core user views"""
from django.contrib import messages
from django.contrib.auth import logout, update_session_auth_hash
from django.contrib.auth import logout
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.forms.utils import ErrorList
from django.shortcuts import redirect, reverse
from django.shortcuts import reverse
from django.urls import reverse_lazy
from django.utils.translation import gettext as _
from django.views.generic import DeleteView, FormView, UpdateView
from django.views.generic import DeleteView, UpdateView
from passbook.core.forms.users import PasswordChangeForm, UserDetailForm
from passbook.lib.config import CONFIG
from passbook.core.forms.users import UserDetailForm
class UserSettingsView(SuccessMessageMixin, LoginRequiredMixin, UpdateView):
@ -37,35 +35,4 @@ class UserDeleteView(LoginRequiredMixin, DeleteView):
def get_success_url(self):
messages.success(self.request, _("Successfully deleted user."))
logout(self.request)
return reverse("passbook_core:auth-login")
class UserChangePasswordView(LoginRequiredMixin, FormView):
"""View for users to update their password"""
form_class = PasswordChangeForm
template_name = "login/form_with_user.html"
def form_valid(self, form: PasswordChangeForm):
# TODO: Rewrite to flow
try:
# user.set_password checks against Policies so we don't need to manually do it here
self.request.user.set_password(form.cleaned_data.get("password"))
self.request.user.save()
update_session_auth_hash(self.request, self.request.user)
messages.success(self.request, _("Successfully changed password"))
except ValueError:
# Manually inject error into form
# pylint: disable=protected-access
errors = form._errors.setdefault("password_repeat", ErrorList(""))
# pylint: disable=protected-access
errors = form._errors.setdefault("password", ErrorList())
errors.append("foo")
return self.form_invalid(form)
return redirect("passbook_core:overview")
def get_context_data(self, **kwargs):
kwargs["config"] = CONFIG.y("passbook")
kwargs["title"] = _("Change Password")
kwargs["primary_action"] = _("Change")
return super().get_context_data(**kwargs)
return reverse("passbook_flows:default-auth")

View File

@ -1,9 +1,34 @@
"""flow urls"""
from django.urls import path
from passbook.flows.views import FlowExecutorView, FlowPermissionDeniedView
from passbook.flows.models import FlowDesignation
from passbook.flows.views import (
FlowExecutorView,
FlowPermissionDeniedView,
ToDefaultFlow,
)
urlpatterns = [
path("denied/", FlowPermissionDeniedView.as_view(), name="denied"),
path("-/denied/", FlowPermissionDeniedView.as_view(), name="denied"),
path(
"-/default/auth/",
ToDefaultFlow.as_view(designation=FlowDesignation.AUTHENTICATION),
name="default-auth",
),
path(
"-/default/recovery/",
ToDefaultFlow.as_view(designation=FlowDesignation.RECOVERY),
name="default-recovery",
),
path(
"-/default/enrollment/",
ToDefaultFlow.as_view(designation=FlowDesignation.ENROLLMENT),
name="default-enrollment",
),
path(
"-/default/password_change/",
ToDefaultFlow.as_view(designation=FlowDesignation.PASSWORD_CHANGE),
name="default-password-change",
),
path("<slug:flow_slug>/", FlowExecutorView.as_view(), name="flow-executor"),
]

View File

@ -44,7 +44,7 @@ INTERNAL_IPS = ["127.0.0.1"]
ALLOWED_HOSTS = ["*"]
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
LOGIN_URL = "passbook_core:auth-login"
LOGIN_URL = "passbook_flows:default-auth"
# CSRF_FAILURE_VIEW = 'passbook.core.views.errors.CSRFErrorView.as_view'
# Custom user model

View File

@ -11,7 +11,7 @@ from passbook.root.monitoring import MetricsView
LOGGER = get_logger()
admin.autodiscover()
admin.site.login = RedirectView.as_view(pattern_name="passbook_core:auth-login")
admin.site.login = RedirectView.as_view(pattern_name="passbook_flows:default-auth")
handler400 = error.BadRequestView.as_view()
handler403 = error.ForbiddenView.as_view()