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
This commit is contained in:
@@ -3,8 +3,9 @@ MCLogger – Authentifizierung
|
||||
Getrennte Login-Seiten für Site-Admins und normale Nutzer/Gruppen-Admins.
|
||||
"""
|
||||
import json
|
||||
from datetime import datetime
|
||||
from flask import Blueprint, render_template, request, redirect, url_for, session, flash
|
||||
from panel_db import check_login, get_user_groups
|
||||
from panel_db import accept_group_invite, check_login, get_invite_by_token, get_user_groups
|
||||
|
||||
auth = Blueprint("auth", __name__)
|
||||
|
||||
@@ -72,6 +73,42 @@ def switch_group(group_id):
|
||||
return redirect(url_for("panel.dashboard"))
|
||||
|
||||
|
||||
@auth.route("/invite/<token>", methods=["GET", "POST"])
|
||||
def accept_invite(token):
|
||||
if session.get("user_id"):
|
||||
return redirect(url_for("panel.dashboard"))
|
||||
|
||||
invite = get_invite_by_token(token)
|
||||
if not invite:
|
||||
flash("Invitation not found.", "danger")
|
||||
return redirect(url_for("auth.login"))
|
||||
|
||||
is_expired = invite["expires_at"] <= datetime.utcnow()
|
||||
is_invalid = bool(invite.get("accepted_at") or invite.get("revoked_at") or is_expired)
|
||||
error = None
|
||||
|
||||
if request.method == "POST" and not is_invalid:
|
||||
password = request.form.get("password", "")
|
||||
confirm_password = request.form.get("confirm_password", "")
|
||||
|
||||
if len(password) < 8:
|
||||
error = "Password must be at least 8 characters long."
|
||||
elif password != confirm_password:
|
||||
error = "Passwords do not match."
|
||||
else:
|
||||
result = accept_group_invite(token, password)
|
||||
if result is None:
|
||||
flash("Invitation is no longer valid.", "danger")
|
||||
return redirect(url_for("auth.login"))
|
||||
if result.get("error") == "username_or_email_taken":
|
||||
error = "The invited username or email is already in use. Please contact your administrator."
|
||||
else:
|
||||
flash("Your account has been created. You can now sign in.", "success")
|
||||
return redirect(url_for("auth.login"))
|
||||
|
||||
return render_template("auth/accept_invite.html", invite=invite, is_invalid=is_invalid, is_expired=is_expired, error=error)
|
||||
|
||||
|
||||
def _set_user_session(user, groups):
|
||||
session["user_id"] = user["id"]
|
||||
session["username"] = user["username"]
|
||||
|
||||
@@ -63,11 +63,12 @@ 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,
|
||||
group=group, members=members, non_members=non_members, pending_invites=pending_invites,
|
||||
all_permissions=ALL_PERMISSIONS)
|
||||
|
||||
|
||||
@@ -83,6 +84,52 @@ def member_add():
|
||||
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):
|
||||
|
||||
Reference in New Issue
Block a user