Files
evo-sync/web/routes/auth.py
mguschin 951c12a208 Add user registration and auth web app
FastAPI + Jinja2 + MariaDB web application with registration,
login, profile, password reset, and email confirmation flows.
All UI in Russian. Styled with Evotor brand colors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:01:58 +03:00

124 lines
4.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import uuid
from fastapi import APIRouter, Request, Depends
from fastapi.responses import RedirectResponse
from fastapi.templating import Jinja2Templates
from sqlalchemy.orm import Session
from web.auth import hash_password, verify_password, get_current_user
from web.config import settings
from web.database import get_db
from web.models import User
from web.schemas import validate_registration, validate_login
router = APIRouter()
templates = Jinja2Templates(directory="web/templates")
@router.get("/register")
def register_form(request: Request, user: User | None = Depends(get_current_user)):
if user:
return RedirectResponse("/profile", 303)
return templates.TemplateResponse("register.html", {"request": request, "user": None})
@router.post("/register")
async def register_submit(request: Request, db: Session = Depends(get_db)):
form = await request.form()
data = dict(form)
errors = validate_registration(data)
if not errors:
existing = db.query(User).filter(
(User.email == data["email"].strip()) | (User.phone == data["phone"].strip())
).first()
if existing:
if existing.email == data["email"].strip():
errors.append("Пользователь с таким email уже существует")
else:
errors.append("Пользователь с таким телефоном уже существует")
if errors:
return templates.TemplateResponse("register.html", {
"request": request, "user": None, "errors": errors, "form": data,
})
token = uuid.uuid4().hex
user = User(
first_name=data["first_name"].strip(),
last_name=data["last_name"].strip(),
email=data["email"].strip(),
phone=data["phone"].strip(),
password_hash=hash_password(data["password"]),
email_confirm_token=token,
)
db.add(user)
db.commit()
confirm_url = f"{settings.BASE_URL}/confirm-email?token={token}"
print("=" * 40)
print("ПОДТВЕРЖДЕНИЕ EMAIL")
print(f"Пользователь: {user.email}")
print(f"Ссылка: {confirm_url}")
print("=" * 40)
return templates.TemplateResponse("confirm_email.html", {"request": request, "user": None})
@router.get("/confirm-email")
def confirm_email(request: Request, token: str, db: Session = Depends(get_db)):
user = db.query(User).filter(User.email_confirm_token == token).first()
if not user:
return templates.TemplateResponse("message.html", {
"request": request, "user": None,
"title": "Ошибка", "message": "Неверная или устаревшая ссылка.",
})
user.is_email_confirmed = True
user.email_confirm_token = None
db.commit()
return templates.TemplateResponse("email_confirmed.html", {"request": request, "user": None})
@router.get("/login")
def login_form(request: Request, user: User | None = Depends(get_current_user)):
if user:
return RedirectResponse("/profile", 303)
return templates.TemplateResponse("login.html", {"request": request, "user": None})
@router.post("/login")
async def login_submit(request: Request, db: Session = Depends(get_db)):
form = await request.form()
data = dict(form)
errors = validate_login(data)
if errors:
return templates.TemplateResponse("login.html", {
"request": request, "user": None, "errors": errors, "form": data,
})
user = db.query(User).filter(User.email == data["email"].strip()).first()
if not user or not verify_password(data["password"], user.password_hash):
return templates.TemplateResponse("login.html", {
"request": request, "user": None,
"errors": ["Неверный email или пароль"], "form": data,
})
if not user.is_email_confirmed:
return templates.TemplateResponse("login.html", {
"request": request, "user": None,
"errors": ["Пожалуйста, подтвердите ваш email"], "form": data,
})
request.session["user_id"] = user.id
return RedirectResponse("/profile", 303)
@router.get("/logout")
def logout(request: Request):
request.session.clear()
return RedirectResponse("/login", 303)