Add Teams endpoint and endpoints with service

This commit is contained in:
2026-03-09 15:48:47 +01:00
parent 67d4288c84
commit ea45d74c0f
7 changed files with 383 additions and 44 deletions

View File

@@ -4,6 +4,7 @@ import 'dotenv/config';
import {TournamentService} from './services/tournament-service';
import {UserService} from './services/user-service';
import {TeamService} from './services/team-service';
import router from './middlewares/logger';
import {Database} from 'sqlite3';
import fs from "fs";
@@ -17,6 +18,7 @@ if (fs.existsSync(dbFilename)){
const db = new Database(dbFilename);
const tournamentService = new TournamentService(db);
const userService = new UserService(db);
const teamService = new TeamService(db);
const port = process.env.PORT || 3000;
const app = express();
@@ -24,12 +26,11 @@ app.use(bodyParser.json());
app.use(router);
app.get('/tournaments', async (req: Request, res: Response) => {
console.log(req.params)
if (!req.params.id) {
const tournaments = await tournamentService.getAllTournaments();
console.log(tournaments)
return res.send(tournaments);
}
const tournaments = await tournamentService.getAllTournaments();
return res.send(tournaments);
});
app.get('/tournaments/:id', async (req: Request, res: Response) => {
const tournament = await tournamentService.getTournamentById(+req.params.id);
if (!tournament) {
return res.status(404).send({error: 'Tournament not found'});
@@ -38,42 +39,113 @@ app.get('/tournaments', async (req: Request, res: Response) => {
});
app.post('/tournaments', async (req: Request, res: Response) => {
console.log("post");
try {
await tournamentService.addTournament(req.body);
res.status(200).send();
}catch (err){
res.status(201).send();
} catch (err){
console.log(err);
res.status(404).send();
res.status(400).send({error: 'Failed to create tournament'});
}
});
app.put('/tournaments', async (req: Request, res: Response) => {
if (!req.query.id) {
return res.status(400).send({error: 'Missing id parameter'});
}
app.put('/tournaments/:id', async (req: Request, res: Response) => {
try {
const success = await tournamentService.updateTournament(+req.query.id!, req.body);
await tournamentService.updateTournament(+req.params.id, req.body);
} catch (err) {
return res.status(400).send({error: 'Failed to update Tournament'});
}
res.status(200).send({message: 'Tournament updated successfully'});
});
app.delete('/tournaments', async (req: Request, res: Response) => {
if (!req.query.id) {
return res.status(400).send({error: 'Missing id parameter'});
}
app.delete('/tournaments/:id', async (req: Request, res: Response) => {
try {
const success = await tournamentService.deleteTournament(+req.query.id!);
await tournamentService.deleteTournament(+req.params.id);
} catch (err) {
return res.status(400).send({error: 'Failed to delete Tournament'});
}
res.status(200).send({message: 'Tournament deleted successfully'});
});
// Auth routes
app.get('/teams', async (req: Request, res: Response) => {
const teams = await teamService.getAllTeams();
res.send(teams);
});
app.get('/teams/:id', async (req: Request, res: Response) => {
const team = await teamService.getTeamById(+req.params.id);
if (!team) {
return res.status(404).send({error: 'Team not found'});
}
res.send(team);
});
app.post('/teams', async (req: Request, res: Response) => {
const {name, tag, description} = req.body;
if (!name || !tag) {
return res.status(400).send({error: 'name and tag are required'});
}
try {
const team = await teamService.addTeam({name, tag, description: description ?? ''});
res.status(201).send(team);
} catch (err) {
console.log(err);
res.status(400).send({error: 'Failed to create team'});
}
});
app.put('/teams/:id', async (req: Request, res: Response) => {
try {
await teamService.updateTeam(+req.params.id, req.body);
} catch (err) {
return res.status(400).send({error: 'Failed to update team'});
}
res.status(200).send({message: 'Team updated successfully'});
});
app.delete('/teams/:id', async (req: Request, res: Response) => {
try {
await teamService.deleteTeam(+req.params.id);
} catch (err) {
return res.status(400).send({error: 'Failed to delete team'});
}
res.status(200).send({message: 'Team deleted successfully'});
});
app.get('/tournaments/:id/teams', async (req: Request, res: Response) => {
const teams = await teamService.getTeamsByTournamentId(+req.params.id);
res.send(teams);
});
app.post('/tournaments/:id/teams', async (req: Request, res: Response) => {
const {teamId} = req.body;
if (!teamId) {
return res.status(400).send({error: 'teamId is required'});
}
try {
const entry = await teamService.registerTeamForTournament(+req.params.id, +teamId);
res.status(201).send(entry);
} catch (err: any) {
if (err.message?.includes('UNIQUE constraint failed')) {
return res.status(409).send({error: 'Team is already registered for this tournament'});
}
res.status(400).send({error: 'Failed to register team'});
}
});
app.delete('/tournaments/:id/teams/:teamId', async (req: Request, res: Response) => {
try {
await teamService.removeTeamFromTournament(+req.params.id, +req.params.teamId);
} catch (err) {
return res.status(400).send({error: 'Failed to remove team from tournament'});
}
res.status(200).send({message: 'Team removed from tournament'});
});
app.get('/teams/:id/tournaments', async (req: Request, res: Response) => {
const entries = await teamService.getTournamentsByTeamId(+req.params.id);
res.send(entries);
});
app.post('/register', async (req: Request, res: Response) => {
const { username, password } = req.body;
if (!username || !password) {

View File

@@ -0,0 +1,15 @@
export interface Team {
id: number;
name: string;
tag: string;
description: string;
createdAt: string;
}
export interface TournamentTeam {
id: number;
tournamentId: number;
teamId: number;
registeredAt: string;
}

View File

@@ -1,9 +1,12 @@
import { Team } from './team';
export interface Tournament {
id:number;
name:String;
description:String;
maxTeamAmount:number;
currentTeamAmount:number;
registrationStartDate:String;
registrationEndDate:String;
id: number;
name: String;
description: String;
maxTeamAmount: number;
currentTeamAmount: number;
registrationStartDate: String;
registrationEndDate: String;
teams?: Team[];
}

View File

@@ -0,0 +1,149 @@
import { Team, TournamentTeam } from '../models/team';
import { Database, RunResult } from 'sqlite3';
export class TeamService {
private db: Database;
constructor(db: Database) {
this.db = db;
this.db.serialize(() => {
this.db.run(`CREATE TABLE IF NOT EXISTS Teams
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
tag TEXT NOT NULL,
description TEXT,
createdAt TEXT NOT NULL DEFAULT (datetime('now'))
)`);
this.db.run(`CREATE TABLE IF NOT EXISTS TournamentTeams
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
tournamentId INTEGER NOT NULL,
teamId INTEGER NOT NULL,
registeredAt TEXT NOT NULL DEFAULT (datetime('now')),
FOREIGN KEY (tournamentId) REFERENCES Tournaments (id) ON DELETE CASCADE,
FOREIGN KEY (teamId) REFERENCES Teams (id) ON DELETE CASCADE,
UNIQUE (tournamentId, teamId)
)`);
});
}
getAllTeams(): Promise<Team[]> {
return new Promise<Team[]>((resolve, reject) => {
this.db.all(`SELECT * FROM Teams`, (err: Error | null, rows: Team[]) => {
if (err) return reject(err);
resolve(rows);
});
});
}
getTeamById(id: number): Promise<Team | undefined> {
return new Promise<Team | undefined>((resolve, reject) => {
this.db.get(
`SELECT * FROM Teams WHERE id = ?`,
[id],
(err: Error | null, row: Team | undefined) => {
if (err) return reject(err);
resolve(row);
}
);
});
}
addTeam(team: Omit<Team, 'id' | 'createdAt'>): Promise<Team> {
return new Promise<Team>((resolve, reject) => {
const stmt = this.db.prepare(
`INSERT INTO Teams (name, tag, description) VALUES (?, ?, ?)`
);
stmt.run(team.name, team.tag, team.description, function (this: RunResult, err: Error | null) {
if (err) return reject(err);
resolve({ id: (this as any).lastID, createdAt: new Date().toISOString(), ...team });
});
stmt.finalize();
});
}
updateTeam(id: number, team: Partial<Omit<Team, 'id' | 'createdAt'>>): Promise<void> {
return new Promise((resolve, reject) => {
this.db.run(
`UPDATE Teams SET name = COALESCE(?, name), tag = COALESCE(?, tag), description = COALESCE(?, description) WHERE id = ?`,
[team.name ?? null, team.tag ?? null, team.description ?? null, id],
(err: Error | null) => {
if (err) return reject(err);
resolve();
}
);
});
}
deleteTeam(id: number): Promise<void> {
return new Promise((resolve, reject) => {
this.db.run(`DELETE FROM Teams WHERE id = ?`, [id], (err: Error | null) => {
if (err) return reject(err);
resolve();
});
});
}
getTeamsByTournamentId(tournamentId: number): Promise<Team[]> {
return new Promise<Team[]>((resolve, reject) => {
this.db.all(
`SELECT t.*, tt.registeredAt
FROM Teams t
INNER JOIN TournamentTeams tt ON t.id = tt.teamId
WHERE tt.tournamentId = ?`,
[tournamentId],
(err: Error | null, rows: Team[]) => {
if (err) return reject(err);
resolve(rows);
}
);
});
}
getTournamentsByTeamId(teamId: number): Promise<TournamentTeam[]> {
return new Promise<TournamentTeam[]>((resolve, reject) => {
this.db.all(
`SELECT * FROM TournamentTeams WHERE teamId = ?`,
[teamId],
(err: Error | null, rows: TournamentTeam[]) => {
if (err) return reject(err);
resolve(rows);
}
);
});
}
registerTeamForTournament(tournamentId: number, teamId: number): Promise<TournamentTeam> {
return new Promise<TournamentTeam>((resolve, reject) => {
const stmt = this.db.prepare(
`INSERT INTO TournamentTeams (tournamentId, teamId) VALUES (?, ?)`
);
stmt.run(tournamentId, teamId, function (this: RunResult, err: Error | null) {
if (err) return reject(err);
resolve({
id: (this as any).lastID,
tournamentId,
teamId,
registeredAt: new Date().toISOString(),
});
});
stmt.finalize();
});
}
removeTeamFromTournament(tournamentId: number, teamId: number): Promise<void> {
return new Promise((resolve, reject) => {
this.db.run(
`DELETE FROM TournamentTeams WHERE tournamentId = ? AND teamId = ?`,
[tournamentId, teamId],
(err: Error | null) => {
if (err) return reject(err);
resolve();
}
);
});
}
}

View File

@@ -1,4 +1,5 @@
import {Tournament} from '../models/tournament';
import {Team} from '../models/team';
import fs from 'fs';
import path from 'path';
import {Database, RunResult} from "sqlite3";
@@ -26,27 +27,83 @@ export class TournamentService {
getAllTournaments(): Promise<Tournament[]> {
return new Promise<Tournament[]>((resolve, reject) => {
this.db.all(`SELECT *
FROM Tournaments`, (err: RunResult, rows: Tournament[]) => {
if (!err) {
resolve(rows);
this.db.all(
`SELECT t.*, tm.id as teamId, tm.name as teamName, tm.tag as teamTag,
tm.description as teamDescription, tm.createdAt as teamCreatedAt
FROM Tournaments t
LEFT JOIN TournamentTeams tt ON t.id = tt.tournamentId
LEFT JOIN Teams tm ON tt.teamId = tm.id`,
(err: Error | null, rows: any[]) => {
if (err) return reject(err);
const tournamentsMap = new Map<number, Tournament>();
for (const row of rows) {
if (!tournamentsMap.has(row.id)) {
tournamentsMap.set(row.id, {
id: row.id,
name: row.name,
description: row.description,
maxTeamAmount: row.maxTeamAmount,
currentTeamAmount: row.currentTeamAmount,
registrationStartDate: row.registrationStartDate,
registrationEndDate: row.registrationEndDate,
teams: [],
});
}
if (row.teamId) {
tournamentsMap.get(row.id)!.teams!.push({
id: row.teamId,
name: row.teamName,
tag: row.teamTag,
description: row.teamDescription,
createdAt: row.teamCreatedAt,
} as Team);
}
}
resolve(Array.from(tournamentsMap.values()));
}
reject(err);
});
);
});
}
getTournamentById(id: number): Promise<Tournament> {
return new Promise<Tournament>((resolve, reject) => {
this.db.get(`Select *
From Tournaments
WHERE id = ${id}`, (err: RunResult, tournament: Tournament) => {
if (!err) {
getTournamentById(id: number): Promise<Tournament | undefined> {
return new Promise<Tournament | undefined>((resolve, reject) => {
this.db.all(
`SELECT t.*, tm.id as teamId, tm.name as teamName, tm.tag as teamTag,
tm.description as teamDescription, tm.createdAt as teamCreatedAt
FROM Tournaments t
LEFT JOIN TournamentTeams tt ON t.id = tt.tournamentId
LEFT JOIN Teams tm ON tt.teamId = tm.id
WHERE t.id = ?`,
[id],
(err: Error | null, rows: any[]) => {
if (err) return reject(err);
if (!rows || rows.length === 0) return resolve(undefined);
const first = rows[0];
const tournament: Tournament = {
id: first.id,
name: first.name,
description: first.description,
maxTeamAmount: first.maxTeamAmount,
currentTeamAmount: first.currentTeamAmount,
registrationStartDate: first.registrationStartDate,
registrationEndDate: first.registrationEndDate,
teams: [],
};
for (const row of rows) {
if (row.teamId) {
tournament.teams!.push({
id: row.teamId,
name: row.teamName,
tag: row.teamTag,
description: row.teamDescription,
createdAt: row.teamCreatedAt,
} as Team);
}
}
resolve(tournament);
}
reject(err);
});
})
);
});
}
addTournament(tournament: Tournament): Promise<void> {