63 lines
2.0 KiB
Python
63 lines
2.0 KiB
Python
"""Правила повышения ранга."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.models.journal import JournalEventType
|
|
from app.models.mission import SubmissionStatus
|
|
from app.models.rank import Rank
|
|
from app.models.user import User
|
|
from app.services.journal import log_event
|
|
|
|
|
|
def _eligible_rank(user: User, db: Session) -> Rank | None:
|
|
"""Определяем максимальный ранг, который доступен пользователю."""
|
|
|
|
ranks = db.query(Rank).order_by(Rank.required_xp).all()
|
|
approved_missions = {
|
|
submission.mission_id
|
|
for submission in user.submissions
|
|
if submission.status == SubmissionStatus.APPROVED
|
|
}
|
|
competencies = {c.competency_id: c.level for c in user.competencies}
|
|
|
|
candidate: Rank | None = None
|
|
for rank in ranks:
|
|
if user.xp < rank.required_xp:
|
|
break
|
|
|
|
missions_ok = all(req.mission_id in approved_missions for req in rank.mission_requirements)
|
|
competencies_ok = all(
|
|
competencies.get(req.competency_id, 0) >= req.required_level
|
|
for req in rank.competency_requirements
|
|
)
|
|
if missions_ok and competencies_ok:
|
|
candidate = rank
|
|
|
|
return candidate
|
|
|
|
|
|
def apply_rank_upgrade(user: User, db: Session) -> Rank | None:
|
|
"""Пытаемся повысить ранг и фиксируем событие."""
|
|
|
|
new_rank = _eligible_rank(user, db)
|
|
if not new_rank or user.current_rank_id == new_rank.id:
|
|
return None
|
|
|
|
previous_rank_id = user.current_rank_id
|
|
user.current_rank_id = new_rank.id
|
|
db.add(user)
|
|
db.commit()
|
|
db.refresh(user)
|
|
|
|
log_event(
|
|
db,
|
|
user_id=user.id,
|
|
event_type=JournalEventType.RANK_UP,
|
|
title="Повышение ранга",
|
|
description=f"Пилот достиг ранга «{new_rank.title}».",
|
|
payload={"previous_rank_id": previous_rank_id, "new_rank_id": new_rank.id},
|
|
)
|
|
return new_rank
|