diff --git a/WebApi/DataManagers/PlayerDataManager.cs b/WebApi/DataManagers/PlayerDataManager.cs index 90eeee7..4d3dde3 100644 --- a/WebApi/DataManagers/PlayerDataManager.cs +++ b/WebApi/DataManagers/PlayerDataManager.cs @@ -91,5 +91,10 @@ namespace DataManagers { return (await manager.removePlayer(id))?.ToModel(); } + + public async Task updatePlayer(int id, Player player) + { + return (await manager.updatePlayer(id, player.ToEntity()))?.ToModel(); + } } } diff --git a/WebApi/DataManagers/QuestionDataManager.cs b/WebApi/DataManagers/QuestionDataManager.cs index f51a566..b677c49 100644 --- a/WebApi/DataManagers/QuestionDataManager.cs +++ b/WebApi/DataManagers/QuestionDataManager.cs @@ -54,35 +54,22 @@ namespace DataManagers return await Task.FromResult((await manager.getQuestion(id))?.ToModel()); } + public async Task getQuestion(string content) + { + return (await manager.getQuestion(content))?.ToModel(); + } + public async Task<(int nbPages, IEnumerable? questions)> getQuestions(int nb, int count, QuestionOrderCriteria orderCriteria = QuestionOrderCriteria.ById) { - List? tmp = new List(); var res = await manager.getQuestions(nb, count, orderCriteria); - if (res.questions == null) tmp = null; - else - { - foreach (var item in res.questions) - { - tmp.Add(item.ToModel()); - } - } - return await Task.FromResult<(int nbPages, IEnumerable? questions)>((res.nbPages, tmp)); + return (res.nbPages, res.questions?.Select(q => q.ToModel())); } public async Task<(int nbPages, IEnumerable? questions)?> getQuestionsByChapterAndDifficulty(int idChapter, int difficulty, int nb, int count, QuestionOrderCriteria orderCriteria = QuestionOrderCriteria.ById) { - List? tmp = new List(); var res = await manager.getQuestionsByChapterAndDifficulty(idChapter, difficulty, nb, count, orderCriteria); - if (res == null) return await Task.FromResult<(int nbPages, IEnumerable? questions)?>(null); - if (res.Value.questions == null) tmp = null; - else - { - foreach (var item in res.Value.questions) - { - tmp.Add(item.ToModel()); - } - } - return await Task.FromResult<(int nbPages, IEnumerable? questions)>((res.Value.nbPages, tmp)); + if (res == null) return null; + return (res?.nbPages ?? getNbQuestions()/count, res?.questions?.Select(q => q.ToModel())); } public async Task removeQuestion(Question question) diff --git a/WebApi/EntityManagers/PlayerEntityManager.cs b/WebApi/EntityManagers/PlayerEntityManager.cs index a64db9d..a1ce3c4 100644 --- a/WebApi/EntityManagers/PlayerEntityManager.cs +++ b/WebApi/EntityManagers/PlayerEntityManager.cs @@ -99,5 +99,16 @@ namespace EntityManagers await dbContext.SaveChangesAsync(); return await Task.FromResult(tmp); } + + public async Task updatePlayer(int id, PlayerEntity player) + { + if (dbContext.Players.Where(p => p.Nickname == player.Nickname).Count() > 0) return null; + var tmp = await getPlayer(id); + if (tmp == null) return null; + tmp.Nickname = player.Nickname; + tmp.HashedPassword = player.HashedPassword; + await dbContext.SaveChangesAsync(); + return tmp; + } } } diff --git a/WebApi/EntityManagers/QuestionEntityManager.cs b/WebApi/EntityManagers/QuestionEntityManager.cs index 1ea7c39..3d2c5ca 100644 --- a/WebApi/EntityManagers/QuestionEntityManager.cs +++ b/WebApi/EntityManagers/QuestionEntityManager.cs @@ -14,6 +14,8 @@ namespace EntityManagers { public class QuestionEntityManager(MyDbContext dbContext) : IQuestionManager { + private const int secondDifficultyBorn = 50; + private const int thirdDifficultyBorn = 150; private MyDbContext dbContext = dbContext; private IQueryable trier(IQueryable query, QuestionOrderCriteria orderCriteria) @@ -36,14 +38,14 @@ namespace EntityManagers public async Task addQuestion(QuestionEntity question) { - var tmp = await dbContext.Questions.Where(q => q.Equals(question)).FirstOrDefaultAsync(); + var tmp = await getQuestion(question.Content); if (tmp != null) // <=> he already exist { return tmp!; } dbContext.Questions.Add(question); await dbContext.SaveChangesAsync(); - return await dbContext.Questions.Where(q => q.Equals(question)).FirstAsync(); + return await dbContext.Questions.SingleAsync(q => q.Content == question.Content); } public async Task> addQuestions(IEnumerable questions) @@ -76,29 +78,29 @@ namespace EntityManagers public async Task<(int nbPages, IEnumerable? questions)?> getQuestionsByChapterAndDifficulty(int idChapter, int difficulty, int nb, int count, QuestionOrderCriteria orderCriteria = QuestionOrderCriteria.ById) { - if (nb < 0 || count < 0 || difficulty < 1 || difficulty > 3 || !dbContext.Chapters.Where(c => c.Id == idChapter).AnyAsync().Result) + if (nb < 0 || count < 0 || difficulty < 1 || difficulty > 3 || !(await dbContext.Chapters.Where(c => c.Id == idChapter).AnyAsync())) return await Task.FromResult<(int nbPages, IEnumerable? questions)?>(null); int nbEl = getNbQuestions(); if (nb > nbEl / count) return await Task.FromResult<(int nbPages, IEnumerable? questions)?>((nbEl / count, null)); - var tmp = trier(dbContext.Questions, orderCriteria); + var tmp = trier(dbContext.Questions.Where(q => q.IdChapter == idChapter && q.Difficulty == difficulty), orderCriteria); return await Task.FromResult<(int nbPages, IEnumerable? questions)?>((nbEl / count, tmp.Skip((nb - 1) * count).Take(count))); } public async Task removeQuestion(QuestionEntity question) { - var tmp = await dbContext.Questions.Where(q => q.Equals(question)).FirstOrDefaultAsync(); + var tmp = await getQuestion(question.Content); if (tmp == null) return tmp; dbContext.Questions.Remove(tmp); await dbContext.SaveChangesAsync(); return tmp; } - public Task removeQuestion(int id) + public async Task removeQuestion(int id) { - var tmp = getQuestion(id); - if (tmp.Result == null) return tmp; - dbContext.Questions.Remove(tmp.Result); - dbContext.SaveChangesAsync(); + var tmp = await getQuestion(id); + if (tmp == null) return tmp; + dbContext.Questions.Remove(tmp); + await dbContext.SaveChangesAsync(); return tmp; } @@ -121,10 +123,15 @@ namespace EntityManagers if (tmp.Result == null) return await tmp; tmp.Result.NbFalls++; int nbFalls = tmp.Result.NbFalls; - if (nbFalls == 50) tmp.Result.Difficulty = 2; - if (nbFalls == 150) tmp.Result.Difficulty = 3; + if (nbFalls == secondDifficultyBorn) tmp.Result.Difficulty = 2; + if (nbFalls == thirdDifficultyBorn) tmp.Result.Difficulty = 3; await dbContext.SaveChangesAsync(); return await tmp; } + + public async Task getQuestion(string content) + { + return await dbContext.Questions.SingleOrDefaultAsync(q => q.Content == content); + } } } diff --git a/WebApi/ManagerInterfaces/IPlayerManager.cs b/WebApi/ManagerInterfaces/IPlayerManager.cs index 6fd5530..4649dde 100644 --- a/WebApi/ManagerInterfaces/IPlayerManager.cs +++ b/WebApi/ManagerInterfaces/IPlayerManager.cs @@ -115,5 +115,18 @@ namespace ManagerInterfaces /// or null if the player does not exist /// public Task getMaxScorePlayer(int id); + + /// + /// update a player + /// + /// the id of the player to update + /// a player class which contains all properties to changes + /// + /// the player changed or null + /// if the id doesn't exist or + /// if the player nickname is + /// already used + /// + public Task updatePlayer(int id, T player); } } diff --git a/WebApi/ManagerInterfaces/IQuestionManager.cs b/WebApi/ManagerInterfaces/IQuestionManager.cs index 4bbe62c..64fa8a6 100644 --- a/WebApi/ManagerInterfaces/IQuestionManager.cs +++ b/WebApi/ManagerInterfaces/IQuestionManager.cs @@ -69,6 +69,15 @@ namespace ManagerInterfaces /// public Task getQuestion(int id); /// + /// get a question with a content + /// + /// the content of the question + /// + /// the question that corresponde + /// to the content or null if there isn't any + /// + public Task getQuestion(string content); + /// /// modified a question with an id /// /// the id of the question diff --git a/WebApi/ServiceManagers/PlayerServiceManager.cs b/WebApi/ServiceManagers/PlayerServiceManager.cs index 1475d90..62b531c 100644 --- a/WebApi/ServiceManagers/PlayerServiceManager.cs +++ b/WebApi/ServiceManagers/PlayerServiceManager.cs @@ -86,5 +86,10 @@ namespace ServiceManagers { return (await manager.removePlayer(id))?.ToDto(); } + + public async Task updatePlayer(int id, PlayerDto player) + { + return (await manager.updatePlayer(id, player.ToModel()))?.ToDto(); + } } } diff --git a/WebApi/ServiceManagers/QuestionServiceManager.cs b/WebApi/ServiceManagers/QuestionServiceManager.cs index 229135f..2c9605b 100644 --- a/WebApi/ServiceManagers/QuestionServiceManager.cs +++ b/WebApi/ServiceManagers/QuestionServiceManager.cs @@ -51,35 +51,22 @@ namespace ServiceManagers return await Task.FromResult((await manager.getQuestion(id))?.ToDto()); } + public async Task getQuestion(string content) + { + return (await manager.getQuestion(content))?.ToDto(); + } + public async Task<(int nbPages, IEnumerable? questions)> getQuestions(int nb, int count, QuestionOrderCriteria orderCriteria = QuestionOrderCriteria.ById) { - List? tmp = new List(); var res = await manager.getQuestions(nb, count, orderCriteria); - if (res.questions == null) tmp = null; - else - { - foreach (var item in res.questions) - { - tmp.Add(item.ToDto()); - } - } - return await Task.FromResult<(int nbPages, IEnumerable? questions)>((res.nbPages, tmp)); + return (res.nbPages, res.questions?.Select(q => q.ToDto())); } public async Task<(int nbPages, IEnumerable? questions)?> getQuestionsByChapterAndDifficulty(int idChapter, int difficulty, int nb, int count, QuestionOrderCriteria orderCriteria = QuestionOrderCriteria.ById) { - List? tmp = new List(); var res = await manager.getQuestionsByChapterAndDifficulty(idChapter, difficulty, nb, count, orderCriteria); - if (res == null) return await Task.FromResult<(int nbPages, IEnumerable? questions)?>(null); - if (res.Value.questions == null) tmp = null; - else - { - foreach (var item in res.Value.questions) - { - tmp.Add(item.ToDto()); - } - } - return await Task.FromResult<(int nbPages, IEnumerable? questions)>((res.Value.nbPages, tmp)); + if (res == null) return null; + return (res?.nbPages ?? getNbQuestions() / count, res?.questions?.Select(q => q.ToDto())); } public async Task removeQuestion(QuestionDto question) diff --git a/WebApi/WebApi/Controllers/FrontController.cs b/WebApi/WebApi/Controllers/FrontController.cs index f264a5d..d8c7227 100644 --- a/WebApi/WebApi/Controllers/FrontController.cs +++ b/WebApi/WebApi/Controllers/FrontController.cs @@ -2,15 +2,22 @@ using DbConnectionLibrairie; using DTOs; using EntityManagers; +using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using OrderCriterias; using ServiceManagers; +using RouteAttribute = Microsoft.AspNetCore.Mvc.RouteAttribute; namespace WebApi.Controllers { + [ApiVersion("1.0")] + [Route("api/v{version:apiversion}")] public class FrontController { + [Inject] + public MyDbContext dbContext { get; set; } + // all secondary controllers private AdministratorController administratorController; private ChapterController chapterController; @@ -19,7 +26,6 @@ namespace WebApi.Controllers private QuestionController questionController; public FrontController( - MyDbContext dbContext, Logger logAdmin, Logger logChapter, Logger logLobby, @@ -34,12 +40,12 @@ namespace WebApi.Controllers new LobbyServiceManager(new LobbyDataManager(new LobbyEntityManager(dbContext))), new PlayerServiceManager(new PlayerDataManager(new PlayerEntityManager(dbContext))), new QuestionServiceManager(new QuestionDataManager(new QuestionEntityManager(dbContext))) - ) ; + ); administratorController = new AdministratorController(unity, logAdmin); chapterController = new ChapterController(unity, logChapter); lobbyController = new LobbyController(unity, logLobby); - //playerController = new PlayerController(unity, logPlayer); - //questionController = new QuestionController(unity, logQuestion); + playerController = new PlayerController(unity, logPlayer); + questionController = new QuestionController(unity, logQuestion); } /// @@ -357,5 +363,234 @@ namespace WebApi.Controllers public async Task GetLobby(int id) => await lobbyController.GetLobby(id); + /// + /// add a player + /// + /// the player to add + /// + /// status code : + /// 200 if the player is added + /// 202 if the player is added + /// 208 if the player was already in the database + /// 500 if there was an internal error that doesn't allow to continue + /// return content : + /// no content when status code = 200 + /// player added when status code = 202 + /// player already in the database that equals the one we wanted to add when status code = 208 + /// no content when status code = 500 + /// + [HttpPost("add/player")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status202Accepted)] + [ProducesResponseType(StatusCodes.Status208AlreadyReported)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + public async Task PostPlayer([FromBody] PlayerDto player) + => await playerController.PostPlayer(player); + + /// + /// get a part of all players + /// + /// the actual page + /// number of T element in a page + /// the order criteria + /// + /// status code : + /// 200 if we got a set + /// 204 if we got an empty set + /// 400 if we got nothing + /// + /// return content : + /// a tuple of the number of page and + /// all players in the database for + /// the page nb if status code = 200 + /// the number of page for count element if status code = 204 + /// nothing if status code = 400 + /// + [HttpGet("all/players")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + public async Task GetSomePlayers([FromQuery] int page, int count = 10, PlayerOrderCriteria orderCriteria = PlayerOrderCriteria.ById) + => await playerController.GetSomePlayers(page, count, orderCriteria); + + /// + /// delete a player + /// + /// the id of the player to delete + /// + /// + /// status code : + /// 200 if the player is removed + /// 204 if the player is removed + /// 400 if the id is incorrect + /// 500 if there was an internal error that doesn't allow to continue + /// return content : + /// aministrator deleted when status code = 200 + /// no content when status code = 204 + /// no content when status code = 400 + /// no content when status code = 500 + /// + [HttpDelete("delete/player")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + public async Task DeletePlayer(int id) + => await playerController.DeletePlayer(id); + + /// + /// get a player + /// + /// the id of the player + /// + /// status code : + /// 200 when we got a player + /// 204 when we got null + /// + /// return content : + /// the player that correspond to the id when status code = 200 + /// nothing when status code = 204 + /// + [HttpGet("player")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status204NoContent)] + public async Task GetPlayer(int id) + => await playerController.GetPlayer(id); + + /// + /// update a player + /// + /// the id of the player + /// + /// status code : + /// 200 when we got a player + /// 204 when we got null + /// 208 when the nickname is already used + /// return content : + /// the player that correspond to the id when status code = 200 + /// nothing when status code = 204 + /// the player which have this nickname when status code = 208 + /// + [HttpPut("update/player")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status208AlreadyReported)] + public async Task PutPlayer([FromQuery] int id, [FromBody] PlayerDto player) + => await playerController.PutPlayer(id, player); + + /// + /// add a question + /// + /// the question to add + /// + /// status code : + /// 200 if the question is added + /// 202 if the question is added + /// 208 if the question was already in the database + /// 500 if there was an internal error that doesn't allow to continue + /// return content : + /// no content when status code = 200 + /// question added when status code = 202 + /// question already in the database that equals the one we wanted to add when status code = 208 + /// no content when status code = 500 + /// + [HttpPost("add/question")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status202Accepted)] + [ProducesResponseType(StatusCodes.Status208AlreadyReported)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + public async Task PostQuestion([FromBody] QuestionDto question) + => await questionController.PostQuestion(question); + + /// + /// get a part of all questions + /// + /// the actual page + /// number of T element in a page + /// the order criteria + /// + /// status code : + /// 200 if we got a set + /// 204 if we got an empty set + /// 400 if we got nothing + /// + /// return content : + /// a tuple of the number of page and + /// all questions in the database for + /// the page nb if status code = 200 + /// the number of page for count element if status code = 204 + /// nothing if status code = 400 + /// + [HttpGet("questions/all")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task GetSomeQuestions([FromQuery] int page, int count = 10, QuestionOrderCriteria orderCriteria = QuestionOrderCriteria.ById) + => await questionController.GetSomeQuestions(page, count, orderCriteria); + + /// + /// delete a question + /// + /// the id of the question to delete + /// + /// status code : + /// 200 if the question is removed + /// 204 if the question is removed + /// 400 if the id is incorrect + /// 500 if there was an internal error that doesn't allow to continue + /// return content : + /// aministrator deleted when status code = 200 + /// no content when status code = 204 + /// no content when status code = 400 + /// no content when status code = 500 + /// + [HttpDelete("delete/question")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + public async Task DeleteQuestion([FromQuery] int id) + => await questionController.DeleteQuestion(id); + + /// + /// get a question + /// + /// the id of the question + /// + /// status code : + /// 200 when we got a question + /// 204 when we got null + /// + /// return content : + /// the question that correspond to the id when status code = 200 + /// nothing when status code = 204 + /// + [HttpGet("question")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status204NoContent)] + public async Task GetQuestion([FromQuery] int id) + => await questionController.GetQuestion(id); + + /// + /// update a question + /// + /// the id of the question + /// + /// status code : + /// 200 when we got a question + /// 204 when we got null + /// 208 when the nickname is already used + /// return content : + /// the question that correspond to the id when status code = 200 + /// nothing when status code = 204 + /// the question which have this nickname when status code = 208 + /// + [HttpPut] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status208AlreadyReported)] + public async Task PutQuestion(int id, QuestionDto question) + => await questionController.PutQuestion(id, question); + } } diff --git a/WebApi/WebApi/Controllers/PlayerController.cs b/WebApi/WebApi/Controllers/PlayerController.cs index 696c6a9..fcd2f0f 100644 --- a/WebApi/WebApi/Controllers/PlayerController.cs +++ b/WebApi/WebApi/Controllers/PlayerController.cs @@ -1,6 +1,247 @@ -namespace WebApi.Controllers +using DTOs; +using Microsoft.AspNetCore.Mvc; +using OrderCriterias; + +namespace WebApi.Controllers { - public class PlayerController + public class PlayerController : ControllerBase { + private Unit unity; + + private readonly Logger logger; + + public PlayerController(Unit unit, Logger logger) + { + this.unity = unit; + this.logger = logger; + } + + /// + /// add a player + /// + /// the player to add + /// + /// status code : + /// 200 if the player is added + /// 202 if the player is added + /// 208 if the player was already in the database + /// 500 if there was an internal error that doesn't allow to continue + /// return content : + /// no content when status code = 200 + /// player added when status code = 202 + /// player already in the database that equals the one we wanted to add when status code = 208 + /// no content when status code = 500 + /// + public async Task PostPlayer(PlayerDto player) + { + int count = unity.getNbPlayers(); // count : number of elements before opperation + var tmp = await unity.addPlayer(player); // tmp : player recieve by the addPlayer method + if (unity.getNbPlayers() == count) // <=> not added + { + if (tmp.Nickname == player.Nickname) + { + // it was already in the database + logger.LogInformation(message: $"want to add a player already in the database : {tmp.ToString()}"); + return StatusCode(208, tmp); + } + else + { + // we recieve a player already in the database + // that should be equal to the player that we + // wanted to add but it isn't + logger.LogCritical(message: "controller's add fail (already in the database) but\nplayer" + + $" recieve isn't the same as the one we wanted to add.\n" + + $"Player recieve : {tmp.ToString()}\nplayer to add : {player.ToString()}"); + return StatusCode(500); + } + } + // added + if (tmp.Nickname == player.Nickname) + { + logger.LogTrace(message: $"player added : {tmp.ToString()}"); + // the player has been added and we recieved him + return StatusCode(202, tmp); + } + else + { + // the player may be added but we do not recieved him + try + { + if (unity.getPlayer(player.Nickname) != null) + { + // he is added + logger.LogError(message: $"player added but not recieved"); + return Ok(); // not 202 to make a difference between 2 cases + } + else + { + // he is not added + logger.LogCritical(message: "player that we wanted to add not added\nand we have added another one"); + if (unity.getPlayer(player.Nickname) == null) // <=> not added + return StatusCode(500); + } + } + catch (Exception) + { + return StatusCode(500); + } + } + logger.LogError(message: "this case should not append"); + return StatusCode(500); + } + + /// + /// get a part of all players + /// + /// the actual page + /// number of T element in a page + /// the order criteria + /// + /// status code : + /// 200 if we got a set + /// 204 if we got an empty set + /// 400 if we got nothing + /// + /// return content : + /// a tuple of the number of page and + /// all players in the database for + /// the page nb if status code = 200 + /// the number of page for count element if status code = 204 + /// nothing if status code = 400 + /// + public async Task GetSomePlayers(int page, int count = 10, PlayerOrderCriteria orderCriteria = PlayerOrderCriteria.ById) + { + var tmp = await unity.getPlayers(page, count, orderCriteria); + if (tmp.players == null) + { + logger.LogInformation(message: "get player : bad request (page or/and count incorrect)"); + return BadRequest(tmp.nbPages); + } + else if (tmp.players.Count() == 0) + { + logger.LogWarning(message: $"get player : no content. number of element : {unity.getNbPlayers()}, page wanted : {page}, number of elements in a page : {count}"); + return NoContent(); + } + else + { + logger.LogTrace(message: $"get players : page = {page}, count = {count}, order criteria = {orderCriteria switch + { + PlayerOrderCriteria.ById => "byId", + PlayerOrderCriteria.ByNickname => "byNickname", + _ => "none" + }}"); + return Ok(tmp); + } + } + + /// + /// delete a player + /// + /// the id of the player to delete + /// + /// + /// status code : + /// 200 if the player is removed + /// 204 if the player is removed + /// 400 if the id is incorrect + /// 500 if there was an internal error that doesn't allow to continue + /// return content : + /// aministrator deleted when status code = 200 + /// no content when status code = 204 + /// no content when status code = 400 + /// no content when status code = 500 + /// + public async Task DeletePlayer(int id) + { + if (id < 0) + { + logger.LogError("want to delete a player with an id less than 0"); + return BadRequest(); + } + int count = unity.getNbPlayers(); // count : number of elements before opperation + var tmp = await unity.removePlayer(id); + if (tmp == null) // we don't recieve the player + { + if (unity.getNbPlayers() == count) // he is not deleted + { + if (unity.getPlayer(id) != null) + { + logger.LogCritical(message: "remove player fail : player not removed and not recieved"); + return StatusCode(500); + } + else + { + logger.LogInformation(message: "trying to remove a player with an id who don't exist"); + return BadRequest(); + } + } + else // he may be deleted + { + if (unity.getPlayer(id) == null) // he must be deleted + { + logger.LogError(message: "player removed but not returned"); + return NoContent(); + } + else // he is not deleted + { + logger.LogCritical(message: "remove player fail : player to remove not remove\ninstead, anotherone is deleted and we recieved nothing"); + return StatusCode(500); + } + } + } + if (unity.getNbPlayers() == count) + { + // <=> we have recieved a player which should be deleted + // but since we have the same number of player than + // before deletion, it isn't deleted + logger.LogCritical(message: $"player \"{tmp.ToString()}\"should be delete but it isn't"); + return StatusCode(500); + } + logger.LogTrace(message: $"player removed {tmp.ToString()}"); + return Ok(tmp); + } + + /// + /// get a player + /// + /// the id of the player + /// + /// status code : + /// 200 when we got a player + /// 204 when we got null + /// + /// return content : + /// the player that correspond to the id when status code = 200 + /// nothing when status code = 204 + /// + public async Task GetPlayer(int id) + { + var tmp = await unity.getPlayer(id); + if (tmp == null) return NoContent(); + return Ok(tmp); + } + + /// + /// update a player + /// + /// the id of the player + /// + /// status code : + /// 200 when we got a player + /// 204 when we got null + /// 208 when the nickname is already used + /// return content : + /// the player that correspond to the id when status code = 200 + /// nothing when status code = 204 + /// the player which have this nickname when status code = 208 + /// + public async Task PutPlayer(int id, PlayerDto player) + { + var tmp = await unity.getPlayer(player.Nickname); + if (tmp != null) return StatusCode(208); + tmp = await unity.updatePlayer(id, player); + if (tmp == null) return NoContent(); + return Ok(tmp); + } } } diff --git a/WebApi/WebApi/Controllers/QuestionController.cs b/WebApi/WebApi/Controllers/QuestionController.cs index 58b51cd..245b9b7 100644 --- a/WebApi/WebApi/Controllers/QuestionController.cs +++ b/WebApi/WebApi/Controllers/QuestionController.cs @@ -1,6 +1,249 @@ -namespace WebApi.Controllers +using DTOs; +using Microsoft.AspNetCore.Mvc; +using OrderCriterias; + +namespace WebApi.Controllers { - public class QuestionController + public class QuestionController : ControllerBase { + private Unit unity; + + private readonly Logger logger; + + public QuestionController(Unit unit, Logger logger) + { + this.unity = unit; + this.logger = logger; + } + + /// + /// add a question + /// + /// the question to add + /// + /// status code : + /// 200 if the question is added + /// 202 if the question is added + /// 208 if the question was already in the database + /// 500 if there was an internal error that doesn't allow to continue + /// return content : + /// no content when status code = 200 + /// question added when status code = 202 + /// question already in the database that equals the one we wanted to add when status code = 208 + /// no content when status code = 500 + /// + public async Task PostQuestion(QuestionDto question) + { + int count = unity.getNbQuestions(); // count : number of elements before opperation + var tmp = await unity.addQuestion(question); // tmp : question recieve by the addQuestion method + if (unity.getNbQuestions() == count) // <=> not added + { + if (tmp.Content == question.Content) + { + // it was already in the database + logger.LogInformation(message: $"want to add a question already in the database : {tmp.ToString()}"); + return StatusCode(208, tmp); + } + else + { + // we recieve a question already in the database + // that should be equal to the question that we + // wanted to add but it isn't + logger.LogCritical(message: "controller's add fail (already in the database) but\nquestion" + + $" recieve isn't the same as the one we wanted to add.\n" + + $"Question recieve : {tmp.ToString()}\nquestion to add : {question.ToString()}"); + return StatusCode(500); + } + } + // added + if (tmp.Content == question.Content) + { + logger.LogTrace(message: $"question added : {tmp.ToString()}"); + // the question has been added and we recieved him + return StatusCode(202, tmp); + } + else + { + // the question may be added but we do not recieved him + try + { + if (unity.getQuestion(question.Content) != null) + { + // he is added + logger.LogError(message: $"question added but not recieved"); + return Ok(); // not 202 to make a difference between 2 cases + } + else + { + // he is not added + logger.LogCritical(message: "question that we wanted to add not added\nand we have added another one"); + if (unity.getQuestion(question.Content) == null) // <=> not added + return StatusCode(500); + } + } + catch (Exception) + { + return StatusCode(500); + } + } + logger.LogError(message: "this case should not append"); + return StatusCode(500); + } + + /// + /// get a part of all questions + /// + /// the actual page + /// number of T element in a page + /// the order criteria + /// + /// status code : + /// 200 if we got a set + /// 204 if we got an empty set + /// 400 if we got nothing + /// + /// return content : + /// a tuple of the number of page and + /// all questions in the database for + /// the page nb if status code = 200 + /// the number of page for count element if status code = 204 + /// nothing if status code = 400 + /// + public async Task GetSomeQuestions(int page, int count = 10, QuestionOrderCriteria orderCriteria = QuestionOrderCriteria.ById) + { + var tmp = await unity.getQuestions(page, count, orderCriteria); + if (tmp.questions == null) + { + logger.LogInformation(message: "get question : bad request (page or/and count incorrect)"); + return BadRequest(tmp.nbPages); + } + else if (tmp.questions.Count() == 0) + { + logger.LogWarning(message: $"get question : no content. number of element : {unity.getNbQuestions()}, page wanted : {page}, number of elements in a page : {count}"); + return NoContent(); + } + else + { + logger.LogTrace(message: $"get questions : page = {page}, count = {count}, order criteria = {orderCriteria switch + { + QuestionOrderCriteria.ById => "byId", + QuestionOrderCriteria.ByContent => "byContent", + QuestionOrderCriteria.ByIdChapter => "byIdChapter", + QuestionOrderCriteria.ByNbFalls => "byNbFalls", + QuestionOrderCriteria.ByDifficulty => "byDifficulty", + _ => "none" + }}"); + return Ok(tmp); + } + } + + /// + /// delete a question + /// + /// the id of the question to delete + /// + /// status code : + /// 200 if the question is removed + /// 204 if the question is removed + /// 400 if the id is incorrect + /// 500 if there was an internal error that doesn't allow to continue + /// return content : + /// aministrator deleted when status code = 200 + /// no content when status code = 204 + /// no content when status code = 400 + /// no content when status code = 500 + /// + public async Task DeleteQuestion(int id) + { + if (id < 0) + { + logger.LogError("want to delete a question with an id less than 0"); + return BadRequest(); + } + int count = unity.getNbQuestions(); // count : number of elements before opperation + var tmp = await unity.removeQuestion(id); + if (tmp == null) // we don't recieve the question + { + if (unity.getNbQuestions() == count) // he is not deleted + { + if (unity.getQuestion(id) != null) + { + logger.LogCritical(message: "remove question fail : question not removed and not recieved"); + return StatusCode(500); + } + else + { + logger.LogInformation(message: "trying to remove a question with an id who don't exist"); + return BadRequest(); + } + } + else // he may be deleted + { + if (unity.getQuestion(id) == null) // he must be deleted + { + logger.LogError(message: "question removed but not returned"); + return NoContent(); + } + else // he is not deleted + { + logger.LogCritical(message: "remove question fail : question to remove not remove\ninstead, anotherone is deleted and we recieved nothing"); + return StatusCode(500); + } + } + } + if (unity.getNbQuestions() == count) + { + // <=> we have recieved a question which should be deleted + // but since we have the same number of question than + // before deletion, it isn't deleted + logger.LogCritical(message: $"question \"{tmp.ToString()}\"should be delete but it isn't"); + return StatusCode(500); + } + logger.LogTrace(message: $"question removed {tmp.ToString()}"); + return Ok(tmp); + } + + /// + /// get a question + /// + /// the id of the question + /// + /// status code : + /// 200 when we got a question + /// 204 when we got null + /// + /// return content : + /// the question that correspond to the id when status code = 200 + /// nothing when status code = 204 + /// + public async Task GetQuestion(int id) + { + var tmp = await unity.getQuestion(id); + if (tmp == null) return NoContent(); + return Ok(tmp); + } + + /// + /// update a question + /// + /// the id of the question + /// + /// status code : + /// 200 when we got a question + /// 204 when we got null + /// 208 when the nickname is already used + /// return content : + /// the question that correspond to the id when status code = 200 + /// nothing when status code = 204 + /// the question which have this nickname when status code = 208 + /// + public async Task PutQuestion(int id, QuestionDto question) + { + var tmp = await unity.getQuestion(question.Content); + if (tmp != null) return StatusCode(208); + tmp = await unity.updateQuestion(id, question); + if (tmp == null) return NoContent(); + return Ok(tmp); + } } } diff --git a/WebApi/WebApi/Program.cs b/WebApi/WebApi/Program.cs index 48863a6..1523393 100644 --- a/WebApi/WebApi/Program.cs +++ b/WebApi/WebApi/Program.cs @@ -1,3 +1,5 @@ +using Microsoft.Extensions.DependencyInjection; + var builder = WebApplication.CreateBuilder(args); // Add services to the container. @@ -7,6 +9,8 @@ builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); +builder.Services.AddApiVersioning(); + var app = builder.Build(); // Configure the HTTP request pipeline. diff --git a/WebApi/WebApi/Unit.cs b/WebApi/WebApi/Unit.cs index a97d88e..e7deba3 100644 --- a/WebApi/WebApi/Unit.cs +++ b/WebApi/WebApi/Unit.cs @@ -252,6 +252,11 @@ namespace WebApi return PlayerManager.getMaxScorePlayer(id); } + public Task updatePlayer(int id, PlayerDto player) + { + return PlayerManager.updatePlayer(id, player); + } + public int getNbQuestions() { return QuestionManager.getNbQuestions(); @@ -301,5 +306,10 @@ namespace WebApi { return QuestionManager.getQuestionsByChapterAndDifficulty(idChapter, difficulty, nb, count, orderCriteria); } + + public Task getQuestion(string content) + { + return QuestionManager.getQuestion(content); + } } }