Enhance MyTischtennisUrlController with ratings update and improve apiLogService truncation limits
Added functionality in MyTischtennisUrlController to update (Q)TTR ratings for clubs based on user authentication. Enhanced error handling for ratings updates to provide clearer feedback. Updated apiLogService to increase truncation limits for request and response bodies, accommodating larger API JSON payloads, ensuring better logging accuracy.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import myTischtennisUrlParserService from '../services/myTischtennisUrlParserService.js';
|
||||
import myTischtennisService from '../services/myTischtennisService.js';
|
||||
import MemberService from '../services/memberService.js';
|
||||
import autoFetchMatchResultsService from '../services/autoFetchMatchResultsService.js';
|
||||
import apiLogService from '../services/apiLogService.js';
|
||||
import ClubTeam from '../models/ClubTeam.js';
|
||||
@@ -383,13 +384,24 @@ class MyTischtennisUrlController {
|
||||
// Don't fail the entire request if table update fails
|
||||
}
|
||||
|
||||
// Additionally update (Q)TTR ratings for the club
|
||||
let ratingsUpdate = null;
|
||||
try {
|
||||
// Use already resolved userId instead of authcode to avoid header dependency
|
||||
const ratingsResult = await MemberService.updateRatingsFromMyTischtennisByUserId(userId, team.clubId);
|
||||
ratingsUpdate = ratingsResult?.response?.message || `Ratings update status: ${ratingsResult?.status}`;
|
||||
} catch (ratingsErr) {
|
||||
ratingsUpdate = 'Ratings update failed: ' + (ratingsErr.message || String(ratingsErr));
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: `${result.fetchedCount} Datensätze abgerufen und verarbeitet`,
|
||||
data: {
|
||||
fetchedCount: result.fetchedCount,
|
||||
teamName: team.name,
|
||||
tableUpdate: tableUpdateResult
|
||||
tableUpdate: tableUpdateResult,
|
||||
ratingsUpdate
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
|
||||
@@ -22,8 +22,8 @@ class ApiLogService {
|
||||
schedulerJobType = null
|
||||
} = options;
|
||||
|
||||
// Truncate long fields
|
||||
const truncate = (str, maxLen = 10000) => {
|
||||
// Truncate long fields (raise limits to fit typical API JSON bodies)
|
||||
const truncate = (str, maxLen = 64000) => {
|
||||
if (!str) return null;
|
||||
const strVal = typeof str === 'string' ? str : JSON.stringify(str);
|
||||
return strVal.length > maxLen ? strVal.substring(0, maxLen) + '... (truncated)' : strVal;
|
||||
@@ -34,8 +34,8 @@ class ApiLogService {
|
||||
method,
|
||||
path,
|
||||
statusCode,
|
||||
requestBody: truncate(requestBody),
|
||||
responseBody: truncate(responseBody),
|
||||
requestBody: truncate(requestBody, 64000),
|
||||
responseBody: truncate(responseBody, 64000),
|
||||
executionTime,
|
||||
errorMessage: truncate(errorMessage, 5000),
|
||||
ipAddress,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import UserClub from "../models/UserClub.js";
|
||||
import { checkAccess } from "../utils/userUtils.js";
|
||||
import { getUserByToken } from "../utils/userUtils.js";
|
||||
import { checkAccess, getUserByToken, hasUserClubAccess } from "../utils/userUtils.js";
|
||||
import Member from "../models/Member.js";
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
@@ -141,26 +140,21 @@ class MemberService {
|
||||
}
|
||||
}
|
||||
|
||||
async updateRatingsFromMyTischtennis(userToken, clubId) {
|
||||
await checkAccess(userToken, clubId);
|
||||
|
||||
const user = await getUserByToken(userToken);
|
||||
|
||||
async _updateRatingsInternal(userId, clubId) {
|
||||
const myTischtennisService = (await import('./myTischtennisService.js')).default;
|
||||
const myTischtennisClient = (await import('../clients/myTischtennisClient.js')).default;
|
||||
|
||||
try {
|
||||
// 1. myTischtennis-Session abrufen oder Login durchführen
|
||||
let session;
|
||||
try {
|
||||
session = await myTischtennisService.getSession(user.id);
|
||||
session = await myTischtennisService.getSession(userId);
|
||||
} catch (sessionError) {
|
||||
console.log('[updateRatingsFromMyTischtennis] - Session invalid, attempting login...', sessionError.message);
|
||||
|
||||
// Versuche automatischen Login mit gespeicherten Credentials
|
||||
try {
|
||||
await myTischtennisService.verifyLogin(user.id);
|
||||
const freshSession = await myTischtennisService.getSession(user.id);
|
||||
await myTischtennisService.verifyLogin(userId);
|
||||
const freshSession = await myTischtennisService.getSession(userId);
|
||||
session = {
|
||||
cookie: freshSession.cookie,
|
||||
accessToken: freshSession.accessToken,
|
||||
@@ -183,7 +177,7 @@ class MemberService {
|
||||
}
|
||||
}
|
||||
|
||||
const account = await myTischtennisService.getAccount(user.id);
|
||||
const account = await myTischtennisService.getAccount(userId);
|
||||
|
||||
if (!account) {
|
||||
console.error('[updateRatingsFromMyTischtennis] - No account found!');
|
||||
@@ -193,7 +187,7 @@ class MemberService {
|
||||
message: 'Kein myTischtennis-Account gefunden.',
|
||||
updated: 0,
|
||||
errors: [],
|
||||
debug: { userId: user.id }
|
||||
debug: { userId }
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -219,22 +213,80 @@ class MemberService {
|
||||
};
|
||||
}
|
||||
|
||||
// 2. Ranglisten vom Verein abrufen
|
||||
// 2. Ranglisten vom Verein abrufen (Logging hinzufügen)
|
||||
// TTR (aktuell)
|
||||
try {
|
||||
await (await import('./apiLogService.js')).default.logRequest({
|
||||
userId,
|
||||
method: 'GET',
|
||||
path: `/rankings/andro-rangliste?club=${account.clubId}&fed=${account.fedNickname}¤t=yes`,
|
||||
statusCode: null,
|
||||
requestBody: null,
|
||||
responseBody: null,
|
||||
executionTime: null,
|
||||
errorMessage: 'TTR-Rangliste wird abgerufen...',
|
||||
logType: 'api_request',
|
||||
schedulerJobType: 'mytischtennis_rankings'
|
||||
});
|
||||
} catch {}
|
||||
const ttrStart = Date.now();
|
||||
const rankingsCurrent = await myTischtennisClient.getClubRankings(
|
||||
session.cookie,
|
||||
account.clubId,
|
||||
account.fedNickname,
|
||||
'yes'
|
||||
);
|
||||
try {
|
||||
await (await import('./apiLogService.js')).default.logRequest({
|
||||
userId,
|
||||
method: 'GET',
|
||||
path: `/rankings/andro-rangliste?club=${account.clubId}&fed=${account.fedNickname}¤t=yes`,
|
||||
statusCode: rankingsCurrent.success ? 200 : 500,
|
||||
requestBody: null,
|
||||
responseBody: JSON.stringify(rankingsCurrent),
|
||||
executionTime: Date.now() - ttrStart,
|
||||
errorMessage: rankingsCurrent.success ? null : 'TTR-Rangliste Fehler',
|
||||
logType: 'api_request',
|
||||
schedulerJobType: 'mytischtennis_rankings'
|
||||
});
|
||||
} catch {}
|
||||
|
||||
// QTTR (Quartalswert)
|
||||
try {
|
||||
await (await import('./apiLogService.js')).default.logRequest({
|
||||
userId,
|
||||
method: 'GET',
|
||||
path: `/rankings/andro-rangliste?club=${account.clubId}&fed=${account.fedNickname}¤t=no`,
|
||||
statusCode: null,
|
||||
requestBody: null,
|
||||
responseBody: null,
|
||||
executionTime: null,
|
||||
errorMessage: 'QTTR-Rangliste wird abgerufen...',
|
||||
logType: 'api_request',
|
||||
schedulerJobType: 'mytischtennis_rankings'
|
||||
});
|
||||
} catch {}
|
||||
const qttrStart = Date.now();
|
||||
const rankingsQuarter = await myTischtennisClient.getClubRankings(
|
||||
session.cookie,
|
||||
account.clubId,
|
||||
account.fedNickname,
|
||||
'no'
|
||||
);
|
||||
try {
|
||||
await (await import('./apiLogService.js')).default.logRequest({
|
||||
userId,
|
||||
method: 'GET',
|
||||
path: `/rankings/andro-rangliste?club=${account.clubId}&fed=${account.fedNickname}¤t=no`,
|
||||
statusCode: rankingsQuarter.success ? 200 : 500,
|
||||
requestBody: null,
|
||||
responseBody: JSON.stringify(rankingsQuarter),
|
||||
executionTime: Date.now() - qttrStart,
|
||||
errorMessage: rankingsQuarter.success ? null : 'QTTR-Rangliste Fehler',
|
||||
logType: 'api_request',
|
||||
schedulerJobType: 'mytischtennis_rankings'
|
||||
});
|
||||
} catch {}
|
||||
|
||||
if (!rankingsCurrent.success) {
|
||||
return {
|
||||
@@ -367,6 +419,28 @@ class MemberService {
|
||||
}
|
||||
}
|
||||
|
||||
async updateRatingsFromMyTischtennis(userToken, clubId) {
|
||||
await checkAccess(userToken, clubId);
|
||||
const user = await getUserByToken(userToken);
|
||||
return this._updateRatingsInternal(user.id, clubId);
|
||||
}
|
||||
|
||||
async updateRatingsFromMyTischtennisByUserId(userId, clubId) {
|
||||
// Zugriff prüfen: User muss Zugriff auf den Club haben
|
||||
const allowed = await hasUserClubAccess(userId, clubId);
|
||||
if (!allowed) {
|
||||
return {
|
||||
status: 403,
|
||||
response: {
|
||||
message: 'noaccess',
|
||||
updated: 0,
|
||||
errors: ['noaccess']
|
||||
}
|
||||
};
|
||||
}
|
||||
return this._updateRatingsInternal(userId, clubId);
|
||||
}
|
||||
|
||||
async rotateMemberImage(userToken, clubId, memberId, direction) {
|
||||
try {
|
||||
await checkAccess(userToken, clubId);
|
||||
|
||||
Reference in New Issue
Block a user