feat: Nutzerverwaltung + CMDB + Wissensdatenbank (Grundgeruest)

This commit is contained in:
mscadm 2026-07-13 15:28:53 +00:00
parent b802d252ba
commit 8c089d4f67
1 changed files with 175 additions and 0 deletions

175
db.py
View File

@ -135,6 +135,36 @@ def email_exists(email):
return cur.fetchone() is not None return cur.fetchone() is not None
def list_users(tenant_id):
with get_conn() as conn:
with _dict_cursor(conn) as cur:
cur.execute(
"SELECT id, email, role, active, auth_source, created_at, last_login_at "
"FROM users WHERE tenant_id=%s ORDER BY email", (tenant_id,))
return cur.fetchall()
def get_user(tenant_id, user_id):
with get_conn() as conn:
with _dict_cursor(conn) as cur:
cur.execute(
"SELECT id, email, role, active, auth_source, created_at, last_login_at "
"FROM users WHERE tenant_id=%s AND id=%s", (tenant_id, user_id))
return cur.fetchone()
def set_user_role(tenant_id, user_id, role):
with get_conn() as conn:
with conn.cursor() as cur:
cur.execute("UPDATE users SET role=%s WHERE tenant_id=%s AND id=%s", (role, tenant_id, user_id))
def set_user_active(tenant_id, user_id, active):
with get_conn() as conn:
with conn.cursor() as cur:
cur.execute("UPDATE users SET active=%s WHERE tenant_id=%s AND id=%s", (active, tenant_id, user_id))
# ── Audit-Log ─────────────────────────────────────────────────────────────────── # ── Audit-Log ───────────────────────────────────────────────────────────────────
def log_audit(tenant_id, user_id, aktion, entity_typ=None, entity_id=None, details=None, ip=None): def log_audit(tenant_id, user_id, aktion, entity_typ=None, entity_id=None, details=None, ip=None):
with get_conn() as conn: with get_conn() as conn:
@ -321,3 +351,148 @@ def run_retention_cleanup():
finally: finally:
with conn.cursor() as cur: with conn.cursor() as cur:
cur.execute("SELECT pg_advisory_unlock(%s)", (_RETENTION_LOCK_KEY,)) cur.execute("SELECT pg_advisory_unlock(%s)", (_RETENTION_LOCK_KEY,))
# ── CMDB (Configuration Management Database) ─────────────────────────────────
def create_ci(tenant_id, name, ci_typ, status, beschreibung, attribute):
with get_conn() as conn:
with _dict_cursor(conn) as cur:
cur.execute(
"""INSERT INTO configuration_items
(tenant_id, name, ci_typ, status, beschreibung, attribute)
VALUES (%s,%s,%s,%s,%s,%s) RETURNING id""",
(tenant_id, name, ci_typ, status, beschreibung, json.dumps(attribute or {})),
)
return cur.fetchone()["id"]
def list_cis(tenant_id, ci_typ=None):
with get_conn() as conn:
with _dict_cursor(conn) as cur:
if ci_typ:
cur.execute(
"SELECT * FROM configuration_items WHERE tenant_id=%s AND ci_typ=%s ORDER BY name",
(tenant_id, ci_typ))
else:
cur.execute(
"SELECT * FROM configuration_items WHERE tenant_id=%s ORDER BY ci_typ, name",
(tenant_id,))
return cur.fetchall()
def get_ci(tenant_id, ci_id):
with get_conn() as conn:
with _dict_cursor(conn) as cur:
cur.execute(
"SELECT * FROM configuration_items WHERE tenant_id=%s AND id=%s",
(tenant_id, ci_id))
ci = cur.fetchone()
if not ci:
return None
ci = dict(ci)
cur.execute(
"""SELECT r.*, c.name AS to_name FROM ci_relationships r
JOIN configuration_items c ON c.id = r.to_ci_id
WHERE r.tenant_id=%s AND r.from_ci_id=%s ORDER BY r.id""",
(tenant_id, ci_id))
ci["rel_out"] = cur.fetchall()
cur.execute(
"""SELECT r.*, c.name AS from_name FROM ci_relationships r
JOIN configuration_items c ON c.id = r.from_ci_id
WHERE r.tenant_id=%s AND r.to_ci_id=%s ORDER BY r.id""",
(tenant_id, ci_id))
ci["rel_in"] = cur.fetchall()
return ci
def update_ci(tenant_id, ci_id, name, ci_typ, status, beschreibung, attribute):
with get_conn() as conn:
with conn.cursor() as cur:
cur.execute(
"""UPDATE configuration_items SET name=%s, ci_typ=%s, status=%s,
beschreibung=%s, attribute=%s, updated_at=now()
WHERE tenant_id=%s AND id=%s""",
(name, ci_typ, status, beschreibung, json.dumps(attribute or {}), tenant_id, ci_id),
)
def delete_ci(tenant_id, ci_id):
with get_conn() as conn:
with conn.cursor() as cur:
cur.execute("DELETE FROM configuration_items WHERE tenant_id=%s AND id=%s", (tenant_id, ci_id))
def create_ci_relationship(tenant_id, from_ci_id, to_ci_id, beziehungs_typ):
with get_conn() as conn:
with _dict_cursor(conn) as cur:
cur.execute(
"""INSERT INTO ci_relationships (tenant_id, from_ci_id, to_ci_id, beziehungs_typ)
VALUES (%s,%s,%s,%s) RETURNING id""",
(tenant_id, from_ci_id, to_ci_id, beziehungs_typ),
)
return cur.fetchone()["id"]
def delete_ci_relationship(tenant_id, rel_id):
with get_conn() as conn:
with conn.cursor() as cur:
cur.execute("DELETE FROM ci_relationships WHERE tenant_id=%s AND id=%s", (tenant_id, rel_id))
# ── Wissensdatenbank ──────────────────────────────────────────────────────────
def create_kb_article(tenant_id, titel, kategorie, inhalt, tags, autor_user_id):
with get_conn() as conn:
with _dict_cursor(conn) as cur:
cur.execute(
"""INSERT INTO kb_articles (tenant_id, titel, kategorie, inhalt, tags, autor_user_id)
VALUES (%s,%s,%s,%s,%s,%s) RETURNING id""",
(tenant_id, titel, kategorie, inhalt, tags, autor_user_id),
)
return cur.fetchone()["id"]
def list_kb_articles(tenant_id, kategorie=None, q=None):
with get_conn() as conn:
with _dict_cursor(conn) as cur:
sql = """SELECT k.*, u.email AS autor_email FROM kb_articles k
LEFT JOIN users u ON u.id = k.autor_user_id
WHERE k.tenant_id=%s"""
params = [tenant_id]
if kategorie:
sql += " AND k.kategorie=%s"
params.append(kategorie)
if q:
sql += " AND (k.titel ILIKE %s OR k.inhalt ILIKE %s OR k.tags ILIKE %s)"
like = "%%%s%%" % q
params += [like, like, like]
sql += " ORDER BY k.updated_at DESC"
cur.execute(sql, params)
return cur.fetchall()
def get_kb_article(tenant_id, article_id):
with get_conn() as conn:
with _dict_cursor(conn) as cur:
cur.execute(
"""SELECT k.*, u.email AS autor_email FROM kb_articles k
LEFT JOIN users u ON u.id = k.autor_user_id
WHERE k.tenant_id=%s AND k.id=%s""",
(tenant_id, article_id))
return cur.fetchone()
def update_kb_article(tenant_id, article_id, titel, kategorie, inhalt, tags):
with get_conn() as conn:
with conn.cursor() as cur:
cur.execute(
"""UPDATE kb_articles SET titel=%s, kategorie=%s, inhalt=%s, tags=%s, updated_at=now()
WHERE tenant_id=%s AND id=%s""",
(titel, kategorie, inhalt, tags, tenant_id, article_id),
)
def delete_kb_article(tenant_id, article_id):
with get_conn() as conn:
with conn.cursor() as cur:
cur.execute("DELETE FROM kb_articles WHERE tenant_id=%s AND id=%s", (tenant_id, article_id))