re-add yasi-applets

This commit is contained in:
Jonathan Carter
2025-08-23 22:33:58 +02:00
parent 69d6ba277d
commit 652bbba9c0
62 changed files with 1852 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
from flask import Blueprint
bp = Blueprint('users', __name__,
template_folder='',
static_folder='static',
static_url_path='/users/static')
from yasi_applets.users import routes

Binary file not shown.

View File

@@ -0,0 +1,65 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-20 15:48+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: routes.py:33
msgid "Let's set up an initial user."
msgstr "Kom on stel 'n gebruiker op."
msgid "Users"
msgstr "Gebruikers"
#: routes.py:34
msgid "Full Name"
msgstr "Volle Naam"
#: routes.py:35
msgid "Username"
msgstr "Gebruikersnaam"
#: routes.py:36
msgid "This username is available"
msgstr "Hierdie gebruikersnaam is nie beskikbaar nie."
#: routes.py:37
msgid "This username is not available"
msgstr "Hierdie gebruikersnaam is nie beskikbaar nie."
#: routes.py:38
msgid "This username is reserved by the system"
msgstr "Hierdie gebruikersnaam is reserveerd deur vir die sisteem."
#: routes.py:39
msgid "The username must be one word, lowercase, with no special characters"
msgstr "Die gebruikersnaam moet een woord wees, kleinletters, met geen spesiale karakters."
#: routes.py:40
msgid "Password"
msgstr "Wagwoord"
#: routes.py:41
msgid "Password (confirm)"
msgstr "Wagwoord (bevestig)"
#: routes.py:42
msgid "These passwords do now match"
msgstr "Hierdie wagwoorde is nie dieselfde nie"
#: routes.py:43
msgid "This password is too short"
msgstr "Hierdie wagwoord is te kort"

View File

@@ -0,0 +1,62 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-20 15:48+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: routes.py:33
msgid "Let's set up an initial user."
msgstr ""
#: routes.py:34
msgid "Full Name"
msgstr ""
#: routes.py:35
msgid "Username"
msgstr ""
#: routes.py:36
msgid "This username is available"
msgstr ""
#: routes.py:37
msgid "This username is not available"
msgstr ""
#: routes.py:38
msgid "This username is reserved by the system"
msgstr ""
#: routes.py:39
msgid "The username must be one word, lowercase, with no special characters"
msgstr ""
#: routes.py:40
msgid "Password"
msgstr ""
#: routes.py:41
msgid "Password (confirm)"
msgstr ""
#: routes.py:42
msgid "These passwords do now match"
msgstr ""
#: routes.py:43
msgid "This password is too short"
msgstr ""

View File

@@ -0,0 +1,126 @@
from yasi_applets.software import bp
from flask import Flask, request, session, redirect, \
url_for, render_template, flash, Blueprint
import gettext
# we use this neat little trick to get config data from the main app
from flask import current_app
# Set up Gettext
def set_language(LANG):
"""
Sets language for this applet
"""
translations = gettext.translation("users", './applets/users/locales',
fallback=True, languages=[LANG])
translations.install()
_ = translations.gettext
set_language('')
@bp.route('/users')
def users_root():
"""
Users screen for the webui.
"""
set_language(current_app.config['CONFIG']['settings']['language'])
string_dict = build_stringlist()
build_menu()
menu = current_app.config['CONFIG']['settings']['menu_order'].split(" ")
next_step_url = menu[menu.index("users")+1]
if menu[menu.index("users")] == 1:
previous_step_url = False
else:
previous_step_url = menu[menu.index("users")-1]
root_button = '&nbsp; <button class="button not-allowed is-light"> <i class="fa fa-user" aria-hidden="true"></i> &nbsp; Setup root user </button>'
ldap_button = '&nbsp; <button class="button is-light"> <i class="fa fa-address-card" aria-hidden="true"></i> &nbsp; Connect LDAP </button>'
ad_button = '&nbsp; <button class="button is-light"> <i class="fa fa-address-card" aria-hidden="true"></i> &nbsp; Connect AD </button>'
csv_button = '&nbsp; <button class="button is-light"> <i class="fa fa-users" aria-hidden="true"></i> &nbsp; Import CSV </button>'
bottom_menu = root_button + ldap_button + ad_button + csv_button
bottom_menu = ""
initial_user = current_app.config['CONFIG']['recipe']['users']['users'][0]
build_summary()
return render_template('users.html', string_dict=string_dict,
menu=current_app.config['CONFIG']['settings']['menu'],
menu_order=current_app.config['CONFIG']['settings']['menu_order'].split(),
previous_step=previous_step_url,
next_step=next_step_url,
bottom_menu=bottom_menu,
initial_user=initial_user)
@bp.route('/users/user-check/', methods=['GET', 'POST', 'PUT'])
def check_user():
if request.method == 'POST':
username = request.form["username"]
fullname = request.form["fullname"]
current_app.config['CONFIG']['recipe']['users']['users'][0]['username'] = username
current_app.config['CONFIG']['recipe']['users']['users'][0]['fullname'] = fullname
if username in ["root", "games"]:
return('<p class="has-text-danger"><b>That username is not available</b> </p>')
else:
return('<p class="has-text-success"><b>That username is available</b> </p>')
build_summary()
return("")
@bp.route('/users/password-check/', methods=['GET', 'POST', 'PUT'])
def check_password():
if request.method == 'POST':
password = request.form["password"]
password_confirm = request.form["password_confirm"]
current_app.config['CONFIG']['recipe']['users']['users'][0]['password'] = password
current_app.config['CONFIG']['recipe']['users']['users'][0]['password_confirm'] = password_confirm
if password != password_confirm:
return('<p class="has-text-danger"><b>Passwords do not match</b> </p>')
else:
return('<p class="has-text-success"><b>Passwords match</b> </p>')
build_summary()
return("")
def build_stringlist():
"""
Return all the strings that is used in this applet.
"""
string_dict = {}
string_dict['menu_item'] = _("Users")
string_dict['initial_user_text'] = _("Let's set up an initial user.")
string_dict['full_name'] = _("Full Name")
string_dict['user_name'] = _("Username")
string_dict['user_name_hint'] = _("One word, all lowercase")
string_dict['user_name_available'] = _("This username is available")
string_dict['user_name_not_available'] = _("This username is not available")
string_dict['user_name_reserved'] = _("This username is reserved by the system")
string_dict['user_name_characters'] = _("The username must be one word, lowercase, with no special characters")
string_dict['password'] = _("Password")
string_dict['password_confirm'] = _("Password (confirm)")
string_dict['password_nomatch'] = _("These passwords do now match")
string_dict['password_tooshort'] = _("This password is too short")
return string_dict
def build_menu():
"""
Define menu items and paths.
"""
current_app.config['CONFIG']['settings']['menu']['users'] = (build_stringlist()['menu_item'], "/users", 20)
print(current_app.config['CONFIG']['settings']['menu'])
def build_summary():
"""
Write up a summary of what this module will do.
"""
current_app.config['CONFIG']['Summary']['users'] = {}
current_app.config['CONFIG']['Summary']['users']['heading'] = "Users and Identity"
current_app.config['CONFIG']['Summary']['users']['bleh'] = current_app.config['CONFIG']['recipe']['popcon']['enable_popcon']
current_app.config['CONFIG']['Summary']['users']['settings'] = current_app.config['CONFIG']['recipe']['users']['users']
current_app.config['CONFIG']['Summary']['users']['text'] = "Add primary user with the username: " + str(current_app.config['CONFIG']['recipe']['users']['users'][0]['username'])
return("ok?")
build_menu()

View File

@@ -0,0 +1,24 @@
from applets.software import bp
from flask import Flask, request, session, redirect, \
url_for, render_template, flash, Blueprint
# we use this neat little trick to get config data from the main app
from flask import current_app
def build_stringlist():
"""
Return all the strings that is used in this applet.
"""
string_dict = {}
string_dict['initial_user_text'] = _("Let's set up an initial user.")
string_dict['full_name'] = _("Full Name")
string_dict['user_name'] = _("Username")
string_dict['user_name_available'] = _("This username is available")
string_dict['user_name_not_available'] = _("This username is not available")
string_dict['user_name_reserved'] = _("This username is reserved by the system")
string_dict['user_name_characters'] = _("The username must be one word, lowercase, with no special characters")
string_dict['password'] = _("Password")
string_dict['password_confirm'] = _("Password (confirm)")
string_dict['password_nomatch'] = _("These passwords do now match")
string_dict['password_tooshort'] = _("This password is too short")
return string_dict

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="128px" viewBox="0 0 128 128" width="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<linearGradient id="a" gradientUnits="userSpaceOnUse" x1="16.98286657496" x2="113.51232281881" y1="91.79046347784" y2="91.79046347784">
<stop offset="0" stop-color="#e6f0fc"/>
<stop offset="0.0383542" stop-color="#cadff8" stop-opacity="0.996078"/>
<stop offset="0.124655" stop-color="#d4e5f9" stop-opacity="0.992157"/>
<stop offset="0.901364" stop-color="#b2d0f4" stop-opacity="0.964706"/>
<stop offset="0.9589" stop-color="#d0e3f9" stop-opacity="0.964706"/>
<stop offset="1" stop-color="#98c1f1" stop-opacity="0.964706"/>
</linearGradient>
<linearGradient id="b" gradientUnits="userSpaceOnUse" x1="35.05556157496" x2="88.56691281881" y1="91.79046347784" y2="91.79046347784">
<stop offset="0" stop-color="#e6f0fc"/>
<stop offset="0.230125" stop-color="#cadff8" stop-opacity="0.996078"/>
<stop offset="0.383542" stop-color="#d4e5f9" stop-opacity="0.992157"/>
<stop offset="0.588996" stop-color="#b2d0f4" stop-opacity="0.964706"/>
<stop offset="0.753397" stop-color="#d0e3f9" stop-opacity="0.964706"/>
<stop offset="1" stop-color="#98c1f1" stop-opacity="0.964706"/>
</linearGradient>
<path d="m 65.007812 67.363281 c -24.257812 0.027344 -44.703124 16.957031 -49.898437 39.847657 c -1.597656 5.96875 1.65625 9.007812 5.269531 9.007812 h 88.402344 c 4.75 0 7.4375 -4.191406 6.222656 -8.734375 c -5.097656 -23.042969 -25.625 -40.109375 -49.996094 -40.121094 z m 0 0" fill="url(#a)"/>
<path d="m 89.351562 33.375 c 0 14.257812 -11.554687 25.8125 -25.8125 25.8125 c -14.257812 0 -25.816406 -11.554688 -25.816406 -25.8125 s 11.558594 -25.816406 25.816406 -25.816406 c 14.257813 0 25.8125 11.558594 25.8125 25.816406 z m 0 0" fill="url(#b)"/>
<path d="m 65.007812 64.082031 c -24.257812 0.03125 -44.703124 16.074219 -49.898437 38.96875 c -1.597656 5.96875 1.65625 9.007813 5.269531 9.007813 h 88.402344 c 4.75 0 7.4375 -4.191406 6.222656 -8.734375 c -5.097656 -23.042969 -25.625 -39.226563 -49.996094 -39.242188 z m 24.34375 -34.046875 c 0 14.257813 -11.554687 25.8125 -25.8125 25.8125 c -14.257812 0 -25.816406 -11.554687 -25.816406 -25.8125 c 0 -14.257812 11.558594 -25.816406 25.816406 -25.816406 c 14.257813 0 25.8125 11.558594 25.8125 25.816406 z m 0 0" fill="#f6f9fe" fill-opacity="0.996078"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,73 @@
{% extends "layout.html" %}
{% block body %}
<p><b> {{ string_dict['initial_user_text'] }} </b></p>
<br>
<form action="/users" method="POST">
<img src="/users/static/img/avatar-default.svg" width="160px" style="float: left; position: absolute;" />
<div style="margin-left: 180px;">
<div class="field">
<label>{{ string_dict['full_name'] }}</label>
<div class="control has-icons-left has-icons-right">
<input class="input" name="fullname" type="text" placeholder="Full Name" value="{% if initial_user['fullname'] %}{{ initial_user['fullname'] }}{% endif %}" hx-post="/users/user-check" hx-trigger="keyup changed delay:500ms" hx-target="#username-name">
<span class="icon is-small is-left">
<i class="fa fa-user-circle-o" aria-hidden="true"></i>
</span>
<!-- <span class="icon is-small is-right">
<img src="/static/icons/emblem-default-symbolic.svg">
</span> -->
</div>
</div>
<div class="field">
<label>{{ string_dict['user_name'] }}</label>
<div class="control has-icons-left has-icons-right">
<input class="input" type="text" placeholder="{{ string_dict['user_name'] }}" value="{% if initial_user['username'] %}{{ initial_user['username'] }}{% endif %}" name="username" hx-post="/users/user-check" hx-trigger="keyup changed delay:200ms" hx-trigger="load" hx-target="#username-status">
<span class="icon is-small is-left">
<i class="fa fa-user-circle-o" aria-hidden="true"></i>
</span>
<!-- <span class="icon is-small is-right">
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
</span> -->
</div>
<div id="username-status">
<p> {{ string_dict['user_name_hint'] }}</p>
</div>
</div>
<div class="field">
<label class="password">{{ string_dict['password'] }}</label>
<div class="control has-icons-left has-icons-right">
<input class="input" name="password" type="password" placeholder="{{ string_dict['password'] }}" value="{% if initial_user['password'] %}{{ initial_user['password'] }}{% endif %}" hx-post="/users/password-check" hx-trigger="keyup changed delay:200ms" hx-target="#password-status">
<span class="icon is-small is-left">
<i class="fa fa-address-card" aria-hidden="true"></i>
</span>
</div>
</div>
<div class="field">
<label class="password">{{ string_dict['password_confirm'] }}</label>
<div class="control has-icons-left has-icons-right">
<input class="input" name="password_confirm" type="password" placeholder="{{ string_dict['password_confirm'] }}" value="{% if initial_user['password_confirm'] %}{{ initial_user['password_confirm'] }}{% endif %}" hx-post="/users/password-check" hx-trigger="keyup changed delay:200ms" hx-target="#password-status">
<span class="icon is-small is-left">
<i class="fa fa-address-card" aria-hidden="true"></i>
</span>
<div id="password-status">
<p> </p>
</div>
</div>
</div>
</form>
</div> <!-- style 180 -->
</div>
</div>
{% endblock %}