diff --git a/Shogi.Api/Controllers/SessionsController.cs b/Shogi.Api/Controllers/SessionsController.cs index 1b545c7..1d167c4 100644 --- a/Shogi.Api/Controllers/SessionsController.cs +++ b/Shogi.Api/Controllers/SessionsController.cs @@ -15,134 +15,146 @@ namespace Shogi.Api.Controllers; [Authorize] public class SessionsController : ControllerBase { - private readonly ISocketConnectionManager communicationManager; - private readonly IModelMapper mapper; - private readonly ISessionRepository sessionRepository; - private readonly IQueryRespository queryRespository; - private readonly ILogger logger; + private readonly ISocketConnectionManager communicationManager; + private readonly IModelMapper mapper; + private readonly ISessionRepository sessionRepository; + private readonly IQueryRespository queryRespository; + private readonly ILogger logger; - public SessionsController( - ISocketConnectionManager communicationManager, - IModelMapper mapper, - ISessionRepository sessionRepository, - IQueryRespository queryRespository, - ILogger logger) - { - this.communicationManager = communicationManager; - this.mapper = mapper; - this.sessionRepository = sessionRepository; - this.queryRespository = queryRespository; - this.logger = logger; - } + public SessionsController( + ISocketConnectionManager communicationManager, + IModelMapper mapper, + ISessionRepository sessionRepository, + IQueryRespository queryRespository, + ILogger logger) + { + this.communicationManager = communicationManager; + this.mapper = mapper; + this.sessionRepository = sessionRepository; + this.queryRespository = queryRespository; + this.logger = logger; + } - [HttpPost] - public async Task CreateSession([FromBody] CreateSessionCommand request) - { - var userId = User.GetShogiUserId(); - var session = new Domain.Session(request.Name, userId); - try - { - await sessionRepository.CreateSession(session); - } - catch (SqlException e) - { - logger.LogError(exception: e, message: "Uh oh"); - return this.Conflict(); - } + [HttpPost] + public async Task CreateSession([FromBody] CreateSessionCommand request) + { + var userId = User.GetShogiUserId(); + var session = new Domain.Session(request.Name, userId); + try + { + await sessionRepository.CreateSession(session); + } + catch (SqlException e) + { + logger.LogError(exception: e, message: "Uh oh"); + return this.Conflict(); + } - await communicationManager.BroadcastToAll(new SessionCreatedSocketMessage()); - return CreatedAtAction(nameof(CreateSession), new { sessionName = request.Name }, null); - } + await communicationManager.BroadcastToAll(new SessionCreatedSocketMessage()); + return CreatedAtAction(nameof(CreateSession), new { sessionName = request.Name }, null); + } - [HttpDelete("{name}")] - public async Task DeleteSession(string name) - { - var userId = User.GetShogiUserId(); - var session = await sessionRepository.ReadSession(name); + [HttpDelete("{name}")] + public async Task DeleteSession(string name) + { + var userId = User.GetShogiUserId(); + var session = await sessionRepository.ReadSession(name); - if (session == null) return this.NoContent(); + if (session == null) return this.NoContent(); - if (session.Player1 == userId) - { - await sessionRepository.DeleteSession(name); - return this.NoContent(); - } + if (session.Player1 == userId) + { + await sessionRepository.DeleteSession(name); + return this.NoContent(); + } - return this.StatusCode(StatusCodes.Status403Forbidden, "Cannot delete sessions created by others."); - } + return this.StatusCode(StatusCodes.Status403Forbidden, "Cannot delete sessions created by others."); + } - [HttpGet("PlayerCount")] - public async Task> GetSessionsPlayerCount() - { - var sessions = await this.queryRespository.ReadSessionPlayerCount(); + [HttpGet("PlayerCount")] + public async Task> GetSessionsPlayerCount() + { + var sessions = await this.queryRespository.ReadSessionPlayerCount(); - return Ok(new ReadSessionsPlayerCountResponse - { - PlayerHasJoinedSessions = Array.Empty(), - AllOtherSessions = sessions.ToList() - }); - } + return Ok(new ReadSessionsPlayerCountResponse + { + PlayerHasJoinedSessions = Array.Empty(), + AllOtherSessions = sessions.ToList() + }); + } - [HttpGet("{name}")] - public async Task> GetSession(string name) - { - var session = await sessionRepository.ReadSession(name); - if (session == null) return this.NotFound(); + [HttpGet("{name}")] + public async Task> GetSession(string name) + { + var session = await sessionRepository.ReadSession(name); + if (session == null) return this.NotFound(); - return new ReadSessionResponse - { - Session = new Session - { - BoardState = new BoardState - { - Board = session.Board.BoardState.State.ToContract(), - Player1Hand = session.Board.BoardState.Player1Hand.ToContract(), - Player2Hand = session.Board.BoardState.Player2Hand.ToContract(), - PlayerInCheck = session.Board.BoardState.InCheck?.ToContract(), - WhoseTurn = session.Board.BoardState.WhoseTurn.ToContract() - }, - Player1 = session.Player1, - Player2 = session.Player2, - SessionName = session.Name - } - }; - } + return new ReadSessionResponse + { + Session = new Session + { + BoardState = new BoardState + { + Board = session.Board.BoardState.State.ToContract(), + Player1Hand = session.Board.BoardState.Player1Hand.ToContract(), + Player2Hand = session.Board.BoardState.Player2Hand.ToContract(), + PlayerInCheck = session.Board.BoardState.InCheck?.ToContract(), + WhoseTurn = session.Board.BoardState.WhoseTurn.ToContract() + }, + Player1 = session.Player1, + Player2 = session.Player2, + SessionName = session.Name + } + }; + } - [HttpPatch("{sessionName}/Move")] - public async Task Move([FromRoute] string sessionName, [FromBody] MovePieceCommand command) - { - var userId = User.GetShogiUserId(); - var session = await sessionRepository.ReadSession(sessionName); + [HttpPut("{name}/Join")] + public async Task JoinSession(string name) + { + var session = await sessionRepository.ReadSession(name); + if (session == null) return this.NotFound(); - if (session == null) return this.NotFound("Shogi session does not exist."); + if (string.IsNullOrEmpty(session.Player2)) + { + session.AddPlayer2(User.GetShogiUserId()); + } + } - if (!session.IsSeated(userId)) return this.StatusCode(StatusCodes.Status403Forbidden, "Player is not a member of the Shogi session."); + [HttpPatch("{sessionName}/Move")] + public async Task Move([FromRoute] string sessionName, [FromBody] MovePieceCommand command) + { + var userId = User.GetShogiUserId(); + var session = await sessionRepository.ReadSession(sessionName); - try - { - if (command.PieceFromHand.HasValue) - { - session.Board.Move(command.PieceFromHand.Value.ToDomain(), command.To); - } - else - { - session.Board.Move(command.From!, command.To, command.IsPromotion ?? false); - } - } - catch (InvalidOperationException e) - { - return this.Conflict(e.Message); - } - await sessionRepository.CreateMove(sessionName, command); - await communicationManager.BroadcastToPlayers( - new PlayerHasMovedMessage - { - PlayerName = userId, - SessionName = session.Name, - }, - session.Player1, - session.Player2); + if (session == null) return this.NotFound("Shogi session does not exist."); - return this.NoContent(); - } + if (!session.IsSeated(userId)) return this.StatusCode(StatusCodes.Status403Forbidden, "Player is not a member of the Shogi session."); + + try + { + if (command.PieceFromHand.HasValue) + { + session.Board.Move(command.PieceFromHand.Value.ToDomain(), command.To); + } + else + { + session.Board.Move(command.From!, command.To, command.IsPromotion ?? false); + } + } + catch (InvalidOperationException e) + { + return this.Conflict(e.Message); + } + await sessionRepository.CreateMove(sessionName, command); + await communicationManager.BroadcastToPlayers( + new PlayerHasMovedMessage + { + PlayerName = userId, + SessionName = session.Name, + }, + session.Player1, + session.Player2); + + return this.NoContent(); + } } diff --git a/Shogi.Domain/Aggregates/Session.cs b/Shogi.Domain/Aggregates/Session.cs index 1c59c90..4ae8e02 100644 --- a/Shogi.Domain/Aggregates/Session.cs +++ b/Shogi.Domain/Aggregates/Session.cs @@ -4,28 +4,29 @@ namespace Shogi.Domain; public class Session { - public Session( - string name, - string player1Name) - { - Name = name; - Player1 = player1Name; - Board = new(BoardState.StandardStarting); - } + public Session( + string name, + string player1Name) + { + Name = name; + Player1 = player1Name; + Board = new(BoardState.StandardStarting); + } - public string Name { get; } - public ShogiBoard Board { get; } - public string Player1 { get; } - public string? Player2 { get; private set; } + public string Name { get; } + public ShogiBoard Board { get; } + public string Player1 { get; } + public string? Player2 { get; private set; } - public void AddPlayer2(string player2Name) - { - if (Player2 != null) throw new InvalidOperationException("Player 2 already exists while trying to add a second player."); - Player2 = player2Name; - } + public void AddPlayer2(string player2Name) + { + if (Player2 != null) throw new InvalidOperationException("Player 2 already exists while trying to add a second player."); + if (Player1.Equals(player2Name, StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException("Player 2 must be different from Player 1"); + Player2 = player2Name; + } - public bool IsSeated(string playerName) - { - return Player1 == playerName || Player2 == playerName; - } + public bool IsSeated(string playerName) + { + return Player1 == playerName || Player2 == playerName; + } }