Fix
This commit is contained in:
@@ -10,6 +10,7 @@ from app.core.config import settings
|
||||
from app.models import Marathon, MarathonStatus, GameProposalMode, Game, GameStatus, Challenge, Activity, ActivityType
|
||||
from app.schemas import GameCreate, GameUpdate, GameResponse, MessageResponse, UserPublic
|
||||
from app.services.storage import storage_service
|
||||
from app.services.telegram_notifier import telegram_notifier
|
||||
|
||||
router = APIRouter(tags=["games"])
|
||||
|
||||
@@ -268,6 +269,13 @@ async def approve_game(game_id: int, current_user: CurrentUser, db: DbSession):
|
||||
if game.status != GameStatus.PENDING.value:
|
||||
raise HTTPException(status_code=400, detail="Game is not pending")
|
||||
|
||||
# Get marathon title for notification
|
||||
marathon_result = await db.execute(select(Marathon).where(Marathon.id == game.marathon_id))
|
||||
marathon = marathon_result.scalar_one()
|
||||
|
||||
# Save proposer id before status change
|
||||
proposer_id = game.proposed_by_id
|
||||
|
||||
game.status = GameStatus.APPROVED.value
|
||||
game.approved_by_id = current_user.id
|
||||
|
||||
@@ -283,6 +291,12 @@ async def approve_game(game_id: int, current_user: CurrentUser, db: DbSession):
|
||||
await db.commit()
|
||||
await db.refresh(game)
|
||||
|
||||
# Notify proposer (if not self-approving)
|
||||
if proposer_id and proposer_id != current_user.id:
|
||||
await telegram_notifier.notify_game_approved(
|
||||
db, proposer_id, marathon.title, game.title
|
||||
)
|
||||
|
||||
# Need to reload relationships
|
||||
game = await get_game_or_404(db, game_id)
|
||||
challenges_count = await db.scalar(
|
||||
@@ -302,6 +316,14 @@ async def reject_game(game_id: int, current_user: CurrentUser, db: DbSession):
|
||||
if game.status != GameStatus.PENDING.value:
|
||||
raise HTTPException(status_code=400, detail="Game is not pending")
|
||||
|
||||
# Get marathon title for notification
|
||||
marathon_result = await db.execute(select(Marathon).where(Marathon.id == game.marathon_id))
|
||||
marathon = marathon_result.scalar_one()
|
||||
|
||||
# Save proposer id and game title before changes
|
||||
proposer_id = game.proposed_by_id
|
||||
game_title = game.title
|
||||
|
||||
game.status = GameStatus.REJECTED.value
|
||||
|
||||
# Log activity
|
||||
@@ -316,6 +338,12 @@ async def reject_game(game_id: int, current_user: CurrentUser, db: DbSession):
|
||||
await db.commit()
|
||||
await db.refresh(game)
|
||||
|
||||
# Notify proposer
|
||||
if proposer_id and proposer_id != current_user.id:
|
||||
await telegram_notifier.notify_game_rejected(
|
||||
db, proposer_id, marathon.title, game_title
|
||||
)
|
||||
|
||||
# Need to reload relationships
|
||||
game = await get_game_or_404(db, game_id)
|
||||
challenges_count = await db.scalar(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from datetime import timedelta
|
||||
import secrets
|
||||
import string
|
||||
from fastapi import APIRouter, HTTPException, status
|
||||
from sqlalchemy import select, func
|
||||
from sqlalchemy.orm import selectinload
|
||||
@@ -10,7 +11,7 @@ from app.api.deps import (
|
||||
get_participant,
|
||||
)
|
||||
from app.models import (
|
||||
Marathon, Participant, MarathonStatus, Game, GameStatus,
|
||||
Marathon, Participant, MarathonStatus, Game, GameStatus, Challenge,
|
||||
Assignment, AssignmentStatus, Activity, ActivityType, ParticipantRole,
|
||||
)
|
||||
from app.schemas import (
|
||||
@@ -40,7 +41,7 @@ async def get_marathon_by_code(invite_code: str, db: DbSession):
|
||||
select(Marathon, func.count(Participant.id).label("participants_count"))
|
||||
.outerjoin(Participant)
|
||||
.options(selectinload(Marathon.creator))
|
||||
.where(Marathon.invite_code == invite_code)
|
||||
.where(func.upper(Marathon.invite_code) == invite_code.upper())
|
||||
.group_by(Marathon.id)
|
||||
)
|
||||
row = result.first()
|
||||
@@ -62,7 +63,9 @@ async def get_marathon_by_code(invite_code: str, db: DbSession):
|
||||
|
||||
|
||||
def generate_invite_code() -> str:
|
||||
return secrets.token_urlsafe(8)
|
||||
"""Generate a clean 8-character uppercase alphanumeric code."""
|
||||
alphabet = string.ascii_uppercase + string.digits
|
||||
return ''.join(secrets.choice(alphabet) for _ in range(8))
|
||||
|
||||
|
||||
async def get_marathon_or_404(db, marathon_id: int) -> Marathon:
|
||||
@@ -272,15 +275,33 @@ async def start_marathon(marathon_id: int, current_user: CurrentUser, db: DbSess
|
||||
if marathon.status != MarathonStatus.PREPARING.value:
|
||||
raise HTTPException(status_code=400, detail="Marathon is not in preparing state")
|
||||
|
||||
# Check if there are approved games with challenges
|
||||
games_count = await db.scalar(
|
||||
select(func.count()).select_from(Game).where(
|
||||
# Check if there are approved games
|
||||
games_result = await db.execute(
|
||||
select(Game).where(
|
||||
Game.marathon_id == marathon_id,
|
||||
Game.status == GameStatus.APPROVED.value,
|
||||
)
|
||||
)
|
||||
if games_count == 0:
|
||||
raise HTTPException(status_code=400, detail="Add and approve at least one game before starting")
|
||||
approved_games = games_result.scalars().all()
|
||||
|
||||
if len(approved_games) == 0:
|
||||
raise HTTPException(status_code=400, detail="Добавьте и одобрите хотя бы одну игру")
|
||||
|
||||
# Check that all approved games have at least one challenge
|
||||
games_without_challenges = []
|
||||
for game in approved_games:
|
||||
challenge_count = await db.scalar(
|
||||
select(func.count()).select_from(Challenge).where(Challenge.game_id == game.id)
|
||||
)
|
||||
if challenge_count == 0:
|
||||
games_without_challenges.append(game.title)
|
||||
|
||||
if games_without_challenges:
|
||||
games_list = ", ".join(games_without_challenges)
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"У следующих игр нет челленджей: {games_list}"
|
||||
)
|
||||
|
||||
marathon.status = MarathonStatus.ACTIVE.value
|
||||
|
||||
@@ -332,7 +353,7 @@ async def finish_marathon(marathon_id: int, current_user: CurrentUser, db: DbSes
|
||||
@router.post("/join", response_model=MarathonResponse)
|
||||
async def join_marathon(data: JoinMarathon, current_user: CurrentUser, db: DbSession):
|
||||
result = await db.execute(
|
||||
select(Marathon).where(Marathon.invite_code == data.invite_code)
|
||||
select(Marathon).where(func.upper(Marathon.invite_code) == data.invite_code.upper())
|
||||
)
|
||||
marathon = result.scalar_one_or_none()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user