feat(tournament): implement multi-stage tournament support with intermediate and final stages

- Added backend controller for tournament stages with endpoints to get, upsert, and advance stages.
- Created database migration for new tables: tournament_stage and tournament_stage_advancement.
- Updated models for TournamentStage and TournamentStageAdvancement.
- Enhanced frontend components to manage tournament stages, including configuration for intermediate and final rounds.
- Implemented logic for saving and advancing tournament stages, including handling of pool rules and third place matches.
- Added error handling and loading states in the frontend for better user experience.
This commit is contained in:
Torsten Schulz (local)
2025-12-14 06:46:00 +01:00
parent e83bc250a8
commit 945ec0d48c
23 changed files with 1688 additions and 50 deletions

View File

@@ -10,8 +10,17 @@ config(); // sorgt dafür, dass process.env.JWT_SECRET geladen wird
export const getUserByToken = async (token) => {
try {
if (!token) {
throw new HttpError('Token fehlt', 401);
}
// 1. JWT validieren
const payload = jwt.verify(token, process.env.JWT_SECRET);
let payload;
try {
payload = jwt.verify(token, process.env.JWT_SECRET);
} catch (e) {
throw new HttpError('Unauthorized: Invalid credentials', 401);
}
// 2. Token-Eintrag prüfen (existiert und nicht abgelaufen)
const stored = await UserToken.findOne({
@@ -21,7 +30,7 @@ export const getUserByToken = async (token) => {
}
});
if (!stored) {
throw new HttpError('Token abgelaufen oder ungültig', 401);
throw new HttpError('Unauthorized: Invalid credentials', 401);
}
// 3. User laden
@@ -35,8 +44,8 @@ export const getUserByToken = async (token) => {
console.error(err);
// Falls es ein HttpError ist, einfach weiterwerfen
if (err instanceof HttpError) throw err;
// ansonsten pauschal „noaccess“
throw new HttpError('noaccess', 403);
// ansonsten: nicht maskieren, sondern als Unauthorized behandeln
throw new HttpError('Unauthorized: Invalid credentials', 401);
}
};
@@ -59,8 +68,15 @@ export const hasUserClubAccess = async (userId, clubId) => {
export const checkAccess = async (userToken, clubId) => {
try {
const user = await getUserByToken(userToken);
const hasAccess = await hasUserClubAccess(user.id, clubId);
const hasAccess = await hasUserClubAccess(user.id, clubId);
if (!hasAccess) {
// Debug-Hilfe: keine Tokens loggen, nur userId/clubId.
// (Wir loggen das immer, weil auf Servern NODE_ENV teils nicht gesetzt ist.)
console.warn('[checkAccess] noaccess:', {
userId: user?.id,
clubId,
clubIdType: typeof clubId,
});
throw new HttpError('noaccess', 403);
}
} catch (error) {