168 lines
5.8 KiB
Python
168 lines
5.8 KiB
Python
"""HR-панель и административные действия."""
|
||
|
||
from __future__ import annotations
|
||
|
||
from fastapi import APIRouter, Depends, HTTPException, status
|
||
from sqlalchemy.orm import Session
|
||
|
||
from app.api.deps import require_hr
|
||
from app.db.session import get_db
|
||
from app.models.branch import BranchMission
|
||
from app.models.mission import Mission, MissionCompetencyReward, MissionPrerequisite, MissionSubmission, SubmissionStatus
|
||
from app.models.rank import Rank
|
||
from app.schemas.mission import MissionBase, MissionCreate, MissionDetail, MissionSubmissionRead
|
||
from app.schemas.rank import RankBase
|
||
from app.services.mission import approve_submission, reject_submission
|
||
|
||
router = APIRouter(prefix="/api/admin", tags=["admin"])
|
||
|
||
|
||
@router.get("/missions", response_model=list[MissionBase], summary="Миссии (HR)")
|
||
def admin_missions(*, db: Session = Depends(get_db), current_user=Depends(require_hr)) -> list[MissionBase]:
|
||
"""Список всех миссий для HR."""
|
||
|
||
missions = db.query(Mission).order_by(Mission.title).all()
|
||
return [MissionBase.model_validate(mission) for mission in missions]
|
||
|
||
|
||
@router.post("/missions", response_model=MissionDetail, summary="Создать миссию")
|
||
def create_mission_endpoint(
|
||
mission_in: MissionCreate,
|
||
*,
|
||
db: Session = Depends(get_db),
|
||
current_user=Depends(require_hr),
|
||
) -> MissionDetail:
|
||
"""Создаём новую миссию."""
|
||
|
||
mission = Mission(
|
||
title=mission_in.title,
|
||
description=mission_in.description,
|
||
xp_reward=mission_in.xp_reward,
|
||
mana_reward=mission_in.mana_reward,
|
||
difficulty=mission_in.difficulty,
|
||
minimum_rank_id=mission_in.minimum_rank_id,
|
||
artifact_id=mission_in.artifact_id,
|
||
)
|
||
db.add(mission)
|
||
db.flush()
|
||
|
||
for reward in mission_in.competency_rewards:
|
||
db.add(
|
||
MissionCompetencyReward(
|
||
mission_id=mission.id,
|
||
competency_id=reward.competency_id,
|
||
level_delta=reward.level_delta,
|
||
)
|
||
)
|
||
|
||
for prerequisite_id in mission_in.prerequisite_ids:
|
||
db.add(
|
||
MissionPrerequisite(mission_id=mission.id, required_mission_id=prerequisite_id)
|
||
)
|
||
|
||
if mission_in.branch_id:
|
||
db.add(
|
||
BranchMission(
|
||
branch_id=mission_in.branch_id,
|
||
mission_id=mission.id,
|
||
order=mission_in.branch_order,
|
||
)
|
||
)
|
||
|
||
db.commit()
|
||
db.refresh(mission)
|
||
|
||
return MissionDetail(
|
||
id=mission.id,
|
||
title=mission.title,
|
||
description=mission.description,
|
||
xp_reward=mission.xp_reward,
|
||
mana_reward=mission.mana_reward,
|
||
difficulty=mission.difficulty,
|
||
is_active=mission.is_active,
|
||
minimum_rank_id=mission.minimum_rank_id,
|
||
artifact_id=mission.artifact_id,
|
||
prerequisites=[link.required_mission_id for link in mission.prerequisites],
|
||
competency_rewards=[
|
||
{
|
||
"competency_id": reward.competency_id,
|
||
"competency_name": reward.competency.name,
|
||
"level_delta": reward.level_delta,
|
||
}
|
||
for reward in mission.competency_rewards
|
||
],
|
||
created_at=mission.created_at,
|
||
updated_at=mission.updated_at,
|
||
)
|
||
|
||
|
||
@router.get("/ranks", response_model=list[RankBase], summary="Список рангов")
|
||
def admin_ranks(*, db: Session = Depends(get_db), current_user=Depends(require_hr)) -> list[RankBase]:
|
||
"""Перечень рангов."""
|
||
|
||
ranks = db.query(Rank).order_by(Rank.required_xp).all()
|
||
return [RankBase.model_validate(rank) for rank in ranks]
|
||
|
||
|
||
@router.get(
|
||
"/submissions",
|
||
response_model=list[MissionSubmissionRead],
|
||
summary="Очередь модерации",
|
||
)
|
||
def moderation_queue(
|
||
status_filter: SubmissionStatus = SubmissionStatus.PENDING,
|
||
*,
|
||
db: Session = Depends(get_db),
|
||
current_user=Depends(require_hr),
|
||
) -> list[MissionSubmissionRead]:
|
||
"""Возвращаем отправки со статусом по умолчанию pending."""
|
||
|
||
submissions = (
|
||
db.query(MissionSubmission)
|
||
.filter(MissionSubmission.status == status_filter)
|
||
.order_by(MissionSubmission.created_at)
|
||
.all()
|
||
)
|
||
return [MissionSubmissionRead.model_validate(submission) for submission in submissions]
|
||
|
||
|
||
@router.post(
|
||
"/submissions/{submission_id}/approve",
|
||
response_model=MissionSubmissionRead,
|
||
summary="Одобрить миссию",
|
||
)
|
||
def approve_submission_endpoint(
|
||
submission_id: int,
|
||
*,
|
||
db: Session = Depends(get_db),
|
||
current_user=Depends(require_hr),
|
||
) -> MissionSubmissionRead:
|
||
"""HR подтверждает выполнение."""
|
||
|
||
submission = db.query(MissionSubmission).filter(MissionSubmission.id == submission_id).first()
|
||
if not submission:
|
||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Отправка не найдена")
|
||
submission = approve_submission(db, submission)
|
||
return MissionSubmissionRead.model_validate(submission)
|
||
|
||
|
||
@router.post(
|
||
"/submissions/{submission_id}/reject",
|
||
response_model=MissionSubmissionRead,
|
||
summary="Отклонить миссию",
|
||
)
|
||
def reject_submission_endpoint(
|
||
submission_id: int,
|
||
comment: str | None = None,
|
||
*,
|
||
db: Session = Depends(get_db),
|
||
current_user=Depends(require_hr),
|
||
) -> MissionSubmissionRead:
|
||
"""HR отклоняет выполнение."""
|
||
|
||
submission = db.query(MissionSubmission).filter(MissionSubmission.id == submission_id).first()
|
||
if not submission:
|
||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Отправка не найдена")
|
||
submission = reject_submission(db, submission, comment)
|
||
return MissionSubmissionRead.model_validate(submission)
|