Files

100 lines
4.0 KiB
Python
Raw Permalink Normal View History

from datetime import datetime, timezone
from fastapi import APIRouter, Depends, Request
from fastapi.responses import HTMLResponse, RedirectResponse
from sqlalchemy import or_
from sqlalchemy.orm import Session
from web.auth.password import hash_password
from web.config import settings
from web.database import get_db
from web.models.user import User, UserStatusEnum
from web.templates_env import templates
router = APIRouter()
def _render(request: Request, template: str, ctx: dict) -> HTMLResponse:
ctx["request"] = request
ctx.setdefault("jivosite_widget_id", settings.JIVOSITE_WIDGET_ID)
return templates.TemplateResponse(ctx.pop("request"), template, ctx)
def _bad_token(request: Request) -> HTMLResponse:
return _render(request, "message.html", {
"user": None,
"title": "Ссылка недействительна",
"message": "Ссылка приглашения устарела или недействительна. Обратитесь к администратору.",
"link": "/login", "link_text": "Войти",
})
@router.get("/invite")
async def invite_get(request: Request, db: Session = Depends(get_db)):
token = request.query_params.get("token", "")
user = db.query(User).filter(User.invite_token == token).first()
if not user or not user.invite_expires or user.invite_expires < datetime.now(timezone.utc).replace(tzinfo=None):
return _bad_token(request)
return _render(request, "invite.html", {"user": None, "invite_user": user, "token": token})
@router.post("/invite")
async def invite_post(request: Request, db: Session = Depends(get_db)):
token = request.query_params.get("token", "")
invite_user = db.query(User).filter(User.invite_token == token).first()
if not invite_user or not invite_user.invite_expires or invite_user.invite_expires < datetime.now(timezone.utc).replace(tzinfo=None):
return _bad_token(request)
form = await request.form()
data = {k: str(v).strip() for k, v in form.items()}
errors = []
if not data.get("first_name"):
errors.append("Имя обязательно")
if not data.get("last_name"):
errors.append("Фамилия обязательна")
if not data.get("email"):
errors.append("Email обязателен")
if not data.get("phone"):
errors.append("Телефон обязателен")
if len(data.get("password", "")) < 8:
errors.append("Пароль должен содержать минимум 8 символов")
if data.get("password") != data.get("password_confirm"):
errors.append("Пароли не совпадают")
if not errors:
# Check uniqueness (excluding current invite_user)
dup = db.query(User).filter(
or_(User.email == data["email"], User.phone == data["phone"]),
User.id != invite_user.id,
).first()
if dup:
if dup.email == data["email"]:
errors.append("Пользователь с таким email уже существует")
else:
errors.append("Пользователь с таким телефоном уже существует")
if errors:
return _render(request, "invite.html", {
"user": None, "invite_user": invite_user, "token": token,
"errors": errors, "form": data,
})
invite_user.first_name = data["first_name"]
invite_user.last_name = data["last_name"]
invite_user.email = data["email"]
invite_user.phone = data["phone"]
invite_user.password_hash = hash_password(data["password"])
invite_user.is_email_confirmed = True
invite_user.status = UserStatusEnum.active
invite_user.invite_token = None
invite_user.invite_expires = None
db.commit()
return _render(request, "message.html", {
"user": None,
"title": "Регистрация завершена!",
"message": "Ваш аккаунт активирован. Теперь вы можете войти.",
"link": "/login", "link_text": "Войти",
})