diff --git a/backend/controllers/officialTournamentController.js b/backend/controllers/officialTournamentController.js index 99b3ab53..c94f3054 100755 --- a/backend/controllers/officialTournamentController.js +++ b/backend/controllers/officialTournamentController.js @@ -16,6 +16,20 @@ export const saveTournamentSuggestion = async (req, res) => { } }; +export const reimportOfficialTournament = async (req, res) => { + try { + const { authcode: userToken } = req.headers; + const { clubId, id } = req.params; + await checkAccess(userToken, clubId); + const result = await officialTournamentService.reimportOfficialTournament(clubId, id); + if (!result) return res.status(404).json({ error: 'Turnier nicht gefunden.' }); + return res.json(result); + } catch (error) { + console.error('[reimportOfficialTournament] Error:', error); + return res.status(error.status || 500).json({ error: error.message || 'Turnierdaten konnten nicht aktualisiert werden.' }); + } +}; + export const updateOfficialTournament = async (req, res) => { try { const { authcode: userToken } = req.headers; diff --git a/backend/routes/officialTournamentRoutes.js b/backend/routes/officialTournamentRoutes.js index 05a5babf..cbbd54a4 100755 --- a/backend/routes/officialTournamentRoutes.js +++ b/backend/routes/officialTournamentRoutes.js @@ -11,7 +11,7 @@ import { listClubParticipations, updateParticipantStatus, autoRegisterOfficialTournamentParticipants - , listTacticPlans, saveTacticPlan, deleteTacticPlan, saveTournamentSuggestion + , listTacticPlans, saveTacticPlan, deleteTacticPlan, saveTournamentSuggestion, reimportOfficialTournament } from '../controllers/officialTournamentController.js'; import { fetchTournamentSuggestions, listTournamentSuggestions, updateTournamentSuggestion } from '../controllers/tournamentSuggestionController.js'; @@ -31,6 +31,7 @@ router.get('/:clubId/:tournamentId/tactics', listTacticPlans); router.post('/:clubId/:tournamentId/tactics', saveTacticPlan); router.patch('/:clubId/:tournamentId/tactics/:planId', saveTacticPlan); router.delete('/:clubId/:tournamentId/tactics/:planId', deleteTacticPlan); +router.post('/:clubId/:id/reimport', reimportOfficialTournament); router.get('/:clubId/:id', getParsedTournament); router.patch('/:clubId/:id', updateOfficialTournament); router.delete('/:clubId/:id', deleteOfficialTournament); diff --git a/backend/services/officialTournamentService.js b/backend/services/officialTournamentService.js index 587c459e..d2a8b49b 100755 --- a/backend/services/officialTournamentService.js +++ b/backend/services/officialTournamentService.js @@ -96,6 +96,18 @@ class OfficialTournamentService { return repaired; } + async reimportOfficialTournament(clubId, tournamentId) { + const tournament = await OfficialTournament.findOne({ where: { id: tournamentId, clubId } }); + if (!tournament) return null; + const updatedCount = await this.repairTournamentFromSource(clubId, tournament); + if (!tournament.sourceUrl) { + const error = new Error('Für dieses Turnier ist keine myTischtennis-Quelle hinterlegt.'); + error.status = 400; + throw error; + } + return { id: String(tournament.id), updatedCount }; + } + async saveTournamentSuggestion(clubId, suggestionId) { const suggestion = await TournamentSuggestion.findOne({ where: { id: suggestionId, clubId } }); if (!suggestion) return null; diff --git a/frontend/src/views/OfficialTournaments.vue b/frontend/src/views/OfficialTournaments.vue index 6072a330..20294d4a 100755 --- a/frontend/src/views/OfficialTournaments.vue +++ b/frontend/src/views/OfficialTournaments.vue @@ -232,6 +232,9 @@ @click="generateMembersPdf"> {{ $t('officialTournaments.pdfForSelectedMembers') }} +
@@ -690,6 +694,7 @@ export default { editingTournamentId: null, editingTitle: '', autoRegistering: false, + reimporting: false, suggestions: [], fetchingSuggestions: false, suggestionError: '', suggestionSearch: '', suggestionStatusFilter: 'new', tacticPlans: [], tacticPlan: null, tacticPlansSnapshot: '', tacticsLoading: false, tacticSaving: false, tacticsError: '', tacticTournamentId: null, tacticLoadToken: 0, reloadToken: 0, @@ -1678,6 +1683,16 @@ export default { this.workspaceTab = 'saved'; } catch (error) { this.suggestionError = getSafeErrorMessage(error, 'Der Vorschlag konnte nicht gespeichert werden.'); } }, + async reimportTournament() { + if (!this.uploadedId || this.reimporting) return; + this.reimporting = true; + try { + const response = await apiClient.post(`/official-tournaments/${this.currentClub}/${this.uploadedId}/reimport`); + await Promise.all([this.reload(), this.loadList()]); + await this.showInfo('Turnierdaten aktualisiert', `${response.data?.updatedCount || 0} Datenbereiche wurden aus myTischtennis aktualisiert.`, '', 'success'); + } catch (error) { await this.showInfo('Aktualisierung nicht möglich', getSafeErrorMessage(error, 'Die Turnierdaten konnten nicht aktualisiert werden.'), '', 'error'); } + finally { this.reimporting = false; } + }, buildParticipationMap(entries) { const map = {}; for (const e of entries) {