56 changed files with 1081 additions and 88 deletions
@ -0,0 +1,6 @@ |
|||
import {Request, Response} from "express"; |
|||
import * as express from 'express'; |
|||
const bodyParser = require('body-parser'); |
|||
const cookieParser = require('cookie-parser'); |
|||
import * as jwt from 'jsonwebtoken'; |
|||
import * as fs from "fs"; |
|||
@ -0,0 +1,78 @@ |
|||
class gbxHeader { |
|||
|
|||
has_magic = true |
|||
version = -1 |
|||
format = -1 |
|||
compressionofRefTable = -1 |
|||
compressionOfrefBofy = -1 |
|||
compressionTextFlag = '' |
|||
id = -1 |
|||
userData = [] |
|||
numNodes = 0 |
|||
|
|||
is_vaild = false |
|||
|
|||
parse(buff) |
|||
{ |
|||
let header_magic = buff.readString(3); |
|||
|
|||
if (header_magic != 'GBX') |
|||
{ |
|||
console.log("Header Magic Mismatch: " + header_magic); |
|||
return |
|||
} |
|||
this.has_magic = true |
|||
|
|||
this.version = buff.readUInt16(); |
|||
console.log(this.version) |
|||
|
|||
if (this.version < 5 || this.version >7 ) |
|||
{ |
|||
console.log("Unsupported version") |
|||
return; |
|||
} |
|||
|
|||
this.format = buff.readInt8(); |
|||
if (this.format != 66) |
|||
{ |
|||
console.log("Unsupported format") |
|||
return; |
|||
} |
|||
|
|||
this.compressionofRefTable = buff.readInt8(); |
|||
|
|||
if (this.compressionofRefTable != 67 && this.compressionofRefTable != 85) |
|||
{ |
|||
console.log("Unsupported compression format, Ref") |
|||
return; |
|||
} |
|||
|
|||
this.compressionofRefBody = buff.readInt8(); |
|||
if (this.compressionofRefBody != 67 && this.compressionofRefBody != 85) |
|||
{ |
|||
console.log("Unsupported compression format, Body") |
|||
return; |
|||
} |
|||
|
|||
this.compressionTextFlag = ''; |
|||
if (this.version >= 4) |
|||
{ |
|||
this.compressionTextFlag = buff.readString(1); |
|||
} |
|||
|
|||
this.id = buff.readUInt32(); |
|||
console.log(id) |
|||
|
|||
if (this.version >=6) |
|||
{ |
|||
this.userData = buff.readBytes(); |
|||
} |
|||
|
|||
this.numNodes = buff.readUInt32(); |
|||
|
|||
this.is_vaild = true |
|||
} |
|||
} |
|||
|
|||
|
|||
module.exports = gbxHeader; |
|||
@ -0,0 +1,15 @@ |
|||
-----BEGIN RSA PRIVATE KEY----- |
|||
MIICWgIBAAKBgGB4qg68oSTGrUmTt2sq7TLMBtxlGYeNZCv1Zhjlhtwp9wGjbWVA |
|||
J7pa16o0Pcydo18ApFWCIOnXDyvPwYLoyc/oDA2fVnjdz2MeHNkjD1uIToig8AcP |
|||
UaBM8R5QnByRXPyaud8VfVybcCjXJoMzH2dKWsm/O/PmtqV1/dIJyC+ZAgMBAAEC |
|||
gYAhDLWV3uGF69qp/kU0HbytTmB7WNdqLPJIbQXRObD99BJ/KTHtIhF6Mmz4DnWt |
|||
h8PUZC/oa3BDLD4yUDaHVqDsf4jxOCOeNBuCh24ZCiYXq9gkzX5YFwz/6Leoiccr |
|||
WRbfjvaz/Mgi9PfkTijgnbExsEHRhrb/IvIdcKbXQlTqQQJBAL2mgRzvCCQ2oWuI |
|||
qgrSEk2CyYJhmOKHbfDazbLvO0b3qtnof9a/T7C28+/8oXfRW2ZJ8eahHkA/WOiw |
|||
271Cdx0CQQCCONgR+EQT1hHjpXbVeoRz8gEv8WHvndTjdTYxOMs2k48TV+IZ+wgp |
|||
OFkvExdt11W235yA5NX+M8tP0To9+KWtAkBMrf/SNQtzqOsHUZB/I4Tm9hSHtPJd |
|||
1SgslCtLR9MN1KGtzYWyzFNqPe7Pf7PBgFKWPxuhhk925qYKH0gZc8A5AkBOMkg9 |
|||
cjGfH7saUi/rvWhwH3BrE63Vr5c5BxeFsy8EFNOjr/BL3Zxm9DlJtVMqWFZWPCzE |
|||
kaWWwg9iXKd2syr5AkBi3Uwd4MMG6AC8nn9mlXVizleN303TNFBc6yGqiPjEJNdL |
|||
UcLxu/86PnH8gRA0Iy4b/HPJAKXqHQbtOQTROvWC |
|||
-----END RSA PRIVATE KEY----- |
|||
@ -0,0 +1,6 @@ |
|||
-----BEGIN PUBLIC KEY----- |
|||
MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgGB4qg68oSTGrUmTt2sq7TLMBtxl |
|||
GYeNZCv1Zhjlhtwp9wGjbWVAJ7pa16o0Pcydo18ApFWCIOnXDyvPwYLoyc/oDA2f |
|||
Vnjdz2MeHNkjD1uIToig8AcPUaBM8R5QnByRXPyaud8VfVybcCjXJoMzH2dKWsm/ |
|||
O/PmtqV1/dIJyC+ZAgMBAAE= |
|||
-----END PUBLIC KEY----- |
|||
@ -1,3 +1,5 @@ |
|||
<h1>{{title}}</h1> |
|||
<app-replay-upload></app-replay-upload> |
|||
<app-top-bar></app-top-bar> |
|||
|
|||
<div class="main"> |
|||
<router-outlet></router-outlet> |
|||
</div> |
|||
|
|||
@ -0,0 +1,4 @@ |
|||
.main { |
|||
margin: 1rem auto; |
|||
width: 80%; |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
<form [formGroup]="form"> |
|||
<fieldset> |
|||
<legend>Login</legend> |
|||
<div class="form-field"> |
|||
<label>Email:</label> |
|||
<input name="email" formControlName="email"> |
|||
</div> |
|||
<div class="form-field"> |
|||
<label>Password:</label> |
|||
<input name="password" formControlName="password" |
|||
type="password"> |
|||
</div> |
|||
</fieldset> |
|||
<div class="form-buttons"> |
|||
<button class="button button-primary" |
|||
(click)="login()">Login</button> |
|||
</div> |
|||
</form> |
|||
@ -0,0 +1,21 @@ |
|||
import { ComponentFixture, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { LoginComponent } from './login.component'; |
|||
|
|||
describe('LoginComponent', () => { |
|||
let component: LoginComponent; |
|||
let fixture: ComponentFixture<LoginComponent>; |
|||
|
|||
beforeEach(() => { |
|||
TestBed.configureTestingModule({ |
|||
declarations: [LoginComponent] |
|||
}); |
|||
fixture = TestBed.createComponent(LoginComponent); |
|||
component = fixture.componentInstance; |
|||
fixture.detectChanges(); |
|||
}); |
|||
|
|||
it('should create', () => { |
|||
expect(component).toBeTruthy(); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,38 @@ |
|||
import { Component } from '@angular/core'; |
|||
import { FormGroup, FormBuilder, Validators } from '@angular/forms'; |
|||
import { Router } from '@angular/router'; |
|||
import { AuthService } from '../../services/auth-service'; |
|||
|
|||
@Component({ |
|||
selector: 'app-login', |
|||
templateUrl: './login.component.html', |
|||
styleUrls: ['./login.component.less'] |
|||
}) |
|||
export class LoginComponent { |
|||
form:FormGroup; |
|||
|
|||
constructor(private fb:FormBuilder, |
|||
private authService: AuthService, |
|||
private router: Router) |
|||
{ |
|||
|
|||
this.form = this.fb.group({ |
|||
email: ['',Validators.required], |
|||
password: ['',Validators.required] |
|||
}); |
|||
} |
|||
|
|||
login() { |
|||
const val = this.form.value; |
|||
|
|||
if (val.email && val.password) { |
|||
this.authService.login(val.email, val.password) |
|||
.subscribe( |
|||
() => { |
|||
console.log("User is logged in"); |
|||
this.router.navigateByUrl('/'); |
|||
} |
|||
); |
|||
} |
|||
} |
|||
} |
|||
@ -1,6 +1,6 @@ |
|||
import { HttpClient } from '@angular/common/http'; |
|||
import { Component } from '@angular/core'; |
|||
import { ApiService } from '../api.service'; |
|||
import { ApiService } from '../../services/api.service'; |
|||
|
|||
@Component({ |
|||
selector: 'app-replay-upload', |
|||
@ -0,0 +1,15 @@ |
|||
<mat-card class="example-card" routerLink="/seasons/{{season?.id}}"> |
|||
<mat-card-header> |
|||
<div mat-card-avatar class="example-header-image"></div> |
|||
<mat-card-title>{{season?.seasonName}}</mat-card-title> |
|||
<mat-card-subtitle>{{season?.seasonTag}}</mat-card-subtitle> |
|||
</mat-card-header> |
|||
<img mat-card-image src="https://material.angular.io/assets/img/examples/shiba2.jpg" alt="Photo of a Shiba Inu"> |
|||
<mat-card-content> |
|||
<p> |
|||
The Shiba Inu is the smallest of the six original and distinct spitz breeds of dog from Japan. |
|||
A small, agile dog that copes very well with mountainous terrain, the Shiba Inu was originally |
|||
bred for hunting. |
|||
</p> |
|||
</mat-card-content> |
|||
</mat-card> |
|||
@ -0,0 +1,8 @@ |
|||
.example-card { |
|||
max-width: 400px; |
|||
} |
|||
|
|||
.example-header-image { |
|||
background-image: url('https://material.angular.io/assets/img/examples/shiba1.jpg'); |
|||
background-size: cover; |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
import { ComponentFixture, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { SeasonCardComponent } from './season-card.component'; |
|||
|
|||
describe('SeasonCardComponent', () => { |
|||
let component: SeasonCardComponent; |
|||
let fixture: ComponentFixture<SeasonCardComponent>; |
|||
|
|||
beforeEach(() => { |
|||
TestBed.configureTestingModule({ |
|||
declarations: [SeasonCardComponent] |
|||
}); |
|||
fixture = TestBed.createComponent(SeasonCardComponent); |
|||
component = fixture.componentInstance; |
|||
fixture.detectChanges(); |
|||
}); |
|||
|
|||
it('should create', () => { |
|||
expect(component).toBeTruthy(); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,11 @@ |
|||
import { Component, Input } from '@angular/core'; |
|||
import { Season } from '../../models/season'; |
|||
|
|||
@Component({ |
|||
selector: 'app-season-card', |
|||
templateUrl: './season-card.component.html', |
|||
styleUrls: ['./season-card.component.less'] |
|||
}) |
|||
export class SeasonCardComponent { |
|||
@Input() season?: Season; |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
<div *ngIf="seasonInfo && seasonStandings"> |
|||
<h1>{{seasonInfo.seasonName}}</h1> |
|||
<h3>{{seasonInfo.seasonTag}}</h3> |
|||
<mat-divider></mat-divider> |
|||
<br/> |
|||
<mat-tab-group> |
|||
<mat-tab label="Standings"> |
|||
<app-season-standings-table [dataSource]="seasonStandings"></app-season-standings-table> |
|||
</mat-tab> |
|||
<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> |
|||
@ -0,0 +1,21 @@ |
|||
import { ComponentFixture, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { SeasonDetailsComponent } from './season-details.component'; |
|||
|
|||
describe('SeasonDetailsComponent', () => { |
|||
let component: SeasonDetailsComponent; |
|||
let fixture: ComponentFixture<SeasonDetailsComponent>; |
|||
|
|||
beforeEach(() => { |
|||
TestBed.configureTestingModule({ |
|||
declarations: [SeasonDetailsComponent] |
|||
}); |
|||
fixture = TestBed.createComponent(SeasonDetailsComponent); |
|||
component = fixture.componentInstance; |
|||
fixture.detectChanges(); |
|||
}); |
|||
|
|||
it('should create', () => { |
|||
expect(component).toBeTruthy(); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,35 @@ |
|||
import { Component } from '@angular/core'; |
|||
import { ActivatedRoute } from '@angular/router'; |
|||
import { ApiService } from '../../services/api.service'; |
|||
import { Season, SeasonWeek, SeasonStandingsEntry } from '../../models/season'; |
|||
|
|||
@Component({ |
|||
selector: 'app-season-details', |
|||
templateUrl: './season-details.component.html', |
|||
styleUrls: ['./season-details.component.less'] |
|||
}) |
|||
export class SeasonDetailsComponent { |
|||
seasonInfo?: Season; |
|||
seasonStandings?: SeasonStandingsEntry[]; |
|||
weeks?: SeasonWeek[]; |
|||
|
|||
constructor( |
|||
private route: ActivatedRoute, |
|||
private apiService: ApiService, |
|||
//private location: Location
|
|||
) |
|||
{ |
|||
} |
|||
|
|||
ngOnInit(): void { |
|||
const id = Number(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; |
|||
console.log(this.seasonStandings); |
|||
console.log(this.weeks); |
|||
}); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1 @@ |
|||
<p>season-list works!</p> |
|||
@ -0,0 +1,21 @@ |
|||
import { ComponentFixture, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { SeasonListComponent } from './season-list.component'; |
|||
|
|||
describe('SeasonListComponent', () => { |
|||
let component: SeasonListComponent; |
|||
let fixture: ComponentFixture<SeasonListComponent>; |
|||
|
|||
beforeEach(() => { |
|||
TestBed.configureTestingModule({ |
|||
declarations: [SeasonListComponent] |
|||
}); |
|||
fixture = TestBed.createComponent(SeasonListComponent); |
|||
component = fixture.componentInstance; |
|||
fixture.detectChanges(); |
|||
}); |
|||
|
|||
it('should create', () => { |
|||
expect(component).toBeTruthy(); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,10 @@ |
|||
import { Component } from '@angular/core'; |
|||
|
|||
@Component({ |
|||
selector: 'app-season-list', |
|||
templateUrl: './season-list.component.html', |
|||
styleUrls: ['./season-list.component.less'] |
|||
}) |
|||
export class SeasonListComponent { |
|||
|
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
<div *ngIf="dataSource"> |
|||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8"> |
|||
<ng-container matColumnDef="position"> |
|||
<th mat-header-cell *matHeaderCellDef> No. </th> |
|||
<td mat-cell *matCellDef="let element"> {{element.position}} </td> |
|||
</ng-container> |
|||
|
|||
<!-- Name Column --> |
|||
<ng-container matColumnDef="name"> |
|||
<th mat-header-cell *matHeaderCellDef> Name </th> |
|||
<td mat-cell *matCellDef="let element"> {{element.user.realName}} </td> |
|||
</ng-container> |
|||
|
|||
<!-- Weight Column --> |
|||
<ng-container matColumnDef="points"> |
|||
<th mat-header-cell *matHeaderCellDef> runTime </th> |
|||
<td mat-cell *matCellDef="let element"> {{element.points}} </td> |
|||
</ng-container> |
|||
|
|||
<!-- Symbol Column --> |
|||
<ng-container matColumnDef="gameHandle"> |
|||
<th mat-header-cell *matHeaderCellDef> gamerTag </th> |
|||
<td mat-cell *matCellDef="let element"> {{element.user.gamerHandle}} </td> |
|||
</ng-container> |
|||
|
|||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> |
|||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> |
|||
</table> |
|||
</div> |
|||
@ -0,0 +1,21 @@ |
|||
import { ComponentFixture, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { SeasonStandingsTableComponent } from './season-standings-table.component'; |
|||
|
|||
describe('SeasonStandingsTableComponent', () => { |
|||
let component: SeasonStandingsTableComponent; |
|||
let fixture: ComponentFixture<SeasonStandingsTableComponent>; |
|||
|
|||
beforeEach(() => { |
|||
TestBed.configureTestingModule({ |
|||
declarations: [SeasonStandingsTableComponent] |
|||
}); |
|||
fixture = TestBed.createComponent(SeasonStandingsTableComponent); |
|||
component = fixture.componentInstance; |
|||
fixture.detectChanges(); |
|||
}); |
|||
|
|||
it('should create', () => { |
|||
expect(component).toBeTruthy(); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,18 @@ |
|||
import { Component, Input } from '@angular/core'; |
|||
import { SeasonStandingsEntry } from '../../models/season'; |
|||
|
|||
@Component({ |
|||
selector: 'app-season-standings-table', |
|||
templateUrl: './season-standings-table.component.html', |
|||
styleUrls: ['./season-standings-table.component.less'] |
|||
}) |
|||
export class SeasonStandingsTableComponent { |
|||
|
|||
displayedColumns: string[] = ['position', 'name', 'gameHandle', 'points']; |
|||
@Input() dataSource?: SeasonStandingsEntry[]; |
|||
|
|||
constructor() |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,5 @@ |
|||
<div *ngIf="seasons"> |
|||
<div *ngFor="let season of seasons"> |
|||
<app-season-card [season]="season"></app-season-card> |
|||
</div> |
|||
</div> |
|||
@ -0,0 +1,21 @@ |
|||
import { ComponentFixture, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { SeasonsComponent } from './seasons.component'; |
|||
|
|||
describe('SeasonsComponent', () => { |
|||
let component: SeasonsComponent; |
|||
let fixture: ComponentFixture<SeasonsComponent>; |
|||
|
|||
beforeEach(() => { |
|||
TestBed.configureTestingModule({ |
|||
declarations: [SeasonsComponent] |
|||
}); |
|||
fixture = TestBed.createComponent(SeasonsComponent); |
|||
component = fixture.componentInstance; |
|||
fixture.detectChanges(); |
|||
}); |
|||
|
|||
it('should create', () => { |
|||
expect(component).toBeTruthy(); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,25 @@ |
|||
import { Component } from '@angular/core'; |
|||
import { Season } from '../../models/season'; |
|||
import { ApiService } from '../../services/api.service'; |
|||
|
|||
@Component({ |
|||
selector: 'app-seasons', |
|||
templateUrl: './seasons.component.html', |
|||
styleUrls: ['./seasons.component.less'] |
|||
}) |
|||
|
|||
export class SeasonsComponent |
|||
{ |
|||
seasons: Season[]; |
|||
|
|||
constructor(private apiService: ApiService) |
|||
{ |
|||
this.seasons = []; |
|||
}; |
|||
|
|||
ngOnInit() { |
|||
this.apiService.getSeasons().subscribe(data => { |
|||
this.seasons = (data as any).seasons; |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
<mat-toolbar> |
|||
<button mat-icon-button class="example-icon" aria-label="Example icon-button with menu icon"> |
|||
<mat-icon>menu</mat-icon> |
|||
</button> |
|||
<span>Stainless Trackmanaia Tournament Tracker</span> |
|||
<span class="example-spacer"></span> |
|||
<button mat-icon-button class="example-icon favorite-icon" aria-label="Example icon-button with heart icon"> |
|||
<mat-icon>favorite</mat-icon> |
|||
</button> |
|||
<button mat-icon-button class="example-icon" aria-label="Example icon-button with share icon"> |
|||
<mat-icon>share</mat-icon> |
|||
</button> |
|||
</mat-toolbar> |
|||
@ -0,0 +1,3 @@ |
|||
.example-spacer { |
|||
flex: 1 1 auto; |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
import { ComponentFixture, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { TopBarComponent } from './top-bar.component'; |
|||
|
|||
describe('TopBarComponent', () => { |
|||
let component: TopBarComponent; |
|||
let fixture: ComponentFixture<TopBarComponent>; |
|||
|
|||
beforeEach(() => { |
|||
TestBed.configureTestingModule({ |
|||
declarations: [TopBarComponent] |
|||
}); |
|||
fixture = TestBed.createComponent(TopBarComponent); |
|||
component = fixture.componentInstance; |
|||
fixture.detectChanges(); |
|||
}); |
|||
|
|||
it('should create', () => { |
|||
expect(component).toBeTruthy(); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,11 @@ |
|||
import { Component } from '@angular/core'; |
|||
|
|||
|
|||
@Component({ |
|||
selector: 'app-top-bar', |
|||
templateUrl: './top-bar.component.html', |
|||
styleUrls: ['./top-bar.component.less'] |
|||
}) |
|||
export class TopBarComponent { |
|||
|
|||
} |
|||
@ -0,0 +1 @@ |
|||
<p>upload-replay-dialog works!</p> |
|||
@ -0,0 +1,21 @@ |
|||
import { ComponentFixture, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { UploadReplayDialogComponent } from './upload-replay-dialog.component'; |
|||
|
|||
describe('UploadReplayDialogComponent', () => { |
|||
let component: UploadReplayDialogComponent; |
|||
let fixture: ComponentFixture<UploadReplayDialogComponent>; |
|||
|
|||
beforeEach(() => { |
|||
TestBed.configureTestingModule({ |
|||
declarations: [UploadReplayDialogComponent] |
|||
}); |
|||
fixture = TestBed.createComponent(UploadReplayDialogComponent); |
|||
component = fixture.componentInstance; |
|||
fixture.detectChanges(); |
|||
}); |
|||
|
|||
it('should create', () => { |
|||
expect(component).toBeTruthy(); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,10 @@ |
|||
import { Component } from '@angular/core'; |
|||
|
|||
@Component({ |
|||
selector: 'app-upload-replay-dialog', |
|||
templateUrl: './upload-replay-dialog.component.html', |
|||
styleUrls: ['./upload-replay-dialog.component.less'] |
|||
}) |
|||
export class UploadReplayDialogComponent { |
|||
|
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
<div *ngIf="dataSource"> |
|||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8"> |
|||
<ng-container matColumnDef="position"> |
|||
<th mat-header-cell *matHeaderCellDef> No. </th> |
|||
<td mat-cell *matCellDef="let element"> {{element.position}} </td> |
|||
</ng-container> |
|||
|
|||
<!-- Name Column --> |
|||
<ng-container matColumnDef="name"> |
|||
<th mat-header-cell *matHeaderCellDef> Name </th> |
|||
<td mat-cell *matCellDef="let element"> {{element.user.realName}} </td> |
|||
</ng-container> |
|||
|
|||
<!-- Weight Column --> |
|||
<ng-container matColumnDef="runTime"> |
|||
<th mat-header-cell *matHeaderCellDef> runTime </th> |
|||
<td mat-cell *matCellDef="let element"> {{element.runTime}} </td> |
|||
</ng-container> |
|||
|
|||
<!-- Symbol Column --> |
|||
<ng-container matColumnDef="gameHandle"> |
|||
<th mat-header-cell *matHeaderCellDef> gamerTag </th> |
|||
<td mat-cell *matCellDef="let element"> {{element.user.gamerHandle}} </td> |
|||
</ng-container> |
|||
|
|||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> |
|||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> |
|||
</table> |
|||
</div> |
|||
@ -0,0 +1,21 @@ |
|||
import { ComponentFixture, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { WeeklyStandingsTableComponent } from './weekly-standings-table.component'; |
|||
|
|||
describe('WeeklyStandingsTableComponent', () => { |
|||
let component: WeeklyStandingsTableComponent; |
|||
let fixture: ComponentFixture<WeeklyStandingsTableComponent>; |
|||
|
|||
beforeEach(() => { |
|||
TestBed.configureTestingModule({ |
|||
declarations: [WeeklyStandingsTableComponent] |
|||
}); |
|||
fixture = TestBed.createComponent(WeeklyStandingsTableComponent); |
|||
component = fixture.componentInstance; |
|||
fixture.detectChanges(); |
|||
}); |
|||
|
|||
it('should create', () => { |
|||
expect(component).toBeTruthy(); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,13 @@ |
|||
import { Component, Input } from '@angular/core'; |
|||
import { SeasonWeekEntry } from '../../models/season'; |
|||
|
|||
@Component({ |
|||
selector: 'app-weekly-standings-table', |
|||
templateUrl: './weekly-standings-table.component.html', |
|||
styleUrls: ['./weekly-standings-table.component.less'] |
|||
}) |
|||
export class WeeklyStandingsTableComponent { |
|||
displayedColumns: string[] = ['position', 'name', 'gameHandle', 'runTime']; |
|||
@Input() dataSource?: SeasonWeekEntry[]; |
|||
|
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
import { Injectable } from '@angular/core'; |
|||
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from "@angular/common/http"; |
|||
import { Observable } from 'rxjs'; |
|||
|
|||
@Injectable() |
|||
export class AuthInterceptor implements HttpInterceptor { |
|||
|
|||
intercept(req: HttpRequest<any>, |
|||
next: HttpHandler): Observable<HttpEvent<any>> { |
|||
|
|||
const idToken = localStorage.getItem("id_token"); |
|||
|
|||
if (idToken) { |
|||
const cloned = req.clone({ |
|||
headers: req.headers.set("Authorization", |
|||
"Bearer " + idToken) |
|||
}); |
|||
|
|||
return next.handle(cloned); |
|||
} |
|||
else { |
|||
return next.handle(req); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
export interface Season { |
|||
id: string, |
|||
seasonName: string; |
|||
seasonTag: string; |
|||
seasonCardImage: string; |
|||
seasonHeaderImage: string; |
|||
seasonStartDate: string; |
|||
seasonSendDate: string; |
|||
seasonId: string; |
|||
seasonDesc: string; |
|||
} |
|||
|
|||
export interface BridgeUser { |
|||
id: string; |
|||
realName: string; |
|||
gameHandle: string; |
|||
} |
|||
|
|||
export interface SeasonStandingsEntry { |
|||
position: string; |
|||
points: number; |
|||
user: BridgeUser; |
|||
} |
|||
|
|||
export interface SeasonWeekEntry { |
|||
position: string; |
|||
runTime: string; |
|||
user: BridgeUser; |
|||
} |
|||
|
|||
export interface SeasonWeek { |
|||
id: string; |
|||
mapName: string; |
|||
mapImg: string; |
|||
entries: SeasonWeekEntry[]; |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
import { Injectable } from '@angular/core'; |
|||
import { HttpClient } from '@angular/common/http'; |
|||
import { shareReplay, tap } from 'rxjs/operators' |
|||
import * as moment from "moment"; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root' |
|||
}) |
|||
|
|||
export class AuthService |
|||
{ |
|||
constructor(private http: HttpClient) { } |
|||
|
|||
login(email: string, password: string) |
|||
{ |
|||
return this.http.post('/api/login', {email, password}).pipe( |
|||
tap( res => this.setSession ), |
|||
shareReplay() |
|||
); |
|||
} |
|||
|
|||
private setSession(authResult: any) { |
|||
const expiresAt = moment().add((authResult as any).expiresIn,'second'); |
|||
|
|||
localStorage.setItem('id_token', (authResult as any).idToken); |
|||
localStorage.setItem("expires_at", JSON.stringify(expiresAt.valueOf()) ); |
|||
} |
|||
|
|||
logout() { |
|||
localStorage.removeItem("id_token"); |
|||
localStorage.removeItem("expires_at"); |
|||
} |
|||
|
|||
public isLoggedIn() { |
|||
return moment().isBefore(this.getExpiration()); |
|||
} |
|||
|
|||
isLoggedOut() { |
|||
return !this.isLoggedIn(); |
|||
} |
|||
|
|||
getExpiration() { |
|||
const expiration = localStorage.getItem("expires_at"); |
|||
const expiresAt = JSON.parse(expiration ? expiration : ''); |
|||
return moment(expiresAt); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue