Files
co_app/app/pages/user.py
2025-12-16 08:53:36 +01:00

447 lines
15 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# import streamlit as st
# import pandas as pd
# from db_users import init_db, get_user, update_user, set_password # wie zuvor
# from db_users_search import search_users # wie zuvor
# st.set_page_config(layout="wide")
# init_db()
# if "selected_user_id" not in st.session_state:
# st.session_state.selected_user_id = None
# def open_edit(user_id: int):
# st.session_state.selected_user_id = user_id
# st.session_state.show_edit = True
# @st.dialog("Benutzer bearbeiten")
# def edit_user_dialog(user_id: int):
# user = get_user(user_id)
# if not user:
# st.error("Benutzer nicht gefunden.")
# return
# st.markdown(f"**{user['username']}** (ID {user['id']})")
# with st.form("edit_user_form"):
# display_name = st.text_input("Anzeigename", value=user.get("display_name") or "")
# email = st.text_input("E-Mail", value=user.get("email") or "")
# role = st.selectbox("Rolle", ["user", "admin"], index=0 if user["role"] == "user" else 1)
# is_active = st.checkbox("Aktiv", value=bool(user["is_active"]))
# save = st.form_submit_button("Speichern")
# if save:
# update_user(user_id, display_name, email, role, is_active)
# st.success("Gespeichert.")
# st.session_state.show_edit = False
# st.rerun()
# st.divider()
# st.markdown("**Passwort zurücksetzen**")
# with st.form("pw_form", clear_on_submit=True):
# pw = st.text_input("Neues Passwort", type="password")
# pw_save = st.form_submit_button("Passwort setzen")
# if pw_save:
# if not pw:
# st.error("Bitte Passwort eingeben.")
# else:
# set_password(user_id, pw)
# st.success("Passwort aktualisiert.")
# st.session_state.show_edit = False
# st.rerun()
# st.title("Benutzerverwaltung")
# q = st.text_input("Suche", placeholder="username / Name / E-Mail")
# rows, total = search_users(q, limit=20, offset=0)
# st.caption(f"{total} Treffer")
# for r in rows:
# c1, c2, c3, c4 = st.columns([2, 2, 3, 1])
# c1.write(r["username"])
# c2.write(r.get("display_name") or "")
# c3.write(r.get("email") or "")
# if c4.button("Ändern", key=f"edit_{r['id']}"):
# open_edit(r["id"])
# # Dialog öffnen, wenn Flag gesetzt
# if st.session_state.get("show_edit") and st.session_state.selected_user_id:
# edit_user_dialog(int(st.session_state.selected_user_id))
# # admin_users.py
# import streamlit as st
# import pandas as pd
# from db_users import init_db, list_users, get_user, create_user, update_user, set_password, delete_user
# st.set_page_config(page_title="User Admin", layout="wide")
# init_db()
# st.title("Benutzerverwaltung")
# # --- Übersicht ---
# users = list_users()
# df = pd.DataFrame(users)
# if df.empty:
# st.info("Noch keine Benutzer vorhanden.")
# df = pd.DataFrame(columns=["id","username","display_name","email","role","is_active","created_at"])
# st.subheader("Übersicht")
# st.dataframe(df, use_container_width=True, hide_index=True)
# st.divider()
# colA, colB = st.columns(2, gap="large")
# # --- Neuen Benutzer anlegen ---
# with colA:
# st.subheader("Neuen Benutzer anlegen")
# with st.form("create_user", clear_on_submit=True):
# username = st.text_input("Username*", max_chars=50)
# password = st.text_input("Initiales Passwort*", type="password")
# display_name = st.text_input("Anzeigename")
# email = st.text_input("E-Mail")
# role = st.selectbox("Rolle", ["user", "admin"], index=0)
# is_active = st.checkbox("Aktiv", value=True)
# submitted = st.form_submit_button("Anlegen")
# if submitted:
# if not username or not password:
# st.error("Username und Passwort sind Pflicht.")
# else:
# try:
# create_user(username, password, display_name, email, role, is_active)
# st.success("Benutzer angelegt.")
# st.rerun()
# except Exception as e:
# st.error(f"Fehler beim Anlegen: {e}")
# # --- Bestehenden Benutzer bearbeiten/löschen ---
# with colB:
# st.subheader("Benutzer bearbeiten / löschen")
# user_ids = df["id"].tolist() if "id" in df.columns else []
# selected_id = st.selectbox("Benutzer wählen", user_ids, format_func=lambda uid: f"{uid} {df.loc[df.id==uid,'username'].values[0] if len(df)>0 else uid}" if uid in user_ids else str(uid))
# user = get_user(int(selected_id)) if selected_id else None
# if user:
# with st.form("edit_user"):
# display_name2 = st.text_input("Anzeigename", value=user.get("display_name") or "")
# email2 = st.text_input("E-Mail", value=user.get("email") or "")
# role2 = st.selectbox("Rolle", ["user", "admin"], index=0 if user["role"]=="user" else 1)
# is_active2 = st.checkbox("Aktiv", value=bool(user["is_active"]))
# save = st.form_submit_button("Änderungen speichern")
# if save:
# update_user(int(selected_id), display_name2, email2, role2, is_active2)
# st.success("Gespeichert.")
# st.rerun()
# st.markdown("**Passwort zurücksetzen**")
# with st.form("reset_pw", clear_on_submit=True):
# new_pw = st.text_input("Neues Passwort", type="password")
# reset = st.form_submit_button("Passwort setzen")
# if reset:
# if not new_pw:
# st.error("Bitte ein Passwort eingeben.")
# else:
# set_password(int(selected_id), new_pw)
# st.success("Passwort aktualisiert.")
# st.markdown("**Löschen**")
# confirm = st.checkbox("Ich möchte diesen Benutzer wirklich löschen.")
# if st.button("Benutzer löschen", disabled=not confirm):
# delete_user(int(selected_id))
# st.success("Benutzer gelöscht.")
# st.rerun()
import streamlit as st
from auth_runtime import require_login
from ui.sidebar import build_sidebar
from auth import create_user
from pathlib import Path
from tools.load_css import load_css
from app_db.app_db import get_list, send_cmd
from ui.selectboxes import get_roles, get_id
import bcrypt
DASH_NAME = Path(__file__).stem # Hier muss die dash_id aus der DB stehen -> wird gegen die session_state geprüft (User-Berechtigung)
load_css()
st.set_page_config(page_title="Co-App Benutzer", page_icon=":material/person:", layout="wide", initial_sidebar_state="collapsed")
authenticator = require_login()
st.session_state["authenticator"] = authenticator
def sidebar():
fullname = st.session_state.get("fullname")
role_text = st.session_state.get("role_text")
with st.sidebar:
st.logo("app/images/GMN_Logo_neu_rgb.png", size="small")
st.markdown(f"**{fullname}** ({role_text})")
col1, col2 = st.columns([2,2])
with col1:
authenticator.logout("Logout")
with col2:
if st.button("Home", use_container_width=True, icon=":material/home:"):
st.switch_page("pages/home.py")
user()
@st.dialog("Benutzer anlegen")
def dialog_create_user():
txt_username = st.text_input("Benutzername")
txt_firstname = st.text_input("Vorname")
txt_lastname = st.text_input("Nachname")
txt_email = st.text_input("Email")
txt_pwd = st.text_input("Kennwort", type="password")
cmb_role = st.selectbox("Rolle", get_roles(), index=None)
if st.button("Save"):
if create_user(
username=txt_username,
firstname=txt_firstname,
lastname=txt_lastname,
email=txt_email,
role_id=get_id(cmb_role),
password=txt_pwd
):
st.session_state.save_msg = f"✅ Benutzer '{txt_username}' erfolgreich gespeichert"
else:
st.session_state.save_msg = "❌ Fehler beim Speichern"
st.rerun()
@st.dialog("Benutzer löschen")
def dialog_delete_user(id):
if id == None:
st.write("kein Benutzer ausgewählt")
else:
df = get_list("select username from users where id = ?",(id,))
username = df.iloc[0]["username"]
st.write(f"Der Benutzer {username} wird gelöscht! Sind Sie sicher?")
if st.button("Löschen"):
if username != "admin":
if send_cmd("delete from users where id = ?",(id,)):
st.session_state.delete_msg = f"✅ Benutzer '{username}' erfolgreich gelöscht!"
else:
st.session_state.delete_msg = f"❌ Benutzer '{username}' konnte nicht gelöscht werden!"
else:
st.session_state.delete_msg = f"❌ Benutzer '{username}' darf nicht gelöscht werden!"
st.rerun()
@st.dialog("Benutzer bearbeiten")
def dialog_modify_user(id):
if id == None:
st.write("kein Benutzer ausgewählt")
else:
sql = """
select
u.id,
u.username as user, -- ACHTUNG: nicht mit username arbeiten, da Überschneidung in sessionstate!!
u.firstname,
u.lastname,
u.email,
u.role_id || ' | ' || r.role_text as role,
r.role_text,
u.new_pwd,
u.active
from
users u
left join roles r
on u.role_id = r.role_id
where u.id = ?
"""
df = get_list(sql,(id,))
# df = get_list("select username from users where id = ?",(id,))
# st.session_state.orig_user_data = df
df_roles = get_roles()
roles = df_roles["text"].tolist()
role = df.iloc[0]["role"]
try:
idx = roles.index(role)
except:
idx = None
txt_username = st.text_input(label="Benutzername", value=df.iloc[0]["user"])
txt_firstname = st.text_input(label="Vorname", value=df.iloc[0]["firstname"])
txt_lastname = st.text_input(label="Nachname", value=df.iloc[0]["lastname"])
txt_email = st.text_input(label="Email", value=df.iloc[0]["email"])
txt_pwd = st.text_input(label="Passwort", placeholder="Neues Passwort eingeben", type="password")
new_pwd = st.checkbox(label="Neues Passwort", value=df.iloc[0]["new_pwd"])
cmb_role = st.selectbox(label="Rolle", options=roles, placeholder="Rolle auswählen", index=idx)
if st.button("Save"):
pw_hash = bcrypt.hashpw(txt_pwd.encode("utf-8"), bcrypt.gensalt()).decode("utf-8")
if txt_pwd and txt_pwd.strip():
sql = """
update users set
username = ?,
firstname = ?,
lastname = ?,
email = ?,
password_hash = ?,
new_pwd = ?,
role_id = ?
where id = ?
"""
params = (txt_username, txt_firstname, txt_lastname, txt_email, pw_hash, new_pwd, get_id(cmb_role), id)
# send_cmd(sql,(txt_username, txt_firstname, txt_lastname, txt_email, pw_hash, new_pwd, get_id(cmb_role), id))
else:
sql = """
update users set
username = ?,
firstname = ?,
lastname = ?,
email = ?,
new_pwd = ?,
role_id = ?
where id = ?
"""
params = (txt_username, txt_firstname, txt_lastname, txt_email, new_pwd, get_id(cmb_role), id)
# send_cmd(sql,(txt_username, txt_firstname, txt_lastname, txt_email, new_pwd, get_id(cmb_role), id))
print (params)
if send_cmd(sql, params):
st.session_state.save_msg = f"✅ Benutzer '{txt_username}' erfolgreich geändert"
else:
st.session_state.save_msg = "❌ Fehler beim Speichern"
st.rerun()
def user():
if "selected_user_id" not in st.session_state:
st.session_state.selected_user_id = None
tab_user, tab_role, tab_permission = st.tabs(["Benutzer", "Rollen", "Berechtigungen"])
#--------------------------------------------------------------------------------------------------
# Benutzerverwaltung
#--------------------------------------------------------------------------------------------------
with tab_user:
df = get_list("""
select
u.id,
u.username,
u.firstname,
u.lastname,
u.role_id || ' | ' || r.role_text as role,
u.new_pwd,
u.active
from
users u
left join roles r
on u.role_id = r.role_id
""")
col_find_user, col_create_user, col_modify_user, col_delete_user = st.columns([3,2,2,2], vertical_alignment="bottom")
with col_find_user:
txt_search = st.text_input(label="Suche", label_visibility="hidden", placeholder="Benutzer, Vorname, ...", icon=":material/search:")
with col_create_user:
if st.button(label="Benutzer anlegen", use_container_width=True, icon=":material/person_add:"):
dialog_create_user()
if "save_msg" in st.session_state:
st.toast(st.session_state.save_msg)
del st.session_state.save_msg
with col_modify_user:
if st.button(label="Benutzer bearbeiten", use_container_width=True, icon=":material/person:"):
if not st.session_state.selected_user_id is None:
dialog_modify_user(st.session_state.selected_user_id)
else:
st.toast("❌ Bitte erst eine Zeile auswählen")
if "save_msg" in st.session_state:
st.toast(st.session_state.save_msg)
del st.session_state.save_msg
with col_delete_user:
if st.button(label="Benutzer löschen", use_container_width=True, icon=":material/person_remove:"):
if not st.session_state.selected_user_id is None:
dialog_delete_user(st.session_state.selected_user_id)
else:
st.toast("❌ Bitte erst eine Zeile auswählen")
if "delete_msg" in st.session_state:
st.toast(st.session_state.delete_msg)
del st.session_state.delete_msg
if txt_search.strip():
txt_search_norm = txt_search.strip().lower()
mask = (
df["username"].fillna("").str.lower().str.contains(txt_search_norm)
| df["firstname"].fillna("").str.lower().str.contains(txt_search_norm)
| df["lastname"].fillna("").str.lower().str.contains(txt_search_norm)
)
df_view = df.loc[mask].copy()
else:
df_view = df.copy()
event = st.dataframe(df_view,key="data", on_select="rerun", selection_mode="single-row")
rows = event.selection.rows
if rows:
row_idx = rows[0]
st.session_state.selected_user_id = int(df_view.iloc[row_idx]["id"])
else:
st.session_state.selected_user_id = None
if __name__ == "__main__":
sidebar()