diff --git a/backend/bracket/routes/models.py b/backend/bracket/routes/models.py index e5ffabbe..e47c0f1e 100644 --- a/backend/bracket/routes/models.py +++ b/backend/bracket/routes/models.py @@ -25,6 +25,10 @@ class ClubsResponse(DataResponse[list[Club]]): pass +class TournamentResponse(DataResponse[Tournament]): + pass + + class TournamentsResponse(DataResponse[list[Tournament]]): pass diff --git a/backend/bracket/routes/tournaments.py b/backend/bracket/routes/tournaments.py index c7c103db..789bcb09 100644 --- a/backend/bracket/routes/tournaments.py +++ b/backend/bracket/routes/tournaments.py @@ -10,20 +10,46 @@ from bracket.models.db.tournament import ( TournamentUpdateBody, ) from bracket.models.db.user import UserPublic -from bracket.routes.auth import user_authenticated, user_authenticated_for_tournament -from bracket.routes.models import SuccessResponse, TournamentsResponse +from bracket.routes.auth import ( + user_authenticated, + user_authenticated_for_tournament, + user_authenticated_or_public_dashboard, +) +from bracket.routes.models import SuccessResponse, TournamentResponse, TournamentsResponse from bracket.schema import tournaments -from bracket.utils.db import fetch_all_parsed -from bracket.utils.sql import get_user_access_to_club +from bracket.utils.db import fetch_all_parsed, fetch_one_parsed, fetch_one_parsed_certain +from bracket.utils.sql import get_user_access_to_club, get_which_clubs_has_user_access_to from bracket.utils.types import assert_some router = APIRouter() +@router.get("/tournaments/{tournament_id}", response_model=TournamentResponse) +async def get_tournament( + tournament_id: int, user: UserPublic | None = Depends(user_authenticated_or_public_dashboard) +) -> TournamentResponse: + tournament = await fetch_one_parsed_certain( + database, Tournament, tournaments.select().where(tournaments.c.id == tournament_id) + ) + if user is None and not tournament.dashboard_public: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="You don't have access to this tournament", + headers={"WWW-Authenticate": "Bearer"}, + ) + + return TournamentResponse(data=tournament) + + @router.get("/tournaments", response_model=TournamentsResponse) -async def get_tournaments(_: UserPublic = Depends(user_authenticated)) -> TournamentsResponse: +async def get_tournaments(user: UserPublic = Depends(user_authenticated)) -> TournamentsResponse: + user_clubs = await get_which_clubs_has_user_access_to(assert_some(user.id)) return TournamentsResponse( - data=await fetch_all_parsed(database, Tournament, tournaments.select()) + data=await fetch_all_parsed( + database, + Tournament, + tournaments.select().where(tournaments.c.club_id.in_(tuple(user_clubs))), + ) ) diff --git a/backend/bracket/utils/sql.py b/backend/bracket/utils/sql.py index 53e9e2ca..f52e422e 100644 --- a/backend/bracket/utils/sql.py +++ b/backend/bracket/utils/sql.py @@ -87,11 +87,15 @@ async def get_user_access_to_tournament(tournament_id: int, user_id: int) -> boo return tournament_id in {tournament.id for tournament in result} # type: ignore[attr-defined] -async def get_user_access_to_club(club_id: int, user_id: int) -> bool: +async def get_which_clubs_has_user_access_to(user_id: int) -> set[int]: query = f''' SELECT club_id FROM users_x_clubs WHERE user_id = :user_id ''' result = await database.fetch_all(query=query, values={'user_id': user_id}) - return club_id in {club.club_id for club in result} # type: ignore[attr-defined] + return {club.club_id for club in result} # type: ignore[attr-defined] + + +async def get_user_access_to_club(club_id: int, user_id: int) -> bool: + return club_id in await get_which_clubs_has_user_access_to(user_id) diff --git a/frontend/src/pages/tournaments/[id]/dashboard.tsx b/frontend/src/pages/tournaments/[id]/dashboard.tsx index 44553d55..f9218875 100644 --- a/frontend/src/pages/tournaments/[id]/dashboard.tsx +++ b/frontend/src/pages/tournaments/[id]/dashboard.tsx @@ -6,7 +6,7 @@ import NotFoundTitle from '../../404'; import Brackets from '../../../components/brackets/brackets'; import { getTournamentIdFromRouter } from '../../../components/utils/util'; import { Tournament } from '../../../interfaces/tournament'; -import { getBaseApiUrl, getRounds, getTournaments } from '../../../services/adapter'; +import { getBaseApiUrl, getRounds, getTournament } from '../../../services/adapter'; function TournamentLogo({ tournamentDataFull }: { tournamentDataFull: Tournament }) { return tournamentDataFull.logo_path ? ( @@ -17,13 +17,10 @@ function TournamentLogo({ tournamentDataFull }: { tournamentDataFull: Tournament export default function Dashboard() { const { tournamentData } = getTournamentIdFromRouter(); const swrRoundsResponse: SWRResponse = getRounds(tournamentData.id, true); - const swrTournamentsResponse = getTournaments(); + const swrTournamentsResponse = getTournament(tournamentData.id); - const tournaments: Tournament[] = - swrTournamentsResponse.data != null ? swrTournamentsResponse.data.data : []; - const tournamentDataFull = tournaments.filter( - (tournament) => tournament.id === tournamentData.id - )[0]; + const tournamentDataFull: Tournament = + swrTournamentsResponse.data != null ? swrTournamentsResponse.data.data : null; if (tournamentDataFull == null) { return ; diff --git a/frontend/src/services/adapter.tsx b/frontend/src/services/adapter.tsx index 4489c82b..3184aad8 100644 --- a/frontend/src/services/adapter.tsx +++ b/frontend/src/services/adapter.tsx @@ -52,6 +52,10 @@ export function getClubs(): SWRResponse { return useSWR('clubs', fetcher); } +export function getTournament(tournament_id: number): SWRResponse { + return useSWR(`tournaments/${tournament_id}`, fetcher); +} + export function getTournaments(): SWRResponse { return useSWR('tournaments', fetcher); } @@ -65,7 +69,9 @@ export function getTeams(tournament_id: number): SWRResponse { } export function getRounds(tournament_id: number, no_draft_rounds: boolean = false): SWRResponse { - return useSWR(`tournaments/${tournament_id}/rounds?no_draft_rounds=${no_draft_rounds}`, fetcher); + return useSWR(`tournaments/${tournament_id}/rounds?no_draft_rounds=${no_draft_rounds}`, fetcher, { + refreshInterval: 3000, + }); } export function getUpcomingMatches(tournament_id: number): SWRResponse {