feat: добавлена пометка типа операции (Build/Push) в истории сборок Dockerfile
- Добавлена колонка 'Тип' во все таблицы истории сборок - Для push операций отображается registry вместо платформ - Сохранение пользователя при создании push лога - Исправлена ошибка с logger в push_docker_image endpoint - Улучшено отображение истории сборок с визуальными индикаторами
This commit is contained in:
217
app/api/v1/endpoints/profile.py
Normal file
217
app/api/v1/endpoints/profile.py
Normal file
@@ -0,0 +1,217 @@
|
||||
"""
|
||||
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 обновлены успешно"
|
||||
})
|
||||
Reference in New Issue
Block a user