feat(tournament): add cleanup logic for orphaned matches
- Implemented a new method to clean up orphaned matches where at least one player no longer exists, enhancing data integrity in tournament management. - Added a corresponding route and frontend functionality to trigger the cleanup process, allowing users to easily remove invalid match records. - Updated localization strings to support the new feature, ensuring clarity in the user interface.
This commit is contained in:
@@ -420,6 +420,19 @@ export const resetMatches = async (req, res) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const cleanupOrphanedMatches = async (req, res) => {
|
||||
const { authcode: token } = req.headers;
|
||||
const { clubId, tournamentId } = req.body;
|
||||
try {
|
||||
const result = await tournamentService.cleanupOrphanedMatches(token, clubId, tournamentId);
|
||||
emitTournamentChanged(clubId, tournamentId);
|
||||
res.status(200).json(result);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
};
|
||||
|
||||
export const removeParticipant = async (req, res) => {
|
||||
const { authcode: token } = req.headers;
|
||||
const { clubId, tournamentId, participantId } = req.body;
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
manualAssignGroups,
|
||||
resetGroups,
|
||||
resetMatches,
|
||||
cleanupOrphanedMatches,
|
||||
removeParticipant,
|
||||
updateParticipantSeeded,
|
||||
setParticipantGaveUp,
|
||||
@@ -61,6 +62,7 @@ router.put('/participant/:clubId/:tournamentId/:participantId/gave-up', authenti
|
||||
router.post('/modus', authenticate, setModus);
|
||||
router.post('/groups/reset', authenticate, resetGroups);
|
||||
router.post('/matches/reset', authenticate, resetMatches);
|
||||
router.post('/matches/cleanup-orphaned', authenticate, cleanupOrphanedMatches);
|
||||
router.put('/groups', authenticate, createGroups);
|
||||
router.post('/groups/create', authenticate, createGroupsPerClass);
|
||||
router.post('/groups', authenticate, fillGroups);
|
||||
|
||||
@@ -3201,6 +3201,38 @@ Ve // 2. Neues Turnier anlegen
|
||||
await TournamentMatch.destroy({ where });
|
||||
}
|
||||
|
||||
/**
|
||||
* Entfernt Matches, bei denen mindestens ein Spieler nicht mehr existiert
|
||||
* (z.B. gelöscht bevor die Aufräum-Logik beim Teilnehmerlöschen eingeführt wurde).
|
||||
*/
|
||||
async cleanupOrphanedMatches(userToken, clubId, tournamentId) {
|
||||
await checkAccess(userToken, clubId);
|
||||
const tournament = await Tournament.findByPk(tournamentId);
|
||||
if (!tournament || tournament.clubId != clubId) {
|
||||
throw new Error('Turnier nicht gefunden');
|
||||
}
|
||||
|
||||
const members = await TournamentMember.findAll({ where: { tournamentId }, attributes: ['id'] });
|
||||
const externals = await ExternalTournamentParticipant.findAll({ where: { tournamentId }, attributes: ['id'] });
|
||||
const validIds = new Set([
|
||||
...members.map(m => m.id),
|
||||
...externals.map(e => e.id)
|
||||
]);
|
||||
|
||||
const matches = await TournamentMatch.findAll({ where: { tournamentId } });
|
||||
let deletedCount = 0;
|
||||
for (const m of matches) {
|
||||
const p1Exists = !m.player1Id || validIds.has(m.player1Id);
|
||||
const p2Exists = !m.player2Id || validIds.has(m.player2Id);
|
||||
if (!p1Exists || !p2Exists) {
|
||||
await TournamentResult.destroy({ where: { matchId: m.id } });
|
||||
await m.destroy();
|
||||
deletedCount++;
|
||||
}
|
||||
}
|
||||
return { deletedCount };
|
||||
}
|
||||
|
||||
async removeParticipant(userToken, clubId, tournamentId, participantId) {
|
||||
await checkAccess(userToken, clubId);
|
||||
|
||||
|
||||
@@ -162,8 +162,14 @@
|
||||
<button @click="$emit('create-matches')" class="btn-primary">
|
||||
▶️ Gruppenspiele berechnen
|
||||
</button>
|
||||
<button @click="$emit('cleanup-orphaned-matches')" class="btn-secondary">
|
||||
🧹 {{ $t('tournaments.cleanupOrphanedMatches') }}
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="filteredGroupMatches.length > 0" class="reset-controls" style="margin-top:1rem">
|
||||
<button @click="$emit('cleanup-orphaned-matches')" class="btn-secondary">
|
||||
🧹 {{ $t('tournaments.cleanupOrphanedMatches') }}
|
||||
</button>
|
||||
<button @click="$emit('reset-matches')" class="trash-btn">
|
||||
🗑️ {{ $t('tournaments.resetGroupMatches') }}
|
||||
</button>
|
||||
@@ -246,6 +252,7 @@ export default {
|
||||
'randomize-groups',
|
||||
'reset-groups',
|
||||
'reset-matches',
|
||||
'cleanup-orphaned-matches',
|
||||
'create-matches',
|
||||
'highlight-match',
|
||||
'go-to-match',
|
||||
|
||||
@@ -648,6 +648,7 @@
|
||||
"errorMoreSeededThanUnseeded": "Es gibt mehr gesetzte als nicht gesetzte Spieler. Zufällige Paarungen können nicht erstellt werden.",
|
||||
"randomPairingsCreated": "Zufällige Paarungen wurden erstellt.",
|
||||
"resetGroupMatches": "Gruppenspiele",
|
||||
"cleanupOrphanedMatches": "Verwaiste Spiele aufräumen",
|
||||
"groupMatches": "Gruppenspiele",
|
||||
"round": "Runde",
|
||||
"encounter": "Begegnung",
|
||||
|
||||
@@ -198,6 +198,7 @@
|
||||
@randomize-groups="randomizeGroups()"
|
||||
@reset-groups="resetGroups()"
|
||||
@reset-matches="resetMatches()"
|
||||
@cleanup-orphaned-matches="cleanupOrphanedMatches()"
|
||||
@create-matches="createMatches()"
|
||||
@highlight-match="highlightMatch"
|
||||
@go-to-match="goToMatch"
|
||||
@@ -2084,6 +2085,26 @@ export default {
|
||||
await this.loadTournamentData();
|
||||
},
|
||||
|
||||
async cleanupOrphanedMatches() {
|
||||
try {
|
||||
const res = await apiClient.post('/tournament/matches/cleanup-orphaned', {
|
||||
clubId: this.currentClub,
|
||||
tournamentId: this.selectedDate
|
||||
});
|
||||
const count = res.data?.deletedCount ?? 0;
|
||||
await this.loadTournamentData();
|
||||
if (count > 0) {
|
||||
await this.showInfo(this.$t('messages.success'), `${count} ${count === 1 ? 'Spiel' : 'Spiele'} entfernt.`, '');
|
||||
} else {
|
||||
await this.showInfo(this.$t('messages.info'), 'Keine verwaisten Spiele gefunden.', '');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Aufräumen:', error);
|
||||
const message = safeErrorMessage(error, 'Fehler beim Aufräumen verwaister Spiele.');
|
||||
await this.showInfo(this.$t('messages.error'), message, '', 'error');
|
||||
}
|
||||
},
|
||||
|
||||
async removeParticipant(p) {
|
||||
try {
|
||||
if (this.allowsExternal && p.isExternal) {
|
||||
|
||||
Reference in New Issue
Block a user