new file: .gitignore
new file: README.md new file: database/schema.sql new file: paper-plugin/pom.xml new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/PaperLoggerPlugin.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/commands/MCLoggerCommand.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/database/DatabaseManager.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/BlockListener.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/EntityListener.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/InventoryListener.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/LuckPermsListener.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/PlayerChatCommandListener.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/PlayerDeathListener.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/PlayerMiscListener.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/PlayerSessionListener.java new file: paper-plugin/src/main/java/de/simolzimol/mclogger/paper/listeners/WorldListener.java new file: paper-plugin/src/main/resources/config.yml new file: paper-plugin/src/main/resources/plugin.yml new file: paper-plugin/target/classes/config.yml new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/PaperLoggerPlugin.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/commands/MCLoggerCommand$RsConsumer.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/commands/MCLoggerCommand.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/database/DatabaseManager$ThrowingRunnable.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/database/DatabaseManager.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/BlockListener.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/EntityListener.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/InventoryListener.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/LuckPermsListener.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/PlayerChatCommandListener.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/PlayerDeathListener.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/PlayerMiscListener.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/PlayerSessionListener.class new file: paper-plugin/target/classes/de/simolzimol/mclogger/paper/listeners/WorldListener.class new file: paper-plugin/target/classes/plugin.yml new file: paper-plugin/target/maven-archiver/pom.properties new file: paper-plugin/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file: paper-plugin/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file: paper-plugin/target/mclogger-paper-1.0.0.jar new file: paper-plugin/target/original-mclogger-paper-1.0.0.jar new file: velocity-plugin/pom.xml new file: velocity-plugin/src/main/java/de/simolzimol/mclogger/velocity/VelocityLoggerPlugin.java new file: velocity-plugin/src/main/java/de/simolzimol/mclogger/velocity/database/VelocityDatabaseManager.java new file: velocity-plugin/src/main/java/de/simolzimol/mclogger/velocity/listeners/VelocityEventListener.java new file: velocity-plugin/src/main/resources/velocity-config.yml new file: velocity-plugin/target/classes/de/simolzimol/mclogger/velocity/VelocityLoggerPlugin.class new file: velocity-plugin/target/classes/de/simolzimol/mclogger/velocity/database/VelocityDatabaseManager$ThrowingRunnable.class new file: velocity-plugin/target/classes/de/simolzimol/mclogger/velocity/database/VelocityDatabaseManager.class new file: velocity-plugin/target/classes/de/simolzimol/mclogger/velocity/listeners/VelocityEventListener.class new file: velocity-plugin/target/classes/velocity-config.yml new file: velocity-plugin/target/classes/velocity-plugin.json new file: velocity-plugin/target/maven-archiver/pom.properties new file: velocity-plugin/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file: velocity-plugin/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file: velocity-plugin/target/mclogger-velocity-1.0.0.jar new file: velocity-plugin/target/original-mclogger-velocity-1.0.0.jar new file: web/Dockerfile new file: web/app.py new file: web/blueprints/__init__.py new file: web/blueprints/auth.py new file: web/blueprints/group_admin.py new file: web/blueprints/panel.py new file: web/blueprints/site_admin.py new file: web/config.py new file: web/crypto.py new file: web/docker-compose.yml new file: web/panel_db.py new file: web/requirements.txt new file: web/static/css/style.css new file: web/static/js/main.js new file: web/templates/_pagination.html new file: web/templates/admin/base.html new file: web/templates/admin/dashboard.html new file: web/templates/admin/group_edit.html new file: web/templates/admin/group_members.html new file: web/templates/admin/groups.html new file: web/templates/admin/user_edit.html new file: web/templates/admin/users.html new file: web/templates/auth/admin_login.html new file: web/templates/auth/login.html new file: web/templates/base.html new file: web/templates/blocks.html new file: web/templates/chat.html new file: web/templates/commands.html new file: web/templates/dashboard.html new file: web/templates/deaths.html new file: web/templates/group_admin/base.html new file: web/templates/group_admin/dashboard.html new file: web/templates/group_admin/database.html new file: web/templates/group_admin/member_edit.html new file: web/templates/group_admin/members.html new file: web/templates/login.html new file: web/templates/panel/blocks.html new file: web/templates/panel/chat.html new file: web/templates/panel/commands.html new file: web/templates/panel/dashboard.html new file: web/templates/panel/deaths.html new file: web/templates/panel/no_db.html new file: web/templates/panel/perms.html new file: web/templates/panel/player_detail.html new file: web/templates/panel/players.html new file: web/templates/panel/proxy.html new file: web/templates/panel/server_events.html new file: web/templates/panel/sessions.html new file: web/templates/perms.html new file: web/templates/player_detail.html new file: web/templates/players.html new file: web/templates/proxy.html new file: web/templates/server_events.html new file: web/templates/sessions.html
This commit is contained in:
1
web/blueprints/__init__.py
Normal file
1
web/blueprints/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# blueprints/__init__.py
|
||||
93
web/blueprints/auth.py
Normal file
93
web/blueprints/auth.py
Normal file
@@ -0,0 +1,93 @@
|
||||
"""
|
||||
MCLogger – Authentifizierung
|
||||
Getrennte Login-Seiten für Site-Admins und normale Nutzer/Gruppen-Admins.
|
||||
"""
|
||||
import json
|
||||
from flask import Blueprint, render_template, request, redirect, url_for, session, flash
|
||||
from panel_db import check_login, get_user_groups
|
||||
|
||||
auth = Blueprint("auth", __name__)
|
||||
|
||||
|
||||
@auth.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
if session.get("user_id"):
|
||||
return redirect(url_for("panel.dashboard"))
|
||||
error = None
|
||||
if request.method == "POST":
|
||||
user = check_login(request.form.get("username", ""), request.form.get("password", ""))
|
||||
if user and user["is_site_admin"]:
|
||||
flash("Bitte nutze den Site-Admin-Login.", "warning")
|
||||
return redirect(url_for("auth.admin_login"))
|
||||
if user:
|
||||
groups = get_user_groups(user["id"])
|
||||
if not groups:
|
||||
error = "Du bist keiner Gruppe zugewiesen. Wende dich an einen Admin."
|
||||
else:
|
||||
_set_user_session(user, groups)
|
||||
return redirect(url_for("panel.dashboard"))
|
||||
else:
|
||||
error = "Falscher Benutzername oder Passwort."
|
||||
return render_template("auth/login.html", error=error)
|
||||
|
||||
|
||||
@auth.route("/admin/login", methods=["GET", "POST"])
|
||||
def admin_login():
|
||||
if session.get("is_site_admin"):
|
||||
return redirect(url_for("site_admin.dashboard"))
|
||||
error = None
|
||||
if request.method == "POST":
|
||||
user = check_login(request.form.get("username", ""), request.form.get("password", ""))
|
||||
if user and user["is_site_admin"]:
|
||||
session["user_id"] = user["id"]
|
||||
session["username"] = user["username"]
|
||||
session["is_site_admin"] = True
|
||||
session["group_id"] = None
|
||||
session["permissions"] = {}
|
||||
return redirect(url_for("site_admin.dashboard"))
|
||||
elif user:
|
||||
error = "Keine Site-Admin-Berechtigung."
|
||||
else:
|
||||
error = "Falscher Benutzername oder Passwort."
|
||||
return render_template("auth/admin_login.html", error=error)
|
||||
|
||||
|
||||
@auth.route("/logout")
|
||||
def logout():
|
||||
session.clear()
|
||||
return redirect(url_for("auth.login"))
|
||||
|
||||
|
||||
@auth.route("/switch-group/<int:group_id>")
|
||||
def switch_group(group_id):
|
||||
if not session.get("user_id") or session.get("is_site_admin"):
|
||||
return redirect(url_for("auth.login"))
|
||||
user_id = session["user_id"]
|
||||
groups = get_user_groups(user_id)
|
||||
target = next((g for g in groups if g["id"] == group_id), None)
|
||||
if not target:
|
||||
flash("Gruppe nicht gefunden oder kein Zugriff.", "danger")
|
||||
return redirect(url_for("panel.dashboard"))
|
||||
_apply_group(target)
|
||||
return redirect(url_for("panel.dashboard"))
|
||||
|
||||
|
||||
def _set_user_session(user, groups):
|
||||
session["user_id"] = user["id"]
|
||||
session["username"] = user["username"]
|
||||
session["is_site_admin"] = False
|
||||
_apply_group(groups[0]) # Erste Gruppe als Standard
|
||||
|
||||
|
||||
def _apply_group(group):
|
||||
raw = group.get("permissions")
|
||||
if isinstance(raw, str):
|
||||
perms = json.loads(raw)
|
||||
elif isinstance(raw, dict):
|
||||
perms = raw
|
||||
else:
|
||||
perms = {}
|
||||
session["group_id"] = group["id"]
|
||||
session["group_name"] = group["name"]
|
||||
session["role"] = group.get("role", "member")
|
||||
session["permissions"] = perms
|
||||
164
web/blueprints/group_admin.py
Normal file
164
web/blueprints/group_admin.py
Normal file
@@ -0,0 +1,164 @@
|
||||
"""
|
||||
MCLogger – Gruppen-Admin-Bereich
|
||||
Gruppen-Admins können ihre Mitglieder und MC-DB-Verbindung verwalten.
|
||||
"""
|
||||
import json
|
||||
from functools import wraps
|
||||
from flask import Blueprint, render_template, request, redirect, url_for, session, flash
|
||||
import panel_db as db
|
||||
|
||||
group_admin = Blueprint("group_admin", __name__, url_prefix="/group-admin")
|
||||
|
||||
ALL_PERMISSIONS = [
|
||||
("view_dashboard", "Dashboard"),
|
||||
("view_players", "Spieler"),
|
||||
("view_sessions", "Sessions"),
|
||||
("view_chat", "Chat"),
|
||||
("view_commands", "Commands"),
|
||||
("view_deaths", "Tode"),
|
||||
("view_blocks", "Block-Events"),
|
||||
("view_proxy", "Proxy-Events"),
|
||||
("view_server_events", "Server-Events"),
|
||||
("view_perms", "Berechtigungen"),
|
||||
]
|
||||
|
||||
|
||||
def group_admin_required(f):
|
||||
@wraps(f)
|
||||
def decorated(*args, **kwargs):
|
||||
if not session.get("user_id"):
|
||||
return redirect(url_for("auth.login"))
|
||||
if session.get("is_site_admin"):
|
||||
return redirect(url_for("site_admin.dashboard"))
|
||||
if session.get("role") != "admin":
|
||||
flash("Du hast keine Gruppen-Admin-Berechtigung.", "danger")
|
||||
return redirect(url_for("panel.dashboard"))
|
||||
return f(*args, **kwargs)
|
||||
return decorated
|
||||
|
||||
|
||||
@group_admin.route("/")
|
||||
@group_admin_required
|
||||
def dashboard():
|
||||
group_id = session["group_id"]
|
||||
group = db.get_group_by_id(group_id)
|
||||
members = db.get_group_members(group_id)
|
||||
has_db = db.has_db_configured(group_id)
|
||||
return render_template("group_admin/dashboard.html",
|
||||
group=group, members=members, has_db=has_db)
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# Mitglieder
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
@group_admin.route("/members")
|
||||
@group_admin_required
|
||||
def members():
|
||||
group_id = session["group_id"]
|
||||
group = db.get_group_by_id(group_id)
|
||||
members = db.get_group_members(group_id)
|
||||
all_users = db.list_all_users()
|
||||
member_ids = {m["id"] for m in members}
|
||||
non_members = [u for u in all_users if u["id"] not in member_ids and not u["is_site_admin"]]
|
||||
return render_template("group_admin/members.html",
|
||||
group=group, members=members, non_members=non_members,
|
||||
all_permissions=ALL_PERMISSIONS)
|
||||
|
||||
|
||||
@group_admin.route("/members/add", methods=["POST"])
|
||||
@group_admin_required
|
||||
def member_add():
|
||||
group_id = session["group_id"]
|
||||
user_id = request.form.get("user_id", type=int)
|
||||
role = request.form.get("role", "member")
|
||||
if user_id:
|
||||
db.add_group_member(user_id, group_id, role)
|
||||
flash("Mitglied hinzugefügt.", "success")
|
||||
return redirect(url_for("group_admin.members"))
|
||||
|
||||
|
||||
@group_admin.route("/members/<int:user_id>/edit", methods=["GET", "POST"])
|
||||
@group_admin_required
|
||||
def member_edit(user_id):
|
||||
group_id = session["group_id"]
|
||||
group = db.get_group_by_id(group_id)
|
||||
member = db.get_group_member(user_id, group_id)
|
||||
user = db.get_user_by_id(user_id)
|
||||
if not member or not user:
|
||||
flash("Mitglied nicht gefunden.", "danger")
|
||||
return redirect(url_for("group_admin.members"))
|
||||
|
||||
raw_perms = member.get("permissions")
|
||||
current_perms = json.loads(raw_perms) if isinstance(raw_perms, str) else (raw_perms or {})
|
||||
|
||||
if request.method == "POST":
|
||||
role = request.form.get("role", "member")
|
||||
new_perms = {key: (request.form.get(key) == "1") for key, _ in ALL_PERMISSIONS}
|
||||
db.update_member(user_id, group_id, role, new_perms)
|
||||
flash("Berechtigungen aktualisiert.", "success")
|
||||
return redirect(url_for("group_admin.members"))
|
||||
|
||||
return render_template("group_admin/member_edit.html",
|
||||
group=group, user=user, member=member,
|
||||
current_perms=current_perms, all_permissions=ALL_PERMISSIONS)
|
||||
|
||||
|
||||
@group_admin.route("/members/<int:user_id>/remove", methods=["POST"])
|
||||
@group_admin_required
|
||||
def member_remove(user_id):
|
||||
if user_id == session["user_id"]:
|
||||
flash("Du kannst dich nicht selbst entfernen.", "danger")
|
||||
else:
|
||||
db.remove_group_member(user_id, session["group_id"])
|
||||
flash("Mitglied entfernt.", "success")
|
||||
return redirect(url_for("group_admin.members"))
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# Datenbank-Konfiguration
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
@group_admin.route("/database", methods=["GET", "POST"])
|
||||
@group_admin_required
|
||||
def database():
|
||||
group_id = session["group_id"]
|
||||
group = db.get_group_by_id(group_id)
|
||||
has_db = db.has_db_configured(group_id)
|
||||
error = None
|
||||
|
||||
if request.method == "POST":
|
||||
host = request.form.get("host", "").strip()
|
||||
port = request.form.get("port", "3306").strip()
|
||||
user = request.form.get("user", "").strip()
|
||||
password = request.form.get("password", "")
|
||||
database_name = request.form.get("database", "").strip()
|
||||
|
||||
if not all([host, port, user, database_name]):
|
||||
error = "Host, Port, Benutzer und Datenbankname sind Pflichtfelder."
|
||||
else:
|
||||
try:
|
||||
# Verbindung testen
|
||||
import pymysql
|
||||
test = pymysql.connect(
|
||||
host=host, port=int(port), user=user,
|
||||
password=password, database=database_name,
|
||||
connect_timeout=5
|
||||
)
|
||||
test.close()
|
||||
db.set_group_db_creds(group_id, host, int(port), user, password, database_name)
|
||||
flash("Datenbankverbindung gespeichert und getestet ✓", "success")
|
||||
return redirect(url_for("group_admin.database"))
|
||||
except Exception as e:
|
||||
error = f"Verbindungstest fehlgeschlagen: {e}"
|
||||
|
||||
return render_template("group_admin/database.html",
|
||||
group=group, has_db=has_db, error=error)
|
||||
|
||||
|
||||
@group_admin.route("/database/delete", methods=["POST"])
|
||||
@group_admin_required
|
||||
def database_delete():
|
||||
db.delete_group_db_creds(session["group_id"])
|
||||
flash("Datenbankverbindung entfernt.", "success")
|
||||
return redirect(url_for("group_admin.database"))
|
||||
410
web/blueprints/panel.py
Normal file
410
web/blueprints/panel.py
Normal file
@@ -0,0 +1,410 @@
|
||||
"""
|
||||
MCLogger – Panel (MC-Daten)
|
||||
Zeigt die Minecraft-Logdaten der Gruppe an.
|
||||
Die Datenbankverbindung kommt aus den verschlüsselten Gruppen-Credentials.
|
||||
"""
|
||||
from functools import wraps
|
||||
from datetime import datetime
|
||||
from flask import Blueprint, render_template, request, redirect, url_for, session, flash, jsonify, abort
|
||||
import pymysql
|
||||
import pymysql.cursors
|
||||
import panel_db as pdb
|
||||
|
||||
panel = Blueprint("panel", __name__)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Hilfsfunktionen
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
|
||||
def login_required(f):
|
||||
@wraps(f)
|
||||
def decorated(*args, **kwargs):
|
||||
if not session.get("user_id"):
|
||||
return redirect(url_for("auth.login"))
|
||||
if session.get("is_site_admin") and not session.get("group_id"):
|
||||
return redirect(url_for("site_admin.dashboard"))
|
||||
if not session.get("group_id"):
|
||||
return redirect(url_for("auth.login"))
|
||||
return f(*args, **kwargs)
|
||||
return decorated
|
||||
|
||||
|
||||
def perm_required(perm):
|
||||
def decorator(f):
|
||||
@wraps(f)
|
||||
def wrapped(*args, **kwargs):
|
||||
if session.get("is_site_admin") or session.get("role") == "admin":
|
||||
return f(*args, **kwargs)
|
||||
perms = session.get("permissions", {})
|
||||
if not perms.get(perm, False):
|
||||
flash("Du hast keine Berechtigung, diese Seite zu sehen.", "danger")
|
||||
return redirect(url_for("panel.dashboard"))
|
||||
return f(*args, **kwargs)
|
||||
return wrapped
|
||||
return decorator
|
||||
|
||||
|
||||
def get_mc_db():
|
||||
"""Liefert eine Datenbankverbindung zur MC-Datenbank der aktuellen Gruppe."""
|
||||
group_id = session.get("group_id")
|
||||
if not group_id:
|
||||
abort(403)
|
||||
creds = pdb.get_group_db_creds(group_id)
|
||||
if not creds:
|
||||
abort(503)
|
||||
return pymysql.connect(
|
||||
host=creds["host"],
|
||||
port=creds["port"],
|
||||
user=creds["user"],
|
||||
password=creds["password"],
|
||||
database=creds["database"],
|
||||
charset="utf8mb4",
|
||||
cursorclass=pymysql.cursors.DictCursor,
|
||||
autocommit=True,
|
||||
connect_timeout=10,
|
||||
)
|
||||
|
||||
|
||||
def query(sql, args=None, fetchone=False):
|
||||
conn = get_mc_db()
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(sql, args or ())
|
||||
return cur.fetchone() if fetchone else cur.fetchall()
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
def query_paged(sql, count_sql, args=None, page=1, per_page=50):
|
||||
args = args or ()
|
||||
total_row = query(count_sql, args, fetchone=True)
|
||||
total = list(total_row.values())[0] if total_row else 0
|
||||
pages = max(1, (total + per_page - 1) // per_page)
|
||||
offset = (page - 1) * per_page
|
||||
rows = query(sql + f" LIMIT {per_page} OFFSET {offset}", args)
|
||||
return rows, total, pages
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Fehler-Handler wenn DB nicht konfiguriert
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
|
||||
@panel.errorhandler(503)
|
||||
def no_db(e):
|
||||
return render_template("panel/no_db.html"), 503
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Dashboard
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
|
||||
@panel.route("/")
|
||||
@login_required
|
||||
@perm_required("view_dashboard")
|
||||
def dashboard():
|
||||
group_id = session["group_id"]
|
||||
if not pdb.has_db_configured(group_id):
|
||||
return render_template("panel/no_db.html")
|
||||
try:
|
||||
stats = {
|
||||
"players_total": query("SELECT COUNT(*) AS c FROM players", fetchone=True)["c"],
|
||||
"sessions_today": query("SELECT COUNT(*) AS c FROM player_sessions WHERE login_time >= CURDATE()", fetchone=True)["c"],
|
||||
"chat_today": query("SELECT COUNT(*) AS c FROM player_chat WHERE timestamp >= CURDATE()", fetchone=True)["c"],
|
||||
"commands_today": query("SELECT COUNT(*) AS c FROM player_commands WHERE timestamp >= CURDATE()", fetchone=True)["c"],
|
||||
"blocks_today": query("SELECT COUNT(*) AS c FROM block_events WHERE timestamp >= CURDATE()", fetchone=True)["c"],
|
||||
"deaths_today": query("SELECT COUNT(*) AS c FROM player_deaths WHERE timestamp >= CURDATE()", fetchone=True)["c"],
|
||||
"proxy_events_today": query("SELECT COUNT(*) AS c FROM proxy_events WHERE timestamp >= CURDATE()", fetchone=True)["c"],
|
||||
}
|
||||
online = query("""
|
||||
SELECT p.username, ps.server_name, ps.login_time, ps.country
|
||||
FROM player_sessions ps
|
||||
JOIN players p ON p.uuid = ps.player_uuid
|
||||
WHERE ps.logout_time IS NULL
|
||||
ORDER BY ps.login_time DESC
|
||||
""")
|
||||
top_players = query("""
|
||||
SELECT username, total_playtime_sec
|
||||
FROM players ORDER BY total_playtime_sec DESC LIMIT 10
|
||||
""")
|
||||
death_causes = query("""
|
||||
SELECT cause, COUNT(*) AS cnt FROM player_deaths
|
||||
WHERE timestamp >= NOW() - INTERVAL 7 DAY
|
||||
GROUP BY cause ORDER BY cnt DESC LIMIT 8
|
||||
""")
|
||||
server_events = query("""
|
||||
SELECT timestamp, event_type, server_name, message
|
||||
FROM server_events
|
||||
WHERE timestamp >= NOW() - INTERVAL 24 HOUR
|
||||
ORDER BY timestamp DESC LIMIT 20
|
||||
""")
|
||||
except Exception as e:
|
||||
flash(f"Datenbankfehler: {e}", "danger")
|
||||
return render_template("panel/no_db.html")
|
||||
|
||||
return render_template("panel/dashboard.html",
|
||||
stats=stats, online=online, top_players=top_players,
|
||||
death_causes=death_causes, server_events=server_events)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Spieler
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
|
||||
@panel.route("/players")
|
||||
@login_required
|
||||
@perm_required("view_players")
|
||||
def players():
|
||||
search = request.args.get("q", "")
|
||||
page = max(1, request.args.get("page", 1, type=int))
|
||||
if search:
|
||||
base = "FROM players WHERE username LIKE %s"
|
||||
args = (f"%{search}%",)
|
||||
else:
|
||||
base = "FROM players WHERE 1"
|
||||
args = ()
|
||||
rows, total, pages = query_paged(
|
||||
f"SELECT * {base} ORDER BY last_seen DESC",
|
||||
f"SELECT COUNT(*) AS c {base}", args, page)
|
||||
return render_template("panel/players.html",
|
||||
players=rows, total=total, pages=pages, page=page, search=search)
|
||||
|
||||
|
||||
@panel.route("/players/<uuid>")
|
||||
@login_required
|
||||
@perm_required("view_players")
|
||||
def player_detail(uuid):
|
||||
player = query("SELECT * FROM players WHERE uuid = %s", (uuid,), fetchone=True)
|
||||
if not player:
|
||||
flash("Spieler nicht gefunden.", "danger")
|
||||
return redirect(url_for("panel.players"))
|
||||
perms = session.get("permissions", {})
|
||||
is_admin = session.get("is_site_admin") or session.get("role") == "admin"
|
||||
return render_template("panel/player_detail.html",
|
||||
player=player,
|
||||
sessions = query("SELECT * FROM player_sessions WHERE player_uuid=%s ORDER BY login_time DESC LIMIT 20", (uuid,)),
|
||||
chat = query("SELECT * FROM player_chat WHERE player_uuid=%s ORDER BY timestamp DESC LIMIT 50", (uuid,)) if (is_admin or perms.get("view_chat")) else [],
|
||||
commands = query("SELECT * FROM player_commands WHERE player_uuid=%s ORDER BY timestamp DESC LIMIT 50", (uuid,)) if (is_admin or perms.get("view_commands")) else [],
|
||||
deaths = query("SELECT * FROM player_deaths WHERE player_uuid=%s ORDER BY timestamp DESC LIMIT 20", (uuid,)) if (is_admin or perms.get("view_deaths")) else [],
|
||||
teleports = query("SELECT * FROM player_teleports WHERE player_uuid=%s ORDER BY timestamp DESC LIMIT 20", (uuid,)),
|
||||
stats = query("SELECT * FROM player_stats WHERE player_uuid=%s ORDER BY timestamp DESC LIMIT 30", (uuid,)),
|
||||
proxy_events = query("SELECT * FROM proxy_events WHERE player_uuid=%s ORDER BY timestamp DESC LIMIT 30", (uuid,)) if (is_admin or perms.get("view_proxy")) else [],
|
||||
)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Sessions
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
|
||||
@panel.route("/sessions")
|
||||
@login_required
|
||||
@perm_required("view_sessions")
|
||||
def sessions():
|
||||
page = max(1, request.args.get("page", 1, type=int))
|
||||
player = request.args.get("player", "")
|
||||
server = request.args.get("server", "")
|
||||
conditions, args = [], []
|
||||
if player: conditions.append("player_name LIKE %s"); args.append(f"%{player}%")
|
||||
if server: conditions.append("server_name = %s"); args.append(server)
|
||||
where = ("WHERE " + " AND ".join(conditions)) if conditions else ""
|
||||
rows, total, pages = query_paged(
|
||||
f"SELECT * FROM player_sessions {where} ORDER BY login_time DESC",
|
||||
f"SELECT COUNT(*) AS c FROM player_sessions {where}", tuple(args), page)
|
||||
servers = [r["server_name"] for r in query("SELECT DISTINCT server_name FROM player_sessions ORDER BY server_name")]
|
||||
return render_template("panel/sessions.html",
|
||||
rows=rows, total=total, pages=pages, page=page,
|
||||
player=player, server=server, servers=servers)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Chat
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
|
||||
@panel.route("/chat")
|
||||
@login_required
|
||||
@perm_required("view_chat")
|
||||
def chat():
|
||||
page = max(1, request.args.get("page", 1, type=int))
|
||||
search = request.args.get("q", ""); server = request.args.get("server", "")
|
||||
date_from = request.args.get("from", ""); date_to = request.args.get("to", "")
|
||||
conditions, args = [], []
|
||||
if search: conditions.append("message LIKE %s"); args.append(f"%{search}%")
|
||||
if server: conditions.append("server_name = %s"); args.append(server)
|
||||
if date_from: conditions.append("timestamp >= %s"); args.append(date_from)
|
||||
if date_to: conditions.append("timestamp <= %s"); args.append(date_to + " 23:59:59")
|
||||
where = ("WHERE " + " AND ".join(conditions)) if conditions else ""
|
||||
rows, total, pages = query_paged(
|
||||
f"SELECT * FROM player_chat {where} ORDER BY timestamp DESC",
|
||||
f"SELECT COUNT(*) AS c FROM player_chat {where}", tuple(args), page)
|
||||
servers = [r["server_name"] for r in query("SELECT DISTINCT server_name FROM player_chat ORDER BY server_name")]
|
||||
return render_template("panel/chat.html",
|
||||
rows=rows, total=total, pages=pages, page=page,
|
||||
search=search, server=server, servers=servers, date_from=date_from, date_to=date_to)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Commands
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
|
||||
@panel.route("/commands")
|
||||
@login_required
|
||||
@perm_required("view_commands")
|
||||
def commands():
|
||||
page = max(1, request.args.get("page", 1, type=int))
|
||||
player = request.args.get("player", ""); search = request.args.get("q", ""); server = request.args.get("server", "")
|
||||
conditions, args = [], []
|
||||
if player: conditions.append("player_name LIKE %s"); args.append(f"%{player}%")
|
||||
if search: conditions.append("command LIKE %s"); args.append(f"%{search}%")
|
||||
if server: conditions.append("server_name = %s"); args.append(server)
|
||||
where = ("WHERE " + " AND ".join(conditions)) if conditions else ""
|
||||
rows, total, pages = query_paged(
|
||||
f"SELECT * FROM player_commands {where} ORDER BY timestamp DESC",
|
||||
f"SELECT COUNT(*) AS c FROM player_commands {where}", tuple(args), page)
|
||||
servers = [r["server_name"] for r in query("SELECT DISTINCT server_name FROM player_commands ORDER BY server_name")]
|
||||
return render_template("panel/commands.html",
|
||||
rows=rows, total=total, pages=pages, page=page,
|
||||
player=player, search=search, server=server, servers=servers)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Tode
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
|
||||
@panel.route("/deaths")
|
||||
@login_required
|
||||
@perm_required("view_deaths")
|
||||
def deaths():
|
||||
page = max(1, request.args.get("page", 1, type=int))
|
||||
player = request.args.get("player", ""); cause = request.args.get("cause", "")
|
||||
conditions, args = [], []
|
||||
if player: conditions.append("player_name LIKE %s"); args.append(f"%{player}%")
|
||||
if cause: conditions.append("cause = %s"); args.append(cause)
|
||||
where = ("WHERE " + " AND ".join(conditions)) if conditions else ""
|
||||
rows, total, pages = query_paged(
|
||||
f"SELECT * FROM player_deaths {where} ORDER BY timestamp DESC",
|
||||
f"SELECT COUNT(*) AS c FROM player_deaths {where}", tuple(args), page)
|
||||
causes = [r["cause"] for r in query("SELECT DISTINCT cause FROM player_deaths ORDER BY cause")]
|
||||
return render_template("panel/deaths.html",
|
||||
rows=rows, total=total, pages=pages, page=page, player=player, cause=cause, causes=causes)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Block-Events
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
|
||||
@panel.route("/blocks")
|
||||
@login_required
|
||||
@perm_required("view_blocks")
|
||||
def blocks():
|
||||
page = max(1, request.args.get("page", 1, type=int))
|
||||
event_type = request.args.get("type", ""); player = request.args.get("player", "")
|
||||
world = request.args.get("world", ""); server = request.args.get("server", ""); block = request.args.get("block", "")
|
||||
conditions, args = [], []
|
||||
if event_type: conditions.append("event_type = %s"); args.append(event_type)
|
||||
if player: conditions.append("player_name LIKE %s"); args.append(f"%{player}%")
|
||||
if world: conditions.append("world = %s"); args.append(world)
|
||||
if server: conditions.append("server_name = %s"); args.append(server)
|
||||
if block: conditions.append("block_type LIKE %s"); args.append(f"%{block}%")
|
||||
where = ("WHERE " + " AND ".join(conditions)) if conditions else ""
|
||||
rows, total, pages = query_paged(
|
||||
f"SELECT * FROM block_events {where} ORDER BY timestamp DESC",
|
||||
f"SELECT COUNT(*) AS c FROM block_events {where}", tuple(args), page)
|
||||
worlds = [r["world"] for r in query("SELECT DISTINCT world FROM block_events ORDER BY world")]
|
||||
servers = [r["server_name"] for r in query("SELECT DISTINCT server_name FROM block_events ORDER BY server_name")]
|
||||
return render_template("panel/blocks.html",
|
||||
rows=rows, total=total, pages=pages, page=page,
|
||||
event_type=event_type, player=player, world=world, server=server, block=block,
|
||||
worlds=worlds, servers=servers)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Proxy-Events
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
|
||||
@panel.route("/proxy")
|
||||
@login_required
|
||||
@perm_required("view_proxy")
|
||||
def proxy():
|
||||
page = max(1, request.args.get("page", 1, type=int))
|
||||
event_type = request.args.get("type", ""); player = request.args.get("player", "")
|
||||
conditions, args = [], []
|
||||
if event_type: conditions.append("event_type = %s"); args.append(event_type)
|
||||
if player: conditions.append("player_name LIKE %s"); args.append(f"%{player}%")
|
||||
where = ("WHERE " + " AND ".join(conditions)) if conditions else ""
|
||||
rows, total, pages = query_paged(
|
||||
f"SELECT * FROM proxy_events {where} ORDER BY timestamp DESC",
|
||||
f"SELECT COUNT(*) AS c FROM proxy_events {where}", tuple(args), page)
|
||||
return render_template("panel/proxy.html",
|
||||
rows=rows, total=total, pages=pages, page=page, event_type=event_type, player=player)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Server-Events
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
|
||||
@panel.route("/server-events")
|
||||
@login_required
|
||||
@perm_required("view_server_events")
|
||||
def server_events():
|
||||
page = max(1, request.args.get("page", 1, type=int))
|
||||
server = request.args.get("server", ""); etype = request.args.get("type", "")
|
||||
conditions, args = [], []
|
||||
if server: conditions.append("server_name = %s"); args.append(server)
|
||||
if etype: conditions.append("event_type = %s"); args.append(etype)
|
||||
where = ("WHERE " + " AND ".join(conditions)) if conditions else ""
|
||||
rows, total, pages = query_paged(
|
||||
f"SELECT * FROM server_events {where} ORDER BY timestamp DESC",
|
||||
f"SELECT COUNT(*) AS c FROM server_events {where}", tuple(args), page)
|
||||
servers = [r["server_name"] for r in query("SELECT DISTINCT server_name FROM server_events ORDER BY server_name")]
|
||||
etypes = [r["event_type"] for r in query("SELECT DISTINCT event_type FROM server_events ORDER BY event_type")]
|
||||
return render_template("panel/server_events.html",
|
||||
rows=rows, total=total, pages=pages, page=page,
|
||||
server=server, etype=etype, servers=servers, etypes=etypes)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Berechtigungen (plugin_events)
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
|
||||
@panel.route("/perms")
|
||||
@login_required
|
||||
@perm_required("view_perms")
|
||||
def perms():
|
||||
page = max(1, request.args.get("page", 1, type=int))
|
||||
player = request.args.get("player", ""); plugin_filter = request.args.get("plugin", ""); etype = request.args.get("type", "")
|
||||
conditions, args = [], []
|
||||
if player: conditions.append("player_name LIKE %s"); args.append(f"%{player}%")
|
||||
if plugin_filter: conditions.append("plugin_name = %s"); args.append(plugin_filter)
|
||||
if etype: conditions.append("event_type LIKE %s"); args.append(f"%{etype}%")
|
||||
where = ("WHERE " + " AND ".join(conditions)) if conditions else ""
|
||||
rows, total, pages = query_paged(
|
||||
f"SELECT * FROM plugin_events {where} ORDER BY timestamp DESC",
|
||||
f"SELECT COUNT(*) AS c FROM plugin_events {where}", tuple(args), page)
|
||||
plugins = [r["plugin_name"] for r in query("SELECT DISTINCT plugin_name FROM plugin_events ORDER BY plugin_name")]
|
||||
return render_template("panel/perms.html",
|
||||
rows=rows, total=total, pages=pages, page=page,
|
||||
player=player, plugin_filter=plugin_filter, etype=etype, plugins=plugins)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# API
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
|
||||
@panel.route("/api/online")
|
||||
@login_required
|
||||
def api_online():
|
||||
rows = query("""
|
||||
SELECT p.username, ps.server_name, ps.login_time, ps.country
|
||||
FROM player_sessions ps
|
||||
JOIN players p ON p.uuid = ps.player_uuid
|
||||
WHERE ps.logout_time IS NULL ORDER BY ps.login_time DESC
|
||||
""")
|
||||
return jsonify([dict(r) for r in rows])
|
||||
|
||||
|
||||
@panel.route("/api/stats")
|
||||
@login_required
|
||||
def api_stats():
|
||||
return jsonify({
|
||||
"players_online": query("SELECT COUNT(*) AS c FROM player_sessions WHERE logout_time IS NULL", fetchone=True)["c"],
|
||||
})
|
||||
221
web/blueprints/site_admin.py
Normal file
221
web/blueprints/site_admin.py
Normal file
@@ -0,0 +1,221 @@
|
||||
"""
|
||||
MCLogger – Site-Admin-Bereich
|
||||
Verwaltet alle Gruppen und Nutzer global.
|
||||
"""
|
||||
from functools import wraps
|
||||
from flask import Blueprint, render_template, request, redirect, url_for, session, flash
|
||||
import panel_db as db
|
||||
|
||||
site_admin = Blueprint("site_admin", __name__, url_prefix="/admin")
|
||||
|
||||
|
||||
def admin_required(f):
|
||||
@wraps(f)
|
||||
def decorated(*args, **kwargs):
|
||||
if not session.get("is_site_admin"):
|
||||
return redirect(url_for("auth.admin_login"))
|
||||
return f(*args, **kwargs)
|
||||
return decorated
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# Dashboard
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
@site_admin.route("/")
|
||||
@admin_required
|
||||
def dashboard():
|
||||
groups = db.list_all_groups()
|
||||
users = db.list_all_users()
|
||||
# Für jede Gruppe DB-Status prüfen
|
||||
for g in groups:
|
||||
g["has_db"] = db.has_db_configured(g["id"])
|
||||
return render_template("admin/dashboard.html", groups=groups, users=users)
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# Gruppen verwalten
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
@site_admin.route("/groups")
|
||||
@admin_required
|
||||
def groups():
|
||||
all_groups = db.list_all_groups()
|
||||
for g in all_groups:
|
||||
g["has_db"] = db.has_db_configured(g["id"])
|
||||
return render_template("admin/groups.html", groups=all_groups)
|
||||
|
||||
|
||||
@site_admin.route("/groups/new", methods=["GET", "POST"])
|
||||
@admin_required
|
||||
def group_new():
|
||||
if request.method == "POST":
|
||||
name = request.form.get("name", "").strip()
|
||||
desc = request.form.get("description", "").strip()
|
||||
if not name:
|
||||
flash("Gruppenname darf nicht leer sein.", "danger")
|
||||
elif db.get_group_by_name(name):
|
||||
flash("Eine Gruppe mit diesem Namen existiert bereits.", "danger")
|
||||
else:
|
||||
db.create_group(name, desc)
|
||||
flash(f"Gruppe '{name}' erstellt.", "success")
|
||||
return redirect(url_for("site_admin.groups"))
|
||||
return render_template("admin/group_edit.html", group=None)
|
||||
|
||||
|
||||
@site_admin.route("/groups/<int:group_id>/edit", methods=["GET", "POST"])
|
||||
@admin_required
|
||||
def group_edit(group_id):
|
||||
group = db.get_group_by_id(group_id)
|
||||
if not group:
|
||||
flash("Gruppe nicht gefunden.", "danger")
|
||||
return redirect(url_for("site_admin.groups"))
|
||||
if request.method == "POST":
|
||||
name = request.form.get("name", "").strip()
|
||||
desc = request.form.get("description", "").strip()
|
||||
if not name:
|
||||
flash("Gruppenname darf nicht leer sein.", "danger")
|
||||
else:
|
||||
db.update_group(group_id, name, desc)
|
||||
flash("Gruppe aktualisiert.", "success")
|
||||
return redirect(url_for("site_admin.groups"))
|
||||
return render_template("admin/group_edit.html", group=group)
|
||||
|
||||
|
||||
@site_admin.route("/groups/<int:group_id>/delete", methods=["POST"])
|
||||
@admin_required
|
||||
def group_delete(group_id):
|
||||
db.delete_group(group_id)
|
||||
flash("Gruppe gelöscht.", "success")
|
||||
return redirect(url_for("site_admin.groups"))
|
||||
|
||||
|
||||
@site_admin.route("/groups/<int:group_id>/members")
|
||||
@admin_required
|
||||
def group_members(group_id):
|
||||
group = db.get_group_by_id(group_id)
|
||||
members = db.get_group_members(group_id)
|
||||
all_users = db.list_all_users()
|
||||
member_ids = {m["id"] for m in members}
|
||||
non_members = [u for u in all_users if u["id"] not in member_ids]
|
||||
return render_template("admin/group_members.html",
|
||||
group=group, members=members, non_members=non_members)
|
||||
|
||||
|
||||
@site_admin.route("/groups/<int:group_id>/members/add", methods=["POST"])
|
||||
@admin_required
|
||||
def group_member_add(group_id):
|
||||
user_id = request.form.get("user_id", type=int)
|
||||
role = request.form.get("role", "member")
|
||||
if user_id:
|
||||
db.add_group_member(user_id, group_id, role)
|
||||
flash("Mitglied hinzugefügt.", "success")
|
||||
return redirect(url_for("site_admin.group_members", group_id=group_id))
|
||||
|
||||
|
||||
@site_admin.route("/groups/<int:group_id>/members/<int:user_id>/remove", methods=["POST"])
|
||||
@admin_required
|
||||
def group_member_remove(group_id, user_id):
|
||||
db.remove_group_member(user_id, group_id)
|
||||
flash("Mitglied entfernt.", "success")
|
||||
return redirect(url_for("site_admin.group_members", group_id=group_id))
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# Nutzer verwalten
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
@site_admin.route("/users")
|
||||
@admin_required
|
||||
def users():
|
||||
return render_template("admin/users.html", users=db.list_all_users())
|
||||
|
||||
|
||||
@site_admin.route("/users/new", methods=["GET", "POST"])
|
||||
@admin_required
|
||||
def user_new():
|
||||
if request.method == "POST":
|
||||
username = request.form.get("username", "").strip()
|
||||
email = request.form.get("email", "").strip()
|
||||
password = request.form.get("password", "")
|
||||
is_site_admin = request.form.get("is_site_admin") == "1"
|
||||
if not username or not email or not password:
|
||||
flash("Alle Felder sind Pflichtfelder.", "danger")
|
||||
elif db.get_user_by_username(username):
|
||||
flash("Benutzername bereits vergeben.", "danger")
|
||||
else:
|
||||
db.create_user(username, email, password, is_site_admin)
|
||||
flash(f"Nutzer '{username}' erstellt.", "success")
|
||||
return redirect(url_for("site_admin.users"))
|
||||
return render_template("admin/user_edit.html", user=None)
|
||||
|
||||
|
||||
@site_admin.route("/users/<int:user_id>/edit", methods=["GET", "POST"])
|
||||
@admin_required
|
||||
def user_edit(user_id):
|
||||
user = db.get_user_by_id(user_id)
|
||||
if not user:
|
||||
flash("Nutzer nicht gefunden.", "danger")
|
||||
return redirect(url_for("site_admin.users"))
|
||||
if request.method == "POST":
|
||||
username = request.form.get("username", "").strip()
|
||||
email = request.form.get("email", "").strip()
|
||||
is_site_admin = request.form.get("is_site_admin") == "1"
|
||||
new_password = request.form.get("new_password", "")
|
||||
db.update_user(user_id, username, email, is_site_admin)
|
||||
if new_password:
|
||||
db.change_password(user_id, new_password)
|
||||
flash("Passwort geändert.", "info")
|
||||
flash("Nutzer aktualisiert.", "success")
|
||||
return redirect(url_for("site_admin.users"))
|
||||
return render_template("admin/user_edit.html", user=user)
|
||||
|
||||
|
||||
@site_admin.route("/users/<int:user_id>/delete", methods=["POST"])
|
||||
@admin_required
|
||||
def user_delete(user_id):
|
||||
if user_id == session.get("user_id"):
|
||||
flash("Du kannst dich nicht selbst löschen.", "danger")
|
||||
else:
|
||||
db.delete_user(user_id)
|
||||
flash("Nutzer gelöscht.", "success")
|
||||
return redirect(url_for("site_admin.users"))
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# Als Gruppe anzeigen (Site-Admin liest Gruppen-DB)
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
@site_admin.route("/view-group/<int:group_id>")
|
||||
@admin_required
|
||||
def view_group(group_id):
|
||||
"""Site-Admin wechselt temporär in eine Gruppe, um deren MC-Daten zu sehen."""
|
||||
group = db.get_group_by_id(group_id)
|
||||
if not group:
|
||||
flash("Gruppe nicht gefunden.", "danger")
|
||||
return redirect(url_for("site_admin.dashboard"))
|
||||
if not db.has_db_configured(group_id):
|
||||
flash("Für diese Gruppe ist noch keine Datenbank konfiguriert.", "warning")
|
||||
return redirect(url_for("site_admin.dashboard"))
|
||||
# Alle Berechtigungen als Admin
|
||||
all_perms = {k: True for k in ["view_dashboard","view_players","view_sessions",
|
||||
"view_chat","view_commands","view_deaths","view_blocks",
|
||||
"view_proxy","view_server_events","view_perms"]}
|
||||
session["group_id"] = group_id
|
||||
session["group_name"] = group["name"]
|
||||
session["role"] = "admin"
|
||||
session["permissions"] = all_perms
|
||||
session["admin_viewing"] = True
|
||||
return redirect(url_for("panel.dashboard"))
|
||||
|
||||
|
||||
@site_admin.route("/stop-view")
|
||||
@admin_required
|
||||
def stop_view():
|
||||
"""Kehrt zum Site-Admin-Dashboard zurück."""
|
||||
session.pop("group_id", None)
|
||||
session.pop("group_name", None)
|
||||
session.pop("role", None)
|
||||
session.pop("permissions", None)
|
||||
session.pop("admin_viewing", None)
|
||||
return redirect(url_for("site_admin.dashboard"))
|
||||
Reference in New Issue
Block a user