diff --git a/server.js b/server.js
index 1d4f3d9..3327ca0 100644
--- a/server.js
+++ b/server.js
@@ -21,9 +21,9 @@ class Season extends Document {
constructor() {
super();
- this.name = String;
- this.subtitle = String;
- this.seasonStartDate = Date;
+ this.title = String;
+ this.subTitle = String;
+ this.seasonStartDate = String;
}
}
@@ -33,8 +33,8 @@ class Race extends Document {
super();
this.weekNumber = Number;
- this.raceStartDate = Date;
- this.raceEndDate = Date;
+ this.startDate = Date;
+ this.endDate = Date;
this.mapName = String;
this.mapLink = String;
this.season = Season;
@@ -53,7 +53,7 @@ class RaceResult extends Document {
}
}
-connect('nedb://./nedb-database.db');
+connect('nedb://./nedb-database');
const fs = require('fs');
const app = express();
@@ -70,77 +70,26 @@ app.use(bodyParser.json());
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' }
];
-const seasons = [
- { id: 1, seasonName: "Season 1", seasonTag: "Post Winter Blues", seasonCardImage: "", seasonHeaderImage: "", seasonStartDate: "", seasonEndDate: "", seasonDesc: "",},
- { id: 2, seasonName: "Season 2", seasonTag: "Post Winter Blues", seasonCardImage: "", seasonHeaderImage: "", seasonStartDate: "", seasonEndDate: "", seasonDesc: "",}
-]
-
-const season_details = {
- details: {
- id: 1,
- seasonName: "Season 1",
- seasonTag: "Post Winter Blues",
- seasonCardImage: "",
- seasonHeaderImage: "",
- seasonStartDate: "",
- seasonSendDate: "",
- seasonId: "",
- seasonDesc: "",
- },
- standings: [{
- position: 1,
- points: 4,
- user: {
- realName: "Dan H",
- gamerHandle: "Quildra",
- }
- },
- {
- position: 2,
- points: 2,
- user: {
- realName: "Dan Mc",
- gamerHandle: "Mini-Quildra",
- }
- },
- ],
- weeks:[{
- id: "1",
- map: "bob",
- mapImg: "bob.jpg",
- entries: [
- {
- position: 1,
- runTime: 4.0,
- user: {
- realName: "Dan H",
- gamerHandle: "Quildra",
- }
- }
- ]
- }]
-}
-
function verifyToken(req, res, next) {
const token = req.headers['authorization'];
+ console.log(token);
- if (!token) {
- return res.status(403).json({ message: 'Token not provided' });
+ if (!token || !token.startsWith('Bearer ')) {
+ return res.status(401).json({ message: 'Unauthorized' });
}
- jwt.verify(token, RSA_PRIVATE_KEY, (err, decoded) => {
+ const tokenWithoutBearer = token.slice(7); // Remove 'Bearer ' prefix
+ jwt.verify(tokenWithoutBearer, RSA_PRIVATE_KEY, (err, decoded) => {
if (err) {
- return res.status(401).json({ message: 'Failed to authenticate token',
- error: err});
+ console.error(err);
+ return res.status(401).json({ message: 'Invalid token' });
}
-
- req.userId = decoded.userId;
+ req.user = decoded.user;
next();
});
}
@@ -156,33 +105,99 @@ app.post('/api/login', (req, res) => {
}
// Generate and return a JWT token
- const token = jwt.sign({ userId: user.id, username: user.username }, RSA_PRIVATE_KEY, { expiresIn: '1h' });
+ const token = jwt.sign({ userId: user.id }, RSA_PRIVATE_KEY, { expiresIn: '1h', algorithm: 'HS256' });
+ console.log(token);
res.json({ token });
});
-// Protected route example
-app.get('/api/profile', verifyToken, (req, res) => {
- const user = users.find(u => u.id === req.userId);
- res.json({ username: user.username, userId: user.id });
-});
-
app.get('/api/seasons', async (req, res) => {
const seasons = await Season.find();
res.json({seasons: seasons});
});
-app.get('/api/seasons/:id', (req, res) => {
- res.json({data: season_details});
+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) => {
- console.log("New Seaosn Time");
const { name, subtitle, seasonStartDate } = req.body;
- const season = await Season.create({ name, subtitle, seasonStartDate });
+ const season = await Season.create({ name, subtitle, seasonStartDate }).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;
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 89ae213..30da9c6 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -31,6 +31,7 @@ import { NewSeasonDialogComponent } from './components/new-season-dialog/new-sea
import { MatMenuModule } from '@angular/material/menu';
import { FormsModule } from '@angular/forms';
import { MatDialogModule } from '@angular/material/dialog';
+import { NewRaceDialogComponent } from './components/new-race-dialog/new-race-dialog.component';
@NgModule({
declarations: [
@@ -47,7 +48,8 @@ import { MatDialogModule } from '@angular/material/dialog';
LoginComponent,
AdminComponent,
NewSeasonCardComponent,
- NewSeasonDialogComponent
+ NewSeasonDialogComponent,
+ NewRaceDialogComponent
],
imports: [
BrowserModule,
diff --git a/src/app/components/login/login.component.ts b/src/app/components/login/login.component.ts
index c6ae592..6246cf9 100644
--- a/src/app/components/login/login.component.ts
+++ b/src/app/components/login/login.component.ts
@@ -23,7 +23,7 @@ export class LoginComponent {
(response) => {
if (response.token) {
localStorage.setItem('token', response.token);
- this.router.navigate(['/profile']);
+ this.router.navigate(['/']);
}
},
(error) => console.error(error)
diff --git a/src/app/components/new-race-dialog/new-race-dialog.component.html b/src/app/components/new-race-dialog/new-race-dialog.component.html
new file mode 100644
index 0000000..71f14ea
--- /dev/null
+++ b/src/app/components/new-race-dialog/new-race-dialog.component.html
@@ -0,0 +1,12 @@
+
New Season
+
+
+
+
+
diff --git a/src/app/components/new-race-dialog/new-race-dialog.component.less b/src/app/components/new-race-dialog/new-race-dialog.component.less
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/components/new-race-dialog/new-race-dialog.component.spec.ts b/src/app/components/new-race-dialog/new-race-dialog.component.spec.ts
new file mode 100644
index 0000000..882081d
--- /dev/null
+++ b/src/app/components/new-race-dialog/new-race-dialog.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { NewRaceDialogComponent } from './new-race-dialog.component';
+
+describe('NewRaceDialogComponent', () => {
+ let component: NewRaceDialogComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ declarations: [NewRaceDialogComponent]
+ });
+ fixture = TestBed.createComponent(NewRaceDialogComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/components/new-race-dialog/new-race-dialog.component.ts b/src/app/components/new-race-dialog/new-race-dialog.component.ts
new file mode 100644
index 0000000..5c39b36
--- /dev/null
+++ b/src/app/components/new-race-dialog/new-race-dialog.component.ts
@@ -0,0 +1,32 @@
+import { Component, OnInit, Inject } from '@angular/core';
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { ApiService } from 'src/app/services/api.service';
+
+@Component({
+ selector: 'app-new-race-dialog',
+ templateUrl: './new-race-dialog.component.html',
+ styleUrls: ['./new-race-dialog.component.less']
+})
+export class NewRaceDialogComponent {
+ constructor(
+ public dialogRef: MatDialogRef,
+ @Inject(MAT_DIALOG_DATA) public data: any,
+ private apiService: ApiService
+ ) { }
+
+ ngOnInit(): void {
+ }
+
+ onCancelClick(): void {
+ this.dialogRef.close();
+ }
+
+ onSaveClick(): void {
+ this.apiService.addRace(
+ this.data.seasonId, this.data.startDate, this.data.endDate, this.data.mapName, this.data.mapLink, this.data.weekNumber
+ ).subscribe(data => {
+ console.log(data);
+ });
+ this.dialogRef.close(this.data);
+ }
+}
diff --git a/src/app/components/season-card/season-card.component.html b/src/app/components/season-card/season-card.component.html
index 2e4d82d..01dd419 100644
--- a/src/app/components/season-card/season-card.component.html
+++ b/src/app/components/season-card/season-card.component.html
@@ -1,8 +1,8 @@
-
+
- {{season?.seasonName}}
- {{season?.seasonTag}}
+ {{season?.title}}
+ {{season?.subTitle}}
diff --git a/src/app/components/season-details/season-details.component.html b/src/app/components/season-details/season-details.component.html
index 4c37c96..12b71f9 100644
--- a/src/app/components/season-details/season-details.component.html
+++ b/src/app/components/season-details/season-details.component.html
@@ -1,12 +1,17 @@
-
-
{{seasonInfo.seasonName}}
-
{{seasonInfo.seasonTag}}
+
+
{{seasonInfo.title}}
+
{{seasonInfo.subTitle}}
+
+
+
-
-
-
+
diff --git a/src/app/components/season-details/season-details.component.ts b/src/app/components/season-details/season-details.component.ts
index c156bc2..126910d 100644
--- a/src/app/components/season-details/season-details.component.ts
+++ b/src/app/components/season-details/season-details.component.ts
@@ -1,7 +1,10 @@
import { Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
+import { MatDialog } from '@angular/material/dialog';
import { ApiService } from '../../services/api.service';
import { Season, SeasonWeek, SeasonStandingsEntry } from '../../models/season';
+import { AuthService } from 'src/app/services/auth-service';
+import { NewRaceDialogComponent } from '../new-race-dialog/new-race-dialog.component';
@Component({
selector: 'app-season-details',
@@ -13,23 +16,58 @@ export class SeasonDetailsComponent {
seasonStandings?: SeasonStandingsEntry[];
weeks?: SeasonWeek[];
+ newRaceDetails = {
+ seasonId: '',
+ mapName: '',
+ mapImgUrl: '',
+ startDate: '',
+ endDate: '',
+ };
+
constructor(
private route: ActivatedRoute,
private apiService: ApiService,
- //private location: Location
+ private authService: AuthService,
+ public dialog: MatDialog
)
{
}
+ isAuthenticated: boolean = false;
+
ngOnInit(): void {
- const id = Number(this.route.snapshot.paramMap.get('id'));
+ this.isAuthenticated = this.authService.isAuthenticated();
+ const id = String(this.route.snapshot.paramMap.get('id'));
this.apiService.getSeasonDetails(id).subscribe(data => {
- this.seasonInfo = (data as any).data.details;
- this.weeks = (data as any).data.weeks;
- this.seasonStandings = (data as any).data.standings;
+ this.seasonInfo = (data as any).season;
+ this.weeks = (data as any).races;
+ this.seasonStandings = (data as any).standings;
+ console.log(data);
+ console.log(this.seasonInfo);
console.log(this.seasonStandings);
console.log(this.weeks);
});
}
+ openNewRaceDialog(): void {
+ if(this.seasonInfo)
+ {
+ this.newRaceDetails.seasonId = this.seasonInfo._id;
+ }
+ const dialogRef = this.dialog.open(NewRaceDialogComponent, {
+ width: '400px',
+ data: { ...this.newRaceDetails }
+ });
+
+ dialogRef.afterClosed().subscribe(result => {
+ if (result) {
+ console.log('Follow details saved:', result);
+ // You can update your data or perform other actions here
+ } else {
+ console.log('Dialog canceled');
+ }
+ });
+ }
+
}
+
diff --git a/src/app/components/seasons/seasons.component.ts b/src/app/components/seasons/seasons.component.ts
index 9033630..c5ede3c 100644
--- a/src/app/components/seasons/seasons.component.ts
+++ b/src/app/components/seasons/seasons.component.ts
@@ -23,6 +23,7 @@ export class SeasonsComponent
ngOnInit() {
this.apiService.getSeasons().subscribe(data => {
this.seasons = (data as any).seasons;
+ console.log(this.seasons);
});
this.isAuthenticated = this.authService.isAuthenticated();
}
diff --git a/src/app/models/season.ts b/src/app/models/season.ts
index 30a216e..14dcfa7 100644
--- a/src/app/models/season.ts
+++ b/src/app/models/season.ts
@@ -1,31 +1,32 @@
export interface Season {
- id: string,
- seasonName: string;
- seasonTag: string;
- seasonCardImage: string;
- seasonHeaderImage: string;
+ _id: string,
+ title: string;
+ subTitle: string;
+ startDate: string;
}
export interface BridgeUser {
- id: string;
+ _id: string;
realName: string;
gameHandle: string;
}
export interface SeasonStandingsEntry {
+ _id: string;
position: string;
points: number;
user: BridgeUser;
}
export interface SeasonWeekEntry {
+ _id: string;
position: string;
runTime: string;
user: BridgeUser;
}
export interface SeasonWeek {
- id: string;
+ _id: string;
seasonId: string;
mapName: string;
mapImg: string;
diff --git a/src/app/services/api.service.ts b/src/app/services/api.service.ts
index aabc54f..f235973 100644
--- a/src/app/services/api.service.ts
+++ b/src/app/services/api.service.ts
@@ -30,7 +30,7 @@ export class ApiService
this.server_route+'/api/seasons');
}
- getSeasonDetails(id: number)
+ getSeasonDetails(id: string)
{
return this.http.get(
this.server_route+'/api/seasons/'+id);
@@ -38,8 +38,13 @@ export class ApiService
addSeason(title: string, subtitle: string, startDate: Date)
{
- console.log("hullo");
return this.http.post<{title: string, subtitle: string, startDate: Date}>(this.server_route+'/api/seasons/add', { title, subtitle, startDate },
{headers: { authorization: `Bearer ${localStorage.getItem('token')}` },});
}
+
+ addRace(seasonId: string, startDate: Date, endDate: Date, mapName: string, mapLink: string, weekNumber: Number)
+ {
+ return this.http.post<{title: string, subtitle: string, startDate: Date}>(this.server_route+'/api/race/add', { seasonId, startDate, endDate, mapName, mapLink, weekNumber },
+ {headers: { authorization: `Bearer ${localStorage.getItem('token')}` },});
+ }
}
\ No newline at end of file