Refactor error handling in MyTischtennisUrlController and improve memberService indexing

Refactored error handling in MyTischtennisUrlController to standardize error messages and ensure consistent status codes. Enhanced memberService by implementing a more efficient indexing system for member data retrieval, improving performance and accuracy in TTR and QTTR updates. Updated TeamManagementView to handle timeout errors and provide detailed user feedback, enhancing overall user experience.
This commit is contained in:
Torsten Schulz (local)
2025-11-03 10:45:04 +01:00
parent acf2cf00bd
commit 23708b99b5
3 changed files with 68 additions and 32 deletions

View File

@@ -20,12 +20,12 @@ class MyTischtennisUrlController {
const { url } = req.body;
if (!url) {
throw new HttpError(400, 'URL is required');
throw new HttpError('URL is required', 400);
}
// Validate URL
if (!myTischtennisUrlParserService.isValidTeamUrl(url)) {
throw new HttpError(400, 'Invalid myTischtennis URL format');
throw new HttpError('Invalid myTischtennis URL format', 400);
}
// Parse URL
@@ -229,11 +229,11 @@ class MyTischtennisUrlController {
const userIdOrEmail = req.headers.userid;
if (!clubTeamId) {
throw new HttpError(400, 'clubTeamId is required');
throw new HttpError('clubTeamId is required', 400);
}
if (!userIdOrEmail) {
throw new HttpError(401, 'User-ID fehlt. Bitte melden Sie sich an.');
throw new HttpError('User-ID fehlt. Bitte melden Sie sich an.', 401);
}
// Get actual user ID (userid header might be email address)
@@ -269,7 +269,7 @@ class MyTischtennisUrlController {
session = await myTischtennisService.getSession(userId);
} catch (loginError) {
const errorMessage = loginError.message || 'Automatischer Login fehlgeschlagen';
throw new HttpError(401, `MyTischtennis-Session abgelaufen und automatischer Login fehlgeschlagen: ${errorMessage}. Bitte melden Sie sich in den MyTischtennis-Einstellungen an.`);
throw new HttpError(`MyTischtennis-Session abgelaufen und automatischer Login fehlgeschlagen: ${errorMessage}. Bitte melden Sie sich in den MyTischtennis-Einstellungen an.`, 401);
}
}
@@ -277,7 +277,7 @@ class MyTischtennisUrlController {
account = await myTischtennisService.getAccount(userId);
if (!account) {
throw new HttpError(404, 'MyTischtennis-Account nicht verknüpft. Bitte verknüpfen Sie Ihren Account in den MyTischtennis-Einstellungen.');
throw new HttpError('MyTischtennis-Account nicht verknüpft. Bitte verknüpfen Sie Ihren Account in den MyTischtennis-Einstellungen.', 404);
}
@@ -298,25 +298,25 @@ class MyTischtennisUrlController {
});
if (!team) {
throw new HttpError(404, `Team mit ID ${clubTeamId} nicht gefunden`);
throw new HttpError(`Team mit ID ${clubTeamId} nicht gefunden`, 404);
}
// Verbesserte Validierung mit detaillierten Fehlermeldungen
if (!team.myTischtennisTeamId) {
throw new HttpError(400, `Team "${team.name}" (interne ID: ${team.id}) ist nicht für myTischtennis konfiguriert: myTischtennisTeamId fehlt. Bitte konfigurieren Sie das Team zuerst über die MyTischtennis-URL.`);
throw new HttpError(`Team "${team.name}" (interne ID: ${team.id}) ist nicht für myTischtennis konfiguriert: myTischtennisTeamId fehlt. Bitte konfigurieren Sie das Team zuerst über die MyTischtennis-URL.`, 400);
}
if (!team.league) {
throw new HttpError(400, 'Team ist keiner Liga zugeordnet. Bitte ordnen Sie das Team einer Liga zu.');
throw new HttpError('Team ist keiner Liga zugeordnet. Bitte ordnen Sie das Team einer Liga zu.', 400);
}
if (!team.league.myTischtennisGroupId) {
throw new HttpError(400, 'Liga ist nicht für myTischtennis konfiguriert: myTischtennisGroupId fehlt. Bitte konfigurieren Sie die Liga zuerst über die MyTischtennis-URL.');
throw new HttpError('Liga ist nicht für myTischtennis konfiguriert: myTischtennisGroupId fehlt. Bitte konfigurieren Sie die Liga zuerst über die MyTischtennis-URL.', 400);
}
// Validate season before proceeding
if (!team.league.season || !team.league.season.season) {
throw new HttpError(400, 'Liga ist keiner Saison zugeordnet. Bitte ordnen Sie die Liga einer Saison zu.');
throw new HttpError('Liga ist keiner Saison zugeordnet. Bitte ordnen Sie die Liga einer Saison zu.', 400);
}
// Build the URL that will be used - do this early so we can log it even if errors occur
@@ -424,7 +424,10 @@ class MyTischtennisUrlController {
}
}
const status = error.statusCode || error.status || 500;
// Normalize HTTP status code (guard against strings)
const rawCode = error && (error.statusCode != null ? error.statusCode : error.status);
const parsed = Number(rawCode);
const status = Number.isInteger(parsed) && parsed >= 100 && parsed <= 599 ? parsed : 500;
const debug = {
message: error.message || String(error),
name: error.name,
@@ -434,7 +437,14 @@ class MyTischtennisUrlController {
url: typeof myTischtennisUrl !== 'undefined' ? myTischtennisUrl : null
};
try {
res.status(status).json({ success: false, error: debug.message, debug });
if (!res.headersSent) {
// Spezieller Fall: myTischtennis-Reauth nötig → nicht 401 an FE senden, um App-Logout zu vermeiden
const isMyTischtennisAuthIssue = status === 401 && /MyTischtennis-Session abgelaufen|Automatischer Login fehlgeschlagen|Passwort gespeichert/i.test(debug.message || '');
if (isMyTischtennisAuthIssue) {
return res.status(200).json({ success: false, error: debug.message, debug, needsMyTischtennisReauth: true });
}
res.status(status).json({ success: false, error: debug.message, debug });
}
} catch (writeErr) {
// Fallback, falls Headers schon gesendet wurden
// eslint-disable-next-line no-console
@@ -510,7 +520,7 @@ class MyTischtennisUrlController {
const parsedData = myTischtennisUrlParserService.parseUrl(url);
if (parsedData.urlType !== 'table') {
throw new HttpError(400, 'URL must be a table URL (not a team URL)');
throw new HttpError('URL must be a table URL (not a team URL)', 400);
}
// Find or create season