Implement external participant management and tournament class features

This commit enhances the tournament management system by introducing functionality for handling external participants and tournament classes. New methods are added to the `tournamentController` and `tournamentService` for adding, retrieving, updating, and removing external participants, as well as managing tournament classes. The backend models are updated to support these features, including new relationships and attributes. The frontend is also updated to allow users to manage external participants and classes, improving the overall user experience and interactivity in tournament management.
This commit is contained in:
Torsten Schulz (local)
2025-11-14 22:36:51 +01:00
parent 3334d76688
commit d08835e206
24 changed files with 2798 additions and 326 deletions

View File

@@ -0,0 +1,89 @@
import { DataTypes } from 'sequelize';
import sequelize from '../database.js';
import { encryptData, decryptData } from '../utils/encrypt.js';
const ExternalTournamentParticipant = sequelize.define('ExternalTournamentParticipant', {
tournamentId: {
type: DataTypes.INTEGER,
allowNull: false,
},
groupId: {
type: DataTypes.INTEGER,
autoIncrement: false,
allowNull: true
},
firstName: {
type: DataTypes.STRING,
allowNull: false,
set(value) {
const encryptedValue = encryptData(value);
this.setDataValue('firstName', encryptedValue);
},
get() {
const encryptedValue = this.getDataValue('firstName');
return decryptData(encryptedValue);
}
},
lastName: {
type: DataTypes.STRING,
allowNull: false,
set(value) {
const encryptedValue = encryptData(value);
this.setDataValue('lastName', encryptedValue);
},
get() {
const encryptedValue = this.getDataValue('lastName');
return decryptData(encryptedValue);
}
},
club: {
type: DataTypes.STRING,
allowNull: true,
set(value) {
if (!value) {
this.setDataValue('club', null);
return;
}
const encryptedValue = encryptData(value);
this.setDataValue('club', encryptedValue);
},
get() {
const encryptedValue = this.getDataValue('club');
if (!encryptedValue) return null;
return decryptData(encryptedValue);
}
},
birthDate: {
type: DataTypes.STRING,
allowNull: true,
set(value) {
if (!value) {
this.setDataValue('birthDate', null);
return;
}
const encryptedValue = encryptData(value || '');
this.setDataValue('birthDate', encryptedValue);
},
get() {
const encryptedValue = this.getDataValue('birthDate');
if (!encryptedValue) return null;
return decryptData(encryptedValue);
}
},
seeded: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
},
classId: {
type: DataTypes.INTEGER,
allowNull: true
}
}, {
underscored: true,
tableName: 'external_tournament_participant',
timestamps: true,
});
export default ExternalTournamentParticipant;

View File

@@ -34,6 +34,11 @@ const Tournament = sequelize.define('Tournament', {
allowNull: false,
defaultValue: 3,
},
allowsExternal: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
},
}, {
underscored: true,
tableName: 'tournament',

View File

@@ -0,0 +1,38 @@
import { DataTypes } from 'sequelize';
import sequelize from '../database.js';
import Tournament from './Tournament.js';
const TournamentClass = sequelize.define('TournamentClass', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false
},
tournamentId: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: Tournament,
key: 'id'
},
onDelete: 'CASCADE',
onUpdate: 'CASCADE'
},
name: {
type: DataTypes.STRING,
allowNull: false
},
sortOrder: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
}
}, {
underscored: true,
tableName: 'tournament_class',
timestamps: true
});
export default TournamentClass;

View File

@@ -12,6 +12,10 @@ const TournamentGroup = sequelize.define('TournamentGroup', {
type: DataTypes.INTEGER,
allowNull: false
},
classId: {
type: DataTypes.INTEGER,
allowNull: true
},
}, {
underscored: true,
tableName: 'tournament_group',

View File

@@ -25,6 +25,10 @@ const TournamentMatch = sequelize.define('TournamentMatch', {
onDelete: 'SET NULL',
onUpdate: 'CASCADE'
},
classId: {
type: DataTypes.INTEGER,
allowNull: true,
},
groupRound: {
type: DataTypes.INTEGER,
allowNull: true,

View File

@@ -21,6 +21,10 @@ const TournamentMember = sequelize.define('TournamentMember', {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
},
classId: {
type: DataTypes.INTEGER,
allowNull: true
}
}, {
underscored: true,

View File

@@ -27,9 +27,11 @@ import Group from './Group.js';
import GroupActivity from './GroupActivity.js';
import Tournament from './Tournament.js';
import TournamentGroup from './TournamentGroup.js';
import TournamentClass from './TournamentClass.js';
import TournamentMember from './TournamentMember.js';
import TournamentMatch from './TournamentMatch.js';
import TournamentResult from './TournamentResult.js';
import ExternalTournamentParticipant from './ExternalTournamentParticipant.js';
import Accident from './Accident.js';
import UserToken from './UserToken.js';
import OfficialTournament from './OfficialTournament.js';
@@ -201,6 +203,15 @@ Member.hasMany(TournamentMember, { foreignKey: 'clubMemberId', as: 'tournamentGr
TournamentMember.belongsTo(Tournament, { foreignKey: 'tournamentId', as: 'tournament' });
Tournament.hasMany(TournamentMember, { foreignKey: 'tournamentId', as: 'tournamentMembers' });
TournamentMember.belongsTo(TournamentClass, {
foreignKey: 'classId',
as: 'class',
constraints: false
});
TournamentClass.hasMany(TournamentMember, {
foreignKey: 'classId',
as: 'members'
});
TournamentMatch.belongsTo(Tournament, { foreignKey: 'tournamentId', as: 'tournament' });
Tournament.hasMany(TournamentMatch, { foreignKey: 'tournamentId', as: 'tournamentMatches' });
@@ -227,6 +238,33 @@ TournamentMatch.belongsTo(TournamentMember, { foreignKey: 'player2Id', as: 'play
TournamentMember.hasMany(TournamentMatch, { foreignKey: 'player1Id', as: 'player1Matches' });
TournamentMember.hasMany(TournamentMatch, { foreignKey: 'player2Id', as: 'player2Matches' });
// Tournament Classes
TournamentClass.belongsTo(Tournament, { foreignKey: 'tournamentId', as: 'tournament' });
Tournament.hasMany(TournamentClass, { foreignKey: 'tournamentId', as: 'classes' });
// External Tournament Participants
ExternalTournamentParticipant.belongsTo(Tournament, { foreignKey: 'tournamentId', as: 'tournament' });
Tournament.hasMany(ExternalTournamentParticipant, { foreignKey: 'tournamentId', as: 'externalParticipants' });
ExternalTournamentParticipant.belongsTo(TournamentGroup, {
foreignKey: 'groupId',
targetKey: 'id',
as: 'group',
constraints: false
});
TournamentGroup.hasMany(ExternalTournamentParticipant, {
foreignKey: 'groupId',
as: 'externalGroupMembers'
});
ExternalTournamentParticipant.belongsTo(TournamentClass, {
foreignKey: 'classId',
as: 'class',
constraints: false
});
TournamentClass.hasMany(ExternalTournamentParticipant, {
foreignKey: 'classId',
as: 'externalParticipants'
});
Accident.belongsTo(Member, { foreignKey: 'memberId', as: 'members' });
Member.hasMany(Accident, { foreignKey: 'memberId', as: 'accidents' });
@@ -283,9 +321,11 @@ export {
GroupActivity,
Tournament,
TournamentGroup,
TournamentClass,
TournamentMember,
TournamentMatch,
TournamentResult,
ExternalTournamentParticipant,
Accident,
UserToken,
OfficialTournament,