Add Teams endpoint and endpoints with service
This commit is contained in:
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
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) {
|
||||
|
||||
15
backend_splatournament_manager/src/models/team.ts
Normal file
15
backend_splatournament_manager/src/models/team.ts
Normal 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;
|
||||
}
|
||||
|
||||
@@ -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[];
|
||||
}
|
||||
|
||||
149
backend_splatournament_manager/src/services/team-service.ts
Normal file
149
backend_splatournament_manager/src/services/team-service.ts
Normal 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();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
reject(err);
|
||||
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()));
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
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> {
|
||||
|
||||
36
frontend_splatournament_manager/lib/models/team.dart
Normal file
36
frontend_splatournament_manager/lib/models/team.dart
Normal file
@@ -0,0 +1,36 @@
|
||||
class Team {
|
||||
final int id;
|
||||
final String name;
|
||||
final String tag;
|
||||
final String description;
|
||||
final String createdAt;
|
||||
|
||||
Team({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.tag,
|
||||
required this.description,
|
||||
required this.createdAt,
|
||||
});
|
||||
|
||||
factory Team.fromJson(Map<String, dynamic> json) {
|
||||
return Team(
|
||||
id: json['id'] as int,
|
||||
name: json['name'] as String,
|
||||
tag: json['tag'] as String,
|
||||
description: (json['description'] as String?) ?? '',
|
||||
createdAt: (json['createdAt'] as String?) ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'name': name,
|
||||
'tag': tag,
|
||||
'description': description,
|
||||
'createdAt': createdAt,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'package:frontend_splatournament_manager/models/team.dart';
|
||||
|
||||
class Tournament {
|
||||
final int id;
|
||||
final String name;
|
||||
@@ -6,6 +8,7 @@ class Tournament {
|
||||
final int currentTeamAmount;
|
||||
final String registrationStartDate;
|
||||
final String registrationEndDate;
|
||||
final List<Team> teams;
|
||||
|
||||
Tournament({
|
||||
required this.id,
|
||||
@@ -15,6 +18,7 @@ class Tournament {
|
||||
required this.currentTeamAmount,
|
||||
required this.registrationStartDate,
|
||||
required this.registrationEndDate,
|
||||
this.teams = const [],
|
||||
});
|
||||
|
||||
factory Tournament.fromJson(dynamic json) {
|
||||
@@ -26,6 +30,9 @@ class Tournament {
|
||||
currentTeamAmount: json['currentTeamAmount'],
|
||||
registrationStartDate: json['registrationStartDate'],
|
||||
registrationEndDate: json['registrationEndDate'],
|
||||
teams: (json['teams'] as List<dynamic>? ?? [])
|
||||
.map((t) => Team.fromJson(t as Map<String, dynamic>))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user