Add email invitation system with SMTP configuration and invite token workflow
Implemented comprehensive email invitation functionality for new users. Added SMTP settings management in admin panel with configuration UI for host, port, credentials, sender details, and TLS options. Created invite token system with 48-hour expiration and single-use enforcement. Added mailer module with HTML email templates in German theme styling (radial gradient backgrounds, gold accents, bordered cards). Implemented invite
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
import hashlib
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request, Response
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..db import get_db
|
||||
from ..models import InviteToken, User
|
||||
from ..security import hash_password, make_session_value, set_session
|
||||
|
||||
router = APIRouter(prefix="/auth/invite", tags=["invites"])
|
||||
|
||||
|
||||
def get_invite(token: str, db: Session):
|
||||
token_hash = hashlib.sha256(token.encode()).hexdigest()
|
||||
invite = db.query(InviteToken).filter(InviteToken.token_hash == token_hash).first()
|
||||
expires_at = invite.expires_at if invite else None
|
||||
if expires_at and expires_at.tzinfo is None:
|
||||
expires_at = expires_at.replace(tzinfo=timezone.utc)
|
||||
if not invite or invite.used_at or expires_at <= datetime.now(timezone.utc):
|
||||
raise HTTPException(410, "invite is invalid or expired")
|
||||
user = db.query(User).filter(User.id == invite.user_id, User.disabled == False).first()
|
||||
if not user:
|
||||
raise HTTPException(410, "invite is invalid or expired")
|
||||
return invite, user
|
||||
|
||||
|
||||
@router.get("/{token}")
|
||||
def invite_info(token: str, db: Session = Depends(get_db)):
|
||||
_invite, user = get_invite(token, db)
|
||||
return {"valid": True, "display_name": user.display_name, "email": user.email, "role": user.role}
|
||||
|
||||
|
||||
@router.post("/{token}")
|
||||
def accept_invite(token: str, data: dict, resp: Response, db: Session = Depends(get_db)):
|
||||
invite, user = get_invite(token, db)
|
||||
password = data.get("password") or ""
|
||||
if len(password) < 8:
|
||||
raise HTTPException(400, "password too short (min 8)")
|
||||
|
||||
user.password_hash = hash_password(password)
|
||||
invite.used_at = datetime.now(timezone.utc)
|
||||
db.add(user)
|
||||
db.add(invite)
|
||||
db.commit()
|
||||
set_session(resp, make_session_value(user.id))
|
||||
return {"ok": True}
|
||||
Reference in New Issue
Block a user