chore(backend): Clean up Controllers

This commit is contained in:
2025-03-25 15:52:35 +01:00
parent 60f54ab770
commit f5a131ec4e
9 changed files with 340 additions and 339 deletions

View File

@@ -5,73 +5,62 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using backend.Models; using backend.Models;
public class UserLogin namespace backend.Controllers;
{
public string Username { get; set; } public class UserLogin {
public string Password { get; set; } public required string Username { get; set; }
} public required string Password { get; set; }
}
[ApiController] [ApiController]
[Route("api/[controller]")] [Route("api/v1/[controller]")]
public class AuthController : ControllerBase public class AuthController(GameContext context) : ControllerBase {
{ private readonly GameContext _context = context;
private readonly GameContext _context;
public static string CreateMD5(string input) [HttpPost("login")]
{ public IActionResult Login([FromBody] UserLogin loginData) {
// Use input string to calculate MD5 hash var salt = Environment.GetEnvironmentVariable("MD5_SALT") ?? "";
using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create()) var passwordHash = CreateMD5(loginData.Password + salt);
{
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
byte[] hashBytes = md5.ComputeHash(inputBytes);
return Convert.ToHexString(hashBytes); // .NET 5 + var user = _context
.Users
.Where(u => u.Username == loginData.Username && u.PasswordHash == passwordHash)
.FirstOrDefault();
// Convert the byte array to hexadecimal string prior to .NET 5 if (user != null) {
// StringBuilder sb = new System.Text.StringBuilder(); var token = GenerateJwtToken(user.Id.ToString());
// for (int i = 0; i < hashBytes.Length; i++)
// { return Ok(new { token });
// sb.Append(hashBytes[i].ToString("X2"));
// }
// return sb.ToString();
}
}
public AuthController(GameContext context) {
_context = context;
}
[HttpPost("login")]
public IActionResult Login([FromBody] UserLogin user) {
var salt = Environment.GetEnvironmentVariable("MD5_SALT") ?? "";
var passwordHash = CreateMD5(user.Password + salt);
var dbUser = _context.Users.Where(u => u.Username == user.Username && u.PasswordHash == passwordHash).FirstOrDefault();
if (dbUser != null) {
var token = GenerateJwtToken(dbUser.Id.ToString());
return Ok(new { token });
}
return Unauthorized();
}
private string GenerateJwtToken(string userId)
{
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, userId),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Environment.GetEnvironmentVariable("JWT_SECRET")));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: "wessel.gg",
audience: "wessel.gg",
claims: claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: creds);
return new JwtSecurityTokenHandler().WriteToken(token);
} }
return Unauthorized();
}
private static string GenerateJwtToken(string userId) {
var secret = Environment.GetEnvironmentVariable("JWT_SECRET") ?? "";
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var claims = new[] {
new Claim(JwtRegisteredClaimNames.Sub, userId),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
};
var token = new JwtSecurityToken(
signingCredentials: creds,
issuer: Environment.GetEnvironmentVariable("JWT_ISSUER") ?? "",
audience: Environment.GetEnvironmentVariable("JWT_AUDIENCE") ?? "",
claims: claims,
expires: DateTime.Now.AddHours(6)
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
public static string CreateMD5(string input) {
byte[] inputBytes = Encoding.ASCII.GetBytes(input);
byte[] hashBytes = System.Security.Cryptography.MD5.HashData(inputBytes);
return Convert.ToHexString(hashBytes);
}
} }

View File

@@ -1,178 +1,172 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using backend.Models; using backend.Models;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using System.Security.Claims; using System.Security.Claims;
using System.IdentityModel.Tokens.Jwt;
namespace backend.Controllers namespace backend.Controllers;
{
[Route("/api/v1/[controller]")]
[ApiController]
public class GamesController : ControllerBase {
private readonly GameContext _context;
public GamesController(GameContext context) { [Route("/api/v1/[controller]")]
_context = context; [ApiController]
public class GamesController(GameContext context) : ControllerBase {
private readonly GameContext _context = context;
private long? ParseUserId() {
var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (long.TryParse(userIdClaim, out var userId)) {
return userId;
} }
// GET: api/Games return null;
[HttpGet] }
[Authorize]
public async Task<ActionResult<IEnumerable<Game>>> GetGames() {
var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (!long.TryParse(userIdClaim, out var userId)) { // GET: api/Games
return Unauthorized(); [HttpGet]
} [Authorize]
public async Task<ActionResult<IEnumerable<Game>>> GetGames() {
// return await _context.Games.ToListAsync(); var user = ParseUserId();
return await _context.Games.Where(g => g.UserId == userId).ToListAsync(); if (user == null) {
return BadRequest();
} }
// GET: api/Games/5 return await _context.Games
[HttpGet("{id}")] .Where(g => g.UserId == user)
[Authorize] .ToListAsync();
public async Task<ActionResult<Game>> GetGame(long id) }
{
var game = await _context.Games.FindAsync(id);
if (game == null) // GET: api/Games/5
{ [HttpGet("{id}")]
return NotFound(); [Authorize]
} public async Task<ActionResult<Game>> GetGame(long id) {
var user = ParseUserId();
return game; if (user == null) {
return BadRequest();
} }
// PUT: api/Games/5 var game = await _context.Games
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 .Where(g => g.Id == id && g.UserId == user)
[HttpPut("{id}")] .FirstOrDefaultAsync();
[Authorize]
public async Task<IActionResult> PutGame(long id, Game game)
{
if (id != game.Id)
{
return BadRequest();
}
_context.Entry(game).State = EntityState.Modified; if (game == null || game.UserId != user) {
return NotFound();
try {
await _context.SaveChangesAsync();
} catch (DbUpdateConcurrencyException) {
if (!GameExists(id)) {
return NotFound();
} else {
throw;
}
}
return NoContent();
} }
// POST: api/Games return game;
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 }
[HttpPost]
[Authorize]
public async Task<ActionResult<Game>> PostGame() {
var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; // POST: api/Games
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
if (!long.TryParse(userIdClaim, out var userId)) { [HttpPost]
return Unauthorized(); [Authorize]
} public async Task<ActionResult<Game>> PostGame() {
var user = ParseUserId();
var newGame = new Game { if (user == null) {
Deck = ( return BadRequest();
from shape in Enum.GetValues(typeof(CardShape)).Cast<CardShape>()
from color in Enum.GetValues(typeof(CardColor)).Cast<CardColor>()
from count in Enum.GetValues(typeof(CardCount)).Cast<CardCount>()
from shade in Enum.GetValues(typeof(CardShade)).Cast<CardShade>()
select new Card {
Shape = shape,
Color = color,
Count = count,
Shade = shade
}.ToUshort()).ToArray(),
UserId = userId
};
newGame.ShuffleDeck();
newGame.DealHand();
_context.Games.Add(newGame);
await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetGame), new { id = newGame.Id }, newGame);
} }
// DELETE: api/Games/5 var newGame = new Game {
[HttpDelete("{id}")] UserId = (long)user,
[Authorize] Deck = [..
public async Task<IActionResult> DeleteGame(long id) { from shape in Enum.GetValues<CardShape>().Cast<CardShape>()
var game = await _context.Games.FindAsync(id); from color in Enum.GetValues<CardColor>().Cast<CardColor>()
if (game == null) from count in Enum.GetValues<CardCount>().Cast<CardCount>()
{ from shade in Enum.GetValues<CardShade>().Cast<CardShade>()
return NotFound(); select new Card {
} Shape = shape,
Color = color,
Count = count,
Shade = shade
}.ToUshort()
]
};
_context.Games.Remove(game); newGame.ShuffleDeck();
await _context.SaveChangesAsync(); newGame.DealHand();
return NoContent(); _context.Games.Add(newGame);
await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetGame), new { id = newGame.Id }, newGame);
}
// DELETE: api/Games/5
[HttpDelete("{id}")]
[Authorize]
public async Task<IActionResult> DeleteGame(long id) {
var user = ParseUserId();
if (user == null) {
return BadRequest();
} }
private bool GameExists(long id) { var game = await _context.Games
return _context.Games.Any(e => e.Id == id); .Where(g => g.Id == id && g.UserId == user)
.FirstOrDefaultAsync();
if (game == null) {
return NotFound();
} }
[HttpPost] _context.Games.Remove(game);
[Route("[action]/{id}")] await _context.SaveChangesAsync();
[Authorize]
return NoContent();
}
[HttpPost]
[Route("[action]/{id}")]
[Authorize]
public async Task<ActionResult<SetCheckResult>> CheckSet( public async Task<ActionResult<SetCheckResult>> CheckSet(
long id, long id,
[FromBody] ushort[] cardIndices [FromBody] ushort[] cardIndices
) { ) {
var game = await _context.Games.FindAsync(id); var user = ParseUserId();
if (game == null) { if (user == null) {
return NotFound(); return BadRequest();
}
var res = game.IsSet(cardIndices);
if (res == null) {
return BadRequest();
}
await _context.SaveChangesAsync();
return res;
} }
[HttpGet] var game = await _context.Games
[Route("[action]/{id}")] .Where(g => g.Id == id && g.UserId == user)
[Authorize] .FirstOrDefaultAsync();
public async Task<ActionResult<List<int[]>>> SetsInHand(long id) {
var game = await _context.Games.FindAsync(id);
if (game == null) {
return NotFound();
}
var res = game.GetIndicesOfSet(); if (game == null) {
return NotFound();
if (res == null) {
return BadRequest();
}
Console.WriteLine($"Found {res.Count} sets in hand");
return res;
} }
var res = game.IsSet(cardIndices);
if (res == null) {
return BadRequest();
}
await _context.SaveChangesAsync();
return res;
}
[HttpGet]
[Route("[action]/{id}")]
[Authorize]
public async Task<ActionResult<List<int[]>>> SetsInHand(long id) {
var user = ParseUserId();
if (user == null) {
return BadRequest();
}
var game = await _context.Games
.Where(g => g.Id == id && g.UserId == user)
.FirstOrDefaultAsync();
if (game == null) {
return NotFound();
}
var res = game.GetIndicesOfSet();
if (res == null) {
return BadRequest();
}
return res;
} }
} }

View File

@@ -12,8 +12,8 @@ using backend.Models;
namespace backend.Migrations namespace backend.Migrations
{ {
[DbContext(typeof(GameContext))] [DbContext(typeof(GameContext))]
[Migration("20250325111947_initial")] [Migration("20250325145201_InitialDatabase")]
partial class initial partial class InitialDatabase
{ {
/// <inheritdoc /> /// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder) protected override void BuildTargetModel(ModelBuilder modelBuilder)
@@ -102,13 +102,11 @@ namespace backend.Migrations
modelBuilder.Entity("backend.Models.Game", b => modelBuilder.Entity("backend.Models.Game", b =>
{ {
b.HasOne("backend.Models.User", "User") b.HasOne("backend.Models.User", null)
.WithMany("Games") .WithMany("Games")
.HasForeignKey("UserId") .HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired(); .IsRequired();
b.Navigation("User");
}); });
modelBuilder.Entity("backend.Models.User", b => modelBuilder.Entity("backend.Models.User", b =>

View File

@@ -7,7 +7,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace backend.Migrations namespace backend.Migrations
{ {
/// <inheritdoc /> /// <inheritdoc />
public partial class initial : Migration public partial class InitialDatabase : Migration
{ {
/// <inheritdoc /> /// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder) protected override void Up(MigrationBuilder migrationBuilder)

View File

@@ -99,13 +99,11 @@ namespace backend.Migrations
modelBuilder.Entity("backend.Models.Game", b => modelBuilder.Entity("backend.Models.Game", b =>
{ {
b.HasOne("backend.Models.User", "User") b.HasOne("backend.Models.User", null)
.WithMany("Games") .WithMany("Games")
.HasForeignKey("UserId") .HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired(); .IsRequired();
b.Navigation("User");
}); });
modelBuilder.Entity("backend.Models.User", b => modelBuilder.Entity("backend.Models.User", b =>

View File

@@ -18,8 +18,6 @@ public class Game {
public ushort[]? Deck { get; set; } public ushort[]? Deck { get; set; }
public ushort[] Found { get; set; } = Array.Empty<ushort>(); public ushort[] Found { get; set; } = Array.Empty<ushort>();
public User User { get; set; } = null!;
public void ShuffleDeck() { public void ShuffleDeck() {
if (Deck == null) return; if (Deck == null) return;

View File

@@ -11,7 +11,7 @@ interface LoginResponse {
providedIn: 'root' providedIn: 'root'
}) })
export class AuthService { export class AuthService {
private API_URL = 'http://localhost:5224/api/Auth'; private API_URL = 'http://localhost:5224/api/v1/Auth';
private tokenKey = 'auth_token'; private tokenKey = 'auth_token';
private isAuthenticatedSubject = new BehaviorSubject<boolean>(this.hasToken()); private isAuthenticatedSubject = new BehaviorSubject<boolean>(this.hasToken());
public redirectUrl: string | null = null; public redirectUrl: string | null = null;

View File

@@ -1,13 +1,13 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Card, toCard } from '../../app/models/card'; import { Card, toCard } from '../../app/models/card';
// todo: Rewrite to use angular http client instead of axios, supports always sending tokens import { lastValueFrom } from 'rxjs';
import axios from 'axios'; import { AuthService } from '../auth/auth.service';
axios.defaults.headers.common['Authorization'] = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImp0aSI6ImRmNThhYTU3LWZkNzItNGIzYS05OTNmLTY4NjAyNGMzYjdlNSIsImV4cCI6MTc0MjgxODEzOCwiaXNzIjoid2Vzc2VsLmdnIiwiYXVkIjoid2Vzc2VsLmdnIn0.hDf8qcxXeSFQhmgnMzBrH3ZJJMplwZ-1RQwNxeZo5ok';
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class GameService { export class GameService {
private API_URL = 'http://localhost:5224/api/v1/Games';
public deck: Card[] = []; public deck: Card[] = [];
public hand: Card[] = []; public hand: Card[] = [];
public foundSets: Card[][] = []; public foundSets: Card[][] = [];
@@ -20,8 +20,9 @@ export class GameService {
public finishedAt?: Date; public finishedAt?: Date;
public selectedCards: Card[] = []; public selectedCards: Card[] = [];
constructor() { constructor(
} private http: HttpClient,
) {}
public initGame(gameId?: string): Promise<string> { public initGame(gameId?: string): Promise<string> {
this.deck = []; this.deck = [];
@@ -35,58 +36,113 @@ export class GameService {
} }
public async initializeExistingGame(gameId: string): Promise<string> { public async initializeExistingGame(gameId: string): Promise<string> {
const req = await axios.get('http://localhost:5224/api/v1/Games/' + gameId); try {
req.data.deck.forEach((card: number) => { const response = await lastValueFrom(this.http.get<any>(`${this.API_URL}/${gameId}`));
this.deck.push(toCard(card));
}); response.deck.forEach((card: number) => {
req.data.hand.forEach((card: number) => { this.deck.push(toCard(card));
});
response.hand.forEach((card: number) => {
this.hand.push(toCard(card)); this.hand.push(toCard(card));
}); });
this.startDate = new Date(req.data.startedAt);
this.fails = req.data.fails; this.startDate = new Date(response.startedAt);
this.hints = req.data.hints; this.fails = response.fails;
this.finishedAt = req.data.finishedAt; this.hints = response.hints;
this.finishedAt = response.finishedAt ? new Date(response.finishedAt) : undefined;
this.foundSets = []; this.foundSets = [];
for (let i = 0; i < req.data.found.length; i += 3) { for (let i = 0; i < response.found.length; i += 3) {
this.foundSets.push(req.data.found.slice(i, i + 3).map((card: number) => toCard(card))); this.foundSets.push(response.found.slice(i, i + 3).map((card: number) => toCard(card)));
} }
this.gameId = req.data.id; this.gameId = response.id;
await this.updateSets(); this.updateSets();
return response.id.toString();
return req.data.id; } catch (error) {
console.error('Error initializing existing game', error);
throw error;
}
} }
private async initializeDeck(): Promise<string> { private async initializeDeck(): Promise<string> {
const res = await axios.post('http://localhost:5224/api/v1/Games', {}); try {
res.data.deck.forEach((card: number) => { const response = await lastValueFrom(this.http.post<any>(this.API_URL, {}));
this.deck.push(toCard(card));
});
res.data.hand.forEach((card: number) => { response.deck.forEach((card: number) => {
this.deck.push(toCard(card));
});
response.hand.forEach((card: number) => {
this.hand.push(toCard(card)); this.hand.push(toCard(card));
}); });
this.startDate = new Date(res.data.startedAt); this.startDate = new Date(response.startedAt);
this.fails = res.data.fails; this.fails = response.fails;
this.hints = res.data.hints; this.hints = response.hints;
this.gameId = res.data.id; this.gameId = response.id;
this.finishedAt = res.data.finishedAt; this.finishedAt = response.finishedAt ? new Date(response.finishedAt) : undefined;
this.foundSets = []; this.foundSets = [];
for (let i = 0; i < res.data.newState.found.length; i += 3) { for (let i = 0; i < response.found.length; i += 3) {
this.foundSets.push(res.data.newState.found.slice(i, i + 3).map((card: number) => toCard(card))); this.foundSets.push(response.found.slice(i, i + 3).map((card: number) => toCard(card)));
}
this.updateSets();
return response.id.toString();
} catch (error) {
console.error('Error initializing deck', error);
throw error;
}
}
public async updateSets(): Promise<Card[][]> {
try {
const response = await lastValueFrom(
this.http.get<number[][]>(`${this.API_URL}/SetsInHand/${this.gameId}`)
);
const cards = response.map((set: number[]) =>
set.map((card: number) => this.hand[card])
);
this.possibleSets = cards;
return cards;
} catch (error) {
console.error('Error updating sets', error);
throw error;
}
}
public async checkSet(cards: number[]): Promise<boolean> {
try {
const response = await lastValueFrom(
this.http.post<any>(`${this.API_URL}/CheckSet/${this.gameId}`, cards)
);
this.hand = response.newState.hand.map((card: number) => toCard(card));
this.deck = response.newState.deck.map((card: number) => toCard(card));
this.fails = response.newState.fails;
this.hints = response.newState.hints;
this.finishedAt = response.newState.finishedAt ? new Date(response.newState.finishedAt) : undefined;
this.foundSets = [];
for (let i = 0; i < response.newState.found.length; i += 3) {
this.foundSets.push(response.newState.found.slice(i, i + 3).map((card: number) => toCard(card)));
} }
await this.updateSets(); await this.updateSets();
return response.isSet;
return res.data.id; } catch (error) {
console.error('Error checking set', error);
throw error;
}
} }
public selectCard(card: Card): void { public selectCard(card: Card): void {
const cardIndex = this.hand.indexOf(card); const cardIndex = this.hand.indexOf(card);
if (cardIndex === -1) return; // Card not found on the board if (cardIndex === -1) return; // Card not found in hand
if (this.selectedCards.includes(card)) { if (this.selectedCards.includes(card)) {
this.selectedCards = this.selectedCards.filter(c => c !== card); this.selectedCards = this.selectedCards.filter(c => c !== card);
@@ -95,58 +151,29 @@ export class GameService {
} }
if (this.selectedCards.length === 3) { if (this.selectedCards.length === 3) {
const [card1, card2, card3] = this.selectedCards as [Card, Card, Card]; // ✅ Explicitly cast to a tuple const indices = this.selectedCards.map(c => this.hand.indexOf(c));
if (this.isSet([this.hand.indexOf(card1), this.hand.indexOf(card2), this.hand.indexOf(card3)])) { this.checkSet(indices).then(isSet => {
this.replaceSet(); this.selectedCards = [];
} });
} }
} }
public async updateSets(): Promise<Card[][]> { public async deleteGame(): Promise<void> {
const req = await axios.get(`http://localhost:5224/api/v1/Games/SetsInHand/${this.gameId}`); try {
const cards = req.data await lastValueFrom(this.http.delete<void>(`${this.API_URL}/${this.gameId}`));
.map((set: number[]) => } catch (error) {
set.map((card: number) => this.hand[card]) console.error('Error deleting game', error);
); throw error;
}
this.possibleSets = cards;
return cards;
} }
private isSet(cards: number[]): boolean { public async showHint(): Promise<void> {
this.selectedCards = []; try {
await lastValueFrom(this.http.post<void>(`${this.API_URL}/Hint/${this.gameId}`, {}));
axios.post(`http://localhost:5224/api/v1/Games/CheckSet/${this.gameId}`, cards).then((response) => { this.hints++;
this.hand = response.data.newState.hand.map((card: number) => toCard(card)); } catch (error) {
this.deck = response.data.newState.deck.map((card: number) => toCard(card)); console.error('Error showing hint', error);
this.fails = response.data.newState.fails; throw error;
this.hints = response.data.newState.hints; }
this.finishedAt = response.data.newState.finishedAt;
this.foundSets = [];
for (let i = 0; i < response.data.newState.found.length; i += 3) {
this.foundSets.push(response.data.newState.found.slice(i, i + 3).map((card: number) => toCard(card)));
}
this.updateSets();
return response.data.isSet;
});
return false;
}
private replaceSet(): void {
this.hand.find((c, i) => {
if (this.selectedCards.includes(c)) {
this.hand[i] = this.deck.splice(0, 1)[0];
}
});
this.selectedCards = [];
}
public async deleteGame() {
await axios.delete('http://localhost:5224/api/v1/Games/' + this.gameId);
} }
} }

View File

@@ -1,43 +1,40 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import axios, { AxiosError } from 'axios'; import { HttpClient } from '@angular/common/http';
import { lastValueFrom } from 'rxjs';
// axios.defaults.headers.common['Authorization'] = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImp0aSI6ImRmNThhYTU3LWZkNzItNGIzYS05OTNmLTY4NjAyNGMzYjdlNSIsImV4cCI6MTc0MjgxODEzOCwiaXNzIjoid2Vzc2VsLmdnIiwiYXVkIjoid2Vzc2VsLmdnIn0.hDf8qcxXeSFQhmgnMzBrH3ZJJMplwZ-1RQwNxeZo5ok'; import { AuthService } from '../auth/auth.service';
axios.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class UserDataService { export class UserDataService {
private GAMES_API_URL = 'http://localhost:5224/api/v1/Games';
constructor() { constructor(
// this.login({ username: 'admin', password: 'password' }); private http: HttpClient,
private authService: AuthService
) {}
public async login(credentials: { username: string, password: string }): Promise<void> {
try {
await lastValueFrom(this.authService.login(credentials.username, credentials.password));
} catch (error) {
console.error('Login error:', error);
throw error;
}
} }
public async login(credentials: any) { public async getGames(): Promise<any[]> {
const response = await axios.post('http://localhost:5224/api/Auth/login', credentials); try {
localStorage.setItem('token', response.data.token); const data = await lastValueFrom(this.http.get<any[]>(this.GAMES_API_URL));
}
public async getGames(): Promise<any> { const sortedGames = data
const req = await axios.get('http://localhost:5224/api/v1/Games', { .sort((a: any, b: any) => new Date(a.startedAt).getTime() - new Date(b.startedAt).getTime())
headers: { .reverse();
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImp0aSI6ImRmNThhYTU3LWZkNzItNGIzYS05OTNmLTY4NjAyNGMzYjdlNSIsImV4cCI6MTc0MjgxODEzOCwiaXNzIjoid2Vzc2VsLmdnIiwiYXVkIjoid2Vzc2VsLmdnIn0.hDf8qcxXeSFQhmgnMzBrH3ZJJMplwZ-1RQwNxeZo5ok'
} return sortedGames;
}); } catch (error) {
const sortedGames = req.data console.error('Error getting games:', error);
.sort((a: any, b: any) => new Date(a.startedAt).getTime() - new Date(b.startedAt).getTime()) throw error;
.reverse(); }
return sortedGames;
} }
} }