2026-03-04 22:01:58 +03:00
|
|
|
|
from fastapi import APIRouter, Request, Depends
|
|
|
|
|
|
from fastapi.responses import RedirectResponse
|
2026-03-10 14:11:25 +03:00
|
|
|
|
from web.templates_env import templates
|
2026-03-04 22:01:58 +03:00
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
|
|
|
2026-03-05 21:05:30 +03:00
|
|
|
|
from web.auth import get_current_user, verify_password, hash_password
|
2026-03-04 22:01:58 +03:00
|
|
|
|
from web.database import get_db
|
|
|
|
|
|
from web.models import User
|
2026-03-05 21:05:30 +03:00
|
|
|
|
from web.schemas import validate_profile, validate_reset_password
|
2026-03-04 22:01:58 +03:00
|
|
|
|
|
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-03-05 21:05:30 +03:00
|
|
|
|
# VIEW PROFILE
|
2026-03-04 22:01:58 +03:00
|
|
|
|
@router.get("/profile")
|
|
|
|
|
|
def profile_view(request: Request, user: User | None = Depends(get_current_user)):
|
|
|
|
|
|
if not user:
|
|
|
|
|
|
return RedirectResponse("/login", 303)
|
2026-03-05 21:05:30 +03:00
|
|
|
|
return templates.TemplateResponse("profile_view.html", {"request": request, "user": user})
|
2026-03-04 22:01:58 +03:00
|
|
|
|
|
|
|
|
|
|
|
2026-03-05 21:05:30 +03:00
|
|
|
|
# EDIT PROFILE
|
|
|
|
|
|
@router.get("/profile/edit")
|
|
|
|
|
|
def profile_edit_form(request: Request, user: User | None = Depends(get_current_user)):
|
|
|
|
|
|
if not user:
|
|
|
|
|
|
return RedirectResponse("/login", 303)
|
|
|
|
|
|
return templates.TemplateResponse("profile_edit.html", {"request": request, "user": user})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/profile/edit")
|
|
|
|
|
|
async def profile_edit_submit(
|
2026-03-04 22:01:58 +03:00
|
|
|
|
request: Request,
|
|
|
|
|
|
db: Session = Depends(get_db),
|
|
|
|
|
|
user: User | None = Depends(get_current_user),
|
|
|
|
|
|
):
|
|
|
|
|
|
if not user:
|
|
|
|
|
|
return RedirectResponse("/login", 303)
|
|
|
|
|
|
|
|
|
|
|
|
form = await request.form()
|
|
|
|
|
|
data = dict(form)
|
|
|
|
|
|
|
|
|
|
|
|
errors = validate_profile(data)
|
|
|
|
|
|
|
|
|
|
|
|
if not errors:
|
|
|
|
|
|
existing = db.query(User).filter(
|
|
|
|
|
|
User.phone == data["phone"].strip(), User.id != user.id
|
|
|
|
|
|
).first()
|
|
|
|
|
|
if existing:
|
|
|
|
|
|
errors.append("Пользователь с таким телефоном уже существует")
|
|
|
|
|
|
|
|
|
|
|
|
if errors:
|
2026-03-05 21:05:30 +03:00
|
|
|
|
return templates.TemplateResponse("profile_edit.html", {
|
2026-03-04 22:01:58 +03:00
|
|
|
|
"request": request, "user": user, "errors": errors, "form": data,
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
user.first_name = data["first_name"].strip()
|
|
|
|
|
|
user.last_name = data["last_name"].strip()
|
|
|
|
|
|
user.phone = data["phone"].strip()
|
|
|
|
|
|
db.commit()
|
|
|
|
|
|
|
2026-03-05 21:05:30 +03:00
|
|
|
|
return templates.TemplateResponse("profile_edit.html", {
|
2026-03-04 22:01:58 +03:00
|
|
|
|
"request": request, "user": user, "success": "Профиль обновлен",
|
|
|
|
|
|
})
|
2026-03-05 21:05:30 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# CHANGE PASSWORD
|
|
|
|
|
|
@router.get("/profile/change-password")
|
|
|
|
|
|
def change_password_form(request: Request, user: User | None = Depends(get_current_user)):
|
|
|
|
|
|
if not user:
|
|
|
|
|
|
return RedirectResponse("/login", 303)
|
|
|
|
|
|
return templates.TemplateResponse("profile_change_password.html", {"request": request, "user": user})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/profile/change-password")
|
|
|
|
|
|
async def change_password_submit(
|
|
|
|
|
|
request: Request,
|
|
|
|
|
|
db: Session = Depends(get_db),
|
|
|
|
|
|
user: User | None = Depends(get_current_user),
|
|
|
|
|
|
):
|
|
|
|
|
|
if not user:
|
|
|
|
|
|
return RedirectResponse("/login", 303)
|
|
|
|
|
|
|
|
|
|
|
|
form = await request.form()
|
|
|
|
|
|
data = dict(form)
|
|
|
|
|
|
|
|
|
|
|
|
errors = []
|
|
|
|
|
|
current_password = data.get("current_password", "")
|
|
|
|
|
|
if not current_password:
|
|
|
|
|
|
errors.append("Введите текущий пароль")
|
|
|
|
|
|
elif not verify_password(current_password, user.password_hash):
|
|
|
|
|
|
errors.append("Неверный текущий пароль")
|
|
|
|
|
|
|
|
|
|
|
|
password_errors = validate_reset_password(data)
|
|
|
|
|
|
errors.extend(password_errors)
|
|
|
|
|
|
|
|
|
|
|
|
if errors:
|
|
|
|
|
|
return templates.TemplateResponse("profile_change_password.html", {
|
|
|
|
|
|
"request": request, "user": user, "errors": errors,
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
user.password_hash = hash_password(data["password"])
|
|
|
|
|
|
db.commit()
|
|
|
|
|
|
|
|
|
|
|
|
return templates.TemplateResponse("profile_change_password.html", {
|
|
|
|
|
|
"request": request, "user": user, "success": "Пароль изменен",
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# DELETE ACCOUNT
|
|
|
|
|
|
@router.get("/profile/delete")
|
|
|
|
|
|
def delete_account_form(request: Request, user: User | None = Depends(get_current_user)):
|
|
|
|
|
|
if not user:
|
|
|
|
|
|
return RedirectResponse("/login", 303)
|
|
|
|
|
|
return templates.TemplateResponse("profile_delete.html", {"request": request, "user": user})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/profile/delete")
|
|
|
|
|
|
async def delete_account_submit(
|
|
|
|
|
|
request: Request,
|
|
|
|
|
|
db: Session = Depends(get_db),
|
|
|
|
|
|
user: User | None = Depends(get_current_user),
|
|
|
|
|
|
):
|
|
|
|
|
|
if not user:
|
|
|
|
|
|
return RedirectResponse("/login", 303)
|
|
|
|
|
|
|
|
|
|
|
|
form = await request.form()
|
|
|
|
|
|
data = dict(form)
|
|
|
|
|
|
|
|
|
|
|
|
password = data.get("password", "")
|
|
|
|
|
|
if not password:
|
|
|
|
|
|
return templates.TemplateResponse("profile_delete.html", {
|
|
|
|
|
|
"request": request, "user": user, "errors": ["Введите пароль для подтверждения"],
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
if not verify_password(password, user.password_hash):
|
|
|
|
|
|
return templates.TemplateResponse("profile_delete.html", {
|
|
|
|
|
|
"request": request, "user": user, "errors": ["Неверный пароль"],
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
db.delete(user)
|
|
|
|
|
|
db.commit()
|
|
|
|
|
|
request.session.clear()
|
|
|
|
|
|
|
|
|
|
|
|
return RedirectResponse("/", 303)
|