From 9fc32adb23705b93b4266e64080a550dc90de9bf Mon Sep 17 00:00:00 2001 From: Scheianu Ionut Date: Thu, 11 Sep 2025 22:30:52 +0300 Subject: [PATCH] Role management, login logic, and debug improvements. MariaDB login now uses correct syntax. --- .../app/__pycache__/__init__.cpython-312.pyc | Bin 1337 -> 1337 bytes py_app/app/__pycache__/routes.cpython-312.pyc | Bin 24851 -> 25774 bytes .../app/__pycache__/settings.cpython-312.pyc | Bin 0 -> 4357 bytes .../app/__pycache__/warehouse.cpython-312.pyc | Bin 7480 -> 8605 bytes .../db_create_scripts/create_roles_table.py | 45 ++++++++++ .../drop_external_users_roles_tables.py | 26 ++++++ .../db_create_scripts/print_internal_users.py | 30 +++++++ .../seed_internal_superadmin.py | 34 +++++++ py_app/app/routes.py | 53 +++++++---- py_app/app/settings.py | 76 ++++++++++++++++ py_app/app/templates/create_locations.html | 16 ++++ py_app/app/templates/edit_access_roles.html | 43 +++++++++ .../app/templates/import_locations_csv.html | 6 +- py_app/app/templates/settings.html | 83 ++++++++++-------- py_app/app/warehouse.py | 27 +++++- py_app/instance/users.db | Bin 12288 -> 32768 bytes py_app/seed.py | 20 ++--- py_app/static/style.css | 61 +++++++++++++ 18 files changed, 442 insertions(+), 78 deletions(-) create mode 100644 py_app/app/__pycache__/settings.cpython-312.pyc create mode 100644 py_app/app/db_create_scripts/create_roles_table.py create mode 100644 py_app/app/db_create_scripts/drop_external_users_roles_tables.py create mode 100644 py_app/app/db_create_scripts/print_internal_users.py create mode 100644 py_app/app/db_create_scripts/seed_internal_superadmin.py create mode 100644 py_app/app/settings.py create mode 100644 py_app/app/templates/edit_access_roles.html create mode 100644 py_app/static/style.css diff --git a/py_app/app/__pycache__/__init__.cpython-312.pyc b/py_app/app/__pycache__/__init__.cpython-312.pyc index 7f35629234a42779f525f1c1f31b5c82a2a0f1dc..e34e2d3a70eddbbc96aa338fd0126dbd134fb347 100644 GIT binary patch delta 20 acmdnVwUdkcG%qg~0}yB`9p1>T#|i*6UIcys delta 20 acmdnVwUdkcG%qg~0}!YmI=GQrj}-to1_c@b diff --git a/py_app/app/__pycache__/routes.cpython-312.pyc b/py_app/app/__pycache__/routes.cpython-312.pyc index c3f9a406721aa5d5e0b426039789620852f0a0da..7e521c0305ce6ca7431d465197f3c4024639b379 100644 GIT binary patch delta 6242 zcma)A4Qw38b>7`u9(lYU{vUsiJT8Ak^7wb8NRbjr+miSr*`g>}q^*dQaz1fawwF_b7dX(I;?yG&>LMUW>HrPWI%Jfh zfzkkdZ;rQIQwrJz?(NKc-+MFj=FOYgqyNZ%^JCuiBd0T)gXh!gA53TMz3M9AU%6WU z_eW(>wueh2W#eTL&$x%@1Ww729ZLC40m&RUUcp+NrWWu2hoe-Se1fi(6jZt7oGJbr zxoLZH-j}$WDbw7zlxBJIZ}O=|xxj>1rSYml11~b+)w26b+;~lzRZ}dNKyQMnw^9?k zHqG;t8P+@|e2amX8+e5YFEwzlfmfRFIs=ysyvl^v8+f&W*O>6)G+tBt&^)%7cnxWu zr_QibZ^C_PysBZ7?|mj#qrqz2#A-6JnhaL+CRU4y)oid@H?jOCR*S)ElS@7m6YVBe zYntWRYRs;~g!>J=)4;cx@HPYQGVpE_-frOA4Sa_Q-)i7J2HtDJI}E(fz#lW=ooT%4 z@lC#X!o=E^W_flRR(6^2E(70f;Qc1NJB?QjZ0cpu#M*AKhBmSGm{>a$Z)&gB?0qQi zo;2}#4Bk@@@%EW`y=QsfFzvK1FZhIHuBPaEC_1GDrh`#AtdL}>B8T)qaB@=7v;a}V z$_6Axf}v>AHX9_$v^t|Hb7lUSm>kp<##`6%_o33`N%7!;(J>#N%#0}dv?^

luXQ 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 literal 0 HcmV?d00001 diff --git a/py_app/app/__pycache__/warehouse.cpython-312.pyc b/py_app/app/__pycache__/warehouse.cpython-312.pyc index 82cd5f005352ebfac6ae2f3a3d2bb522abcd22da..a4f8703579571dfba8ae81f4be1262c7a8d6aacd 100644 GIT binary patch delta 1323 zcmZ8g?Mqu%7(eH}Wo$;%;_urAPXbZIEYZAZvv2lGK|y8zl?*5vt-hVaH;-;JGVkDwK5<@ z;WA2uGnAw~*<$P1NzqE3zP2L82y}{-DL)u(JnYISH!99(85xejElT07wKm+?C9?uM zYs3ZYlA8fC9XI1WYiK%d!86}2Xk_+FAZXXip3}REi4DS)((N zjNF!D$*BvXyVbLLwF!5|+CtmRO<-C2rd;8NZ+4fBP!;U>eaJ~n_OU_g@H5E z%dE?vWs!>dq^9CY`4+*uY_$>B0t|Hr+ z=`3((bKKcIzWD`rxn!$ZO{^pewuYRoVME@&nYXp4drP)Uo8x(#H`DtU?^+K%4i$J$ zj`wVa^Sm!TP_jB!J6AdjR#(pI+PIpxUQGK-j=FWvV^6`+lyfv~`tpt|>0rrLzv0_H zx69>ie%!OXW@p2)!NOjp+djgeegJmX>{e(D;q$5NSS%40(V+5U)w^&&F;_RhVZ~eh z6^n2-vGcNeoq|?nhQG)Om_Q#97*W3CYc3PzBl4Yylzt0P2l2^kd9CZ5ObXM9=-X%- eheQ@)m-08?T4{ur4r$*hJl zYFSEnVPYw)H7qp@YuI4wgBdj0{cf=Y_y>nfUMXVE$Uga@h@_q=PRFa{AOAi@Gj6ocd^8;h#eI|CX1Adyla(ZFznPpHBD4m)3aU1Qx0u}kdocO>NJ z^UUPAE}?NzLSu#eWeLj;-aGta{WYC6*ZJiy^2;w^yUefN!E#4Tc6!dloaT z)Ls@d?cly6BsZgWMal;6%R&wv>~{oYC-XOW-r<(IAZ@fG^Fm<674FE*Tw;B!jCPY} zN=Gx^+WbRWn32~3=#X2iX_+~x#YIk&C1e8`9VchWsxkUco+vwyH617$x!FW+J`t', methods=['POST']) +def update_role_access(role): + from .settings import update_role_access_handler + return update_role_access_handler(role) @bp.route('/store_articles') def store_articles(): @@ -48,40 +56,47 @@ def login(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] - user = User.query.filter_by(username=username, password=password).first() + user = None + print("Raw form input:", repr(username), repr(password)) + # Only check external MariaDB for user authentication + try: + conn = get_db_connection() + cursor = conn.cursor() + cursor.execute("SHOW TABLES LIKE 'users'") + if cursor.fetchone(): + cursor.execute("SELECT username, password, role FROM users WHERE username=%s AND password=%s", (username.strip(), password.strip())) + row = cursor.fetchone() + print("External DB query result:", row) + if row: + user = {'username': row[0], 'password': row[1], 'role': row[2]} + conn.close() + except Exception as e: + print("External DB error:", e) if user: - session['user'] = user.username - session['role'] = user.role + session['user'] = user['username'] + session['role'] = user['role'] + print("Logged in as:", session.get('user'), session.get('role')) return redirect(url_for('main.dashboard')) else: + print("Login failed for:", username, password) flash('Invalid credentials. Please try again.') return render_template('login.html') @bp.route('/dashboard') def dashboard(): + print("Session user:", session.get('user'), session.get('role')) if 'user' not in session: return redirect(url_for('main.login')) return render_template('dashboard.html') @bp.route('/settings') def settings(): - if 'role' not in session or session['role'] != 'superadmin': - flash('Access denied: Superadmin only.') - return redirect(url_for('main.dashboard')) - - # Fetch all users from the database - users = User.query.all() + return settings_handler() - # Load external database settings from the instance folder - external_settings = {} - settings_file = os.path.join(current_app.instance_path, 'external_server.conf') - if (os.path.exists(settings_file)): - with open(settings_file, 'r') as f: - for line in f: - key, value = line.strip().split('=', 1) - external_settings[key] = value - - return render_template('settings.html', users=users, external_settings=external_settings) +# Route for editing access roles (superadmin only) +@bp.route('/edit_access_roles') +def edit_access_roles(): + return edit_access_roles_handler() @bp.route('/quality') def quality(): diff --git a/py_app/app/settings.py b/py_app/app/settings.py new file mode 100644 index 0000000..0ea4544 --- /dev/null +++ b/py_app/app/settings.py @@ -0,0 +1,76 @@ +from flask import render_template, request, session, redirect, url_for, flash +from .models import User +from . import db + +# Settings module logic +import sqlite3 +import os +def ensure_roles_table(): + instance_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../instance')) + if not os.path.exists(instance_folder): + os.makedirs(instance_folder) + db_path = os.path.join(instance_folder, 'users.db') + conn = sqlite3.connect(db_path) + cursor = conn.cursor() + cursor.execute(""" + CREATE TABLE IF NOT EXISTS roles ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT UNIQUE NOT NULL, + access_level TEXT NOT NULL, + description TEXT + ) + """) + cursor.execute(""" + INSERT OR IGNORE INTO roles (name, access_level, description) + VALUES (?, ?, ?) + """, ('superadmin', 'full', 'Full access to all app areas and functions')) + conn.commit() + conn.close() +# List of roles (should match your app's roles) +ROLES = [ + 'superadmin', 'admin', 'manager', 'warehouse_manager', 'warehouse_worker', 'quality_manager', 'quality_worker' +] + +# Helper to check if current user is superadmin +def is_superadmin(): + return session.get('role') == 'superadmin' + +# Route handler for editing access roles +def edit_access_roles_handler(): + if not is_superadmin(): + flash('Access denied: Superadmin only.') + return redirect(url_for('main.dashboard')) + ensure_roles_table() + return render_template('edit_access_roles.html', roles=ROLES) + +# Handler for updating role access (stub, to be implemented) +def update_role_access_handler(role): + if not is_superadmin(): + flash('Access denied: Superadmin only.') + return redirect(url_for('main.dashboard')) + if role == 'superadmin': + flash('Superadmin access cannot be changed.') + return redirect(url_for('main.edit_access_roles')) + access_level = request.form.get('access_level') + # TODO: Save access_level for the role in the database or config + flash(f'Access for role {role} updated to {access_level}.') + return redirect(url_for('main.edit_access_roles')) + +def settings_handler(): + if 'role' not in session or session['role'] != 'superadmin': + flash('Access denied: Superadmin only.') + return redirect(url_for('main.dashboard')) + users = User.query.all() + # Load external database settings from the instance folder + external_settings = {} + import os + from flask import current_app + settings_file = os.path.join(current_app.instance_path, 'external_server.conf') + if os.path.exists(settings_file): + with open(settings_file, 'r') as f: + for line in f: + key, value = line.strip().split('=', 1) + external_settings[key] = value + return render_template('settings.html', users=users, external_settings=external_settings) + +# Add more settings-related functions here as needed diff --git a/py_app/app/templates/create_locations.html b/py_app/app/templates/create_locations.html index 05d5649..6a097eb 100644 --- a/py_app/app/templates/create_locations.html +++ b/py_app/app/templates/create_locations.html @@ -25,6 +25,22 @@ Go to Import Page + + {% if session['role'] in ['administrator', 'management'] %} +

+ +
To delete a location, enter the ID of the location and press delete.
To delete 2 or multiple locations, enter the IDs separated by "," and then press delete.
+
+ + +
+ +
+ {% endif %}
diff --git a/py_app/app/templates/edit_access_roles.html b/py_app/app/templates/edit_access_roles.html new file mode 100644 index 0000000..ae53cb1 --- /dev/null +++ b/py_app/app/templates/edit_access_roles.html @@ -0,0 +1,43 @@ +{% extends "base.html" %} +{% block title %}Edit Access Roles{% endblock %} +{% block content %} +
+

Role Access Management

+

Configure which roles can view or execute functions on each app page and feature.

+ + + + + + + + + + + + + + + {% for role in roles %} + {% if role != 'superadmin' %} + + + + + + {% endif %} + {% endfor %} + +
RoleAccess LevelEditable
superadminFull access to all pages and functionsNot editable
{{ role }} +
+ + +
+
Editable
+

Only superadmin users can view and manage role access.

+
+{% endblock %} diff --git a/py_app/app/templates/import_locations_csv.html b/py_app/app/templates/import_locations_csv.html index 6bd6635..1d287d8 100644 --- a/py_app/app/templates/import_locations_csv.html +++ b/py_app/app/templates/import_locations_csv.html @@ -37,9 +37,9 @@
-