You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
5.9 KiB
223 lines
5.9 KiB
|
|
const express = require('express');
|
|
const bodyParser = require('body-parser');
|
|
const jwt = require('jsonwebtoken');
|
|
const cors = require('cors');
|
|
|
|
const { Document, Schema, connect } = require('camo');
|
|
|
|
// Define the Racers schema
|
|
class Racer extends Document {
|
|
constructor() {
|
|
super();
|
|
|
|
this.name = String;
|
|
this.gameHandle = String;
|
|
}
|
|
}
|
|
|
|
// Define the Seasons schema
|
|
class Season extends Document {
|
|
constructor() {
|
|
super();
|
|
|
|
this.title = String;
|
|
this.subTitle = String;
|
|
this.startDate = String;
|
|
}
|
|
}
|
|
|
|
// Define the Races schema
|
|
class Race extends Document {
|
|
constructor() {
|
|
super();
|
|
|
|
this.weekNumber = Number;
|
|
this.startDate = Date;
|
|
this.endDate = Date;
|
|
this.mapName = String;
|
|
this.mapLink = String;
|
|
this.season = Season;
|
|
}
|
|
}
|
|
|
|
// Define the RaceResults schema
|
|
class RaceResult extends Document {
|
|
constructor() {
|
|
super();
|
|
|
|
this.race = Race;
|
|
this.racer = Racer;
|
|
this.timeInSeconds = Number;
|
|
this.replayPath = String;
|
|
}
|
|
}
|
|
|
|
connect('nedb://./nedb-database');
|
|
|
|
const fs = require('fs');
|
|
const app = express();
|
|
const upload = require('./backend/routes/upload-replay');
|
|
|
|
const AdvancableBuffer = require('./backend/utilities/AdvancableBuffer.js');
|
|
const gbxHeader = require('./backend/trackmania-replays/gbx-header.js');
|
|
const gbxReplay = require('./backend/trackmania-replays/gbx-replay');
|
|
|
|
// handling CORS
|
|
app.use(cors());
|
|
app.use(bodyParser.json());
|
|
|
|
//const RSA_PRIVATE_KEY = fs.readFileSync('./private.key');
|
|
const RSA_PRIVATE_KEY = "Secret_KeY";
|
|
const RSA_PUBLIC_KEY = fs.readFileSync('./public.key');
|
|
|
|
const users = [
|
|
{ id: 1, username: 'user1', password: 'password1' },
|
|
{ id: 2, username: 'user2', password: 'password2' }
|
|
];
|
|
|
|
function verifyToken(req, res, next) {
|
|
const token = req.headers['authorization'];
|
|
console.log(token);
|
|
|
|
if (!token || !token.startsWith('Bearer ')) {
|
|
return res.status(401).json({ message: 'Unauthorized' });
|
|
}
|
|
|
|
const tokenWithoutBearer = token.slice(7); // Remove 'Bearer ' prefix
|
|
jwt.verify(tokenWithoutBearer, RSA_PRIVATE_KEY, (err, decoded) => {
|
|
if (err) {
|
|
console.error(err);
|
|
return res.status(401).json({ message: 'Invalid token' });
|
|
}
|
|
req.user = decoded.user;
|
|
next();
|
|
});
|
|
}
|
|
|
|
app.post('/api/login', (req, res) => {
|
|
const { username, password } = req.body;
|
|
|
|
// Check if the user exists and the password is correct
|
|
const user = users.find(u => u.username === username && u.password === password);
|
|
|
|
if (!user) {
|
|
return res.status(401).json({ message: 'Invalid username or password' });
|
|
}
|
|
|
|
// Generate and return a JWT token
|
|
const token = jwt.sign({ userId: user.id }, RSA_PRIVATE_KEY, { expiresIn: '1h', algorithm: 'HS256' });
|
|
console.log(token);
|
|
res.json({ token });
|
|
});
|
|
|
|
app.get('/api/seasons', async (req, res) => {
|
|
const seasons = await Season.find();
|
|
res.json({seasons: seasons});
|
|
});
|
|
|
|
function remapRaceInfo(raceRecord) {
|
|
modableRaceObject = {
|
|
weekNumber: raceRecord.weekNumber,
|
|
startDate: raceRecord.startDate,
|
|
endDate: raceRecord.endDate,
|
|
mapName: raceRecord.mapName,
|
|
mapLink: raceRecord.mapLink,
|
|
season: raceRecord.season,
|
|
results: []
|
|
}
|
|
|
|
return modableRaceObject;
|
|
}
|
|
|
|
app.get('/api/seasons/:id', async (req, res) => {
|
|
const { id } = req.params;
|
|
try {
|
|
let races = []
|
|
let racersInSeason = [];
|
|
const seasonDetails = await Season.findOne({_id: id});
|
|
const seasonRaceDetails = await Race.find({season: id});
|
|
for (let i = 0; i < seasonRaceDetails.length; i++) {
|
|
let raceRecord = seasonRaceDetails[i];
|
|
let modableRace = remapRaceInfo(raceRecord);
|
|
|
|
const fastestTimesMap = new Map();
|
|
const raceResults = await RaceResult.find('racer', { 'race._id': raceRecord._id });
|
|
|
|
raceResults.forEach(result => {
|
|
const racerId = result.racer._id;
|
|
const timeInSeconds = result.timeInSeconds;
|
|
|
|
if (!fastestTimesMap.has(racerId) || timeInSeconds < fastestTimesMap.get(racerId)) {
|
|
fastestTimesMap.set(racerId, timeInSeconds);
|
|
}
|
|
});
|
|
|
|
modableRace.results = Array.from(fastestTimesMap.entries()).map(([racerId, timeInSeconds]) => ({
|
|
racerId,
|
|
timeInSeconds
|
|
}));
|
|
|
|
// This is wrong it will get only the racers the in last race it processes.
|
|
racersInSeason = Array.from(new Set(raceResults.map(result => result.racer)));
|
|
|
|
races.push(modableRace);
|
|
}
|
|
|
|
let i = 1;
|
|
let standings = []
|
|
racersInSeason.forEach((racer) => {
|
|
let entry = {}
|
|
entry._id = i;
|
|
entry.position = i;
|
|
entry.points = 100-i;
|
|
entry.user = racer;
|
|
standings.push(entry);
|
|
});
|
|
|
|
res.json({season: seasonDetails, races: races, standings: standings});
|
|
}
|
|
catch( error ) {
|
|
console.error(error)
|
|
res.status(500).send('Internal Server Error');
|
|
}
|
|
});
|
|
|
|
app.post('/api/seasons/add', verifyToken, async (req, res) => {
|
|
const { title, subTitle, startDate } = req.body;
|
|
const season = await Season.create({ title, subTitle, startDate }).save();
|
|
console.log(season);
|
|
res.json(season);
|
|
});
|
|
|
|
app.post('/api/race/add', verifyToken, async (req, res) => {
|
|
const { seasonId, startDate, endDate, mapName, mapLink, weekNumber } = req.body;
|
|
const season = await Season.findOne({_id: seasonId});
|
|
const race = await Race.create({ weekNumber, startDate, endDate, mapName, mapLink, season })
|
|
console.log(race);
|
|
race.save();
|
|
res.json(race);
|
|
});
|
|
|
|
// route for handling requests from the Angular client
|
|
app.post('/api/upload-replay', upload.single('file'), (req, res) => {
|
|
let file = req.file;
|
|
console.log(req.body);
|
|
const { seasonId } = req.body;
|
|
console.log("File uploaded: ", req.file);
|
|
fs.readFile(file.path, function(err, buffer)
|
|
{
|
|
buff = new AdvancableBuffer(buffer);
|
|
header = new gbxHeader()
|
|
header.parse(buff);
|
|
console.log(header);
|
|
replay = new gbxReplay();
|
|
replay.parse(buff);
|
|
})
|
|
|
|
res.status(200);
|
|
});
|
|
|
|
app.listen(3000, () => {
|
|
console.log('Server listening on port 3000');
|
|
});
|