Skip to content

Commit

Permalink
Fix paths of swiss endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
evroon committed Sep 10, 2024
1 parent bb1dd7e commit 1b708e5
Show file tree
Hide file tree
Showing 9 changed files with 64 additions and 45 deletions.
35 changes: 26 additions & 9 deletions backend/bracket/logic/scheduling/upcoming_matches.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,43 @@
from bracket.logic.scheduling.ladder_teams import get_possible_upcoming_matches_for_swiss
from bracket.models.db.match import MatchFilter, SuggestedMatch
from bracket.models.db.round import Round
from bracket.models.db.stage_item import StageType
from bracket.models.db.stage_item import StageItem, StageType
from bracket.models.db.util import RoundWithMatches, StageItemWithRounds
from bracket.sql.rounds import get_rounds_for_stage_item
from bracket.sql.stages import get_full_tournament_details
from bracket.sql.teams import get_teams_with_members
from bracket.utils.id_types import TournamentId
from bracket.utils.id_types import StageItemId, TournamentId
from bracket.utils.types import assert_some


async def get_upcoming_matches_for_swiss_round(
match_filter: MatchFilter, round_: Round, tournament_id: TournamentId
) -> list[SuggestedMatch]:
[stage] = await get_full_tournament_details(
tournament_id, stage_item_ids={round_.stage_item_id}
async def get_draft_round_in_stage_item(
tournament_id: TournamentId,
stage_item_id: StageItemId,
) -> tuple[RoundWithMatches, StageItemWithRounds]:
[stage] = await get_full_tournament_details(tournament_id, stage_item_ids={stage_item_id})
draft_round, stage_item = next(
(
(round_, stage_item)
for stage_item in stage.stage_items
for round_ in stage_item.rounds
if round_.is_draft
),
(None, None),
)
assert len(stage.stage_items) == 1
[stage_item] = stage.stage_items
if draft_round is None or stage_item is None:
raise HTTPException(400, "Expected stage item to be of type SWISS.")

Check warning on line 30 in backend/bracket/logic/scheduling/upcoming_matches.py

View check run for this annotation

Codecov / codecov/patch

backend/bracket/logic/scheduling/upcoming_matches.py#L30

Added line #L30 was not covered by tests
return draft_round, stage_item


async def get_upcoming_matches_for_swiss_round(
match_filter: MatchFilter, stage_item: StageItem, round_: Round, tournament_id: TournamentId
) -> list[SuggestedMatch]:
if stage_item.type is not StageType.SWISS:
raise HTTPException(400, "Expected stage item to be of type SWISS.")

if not round_.is_draft:
raise HTTPException(400, "There is no draft round, so no matches can be scheduled.")

Check warning on line 41 in backend/bracket/logic/scheduling/upcoming_matches.py

View check run for this annotation

Codecov / codecov/patch

backend/bracket/logic/scheduling/upcoming_matches.py#L41

Added line #L41 was not covered by tests

rounds = await get_rounds_for_stage_item(tournament_id, assert_some(stage_item.id))
teams = await get_teams_with_members(tournament_id, only_active_teams=True)

Expand Down
36 changes: 17 additions & 19 deletions backend/bracket/routes/matches.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from fastapi import APIRouter, Depends, HTTPException
from fastapi import APIRouter, Depends

from bracket.logic.planning.matches import (
get_scheduled_matches,
Expand All @@ -10,6 +10,7 @@
recalculate_ranking_for_stage_item_id,
)
from bracket.logic.scheduling.upcoming_matches import (
get_draft_round_in_stage_item,
get_upcoming_matches_for_swiss_round,
)
from bracket.models.db.match import (
Expand All @@ -21,36 +22,34 @@
MatchRescheduleBody,
SuggestedMatch,
)
from bracket.models.db.round import Round
from bracket.models.db.user import UserPublic
from bracket.models.db.util import RoundWithMatches
from bracket.routes.auth import user_authenticated_for_tournament
from bracket.routes.models import SingleMatchResponse, SuccessResponse, UpcomingMatchesResponse
from bracket.routes.util import match_dependency, round_dependency, round_with_matches_dependency
from bracket.routes.util import match_dependency
from bracket.sql.courts import get_all_courts_in_tournament
from bracket.sql.matches import sql_create_match, sql_delete_match, sql_update_match
from bracket.sql.rounds import get_round_by_id
from bracket.sql.stages import get_full_tournament_details
from bracket.sql.tournaments import sql_get_tournament
from bracket.sql.validation import check_foreign_keys_belong_to_tournament
from bracket.utils.id_types import MatchId, TournamentId
from bracket.utils.id_types import MatchId, StageItemId, TournamentId
from bracket.utils.types import assert_some

router = APIRouter()


@router.get(
"/tournaments/{tournament_id}/rounds/{round_id}/upcoming_matches",
"/tournaments/{tournament_id}/stage_items/{stage_item_id}/upcoming_matches",
response_model=UpcomingMatchesResponse,
)
async def get_matches_to_schedule(
tournament_id: TournamentId,
stage_item_id: StageItemId,
elo_diff_threshold: int = 200,
iterations: int = 200,
only_recommended: bool = False,
limit: int = 50,
_: UserPublic = Depends(user_authenticated_for_tournament),
round_: Round = Depends(round_dependency),
) -> UpcomingMatchesResponse:
match_filter = MatchFilter(
elo_diff_threshold=elo_diff_threshold,
Expand All @@ -59,11 +58,12 @@ async def get_matches_to_schedule(
iterations=iterations,
)

if not round_.is_draft:
raise HTTPException(400, "There is no draft round, so no matches can be scheduled.")
draft_round, stage_item = await get_draft_round_in_stage_item(tournament_id, stage_item_id)

return UpcomingMatchesResponse(
data=await get_upcoming_matches_for_swiss_round(match_filter, round_, tournament_id)
data=await get_upcoming_matches_for_swiss_round(
match_filter, stage_item, draft_round, tournament_id
)
)


Expand Down Expand Up @@ -123,45 +123,43 @@ async def reschedule_match(


@router.post(
"/tournaments/{tournament_id}/rounds/{round_id}/schedule_auto",
"/tournaments/{tournament_id}/stage_items/{stage_item_id}/schedule_auto",
response_model=SuccessResponse,
)
async def create_matches_automatically(
tournament_id: TournamentId,
stage_item_id: StageItemId,
elo_diff_threshold: int = 100,
iterations: int = 200,
only_recommended: bool = False,
_: UserPublic = Depends(user_authenticated_for_tournament),
round_: RoundWithMatches = Depends(round_with_matches_dependency),
) -> SuccessResponse:
if not round_.is_draft:
raise HTTPException(400, "There is no draft round, so no matches can be scheduled.")

match_filter = MatchFilter(
elo_diff_threshold=elo_diff_threshold,
only_recommended=only_recommended,
limit=1,
iterations=iterations,
)

draft_round, stage_item = await get_draft_round_in_stage_item(tournament_id, stage_item_id)
courts = await get_all_courts_in_tournament(tournament_id)
tournament = await sql_get_tournament(tournament_id)

limit = len(courts) - len(round_.matches)
limit = len(courts) - len(draft_round.matches)
for __ in range(limit):
all_matches_to_schedule = await get_upcoming_matches_for_swiss_round(
match_filter, round_, tournament_id
match_filter, stage_item, draft_round, tournament_id
)
if len(all_matches_to_schedule) < 1:
break

match = all_matches_to_schedule[0]
assert isinstance(match, SuggestedMatch)

assert round_.id and match.team1.id and match.team2.id
assert draft_round.id and match.team1.id and match.team2.id
await sql_create_match(
MatchCreateBody(
round_id=round_.id,
round_id=draft_round.id,
team1_id=match.team1.id,
team2_id=match.team2.id,
court_id=None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,13 @@ async def test_schedule_matches_auto(
],
),
)
round_1_id = await sql_create_round(
await sql_create_round(
RoundToInsert(stage_item_id=stage_item_1.id, name="", is_draft=True, is_active=False),
)

response = await send_tournament_request(
HTTPMethod.POST,
f"rounds/{round_1_id}/schedule_auto",
f"stage_items/{stage_item_1.id}/schedule_auto",
auth_context,
)
stages = await get_full_tournament_details(tournament_id)
Expand Down
7 changes: 5 additions & 2 deletions backend/tests/integration_tests/api/matches_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ async def test_upcoming_matches_endpoint(
"stage_item_id": stage_item_inserted.id,
}
)
) as round_inserted,
),
inserted_team(
DUMMY_TEAM1.model_copy(
update={"tournament_id": auth_context.tournament.id, "elo_score": Decimal("1150.0")}
Expand Down Expand Up @@ -308,7 +308,10 @@ async def test_upcoming_matches_endpoint(
) as player_inserted_4,
):
json_response = await send_tournament_request(
HTTPMethod.GET, f"rounds/{round_inserted.id}/upcoming_matches", auth_context, {}
HTTPMethod.GET,
f"stage_items/{stage_item_inserted.id}/upcoming_matches",
auth_context,
{},
)
assert json_response == {
"data": [
Expand Down
9 changes: 3 additions & 6 deletions frontend/src/components/buttons/create_matches_auto.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,16 @@ export function AutoCreateMatchesButton({
tournamentData,
swrStagesResponse,
swrUpcomingMatchesResponse,
roundId,
stageItemId,
schedulerSettings,
}: {
schedulerSettings: SchedulerSettings;
roundId: number;
stageItemId: number;
tournamentData: Tournament;
swrStagesResponse: SWRResponse;
swrUpcomingMatchesResponse: SWRResponse;
}) {
const { t } = useTranslation();
if (roundId == null) {
return null;
}
return (
<Button
size="md"
Expand All @@ -35,7 +32,7 @@ export function AutoCreateMatchesButton({
onClick={async () => {
await createMatchesAuto(
tournamentData.id,
roundId,
stageItemId,
schedulerSettings.eloThreshold,
schedulerSettings.onlyRecommended,
schedulerSettings.iterations
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/components/scheduling/scheduling.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { BracketDisplaySettings } from '../../interfaces/brackets';
import { SchedulerSettings } from '../../interfaces/match';
import { RoundInterface } from '../../interfaces/round';
import { StageWithStageItems } from '../../interfaces/stage';
import { StageItemWithRounds } from '../../interfaces/stage_item';
import { Tournament } from '../../interfaces/tournament';
import { AutoCreateMatchesButton } from '../buttons/create_matches_auto';
import UpcomingMatchesTable from '../tables/upcoming_matches';
Expand Down Expand Up @@ -40,6 +41,7 @@ function SchedulingSystem({

export default function Scheduler({
activeStage,
stageItem,
tournamentData,
draftRound,
swrRoundsResponse,
Expand All @@ -48,6 +50,7 @@ export default function Scheduler({
displaySettings,
}: {
activeStage: StageWithStageItems;
stageItem: StageItemWithRounds;
draftRound: RoundInterface;
tournamentData: Tournament;
swrRoundsResponse: SWRResponse;
Expand All @@ -70,7 +73,7 @@ export default function Scheduler({
swrStagesResponse={swrRoundsResponse}
swrUpcomingMatchesResponse={swrUpcomingMatchesResponse}
tournamentData={tournamentData}
roundId={draftRound.id}
stageItemId={stageItem.id}
schedulerSettings={schedulerSettings}
/>
</Group>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export default function TournamentPage() {
}
}

const swrUpcomingMatchesResponse = getUpcomingMatches(id, draftRound?.id, schedulerSettings);
const swrUpcomingMatchesResponse = getUpcomingMatches(id, stageItemId, schedulerSettings);
const scheduler =
draftRound != null &&
stageItem != null &&
Expand All @@ -100,6 +100,7 @@ export default function TournamentPage() {
<>
<Scheduler
activeStage={activeStage}
stageItem={stageItem}
draftRound={draftRound}
tournamentData={tournamentDataFull}
swrRoundsResponse={swrStagesResponse}
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/services/adapter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,13 +197,13 @@ export function getUser(): SWRResponse {

export function getUpcomingMatches(
tournament_id: number,
round_id: number,
stage_item_id: number,
schedulerSettings: SchedulerSettings
): SWRResponse {
return useSWR(
round_id == null
stage_item_id == null
? null
: `tournaments/${tournament_id}/rounds/${round_id}/upcoming_matches?elo_diff_threshold=${schedulerSettings.eloThreshold}&only_recommended=${schedulerSettings.onlyRecommended}&limit=${schedulerSettings.limit}&iterations=${schedulerSettings.iterations}`,
: `tournaments/${tournament_id}/stage_items/${stage_item_id}/upcoming_matches?elo_diff_threshold=${schedulerSettings.eloThreshold}&only_recommended=${schedulerSettings.onlyRecommended}&limit=${schedulerSettings.limit}&iterations=${schedulerSettings.iterations}`,
fetcher
);
}
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/services/round.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ export async function createRound(tournament_id: number, stage_item_id: number)

export async function createMatchesAuto(
tournament_id: number,
round_id: number,
stage_item_id: number,
elo_diff_threshold: number,
only_recommended: string,
iterations: number
) {
return createAxios()
.post(`tournaments/${tournament_id}/rounds/${round_id}/schedule_auto`, {
.post(`tournaments/${tournament_id}/stage_items/${stage_item_id}/schedule_auto`, {
elo_diff_threshold,
only_recommended,
iterations,
Expand Down

0 comments on commit 1b708e5

Please sign in to comment.