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": "Войти", })