Migrate to single DB for both users and tournaments and introduce userService
This commit is contained in:
@@ -3,10 +3,20 @@ import bodyParser from 'body-parser';
|
||||
import 'dotenv/config';
|
||||
|
||||
import {TournamentService} from './services/tournament-service';
|
||||
import {UserService} from './services/user-service';
|
||||
import router from './middlewares/logger';
|
||||
import {Database} from 'sqlite3';
|
||||
import fs from "fs";
|
||||
|
||||
|
||||
const tournamentService = new TournamentService();
|
||||
const dbFilename = 'tournaments.sqlite';
|
||||
|
||||
if (fs.existsSync(dbFilename)){
|
||||
fs.unlinkSync(dbFilename);
|
||||
}
|
||||
const db = new Database(dbFilename);
|
||||
const tournamentService = new TournamentService(db);
|
||||
const userService = new UserService(db);
|
||||
const port = process.env.PORT || 3000;
|
||||
const app = express();
|
||||
|
||||
@@ -63,6 +73,36 @@ app.delete('/tournaments', async (req: Request, res: Response) => {
|
||||
res.status(200).send({message: 'Tournament deleted successfully'});
|
||||
});
|
||||
|
||||
// Auth routes
|
||||
app.post('/register', async (req: Request, res: Response) => {
|
||||
const { username, password } = req.body;
|
||||
if (!username || !password) {
|
||||
return res.status(400).send({ error: 'Username and password are required' });
|
||||
}
|
||||
try {
|
||||
const user = await userService.register(username, password);
|
||||
res.status(201).send(user);
|
||||
} catch (err: any) {
|
||||
if (err.message?.includes('UNIQUE constraint failed')) {
|
||||
return res.status(409).send({ error: 'Username already exists' });
|
||||
}
|
||||
res.status(500).send({ error: 'Registration failed' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/login', async (req: Request, res: Response) => {
|
||||
const { username, password } = req.body;
|
||||
if (!username || !password) {
|
||||
return res.status(400).send({ error: 'Username and password are required' });
|
||||
}
|
||||
try {
|
||||
const user = await userService.login(username, password);
|
||||
res.status(200).send(user);
|
||||
} catch (err: any) {
|
||||
res.status(401).send({ error: err.message || 'Login failed' });
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`server started on port ${port}`);
|
||||
});
|
||||
|
||||
6
backend_splatournament_manager/src/models/user.ts
Normal file
6
backend_splatournament_manager/src/models/user.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export interface User {
|
||||
id: number;
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
@@ -5,14 +5,10 @@ import {Database, RunResult} from "sqlite3";
|
||||
|
||||
export class TournamentService {
|
||||
private csvFilename = 'csv/tournaments.csv';
|
||||
private dbFilename = 'tournaments.sqlite';
|
||||
private db: Database;
|
||||
|
||||
constructor() {
|
||||
if (fs.existsSync(this.dbFilename)) {
|
||||
fs.unlinkSync(this.dbFilename);
|
||||
}
|
||||
this.db = new Database(this.dbFilename);
|
||||
constructor(db: Database) {
|
||||
this.db = db;
|
||||
this.db.serialize(() => {
|
||||
this.db.run(`CREATE TABLE IF NOT EXISTS Tournaments
|
||||
(
|
||||
|
||||
65
backend_splatournament_manager/src/services/user-service.ts
Normal file
65
backend_splatournament_manager/src/services/user-service.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { User } from '../models/user';
|
||||
import { Database } from 'sqlite3';
|
||||
import * as argon2 from 'argon2';
|
||||
|
||||
export class UserService {
|
||||
private db: Database;
|
||||
|
||||
constructor(db: Database) {
|
||||
this.db = db;
|
||||
this.db.run(`CREATE TABLE IF NOT EXISTS Users
|
||||
(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
username TEXT UNIQUE NOT NULL,
|
||||
password TEXT NOT NULL
|
||||
)`);
|
||||
}
|
||||
|
||||
register(username: string, password: string): Promise<{ id: number; username: string }> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const hash = await argon2.hash(password);
|
||||
this.db.run(
|
||||
'INSERT INTO Users (username, password) VALUES (?, ?)',
|
||||
[username, hash],
|
||||
function (err: Error | null) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
resolve({ id: this.lastID, username });
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
login(username: string, password: string): Promise<{ id: number; username: string }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.db.get(
|
||||
'SELECT * FROM Users WHERE username = ?',
|
||||
[username],
|
||||
async (err: Error | null, user: User | undefined) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
if (!user) {
|
||||
return reject(new Error('User not found'));
|
||||
}
|
||||
try {
|
||||
const valid = await argon2.verify(user.password, password);
|
||||
if (!valid) {
|
||||
return reject(new Error('Invalid password'));
|
||||
}
|
||||
resolve({ id: user.id, username: user.username });
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user