Fix standalone TTR preview route without saved match ID
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 1m0s

This commit is contained in:
Torsten Schulz (local)
2026-10-28 11:21:45 +01:00
parent 3f52fdbd70
commit 68b09a2fa0
3 changed files with 47 additions and 2 deletions

View File

@@ -247,3 +247,9 @@ export const getTtrPreviewPlayers = async (req, res) => {
return res.status(error.statusCode || 500).json({ error: error.message || 'TTR-Werte konnten nicht geladen werden' });
}
};
export const getStandaloneTtrPreviewPlayers = async (req, res) => {
// The literal /ttr-preview/standalone route has no :matchId parameter.
req.params.matchId = 'standalone';
return getTtrPreviewPlayers(req, res);
};

View File

@@ -1,5 +1,5 @@
import express from 'express';
import { uploadCSV, createManualMatch, getLeaguesForCurrentSeason, getMatchesForLeagues, getMatchesForLeague, getLeagueTable, fetchLeagueTableFromMyTischtennis, updateMatchPlayers, getPlayerMatchStats, getMatchPlayers, getTtrPreviewPlayers } from '../controllers/matchController.js';
import { uploadCSV, createManualMatch, getLeaguesForCurrentSeason, getMatchesForLeagues, getMatchesForLeague, getLeagueTable, fetchLeagueTableFromMyTischtennis, updateMatchPlayers, getPlayerMatchStats, getMatchPlayers, getTtrPreviewPlayers, getStandaloneTtrPreviewPlayers } from '../controllers/matchController.js';
import { authenticate } from '../middleware/authMiddleware.js';
import { authorize } from '../middleware/authorizationMiddleware.js';
import multer from 'multer';
@@ -17,7 +17,7 @@ router.get('/leagues/:clubId/table/:leagueId', authenticate, authorize('schedule
router.post('/leagues/:clubId/table/:leagueId/fetch', authenticate, authorize('mytischtennis', 'write'), fetchLeagueTableFromMyTischtennis);
router.get('/:clubId/players', authenticate, authorize('schedule', 'read'), getMatchPlayers);
router.patch('/:matchId/players', authenticate, authorize('schedule', 'write'), updateMatchPlayers);
router.post('/ttr-preview/standalone', authenticate, authorize('schedule', 'read'), getTtrPreviewPlayers);
router.post('/ttr-preview/standalone', authenticate, authorize('schedule', 'read'), getStandaloneTtrPreviewPlayers);
router.post('/:matchId/ttr-preview', authenticate, authorize('schedule', 'read'), getTtrPreviewPlayers);
router.get('/leagues/:clubId/stats/:leagueId', authenticate, authorize('schedule', 'read'), getPlayerMatchStats);

View File

@@ -0,0 +1,39 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import vm from 'node:vm';
const source = readFileSync(new URL('../controllers/matchController.js', import.meta.url), 'utf8')
.replace(/^import .*;\n/gm, '')
.replace(/^export const /gm, 'const ');
test('the literal standalone route resolves players without a match lookup or cache mutation', async () => {
const calls = [];
const context = vm.createContext({
console,
Op: { ne: Symbol('ne') },
Match: { findByPk() { throw new Error('Standalone must not look up a saved match'); } },
sequelize: { query() { throw new Error('Standalone must not access the match cache'); } },
Member: { findAll: async () => [] },
Club: { findAll: async () => [] },
checkAccess: async (_token, clubId) => { assert.equal(clubId, 7); },
myTischtennisService: {}, myTischtennisClient: {},
resolveTtrPreview: async input => {
calls.push(input);
return { players: [{ side: 'home', name: 'Anna Wolf', ttr: 680 }], diagnostics: [] };
},
});
vm.runInContext(source + '\nglobalThis.standaloneHandler = getStandaloneTtrPreviewPlayers;', context);
const req = { params: {}, headers: { authcode: 'test-token' }, body: {
clubId: 7, homePlayers: [{ firstname: 'Anna', lastname: 'Wolf' }],
}, user: { id: 3 } };
let payload;
const res = {
status(code) { assert.fail(`Unexpected HTTP ${code}`); },
json(body) { payload = body; },
};
await context.standaloneHandler(req, res);
assert.equal(calls.length, 1);
assert.equal(calls[0].homePlayers[0].firstname, 'Anna');
assert.equal(payload.players[0].ttr, 680);
});