Implement tournament pairing functionality and enhance participant management
- Introduced new endpoints for managing tournament pairings, including creating, updating, and deleting pairings. - Updated the tournament service to handle pairing logic, ensuring validation for participants and preventing duplicate pairings. - Enhanced participant management by adding class-based checks for gender and age restrictions when adding participants. - Updated the tournament controller and routes to support the new pairing features and improved participant handling. - Added localization support for new UI elements related to pairings in the frontend, enhancing user experience.
This commit is contained in:
@@ -70,6 +70,11 @@ const ExternalTournamentParticipant = sequelize.define('ExternalTournamentPartic
|
||||
return decryptData(encryptedValue);
|
||||
}
|
||||
},
|
||||
gender: {
|
||||
type: DataTypes.ENUM('male', 'female', 'diverse', 'unknown'),
|
||||
allowNull: true,
|
||||
defaultValue: 'unknown'
|
||||
},
|
||||
seeded: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
|
||||
@@ -27,6 +27,23 @@ const TournamentClass = sequelize.define('TournamentClass', {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 0
|
||||
},
|
||||
isDoubles: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: false
|
||||
},
|
||||
gender: {
|
||||
type: DataTypes.ENUM('male', 'female', 'mixed'),
|
||||
allowNull: true,
|
||||
defaultValue: null
|
||||
},
|
||||
minBirthYear: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
field: 'min_birth_year',
|
||||
comment: 'Geboren im Jahr X oder später (>=)'
|
||||
}
|
||||
}, {
|
||||
underscored: true,
|
||||
|
||||
71
backend/models/TournamentPairing.js
Normal file
71
backend/models/TournamentPairing.js
Normal file
@@ -0,0 +1,71 @@
|
||||
import { DataTypes } from 'sequelize';
|
||||
import sequelize from '../database.js';
|
||||
import Tournament from './Tournament.js';
|
||||
import TournamentClass from './TournamentClass.js';
|
||||
|
||||
const TournamentPairing = sequelize.define('TournamentPairing', {
|
||||
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'
|
||||
},
|
||||
classId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
references: {
|
||||
model: TournamentClass,
|
||||
key: 'id'
|
||||
},
|
||||
onDelete: 'CASCADE',
|
||||
onUpdate: 'CASCADE'
|
||||
},
|
||||
groupId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true
|
||||
},
|
||||
// Player 1: entweder Mitglied oder externer Teilnehmer
|
||||
member1Id: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true
|
||||
},
|
||||
external1Id: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true
|
||||
},
|
||||
// Player 2: entweder Mitglied oder externer Teilnehmer
|
||||
member2Id: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true
|
||||
},
|
||||
external2Id: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true
|
||||
},
|
||||
seeded: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: false
|
||||
}
|
||||
}, {
|
||||
underscored: true,
|
||||
tableName: 'tournament_pairing',
|
||||
timestamps: true
|
||||
});
|
||||
|
||||
export default TournamentPairing;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import TournamentMember from './TournamentMember.js';
|
||||
import TournamentMatch from './TournamentMatch.js';
|
||||
import TournamentResult from './TournamentResult.js';
|
||||
import ExternalTournamentParticipant from './ExternalTournamentParticipant.js';
|
||||
import TournamentPairing from './TournamentPairing.js';
|
||||
import Accident from './Accident.js';
|
||||
import UserToken from './UserToken.js';
|
||||
import OfficialTournament from './OfficialTournament.js';
|
||||
@@ -269,6 +270,41 @@ TournamentClass.hasMany(ExternalTournamentParticipant, {
|
||||
as: 'externalParticipants'
|
||||
});
|
||||
|
||||
// Tournament Pairings
|
||||
TournamentPairing.belongsTo(Tournament, { foreignKey: 'tournamentId', as: 'tournament' });
|
||||
Tournament.hasMany(TournamentPairing, { foreignKey: 'tournamentId', as: 'pairings' });
|
||||
TournamentPairing.belongsTo(TournamentClass, { foreignKey: 'classId', as: 'class' });
|
||||
TournamentClass.hasMany(TournamentPairing, { foreignKey: 'classId', as: 'pairings' });
|
||||
TournamentPairing.belongsTo(TournamentGroup, {
|
||||
foreignKey: 'groupId',
|
||||
as: 'group',
|
||||
constraints: false
|
||||
});
|
||||
TournamentGroup.hasMany(TournamentPairing, {
|
||||
foreignKey: 'groupId',
|
||||
as: 'pairings'
|
||||
});
|
||||
TournamentPairing.belongsTo(TournamentMember, {
|
||||
foreignKey: 'member1Id',
|
||||
as: 'member1',
|
||||
constraints: false
|
||||
});
|
||||
TournamentPairing.belongsTo(TournamentMember, {
|
||||
foreignKey: 'member2Id',
|
||||
as: 'member2',
|
||||
constraints: false
|
||||
});
|
||||
TournamentPairing.belongsTo(ExternalTournamentParticipant, {
|
||||
foreignKey: 'external1Id',
|
||||
as: 'external1',
|
||||
constraints: false
|
||||
});
|
||||
TournamentPairing.belongsTo(ExternalTournamentParticipant, {
|
||||
foreignKey: 'external2Id',
|
||||
as: 'external2',
|
||||
constraints: false
|
||||
});
|
||||
|
||||
Accident.belongsTo(Member, { foreignKey: 'memberId', as: 'members' });
|
||||
Member.hasMany(Accident, { foreignKey: 'memberId', as: 'accidents' });
|
||||
|
||||
@@ -355,6 +391,7 @@ export {
|
||||
TournamentMatch,
|
||||
TournamentResult,
|
||||
ExternalTournamentParticipant,
|
||||
TournamentPairing,
|
||||
Accident,
|
||||
UserToken,
|
||||
OfficialTournament,
|
||||
|
||||
Reference in New Issue
Block a user