From 94aab93f7d3cbec7c072f14684d1aed9ec1adc04 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Fri, 7 Nov 2025 13:22:22 +0100 Subject: [PATCH] Add global error handling middleware for API routes and enhance rating update logic Implemented a global error handling middleware in the server to standardize error responses for API routes. Additionally, updated the AutoUpdateRatingsService to retrieve the approved user club before updating ratings, ensuring proper access control. Modified the error handling in MyTischtennisAccount.vue to provide more informative login failure messages. --- backend/server.js | 25 ++++++++++++++++++++ backend/services/autoUpdateRatingsService.js | 24 +++++++++++++++++-- frontend/src/views/MyTischtennisAccount.vue | 2 +- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/backend/server.js b/backend/server.js index 9916c17..99b12bc 100644 --- a/backend/server.js +++ b/backend/server.js @@ -71,6 +71,31 @@ process.on('unhandledRejection', (reason, promise) => { console.error('[unhandledRejection]', reason); }); +// Globale Fehlerbehandlung für API-Routen +app.use((err, req, res, next) => { + if (res.headersSent) { + return next(err); + } + + const status = err?.statusCode || err?.status || 500; + const message = err?.message || 'Interner Serverfehler'; + + const response = { + success: false, + message, + error: message + }; + + if (process.env.NODE_ENV === 'dev' || process.env.NODE_ENV === 'development') { + response.debug = { + stack: err?.stack || null + }; + } + + console.error('[ExpressError]', err); + res.status(status).json(response); +}); + app.use('/api/auth', authRoutes); app.use('/api/clubs', clubRoutes); app.use('/api/clubmembers', memberRoutes); diff --git a/backend/services/autoUpdateRatingsService.js b/backend/services/autoUpdateRatingsService.js index 2f58884..80fbb6f 100644 --- a/backend/services/autoUpdateRatingsService.js +++ b/backend/services/autoUpdateRatingsService.js @@ -4,6 +4,7 @@ import memberService from './memberService.js'; import myTischtennisClient from '../clients/myTischtennisClient.js'; import MyTischtennis from '../models/MyTischtennis.js'; import { devLog } from '../utils/logger.js'; +import UserClub from '../models/UserClub.js'; class AutoUpdateRatingsService { /** @@ -134,8 +135,27 @@ class AutoUpdateRatingsService { devLog(`Updating ratings for ${account.email}`); try { - // Use the memberService to update ratings from MyTischtennis - const result = await memberService.updateRatingsFromMyTischtennis(account.userId); + // Ermittle einen freigeschalteten Vereinszugang für den Benutzer + const userClub = await UserClub.findOne({ + where: { + userId: account.userId, + approved: true + }, + order: [['createdAt', 'ASC']], + attributes: ['clubId'] + }); + + if (!userClub) { + throw new Error('Kein freigeschalteter Vereinszugang gefunden'); + } + + const clubId = userClub.clubId; + + // Verwende den Service-Aufruf, der mit userId/clubId arbeitet + const result = await memberService.updateRatingsFromMyTischtennisByUserId( + account.userId, + clubId + ); return { success: true, diff --git a/frontend/src/views/MyTischtennisAccount.vue b/frontend/src/views/MyTischtennisAccount.vue index bcce970..5780ad3 100644 --- a/frontend/src/views/MyTischtennisAccount.vue +++ b/frontend/src/views/MyTischtennisAccount.vue @@ -287,7 +287,7 @@ export default { }); await this.loadAccount(); // Aktualisiere Account-Daten inkl. clubId, fedNickname } catch (error) { - const message = error.response?.data?.message || 'Login fehlgeschlagen'; + const message = error.response?.data?.message || error.response?.data?.error || error.message || 'Login fehlgeschlagen'; if (error.response?.status === 400 && message.includes('Kein Passwort gespeichert')) { // Passwort-Dialog öffnen