checkpoint

This commit is contained in:
2021-11-10 18:46:29 -06:00
parent 2a3b7b32b4
commit 20f44c8b90
26 changed files with 519 additions and 407 deletions

View File

@@ -7,7 +7,10 @@ using Gameboard.ShogiUI.Sockets.ServiceModels.Types;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace Gameboard.ShogiUI.Sockets.Controllers
@@ -71,10 +74,13 @@ namespace Gameboard.ShogiUI.Sockets.Controllers
{
var user = await gameboardManager.ReadUser(User);
var session = await gameboardRepository.ReadSession(gameName);
if (session == null || user == null || (session.Player1 != user.Name && session.Player2 != user.Name))
if (session == null)
{
throw new UnauthorizedAccessException("User is not seated at this game.");
return NotFound();
}
if (user == null || (session.Player1.Id != user.Id && session.Player2?.Id != user.Id))
{
return Forbid("User is not seated at this game.");
}
var move = request.Move;
@@ -92,15 +98,14 @@ namespace Gameboard.ShogiUI.Sockets.Controllers
}
await communicationManager.BroadcastToPlayers(new MoveResponse
{
BoardState = session.Shogi.ToServiceModel(),
Game = session.ToServiceModel(),
MoveHistory = session.Shogi.MoveHistory.Select(h => h.ToServiceModel()).ToList(),
PlayerPerspective = user.Name == session.Player1 ? WhichPlayer.Player1 : WhichPlayer.Player2
}, session.Player1, session.Player2);
GameName = session.Name,
PlayerName = user.Id
}, session.Player1.Id, session.Player2?.Id);
return Ok();
}
throw new InvalidOperationException("Illegal move.");
return Conflict("Illegal move.");
}
// TODO: Use JWT tokens for guests so they can authenticate and use API routes, too.
//[Route("")]
//public async Task<IActionResult> PostSession([FromBody] PostSession request)
@@ -125,8 +130,8 @@ namespace Gameboard.ShogiUI.Sockets.Controllers
[HttpPost]
public async Task<IActionResult> PostSession([FromBody] PostSession request)
{
var user = await gameboardManager.ReadUser(User);
var session = new Models.SessionMetadata(request.Name, request.IsPrivate, user!.Name);
var user = await ReadUserOrThrow();
var session = new Models.SessionMetadata(request.Name, request.IsPrivate, user!);
var success = await gameboardRepository.CreateSession(session);
if (success)
@@ -134,7 +139,13 @@ namespace Gameboard.ShogiUI.Sockets.Controllers
await communicationManager.BroadcastToAll(new CreateGameResponse
{
Game = session.ToServiceModel(),
PlayerName = user.Name
PlayerName = user.Id
}).ContinueWith(cont =>
{
if (cont.Exception != null)
{
Console.Error.WriteLine("Yep");
}
});
return Ok();
}
@@ -148,29 +159,83 @@ namespace Gameboard.ShogiUI.Sockets.Controllers
[HttpGet("{gameName}")]
public async Task<IActionResult> GetSession([FromRoute] string gameName)
{
var user = await gameboardManager.ReadUser(User);
var user = await ReadUserOrThrow();
var session = await gameboardRepository.ReadSession(gameName);
if (session == null)
{
return NotFound();
}
communicationManager.SubscribeToGame(session, user!.Name);
var response = new GetGameResponse()
communicationManager.SubscribeToGame(session, user!.Id);
var response = new GetSessionResponse()
{
Game = new Models.SessionMetadata(session).ToServiceModel(),
Game = new Models.SessionMetadata(session).ToServiceModel(user),
BoardState = session.Shogi.ToServiceModel(),
MoveHistory = session.Shogi.MoveHistory.Select(_ => _.ToServiceModel()).ToList(),
PlayerPerspective = user.Name == session.Player1 ? WhichPlayer.Player1 : WhichPlayer.Player2
PlayerPerspective = user.Id == session.Player1.Id ? WhichPlayer.Player1 : WhichPlayer.Player2
};
return new JsonResult(response);
}
[HttpGet]
public async Task<IActionResult> GetSessions()
public async Task<GetSessionsResponse> GetSessions()
{
var user = await ReadUserOrThrow();
var sessions = await gameboardRepository.ReadSessionMetadatas();
return new JsonResult(sessions.Select(s => s.ToServiceModel()).ToList());
var sessionsJoinedByUser = sessions
.Where(s => s.IsSeated(user))
.Select(s => s.ToServiceModel())
.ToList();
var sessionsNotJoinedByUser = sessions
.Where(s => !s.IsSeated(user))
.Select(s => s.ToServiceModel())
.ToList();
return new GetSessionsResponse
{
PlayerHasJoinedSessions = new Collection<Game>(sessionsJoinedByUser),
AllOtherSessions = new Collection<Game>(sessionsNotJoinedByUser)
};
}
[HttpPut("{gameName}")]
public async Task<IActionResult> PutJoinSession([FromRoute] string gameName)
{
var user = await ReadUserOrThrow();
var session = await gameboardRepository.ReadSessionMetaData(gameName);
if (session == null)
{
return NotFound();
}
if (session.Player2 != null)
{
return this.Conflict("This session already has two seated players and is full.");
}
session.SetPlayer2(user);
var success = await gameboardRepository.UpdateSession(session);
if (!success) return this.Problem(detail: "Unable to update session.");
var opponentName = user.Id == session.Player1.Id
? session.Player2!.Id
: session.Player1.Id;
await communicationManager.BroadcastToPlayers(new JoinGameResponse
{
GameName = session.Name,
PlayerName = user.Id
}, opponentName);
return Ok();
}
private async Task<Models.User> ReadUserOrThrow()
{
var user = await gameboardManager.ReadUser(User);
if (user == null)
{
throw new UnauthorizedAccessException("Unknown user claims.");
}
return user;
}
}
}

View File

@@ -54,24 +54,21 @@ namespace Gameboard.ShogiUI.Sockets.Controllers
[HttpGet("Token")]
public async Task<IActionResult> GetToken()
{
var identityId = User.UserId();
if (string.IsNullOrWhiteSpace(identityId))
var user = await gameboardManager.ReadUser(User);
if (user == null)
{
if (await gameboardManager.CreateUser(User))
{
user = await gameboardManager.ReadUser(User);
}
}
if (user == null)
{
return Unauthorized();
}
var user = await gameboardManager.ReadUser(User);
if (user == null)
{
user = new User(identityId);
var success = await gameboardRepository.CreateUser(user);
if (!success)
{
return Unauthorized();
}
}
var token = tokenCache.GenerateToken(user.Name);
var token = tokenCache.GenerateToken(user.Id);
return new JsonResult(new GetTokenResponse(token));
}
@@ -79,35 +76,28 @@ namespace Gameboard.ShogiUI.Sockets.Controllers
[AllowAnonymous]
public async Task<IActionResult> GetGuestToken()
{
if (Guid.TryParse(User.UserId(), out Guid webSessionId))
var user = await gameboardManager.ReadUser(User);
if (user == null)
{
var user = await gameboardRepository.ReadGuestUser(webSessionId);
if (user != null)
// Create a guest user.
var newUser = Models.User.CreateGuestUser(Guid.NewGuid().ToString());
var success = await gameboardRepository.CreateUser(newUser);
if (!success)
{
var token = tokenCache.GenerateToken(webSessionId.ToString());
return new JsonResult(new GetGuestTokenResponse(user.Name, token));
return Conflict();
}
}
else
{
// Setup a guest user.
var newSessionId = Guid.NewGuid();
var user = new User(Guid.NewGuid().ToString(), newSessionId);
if (await gameboardRepository.CreateUser(user))
{
var identity = user.CreateGuestUserIdentity();
await this.HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(identity),
authenticationProps
);
var token = tokenCache.GenerateToken(newSessionId.ToString());
return new JsonResult(new GetGuestTokenResponse(user.Name, token));
}
var identity = newUser.CreateClaimsIdentity();
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(identity),
authenticationProps
);
user = newUser;
}
return Unauthorized();
var token = tokenCache.GenerateToken(user.Id.ToString());
return this.Ok(new GetGuestTokenResponse(user.Id, user.DisplayName, token));
}
}
}