fix: NCWF-4 Token Issues (#8)
Co-authored-by: Lala, Shahd <Shahd.Lala@sybit.de> Co-authored-by: shahdlala66 <shahd.lala66@gmail.com> Reviewed-on: #8
This commit was merged in pull request #8.
This commit is contained in:
@@ -8,9 +8,10 @@ export const authInterceptor: HttpInterceptorFn = (req, next) => {
|
||||
req.url.includes('/api/account/bots') ||
|
||||
req.url.includes('/api/account/official-bots') ||
|
||||
req.url.includes('/api/board/game') ||
|
||||
req.url.includes('/api/challenge');
|
||||
req.url.includes('/api/challenge') ||
|
||||
req.url.includes('/api/tournament');
|
||||
|
||||
if (token && isProtectedEndpoint) {
|
||||
if (token && isProtectedEndpoint && !req.headers.has('Authorization')) {
|
||||
req = req.clone({
|
||||
setHeaders: {
|
||||
Authorization: `Bearer ${token}`
|
||||
|
||||
@@ -26,9 +26,9 @@ export class AuthService {
|
||||
})
|
||||
.pipe(
|
||||
tap((response) => {
|
||||
localStorage.setItem('token', response.token);
|
||||
localStorage.setItem('token', response.accessToken); //GRRRRRRRRRR
|
||||
localStorage.setItem('refreshToken', response.refreshToken);
|
||||
localStorage.setItem('username', username);
|
||||
// After login, fetch current user info
|
||||
this.getCurrentUser().subscribe();
|
||||
})
|
||||
);
|
||||
@@ -60,6 +60,7 @@ export class AuthService {
|
||||
|
||||
logout(): void {
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('refreshToken');
|
||||
localStorage.removeItem('username');
|
||||
localStorage.removeItem('userId');
|
||||
this.currentUserSubject.next(null);
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Observable, map } from 'rxjs';
|
||||
import { Bot, BotWithToken } from '../models/bot.models';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class BotService {
|
||||
private readonly http = inject(HttpClient);
|
||||
private readonly base = '/api/account/bots';
|
||||
|
||||
list(): Observable<Bot[]> {
|
||||
return this.http.get<Bot[]>(this.base);
|
||||
}
|
||||
|
||||
create(name: string): Observable<BotWithToken> {
|
||||
return this.http.post<BotWithToken>(this.base, { name });
|
||||
}
|
||||
|
||||
rotateToken(botId: string): Observable<string> {
|
||||
return this.http.post<{ token: string }>(`${this.base}/${botId}/rotate-token`, null)
|
||||
.pipe(map(r => r.token));
|
||||
}
|
||||
|
||||
delete(botId: string): Observable<void> {
|
||||
return this.http.delete<void>(`${this.base}/${botId}`);
|
||||
}
|
||||
}
|
||||
@@ -67,6 +67,14 @@ export class GameApiService {
|
||||
return this.http.post<GameFull>(`${this.apiBase}${this.apiPath}/import/pgn`, { pgn });
|
||||
}
|
||||
|
||||
resignGame(gameId: string): Observable<void> {
|
||||
return this.http.post<void>(`${this.apiBase}${this.apiPath}/${gameId}/resign`, {});
|
||||
}
|
||||
|
||||
offerDraw(gameId: string): Observable<void> {
|
||||
return this.http.post<void>(`${this.apiBase}${this.apiPath}/${gameId}/draw/offer`, {});
|
||||
}
|
||||
|
||||
private resolveWsBase(): string {
|
||||
if (this.wsBase) {
|
||||
return this.wsBase;
|
||||
@@ -77,7 +85,11 @@ export class GameApiService {
|
||||
}
|
||||
|
||||
streamGame(gameId: string): Observable<GameStreamEvent> {
|
||||
const wsUrl = `${this.resolveWsBase()}${this.apiPath}/${gameId}/ws`;
|
||||
const token = localStorage.getItem('token');
|
||||
let wsUrl = `${this.resolveWsBase()}${this.apiPath}/${gameId}/ws`;
|
||||
if (token) {
|
||||
wsUrl += `?token=${encodeURIComponent(token)}`;
|
||||
}
|
||||
return this.streamHandler.createGameStream(wsUrl, gameId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,23 +24,28 @@ export class GameCompletionService {
|
||||
return { isFinished: true, message };
|
||||
}
|
||||
|
||||
isTimeOut(state: GameState | null): boolean {
|
||||
if (!state?.clock) return false;
|
||||
return state.clock.whiteRemainingMs <= 0 || state.clock.blackRemainingMs <= 0;
|
||||
}
|
||||
|
||||
private buildCompletionMessage(status: GameStatus, state: GameState, game: GameFull): string {
|
||||
const winner = state.winner === 'white' ? game.white.displayName : state.winner === 'black' ? game.black.displayName : null;
|
||||
const loser = state.winner === 'white' ? game.black.displayName : state.winner === 'black' ? game.white.displayName : null;
|
||||
|
||||
switch (status) {
|
||||
case 'checkmate':
|
||||
const winner = state.winner === 'white' ? game.white.displayName : game.black.displayName;
|
||||
return `Checkmate! ${winner} wins!`;
|
||||
return winner ? `Checkmate — ${winner} wins!` : 'Checkmate!';
|
||||
case 'stalemate':
|
||||
return 'Stalemate! The game is a draw.';
|
||||
return 'Stalemate — draw!';
|
||||
case 'resign':
|
||||
const resignedPlayer = state.winner === 'white' ? game.black.displayName : game.white.displayName;
|
||||
const resignedWinner = state.winner === 'white' ? game.white.displayName : game.black.displayName;
|
||||
return `${resignedPlayer} resigned. ${resignedWinner} wins!`;
|
||||
return loser && winner ? `${loser} resigned — ${winner} wins!` : 'Resigned.';
|
||||
case 'draw':
|
||||
return 'Draw! The game ended in a draw.';
|
||||
return 'Draw by agreement.';
|
||||
case 'insufficientMaterial':
|
||||
return 'Insufficient material! The game is a draw.';
|
||||
return 'Draw — insufficient material.';
|
||||
default:
|
||||
return 'Game ended!';
|
||||
return 'Game over.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Tournament, TournamentList, RoundPairings } from '../models/tournament.models';
|
||||
|
||||
export interface CreateTournamentForm {
|
||||
name: string;
|
||||
nbRounds: number;
|
||||
clockLimitMinutes: number;
|
||||
clockIncrement: number;
|
||||
rated: boolean;
|
||||
}
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class TournamentService {
|
||||
private readonly http = inject(HttpClient);
|
||||
private readonly base = '/api/tournament';
|
||||
|
||||
list(): Observable<TournamentList> {
|
||||
return this.http.get<TournamentList>(this.base);
|
||||
}
|
||||
|
||||
get(id: string): Observable<Tournament> {
|
||||
return this.http.get<Tournament>(`${this.base}/${id}`);
|
||||
}
|
||||
|
||||
create(form: CreateTournamentForm): Observable<Tournament> {
|
||||
const body = new URLSearchParams();
|
||||
body.set('name', form.name);
|
||||
body.set('nbRounds', String(form.nbRounds));
|
||||
body.set('clockLimit', String(form.clockLimitMinutes * 60));
|
||||
body.set('clockIncrement', String(form.clockIncrement));
|
||||
body.set('rated', String(form.rated));
|
||||
return this.http.post<Tournament>(this.base, body.toString(), {
|
||||
headers: new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' })
|
||||
});
|
||||
}
|
||||
|
||||
start(id: string): Observable<Tournament> {
|
||||
return this.http.post<Tournament>(`${this.base}/${id}/start`, null);
|
||||
}
|
||||
|
||||
joinWithBotToken(id: string, botToken: string): Observable<void> {
|
||||
return this.http.post<void>(`${this.base}/${id}/join`, null, {
|
||||
headers: new HttpHeaders({ Authorization: `Bearer ${botToken}` })
|
||||
});
|
||||
}
|
||||
|
||||
roundPairings(id: string, round: number): Observable<RoundPairings> {
|
||||
return this.http.get<RoundPairings>(`${this.base}/${id}/round/${round}`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user