Files
MClogger/web/blueprints/group_admin.py
simon 6b13ea5c22 modified: web/blueprints/auth.py
modified:   web/blueprints/group_admin.py
	modified:   web/config.py
	modified:   web/panel_db.py
	new file:   web/templates/auth/accept_invite.html
	modified:   web/templates/group_admin/base.html
	modified:   web/templates/group_admin/members.html
2026-04-13 10:26:47 +02:00

224 lines
8.7 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.
"""
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", "Players"),
("view_sessions", "Sessions"),
("view_chat", "Chat"),
("view_commands", "Commands"),
("view_deaths", "Deaths"),
("view_blocks", "Block Events"),
("view_proxy", "Proxy Events"),
("view_server_events", "Server Events"),
("view_perms", "Permissions"),
]
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("You do not have group admin permission.", "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)
stats = {
"member_count": len(members),
"admin_count": sum(1 for m in members if m.get("role") == "admin"),
"db_configured": bool(has_db),
}
return render_template("group_admin/dashboard.html",
group=group, members=members, has_db=has_db, stats=stats)
# ──────────────────────────────────────────────────────────────
# 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)
pending_invites = db.list_active_group_invites(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, pending_invites=pending_invites,
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("Member added.", "success")
return redirect(url_for("group_admin.members"))
@group_admin.route("/members/invite", methods=["POST"])
@group_admin_required
def member_invite():
group_id = session["group_id"]
username = request.form.get("username", "").strip()
email = request.form.get("email", "").strip()
role = request.form.get("role", "member")
if not username or not email:
flash("Username and email are required.", "danger")
return redirect(url_for("group_admin.members"))
if "@" not in email:
flash("Please provide a valid email address.", "danger")
return redirect(url_for("group_admin.members"))
if role not in {"member", "admin"}:
flash("Invalid role selected.", "danger")
return redirect(url_for("group_admin.members"))
if db.get_user_by_username(username):
flash("Username already exists.", "danger")
return redirect(url_for("group_admin.members"))
if db.get_user_by_email(email):
flash("Email address is already in use.", "danger")
return redirect(url_for("group_admin.members"))
if db.get_active_invite_by_email(group_id, email):
flash("There is already an active invitation for this email in the group.", "danger")
return redirect(url_for("group_admin.members"))
token = db.create_group_invite(group_id, username, email, role, session["user_id"])
invite_url = url_for("auth.accept_invite", token=token, _external=True)
flash(f"Invitation created for '{username}'. Share this link: {invite_url}", "success")
return redirect(url_for("group_admin.members"))
@group_admin.route("/invites/<int:invite_id>/revoke", methods=["POST"])
@group_admin_required
def revoke_invite(invite_id):
db.revoke_group_invite(invite_id, session["group_id"])
flash("Invitation revoked.", "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("Member not found.", "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: bool(request.form.get(f"perm_{key}")) for key, _ in ALL_PERMISSIONS}
db.update_member(user_id, group_id, role, new_perms)
flash("Permissions updated.", "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("You cannot remove yourself.", "danger")
else:
db.remove_group_member(user_id, session["group_id"])
flash("Member removed.", "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
creds = db.get_group_db_creds(group_id)
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 password left blank and creds already exist, keep the stored password
if not password and creds:
password = creds["password"]
if not all([host, port, user, database_name]):
error = "Host, Port, User and Database name are required."
elif not password:
error = "Password is required."
else:
try:
import pymysql
test_conn = pymysql.connect(
host=host, port=int(port), user=user,
password=password, database=database_name,
connect_timeout=5
)
test_conn.close()
db.set_group_db_creds(group_id, host, int(port), user, password, database_name)
flash("Database connection saved and tested ✓", "success")
return redirect(url_for("group_admin.database"))
except Exception as e:
error = f"Connection test failed: {e}"
return render_template("group_admin/database.html",
group=group, has_db=has_db, creds=creds, error=error)
@group_admin.route("/database/delete", methods=["POST"])
@group_admin_required
def database_delete():
db.delete_group_db_creds(session["group_id"])
flash("Database connection removed.", "success")
return redirect(url_for("group_admin.database"))