Files
DevOpsLab/app/api/v1/endpoints/profile.py
Сергей Антропов 1fbf9185a2 feat: добавлена пометка типа операции (Build/Push) в истории сборок Dockerfile
- Добавлена колонка 'Тип' во все таблицы истории сборок
- Для push операций отображается registry вместо платформ
- Сохранение пользователя при создании push лога
- Исправлена ошибка с logger в push_docker_image endpoint
- Улучшено отображение истории сборок с визуальными индикаторами
2026-02-15 22:59:02 +03:00

218 lines
7.8 KiB
Python

"""
API endpoints для управления профилем пользователя
Автор: Сергей Антропов
Сайт: https://devops.org.ru
"""
from fastapi import APIRouter, Request, HTTPException, Depends, Form
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.templating import Jinja2Templates
from pathlib import Path
from typing import Optional
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from app.db.session import get_async_db
from app.services.user_service import UserService
from app.models.user import User, UserProfile
from app.models.database import Preset, Dockerfile, Playbook, CommandHistory
from app.auth.deps import get_current_user
router = APIRouter()
templates_path = Path(__file__).parent.parent.parent.parent / "templates"
templates = Jinja2Templates(directory=str(templates_path))
@router.get("/profile", response_class=HTMLResponse)
async def profile_page(
request: Request,
current_user: dict = Depends(get_current_user),
db: AsyncSession = Depends(get_async_db)
):
"""Страница профиля пользователя"""
user = await UserService.get_user_by_username(db, current_user.get("username"))
if not user:
raise HTTPException(status_code=404, detail="Пользователь не найден")
# Получаем или создаем профиль
result = await db.execute(select(UserProfile).where(UserProfile.user_id == user.id))
profile = result.scalar_one_or_none()
if not profile:
profile = UserProfile(user_id=user.id)
db.add(profile)
await db.commit()
await db.refresh(profile)
# Получаем статистику пользователя
username = user.username
# Количество созданных preset'ов
presets_count = await db.execute(
select(func.count(Preset.id)).where(Preset.created_by == username)
)
presets_count = presets_count.scalar() or 0
# Количество созданных Dockerfile'ов
dockerfiles_count = await db.execute(
select(func.count(Dockerfile.id)).where(Dockerfile.created_by == username)
)
dockerfiles_count = dockerfiles_count.scalar() or 0
# Количество созданных playbook'ов
playbooks_count = await db.execute(
select(func.count(Playbook.id)).where(Playbook.created_by == username)
)
playbooks_count = playbooks_count.scalar() or 0
# Количество выполненных команд
commands_count = await db.execute(
select(func.count(CommandHistory.id)).where(CommandHistory.user == username)
)
commands_count = commands_count.scalar() or 0
# Количество успешных тестов
successful_tests = await db.execute(
select(func.count(CommandHistory.id)).where(
CommandHistory.user == username,
CommandHistory.command_type == "test",
CommandHistory.status == "success"
)
)
successful_tests = successful_tests.scalar() or 0
return templates.TemplateResponse(
"pages/profile/index.html",
{
"request": request,
"user": user,
"profile": profile,
"stats": {
"presets": presets_count,
"dockerfiles": dockerfiles_count,
"playbooks": playbooks_count,
"commands": commands_count,
"successful_tests": successful_tests
}
}
)
@router.post("/api/v1/profile")
async def update_profile(
request: Request,
email: Optional[str] = Form(None),
full_name: Optional[str] = Form(None),
current_user: dict = Depends(get_current_user),
db: AsyncSession = Depends(get_async_db)
):
"""Обновление профиля пользователя"""
user = await UserService.get_user_by_username(db, current_user.get("username"))
if not user:
raise HTTPException(status_code=404, detail="Пользователь не найден")
# Получаем или создаем профиль
result = await db.execute(select(UserProfile).where(UserProfile.user_id == user.id))
profile = result.scalar_one_or_none()
if not profile:
profile = UserProfile(user_id=user.id)
db.add(profile)
if email:
profile.email = email
if full_name:
profile.full_name = full_name
await db.commit()
await db.refresh(profile)
return JSONResponse(content={
"success": True,
"message": "Профиль обновлен успешно"
})
@router.get("/profile/docker-settings", response_class=HTMLResponse)
async def docker_settings_page(
request: Request,
current_user: dict = Depends(get_current_user),
db: AsyncSession = Depends(get_async_db)
):
"""Страница настроек Docker (Harbor и Docker Hub)"""
user = await UserService.get_user_by_username(db, current_user.get("username"))
if not user:
raise HTTPException(status_code=404, detail="Пользователь не найден")
# Получаем или создаем профиль
result = await db.execute(select(UserProfile).where(UserProfile.user_id == user.id))
profile = result.scalar_one_or_none()
if not profile:
profile = UserProfile(user_id=user.id)
db.add(profile)
await db.commit()
await db.refresh(profile)
return templates.TemplateResponse(
"pages/profile/docker-settings.html",
{
"request": request,
"profile": profile
}
)
@router.post("/api/v1/profile/docker-settings")
async def update_docker_settings(
request: Request,
dockerhub_username: Optional[str] = Form(None),
dockerhub_password: Optional[str] = Form(None),
dockerhub_repository: Optional[str] = Form(None),
harbor_url: Optional[str] = Form(None),
harbor_username: Optional[str] = Form(None),
harbor_password: Optional[str] = Form(None),
harbor_project: Optional[str] = Form(None),
current_user: dict = Depends(get_current_user),
db: AsyncSession = Depends(get_async_db)
):
"""Обновление настроек Docker"""
user = await UserService.get_user_by_username(db, current_user.get("username"))
if not user:
raise HTTPException(status_code=404, detail="Пользователь не найден")
# Получаем или создаем профиль
result = await db.execute(select(UserProfile).where(UserProfile.user_id == user.id))
profile = result.scalar_one_or_none()
if not profile:
profile = UserProfile(user_id=user.id)
db.add(profile)
# Обновляем настройки Docker Hub
if dockerhub_username is not None:
profile.dockerhub_username = dockerhub_username
if dockerhub_password:
# TODO: Зашифровать пароль перед сохранением
profile.dockerhub_password = dockerhub_password
if dockerhub_repository is not None:
profile.dockerhub_repository = dockerhub_repository
# Обновляем настройки Harbor
if harbor_url is not None:
profile.harbor_url = harbor_url
if harbor_username is not None:
profile.harbor_username = harbor_username
if harbor_password:
# TODO: Зашифровать пароль перед сохранением
profile.harbor_password = harbor_password
if harbor_project is not None:
profile.harbor_project = harbor_project
await db.commit()
await db.refresh(profile)
return JSONResponse(content={
"success": True,
"message": "Настройки Docker обновлены успешно"
})