feat(official-tournaments): implement reimport functionality for official tournaments
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 57s
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 57s
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -232,6 +232,9 @@
|
||||
@click="generateMembersPdf">
|
||||
{{ $t('officialTournaments.pdfForSelectedMembers') }}
|
||||
</button>
|
||||
<button class="btn-secondary" :disabled="reimporting" @click="reimportTournament">
|
||||
{{ reimporting ? 'Aktualisiert …' : 'Daten aktualisieren' }}
|
||||
</button>
|
||||
<button
|
||||
v-if="primaryHeaderAction !== 'auto-register'"
|
||||
class="btn-secondary"
|
||||
@@ -565,6 +568,7 @@
|
||||
<div class="calendar-entry-empty">
|
||||
<h3>Kalendereintrag geöffnet</h3>
|
||||
<p>Für dieses Turnier sind noch keine Konkurrenzen hinterlegt. Importiere eine Ausschreibung als PDF, sobald du Teilnehmer oder Ergebnisse verwalten möchtest.</p>
|
||||
<button class="btn-secondary" :disabled="reimporting" @click="reimportTournament">{{ reimporting ? 'Aktualisiert …' : 'Daten aktualisieren' }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="workspace-detail empty-workspace">
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user