Редактор ачивок в админке + файловое хранилище ачивок (задел под титулы)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
"""Админ-роутер: отдельный вход (логин+пароль) и управление сущностями."""
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Depends, Query, Request, Response
|
||||
from fastapi import APIRouter, Depends, File, Query, Request, Response, UploadFile
|
||||
from sqlmodel import Session
|
||||
|
||||
from app.auth.deps import get_current_admin
|
||||
@@ -11,7 +11,15 @@ from app.db.session import get_session
|
||||
from app.models import User
|
||||
from app.routers.matches import build_match_read
|
||||
from app.schemas import api as s
|
||||
from app.services import admin_service, audit_service, faction_service, match_service
|
||||
from app.services import (
|
||||
achievement_service,
|
||||
admin_service,
|
||||
audit_service,
|
||||
faction_service,
|
||||
match_service,
|
||||
)
|
||||
|
||||
_ACHIEVEMENT_ICON_MAX_BYTES = 2 * 1024 * 1024 # 2 МБ
|
||||
from app.services.match_service import ParticipantInput
|
||||
|
||||
router = APIRouter(prefix="/admin", tags=["admin"])
|
||||
@@ -284,6 +292,82 @@ def delete_match(
|
||||
return s.OkResponse()
|
||||
|
||||
|
||||
# ─── Ачивки (определения; выдача игрокам — на будущее) ────────────────────────
|
||||
|
||||
@router.get("/achievements", response_model=list[s.AchievementRead])
|
||||
def list_achievements(
|
||||
_admin: User = Depends(get_current_admin),
|
||||
) -> list[dict]:
|
||||
return achievement_service.list_achievements()
|
||||
|
||||
|
||||
@router.post("/achievements", response_model=s.AchievementRead)
|
||||
def create_achievement(
|
||||
body: s.AchievementCreate,
|
||||
request: Request,
|
||||
session: Session = Depends(get_session),
|
||||
admin: User = Depends(get_current_admin),
|
||||
) -> dict:
|
||||
ach = achievement_service.create(body.name, body.description, body.condition)
|
||||
audit_service.record(
|
||||
session, actor_id=admin.id, action="create", entity_type="achievement",
|
||||
payload={"slug": ach["slug"], "name": ach["name"]},
|
||||
ip=request.client.host if request.client else None,
|
||||
)
|
||||
session.commit()
|
||||
return ach
|
||||
|
||||
|
||||
@router.patch("/achievements/{slug}", response_model=s.AchievementRead)
|
||||
def update_achievement(
|
||||
slug: str,
|
||||
body: s.AchievementUpdate,
|
||||
request: Request,
|
||||
session: Session = Depends(get_session),
|
||||
admin: User = Depends(get_current_admin),
|
||||
) -> dict:
|
||||
ach = achievement_service.update(
|
||||
slug, name=body.name, description=body.description, condition=body.condition
|
||||
)
|
||||
audit_service.record(
|
||||
session, actor_id=admin.id, action="update", entity_type="achievement",
|
||||
payload={"slug": slug}, ip=request.client.host if request.client else None,
|
||||
)
|
||||
session.commit()
|
||||
return ach
|
||||
|
||||
|
||||
@router.put("/achievements/{slug}/icon", response_model=s.AchievementRead)
|
||||
def upload_achievement_icon(
|
||||
slug: str,
|
||||
file: UploadFile = File(...),
|
||||
_admin: User = Depends(get_current_admin),
|
||||
) -> dict:
|
||||
from app.core.errors import ValidationError
|
||||
|
||||
content = file.file.read(_ACHIEVEMENT_ICON_MAX_BYTES + 1)
|
||||
if len(content) > _ACHIEVEMENT_ICON_MAX_BYTES:
|
||||
raise ValidationError("Файл слишком большой (макс. 2 МБ).")
|
||||
ext = achievement_service.validate_icon(content)
|
||||
return achievement_service.set_icon(slug, content, ext)
|
||||
|
||||
|
||||
@router.delete("/achievements/{slug}", response_model=s.OkResponse)
|
||||
def delete_achievement(
|
||||
slug: str,
|
||||
request: Request,
|
||||
session: Session = Depends(get_session),
|
||||
admin: User = Depends(get_current_admin),
|
||||
) -> s.OkResponse:
|
||||
achievement_service.delete(slug)
|
||||
audit_service.record(
|
||||
session, actor_id=admin.id, action="delete", entity_type="achievement",
|
||||
payload={"slug": slug}, ip=request.client.host if request.client else None,
|
||||
)
|
||||
session.commit()
|
||||
return s.OkResponse()
|
||||
|
||||
|
||||
# ─── Журнал аудита ───────────────────────────────────────────────────────────
|
||||
|
||||
@router.get("/audit-logs", response_model=s.AuditLogList)
|
||||
|
||||
Reference in New Issue
Block a user