Enhance myTischtennis URL controller with improved error handling and logging

Updated MyTischtennisUrlController to include detailed error messages for missing user IDs and team configurations. Added logging for session details and automatic login attempts, improving debugging capabilities. Enhanced request logging for API calls to myTischtennis, ensuring all requests are logged, even in case of errors. Updated requestLoggingMiddleware to only log myTischtennis-related requests, streamlining log management. Improved validation checks in autoFetchMatchResultsService for team and league data integrity.
This commit is contained in:
Torsten Schulz (local)
2025-10-29 18:07:43 +01:00
parent c2b8656783
commit 89329607dc
5 changed files with 295 additions and 50 deletions

View File

@@ -1,6 +1,7 @@
import myTischtennisUrlParserService from '../services/myTischtennisUrlParserService.js';
import myTischtennisService from '../services/myTischtennisService.js';
import autoFetchMatchResultsService from '../services/autoFetchMatchResultsService.js';
import apiLogService from '../services/apiLogService.js';
import ClubTeam from '../models/ClubTeam.js';
import League from '../models/League.js';
import Season from '../models/Season.js';
@@ -228,6 +229,10 @@ class MyTischtennisUrlController {
throw new HttpError(400, 'clubTeamId is required');
}
if (!userIdOrEmail) {
throw new HttpError(401, 'User-ID fehlt. Bitte melden Sie sich an.');
}
// Get actual user ID (userid header might be email address)
let userId = userIdOrEmail;
if (isNaN(userIdOrEmail)) {
@@ -246,17 +251,63 @@ class MyTischtennisUrlController {
try {
session = await myTischtennisService.getSession(userId);
console.log('Session found:', !!session);
if (session) {
console.log('Session details:', {
hasCookie: !!session.cookie,
hasAccessToken: !!session.accessToken,
expiresAt: session.expiresAt ? new Date(session.expiresAt * 1000).toISOString() : null
});
}
} catch (sessionError) {
console.log('Session invalid, attempting login...', sessionError.message);
console.error('Session error details:', {
message: sessionError.message,
stack: sessionError.stack,
name: sessionError.name
});
// Versuche automatischen Login mit gespeicherten Credentials
try {
await myTischtennisService.verifyLogin(userId);
console.log('Attempting automatic login for userId:', userId);
// Check if account exists and has password
const accountCheck = await myTischtennisService.getAccount(userId);
if (!accountCheck) {
throw new Error('MyTischtennis-Account nicht gefunden');
}
console.log('Account found:', {
email: accountCheck.email,
hasPassword: !!accountCheck.encryptedPassword,
hasAccessToken: !!accountCheck.accessToken,
hasCookie: !!accountCheck.cookie
});
if (!accountCheck.encryptedPassword) {
throw new Error('Kein Passwort gespeichert. Bitte melden Sie sich in den MyTischtennis-Einstellungen an und speichern Sie Ihr Passwort.');
}
console.log('Calling verifyLogin...');
const verifyResult = await myTischtennisService.verifyLogin(userId);
console.log('verifyLogin result:', verifyResult);
session = await myTischtennisService.getSession(userId);
console.log('Automatic login successful');
console.log('Automatic login successful, session:', {
hasCookie: !!session?.cookie,
hasAccessToken: !!session?.accessToken
});
} catch (loginError) {
console.error('Automatic login failed:', loginError.message);
throw new HttpError(401, 'MyTischtennis-Session abgelaufen und automatischer Login fehlgeschlagen. Bitte melden Sie sich in den MyTischtennis-Einstellungen an.');
console.error('Automatic login failed - DETAILED ERROR:', {
message: loginError.message,
stack: loginError.stack,
name: loginError.name,
userId: userId,
response: loginError.response?.data,
status: loginError.response?.status
});
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.`);
}
}
@@ -291,7 +342,7 @@ class MyTischtennisUrlController {
});
if (!team) {
throw new HttpError(404, 'Team not found');
throw new HttpError(404, `Team mit ID ${clubTeamId} nicht gefunden`);
}
console.log('Team data:', {
@@ -309,11 +360,74 @@ class MyTischtennisUrlController {
} : null
});
if (!team.myTischtennisTeamId || !team.league || !team.league.myTischtennisGroupId) {
throw new HttpError(400, 'Team is not configured for myTischtennis');
// 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.`);
}
// Stelle sicher, dass die myTischtennisTeamId auch wirklich verwendet wird
console.log(`Verwende myTischtennisTeamId: ${team.myTischtennisTeamId} (nicht die interne clubTeamId: ${team.id})`);
if (!team.league) {
throw new HttpError(400, 'Team ist keiner Liga zugeordnet. Bitte ordnen Sie das Team einer Liga zu.');
}
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.');
}
// 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.');
}
// Build the URL that will be used - do this early so we can log it even if errors occur
const seasonFull = team.league.season.season;
const seasonParts = seasonFull.split('/');
const seasonShort = seasonParts.length === 2
? `${seasonParts[0].slice(-2)}/${seasonParts[1].slice(-2)}`
: seasonFull;
const seasonStr = seasonShort.replace('/', '--');
const teamnameEncoded = encodeURIComponent(team.name.replace(/\s/g, '_'));
const myTischtennisUrl = `https://www.mytischtennis.de/click-tt/${team.league.association}/${seasonStr}/ligen/${team.league.groupname}/gruppe/${team.league.myTischtennisGroupId}/mannschaft/${team.myTischtennisTeamId}/${teamnameEncoded}/spielerbilanzen/gesamt`;
// Log the request to myTischtennis BEFORE making the call
// This ensures we always see what WILL BE sent, even if the call fails
const requestStartTime = Date.now();
console.log('=== ABOUT TO FETCH FROM MYTISCHTENNIS ===');
console.log('URL:', myTischtennisUrl);
console.log('myTischtennisTeamId:', team.myTischtennisTeamId);
console.log('clubTeamId:', team.id);
try {
await apiLogService.logRequest({
userId: account.userId,
method: 'GET',
path: myTischtennisUrl.replace('https://www.mytischtennis.de', ''),
statusCode: null,
requestBody: JSON.stringify({
url: myTischtennisUrl,
myTischtennisTeamId: team.myTischtennisTeamId,
clubTeamId: team.id,
teamName: team.name,
leagueName: team.league.name,
association: team.league.association,
groupId: team.league.myTischtennisGroupId,
groupname: team.league.groupname,
season: seasonFull
}),
responseBody: null,
executionTime: null,
errorMessage: 'Request wird ausgeführt...',
logType: 'api_request',
schedulerJobType: 'mytischtennis_fetch'
});
} catch (logError) {
console.error('Error logging request (non-critical):', logError);
}
// Fetch data for this specific team
// Note: fetchTeamResults will also log and update with actual response
const result = await autoFetchMatchResultsService.fetchTeamResults(
{
userId: account.userId,
@@ -326,32 +440,63 @@ class MyTischtennisUrlController {
team
);
// Also fetch and update league table data
let tableUpdateResult = null;
// Also fetch and update league table data
let tableUpdateResult = null;
try {
await autoFetchMatchResultsService.fetchAndUpdateLeagueTable(account.userId, team.league.id);
tableUpdateResult = 'League table updated successfully';
console.log('✓ League table updated for league:', team.league.id);
} catch (error) {
console.error('Error fetching league table data:', error);
tableUpdateResult = 'League table update failed: ' + error.message;
// Don't fail the entire request if table update fails
}
res.json({
success: true,
message: `${result.fetchedCount} Datensätze abgerufen und verarbeitet`,
data: {
fetchedCount: result.fetchedCount,
teamName: team.name,
tableUpdate: tableUpdateResult
tableUpdateResult = 'League table updated successfully';
console.log('✓ League table updated for league:', team.league.id);
} catch (error) {
console.error('Error fetching league table data:', error);
tableUpdateResult = 'League table update failed: ' + error.message;
// Don't fail the entire request if table update fails
}
});
} catch (error) {
console.error('Error in fetchTeamData:', error);
console.error('Error stack:', error.stack);
next(error);
}
res.json({
success: true,
message: `${result.fetchedCount} Datensätze abgerufen und verarbeitet`,
data: {
fetchedCount: result.fetchedCount,
teamName: team.name,
tableUpdate: tableUpdateResult
}
});
} catch (error) {
console.error('Error in fetchTeamData:', error);
console.error('Error stack:', error.stack);
// Update log with error information if we got far enough to build the URL
if (typeof myTischtennisUrl !== 'undefined' && account && team) {
const requestExecutionTime = Date.now() - requestStartTime;
try {
await apiLogService.logRequest({
userId: account.userId,
method: 'GET',
path: myTischtennisUrl.replace('https://www.mytischtennis.de', ''),
statusCode: 0,
requestBody: JSON.stringify({
url: myTischtennisUrl,
myTischtennisTeamId: team.myTischtennisTeamId,
clubTeamId: team.id,
teamName: team.name,
leagueName: team.league?.name,
association: team.league?.association,
groupname: team.league?.groupname,
groupId: team.league?.myTischtennisGroupId
}),
responseBody: null,
executionTime: requestExecutionTime,
errorMessage: error.message || String(error),
logType: 'api_request',
schedulerJobType: 'mytischtennis_fetch'
});
} catch (logError) {
console.error('Error logging failed request:', logError);
}
}
next(error);
}
}
/**