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)
{
// Use input string to calculate MD5 hash
using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
{
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
byte[] hashBytes = md5.ComputeHash(inputBytes);
return Convert.ToHexString(hashBytes); // .NET 5 +
// Convert the byte array to hexadecimal string prior to .NET 5
// StringBuilder sb = new System.Text.StringBuilder();
// for (int i = 0; i < hashBytes.Length; i++)
// {
// sb.Append(hashBytes[i].ToString("X2"));
// }
// return sb.ToString();
}
}
public AuthController(GameContext context) {
_context = context;
}
[HttpPost("login")] [HttpPost("login")]
public IActionResult Login([FromBody] UserLogin user) { public IActionResult Login([FromBody] UserLogin loginData) {
var salt = Environment.GetEnvironmentVariable("MD5_SALT") ?? ""; var salt = Environment.GetEnvironmentVariable("MD5_SALT") ?? "";
var passwordHash = CreateMD5(user.Password + salt); var passwordHash = CreateMD5(loginData.Password + salt);
var dbUser = _context.Users.Where(u => u.Username == user.Username && u.PasswordHash == passwordHash).FirstOrDefault();
if (dbUser != null) { var user = _context
var token = GenerateJwtToken(dbUser.Id.ToString()); .Users
.Where(u => u.Username == loginData.Username && u.PasswordHash == passwordHash)
.FirstOrDefault();
if (user != null) {
var token = GenerateJwtToken(user.Id.ToString());
return Ok(new { token }); return Ok(new { token });
} }
return Unauthorized(); return Unauthorized();
} }
private string GenerateJwtToken(string userId) private static string GenerateJwtToken(string userId) {
{ var secret = Environment.GetEnvironmentVariable("JWT_SECRET") ?? "";
var claims = new[] 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.Sub, userId),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) 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( var token = new JwtSecurityToken(
issuer: "wessel.gg", signingCredentials: creds,
audience: "wessel.gg", issuer: Environment.GetEnvironmentVariable("JWT_ISSUER") ?? "",
audience: Environment.GetEnvironmentVariable("JWT_AUDIENCE") ?? "",
claims: claims, claims: claims,
expires: DateTime.Now.AddMinutes(30), expires: DateTime.Now.AddHours(6)
signingCredentials: creds); );
return new JwtSecurityTokenHandler().WriteToken(token); 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,106 +1,84 @@
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]")] [Route("/api/v1/[controller]")]
[ApiController] [ApiController]
public class GamesController : ControllerBase { public class GamesController(GameContext context) : ControllerBase {
private readonly GameContext _context; private readonly GameContext _context = context;
public GamesController(GameContext context) { private long? ParseUserId() {
_context = context; var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (long.TryParse(userIdClaim, out var userId)) {
return userId;
}
return null;
} }
// GET: api/Games // GET: api/Games
[HttpGet] [HttpGet]
[Authorize] [Authorize]
public async Task<ActionResult<IEnumerable<Game>>> GetGames() { public async Task<ActionResult<IEnumerable<Game>>> GetGames() {
var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; var user = ParseUserId();
if (user == null) {
if (!long.TryParse(userIdClaim, out var userId)) { return BadRequest();
return Unauthorized();
} }
// return await _context.Games.ToListAsync(); return await _context.Games
return await _context.Games.Where(g => g.UserId == userId).ToListAsync(); .Where(g => g.UserId == user)
.ToListAsync();
} }
// GET: api/Games/5 // GET: api/Games/5
[HttpGet("{id}")] [HttpGet("{id}")]
[Authorize] [Authorize]
public async Task<ActionResult<Game>> GetGame(long id) public async Task<ActionResult<Game>> GetGame(long id) {
{ var user = ParseUserId();
var game = await _context.Games.FindAsync(id); if (user == null) {
return BadRequest();
}
if (game == null) var game = await _context.Games
{ .Where(g => g.Id == id && g.UserId == user)
.FirstOrDefaultAsync();
if (game == null || game.UserId != user) {
return NotFound(); return NotFound();
} }
return game; return game;
} }
// PUT: api/Games/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPut("{id}")]
[Authorize]
public async Task<IActionResult> PutGame(long id, Game game)
{
if (id != game.Id)
{
return BadRequest();
}
_context.Entry(game).State = EntityState.Modified;
try {
await _context.SaveChangesAsync();
} catch (DbUpdateConcurrencyException) {
if (!GameExists(id)) {
return NotFound();
} else {
throw;
}
}
return NoContent();
}
// POST: api/Games // POST: api/Games
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPost] [HttpPost]
[Authorize] [Authorize]
public async Task<ActionResult<Game>> PostGame() { public async Task<ActionResult<Game>> PostGame() {
var user = ParseUserId();
var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; if (user == null) {
return BadRequest();
if (!long.TryParse(userIdClaim, out var userId)) {
return Unauthorized();
} }
var newGame = new Game { var newGame = new Game {
Deck = ( UserId = (long)user,
from shape in Enum.GetValues(typeof(CardShape)).Cast<CardShape>() Deck = [..
from color in Enum.GetValues(typeof(CardColor)).Cast<CardColor>() from shape in Enum.GetValues<CardShape>().Cast<CardShape>()
from count in Enum.GetValues(typeof(CardCount)).Cast<CardCount>() from color in Enum.GetValues<CardColor>().Cast<CardColor>()
from shade in Enum.GetValues(typeof(CardShade)).Cast<CardShade>() from count in Enum.GetValues<CardCount>().Cast<CardCount>()
from shade in Enum.GetValues<CardShade>().Cast<CardShade>()
select new Card { select new Card {
Shape = shape, Shape = shape,
Color = color, Color = color,
Count = count, Count = count,
Shade = shade Shade = shade
}.ToUshort()).ToArray(), }.ToUshort()
UserId = userId ]
}; };
newGame.ShuffleDeck(); newGame.ShuffleDeck();
@@ -116,9 +94,16 @@ namespace backend.Controllers
[HttpDelete("{id}")] [HttpDelete("{id}")]
[Authorize] [Authorize]
public async Task<IActionResult> DeleteGame(long id) { public async Task<IActionResult> DeleteGame(long id) {
var game = await _context.Games.FindAsync(id); var user = ParseUserId();
if (game == null) if (user == null) {
{ return BadRequest();
}
var game = await _context.Games
.Where(g => g.Id == id && g.UserId == user)
.FirstOrDefaultAsync();
if (game == null) {
return NotFound(); return NotFound();
} }
@@ -128,10 +113,6 @@ namespace backend.Controllers
return NoContent(); return NoContent();
} }
private bool GameExists(long id) {
return _context.Games.Any(e => e.Id == id);
}
[HttpPost] [HttpPost]
[Route("[action]/{id}")] [Route("[action]/{id}")]
[Authorize] [Authorize]
@@ -139,7 +120,15 @@ namespace backend.Controllers
long id, long id,
[FromBody] ushort[] cardIndices [FromBody] ushort[] cardIndices
) { ) {
var game = await _context.Games.FindAsync(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) { if (game == null) {
return NotFound(); return NotFound();
} }
@@ -159,7 +148,15 @@ namespace backend.Controllers
[Route("[action]/{id}")] [Route("[action]/{id}")]
[Authorize] [Authorize]
public async Task<ActionResult<List<int[]>>> SetsInHand(long id) { public async Task<ActionResult<List<int[]>>> SetsInHand(long id) {
var game = await _context.Games.FindAsync(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) { if (game == null) {
return NotFound(); return NotFound();
} }
@@ -170,9 +167,6 @@ namespace backend.Controllers
return BadRequest(); return BadRequest();
} }
Console.WriteLine($"Found {res.Count} sets in hand");
return res; 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) => {
this.deck.push(toCard(card));
}); });
req.data.hand.forEach((card: number) => {
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, {}));
response.deck.forEach((card: number) => {
this.deck.push(toCard(card)); this.deck.push(toCard(card));
}); });
res.data.hand.forEach((card: number) => { 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();
}
}
}
public async updateSets(): Promise<Card[][]> {
const req = await axios.get(`http://localhost:5224/api/v1/Games/SetsInHand/${this.gameId}`);
const cards = req.data
.map((set: number[]) =>
set.map((card: number) => this.hand[card])
);
this.possibleSets = cards;
return cards;
}
private isSet(cards: number[]): boolean {
this.selectedCards = []; this.selectedCards = [];
axios.post(`http://localhost:5224/api/v1/Games/CheckSet/${this.gameId}`, cards).then((response) => {
this.hand = response.data.newState.hand.map((card: number) => toCard(card));
this.deck = response.data.newState.deck.map((card: number) => toCard(card));
this.fails = response.data.newState.fails;
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;
} }
public async deleteGame(): Promise<void> {
private replaceSet(): void { try {
this.hand.find((c, i) => { await lastValueFrom(this.http.delete<void>(`${this.API_URL}/${this.gameId}`));
if (this.selectedCards.includes(c)) { } catch (error) {
this.hand[i] = this.deck.splice(0, 1)[0]; console.error('Error deleting game', error);
throw error;
} }
});
this.selectedCards = [];
} }
public async deleteGame() { public async showHint(): Promise<void> {
await axios.delete('http://localhost:5224/api/v1/Games/' + this.gameId); try {
await lastValueFrom(this.http.post<void>(`${this.API_URL}/Hint/${this.gameId}`, {}));
this.hints++;
} catch (error) {
console.error('Error showing hint', error);
throw error;
}
} }
} }

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', {
headers: {
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImp0aSI6ImRmNThhYTU3LWZkNzItNGIzYS05OTNmLTY4NjAyNGMzYjdlNSIsImV4cCI6MTc0MjgxODEzOCwiaXNzIjoid2Vzc2VsLmdnIiwiYXVkIjoid2Vzc2VsLmdnIn0.hDf8qcxXeSFQhmgnMzBrH3ZJJMplwZ-1RQwNxeZo5ok'
}
});
const sortedGames = req.data
.sort((a: any, b: any) => new Date(a.startedAt).getTime() - new Date(b.startedAt).getTime()) .sort((a: any, b: any) => new Date(a.startedAt).getTime() - new Date(b.startedAt).getTime())
.reverse(); .reverse();
return sortedGames; return sortedGames;
} catch (error) {
console.error('Error getting games:', error);
throw error;
}
} }
} }