diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..483215f --- /dev/null +++ b/.drone.yml @@ -0,0 +1,43 @@ +kind: pipeline +type: docker +name: API_SQLuedo + +trigger: + event: + - push + +steps: + - name: build + image: mcr.microsoft.com/dotnet/sdk:8.0 + commands: + - cd API_SQLuedo/ + - dotnet restore API_SQLuedo.sln + - dotnet build API_SQLuedo.sln -c Release --no-restore + + - name: tests + image: mcr.microsoft.com/dotnet/sdk:8.0 + commands: + - cd API_SQLuedo/ + - dotnet restore API_SQLuedo.sln + - dotnet test API_SQLuedo.sln -c Release --no-build --no-restore + depends_on: [ build ] + + - name: code-inspection + image: hub.codefirst.iut.uca.fr/marc.chevaldonne/codefirst-dronesonarplugin-dotnet8 + secrets: [ SECRET_SONAR_LOGIN ] + environment: + sonar_host: https://codefirst.iut.uca.fr/sonar/ + sonar_token: + from_secret: SECRET_SONAR_LOGIN + project_key: API_SQLuedo + coverage_exclusions: "Test*/**" + commands: + - cd API_SQLuedo/ + - dotnet restore API_SQLuedo.sln + - dotnet sonarscanner begin /k:$${project_key} /d:sonar.host.url=$${sonar_host} /d:sonar.coverageReportPaths="coveragereport/SonarQube.xml" /d:sonar.coverage.exclusions=$${coverage_exclusions} /d:sonar.login=$${sonar_token} + - dotnet build API_SQLuedo.sln -c Release --no-restore + - dotnet test API_SQLuedo.sln --logger trx --no-restore /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura --collect "XPlat Code Coverage" + - reportgenerator -reports:"**/coverage.cobertura.xml" -reporttypes:SonarQube -targetdir:"coveragereport" + - dotnet publish API_SQLuedo.sln -c Release --no-restore -o CI_PROJECT_DIR/build/release + - dotnet sonarscanner end /d:sonar.login=$${sonar_token} + depends_on: [ build ] \ No newline at end of file diff --git a/API_SQLuedo/API/API.csproj b/API_SQLuedo/API/API.csproj index 74687fb..822644c 100644 --- a/API_SQLuedo/API/API.csproj +++ b/API_SQLuedo/API/API.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -8,17 +8,20 @@ - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/API_SQLuedo/API/Controllers/InquiriesController.cs b/API_SQLuedo/API/Controllers/InquiriesController.cs new file mode 100644 index 0000000..e42d14e --- /dev/null +++ b/API_SQLuedo/API/Controllers/InquiriesController.cs @@ -0,0 +1,65 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Model.DTO; +using Services; + +namespace API.Controllers +{ + [Route("api/[controller]")] + [Authorize] + [ApiController] + public class InquiriesController : Controller + { + private IDataService _inquiryDataService; + + private readonly ILogger _logger; + + public InquiriesController(IDataService inquiryDataService) + { + _inquiryDataService = inquiryDataService; + } + + [HttpGet("inquiries/{page}/{number}")] + public IActionResult GetInquiries(int page, int number) + { + var nbInquiry = _inquiryDataService.GetInquiries(page, number).Count(); + if (nbInquiry == 0) + { + _logger.LogError("[ERREUR] Aucune enquête trouvé."); + return StatusCode(204); + } + _logger.LogInformation("[INFORMATION] {nb} Enquête(s) trouvée(s)", nbInquiry); + return Ok(_inquiryDataService.GetInquiries(page, number)); + } + + [HttpGet("inquiry/id/{id}")] + public IActionResult GetInquiryById(int id) + { + try + { + _logger.LogInformation("[INFORMATION] Enquête avec l'id {id} a été trouvé.", id); + return Ok(_inquiryDataService.GetInquiryById(id)); + } + catch (ArgumentException) + { + _logger.LogError("[ERREUR] Aucune enquête trouvée avec l'id {id}.", id); + return NotFound(); + } + } + + [HttpGet("inquiry/title/{title}")] + public IActionResult GetInquiryByTitle(string title) + { + try + { + _logger.LogInformation("[INFORMATION] Enquête avec le titre {title} a été trouvé.", title); + return Ok(_inquiryDataService.GetInquiryByTitle(title)); + } + catch (ArgumentException) + { + _logger.LogError("[ERREUR] Aucune enquête trouvée avec le titre {title}.", title); + return NotFound(); + } + } + } +} \ No newline at end of file diff --git a/API_SQLuedo/API/Controllers/UserController.cs b/API_SQLuedo/API/Controllers/UserController.cs index 1708d72..6d2e9d6 100644 --- a/API_SQLuedo/API/Controllers/UserController.cs +++ b/API_SQLuedo/API/Controllers/UserController.cs @@ -1,26 +1,119 @@ using DbContextLib; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Model.Business; using Model.DTO; using Services; namespace API.Controllers { - [Route("api/[controller]")] + [Route("api/{version:apiVersion}/[controller]")] + [Authorize] + [ApiVersion("1.0")] [ApiController] public class UserController : Controller { - private IDataService _userDataService; + private IDataService _userDataService; + + private readonly ILogger _logger; - public UserController(IDataService userDataService) + public UserController(IDataService userDataService, ILogger logger) { _userDataService = userDataService; + _logger = logger; } [HttpGet("users/{page}/{number}")] public IActionResult GetUsers(int page, int number) { + var nbUser = _userDataService.GetUsers(page, number).Count(); + if(nbUser == 0) + { + _logger.LogError("[ERREUR] Aucun utilisateur trouvé."); + return StatusCode(204); + } + _logger.LogInformation("[INFORMATION] {nb} Utilisateur(s) trouvé(s)", nbUser); return Ok(_userDataService.GetUsers(page, number)); } + + [HttpGet("user/id/{id}")] + public IActionResult GetUserById(int id) + { + try + { + _logger.LogInformation("[INFORMATION] Utilisateur avec l'id {id} a été trouvé.", id); + return Ok(_userDataService.GetUserById(id)); + } catch (ArgumentException) + { + _logger.LogError("[ERREUR] Aucun utilisateur trouvé avec l'id {id}.", id); + return NotFound(); + } + } + + [HttpGet("user/username/{username}")] + public IActionResult GetUserByUsername(string username) + { + try + { + _logger.LogInformation("[INFORMATION] Utilisateur avec l'username {username} a été trouvé.", username); + return Ok(_userDataService.GetUserByUsername(username)); + }catch (ArgumentException) + { + _logger.LogError("[ERREUR] Aucun utilisateur trouvé avec l'username {username}.", username); + return NotFound(); + } + + } + + [HttpDelete] + public IActionResult DeleteUser(int id) + { + var success = _userDataService.DeleteUser(id); + if(success) + { + _logger.LogInformation("[INFORMATION] L'utilisateur avec l'id {id} a été supprimé.", id); + return Ok(_userDataService.DeleteUser(id)); + } else + { + _logger.LogError("[ERREUR] Aucun utilisateur trouvé avec l'id {id}.", id); + return NotFound(); + } + + } + + [HttpPost] + public IActionResult CreateUser([FromBody]UserDTO dto) + { + if (dto.Username == null || dto.Password == null || dto.Email == null) + { + return BadRequest(); + } + // return Ok(_userDataService.CreateUser(username, password, email, isAdmin)); + _logger.LogInformation("[INFORMATION] Un utilisateur a été créé : username - {username}, password - {password}, email - {email}, isAdmin - {isAdmin}", dto.Username, dto.Password, dto.Email, dto.IsAdmin); + return Created(nameof(GetUsers), _userDataService.CreateUser(dto.Username, dto.Password, dto.Email, dto.IsAdmin)); + } + + [HttpPut] + public IActionResult UpdateUser(int id, [FromBody] UserDTO userDTO) + { + if(id != userDTO.Id) + { + _logger.LogError("[ERREUR] Problème ID - La mise à jour de l'utilisateur avec l'id {id} a échouée.", id); + return BadRequest(); + } + if(!ModelState.IsValid) + { + _logger.LogError("[ERREUR] Problème controlleur - La mise à jour de l'utilisateur avec l'id {id} a échouée.", id); + return BadRequest(); + } + if(userDTO != null) + { + _logger.LogInformation("[INFORMATION] La mise à jour de l'utilsiateur avec l'id {id} a été effectuée", id); + return Ok(_userDataService.UpdateUser(id, userDTO)); + } + _logger.LogError("[ERREUR] Aucun utilisateur trouvé avec l'id {id}.", id); + return NotFound(); + } } } diff --git a/API_SQLuedo/API/Program.cs b/API_SQLuedo/API/Program.cs index 8168dce..8630246 100644 --- a/API_SQLuedo/API/Program.cs +++ b/API_SQLuedo/API/Program.cs @@ -1,5 +1,9 @@ +using API; using DbContextLib; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc.Versioning; using Microsoft.EntityFrameworkCore; +using Microsoft.OpenApi.Models; using Services; var builder = WebApplication.CreateBuilder(args); @@ -12,6 +16,39 @@ builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddScoped(); builder.Services.AddDbContext(); +builder.Services.AddDbContext(options => options.UseInMemoryDatabase("appDb")); +builder.Services.AddIdentityApiEndpoints().AddEntityFrameworkStores(); +builder.Services.AddAuthorization(); +builder.Services.AddApiVersioning(o => o.ApiVersionReader = new HeaderApiVersionReader("api-version")); +//builder.Services.AddIdentityApiEndpoints() +// .AddEntityFrameworkStores(); +builder.Services.AddSwaggerGen(option => +{ + option.SwaggerDoc("v1", new OpenApiInfo { Title = "Demo API", Version = "v1" }); + option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme + { + In = ParameterLocation.Header, + Description = "Please enter a valid token", + Name = "Authorization", + Type = SecuritySchemeType.Http, + BearerFormat = "JWT", + Scheme = "Bearer" + }); + option.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type=ReferenceType.SecurityScheme, + Id="Bearer" + } + }, + new string[]{} + } + }); +}); var app = builder.Build(); @@ -28,4 +65,6 @@ app.UseAuthorization(); app.MapControllers(); +app.MapIdentityApi(); + app.Run(); diff --git a/API_SQLuedo/API/WebAPIDbContext.cs b/API_SQLuedo/API/WebAPIDbContext.cs new file mode 100644 index 0000000..afc8996 --- /dev/null +++ b/API_SQLuedo/API/WebAPIDbContext.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; + +namespace API +{ + public class WebAPIDbContext : IdentityDbContext + { + public WebAPIDbContext(DbContextOptions options) : base(options) { } + } +} diff --git a/API_SQLuedo/API_SQLuedo.sln b/API_SQLuedo/API_SQLuedo.sln index 888826d..58f87a2 100644 --- a/API_SQLuedo/API_SQLuedo.sln +++ b/API_SQLuedo/API_SQLuedo.sln @@ -3,19 +3,21 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.8.34408.163 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "API", "API\API.csproj", "{65F4AE69-E1CA-4B87-BDF0-946A37351BD1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "API", "API\API.csproj", "{65F4AE69-E1CA-4B87-BDF0-946A37351BD1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entities", "EntityFramework\Entities.csproj", "{6D079CDA-C000-4833-98A0-D07D153EA264}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Entities", "EntityFramework\Entities.csproj", "{6D079CDA-C000-4833-98A0-D07D153EA264}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "Model\Model.csproj", "{ADCC427D-A3CD-431C-A90B-F9369C4584E8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model", "Model\Model.csproj", "{ADCC427D-A3CD-431C-A90B-F9369C4584E8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestAPI", "TestAPI\TestAPI.csproj", "{17025B90-8B2A-49E9-97D3-1A84A208DF50}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestAPI", "TestAPI\TestAPI.csproj", "{17025B90-8B2A-49E9-97D3-1A84A208DF50}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestEF", "TestEF\TestEF.csproj", "{54FAD8AF-7601-4C54-8406-D81476A8D7D7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestEF", "TestEF\TestEF.csproj", "{54FAD8AF-7601-4C54-8406-D81476A8D7D7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DbContextLib", "DbContextLib\DbContextLib.csproj", "{BDCB3BFD-B744-4BC0-BCFC-78E08600203A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DbContextLib", "DbContextLib\DbContextLib.csproj", "{BDCB3BFD-B744-4BC0-BCFC-78E08600203A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Services", "Services\Services.csproj", "{9BD3DCBA-AFD8-47FA-B07C-613B53E63968}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Services", "Services\Services.csproj", "{9BD3DCBA-AFD8-47FA-B07C-613B53E63968}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestConsoleAPI", "TestConsoleAPI\TestConsoleAPI.csproj", "{46376AEF-4093-4AE9-AD2F-F51B541F9C6A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -51,6 +53,10 @@ Global {9BD3DCBA-AFD8-47FA-B07C-613B53E63968}.Debug|Any CPU.Build.0 = Debug|Any CPU {9BD3DCBA-AFD8-47FA-B07C-613B53E63968}.Release|Any CPU.ActiveCfg = Release|Any CPU {9BD3DCBA-AFD8-47FA-B07C-613B53E63968}.Release|Any CPU.Build.0 = Release|Any CPU + {46376AEF-4093-4AE9-AD2F-F51B541F9C6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {46376AEF-4093-4AE9-AD2F-F51B541F9C6A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {46376AEF-4093-4AE9-AD2F-F51B541F9C6A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {46376AEF-4093-4AE9-AD2F-F51B541F9C6A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/API_SQLuedo/DbContextLib/DbContextLib.csproj b/API_SQLuedo/DbContextLib/DbContextLib.csproj index 38862a9..f2f138b 100644 --- a/API_SQLuedo/DbContextLib/DbContextLib.csproj +++ b/API_SQLuedo/DbContextLib/DbContextLib.csproj @@ -7,13 +7,15 @@ - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/API_SQLuedo/DbContextLib/UserDbContext.cs b/API_SQLuedo/DbContextLib/UserDbContext.cs index a335310..2084d53 100644 --- a/API_SQLuedo/DbContextLib/UserDbContext.cs +++ b/API_SQLuedo/DbContextLib/UserDbContext.cs @@ -1,11 +1,14 @@ using Entities.SQLuedoDB; +using Entities.SQLudeoDB; +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.AspNetCore.Cryptography.KeyDerivation; using Microsoft.EntityFrameworkCore; using System.Security.Cryptography; +using Microsoft.AspNetCore.Identity; namespace DbContextLib { - public class UserDbContext : DbContext + public class UserDbContext : IdentityDbContext { public DbSet Users { get; set; } public DbSet BlackList { get; set; } diff --git a/API_SQLuedo/EntityFramework/Entities.csproj b/API_SQLuedo/EntityFramework/Entities.csproj index feae017..0768618 100644 --- a/API_SQLuedo/EntityFramework/Entities.csproj +++ b/API_SQLuedo/EntityFramework/Entities.csproj @@ -7,12 +7,12 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/API_SQLuedo/Model/DTO/UserDTO.cs b/API_SQLuedo/Model/DTO/UserDTO.cs index 786fad7..06aa236 100644 --- a/API_SQLuedo/Model/DTO/UserDTO.cs +++ b/API_SQLuedo/Model/DTO/UserDTO.cs @@ -23,5 +23,18 @@ namespace Model.DTO Email = email; IsAdmin = isAdmin; } + + public UserDTO(string username, string password, string email, bool isAdmin) + { + Username = username; + Password = password; + Email = email; + IsAdmin = isAdmin; + } + + public override string ToString() + { + return $"{Id}\t{Username}\t{Email}\t{IsAdmin}"; + } } } diff --git a/API_SQLuedo/Model/Model.csproj b/API_SQLuedo/Model/Model.csproj index b46af5d..6e81eea 100644 --- a/API_SQLuedo/Model/Model.csproj +++ b/API_SQLuedo/Model/Model.csproj @@ -7,12 +7,12 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/API_SQLuedo/Services/IDataService.cs b/API_SQLuedo/Services/IDataService.cs index 2919cc7..a3faad9 100644 --- a/API_SQLuedo/Services/IDataService.cs +++ b/API_SQLuedo/Services/IDataService.cs @@ -1,4 +1,5 @@ -using Model.DTO; +using Model.Business; +using Model.DTO; namespace Services { @@ -7,7 +8,11 @@ namespace Services public IEnumerable GetUsers(int page, int number); public UserDTO GetUserById(int id); public UserDTO GetUserByUsername(string username); - public IEnumerable GetInquiries(); - + public bool DeleteUser(int id); + public UserDTO UpdateUser(int id, UserDTO user); + public UserDTO CreateUser(string username, string password, string email, bool isAdmin); + public IEnumerable GetInquiries(int page, int number); + public InquiryDTO GetInquiryById(int id); + public InquiryDTO GetInquiryByTitle(string title); } } diff --git a/API_SQLuedo/Services/Services.csproj b/API_SQLuedo/Services/Services.csproj index 4cd7b1b..4eafac0 100644 --- a/API_SQLuedo/Services/Services.csproj +++ b/API_SQLuedo/Services/Services.csproj @@ -7,12 +7,12 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/API_SQLuedo/Services/UserDataService.cs b/API_SQLuedo/Services/UserDataService.cs index c3206d9..ddaa3e6 100644 --- a/API_SQLuedo/Services/UserDataService.cs +++ b/API_SQLuedo/Services/UserDataService.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading.Tasks; using Model.Mappers; using Model.Business; +using Microsoft.EntityFrameworkCore; namespace Services { @@ -18,24 +19,89 @@ namespace Services DbContext = context; context.Database.EnsureCreated(); } - public IEnumerable GetInquiries() - { - throw new NotImplementedException(); - } public UserDTO GetUserById(int id) { - throw new NotImplementedException(); + var userEntity = DbContext.Users.FirstOrDefault(u => u.Id == id); + if (userEntity == null) + { + throw new ArgumentException("Impossible de trouver l'utilisateur", nameof(id)); + } + return userEntity.FromEntityToModel().FromModelToDTO(); + } public UserDTO GetUserByUsername(string username) { - throw new NotImplementedException(); + var userEntity = DbContext.Users.FirstOrDefault(u => u.Username == username); + if (userEntity == null) + { + throw new ArgumentException("Impossible de trouver l'utilisateur", nameof(username)); + } + return userEntity.FromEntityToModel().FromModelToDTO(); } public IEnumerable GetUsers(int page, int number) { return DbContext.Users.Skip((page - 1) * number).Take(number).ToList().Select(u => u.FromEntityToModel().FromModelToDTO()); } + + public bool DeleteUser(int id) + { + var userEntity = DbContext.Users.FirstOrDefault(u => u.Id == id); + if (userEntity == null) + { + return false; + } + DbContext.Users.Remove(userEntity); + DbContext.SaveChangesAsync(); + return true; + } + + public UserDTO UpdateUser(int id, UserDTO user) + { + var updatingUser = DbContext.Users.FirstOrDefault(u => u.Id == id); + if (updatingUser == null) + { + throw new ArgumentException("Impossible de trouver l'utilisateur", nameof(id)); + } + updatingUser.Username = user.Username; + updatingUser.Password = user.Password; + updatingUser.Email = user.Email; + updatingUser.IsAdmin = user.IsAdmin; + // Permet d'indiquer en Db que l'entité a été modifiée. + DbContext.Entry(updatingUser).State = EntityState.Modified; + DbContext.SaveChangesAsync(); + return updatingUser.FromEntityToModel().FromModelToDTO(); + } + + public UserDTO CreateUser(string username, string password, string email, bool isAdmin) + { + var newUserEntity = new UserDTO + { + Username = username, + Password = password, + Email = email, + IsAdmin = isAdmin + }; + DbContext.Users.Add(newUserEntity.FromDTOToModel().FromModelToEntity()); + DbContext.SaveChangesAsync(); + return newUserEntity; + } + + public IEnumerable GetInquiries(int page, int number) + { + throw new NotImplementedException(); + } + + public InquiryDTO GetInquiryById(int id) + { + throw new NotImplementedException(); + } + + public InquiryDTO GetInquiryByTitle(string title) + { + throw new NotImplementedException(); + } } } diff --git a/API_SQLuedo/TestAPI/TestAPI.csproj b/API_SQLuedo/TestAPI/TestAPI.csproj index bda60d7..9d1ad3b 100644 --- a/API_SQLuedo/TestAPI/TestAPI.csproj +++ b/API_SQLuedo/TestAPI/TestAPI.csproj @@ -10,19 +10,20 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/API_SQLuedo/TestConsoleAPI/Program.cs b/API_SQLuedo/TestConsoleAPI/Program.cs new file mode 100644 index 0000000..651de21 --- /dev/null +++ b/API_SQLuedo/TestConsoleAPI/Program.cs @@ -0,0 +1,319 @@ +// See https://aka.ms/new-console-template for more information + +using API.Controllers; +using DbContextLib; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Model.DTO; +using Services; + +var connection = new SqliteConnection("DataSource=:memory:"); +connection.Open(); +var options = new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options; +using ILoggerFactory factory = new LoggerFactory(); +ILogger logger = factory.CreateLogger(); + +using (var context = new UserDbContext(options)) +{ + var controller = new UserController(new UserDataService(context), logger); + + void PrintUsers() + { + Console.WriteLine(); + var users = controller.GetUsers(1, 10) as OkObjectResult; + foreach(var item in users.Value as IEnumerable) + { + Console.WriteLine(item); + } + } + + void SearchUserByUsername() + { + Console.WriteLine("\nVeuillez saisir le pseudonyme de l'utilisateur recherché : "); + var username = Console.ReadLine(); + var user = controller.GetUserByUsername(username) as OkObjectResult; + if(user == null) + { + Console.WriteLine("Erreur, la requête n'a rien donné."); + return; + } + Console.WriteLine(user.Value as UserDTO); + } + + void SearchUserById() + { + Console.WriteLine("\nVeuillez saisir l'identifiant de l'utilisateur recherché : "); + var id = Console.ReadLine(); + var user = controller.GetUserById(int.Parse(id)) as OkObjectResult; + if (user == null) + { + Console.WriteLine("Erreur, la requête n'a rien donné."); + return; + } + Console.WriteLine(user.Value as UserDTO); + } + + void AddUser() + { + Console.WriteLine("Veuillez saisir le pseudonyme :"); + var username = Console.ReadLine(); + Console.WriteLine("Veuillez saisir une adresse email :"); + var email = Console.ReadLine(); + Console.WriteLine("Veuillez saisir un mot de passe :"); + var mdp = Console.ReadLine(); + var res = controller.CreateUser(new UserDTO(username, mdp, email, false)); + if(res.GetType() == typeof(CreatedResult)) { + Console.WriteLine("\nUtilisateur créé avec succès"); + } else + { + Console.WriteLine("\nErreur lors de la création de l'utilisateur !"); + } + } + + void UpdateUser() + { + Console.WriteLine("Quel est l'identifiant de l'utilisateur à mettre à jour ?"); + var id = int.Parse(Console.ReadLine()); + var res = (controller.GetUserById(id)); + if (res.GetType() == typeof(OkObjectResult)) { + var user = (res as OkObjectResult).Value as UserDTO; + if (user == null) { + Console.WriteLine("Erreur, un problème est survenu"); + return; + } + else + { + Console.WriteLine("Utilisateur trouvé !\n"); + Console.WriteLine("Veuillez saisir le pseudonyme :"); + var username = Console.ReadLine(); + Console.WriteLine("Veuillez saisir l'email :"); + var email = Console.ReadLine(); + var retour = controller.UpdateUser(id, new UserDTO(id, username, user.Password, email, user.IsAdmin)); + if(retour.GetType() == typeof(OkObjectResult)) + { + Console.WriteLine("Mise à jour effectué avec succès !"); + } else + { + Console.WriteLine("Une erreur est survenue lors de la mise à jour."); + } + } + } + else { + Console.WriteLine("Une erreur est survenue lors de la mise à jour !"); + } + } + + void DeleteUser() + { + Console.WriteLine("Quel est l'identifiant de lutilisateur à supprimer ?"); + var id = int.Parse(Console.ReadLine()); + var res = controller.DeleteUser(id); + if(res.GetType() == typeof(OkObjectResult)) + { + Console.WriteLine("La suppression a été effectuée avec succès !"); + } + else + { + Console.WriteLine("Erreur lors de la suppression !"); + } + } + + + void Menu() + { + Console.WriteLine("|------------------------------------------------|"); + Console.WriteLine("| Menu |"); + Console.WriteLine("|------------------------------------------------|"); + Console.WriteLine("| t - Effectuer des tests automatiques |"); + Console.WriteLine("| 1 - Afficher les utilisateurs |"); + Console.WriteLine("| 2 - Rechercher un utilisateur avec son pseudo |"); + Console.WriteLine("| 3 - Rechercher un utilisateur avec son ID |"); + Console.WriteLine("| 4 - Ajouter un utilisateur |"); + Console.WriteLine("| 5 - Mettre à jour un utilisateur |"); + Console.WriteLine("| 6 - Supprimer un utilisateur |"); + Console.WriteLine("| q - Quitter |"); + Console.WriteLine("|------------------------------------------------|"); + } + + Menu(); + Console.WriteLine("\nSaisie :"); + var saisie = Console.ReadLine(); + + while (saisie != "q") { + switch (saisie) + { + case "1": + PrintUsers(); + break; + case "2": + SearchUserByUsername(); + break; + case "3": + SearchUserById(); + break; + case "4": + AddUser(); + break; + case "5": + UpdateUser(); + break; + case "6": + DeleteUser(); + break; + case "t": + AutoTests(); + break; + default: + break; + } + Console.WriteLine("\nAppuyez sur n'importe quelle touche pour continuer..."); + Console.ReadKey(); + Console.Clear(); + Menu(); + Console.WriteLine("\nSaisie :"); + saisie = Console.ReadLine(); + } + + void AutoTests() + { + // Affichage des utilisateurs + Console.WriteLine("\n##########################################################\n"); + Console.WriteLine("Affichages des utilisateurs stubbés dans le contexte :\n"); + var res = controller.GetUsers(1, 10) as OkObjectResult; + if(res == null) + { + Console.WriteLine("\nErreur lors de l'acquisition de la liste des utilisateurs"); + } + else + { + var users = res.Value as IEnumerable; + if(users == null) { + Console.WriteLine("\nErreur, les ustilisateurs n'ont pas été trouvés !"); + } + else + { + PrintUsers(); + } + } + + // Recherche d'utilisateur par ID + Console.WriteLine("\n##########################################################\n"); + Console.WriteLine("Affichage de l'utilisateur ayant pour identifiant 1 :\n"); + var res1 = controller.GetUserById(1) as OkObjectResult; + if (res1 == null) + { + Console.WriteLine("\nErreur lors de l'acquisition de l'utilisateur !"); + } + else + { + var user = res1.Value as UserDTO; + if (user == null) + { + Console.WriteLine("\nErreur, l'utilisateur n'existe pas !"); + } + else + { + Console.WriteLine(user); + } + } + + // Recherche d'utilisateur par pseudonyme + Console.WriteLine("\n##########################################################\n"); + Console.WriteLine("Affichage de l'utilisateur ayant pour username johnny :\n"); + var res2 = controller.GetUserByUsername("johnny") as OkObjectResult; + if (res2 == null) + { + Console.WriteLine("\nErreur lors de l'acquisition de l'utilisateur !"); + } + else + { + var user1 = res2.Value as UserDTO; + if (user1 == null) + { + Console.WriteLine("\nErreur, l'utilisateur n'existe pas !"); + } + else + { + Console.WriteLine(user1); + } + } + + // Ajout d'un utilisateur + Console.WriteLine("\n##########################################################\n"); + Console.WriteLine("Création de l'utilisateur :\n"); + var user2 = new UserDTO("JohnDoe", "motdepasse", "johndoe@gmail.com", false); + Console.WriteLine(user2); + var res3 = controller.CreateUser(user2) as CreatedResult; + if (res3 == null) + { + Console.WriteLine("\nErreur lors de la création de l'utilisateur !"); + } + else + { + Console.WriteLine("\nUtilisateur créé avec succès !"); + } + + // Affichage des utilisateurs + Console.WriteLine("\n##########################################################\n"); + PrintUsers(); + + // Mise à jour d'un utilisateur + Console.WriteLine("\n##########################################################\n"); + Console.WriteLine("Mise à jour de l'adresse email de l'utilisateur :\n"); + user2 = ((controller.GetUserByUsername("JohnDoe") as OkObjectResult).Value as UserDTO); + if (user2 == null) + { + Console.WriteLine("\nErreur lors de la récupération de l'utilisateur !"); + } + else + { + Console.WriteLine(user2); + Console.WriteLine("\nNouvelle adresse : John.DOE@etu.uca.fr"); + var user3 = new UserDTO(user2.Id, user2.Username, user2.Password, "John.DOE@etu.uca.fr", user2.IsAdmin); + var res4 = controller.UpdateUser(user2.Id, user3) as OkObjectResult; + if (res4 == null) + { + Console.WriteLine("\nErreur lors de la mise à jour de l'utilisateur !"); + } + else + { + Console.WriteLine("\nUtilisateur mis à jour avec succès !"); + } + } + // Affichage des utilisateurs + + Console.WriteLine("\n##########################################################\n"); + PrintUsers(); + + // Suppression d'un utilisateur + Console.WriteLine("\n##########################################################\n"); + Console.WriteLine("Suppression de l'utilisateur JohnDoe:\n"); + user2 = ((controller.GetUserByUsername("JohnDoe") as OkObjectResult).Value as UserDTO); + if (user2 == null) + { + Console.WriteLine("\nErreur lors de la récupération de l'utilisateur !"); + } + else + { + Console.WriteLine(user2); + var res5 = controller.DeleteUser(user2.Id) as OkObjectResult; + if (res5 == null) + { + Console.WriteLine("\nErreur lors de la suppression de l'utilisateur !"); + } + else + { + Console.WriteLine("\nUtilisateur supprimé avec succès !"); + } + } + // Affichage des utilisateurs + + Console.WriteLine("\n##########################################################\n"); + PrintUsers(); + } +} \ No newline at end of file diff --git a/API_SQLuedo/TestConsoleAPI/TestConsoleAPI.csproj b/API_SQLuedo/TestConsoleAPI/TestConsoleAPI.csproj new file mode 100644 index 0000000..c013237 --- /dev/null +++ b/API_SQLuedo/TestConsoleAPI/TestConsoleAPI.csproj @@ -0,0 +1,21 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + + + diff --git a/API_SQLuedo/TestEF/TestEF.csproj b/API_SQLuedo/TestEF/TestEF.csproj index bda60d7..9d1ad3b 100644 --- a/API_SQLuedo/TestEF/TestEF.csproj +++ b/API_SQLuedo/TestEF/TestEF.csproj @@ -10,19 +10,20 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/README.md b/README.md index c3534c5..5b41071 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,86 @@ # API_SQLuedo +## Configuration de l'API + +### Au niveau de la solution du projet : + +- > Création des migrations + +```sh + dotnet ef migrations add MigrationName --project .\DbContextLib --context UserDbContext --startup-project .\API +``` + +- > Mise à jour de la base de données : + +```sh + dotnet ef database update --project .\DbContextLib --startup-project .\API +``` + +- > Exécuter le projet de l'API avec votre IDE + +![alt text](Ressources/image.png) + +
+ +## Caractéristiques de l'API + +### Source de données +--- +L'API est actuellement reliée à un projet __EntityFramework__ qui lui fournit les données dont elle a besoin. +La partie EntityFramework est, elle, reliée à une base de donnée __PostgreSQL__ mais peut très bien être reliée à un autre fournisseur de BDD en injectant un DbContextOptions configuré dans le au moment de l'instanciation du UserDbContext. + +--- +### Injecter un fournisseur de BDD alternatif +```C# + var options = new DbContextOptionsBuilder() + .UseNpgsql() + .Options; + + var dbContext = new UserDbContext(options); +``` +--- +### Configuration de la base de données + +Pour ce qui est de la base de données, il faut évidemment installer PostgreSQL.
+La classe UserDbContext utilise par défaut PostgreSQL à partir d'un utilisateur __admin__ qu'il faut créer au préalable. L'utilisateur __admin__ devra posséder le droit de créer une base de données et devra disposer de tous les droits d'édition sur celle-ci. + +```SQL + CREATE USER admin WITH PASSWORD "motdepasse"; + GRANT pg_read_all_data TO admin; + GRANT pg_write_all_data TO admin; + ALTER USER admin CREATEDB; +``` +--- +### Dans le DbContext + +Il faut également adapter la configuration de la connexion à la base de données dans le UserDbContext afin de l'adapter en fonction de la configuration que vous décidez de faire. Par défaut, si vous avez une base PostgreSQL sur la même machine que celle qui fait tourner l'API et que vous avez utilisé les commandes SQL fournies à l'identique, cela devrait fonctionner sans problème. Sinon, vous pouvez modifier le DbContext dans la méthode OnConfiguring ci-dessous : +>UserDbContext.cs +```C# + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (!optionsBuilder.IsConfigured) + { // Modifier la ligne ci-dessous en fonction de votre configuration + optionsBuilder.UseNpgsql("Host=localhost;Database=SQLuedo;Username=admin;Password=motdepasse"); + } + base.OnConfiguring(optionsBuilder); + } +``` + +--- + +### Utilisation de l'interface Swagger +Pour tester manuellement l'API, à l'exécution du projet de celle-ci, une interface Swagger s'ouvre dans votre navigateur. Etant donné que l'API est configurée pour demander une autentification à l'utilisateur, vous devrez alors créer un compte sur Swagger (qui ne sera valable que pour l'exécution en cours). + +Vous pourrez alors pour cela sélectionner la rubrique Register et entrer une __adresse email__ et un __mot de passe__ quelconque dans l'objet Json puis appuyer sur __Exécuter__. + +Ensuite, il vous faudra vous connecter via la rubrique Login pour laquelle vous n'aurez qu'à entrer l'email et le mot de passe précédents. Vous pouvez également activer les cookies si vous le souhaitez pour une persistance de la connexion. + +Voilà, vous pouvez maintenant utilisez librement l'API ! + +--- + +### Versionnement + +Notre API est versionnée ce qui signifie qu'à chaque requête, la version souhaitée de l'API doit être fournie. Pour l'instant, il n'y a qu'une __version 1.0__. + +--- \ No newline at end of file diff --git a/Ressources/image.png b/Ressources/image.png new file mode 100644 index 0000000..02f6485 Binary files /dev/null and b/Ressources/image.png differ