stages/user_create -> user_write: Stage can create and update existing users
This commit is contained in:
parent
631cf77f89
commit
5b2bf7519a
|
@ -37,8 +37,8 @@ from passbook.stages.identification.api import IdentificationStageViewSet
|
||||||
from passbook.stages.otp.api import OTPStageViewSet
|
from passbook.stages.otp.api import OTPStageViewSet
|
||||||
from passbook.stages.password.api import PasswordStageViewSet
|
from passbook.stages.password.api import PasswordStageViewSet
|
||||||
from passbook.stages.prompt.api import PromptStageViewSet, PromptViewSet
|
from passbook.stages.prompt.api import PromptStageViewSet, PromptViewSet
|
||||||
from passbook.stages.user_create.api import UserCreateStageViewSet
|
|
||||||
from passbook.stages.user_login.api import UserLoginStageViewSet
|
from passbook.stages.user_login.api import UserLoginStageViewSet
|
||||||
|
from passbook.stages.user_write.api import UserWriteStageViewSet
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
router = routers.DefaultRouter()
|
router = routers.DefaultRouter()
|
||||||
|
@ -86,7 +86,7 @@ router.register("stages/otp", OTPStageViewSet)
|
||||||
router.register("stages/password", PasswordStageViewSet)
|
router.register("stages/password", PasswordStageViewSet)
|
||||||
router.register("stages/prompt", PromptStageViewSet)
|
router.register("stages/prompt", PromptStageViewSet)
|
||||||
router.register("stages/prompt/prompts", PromptViewSet)
|
router.register("stages/prompt/prompts", PromptViewSet)
|
||||||
router.register("stages/user_create", UserCreateStageViewSet)
|
router.register("stages/user_write", UserWriteStageViewSet)
|
||||||
router.register("stages/user_login", UserLoginStageViewSet)
|
router.register("stages/user_login", UserLoginStageViewSet)
|
||||||
|
|
||||||
router.register("flows", FlowViewSet)
|
router.register("flows", FlowViewSet)
|
||||||
|
|
|
@ -37,22 +37,19 @@ def create_default_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
|
||||||
if not UserLoginStage.objects.using(db_alias).exists():
|
if not UserLoginStage.objects.using(db_alias).exists():
|
||||||
UserLoginStage.objects.using(db_alias).create(name="authentication")
|
UserLoginStage.objects.using(db_alias).create(name="authentication")
|
||||||
|
|
||||||
ident_stage = IdentificationStage.objects.using(db_alias).first()
|
|
||||||
pw_stage = PasswordStage.objects.using(db_alias).first()
|
|
||||||
login_stage = UserLoginStage.objects.using(db_alias).first()
|
|
||||||
flow = Flow.objects.using(db_alias).create(
|
flow = Flow.objects.using(db_alias).create(
|
||||||
name="default-authentication-flow",
|
name="default-authentication-flow",
|
||||||
slug="default-authentication-flow",
|
slug="default-authentication-flow",
|
||||||
designation=FlowDesignation.AUTHENTICATION,
|
designation=FlowDesignation.AUTHENTICATION,
|
||||||
)
|
)
|
||||||
FlowStageBinding.objects.using(db_alias).create(
|
FlowStageBinding.objects.using(db_alias).create(
|
||||||
flow=flow, stage=ident_stage, order=0,
|
flow=flow, stage=IdentificationStage.objects.using(db_alias).first(), order=0,
|
||||||
)
|
)
|
||||||
FlowStageBinding.objects.using(db_alias).create(
|
FlowStageBinding.objects.using(db_alias).create(
|
||||||
flow=flow, stage=pw_stage, order=1,
|
flow=flow, stage=PasswordStage.objects.using(db_alias).first(), order=1,
|
||||||
)
|
)
|
||||||
FlowStageBinding.objects.using(db_alias).create(
|
FlowStageBinding.objects.using(db_alias).create(
|
||||||
flow=flow, stage=login_stage, order=2,
|
flow=flow, stage=UserLoginStage.objects.using(db_alias).first(), order=2,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -108,8 +108,8 @@ INSTALLED_APPS = [
|
||||||
"passbook.stages.email.apps.PassbookStageEmailConfig",
|
"passbook.stages.email.apps.PassbookStageEmailConfig",
|
||||||
"passbook.stages.prompt.apps.PassbookStagPromptConfig",
|
"passbook.stages.prompt.apps.PassbookStagPromptConfig",
|
||||||
"passbook.stages.identification.apps.PassbookStageIdentificationConfig",
|
"passbook.stages.identification.apps.PassbookStageIdentificationConfig",
|
||||||
"passbook.stages.user_create.apps.PassbookStageUserCreateConfig",
|
|
||||||
"passbook.stages.user_login.apps.PassbookStageUserLoginConfig",
|
"passbook.stages.user_login.apps.PassbookStageUserLoginConfig",
|
||||||
|
"passbook.stages.user_write.apps.PassbookStageUserWriteConfig",
|
||||||
"passbook.stages.otp.apps.PassbookStageOTPConfig",
|
"passbook.stages.otp.apps.PassbookStageOTPConfig",
|
||||||
"passbook.stages.password.apps.PassbookStagePasswordConfig",
|
"passbook.stages.password.apps.PassbookStagePasswordConfig",
|
||||||
"passbook.static.apps.PassbookStaticConfig",
|
"passbook.static.apps.PassbookStaticConfig",
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
"""User Create Stage API Views"""
|
|
||||||
from rest_framework.serializers import ModelSerializer
|
|
||||||
from rest_framework.viewsets import ModelViewSet
|
|
||||||
|
|
||||||
from passbook.stages.user_create.models import UserCreateStage
|
|
||||||
|
|
||||||
|
|
||||||
class UserCreateStageSerializer(ModelSerializer):
|
|
||||||
"""UserCreateStage Serializer"""
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
|
|
||||||
model = UserCreateStage
|
|
||||||
fields = [
|
|
||||||
"pk",
|
|
||||||
"name",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class UserCreateStageViewSet(ModelViewSet):
|
|
||||||
"""UserCreateStage Viewset"""
|
|
||||||
|
|
||||||
queryset = UserCreateStage.objects.all()
|
|
||||||
serializer_class = UserCreateStageSerializer
|
|
|
@ -1,10 +0,0 @@
|
||||||
"""passbook create stage app config"""
|
|
||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class PassbookStageUserCreateConfig(AppConfig):
|
|
||||||
"""passbook create stage config"""
|
|
||||||
|
|
||||||
name = "passbook.stages.user_create"
|
|
||||||
label = "passbook_stages_user_create"
|
|
||||||
verbose_name = "passbook Stages.User Create"
|
|
|
@ -1,16 +0,0 @@
|
||||||
"""passbook flows create forms"""
|
|
||||||
from django import forms
|
|
||||||
|
|
||||||
from passbook.stages.user_create.models import UserCreateStage
|
|
||||||
|
|
||||||
|
|
||||||
class UserCreateStageForm(forms.ModelForm):
|
|
||||||
"""Form to create/edit UserCreateStage instances"""
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
|
|
||||||
model = UserCreateStage
|
|
||||||
fields = ["name"]
|
|
||||||
widgets = {
|
|
||||||
"name": forms.TextInput(),
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
"""create stage models"""
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
from passbook.flows.models import Stage
|
|
||||||
|
|
||||||
|
|
||||||
class UserCreateStage(Stage):
|
|
||||||
"""Create stage, create a user from saved data."""
|
|
||||||
|
|
||||||
type = "passbook.stages.user_create.stage.UserCreateStageView"
|
|
||||||
form = "passbook.stages.user_create.forms.UserCreateStageForm"
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"User Create Stage {self.name}"
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
|
|
||||||
verbose_name = _("User Create Stage")
|
|
||||||
verbose_name_plural = _("User Create Stages")
|
|
|
@ -1,39 +0,0 @@
|
||||||
"""Create stage logic"""
|
|
||||||
from django.contrib import messages
|
|
||||||
from django.contrib.auth.backends import ModelBackend
|
|
||||||
from django.http import HttpRequest, HttpResponse
|
|
||||||
from django.utils.translation import gettext as _
|
|
||||||
from structlog import get_logger
|
|
||||||
|
|
||||||
from passbook.core.models import User
|
|
||||||
from passbook.flows.planner import PLAN_CONTEXT_PENDING_USER
|
|
||||||
from passbook.flows.stage import AuthenticationStage
|
|
||||||
from passbook.lib.utils.reflection import class_to_path
|
|
||||||
from passbook.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
|
|
||||||
from passbook.stages.prompt.stage import PLAN_CONTEXT_PROMPT
|
|
||||||
|
|
||||||
LOGGER = get_logger()
|
|
||||||
|
|
||||||
|
|
||||||
class UserCreateStageView(AuthenticationStage):
|
|
||||||
"""Finalise Enrollment flow by creating a user object."""
|
|
||||||
|
|
||||||
def get(self, request: HttpRequest) -> HttpResponse:
|
|
||||||
if PLAN_CONTEXT_PROMPT not in self.executor.plan.context:
|
|
||||||
message = _("No Pending data.")
|
|
||||||
messages.error(request, message)
|
|
||||||
LOGGER.debug(message)
|
|
||||||
return self.executor.stage_invalid()
|
|
||||||
data = self.executor.plan.context[PLAN_CONTEXT_PROMPT]
|
|
||||||
user = User.objects.create_user(**data)
|
|
||||||
# Set created user as pending_user, so this can be chained with user_login
|
|
||||||
self.executor.plan.context[PLAN_CONTEXT_PENDING_USER] = user
|
|
||||||
self.executor.plan.context[PLAN_CONTEXT_AUTHENTICATION_BACKEND] = class_to_path(
|
|
||||||
ModelBackend
|
|
||||||
)
|
|
||||||
LOGGER.debug(
|
|
||||||
"Created user",
|
|
||||||
user=self.executor.plan.context[PLAN_CONTEXT_PENDING_USER],
|
|
||||||
flow_slug=self.executor.flow.slug,
|
|
||||||
)
|
|
||||||
return self.executor.stage_ok()
|
|
|
@ -1,73 +0,0 @@
|
||||||
"""create tests"""
|
|
||||||
import string
|
|
||||||
from random import SystemRandom
|
|
||||||
|
|
||||||
from django.shortcuts import reverse
|
|
||||||
from django.test import Client, TestCase
|
|
||||||
|
|
||||||
from passbook.core.models import User
|
|
||||||
from passbook.flows.models import Flow, FlowDesignation, FlowStageBinding
|
|
||||||
from passbook.flows.planner import FlowPlan
|
|
||||||
from passbook.flows.views import SESSION_KEY_PLAN
|
|
||||||
from passbook.stages.prompt.stage import PLAN_CONTEXT_PROMPT
|
|
||||||
from passbook.stages.user_create.models import UserCreateStage
|
|
||||||
|
|
||||||
|
|
||||||
class TestUserCreateStage(TestCase):
|
|
||||||
"""Create tests"""
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super().setUp()
|
|
||||||
self.client = Client()
|
|
||||||
|
|
||||||
self.password = "".join(
|
|
||||||
SystemRandom().choice(string.ascii_uppercase + string.digits)
|
|
||||||
for _ in range(8)
|
|
||||||
)
|
|
||||||
self.flow = Flow.objects.create(
|
|
||||||
name="test-create",
|
|
||||||
slug="test-create",
|
|
||||||
designation=FlowDesignation.AUTHENTICATION,
|
|
||||||
)
|
|
||||||
self.stage = UserCreateStage.objects.create(name="create")
|
|
||||||
FlowStageBinding.objects.create(flow=self.flow, stage=self.stage, order=2)
|
|
||||||
|
|
||||||
def test_valid_create(self):
|
|
||||||
"""Test creation of user"""
|
|
||||||
plan = FlowPlan(flow_pk=self.flow.pk.hex, stages=[self.stage])
|
|
||||||
plan.context[PLAN_CONTEXT_PROMPT] = {
|
|
||||||
"username": "test-user",
|
|
||||||
"name": "name",
|
|
||||||
"email": "test@beryju.org",
|
|
||||||
"password": self.password,
|
|
||||||
}
|
|
||||||
session = self.client.session
|
|
||||||
session[SESSION_KEY_PLAN] = plan
|
|
||||||
session.save()
|
|
||||||
|
|
||||||
response = self.client.get(
|
|
||||||
reverse(
|
|
||||||
"passbook_flows:flow-executor", kwargs={"flow_slug": self.flow.slug}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.assertEqual(response.status_code, 302)
|
|
||||||
self.assertTrue(
|
|
||||||
User.objects.filter(
|
|
||||||
username=plan.context[PLAN_CONTEXT_PROMPT]["username"]
|
|
||||||
).exists()
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_without_data(self):
|
|
||||||
"""Test without data results in error"""
|
|
||||||
plan = FlowPlan(flow_pk=self.flow.pk.hex, stages=[self.stage])
|
|
||||||
session = self.client.session
|
|
||||||
session[SESSION_KEY_PLAN] = plan
|
|
||||||
session.save()
|
|
||||||
|
|
||||||
response = self.client.get(
|
|
||||||
reverse(
|
|
||||||
"passbook_flows:flow-executor", kwargs={"flow_slug": self.flow.slug}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.assertEqual(response.status_code, 302)
|
|
||||||
self.assertEqual(response.url, reverse("passbook_flows:denied"))
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
"""User Write Stage API Views"""
|
||||||
|
from rest_framework.serializers import ModelSerializer
|
||||||
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
|
from passbook.stages.user_write.models import UserWriteStage
|
||||||
|
|
||||||
|
|
||||||
|
class UserWriteStageSerializer(ModelSerializer):
|
||||||
|
"""UserWriteStage Serializer"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
model = UserWriteStage
|
||||||
|
fields = [
|
||||||
|
"pk",
|
||||||
|
"name",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class UserWriteStageViewSet(ModelViewSet):
|
||||||
|
"""UserWriteStage Viewset"""
|
||||||
|
|
||||||
|
queryset = UserWriteStage.objects.all()
|
||||||
|
serializer_class = UserWriteStageSerializer
|
|
@ -0,0 +1,10 @@
|
||||||
|
"""passbook write stage app config"""
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class PassbookStageUserWriteConfig(AppConfig):
|
||||||
|
"""passbook write stage config"""
|
||||||
|
|
||||||
|
name = "passbook.stages.user_write"
|
||||||
|
label = "passbook_stages_user_write"
|
||||||
|
verbose_name = "passbook Stages.User Write"
|
|
@ -0,0 +1,16 @@
|
||||||
|
"""passbook flows write forms"""
|
||||||
|
from django import forms
|
||||||
|
|
||||||
|
from passbook.stages.user_write.models import UserWriteStage
|
||||||
|
|
||||||
|
|
||||||
|
class UserWriteStageForm(forms.ModelForm):
|
||||||
|
"""Form to write/edit UserWriteStage instances"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
model = UserWriteStage
|
||||||
|
fields = ["name"]
|
||||||
|
widgets = {
|
||||||
|
"name": forms.TextInput(),
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 3.0.5 on 2020-05-10 14:26
|
# Generated by Django 3.0.5 on 2020-05-10 21:21
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
@ -14,7 +14,7 @@ class Migration(migrations.Migration):
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="UserCreateStage",
|
name="UserWriteStage",
|
||||||
fields=[
|
fields=[
|
||||||
(
|
(
|
||||||
"stage_ptr",
|
"stage_ptr",
|
||||||
|
@ -29,8 +29,8 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
"verbose_name": "User Create Stage",
|
"verbose_name": "User Write Stage",
|
||||||
"verbose_name_plural": "User Create Stages",
|
"verbose_name_plural": "User Write Stages",
|
||||||
},
|
},
|
||||||
bases=("passbook_flows.stage",),
|
bases=("passbook_flows.stage",),
|
||||||
),
|
),
|
|
@ -0,0 +1,19 @@
|
||||||
|
"""write stage models"""
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from passbook.flows.models import Stage
|
||||||
|
|
||||||
|
|
||||||
|
class UserWriteStage(Stage):
|
||||||
|
"""Write stage, write a user from saved data."""
|
||||||
|
|
||||||
|
type = "passbook.stages.user_write.stage.UserWriteStageView"
|
||||||
|
form = "passbook.stages.user_write.forms.UserWriteStageForm"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"User Write Stage {self.name}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
verbose_name = _("User Write Stage")
|
||||||
|
verbose_name_plural = _("User Write Stages")
|
|
@ -0,0 +1,52 @@
|
||||||
|
"""Write stage logic"""
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.backends import ModelBackend
|
||||||
|
from django.http import HttpRequest, HttpResponse
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
|
from structlog import get_logger
|
||||||
|
|
||||||
|
from passbook.core.models import User
|
||||||
|
from passbook.flows.planner import PLAN_CONTEXT_PENDING_USER
|
||||||
|
from passbook.flows.stage import AuthenticationStage
|
||||||
|
from passbook.lib.utils.reflection import class_to_path
|
||||||
|
from passbook.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
|
||||||
|
from passbook.stages.prompt.stage import PLAN_CONTEXT_PROMPT
|
||||||
|
|
||||||
|
LOGGER = get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class UserWriteStageView(AuthenticationStage):
|
||||||
|
"""Finalise Enrollment flow by creating a user object."""
|
||||||
|
|
||||||
|
def get(self, request: HttpRequest) -> HttpResponse:
|
||||||
|
if PLAN_CONTEXT_PROMPT not in self.executor.plan.context:
|
||||||
|
message = _("No Pending data.")
|
||||||
|
messages.error(request, message)
|
||||||
|
LOGGER.debug(message)
|
||||||
|
return self.executor.stage_invalid()
|
||||||
|
data = self.executor.plan.context[PLAN_CONTEXT_PROMPT]
|
||||||
|
if PLAN_CONTEXT_PENDING_USER in self.executor.plan.context:
|
||||||
|
user = self.executor.plan.context[PLAN_CONTEXT_PENDING_USER]
|
||||||
|
for key, value in data.items():
|
||||||
|
setter_name = f"set_{key}"
|
||||||
|
if hasattr(user, setter_name):
|
||||||
|
setter = getattr(user, setter_name)
|
||||||
|
if callable(setter):
|
||||||
|
setter(value)
|
||||||
|
else:
|
||||||
|
setattr(user, key, value)
|
||||||
|
user.save()
|
||||||
|
LOGGER.debug(
|
||||||
|
"Updated existing user", user=user, flow_slug=self.executor.flow.slug,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
user = User.objects.create_user(**data)
|
||||||
|
# Set created user as pending_user, so this can be chained with user_login
|
||||||
|
self.executor.plan.context[PLAN_CONTEXT_PENDING_USER] = user
|
||||||
|
self.executor.plan.context[
|
||||||
|
PLAN_CONTEXT_AUTHENTICATION_BACKEND
|
||||||
|
] = class_to_path(ModelBackend)
|
||||||
|
LOGGER.debug(
|
||||||
|
"Created new user", user=user, flow_slug=self.executor.flow.slug,
|
||||||
|
)
|
||||||
|
return self.executor.stage_ok()
|
|
@ -0,0 +1,110 @@
|
||||||
|
"""write tests"""
|
||||||
|
import string
|
||||||
|
from random import SystemRandom
|
||||||
|
|
||||||
|
from django.shortcuts import reverse
|
||||||
|
from django.test import Client, TestCase
|
||||||
|
|
||||||
|
from passbook.core.models import User
|
||||||
|
from passbook.flows.models import Flow, FlowDesignation, FlowStageBinding
|
||||||
|
from passbook.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlan
|
||||||
|
from passbook.flows.views import SESSION_KEY_PLAN
|
||||||
|
from passbook.stages.prompt.stage import PLAN_CONTEXT_PROMPT
|
||||||
|
from passbook.stages.user_write.forms import UserWriteStageForm
|
||||||
|
from passbook.stages.user_write.models import UserWriteStage
|
||||||
|
|
||||||
|
|
||||||
|
class TestUserWriteStage(TestCase):
|
||||||
|
"""Write tests"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.client = Client()
|
||||||
|
|
||||||
|
self.flow = Flow.objects.create(
|
||||||
|
name="test-write",
|
||||||
|
slug="test-write",
|
||||||
|
designation=FlowDesignation.AUTHENTICATION,
|
||||||
|
)
|
||||||
|
self.stage = UserWriteStage.objects.create(name="write")
|
||||||
|
FlowStageBinding.objects.create(flow=self.flow, stage=self.stage, order=2)
|
||||||
|
|
||||||
|
def test_user_create(self):
|
||||||
|
"""Test creation of user"""
|
||||||
|
password = "".join(
|
||||||
|
SystemRandom().choice(string.ascii_uppercase + string.digits)
|
||||||
|
for _ in range(8)
|
||||||
|
)
|
||||||
|
|
||||||
|
plan = FlowPlan(flow_pk=self.flow.pk.hex, stages=[self.stage])
|
||||||
|
plan.context[PLAN_CONTEXT_PROMPT] = {
|
||||||
|
"username": "test-user",
|
||||||
|
"name": "name",
|
||||||
|
"email": "test@beryju.org",
|
||||||
|
"password": password,
|
||||||
|
}
|
||||||
|
session = self.client.session
|
||||||
|
session[SESSION_KEY_PLAN] = plan
|
||||||
|
session.save()
|
||||||
|
|
||||||
|
response = self.client.get(
|
||||||
|
reverse(
|
||||||
|
"passbook_flows:flow-executor", kwargs={"flow_slug": self.flow.slug}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
user_qs = User.objects.filter(
|
||||||
|
username=plan.context[PLAN_CONTEXT_PROMPT]["username"]
|
||||||
|
)
|
||||||
|
self.assertTrue(user_qs.exists())
|
||||||
|
self.assertTrue(user_qs.first().check_password(password))
|
||||||
|
|
||||||
|
def test_user_update(self):
|
||||||
|
"""Test update of existing user"""
|
||||||
|
new_password = "".join(
|
||||||
|
SystemRandom().choice(string.ascii_uppercase + string.digits)
|
||||||
|
for _ in range(8)
|
||||||
|
)
|
||||||
|
plan = FlowPlan(flow_pk=self.flow.pk.hex, stages=[self.stage])
|
||||||
|
plan.context[PLAN_CONTEXT_PENDING_USER] = User.objects.create(
|
||||||
|
username="unittest", email="test@beryju.org"
|
||||||
|
)
|
||||||
|
plan.context[PLAN_CONTEXT_PROMPT] = {
|
||||||
|
"username": "test-user-new",
|
||||||
|
"password": new_password,
|
||||||
|
}
|
||||||
|
session = self.client.session
|
||||||
|
session[SESSION_KEY_PLAN] = plan
|
||||||
|
session.save()
|
||||||
|
|
||||||
|
response = self.client.get(
|
||||||
|
reverse(
|
||||||
|
"passbook_flows:flow-executor", kwargs={"flow_slug": self.flow.slug}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
user_qs = User.objects.filter(
|
||||||
|
username=plan.context[PLAN_CONTEXT_PROMPT]["username"]
|
||||||
|
)
|
||||||
|
self.assertTrue(user_qs.exists())
|
||||||
|
self.assertTrue(user_qs.first().check_password(new_password))
|
||||||
|
|
||||||
|
def test_without_data(self):
|
||||||
|
"""Test without data results in error"""
|
||||||
|
plan = FlowPlan(flow_pk=self.flow.pk.hex, stages=[self.stage])
|
||||||
|
session = self.client.session
|
||||||
|
session[SESSION_KEY_PLAN] = plan
|
||||||
|
session.save()
|
||||||
|
|
||||||
|
response = self.client.get(
|
||||||
|
reverse(
|
||||||
|
"passbook_flows:flow-executor", kwargs={"flow_slug": self.flow.slug}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
self.assertEqual(response.url, reverse("passbook_flows:denied"))
|
||||||
|
|
||||||
|
def test_form(self):
|
||||||
|
"""Test Form"""
|
||||||
|
data = {"name": "test"}
|
||||||
|
self.assertEqual(UserWriteStageForm(data).is_valid(), True)
|
Reference in New Issue