Skip to content

Commit 2fa8c08

Browse files
authored
Add teams with players (#1118)
fixes #978
1 parent 9b88dff commit 2fa8c08

File tree

4 files changed

+52
-24
lines changed

4 files changed

+52
-24
lines changed

backend/bracket/routes/teams.py

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import csv
12
import os
23
from uuid import uuid4
34

@@ -9,6 +10,7 @@
910
from bracket.database import database
1011
from bracket.logic.subscriptions import check_requirement
1112
from bracket.logic.teams import get_team_logo_path
13+
from bracket.models.db.player import PlayerBody
1214
from bracket.models.db.team import (
1315
FullTeamWithPlayers,
1416
Team,
@@ -34,6 +36,7 @@
3436
team_with_players_dependency,
3537
)
3638
from bracket.schema import players_x_teams, teams
39+
from bracket.sql.players import get_all_players_in_tournament, insert_player
3740
from bracket.sql.teams import (
3841
get_team_by_id,
3942
get_team_count,
@@ -209,19 +212,31 @@ async def create_multiple_teams(
209212
user: UserPublic = Depends(user_authenticated_for_tournament),
210213
_: Tournament = Depends(disallow_archived_tournament),
211214
) -> SuccessResponse:
212-
team_names = [team.strip() for team in team_body.names.split("\n") if len(team) > 0]
215+
reader = list(csv.reader(team_body.names.split("\n"), delimiter=","))
216+
teams_and_players = [
217+
(row[0], row[1:] if len(row) > 1 else []) for row in reader if len(row) > 0
218+
]
219+
players = [player for row in teams_and_players for player in row[1]]
220+
213221
existing_teams = await get_teams_with_members(tournament_id)
214-
check_requirement(existing_teams, user, "max_teams", additions=len(team_names))
215-
216-
for team_name in team_names:
217-
await database.execute(
218-
query=teams.insert(),
219-
values=TeamInsertable(
220-
name=team_name,
221-
active=team_body.active,
222-
created=datetime_utc.now(),
223-
tournament_id=tournament_id,
224-
).model_dump(),
225-
)
222+
existing_players = await get_all_players_in_tournament(tournament_id)
223+
224+
check_requirement(existing_teams, user, "max_teams", additions=len(reader))
225+
check_requirement(existing_players, user, "max_players", additions=len(players))
226+
227+
async with database.transaction():
228+
for team_name, players in teams_and_players:
229+
await database.execute(
230+
query=teams.insert(),
231+
values=TeamInsertable(
232+
name=team_name,
233+
active=team_body.active,
234+
created=datetime_utc.now(),
235+
tournament_id=tournament_id,
236+
).model_dump(),
237+
)
238+
for player in players:
239+
player_body = PlayerBody(name=player, active=team_body.active)
240+
await insert_player(player_body, tournament_id)
226241

227242
return SuccessResponse()

backend/tests/integration_tests/api/teams_test.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from bracket.database import database
66
from bracket.models.db.team import Team
7-
from bracket.schema import teams
7+
from bracket.schema import players, teams
88
from bracket.utils.db import fetch_one_parsed_certain
99
from bracket.utils.dummy_records import DUMMY_MOCK_TIME, DUMMY_TEAM1
1010
from bracket.utils.http import HTTPMethod
@@ -57,12 +57,13 @@ async def test_create_team(
5757
async def test_create_teams(
5858
startup_and_shutdown_uvicorn_server: None, auth_context: AuthContext
5959
) -> None:
60-
body = {"names": "Team -1\nTeam -2", "active": True}
60+
body = {"names": "Team -1,Player 42,Player 43\nTeam -2", "active": True}
6161
response = await send_tournament_request(
6262
HTTPMethod.POST, "teams_multi", auth_context, None, body
6363
)
6464
assert response["success"] is True
6565
await assert_row_count_and_clear(teams, 2)
66+
await assert_row_count_and_clear(players, 3)
6667

6768

6869
@pytest.mark.asyncio(loop_scope="session")

frontend/public/locales/en/common.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
"all_matches_scheduled_description": "Matches have been scheduled on all courts in this round. Add a new round or add a new court for more matches.",
3232
"api_docs_title": "API docs",
3333
"archive_tournament_button": "Archive Tournament",
34-
"archived_label": "Archived",
3534
"archived_header_label": "This tournament is archived. It is now read-only.",
35+
"archived_label": "Archived",
3636
"at_least_one_player_validation": "Enter at least one player",
3737
"at_least_one_team_validation": "Enter at least one team",
3838
"at_least_two_team_validation": "Need at least two teams",
@@ -116,6 +116,7 @@
116116
"empty_name_validation": "Name cannot be empty",
117117
"empty_password_validation": "Password cannot be empty",
118118
"empty_slot": "Empty slot",
119+
"example_label": "Example:",
119120
"filter_stage_item_label": "Filter on stage item",
120121
"filter_stage_item_placeholder": "No filter",
121122
"forgot_password_button": "Forgot password?",
@@ -152,7 +153,7 @@
152153
"multiple_players_input_placeholder": "Player 1",
153154
"multiple_players_title": "Multiple Players",
154155
"multiple_teams": "Multiple Teams",
155-
"multiple_teams_input_label": "Add multiple teams. Put every team on a separate line",
156+
"multiple_teams_input_label": "Add multiple teams. Put every team on a separate line. You can also add players per team, separated by `,`.",
156157
"multiple_teams_input_placeholder": "Team 1",
157158
"name_field_text": "name",
158159
"name_input_label": "Name",
@@ -236,6 +237,7 @@
236237
"team_count_input_round_robin_label": "Number of teams advancing from the previous stage",
237238
"team_count_select_elimination_label": "Number of teams advancing from the previous stage",
238239
"team_count_select_elimination_placeholder": "2, 4, 8 etc.",
240+
"team_member_select_placeholder": "Pick team members for this team",
239241
"team_member_select_title": "Team members",
240242
"team_name_input_placeholder": "Best Team Ever",
241243
"team_title": "Team",

frontend/src/components/forms/player_create_csv_input.tsx

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Textarea } from '@mantine/core';
1+
import { Code, Text, Textarea } from '@mantine/core';
22
import { UseFormReturnType } from '@mantine/form';
33
import { useTranslation } from 'next-i18next';
44
import React from 'react';
@@ -18,11 +18,21 @@ export function MultiPlayersInput({ form }: { form: UseFormReturnType<any> }) {
1818
export function MultiTeamsInput({ form }: { form: UseFormReturnType<any> }) {
1919
const { t } = useTranslation();
2020
return (
21-
<Textarea
22-
label={t('multiple_teams_input_label')}
23-
placeholder={t('multiple_teams_input_placeholder')}
24-
minRows={10}
25-
{...form.getInputProps('names')}
26-
/>
21+
<>
22+
<Textarea
23+
label={t('multiple_teams_input_label')}
24+
placeholder={t('multiple_teams_input_placeholder')}
25+
minRows={10}
26+
{...form.getInputProps('names')}
27+
/>
28+
<Text mt="1rem">{t('example_label')}</Text>
29+
<Code block>
30+
Team 1
31+
<br />
32+
Team 2,Alex
33+
<br />
34+
Team 3,Bob,Charlie
35+
</Code>
36+
</>
2737
);
2838
}

0 commit comments

Comments
 (0)