Files
evo-sync/web-python/routes/reset.py

108 lines
4.2 KiB
Python
Raw Normal View History

import uuid
from datetime import datetime, timedelta, timezone
from fastapi import APIRouter, Request, Depends
from fastapi.responses import RedirectResponse
from web.templates_env import templates
from sqlalchemy.orm import Session
from web.auth import hash_password
from web.config import settings
from web.database import get_db
from web.models import User
from web.schemas import validate_reset_password
router = APIRouter()
@router.get("/forgot-password")
def forgot_form(request: Request):
return templates.TemplateResponse("forgot_password.html", {"request": request, "user": None})
@router.post("/forgot-password")
async def forgot_submit(request: Request, db: Session = Depends(get_db)):
form = await request.form()
email = form.get("email", "").strip()
if email:
user = db.query(User).filter(User.email == email).first()
if user:
token = uuid.uuid4().hex
user.password_reset_token = token
user.password_reset_expires = datetime.now(timezone.utc) + timedelta(
minutes=settings.PASSWORD_RESET_EXPIRE_MINUTES
)
db.commit()
reset_url = f"{settings.BASE_URL}/reset-password?token={token}"
print("=" * 40)
print("СБРОС ПАРОЛЯ")
print(f"Пользователь: {user.email}")
print(f"Ссылка: {reset_url}")
print(f"Действительна: {settings.PASSWORD_RESET_EXPIRE_MINUTES} мин.")
print("=" * 40)
return templates.TemplateResponse("message.html", {
"request": request, "user": None,
"title": "Сброс пароля",
"message": "Если аккаунт с таким email существует, мы отправили письмо со ссылкой для сброса пароля.",
})
@router.get("/reset-password")
def reset_form(request: Request, token: str, db: Session = Depends(get_db)):
user = db.query(User).filter(User.password_reset_token == token).first()
if not user or not user.password_reset_expires:
return templates.TemplateResponse("message.html", {
"request": request, "user": None,
"title": "Ошибка", "message": "Неверная или устаревшая ссылка.",
})
if datetime.now(timezone.utc) > user.password_reset_expires.replace(tzinfo=timezone.utc):
return templates.TemplateResponse("message.html", {
"request": request, "user": None,
"title": "Ошибка", "message": "Срок действия ссылки истек.",
})
return templates.TemplateResponse("reset_password.html", {
"request": request, "user": None, "token": token,
})
@router.post("/reset-password")
async def reset_submit(request: Request, token: str, db: Session = Depends(get_db)):
user = db.query(User).filter(User.password_reset_token == token).first()
if not user or not user.password_reset_expires:
return templates.TemplateResponse("message.html", {
"request": request, "user": None,
"title": "Ошибка", "message": "Неверная или устаревшая ссылка.",
})
if datetime.now(timezone.utc) > user.password_reset_expires.replace(tzinfo=timezone.utc):
return templates.TemplateResponse("message.html", {
"request": request, "user": None,
"title": "Ошибка", "message": "Срок действия ссылки истек.",
})
form = await request.form()
data = dict(form)
errors = validate_reset_password(data)
if errors:
return templates.TemplateResponse("reset_password.html", {
"request": request, "user": None, "token": token, "errors": errors,
})
user.password_hash = hash_password(data["password"])
user.password_reset_token = None
user.password_reset_expires = None
db.commit()
return templates.TemplateResponse("message.html", {
"request": request, "user": None,
"title": "Пароль изменен",
"message": "Ваш пароль успешно изменен. Теперь вы можете войти.",
"link": "/login", "link_text": "Войти",
})