From 4dc203b705f03b51e36f634bd26f32c32dc0e30c Mon Sep 17 00:00:00 2001 From: tleodev Date: Wed, 21 May 2025 14:48:48 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Introduice=20Catalog=20routes=20+?= =?UTF-8?q?=20postman=20test=20lib=20+=20mappers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +- docs/architecture.md | 0 src/CatalogService/CatalogService.csproj | 2 +- .../Controllers/ExercicesController.cs | 64 +++++ .../DTOs/CreateExerciceTemplateDto.cs | 7 +- .../DTOs/ExerciceTemplateDto.cs | 2 +- .../DTOs/UpdateExerciceTemplateDto.cs | 20 ++ src/CatalogService/Program.cs | 1 + .../RequestHelpers/MappingProfiles.cs | 16 ++ src/Shared/DTOs/DeleteDto.cs | 9 + .../Catalog_Exercices.postman_collection.json | 231 ++++++++++++++++++ 11 files changed, 349 insertions(+), 7 deletions(-) create mode 100644 docs/architecture.md create mode 100644 src/CatalogService/Controllers/ExercicesController.cs rename src/{Shared => CatalogService}/DTOs/ExerciceTemplateDto.cs (94%) create mode 100644 src/CatalogService/DTOs/UpdateExerciceTemplateDto.cs create mode 100644 src/CatalogService/RequestHelpers/MappingProfiles.cs create mode 100644 src/Shared/DTOs/DeleteDto.cs create mode 100644 src/Tests/postman/Catalog_Exercices.postman_collection.json diff --git a/.gitignore b/.gitignore index 0ac2699..2e3326d 100644 --- a/.gitignore +++ b/.gitignore @@ -800,4 +800,6 @@ pyrightconfig.json # End of https://www.toptal.com/developers/gitignore/api/rider,intellij,intellij+all,dotnetcore,csharp,python -**/appsettings*.json \ No newline at end of file +**/appsettings*.json + +.DS_Store diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..e69de29 diff --git a/src/CatalogService/CatalogService.csproj b/src/CatalogService/CatalogService.csproj index 497f0c0..c36fcf9 100644 --- a/src/CatalogService/CatalogService.csproj +++ b/src/CatalogService/CatalogService.csproj @@ -2,7 +2,7 @@ net8.0 - disable + enable enable true diff --git a/src/CatalogService/Controllers/ExercicesController.cs b/src/CatalogService/Controllers/ExercicesController.cs new file mode 100644 index 0000000..deb6456 --- /dev/null +++ b/src/CatalogService/Controllers/ExercicesController.cs @@ -0,0 +1,64 @@ +using AutoMapper; +using CatalogService.Data; +using CatalogService.DTOs; +using CatalogService.Entities; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Shared.DTOs; + +namespace CatalogService.Controllers; + +[ApiController] +[Route("api/[controller]")] +public class ExercicesController : ControllerBase +{ + private readonly CatalogDbContext _context; + private readonly IMapper _mapper; + + public ExercicesController(CatalogDbContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + [HttpPost] + public async Task Create([FromBody] CreateExerciceTemplateDto dto) + { + var exercice = _mapper.Map(dto); + _context.Exercices.Add(exercice); + await _context.SaveChangesAsync(); + return CreatedAtAction(nameof(GetById), new { id = exercice.Id }, _mapper.Map(exercice)); + } + + [HttpPut("{id}")] + public async Task Update(string id, [FromBody] UpdateExerciceTemplateDto dto) + { + var exercice = await _context.Exercices.FindAsync(id); + if (exercice == null) return NotFound(); + + _mapper.Map(dto, exercice); + exercice.UpdatedAt = DateTime.UtcNow; + await _context.SaveChangesAsync(); + return NoContent(); + } + + [HttpDelete("{id}")] + public async Task Delete(string id) + { + var exercice = await _context.Exercices.FindAsync(id); + if (exercice == null) return NotFound(); + + _context.Exercices.Remove(exercice); + await _context.SaveChangesAsync(); + return NoContent(); + } + + [HttpGet("{id}")] + public async Task> GetById(string id) + { + var exercice = await _context.Exercices.FindAsync(id); + if (exercice == null) return NotFound(); + + return _mapper.Map(exercice); + } +} \ No newline at end of file diff --git a/src/CatalogService/DTOs/CreateExerciceTemplateDto.cs b/src/CatalogService/DTOs/CreateExerciceTemplateDto.cs index 7104e69..bc2aae5 100644 --- a/src/CatalogService/DTOs/CreateExerciceTemplateDto.cs +++ b/src/CatalogService/DTOs/CreateExerciceTemplateDto.cs @@ -6,10 +6,9 @@ namespace CatalogService.DTOs; public class CreateExerciceTemplateDto { [Required] - public string Name { get; set; } - - [Required] - public string Description { get; set; } + public required string Name { get; set; } + + public string? Description { get; set; } = default; public ETarget? Target { get; set; } = ETarget.None; diff --git a/src/Shared/DTOs/ExerciceTemplateDto.cs b/src/CatalogService/DTOs/ExerciceTemplateDto.cs similarity index 94% rename from src/Shared/DTOs/ExerciceTemplateDto.cs rename to src/CatalogService/DTOs/ExerciceTemplateDto.cs index 18b96b0..9b10968 100644 --- a/src/Shared/DTOs/ExerciceTemplateDto.cs +++ b/src/CatalogService/DTOs/ExerciceTemplateDto.cs @@ -1,6 +1,6 @@ using Shared.Enum; -namespace Shared.DTOs; +namespace CatalogService.DTOs; public class ExerciceTemplateDto { diff --git a/src/CatalogService/DTOs/UpdateExerciceTemplateDto.cs b/src/CatalogService/DTOs/UpdateExerciceTemplateDto.cs new file mode 100644 index 0000000..e19a600 --- /dev/null +++ b/src/CatalogService/DTOs/UpdateExerciceTemplateDto.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using Shared.Enum; + +namespace CatalogService.DTOs; + +public class UpdateExerciceTemplateDto +{ + [Required] + public required string Id { get; set; } + + public string? Name { get; set; } + + public string? Description { get; set; } + + public ETarget? Target { get; set; } + + public string? ImageUrl { get; set; } + + public string? VideoUrl { get; set; } +} \ No newline at end of file diff --git a/src/CatalogService/Program.cs b/src/CatalogService/Program.cs index cc4a318..d702251 100644 --- a/src/CatalogService/Program.cs +++ b/src/CatalogService/Program.cs @@ -10,6 +10,7 @@ builder.Services.AddDbContext(opt => opt.UseNpgsql(builder.Configuration.GetConnectionString("CatalogDb")); }); +builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); var app = builder.Build(); diff --git a/src/CatalogService/RequestHelpers/MappingProfiles.cs b/src/CatalogService/RequestHelpers/MappingProfiles.cs new file mode 100644 index 0000000..a1f98bb --- /dev/null +++ b/src/CatalogService/RequestHelpers/MappingProfiles.cs @@ -0,0 +1,16 @@ +using AutoMapper; +using CatalogService.DTOs; +using CatalogService.Entities; + +namespace CatalogService.RequestHelpers; + +public class MappingProfiles : Profile +{ + public MappingProfiles() + { + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + } +} \ No newline at end of file diff --git a/src/Shared/DTOs/DeleteDto.cs b/src/Shared/DTOs/DeleteDto.cs new file mode 100644 index 0000000..5317d16 --- /dev/null +++ b/src/Shared/DTOs/DeleteDto.cs @@ -0,0 +1,9 @@ +using System.ComponentModel.DataAnnotations; + +namespace Shared.DTOs; + +public class DeleteDto +{ + [Required] + public required string Id { get; set; } +} \ No newline at end of file diff --git a/src/Tests/postman/Catalog_Exercices.postman_collection.json b/src/Tests/postman/Catalog_Exercices.postman_collection.json new file mode 100644 index 0000000..159a90a --- /dev/null +++ b/src/Tests/postman/Catalog_Exercices.postman_collection.json @@ -0,0 +1,231 @@ +{ + "info": { + "_postman_id": "c019ebd5-bed6-49ea-a584-086e91bfe503", + "name": "Catalog Exercices", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Créer un exercice", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var jsonData = pm.response.json();", + "pm.test('Status code is 201', function() {", + " pm.response.to.have.status(201);", + "});", + "pm.test('L\'exercice a un id', function() {", + " pm.expect(jsonData.id).to.be.a('string');", + "});", + "pm.environment.set('exerciceId', jsonData.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"Pompes\",\n \"description\": \"Exercice de musculation pour les pectoraux\",\n \"target\": 1,\n \"imageUrl\": \"images/pompes.jpg\",\n \"videoUrl\": \"https://www.youtube.com/watch?v=IODxDxX7oi4\"\n}" + }, + "url": { + "raw": "{{catalogApi}}/api/exercices", + "host": [ + "{{catalogApi}}" + ], + "path": [ + "api", + "exercices" + ] + } + } + }, + { + "name": "Récupérer l'exercice par id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var jsonData = pm.response.json();", + "pm.test('Status code is 200', function() {", + " pm.response.to.have.status(200);", + "});", + "pm.test('Nom de l\\'exercice est Pompes', function() {", + " pm.expect(jsonData.name).to.eq('Pompes');", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{catalogApi}}/api/exercices/{{exerciceId}}", + "host": [ + "{{catalogApi}}" + ], + "path": [ + "api", + "exercices", + "{{exerciceId}}" + ] + } + } + }, + { + "name": "Mettre à jour l'exercice", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 204', function() {", + " pm.response.to.have.status(204);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"{{exerciceId}}\",\n \"name\": \"Pompes modifiées\",\n \"description\": \"Exercice modifié\",\n \"target\": 2,\n \"imageUrl\": \"images/pompes_mod.jpg\",\n \"videoUrl\": \"https://www.youtube.com/watch?v=abcd\"\n}" + }, + "url": { + "raw": "{{catalogApi}}/api/exercices/{{exerciceId}}", + "host": [ + "{{catalogApi}}" + ], + "path": [ + "api", + "exercices", + "{{exerciceId}}" + ] + } + } + }, + { + "name": "Vérifier la mise à jour", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var jsonData = pm.response.json();", + "pm.test('Status code is 200', function() {", + " pm.response.to.have.status(200);", + "});", + "pm.test('Nom de l\\'exercice est Pompes modifiées', function() {", + " pm.expect(jsonData.name).to.eq('Pompes modifiées');", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{catalogApi}}/api/exercices/{{exerciceId}}", + "host": [ + "{{catalogApi}}" + ], + "path": [ + "api", + "exercices", + "{{exerciceId}}" + ] + } + } + }, + { + "name": "Supprimer l'exercice", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 204', function() {", + " pm.response.to.have.status(204);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{catalogApi}}/api/exercices/{{exerciceId}}", + "host": [ + "{{catalogApi}}" + ], + "path": [ + "api", + "exercices", + "{{exerciceId}}" + ] + } + } + }, + { + "name": "Vérifier la suppression", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 404', function() {", + " pm.response.to.have.status(404);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{catalogApi}}/api/exercices/{{exerciceId}}", + "host": [ + "{{catalogApi}}" + ], + "path": [ + "api", + "exercices", + "{{exerciceId}}" + ] + } + } + } + ], + "variable": [ + { + "key": "catalogApi", + "value": "http://localhost:5000" + } + ] +}