From 163bf4c22647aa1c84abb30971de8d09640b47d5 Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 16 Nov 2023 11:27:12 +0000 Subject: [PATCH] Add api package --- package-lock.json | 90 +++++++++++++++++-- package.json | 2 + server.js | 33 +++++-- src/app/app.module.ts | 10 ++- .../new-race-dialog.component.html | 5 +- .../new-race-dialog.component.ts | 2 +- .../race-details/race-details.component.html | 13 +++ .../race-details/race-details.component.scss | 0 .../race-details.component.spec.ts | 21 +++++ .../race-details/race-details.component.ts | 12 +++ .../season-details.component.html | 22 ++--- .../season-details.component.ts | 4 +- .../weekly-standings-table.component.html | 2 +- .../weekly-standings-table.component.scss | 6 ++ src/app/models/season.ts | 7 +- src/app/services/api.service.ts | 4 +- 16 files changed, 189 insertions(+), 44 deletions(-) create mode 100644 src/app/components/race-details/race-details.component.html create mode 100644 src/app/components/race-details/race-details.component.scss create mode 100644 src/app/components/race-details/race-details.component.spec.ts create mode 100644 src/app/components/race-details/race-details.component.ts diff --git a/package-lock.json b/package-lock.json index cb4a8b9..816c518 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,7 @@ "nodemon": "^3.0.1", "rxjs": "~7.8.0", "sass-loader": "^13.3.2", + "trackmania.io": "^3.2.2", "tslib": "^2.3.0", "zone.js": "~0.13.0" }, @@ -4998,8 +4999,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/autoprefixer": { "version": "10.4.14", @@ -5034,6 +5034,29 @@ "postcss": "^8.1.0" } }, + "node_modules/axios": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/babel-loader": { "version": "9.1.3", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", @@ -5753,7 +5776,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -6462,7 +6484,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -7283,7 +7304,6 @@ "version": "1.15.3", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", - "dev": true, "funding": [ { "type": "individual", @@ -9310,6 +9330,14 @@ "yallist": "^3.0.2" } }, + "node_modules/luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", + "engines": { + "node": ">=12" + } + }, "node_modules/magic-string": { "version": "0.30.1", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz", @@ -10289,6 +10317,44 @@ "dev": true, "optional": true }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -11775,6 +11841,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -13770,6 +13841,15 @@ "node": ">=8" } }, + "node_modules/trackmania.io": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/trackmania.io/-/trackmania.io-3.2.2.tgz", + "integrity": "sha512-LIn02xsHl1Q0RCiRXBGbc4T6HnddSg0jjxygT9xVm5NDDRNbNw8j1dkBNs9FCYbGbIVm0KgCinM1kQUx0F4gxQ==", + "dependencies": { + "luxon": "^3.3.0", + "node-fetch": "2.6.7" + } + }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", diff --git a/package.json b/package.json index 9961182..4b1f7c1 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "@angular/router": "^16.2.0", "@fortawesome/fontawesome-free": "^6.4.2", "@types/jwt-decode": "^3.1.0", + "axios": "^1.6.2", "better-sqlite3": "^9.1.1", "camo": "^0.12.4", "cookie-parser": "^1.4.6", @@ -38,6 +39,7 @@ "nodemon": "^3.0.1", "rxjs": "~7.8.0", "sass-loader": "^13.3.2", + "trackmania.io": "^3.2.2", "tslib": "^2.3.0", "zone.js": "~0.13.0" }, diff --git a/server.js b/server.js index 0ba4bcf..754a97b 100644 --- a/server.js +++ b/server.js @@ -45,7 +45,7 @@ class Race extends Document { this.startDate = Date; this.endDate = Date; this.mapName = String; - this.mapLink = String; + this.mapThumbnailUrl = String; this.mapUID = String; this.season = Season; } @@ -68,6 +68,8 @@ connect('nedb://./nedb-database'); const fs = require('fs'); const app = express(); const upload = require('./backend/routes/upload-replay'); +const TMIO = require('trackmania.io'), + client = new TMIO.Client(); const AdvancableBuffer = require('./backend/utilities/AdvancableBuffer.js'); const gbxHeader = require('./backend/trackmania-replays/gbx-header.js'); @@ -132,11 +134,11 @@ function remapRaceInfo(raceRecord) { startDate: raceRecord.startDate, endDate: raceRecord.endDate, mapName: raceRecord.mapName, - mapLink: raceRecord.mapLink, + mapThumbnailUrl: raceRecord.mapThumbnailUrl, + mapUID: raceRecord.mapUID, season: raceRecord.season, entries: [] } - return modableRaceObject; } @@ -205,12 +207,25 @@ app.post('/api/seasons/add', verifyToken, async (req, res) => { }); 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); + const { seasonId, startDate, endDate, mapUID, weekNumber } = req.body; + + try{ + client.maps.get(mapUID).then(async mapInfo => { + console.log(mapInfo.name); + const season = await Season.findOne({_id: seasonId}); + const mapName = mapInfo.name; + const mapThumbnailUrl = mapInfo.thumbnail; + const race = await Race.create({ weekNumber, startDate, endDate, mapName, mapUID, mapThumbnailUrl, season }) + console.log(race); + race.save(); + res.json(race); + }); + } + catch (error) { + console.error(error) + res.status(500).send('Internal Server Error'); + } + }); app.post('/api/racer/add', verifyToken, async (req, res) => { diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 49e63b5..fc0f21e 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -32,8 +32,11 @@ 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'; +import { MatGridListModule } from '@angular/material/grid-list'; import { MdbTabsModule } from 'mdb-angular-ui-kit/tabs'; +import { MatRippleModule } from '@angular/material/core'; +import { RaceDetailsComponent } from './components/race-details/race-details.component'; @NgModule({ declarations: [ @@ -51,7 +54,8 @@ import { MdbTabsModule } from 'mdb-angular-ui-kit/tabs'; AdminComponent, NewSeasonCardComponent, NewSeasonDialogComponent, - NewRaceDialogComponent + NewRaceDialogComponent, + RaceDetailsComponent ], imports: [ BrowserModule, @@ -71,7 +75,9 @@ import { MdbTabsModule } from 'mdb-angular-ui-kit/tabs'; MatMenuModule, MatDialogModule, HttpClientModule, - MdbTabsModule + MdbTabsModule, + MatRippleModule, + MatGridListModule ], providers: [], bootstrap: [AppComponent] 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 index 71f14ea..5202208 100644 --- a/src/app/components/new-race-dialog/new-race-dialog.component.html +++ b/src/app/components/new-race-dialog/new-race-dialog.component.html @@ -1,10 +1,9 @@

New Season

-

Map Name:

-

Link:

+

Week#:

+

Trackmania UID:

Starting Date:

End Date:

-

Week#:

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 index 64684ef..5781fcf 100644 --- a/src/app/components/new-race-dialog/new-race-dialog.component.ts +++ b/src/app/components/new-race-dialog/new-race-dialog.component.ts @@ -23,7 +23,7 @@ export class NewRaceDialogComponent { onSaveClick(): void { this.apiService.addRace( - this.data.seasonId, this.data.startDate, this.data.endDate, this.data.mapName, this.data.mapLink, this.data.weekNumber + this.data.seasonId, this.data.startDate, this.data.endDate, this.data.mapUID, this.data.weekNumber ).subscribe(data => { console.log(data); }); diff --git a/src/app/components/race-details/race-details.component.html b/src/app/components/race-details/race-details.component.html new file mode 100644 index 0000000..b8efc72 --- /dev/null +++ b/src/app/components/race-details/race-details.component.html @@ -0,0 +1,13 @@ +
+ +

{{week.mapName}}

+ Palm Springs Road + Three +
+
+ +
diff --git a/src/app/components/race-details/race-details.component.scss b/src/app/components/race-details/race-details.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/components/race-details/race-details.component.spec.ts b/src/app/components/race-details/race-details.component.spec.ts new file mode 100644 index 0000000..7b5267e --- /dev/null +++ b/src/app/components/race-details/race-details.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { RaceDetailsComponent } from './race-details.component'; + +describe('RaceDetailsComponent', () => { + let component: RaceDetailsComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [RaceDetailsComponent] + }); + fixture = TestBed.createComponent(RaceDetailsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/race-details/race-details.component.ts b/src/app/components/race-details/race-details.component.ts new file mode 100644 index 0000000..ece32b9 --- /dev/null +++ b/src/app/components/race-details/race-details.component.ts @@ -0,0 +1,12 @@ +import { Component, Input } from '@angular/core'; +import { SeasonWeek } from 'src/app/models/season'; + +@Component({ + selector: 'app-race-details', + templateUrl: './race-details.component.html', + styleUrls: ['./race-details.component.scss'] +}) + +export class RaceDetailsComponent { + @Input() week?: SeasonWeek; +} diff --git a/src/app/components/season-details/season-details.component.html b/src/app/components/season-details/season-details.component.html index f33a57d..9058c63 100644 --- a/src/app/components/season-details/season-details.component.html +++ b/src/app/components/season-details/season-details.component.html @@ -2,7 +2,11 @@

{{seasonInfo.title}}

{{seasonInfo.subTitle}}

- + + + +
+
@@ -12,21 +16,7 @@ - + -
\ No newline at end of file diff --git a/src/app/components/season-details/season-details.component.ts b/src/app/components/season-details/season-details.component.ts index cfd154d..9fb7b95 100644 --- a/src/app/components/season-details/season-details.component.ts +++ b/src/app/components/season-details/season-details.component.ts @@ -19,10 +19,10 @@ export class SeasonDetailsComponent { newRaceDetails = { seasonId: '', - mapName: '', - mapImgUrl: '', + mapUID: '', startDate: '', endDate: '', + weekNumber: 0 }; constructor( diff --git a/src/app/components/weekly-standings-table/weekly-standings-table.component.html b/src/app/components/weekly-standings-table/weekly-standings-table.component.html index 4c39aed..512cf48 100644 --- a/src/app/components/weekly-standings-table/weekly-standings-table.component.html +++ b/src/app/components/weekly-standings-table/weekly-standings-table.component.html @@ -26,4 +26,4 @@ - + \ No newline at end of file diff --git a/src/app/components/weekly-standings-table/weekly-standings-table.component.scss b/src/app/components/weekly-standings-table/weekly-standings-table.component.scss index e69de29..47930a0 100644 --- a/src/app/components/weekly-standings-table/weekly-standings-table.component.scss +++ b/src/app/components/weekly-standings-table/weekly-standings-table.component.scss @@ -0,0 +1,6 @@ +.img-thumbnail { + max-width: 24rem; +} +.br{ + min-height: 4rem; +} \ No newline at end of file diff --git a/src/app/models/season.ts b/src/app/models/season.ts index 1a887be..e5f13ab 100644 --- a/src/app/models/season.ts +++ b/src/app/models/season.ts @@ -30,8 +30,9 @@ export interface SeasonWeek { weekNumber: number; seasonId: string; mapName: string; - mapImg: string; - seasonStartDate: string; - seasonEndDate: string; + mapThumbnailUrl: string; + mapUID: string; + startDate: string; + endDate: string; entries: SeasonWeekEntry[]; } \ No newline at end of file diff --git a/src/app/services/api.service.ts b/src/app/services/api.service.ts index a7115db..16591a5 100644 --- a/src/app/services/api.service.ts +++ b/src/app/services/api.service.ts @@ -52,9 +52,9 @@ export class ApiService {headers: { authorization: `Bearer ${localStorage.getItem('token')}` },}); } - addRace(seasonId: string, startDate: Date, endDate: Date, mapName: string, mapLink: string, weekNumber: Number) + addRace(seasonId: string, startDate: Date, endDate: Date, mapUID: 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 }, + return this.http.post<{title: string, subtitle: string, startDate: Date}>(this.server_route+'/api/race/add', { seasonId, startDate, endDate, mapUID, weekNumber }, {headers: { authorization: `Bearer ${localStorage.getItem('token')}` },}); } } \ No newline at end of file