feat(diary): improve predefined activities UI and enhance socket event integration

- Updated UI components for managing predefined activities to enhance user experience and accessibility.
- Improved socket event integration for real-time updates related to predefined activities, ensuring seamless interaction with the diary service.
- Refactored related mappers to support new UI changes and maintain data consistency across the application.
This commit is contained in:
Torsten Schulz (local)
2026-03-10 21:24:45 +01:00
parent 78f1196f0a
commit 055dbf115c
5 changed files with 596 additions and 0 deletions

View File

@@ -0,0 +1,234 @@
/**
* API-Routes für HTTV/click-TT HTTP-Seiten mit Logging.
* Ermöglicht das Testen verschiedener URLs und das Auslesen der Logs.
*/
import express from 'express';
import clickTtHttpPageService from '../services/clickTtHttpPageService.js';
import HttpPageFetchLog from '../models/HttpPageFetchLog.js';
import { authenticate } from '../middleware/authenticate.js';
import { Op } from 'sequelize';
const router = express.Router();
/**
* GET /api/clicktt/league-page
* Ruft die Ligenübersicht ab (leaguePage)
* Query: association, championship
*/
router.get('/league-page', authenticate, async (req, res, next) => {
try {
const association = req.query.association || 'HeTTV';
const championship = req.query.championship || 'HTTV 25/26';
const userId = req.user?.id ?? null;
const result = await clickTtHttpPageService.fetchLeaguePage({
association,
championship,
userId,
});
res.json({
success: result.success,
status: result.status,
contentType: result.contentType,
executionTimeMs: result.executionTimeMs,
bodyLength: result.body?.length ?? 0,
body: result.body,
});
} catch (error) {
next(error);
}
});
/**
* GET /api/clicktt/club-info
* Ruft die Vereinsinfo ab (clubInfoDisplay)
* Query: association, clubId
*/
router.get('/club-info', authenticate, async (req, res, next) => {
try {
const association = req.query.association || 'HeTTV';
const clubId = req.query.clubId;
const userId = req.user?.id ?? null;
if (!clubId) {
return res.status(400).json({ error: 'clubId ist erforderlich' });
}
const result = await clickTtHttpPageService.fetchClubInfoDisplay({
association,
clubId,
userId,
});
res.json({
success: result.success,
status: result.status,
contentType: result.contentType,
executionTimeMs: result.executionTimeMs,
bodyLength: result.body?.length ?? 0,
body: result.body,
});
} catch (error) {
next(error);
}
});
/**
* GET /api/clicktt/region-meetings
* Ruft den Regionsspielplan ab (regionMeetingFilter)
*/
router.get('/region-meetings', authenticate, async (req, res, next) => {
try {
const association = req.query.association || 'HeTTV';
const championship = req.query.championship || 'HTTV 25/26';
const userId = req.user?.id ?? null;
const result = await clickTtHttpPageService.fetchRegionMeetingFilter({
association,
championship,
userId,
});
res.json({
success: result.success,
status: result.status,
contentType: result.contentType,
executionTimeMs: result.executionTimeMs,
bodyLength: result.body?.length ?? 0,
body: result.body,
});
} catch (error) {
next(error);
}
});
/**
* GET /api/clicktt/fetch
* Ruft eine beliebige URL ab (für manuelle Tests)
* Query: url (erforderlich)
*/
router.get('/fetch', authenticate, async (req, res, next) => {
try {
const url = req.query.url;
const userId = req.user?.id ?? null;
if (!url) {
return res.status(400).json({ error: 'url ist erforderlich' });
}
// Nur click-tt.de und httv.de erlauben
if (!url.includes('click-tt.de') && !url.includes('httv.de')) {
return res.status(400).json({
error: 'Nur URLs von click-tt.de oder httv.de sind erlaubt',
});
}
const result = await clickTtHttpPageService.fetchArbitraryUrl(url, {
fetchType: 'arbitrary',
userId,
});
res.json({
success: result.success,
status: result.status,
contentType: result.contentType,
executionTimeMs: result.executionTimeMs,
bodyLength: result.body?.length ?? 0,
body: result.body,
});
} catch (error) {
next(error);
}
});
/**
* GET /api/clicktt/logs
* Liefert die letzten HTTP-Page-Fetch-Logs
* Query: limit (default 50), fetchType, association, success
*/
router.get('/logs', authenticate, async (req, res, next) => {
try {
const limit = Math.min(parseInt(req.query.limit, 10) || 50, 200);
const { fetchType, association, success } = req.query;
const where = {};
if (fetchType) where.fetchType = fetchType;
if (association) where.association = association;
if (success !== undefined) where.success = success === 'true';
const logs = await HttpPageFetchLog.findAll({
where: Object.keys(where).length > 0 ? where : undefined,
order: [['createdAt', 'DESC']],
limit,
attributes: [
'id',
'fetchType',
'baseDomain',
'fullUrl',
'association',
'championship',
'clubIdParam',
'httpStatus',
'success',
'responseSnippet',
'contentType',
'errorMessage',
'executionTimeMs',
'createdAt',
],
});
res.json({
success: true,
count: logs.length,
logs,
});
} catch (error) {
next(error);
}
});
/**
* GET /api/clicktt/url-info
* Liefert Informationen zur URL-Struktur (Verband→Domain, Beispiel-URLs)
*/
router.get('/url-info', authenticate, async (req, res, next) => {
try {
const info = {
associationToDomain: clickTtHttpPageService.ASSOCIATION_TO_DOMAIN,
exampleUrls: {
leaguePage: clickTtHttpPageService.buildLeaguePageUrl({
association: 'HeTTV',
championship: 'HTTV 25/26',
}),
leaguePageBezirk: clickTtHttpPageService.buildLeaguePageUrl({
association: 'HeTTV',
championship: 'K43 25/26',
}),
clubInfoDisplay: clickTtHttpPageService.buildClubInfoDisplayUrl({
association: 'HeTTV',
clubId: '1060',
}),
regionMeetingFilter: clickTtHttpPageService.buildRegionMeetingFilterUrl({
association: 'HeTTV',
championship: 'HTTV 25/26',
}),
},
championshipExamples: [
'HTTV 25/26',
'HTTV 24/25',
'K43 25/26',
'K16 25/26',
'RL-OL West 25/26',
],
};
res.json({ success: true, ...info });
} catch (error) {
next(error);
}
});
export default router;