diff --git a/app/app_db/app.db b/app/app_db/app.db index 74f37a8..d03e189 100644 Binary files a/app/app_db/app.db and b/app/app_db/app.db differ diff --git a/app/app_db/app_db.py b/app/app_db/app_db.py index 5386aa7..6ef050c 100644 --- a/app/app_db/app_db.py +++ b/app/app_db/app_db.py @@ -14,4 +14,5 @@ def get_list(sql, params=None): conn = get_conn() df = pd.read_sql_query(sql, conn, params=params) conn.close() - return df \ No newline at end of file + return df + diff --git a/app/auth.py b/app/auth.py index 37ff279..bb2ec7f 100644 --- a/app/auth.py +++ b/app/auth.py @@ -2,7 +2,7 @@ from contextlib import closing import bcrypt -from app_db.app_db import get_conn +from app_db.app_db import get_conn, get_list # --------------------------------------------------------------------------- @@ -35,7 +35,7 @@ def create_user( # --------------------------------------------------------------------------- -# Benutzer überprüfen (z.B. für deine alte Streamlit-Login-Maske) +# Benutzer überprüfen # --------------------------------------------------------------------------- def verify_user(username: str, password: str): @@ -84,6 +84,60 @@ def get_fullname_for_user(username: str) -> str: ).fetchone() return row[0] if row else "user" +# --------------------------------------------------------------------------- +# Sidebar-Einträge für den Benutzer +# --------------------------------------------------------------------------- + +def get_sidebar(role_text: str, username: str): + if role_text == "admin": + sql = """ + select + g.group_id, + g.group_text, + d.dash_id, + d.dash_text, + d.page_file, + d.dash_type + from + groups g + left join dashboards d + on g.group_id = d.group_id + where + g.active = 1 + and d.active = 1 + """ + else: + sql = """ + SELECT + d.group_id, + g.group_text, + p.dash_id, + d.dash_text, + d.page_file, + d.dash_type + FROM + users u + left join permissions p + on u.role_id = p.role_id + left join dashboards d + on p.dash_id = d.dash_id + left join groups g + on d.group_id = g.group_id + where + u.active = 1 + and g.active = 1 + and d.active = 1 + and p.active = 1 + and u.username = ? + order by + g.order_no, + d.order_no + """ + params = (username,) if "?" in sql else None + df = get_list(sql, params) + + return df + # --------------------------------------------------------------------------- # Credential-Lader für streamlit-authenticator # --------------------------------------------------------------------------- diff --git a/app/auth_runtime.py b/app/auth_runtime.py index 8015909..98679d2 100644 --- a/app/auth_runtime.py +++ b/app/auth_runtime.py @@ -10,7 +10,7 @@ def get_authenticator(): with open("config/auth.yaml", "r", encoding="utf-8") as f: base_config = yaml.load(f, Loader=SafeLoader) - db_creds = load_credentials_from_db() + db_creds = load_credentials_from_db() # Hier wird name, email und password geladen base_config["credentials"] = db_creds authenticator = stauth.Authenticate( diff --git a/app/dashboards/Benutzer.py b/app/dashboards/Benutzer.py deleted file mode 100644 index c2a9966..0000000 --- a/app/dashboards/Benutzer.py +++ /dev/null @@ -1,45 +0,0 @@ - -import streamlit as st -from auth_runtime import require_login -from ui.sidebar import build_sidebar, hide_sidebar_if_logged_out -from auth import get_fullname_for_user - -hide_sidebar_if_logged_out() - -st.set_page_config(page_title="Co-App Home", page_icon="🏠") - -authenticator = require_login() -st.session_state["authenticator"] = authenticator - -build_sidebar() - -def render(username: str, role: str): - st.title("Benutzerverwaltung") - - with st.expander("Neuen Nutzer anlegen"): - new_u = st.text_input("Neuer Username", key="new_u") - new_fname = st.text_input("Vorname", key="new_fname") - new_lname = st.text_input("Nachname", key="new_lname") - new_email = st.text_input("E-Mail", key="new_email") - new_p = st.text_input("Neues Passwort", type="password", key="new_p") - new_role = st.selectbox("Rolle", ["user", "admin"], key="new_role") - - if st.button("Anlegen"): - if new_u and new_p: - ok = create_user( - new_u.strip(), - new_p, - new_role, - new_email.strip() or None, - new_fname.strip() or None, - new_lname.strip() or None, - ) - st.success("Nutzer angelegt.") if ok else st.error( - "Username bereits vorhanden oder Fehler." - ) - else: - st.warning("Bitte Username und Passwort eingeben.") - - st.subheader("Dein Bereich") - st.write(f"Personalisierter Content für **{username}**.") - diff --git a/app/dashboards/__init__.py b/app/dashboards/__init__.py deleted file mode 100644 index a56a9c6..0000000 --- a/app/dashboards/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -import importlib - -def get_dashboard_renderer(code: str): - """ - Liefert die passende Render-Funktion zum Dashboard-Code. - - "home" -> interne Funktion home_dashboard - - alles andere -> Modul app.dashboards. mit Funktion render(username, role) - """ - if code == "home": - return home_dashboard - - module_name = f"app.dashboards.{code}" - try: - module = importlib.import_module(module_name) - except ModuleNotFoundError: - # Zum Debuggen: - st.error(f"Modul '{module_name}' wurde nicht gefunden.") - return None - - if not hasattr(module, "render"): - st.error(f"Modul '{module_name}' hat keine Funktion render().") - return None - - return module.render diff --git a/app/dashboards/home.py b/app/dashboards/home.py deleted file mode 100644 index 39130cc..0000000 --- a/app/dashboards/home.py +++ /dev/null @@ -1,46 +0,0 @@ -import streamlit as st -from auth import create_user, get_fullname_for_user, get_role_for_user -from ui.sidebar import build_sidebar - -build_sidebar - -st.header("Controlling-Portal") -st.info(f"Willkommen, {username}!") - - - - - - - - - # if role == "admin": - # st.subheader("Admin-Bereich") - # st.write("Nur Admins sehen das hier.") - - # with st.expander("Neuen Nutzer anlegen"): - # new_u = st.text_input("Neuer Username", key="new_u") - # new_fname = st.text_input("Vorname", key="new_fname") - # new_lname = st.text_input("Nachname", key="new_lname") - # new_email = st.text_input("E-Mail", key="new_email") - # new_p = st.text_input("Neues Passwort", type="password", key="new_p") - # new_role = st.selectbox("Rolle", ["user", "admin"], key="new_role") - - # if st.button("Anlegen"): - # if new_u and new_p: - # ok = create_user( - # new_u.strip(), - # new_p, - # new_role, - # new_email.strip() or None, - # new_fname.strip() or None, - # new_lname.strip() or None, - # ) - # st.success("Nutzer angelegt.") if ok else st.error( - # "Username bereits vorhanden oder Fehler." - # ) - # else: - # st.warning("Bitte Username und Passwort eingeben.") - - # st.subheader("Dein Bereich") - # st.write(f"Personalisierter Content für **{username}**.") diff --git a/app/main.py b/app/main.py index ab63be8..232b9aa 100644 --- a/app/main.py +++ b/app/main.py @@ -2,31 +2,54 @@ import streamlit as st import logging from logging_config import setup_logging from version import __version__ +from auth import get_role_for_user, get_fullname_for_user, get_sidebar from auth_runtime import require_login from ui.sidebar import build_sidebar import os +from app_db.app_db import get_list APP_ENV = os.environ.get("APP_ENV", "dev") logger = setup_logging(APP_ENV) -#logger.info(f"Starting migration - APP-Version {__version__}") logger = logging.getLogger(__name__) def main(): st.set_page_config( - page_title=f"Co-App Start - V{__version__}", + page_title=f"Co-App Home - V{__version__}", page_icon="🔒", layout="centered", ) authenticator = require_login() - # damit build_sidebar den authenticator findet: - st.session_state["authenticator"] = authenticator +#-------------------------------------------------------------------------------- +# Ab hier ist Benutzer angemeldet!! +#-------------------------------------------------------------------------------- + + # Alles was man so braucht in der App wird in session_state abgelegt + + # zuerst den authenticator holen ... + st.session_state["authenticator"] = authenticator + # ... dann ist der name des users in der sesstion_state verfügbar! + + + # Ich suche mir erst mal alles zusammen, was ich dann in session_state speichern will ... + username = st.session_state.get("name") # wird duch authenticator gesetzt + role_text = get_role_for_user(username) + fullname = get_fullname_for_user(username) + sidebar = get_sidebar(role_text, username) + + # ... und lege es dann im session_state ab. + st.session_state["role_text"] = role_text + st.session_state["fullname"] = fullname + st.session_state["df_sidebar"] = sidebar + build_sidebar() st.header("Controlling-Portal") st.info(f"Willkommen, {st.session_state.get('username')}!") + st.text("Hier könnte eine Nachricht für den Benutzer stehen") + if __name__ == "__main__": main() \ No newline at end of file diff --git a/app/pages/costobjects.py b/app/pages/costobjects.py index 12c7ea5..065a5bf 100644 --- a/app/pages/costobjects.py +++ b/app/pages/costobjects.py @@ -2,6 +2,16 @@ import streamlit as st import pandas as pd from data.scriptloader import get_sql from data.db import get_conn +from auth_runtime import require_login +from ui.sidebar import build_sidebar, hide_sidebar_if_logged_out +from auth import get_fullname_for_user + +hide_sidebar_if_logged_out() + +st.set_page_config(page_title="Co-App Home", page_icon="🏠") + +authenticator = require_login() +st.session_state["authenticator"] = authenticator diff --git a/app/pages/home.py b/app/pages/home.py index 3a973db..7c9dcab 100644 --- a/app/pages/home.py +++ b/app/pages/home.py @@ -10,8 +10,9 @@ st.set_page_config(page_title="Co-App Home", page_icon="🏠") authenticator = require_login() st.session_state["authenticator"] = authenticator -build_sidebar() +#build_sidebar() username = st.session_state.get("username") st.header("Controlling-Portal") -st.info(f"Willkommen, {get_fullname_for_user(username)}!") \ No newline at end of file +st.info(f"Willkommen, {get_fullname_for_user(username)}!") +st.markdown("**Hier könnte eine Hinweistext für den Benutzer stehen**") \ No newline at end of file diff --git a/app/pages/user.py b/app/pages/user.py index 0dd9ae1..29963e8 100644 --- a/app/pages/user.py +++ b/app/pages/user.py @@ -2,16 +2,25 @@ import streamlit as st from auth_runtime import require_login from ui.sidebar import hide_sidebar_if_logged_out from auth import create_user +from pathlib import Path +from tools.check_permission import check + +DASH_NAME = Path(__file__).stem # Hier muss die dash_id aus der DB stehen -> wird gegen die session_state geprüft (User-Berechtigung) + + hide_sidebar_if_logged_out() -st.set_page_config(page_title="Co-App Home", page_icon="🏠") +st.set_page_config(page_title="Co-App Benutzer", page_icon="🏠") authenticator = require_login() -st.session_state["authenticator"] = authenticator username = st.session_state.get("username") +df = st.session_state.get("df_sidebar") -# build_sidebar() +if check(df,DASH_NAME) == False: + st.markdown("**FEHLER**") + st.error("Die Seite kann nicht angezeigt werden - keine Berechtigung!") + st.stop() st.title("Benutzerverwaltung") diff --git a/app/tools/check_permission.py b/app/tools/check_permission.py new file mode 100644 index 0000000..bc59e4a --- /dev/null +++ b/app/tools/check_permission.py @@ -0,0 +1,27 @@ +import streamlit as st +from auth_runtime import require_login +from auth import get_sidebar, get_fullname_for_user, get_role_for_user + + + +def check(df, page_name): + if "df_sidebar" not in st.session_state: + # authenticator = require_login() + username = st.session_state.get("username") + role_text = get_role_for_user(username) + fullname = get_fullname_for_user(username) + df = get_sidebar(role_text, username) + + st.session_state["role_text"] = role_text + st.session_state["fullname"] = fullname + st.session_state["df_sidebar"] = df + + if df is None or df.empty: + return False # oder True – je nach gewünschtem Verhalten + + allowed = not df[ + (df["dash_type"] == "page") & + (df["page_file"] == page_name) + ].empty + + return True \ No newline at end of file diff --git a/app/ui/sidebar.py b/app/ui/sidebar.py index 8362646..eb3fe26 100644 --- a/app/ui/sidebar.py +++ b/app/ui/sidebar.py @@ -11,64 +11,18 @@ def build_sidebar(): return authenticator = st.session_state.get("authenticator") - username = st.session_state.get("username") + username = st.session_state.get("name") + role_text = st.session_state.get("role_text") + fullname = st.session_state.get("fullname") if not authenticator or not username: return - role = get_role_for_user(username) - fullname = get_fullname_for_user(username) - - if role == "admin": - sql = """ - select - g.group_id, - g.group_text, - d.dash_id, - d.dash_text, - d.page_file, - d.dash_type - from - groups g - left join dashboards d - on g.group_id = d.group_id - where - g.active = 1 - and d.active = 1 - """ - else: - sql = """ - SELECT - d.group_id, - g.group_text, - p.dash_id, - d.dash_text, - d.page_file, - d.dash_type - FROM - users u - left join permissions p - on u.role_id = p.role_id - left join dashboards d - on p.dash_id = d.dash_id - left join groups g - on d.group_id = g.group_id - where - u.active = 1 - and g.active = 1 - and d.active = 1 - and p.active = 1 - and u.username = ? - order by - g.order_no, - d.order_no - """ - params = (username,) if "?" in sql else None - df = get_list(sql, params) + df = st.session_state.get("df_sidebar") with st.sidebar: st.logo("app/images/GMN_Logo_neu_rgb.png", size="small") - st.write(f"**{fullname}** ({role})") + st.markdown(f"**{fullname}** ({role_text})") col1, col2 = st.columns(2) with col1: @@ -81,32 +35,6 @@ def build_sidebar(): st.divider() st.markdown("## Menü") - # for group_text, df_group in df.groupby("group_text"): - # with st.expander(group_text, expanded=False): - # for _, row in df_group.iterrows(): - # dash_type = row.get("dash_type") - # page_file = row.get("page_file") - # label = row.get("dash_text", "") - # print(dash_type, page_file, label) - # # 1) echte Streamlit-Page - # if dash_type == "page" and isinstance(page_file, str) and page_file.strip(): - # st.page_link( - # page_file, # z.B. "pages/umsatz.py" - # label=label, - # ) - - # # 2) externer Link (oder interner HTTP-Link) - # elif dash_type == "url" and isinstance(page_file, str) and page_file.strip(): - # st.markdown( - # f"[{label}]({page_file})", - # unsafe_allow_html=False, - # ) - - # # 3) Platzhalter / noch nicht implementiert - # else: - # st.write(f"▫️ {label} (in Vorbereitung)") - - # --- Suchfeld --- query = st.text_input("Menü-Suche", "", placeholder="z.B. Umsatz, Kosten, User ...") query = query.strip() @@ -145,7 +73,7 @@ def build_sidebar(): # Streamlit-Page if dash_type == "page" and isinstance(page_file, str) and page_file.strip(): - st.page_link(page_file, label=label) + st.page_link(f"pages/{page_file}.py", label=label) # Externer Link elif dash_type == "url" and isinstance(page_file, str) and page_file.strip():