Browse Source

Add api package

old-project-state
Dan 2 years ago
parent
commit
163bf4c226
  1. 90
      package-lock.json
  2. 2
      package.json
  3. 33
      server.js
  4. 10
      src/app/app.module.ts
  5. 5
      src/app/components/new-race-dialog/new-race-dialog.component.html
  6. 2
      src/app/components/new-race-dialog/new-race-dialog.component.ts
  7. 13
      src/app/components/race-details/race-details.component.html
  8. 0
      src/app/components/race-details/race-details.component.scss
  9. 21
      src/app/components/race-details/race-details.component.spec.ts
  10. 12
      src/app/components/race-details/race-details.component.ts
  11. 22
      src/app/components/season-details/season-details.component.html
  12. 4
      src/app/components/season-details/season-details.component.ts
  13. 2
      src/app/components/weekly-standings-table/weekly-standings-table.component.html
  14. 6
      src/app/components/weekly-standings-table/weekly-standings-table.component.scss
  15. 7
      src/app/models/season.ts
  16. 4
      src/app/services/api.service.ts

90
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",

2
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"
},

33
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) => {

10
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]

5
src/app/components/new-race-dialog/new-race-dialog.component.html

@ -1,10 +1,9 @@
<h1 mat-dialog-title>New Season</h1>
<div mat-dialog-content>
<p>Map Name: <input [(ngModel)]="data.mapName" /></p>
<p>Link: <input [(ngModel)]="data.mapLink" /></p>
<p>Week#: <input type="number" [(ngModel)]="data.weekNumber" /></p>
<p>Trackmania UID: <input [(ngModel)]="data.mapUID" /></p>
<p>Starting Date: <input type="date" [(ngModel)]="data.startDate" /></p>
<p>End Date: <input type="date" [(ngModel)]="data.endDate" /></p>
<p>Week#: <input type="number" [(ngModel)]="data.weekNumber" /></p>
</div>
<div mat-dialog-actions>
<button mat-button (click)="onCancelClick()">Cancel</button>

2
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);
});

13
src/app/components/race-details/race-details.component.html

@ -0,0 +1,13 @@
<div *ngIf="week">
<mat-grid-list cols="4" rowHeight="100px">
<mat-grid-tile [colspan]="3" [rowspan]="1"><h1>{{week.mapName}}</h1></mat-grid-tile>
<mat-grid-tile [colspan]="1" [rowspan]="2"><img
src={{week.mapThumbnailUrl}}
class="img-thumbnail shadow-2-strong"
alt="Palm Springs Road"
/></mat-grid-tile>
<mat-grid-tile [colspan]="3" [rowspan]="1">Three</mat-grid-tile>
</mat-grid-list>
<br/>
<app-weekly-standings-table [dataSource]="week.entries"></app-weekly-standings-table>
</div>

0
src/app/components/race-details/race-details.component.scss

21
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<RaceDetailsComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [RaceDetailsComponent]
});
fixture = TestBed.createComponent(RaceDetailsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

12
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;
}

22
src/app/components/season-details/season-details.component.html

@ -2,7 +2,11 @@
<h1>{{seasonInfo.title}}</h1>
<h3>{{seasonInfo.subTitle}}</h3>
<div *ngIf="isAuthenticated">
<button (click)="openNewRaceDialog()">New Race</button>
<button type="button" class="btn btn-outline-primary" mdbRipple rippleColor="dark" (click)="openNewRaceDialog()">New Race</button>
<button type="button" class="btn btn-outline-secondary" mdbRipple rippleColor="dark">New Racer</button>
<button type="button" class="btn btn-outline-success" mdbRipple rippleColor="dark">Edit Season</button>
<br/>
<mat-divider></mat-divider>
</div>
<button mat-raised-button class="full-width-button" color="primary" (click)="openUploadReplayDialog(seasonInfo._id)">Upload Replay</button>
<mat-divider></mat-divider>
@ -12,21 +16,7 @@
<app-season-standings-table [dataSource]="seasonStandings"></app-season-standings-table>
</mdb-tab>
<mdb-tab *ngFor="let week of weeks" title="{{'Week #' +week.weekNumber}}">
<app-weekly-standings-table [dataSource]="week.entries"></app-weekly-standings-table>
<app-race-details [week]="week"></app-race-details>
</mdb-tab>
</mdb-tabs>
<!--
<mat-tab-group>
<div *ngIf="seasonStandings">
<mat-tab label="Standings">
<app-season-standings-table [dataSource]="seasonStandings"></app-season-standings-table>
</mat-tab>
</div>
<div *ngFor="let week of weeks">
<mat-tab label="Second">
<app-weekly-standings-table [dataSource]="week.entries"></app-weekly-standings-table>
</mat-tab>
</div>
</mat-tab-group>
-->
</div>

4
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(

2
src/app/components/weekly-standings-table/weekly-standings-table.component.html

@ -26,4 +26,4 @@
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</div>

6
src/app/components/weekly-standings-table/weekly-standings-table.component.scss

@ -0,0 +1,6 @@
.img-thumbnail {
max-width: 24rem;
}
.br{
min-height: 4rem;
}

7
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[];
}

4
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')}` },});
}
}
Loading…
Cancel
Save