From 084d35fdf4ae9f40f825e734e562041f18d91247 Mon Sep 17 00:00:00 2001 From: Johannes Schriewer Date: Sat, 11 Jan 2025 03:26:25 +0100 Subject: [PATCH] Onboarding workflow --- inventory/locale/de/LC_MESSAGES/django.po | 74 ++++++++++++++++++- inventory/static/inventory/css/main.css | 10 +++ inventory/templates/inventory/onboarding.html | 53 +++++++++++++ .../inventory/onboarding_success.html | 35 +++++++++ inventory/urls.py | 4 +- inventory/views/__init__.py | 4 +- inventory/views/index.py | 12 ++- inventory/views/onboarding.py | 60 +++++++++++++++ 8 files changed, 246 insertions(+), 6 deletions(-) create mode 100644 inventory/templates/inventory/onboarding.html create mode 100644 inventory/templates/inventory/onboarding_success.html create mode 100644 inventory/views/onboarding.py diff --git a/inventory/locale/de/LC_MESSAGES/django.po b/inventory/locale/de/LC_MESSAGES/django.po index 2cc50fb..9449274 100644 --- a/inventory/locale/de/LC_MESSAGES/django.po +++ b/inventory/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 1.0\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" "Last-Translator: Johannes Schriewer \n" "Language: German\n" @@ -467,6 +467,62 @@ msgstr "Inventarverwaltung" msgid "Create new manufacturer..." 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\search_result.html:33 msgid "First page" @@ -552,10 +608,22 @@ msgstr "" msgid "Lost password?" 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" msgstr "Deutsch" -#: .\inventory_project\settings.py:122 +#: .\inventory_project\settings.py:131 msgid "English" msgstr "Englisch" diff --git a/inventory/static/inventory/css/main.css b/inventory/static/inventory/css/main.css index 88770ff..66f1a52 100644 --- a/inventory/static/inventory/css/main.css +++ b/inventory/static/inventory/css/main.css @@ -335,4 +335,14 @@ div.warning-icon { background-color: #c00000; -webkit-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; } \ No newline at end of file diff --git a/inventory/templates/inventory/onboarding.html b/inventory/templates/inventory/onboarding.html new file mode 100644 index 0000000..05b3018 --- /dev/null +++ b/inventory/templates/inventory/onboarding.html @@ -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 %} +

{% translate 'Welcome to the Inventory Management setup' %}

+ +

+ {% blocktranslate %} + Currently no admin user is defined in the database. + To use the inventory management system you need at least one admin user... + {% endblocktranslate %} +

+ +

+ {% blocktranslate %} + Please verify that the following settings are correct and then fill out the + form at the end and click + {% endblocktranslate %} + {% translate 'Create user' %} +

+ +

{% translate 'Current settings' %}

+ +
+ {% for key, value in settings.items %} +
{{ key }}
+
{{ value }}
+ {% endfor %} +
+ +

{% translate 'Create user' %}

+ + {% if form.errors %} +

+ {% blocktranslate %} + Please correct the errors below. + {% endblocktranslate %} +

+ {% endif %} + +
+ {% csrf_token %} + {{ form }} + +
+{% endblock %} \ No newline at end of file diff --git a/inventory/templates/inventory/onboarding_success.html b/inventory/templates/inventory/onboarding_success.html new file mode 100644 index 0000000..76c8fd6 --- /dev/null +++ b/inventory/templates/inventory/onboarding_success.html @@ -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 %} +

Onboarding completed!

+ +

Congratulations, you have successfully setup the Inventory management system

+ +

You may now log in with the password you just set up.

+ +
+ {% csrf_token %} + + + + + + + + + +
{{ form.username.label_tag }}{{ form.username }}
{{ form.password.label_tag }}{{ form.password }}
+ + + +
+ +{% endblock %} \ No newline at end of file diff --git a/inventory/urls.py b/inventory/urls.py index fcc3f68..0ba2f7c 100644 --- a/inventory/urls.py +++ b/inventory/urls.py @@ -34,7 +34,8 @@ from .views import ( ManufacturerView, IndexView, TagView, - SearchView + SearchView, + OnboardingView ) urlpatterns = [ @@ -54,5 +55,6 @@ urlpatterns = [ path('tags', TagListView.as_view(), name='tag-list'), path('tag/', TagView.as_view(), name='tag-detail'), path('search', SearchView.as_view(), name='search'), + path('onboarding', OnboardingView.as_view(), name='onboarding'), path('', IndexView.as_view(), name='index') ] diff --git a/inventory/views/__init__.py b/inventory/views/__init__.py index a5ea7b5..44e69e5 100644 --- a/inventory/views/__init__.py +++ b/inventory/views/__init__.py @@ -7,6 +7,7 @@ from .workshop import WorkshopView, WorkshopListView from .index import IndexView from .tag import TagListView, TagView from .search import SearchView +from .onboarding import OnboardingView __all__ = [ AreaView, AreaListView, @@ -17,5 +18,6 @@ __all__ = [ WorkshopView, WorkshopListView, IndexView, TagView, TagListView, - SearchView + SearchView, + OnboardingView ] \ No newline at end of file diff --git a/inventory/views/index.py b/inventory/views/index.py index 7460b0f..aec1023 100644 --- a/inventory/views/index.py +++ b/inventory/views/index.py @@ -3,14 +3,24 @@ from django.shortcuts import redirect from django.contrib.auth.decorators import login_required from django.utils.decorators import method_decorator 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 -@method_decorator(login_required, name='dispatch') +@method_decorator(login_required, name='post') class IndexView(View): 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() if settings.default_container is not None: return redirect(settings.default_container.url) diff --git a/inventory/views/onboarding.py b/inventory/views/onboarding.py new file mode 100644 index 0000000..f8626a7 --- /dev/null +++ b/inventory/views/onboarding.py @@ -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})