feat(diary): enhance predefined activities management and socket event handling

- Added new API endpoints for managing predefined activities, including retrieval, creation, updating, merging, and deduplication.
- Updated socket event handling to improve the mapping of socket events to domain events, ensuring better integration with the diary service.
- Enhanced repository mappers to support detailed mapping of predefined activities and training statistics, including images and member participation data.
- Introduced new UI strings for managing predefined activities, improving user experience in the diary section.
This commit is contained in:
Torsten Schulz (local)
2026-03-06 10:02:50 +01:00
parent 436973e47e
commit ee2b12f6d0
2965 changed files with 35418 additions and 59 deletions

View File

@@ -1,7 +1,6 @@
import myTischtennisService from './myTischtennisService.js';
import myTischtennisFetchLogService from './myTischtennisFetchLogService.js';
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';
@@ -18,9 +17,9 @@ class AutoUpdateRatingsService {
const accounts = await MyTischtennis.findAll({
where: {
autoUpdateRatings: true,
savePassword: true // Must have saved password
},
attributes: ['id', 'userId', 'email', 'savePassword', 'encryptedPassword', 'accessToken', 'expiresAt', 'cookie']
savePassword: true
}
// No attributes restriction — all fields needed for session handling and re-login
});
devLog(`Found ${accounts.length} accounts with auto-updates enabled`);
@@ -60,30 +59,18 @@ class AutoUpdateRatingsService {
// Check if session is still valid
if (!account.accessToken || !account.expiresAt || account.expiresAt < Date.now() / 1000) {
devLog(`Session expired for ${account.email}, attempting re-login`);
// Try to re-login with stored password
const password = account.getPassword();
if (!password) {
throw new Error('No stored password available for re-login');
devLog(`Session expired for ${account.email}, attempting re-login via verifyLogin (incl. Playwright fallback)`);
// verifyLogin handles CAPTCHA via Playwright and persists the session to DB.
await myTischtennisService.verifyLogin(account.userId);
// Reload the account to get the fresh session data written by verifyLogin.
const refreshed = await MyTischtennis.findOne({ where: { userId: account.userId } });
if (!refreshed?.cookie) {
throw new Error('Re-login via verifyLogin did not produce a valid session');
}
const loginResult = await myTischtennisClient.login(account.email, password);
if (!loginResult.success) {
if (loginResult.requiresCaptcha) {
throw new Error(`Re-login failed: CAPTCHA erforderlich. Bitte loggen Sie sich einmal direkt auf mytischtennis.de ein, um das CAPTCHA zu lösen.`);
}
throw new Error(`Re-login failed: ${loginResult.error}`);
}
// Update session data
account.accessToken = loginResult.accessToken;
account.refreshToken = loginResult.refreshToken;
account.expiresAt = loginResult.expiresAt;
account.cookie = loginResult.cookie;
account.savePassword = true; // Ensure flag persists when saving limited attributes
await account.save();
account.accessToken = refreshed.accessToken;
account.refreshToken = refreshed.refreshToken;
account.expiresAt = refreshed.expiresAt;
account.cookie = refreshed.cookie;
devLog(`Successfully re-logged in for ${account.email}`);
}