Extend admin for websites/scripts and surface links
This commit is contained in:
@@ -18,6 +18,40 @@ def _require_admin():
|
||||
return user, None
|
||||
|
||||
|
||||
def _ensure_tables(cur):
|
||||
cur.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
username VARCHAR(50) NOT NULL UNIQUE,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
role VARCHAR(20) NOT NULL
|
||||
)
|
||||
"""
|
||||
)
|
||||
cur.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS websites (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
url VARCHAR(255) NOT NULL,
|
||||
description VARCHAR(255) DEFAULT ''
|
||||
)
|
||||
"""
|
||||
)
|
||||
cur.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS scripts (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
description VARCHAR(255) DEFAULT '',
|
||||
content TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
@admin_bp.route("/api/admin/users", methods=["GET"])
|
||||
def list_users():
|
||||
_, err = _require_admin()
|
||||
@@ -27,6 +61,7 @@ def list_users():
|
||||
cfg = load_config()
|
||||
conn = connect(**cfg)
|
||||
cur = conn.cursor(dictionary=True)
|
||||
_ensure_tables(cur)
|
||||
cur.execute("SELECT id, username, role FROM users ORDER BY username ASC")
|
||||
users = cur.fetchall()
|
||||
cur.close()
|
||||
@@ -52,6 +87,7 @@ def create_user():
|
||||
cfg = load_config()
|
||||
conn = connect(**cfg)
|
||||
cur = conn.cursor(dictionary=True)
|
||||
_ensure_tables(cur)
|
||||
cur.execute("SELECT id FROM users WHERE username=%s", (username,))
|
||||
if cur.fetchone():
|
||||
cur.close()
|
||||
@@ -86,6 +122,7 @@ def update_user(user_id):
|
||||
cfg = load_config()
|
||||
conn = connect(**cfg)
|
||||
cur = conn.cursor()
|
||||
_ensure_tables(cur)
|
||||
if role:
|
||||
cur.execute("UPDATE users SET role=%s WHERE id=%s", (role, user_id))
|
||||
if password:
|
||||
@@ -112,6 +149,7 @@ def delete_user(user_id):
|
||||
cfg = load_config()
|
||||
conn = connect(**cfg)
|
||||
cur = conn.cursor()
|
||||
_ensure_tables(cur)
|
||||
# Schutz: Admin darf sich nicht selbst löschen
|
||||
cur.execute("SELECT username FROM users WHERE id=%s", (user_id,))
|
||||
row = cur.fetchone()
|
||||
@@ -133,3 +171,213 @@ def delete_user(user_id):
|
||||
except Exception as e:
|
||||
logger.error(f"[Admin delete_user] {e}")
|
||||
return jsonify({"message": "Serverfehler"}), 500
|
||||
|
||||
|
||||
# ---------- Websites (Admin CRUD) ----------
|
||||
|
||||
@admin_bp.route("/api/admin/websites", methods=["GET"])
|
||||
def list_websites_admin():
|
||||
_, err = _require_admin()
|
||||
if err:
|
||||
return err
|
||||
try:
|
||||
cfg = load_config()
|
||||
conn = connect(**cfg)
|
||||
cur = conn.cursor(dictionary=True)
|
||||
_ensure_tables(cur)
|
||||
cur.execute("SELECT id, name, url, description FROM websites ORDER BY name ASC")
|
||||
rows = cur.fetchall()
|
||||
cur.close()
|
||||
conn.close()
|
||||
return jsonify(rows)
|
||||
except Exception as e:
|
||||
logger.error(f"[Admin list_websites] {e}")
|
||||
return jsonify({"message": "Serverfehler"}), 500
|
||||
|
||||
|
||||
@admin_bp.route("/api/admin/websites", methods=["POST"])
|
||||
def create_website():
|
||||
_, err = _require_admin()
|
||||
if err:
|
||||
return err
|
||||
data = request.get_json() or {}
|
||||
name = data.get("name", "").strip()
|
||||
url = data.get("url", "").strip()
|
||||
description = data.get("description", "").strip()
|
||||
if not name or not url:
|
||||
return jsonify({"message": "Name und URL erforderlich"}), 400
|
||||
try:
|
||||
cfg = load_config()
|
||||
conn = connect(**cfg)
|
||||
cur = conn.cursor()
|
||||
_ensure_tables(cur)
|
||||
cur.execute(
|
||||
"INSERT INTO websites (name, url, description) VALUES (%s, %s, %s)",
|
||||
(name, url, description),
|
||||
)
|
||||
conn.commit()
|
||||
new_id = cur.lastrowid
|
||||
cur.close()
|
||||
conn.close()
|
||||
return jsonify({"id": new_id, "name": name, "url": url, "description": description}), 201
|
||||
except Exception as e:
|
||||
logger.error(f"[Admin create_website] {e}")
|
||||
return jsonify({"message": "Serverfehler"}), 500
|
||||
|
||||
|
||||
@admin_bp.route("/api/admin/websites/<int:item_id>", methods=["PUT"])
|
||||
def update_website(item_id):
|
||||
_, err = _require_admin()
|
||||
if err:
|
||||
return err
|
||||
data = request.get_json() or {}
|
||||
try:
|
||||
cfg = load_config()
|
||||
conn = connect(**cfg)
|
||||
cur = conn.cursor()
|
||||
_ensure_tables(cur)
|
||||
cur.execute(
|
||||
"UPDATE websites SET name=%s, url=%s, description=%s WHERE id=%s",
|
||||
(data.get("name"), data.get("url"), data.get("description", ""), item_id),
|
||||
)
|
||||
conn.commit()
|
||||
cur.close()
|
||||
conn.close()
|
||||
return jsonify({"message": "Aktualisiert"}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"[Admin update_website] {e}")
|
||||
return jsonify({"message": "Serverfehler"}), 500
|
||||
|
||||
|
||||
@admin_bp.route("/api/admin/websites/<int:item_id>", methods=["DELETE"])
|
||||
def delete_website(item_id):
|
||||
_, err = _require_admin()
|
||||
if err:
|
||||
return err
|
||||
try:
|
||||
cfg = load_config()
|
||||
conn = connect(**cfg)
|
||||
cur = conn.cursor()
|
||||
_ensure_tables(cur)
|
||||
cur.execute("DELETE FROM websites WHERE id=%s", (item_id,))
|
||||
conn.commit()
|
||||
cur.close()
|
||||
conn.close()
|
||||
return jsonify({"message": "Gelöscht"}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"[Admin delete_website] {e}")
|
||||
return jsonify({"message": "Serverfehler"}), 500
|
||||
|
||||
|
||||
# ---------- Scripts (Admin CRUD) ----------
|
||||
|
||||
@admin_bp.route("/api/admin/scripts", methods=["GET"])
|
||||
def list_scripts_admin():
|
||||
_, err = _require_admin()
|
||||
if err:
|
||||
return err
|
||||
try:
|
||||
cfg = load_config()
|
||||
conn = connect(**cfg)
|
||||
cur = conn.cursor(dictionary=True)
|
||||
_ensure_tables(cur)
|
||||
cur.execute("SELECT id, name, description, created_at FROM scripts ORDER BY created_at DESC")
|
||||
rows = cur.fetchall()
|
||||
cur.close()
|
||||
conn.close()
|
||||
return jsonify(rows)
|
||||
except Exception as e:
|
||||
logger.error(f"[Admin list_scripts] {e}")
|
||||
return jsonify({"message": "Serverfehler"}), 500
|
||||
|
||||
|
||||
@admin_bp.route("/api/admin/scripts", methods=["POST"])
|
||||
def create_script():
|
||||
_, err = _require_admin()
|
||||
if err:
|
||||
return err
|
||||
data = request.get_json() or {}
|
||||
name = data.get("name", "").strip()
|
||||
description = data.get("description", "").strip()
|
||||
content = data.get("content", "")
|
||||
if not name or not content:
|
||||
return jsonify({"message": "Name und Inhalt erforderlich"}), 400
|
||||
try:
|
||||
cfg = load_config()
|
||||
conn = connect(**cfg)
|
||||
cur = conn.cursor()
|
||||
_ensure_tables(cur)
|
||||
cur.execute(
|
||||
"INSERT INTO scripts (name, description, content) VALUES (%s, %s, %s)",
|
||||
(name, description, content),
|
||||
)
|
||||
conn.commit()
|
||||
new_id = cur.lastrowid
|
||||
cur.close()
|
||||
conn.close()
|
||||
return jsonify({"id": new_id, "name": name, "description": description}), 201
|
||||
except Exception as e:
|
||||
logger.error(f"[Admin create_script] {e}")
|
||||
return jsonify({"message": "Serverfehler"}), 500
|
||||
|
||||
|
||||
@admin_bp.route("/api/admin/scripts/<int:item_id>", methods=["DELETE"])
|
||||
def delete_script(item_id):
|
||||
_, err = _require_admin()
|
||||
if err:
|
||||
return err
|
||||
try:
|
||||
cfg = load_config()
|
||||
conn = connect(**cfg)
|
||||
cur = conn.cursor()
|
||||
_ensure_tables(cur)
|
||||
cur.execute("DELETE FROM scripts WHERE id=%s", (item_id,))
|
||||
conn.commit()
|
||||
cur.close()
|
||||
conn.close()
|
||||
return jsonify({"message": "Gelöscht"}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"[Admin delete_script] {e}")
|
||||
return jsonify({"message": "Serverfehler"}), 500
|
||||
|
||||
|
||||
# ---------- Public (logged-in) endpoints ----------
|
||||
|
||||
@admin_bp.route("/api/websites", methods=["GET"])
|
||||
def list_websites_public():
|
||||
user = verify_token()
|
||||
if not user:
|
||||
return jsonify({"message": "Nicht autorisiert"}), 401
|
||||
try:
|
||||
cfg = load_config()
|
||||
conn = connect(**cfg)
|
||||
cur = conn.cursor(dictionary=True)
|
||||
_ensure_tables(cur)
|
||||
cur.execute("SELECT id, name, url, description FROM websites ORDER BY name ASC")
|
||||
rows = cur.fetchall()
|
||||
cur.close()
|
||||
conn.close()
|
||||
return jsonify(rows)
|
||||
except Exception as e:
|
||||
logger.error(f"[Public list_websites] {e}")
|
||||
return jsonify({"message": "Serverfehler"}), 500
|
||||
|
||||
|
||||
@admin_bp.route("/api/scripts", methods=["GET"])
|
||||
def list_scripts_public():
|
||||
user = verify_token()
|
||||
if not user:
|
||||
return jsonify({"message": "Nicht autorisiert"}), 401
|
||||
try:
|
||||
cfg = load_config()
|
||||
conn = connect(**cfg)
|
||||
cur = conn.cursor(dictionary=True)
|
||||
_ensure_tables(cur)
|
||||
cur.execute("SELECT id, name, description, created_at FROM scripts ORDER BY created_at DESC")
|
||||
rows = cur.fetchall()
|
||||
cur.close()
|
||||
conn.close()
|
||||
return jsonify(rows)
|
||||
except Exception as e:
|
||||
logger.error(f"[Public list_scripts] {e}")
|
||||
return jsonify({"message": "Serverfehler"}), 500
|
||||
|
||||
Reference in New Issue
Block a user