modified: web/blueprints/site_admin.py

modified:   web/panel_db.py
	modified:   web/templates/admin/user_edit.html
	modified:   web/templates/admin/users.html
This commit is contained in:
SimolZimol
2026-04-13 18:25:09 +02:00
parent 31b45d4db4
commit fe2e5e3c9c
4 changed files with 323 additions and 30 deletions

View File

@@ -352,28 +352,139 @@ def group_invite_resend(group_id, invite_id):
@site_admin.route("/users")
@admin_required
def users():
return render_template("admin/users.html", users=db.list_all_users())
return render_template(
"admin/users.html",
users=db.list_all_users(),
pending_invites=db.list_all_active_invites(),
)
@site_admin.route("/users/new", methods=["GET", "POST"])
@admin_required
def user_new():
groups = db.list_all_groups()
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("All fields are required.", "danger")
group_id_raw = request.form.get("group_id", "").strip()
role = request.form.get("role", "viewer")
group_id = int(group_id_raw) if group_id_raw else None
error = None
if not username or not email:
error = "Username and email are required."
elif db.get_user_by_username(username):
flash("Username already taken.", "danger")
error = "Username already taken."
elif db.get_user_by_email(email):
flash("Email address already in use.", "danger")
error = "Email address already in use."
elif db.get_active_invite_by_username_global(username):
error = "There is already an active invitation for this username."
elif db.get_active_invite_by_email_global(email):
error = "There is already an active invitation for this email."
elif group_id and role not in GROUP_ROLE_SET:
error = "Invalid role selected."
if error:
flash(error, "danger")
return render_template("admin/user_edit.html", user=None, groups=groups)
effective_role = role if group_id else "member"
token = db.create_group_invite(group_id, username, email, effective_role,
session["user_id"], is_site_admin=is_site_admin)
invite_url = url_for("auth.accept_invite", token=token, _external=True)
mail_settings = db.get_site_mail_settings()
if mail_settings:
if group_id:
group = db.get_group_by_id(group_id)
subject = f"Invitation to join {group['name']}"
body = (
f"Hello {username},\n\n"
f"You have been invited to join the group '{group['name']}' on MCLogger"
f" as {role_label(effective_role)}.\n"
f"Open this link to create your account:\n\n{invite_url}\n\n"
f"This invite expires in {Config.INVITE_EXPIRY_HOURS} hours.\n"
)
else:
subject = "You have been invited to MCLogger"
body = (
f"Hello {username},\n\n"
f"You have been invited to create an account on MCLogger.\n"
f"Open this link to create your account:\n\n{invite_url}\n\n"
f"This invite expires in {Config.INVITE_EXPIRY_HOURS} hours.\n"
)
try:
send_mail(mail_settings, email, subject, body)
invite = db.get_invite_by_token(token)
if invite:
db.mark_invite_sent_global(invite["id"])
flash(f"Invitation email sent to '{email}'.", "success")
except Exception:
flash(
f"Invitation created, but email delivery failed. "
f"Share this link manually: {invite_url}",
"warning",
)
else:
db.create_user(username, email, password, is_site_admin)
flash(f"User '{username}' created.", "success")
return redirect(url_for("site_admin.users"))
return render_template("admin/user_edit.html", user=None)
flash(f"Invitation created for '{username}'. Share this link: {invite_url}", "success")
return redirect(url_for("site_admin.users"))
return render_template("admin/user_edit.html", user=None, groups=groups)
@site_admin.route("/users/invites/<int:invite_id>/revoke", methods=["POST"])
@admin_required
def user_invite_revoke(invite_id):
db.revoke_invite_global(invite_id)
flash("Invitation revoked.", "success")
return redirect(url_for("site_admin.users"))
@site_admin.route("/users/invites/<int:invite_id>/resend", methods=["POST"])
@admin_required
def user_invite_resend(invite_id):
invite = db.get_invite_by_id_global(invite_id)
if not invite:
flash("Invitation not found.", "danger")
return redirect(url_for("site_admin.users"))
if invite.get("accepted_at") or invite.get("revoked_at") or invite["expires_at"] <= datetime.utcnow():
flash("Invitation is no longer active.", "danger")
return redirect(url_for("site_admin.users"))
last_sent = invite.get("last_sent_at")
if last_sent and (datetime.utcnow() - last_sent) < timedelta(seconds=Config.INVITE_RESEND_COOLDOWN_SECONDS):
flash("Please wait before resending this invite again.", "warning")
return redirect(url_for("site_admin.users"))
mail_settings = db.get_site_mail_settings()
if not mail_settings:
flash("No SMTP settings configured.", "danger")
return redirect(url_for("site_admin.users"))
invite_url = url_for("auth.accept_invite", token=invite["token"], _external=True)
if invite["group_id"]:
group = db.get_group_by_id(invite["group_id"])
subject = f"Invitation to join {group['name']}"
body = (
f"Hello {invite['invited_username']},\n\n"
f"You have been invited to join the group '{group['name']}' on MCLogger"
f" as {role_label(invite['role'])}.\n"
f"Open this link to create your account:\n\n{invite_url}\n\n"
f"This invite expires on {invite['expires_at']}.\n"
)
else:
subject = "You have been invited to MCLogger"
body = (
f"Hello {invite['invited_username']},\n\n"
f"You have been invited to create an account on MCLogger.\n"
f"Open this link to create your account:\n\n{invite_url}\n\n"
f"This invite expires on {invite['expires_at']}.\n"
)
try:
send_mail(mail_settings, invite["invited_email"], subject, body)
db.mark_invite_sent_global(invite_id)
flash("Invitation email resent.", "success")
except Exception:
flash("Resend failed. Please verify SMTP settings and try again.", "danger")
return redirect(url_for("site_admin.users"))
@site_admin.route("/users/<int:user_id>/edit", methods=["GET", "POST"])