feat(official-tournaments): add venue handling and repair logic for tournament venues
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 1m2s
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 1m2s
This commit is contained in:
@@ -55,6 +55,17 @@ class OfficialTournamentService {
|
||||
const source = new URL(sourceUrl);
|
||||
if (!['www.mytischtennis.de', 'mytischtennis.de'].includes(source.hostname)) return 0;
|
||||
const response = await axios.get(sourceUrl, { timeout: 30000, headers: { 'User-Agent': 'Trainingstagebuch/1.0 (+turnierdetails)' } });
|
||||
const venues = this.extractJsonArray(response.data, 'tournament_locations')
|
||||
.map((location) => [location.location_name, location.location_street, [location.location_zip, location.location_city].filter(Boolean).join(' ')].filter(Boolean).join(', '))
|
||||
.filter(Boolean);
|
||||
let repaired = 0;
|
||||
if (venues.length) {
|
||||
const storedVenues = JSON.parse(tournament.venues || '[]');
|
||||
if (JSON.stringify(storedVenues) !== JSON.stringify(venues)) {
|
||||
await tournament.update({ venues: JSON.stringify(venues) });
|
||||
repaired += 1;
|
||||
}
|
||||
}
|
||||
const competitions = this.extractJsonArray(response.data, 'competition_infos')
|
||||
.filter((competition) => competition?.competition_name)
|
||||
.map((competition) => ({
|
||||
@@ -69,11 +80,10 @@ class OfficialTournamentService {
|
||||
maxParticipants: competition.competition_player_capacity_total == null ? null : String(competition.competition_player_capacity_total),
|
||||
entryFee: competition.competition_fee == null ? null : `${competition.competition_fee}${competition.competition_fee_currency === 'euro' ? '€' : ''}`,
|
||||
}));
|
||||
if (!competitions.length) return 0;
|
||||
if (!competitions.length) return repaired;
|
||||
|
||||
const existing = await OfficialCompetition.findAll({ where: { tournamentId: tournament.id } });
|
||||
const byName = new Map(existing.map((competition) => [this.normalizeCompetitionName(competition.ageClassCompetition), competition]));
|
||||
let repaired = 0;
|
||||
for (const competition of competitions) {
|
||||
const existingCompetition = byName.get(this.normalizeCompetitionName(competition.ageClassCompetition));
|
||||
if (existingCompetition) {
|
||||
@@ -197,7 +207,9 @@ class OfficialTournamentService {
|
||||
if (!t) return null;
|
||||
|
||||
let comps = await OfficialCompetition.findAll({ where: { tournamentId: id } });
|
||||
const needsRepair = !comps.length || comps.some((competition) => !competition.startTime || competition.entryFee == null);
|
||||
const venues = JSON.parse(t.venues || '[]');
|
||||
const needsVenueRepair = !venues.length || venues.every((venue) => !String(venue).includes(','));
|
||||
const needsRepair = needsVenueRepair || !comps.length || comps.some((competition) => !competition.startTime || competition.entryFee == null);
|
||||
if (needsRepair) {
|
||||
try {
|
||||
await this.repairTournamentFromSource(clubId, t);
|
||||
|
||||
@@ -580,6 +580,15 @@ class PDFGenerator {
|
||||
this.pdf.text(lines, 105, y + 1, { align: 'center' });
|
||||
y += boxHeight + 4;
|
||||
}
|
||||
const venueLines = Array.isArray(venues) ? venues.filter(Boolean) : [];
|
||||
if (venueLines.length) {
|
||||
const venueText = `${this.t('pdfGenerator.venue')}: ${venueLines.join(' · ')}`;
|
||||
const lines = this.pdf.splitTextToSize(venueText, 210 - this.margin * 2);
|
||||
this.pdf.setFont('helvetica', 'bold');
|
||||
this.pdf.setFontSize(11);
|
||||
this.pdf.text(lines, this.margin, y);
|
||||
y += lines.length * 5 + 3;
|
||||
}
|
||||
this.pdf.setFont('helvetica', 'bold');
|
||||
this.pdf.setFontSize(12);
|
||||
this.pdf.text(`${this.t('pdfGenerator.member')} ${memberName}`, this.margin, y);
|
||||
@@ -632,37 +641,6 @@ class PDFGenerator {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Austragungsort(e) direkt vor den Hinweisen
|
||||
const venueLines = Array.isArray(venues) ? venues.filter(Boolean) : [];
|
||||
if (venueLines.length) {
|
||||
const heading = venueLines.length === 1 ? this.t('pdfGenerator.venue') : this.t('pdfGenerator.venues');
|
||||
const maxWidth = 210 - this.margin * 2;
|
||||
if (y + 20 + venueLines.length * 6 > this.pageHeight) {
|
||||
this.addNewPage();
|
||||
y = this.margin;
|
||||
} else {
|
||||
y += 6;
|
||||
}
|
||||
this.pdf.setFont('helvetica', 'bold');
|
||||
this.pdf.setFontSize(13);
|
||||
this.pdf.text(`${heading}:`, this.margin, y);
|
||||
y += 7;
|
||||
this.pdf.setFont('helvetica', 'normal');
|
||||
this.pdf.setFontSize(12);
|
||||
for (const v of venueLines) {
|
||||
const wrapped = this.pdf.splitTextToSize(String(v), maxWidth);
|
||||
for (const line of wrapped) {
|
||||
this.pdf.text(line, this.margin, y);
|
||||
y += 6;
|
||||
if (y > this.pageHeight) {
|
||||
this.addNewPage();
|
||||
y = this.margin;
|
||||
this.pdf.setFont('helvetica', 'normal');
|
||||
this.pdf.setFontSize(12);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Hinweise-Sektion
|
||||
const remainingForHints = 60; // Platz für Überschrift + Liste abschätzen
|
||||
if (y + remainingForHints > this.pageHeight) {
|
||||
|
||||
Reference in New Issue
Block a user