Onboarding workflow

This commit is contained in:
Johannes Schriewer 2025-01-11 03:26:25 +01:00
parent 52b2eb2529
commit 084d35fdf4
8 changed files with 246 additions and 6 deletions

View file

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: 1.0\n" "Project-Id-Version: 1.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-01-07 23:07+0100\n" "POT-Creation-Date: 2025-01-11 03:20+0100\n"
"PO-Revision-Date: 2025-01-07 23:00+0100\n" "PO-Revision-Date: 2025-01-07 23:00+0100\n"
"Last-Translator: Johannes Schriewer <hallo@dunkelstern.de>\n" "Last-Translator: Johannes Schriewer <hallo@dunkelstern.de>\n"
"Language: German\n" "Language: German\n"
@ -467,6 +467,62 @@ msgstr "Inventarverwaltung"
msgid "Create new manufacturer..." msgid "Create new manufacturer..."
msgstr "Neuen Hersteller anlegen..." msgstr "Neuen Hersteller anlegen..."
#: .\inventory\templates\inventory\onboarding.html:5
#: .\inventory\templates\inventory\onboarding.html:8
#: .\inventory\templates\inventory\onboarding_success.html:5
#: .\inventory\templates\inventory\onboarding_success.html:8
msgid "Inventory Setup"
msgstr "Inventarverwaltung Setup"
#: .\inventory\templates\inventory\onboarding.html:12
msgid "Welcome to the Inventory Management setup"
msgstr "Willkommen zur Einrichtung der Inventarverwaltung"
#: .\inventory\templates\inventory\onboarding.html:15
msgid ""
"\n"
" Currently no admin user is defined in the database.\n"
" To use the inventory management system you need at least one admin "
"user...\n"
" "
msgstr ""
"\n"
" Aktuell ist kein Admin Benutzer in der Datenbank angelegt.\n"
" Um die Inventarverwaltung nutzen zu können muss mindestens\n"
" ein Administrator angelegt werden...\n"
" "
#: .\inventory\templates\inventory\onboarding.html:22
msgid ""
"\n"
" Please verify that the following settings are correct and then fill "
"out the\n"
" form at the end and click\n"
" "
msgstr ""
" Bitte überprüfe die folgenden Einstellungen und klicke dann auf\n"
" "
#: .\inventory\templates\inventory\onboarding.html:26
#: .\inventory\templates\inventory\onboarding.html:38
#: .\inventory\templates\inventory\onboarding.html:51
msgid "Create user"
msgstr "Benutzer anlegen"
#: .\inventory\templates\inventory\onboarding.html:29
msgid "Current settings"
msgstr "Aktuelle Einstellungen"
#: .\inventory\templates\inventory\onboarding.html:42
msgid ""
"\n"
" Please correct the errors below.\n"
" "
msgstr ""
"\n"
" Bitte die unten angezeigten Fehler korrigieren.\n"
" "
#: .\inventory\templates\inventory\pagination.html:6 #: .\inventory\templates\inventory\pagination.html:6
#: .\inventory\templates\inventory\search_result.html:33 #: .\inventory\templates\inventory\search_result.html:33
msgid "First page" msgid "First page"
@ -552,10 +608,22 @@ msgstr ""
msgid "Lost password?" msgid "Lost password?"
msgstr "Passwort vergessen?" msgstr "Passwort vergessen?"
#: .\inventory_project\settings.py:121 #: .\inventory\views\onboarding.py:14
msgid "Username"
msgstr "Benutzername"
#: .\inventory\views\onboarding.py:15
msgid "Email"
msgstr "E-Mail"
#: .\inventory\views\onboarding.py:16
msgid "Password"
msgstr "Passwort"
#: .\inventory_project\settings.py:130
msgid "German" msgid "German"
msgstr "Deutsch" msgstr "Deutsch"
#: .\inventory_project\settings.py:122 #: .\inventory_project\settings.py:131
msgid "English" msgid "English"
msgstr "Englisch" msgstr "Englisch"

View file

@ -335,4 +335,14 @@ div.warning-icon {
background-color: #c00000; background-color: #c00000;
-webkit-mask: url(/static/inventory/img/warn.svg) no-repeat center; -webkit-mask: url(/static/inventory/img/warn.svg) no-repeat center;
mask: url(/static/inventory/img/warn.svg) no-repeat center; mask: url(/static/inventory/img/warn.svg) no-repeat center;
}
form label {
display: inline-block;
width: 100px;
}
dt {
font-weight: bold;
font-family: 'Courier New', Courier, monospace;
} }

View file

@ -0,0 +1,53 @@
{% extends "base.html" %}
{% load static %}
{% load i18n %}
{% block title %}{% translate 'Inventory Setup' %}{% endblock %}
{% block header_bar %}
{% translate 'Inventory Setup' %}
{% endblock %}
{% block content %}
<h2>{% translate 'Welcome to the Inventory Management setup' %}</h2>
<p>
{% blocktranslate %}
Currently no admin user is defined in the database.
To use the inventory management system you need at least one admin user...
{% endblocktranslate %}
</p>
<p>
{% blocktranslate %}
Please verify that the following settings are correct and then fill out the
form at the end and click
{% endblocktranslate %}
<em>{% translate 'Create user' %}</em>
</p>
<h2>{% translate 'Current settings' %}</h2>
<dl>
{% for key, value in settings.items %}
<dt>{{ key }}</dt>
<dd>{{ value }}</dd>
{% endfor %}
</dl>
<h2>{% translate 'Create user' %}</h2>
{% if form.errors %}
<p>
{% blocktranslate %}
Please correct the errors below.
{% endblocktranslate %}
</p>
{% endif %}
<form action="{% url 'onboarding' %}" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="{% translate 'Create user' %}">
</form>
{% endblock %}

View file

@ -0,0 +1,35 @@
{% extends "base.html" %}
{% load static %}
{% load i18n %}
{% block title %}{% translate 'Inventory Setup' %}{% endblock %}
{% block header_bar %}
{% translate 'Inventory Setup' %}
{% endblock %}
{% block content %}
<h2>Onboarding completed!</h2>
<p>Congratulations, you have successfully setup the Inventory management system</p>
<p>You may now log in with the password you just set up.</p>
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<table>
<tr>
<td>{{ form.username.label_tag }}</td>
<td>{{ form.username }}</td>
</tr>
<tr>
<td>{{ form.password.label_tag }}</td>
<td>{{ form.password }}</td>
</tr>
</table>
<input type="submit" value="login">
<input type="hidden" name="next" value="{{ next }}">
</form>
{% endblock %}

View file

@ -34,7 +34,8 @@ from .views import (
ManufacturerView, ManufacturerView,
IndexView, IndexView,
TagView, TagView,
SearchView SearchView,
OnboardingView
) )
urlpatterns = [ urlpatterns = [
@ -54,5 +55,6 @@ urlpatterns = [
path('tags', TagListView.as_view(), name='tag-list'), path('tags', TagListView.as_view(), name='tag-list'),
path('tag/<int:pk>', TagView.as_view(), name='tag-detail'), path('tag/<int:pk>', TagView.as_view(), name='tag-detail'),
path('search', SearchView.as_view(), name='search'), path('search', SearchView.as_view(), name='search'),
path('onboarding', OnboardingView.as_view(), name='onboarding'),
path('', IndexView.as_view(), name='index') path('', IndexView.as_view(), name='index')
] ]

View file

@ -7,6 +7,7 @@ from .workshop import WorkshopView, WorkshopListView
from .index import IndexView from .index import IndexView
from .tag import TagListView, TagView from .tag import TagListView, TagView
from .search import SearchView from .search import SearchView
from .onboarding import OnboardingView
__all__ = [ __all__ = [
AreaView, AreaListView, AreaView, AreaListView,
@ -17,5 +18,6 @@ __all__ = [
WorkshopView, WorkshopListView, WorkshopView, WorkshopListView,
IndexView, IndexView,
TagView, TagListView, TagView, TagListView,
SearchView SearchView,
OnboardingView
] ]

View file

@ -3,14 +3,24 @@ from django.shortcuts import redirect
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.views.generic import View from django.views.generic import View
from django.contrib.auth import get_user_model
from django.contrib.auth.views import redirect_to_login
from inventory.models import Settings from inventory.models import Settings
@method_decorator(login_required, name='dispatch') @method_decorator(login_required, name='post')
class IndexView(View): class IndexView(View):
def get(self, request): def get(self, request):
User = get_user_model()
if User.objects.all().count() == 0:
# redirect to onboarding
return redirect(reverse('onboarding'))
if not request.user.is_authenticated:
path = request.get_full_path()
return redirect_to_login(path, reverse('login'))
# check settings for correct starred index page
settings = Settings.objects.first() settings = Settings.objects.first()
if settings.default_container is not None: if settings.default_container is not None:
return redirect(settings.default_container.url) return redirect(settings.default_container.url)

View file

@ -0,0 +1,60 @@
from django.utils.translation import gettext_lazy as _
from django.urls import reverse
from django.template.response import TemplateResponse
from django.shortcuts import redirect
from django.views.generic import View
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import AuthenticationForm
from django.conf import settings
class OnboardingForm(forms.Form):
username = forms.CharField(label=_("Username"), max_length=150, required=True)
email = forms.EmailField(label=_("Email"), max_length=254, required=True)
password = forms.CharField(label=_("Password"), max_length=1024, min_length=8, widget=forms.PasswordInput(), required=True)
class OnboardingView(View):
def get(self, request):
User = get_user_model()
if User.objects.all().count() != 0:
# redirect to index
return redirect(reverse('index'))
return TemplateResponse(request, "inventory/onboarding.html", {
"settings": {
"SERVER_URL": settings.SERVER_URL,
"DEBUG": settings.DEBUG,
"ALLOWED_HOSTS": settings.ALLOWED_HOSTS,
"DATABASE_HOST": settings.DATABASES['default']['HOST'],
"DATABASE_NAME": settings.DATABASES['default']['NAME'],
"DATABASE_USER": settings.DATABASES['default']['USER'],
"DATABASE_PASSWORD": settings.DATABASES['default']['PASSWORD'],
"LANGUAGE_CODE": settings.LANGUAGE_CODE,
"TIME_ZONE": settings.TIME_ZONE,
"STATIC_ROOT": settings.STATIC_ROOT,
"MEDIA_ROOT": settings.MEDIA_ROOT,
"PAGE_SIZE": settings.PAGE_SIZE,
},
"form": OnboardingForm()
})
def post(self, request):
# validate we have everything
form = OnboardingForm(request.POST)
if form.is_valid():
# create superuser
User = get_user_model()
User.objects.create_superuser(
form.cleaned_data['username'],
form.cleaned_data['email'],
form.cleaned_data['password']
)
# show success screen
login_form = AuthenticationForm(data={"username": form.cleaned_data['username'] })
return TemplateResponse(request, "inventory/onboarding_success.html", {"form": login_form, "next": reverse('index')})
return TemplateResponse(request, "inventory/onboarding.html", {"settings": settings, "form": form})