diff --git a/ldap-cesi/Configurations/Conf.cs b/ldap-cesi/Configurations/Conf.cs index fa10ddd..b7bd501 100644 --- a/ldap-cesi/Configurations/Conf.cs +++ b/ldap-cesi/Configurations/Conf.cs @@ -62,9 +62,9 @@ public static class Conf { builder.Services.AddCors(options => { - options.AddPolicy("AllowAll", + options.AddPolicy("AllowSpecific", builder => builder - .AllowAnyOrigin() + .WithOrigins("http://localhost:3000") .AllowAnyMethod() .AllowAnyHeader()); }); diff --git a/ldap-cesi/Controllers/RoleController.cs b/ldap-cesi/Controllers/RoleController.cs index d865d03..213995f 100644 --- a/ldap-cesi/Controllers/RoleController.cs +++ b/ldap-cesi/Controllers/RoleController.cs @@ -23,10 +23,10 @@ namespace ldap_cesi.Controllers /// Un tableau de rôle [HttpGet] [Authorize(Roles = "admin")] - public async Task GetAllRoles() + public async Task GetAllRoles([FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 10) { - var result = await _roleService.GetAll(); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + var result = await _roleService.GetAll(pageNumber, pageSize); + return result.Success ? Ok(result) : BadRequest(result); } // GET: api/Role/{id} @@ -40,7 +40,7 @@ namespace ldap_cesi.Controllers public async Task GetRoleById(int id) { var result = await _roleService.GetById(id); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + return result.Success ? Ok(result) : BadRequest(result); } // POST: api/Role @@ -54,7 +54,7 @@ namespace ldap_cesi.Controllers public async Task CreateRole([FromBody] RoleCreateDto roleDto) { var result = await _roleService.Create(roleDto); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + return result.Success ? Ok(result) : BadRequest(result); } // PUT: api/Role @@ -68,7 +68,7 @@ namespace ldap_cesi.Controllers public async Task UpdateRole([FromBody] RoleUpdateDto roleDto) { var result = await _roleService.Update(roleDto); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + return result.Success ? Ok(result) : BadRequest(result); } // DELETE: api/Role/{id} @@ -82,7 +82,7 @@ namespace ldap_cesi.Controllers public async Task DeleteRole(int id) { var result = await _roleService.Delete(id); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + return result.Success ? Ok(result) : BadRequest(result); } } } diff --git a/ldap-cesi/Controllers/SalarieController.cs b/ldap-cesi/Controllers/SalarieController.cs index 6873f7c..1f831a6 100644 --- a/ldap-cesi/Controllers/SalarieController.cs +++ b/ldap-cesi/Controllers/SalarieController.cs @@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Mvc; namespace ldap_cesi.Controllers; [ApiController] -[Route("api/salarie")] +[Route("api/salaries")] public class SalarieController : ControllerBase { private ISalarieService _salarieService; @@ -21,21 +21,28 @@ public class SalarieController : ControllerBase /// /// Une liste de salariés. [HttpGet] - public async Task GetAllSalaries() + public async Task GetAllSalaries([FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 25) { - var result = await _salarieService.GetAll(); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); - } - - /// - /// Endpoint qui retourne tous les salariés. - /// - /// Une liste de salariés. - [HttpGet("/complete")] - public async Task GetAllSalariesComplet() + var result = await _salarieService.GetAll(pageNumber, pageSize); + return result.Success ? Ok(result) : BadRequest(result); + } + + + [HttpGet("search")] + public async Task SearchSalaries( + [FromQuery] string searchTerm, + [FromQuery] int pageNumber = 1, + [FromQuery] int pageSize = 10) { - var result = await _salarieService.GetAllWithoutIService(); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + if (string.IsNullOrWhiteSpace(searchTerm) || searchTerm.Length < 2) + { + return BadRequest("Votre recherche doit contenir au moins deux caractères."); + } + + var result = await _salarieService.SearchWithRelations( + searchTerm, pageNumber, pageSize, s => s.IdServiceNavigation, s => s.IdSiteNavigation); + + return result.Success ? Ok(result) : BadRequest(result); } /// @@ -47,19 +54,19 @@ public class SalarieController : ControllerBase public async Task GetById(int id) { var result = await _salarieService.GetById(id); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + return result.Success ? Ok(result) : BadRequest(result); } /// /// Endpoint qui retourne le salarié correspondant à l'ID en paramètre. Avec le nom de service et de site auxquels il apaprtient. /// /// L'ID du salarié. - /// Le salarié correspondant à l'ID. + /// Le salarié correspondant à l'ID. Ainsi que son service et son site [HttpGet("/complet/{id}")] public async Task GetSalarieCompletById(int id) { - var result = await _salarieService.GetCompletById(id); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + var result = await _salarieService.GetByIdWithRelations(id,s => s.IdServiceNavigation, s => s.IdSiteNavigation); + return result.Success ? Ok(result) : BadRequest(result); } /// @@ -67,10 +74,10 @@ public class SalarieController : ControllerBase /// /// Tous les salariés avec leurs relations [HttpGet("all")] - public async Task GetAllSariesWithRelations() + public async Task GetAllSariesWithRelations([FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 25) { - var result = await _salarieService.GetAllWithRelationsAsync(s => s.IdServiceNavigation, s => s.IdSiteNavigation); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + var result = await _salarieService.GetAllWithRelationsAsync(pageNumber, pageSize,s => s.IdServiceNavigation, s => s.IdSiteNavigation); + return result.Success ? Ok(result) : BadRequest(result); } /// @@ -83,7 +90,7 @@ public class SalarieController : ControllerBase public async Task CreateSalarie([FromBody] SalarieCreateDto salarieInput) { var result = await _salarieService.Create(salarieInput); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + return result.Success ? Ok(result) : BadRequest(result); } /// @@ -96,7 +103,7 @@ public class SalarieController : ControllerBase public async Task UpdateSalarie([FromBody] SalarieUpdateDto salarieInput) { var result = await _salarieService.Update(salarieInput); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + return result.Success ? Ok(result) : BadRequest(result); } /// @@ -109,7 +116,7 @@ public class SalarieController : ControllerBase public async Task DeleteSalarie(int id) { var result = await _salarieService.Delete(id); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + return result.Success ? Ok(result) : BadRequest(result); } /// @@ -121,7 +128,7 @@ public class SalarieController : ControllerBase public async Task GetSalariesBySite(int siteId) { var result = await _salarieService.GetSalariesBySite(siteId); - return result.Success ? Ok(result.Data) : NotFound(result.Message); + return result.Success ? Ok(result) : NotFound(result); } /// @@ -133,20 +140,7 @@ public class SalarieController : ControllerBase public async Task GetSalariesByService(int serviceId) { var result = await _salarieService.GetSalariesByService(serviceId); - return result.Success ? Ok(result.Data) : NotFound(result.Message); + return result.Success ? Ok(result) : NotFound(result); } - - /// - /// Endpoint qui met à jour partiellement un salarié. - /// - /// L'ID du salarié. - /// Les informations du salarié à mettre à jour partiellement. - /// Le salarié mis à jour partiellement. - // [HttpPatch("{id}")] - // [Authorize(Roles = "admin")] - // public async Task PatchSalarie(int id, [FromBody] SalariePatchDto salariePatch) - // { - // var result = await _salarieService.Patch(id, salariePatch); - // return result.Success ? Ok(result.Data) : BadRequest(result.Message); - // } + } diff --git a/ldap-cesi/Controllers/ServicesController.cs b/ldap-cesi/Controllers/ServicesController.cs index 8f2ec66..19ff669 100644 --- a/ldap-cesi/Controllers/ServicesController.cs +++ b/ldap-cesi/Controllers/ServicesController.cs @@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Mvc; namespace ldap_cesi.Controllers; [ApiController] -[Route("api/service")] +[Route("api/services")] public class ServicesController : ControllerBase { private IServiceService _serviceService; @@ -21,10 +21,9 @@ public class ServicesController : ControllerBase /// /// Retourne tous les services. [HttpGet] - public async Task GetServices() - { - var result = await _serviceService.GetAll(); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + public async Task GetServices([FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 10) { + var result = await _serviceService.GetAll(pageNumber, pageSize); + return result.Success ? Ok(result) : BadRequest(result); } /// @@ -36,7 +35,19 @@ public class ServicesController : ControllerBase public async Task GetServiceById(int id) { var result = await _serviceService.GetById(id); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + return result.Success ? Ok(result) : BadRequest(result); + } + + /// + /// Endpoint qui retourne le service et ses salariés correspondant à l'id en paramètre. + /// + /// L'ID du service. + /// Le service correspondant à l'ID, avec ses salariés + [HttpGet("complete/{id}")] + public async Task GetServiceByIdWithSalaries(int id) + { + var result = await _serviceService.GetByIdWithRelations(id, s=>s.Salaries); + return result.Success ? Ok(result) : BadRequest(result); } /// @@ -49,7 +60,7 @@ public class ServicesController : ControllerBase public async Task CreateService([FromBody] ServiceCreateDto serviceInputDto) { var result = await _serviceService.Create(serviceInputDto); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + return result.Success ? Ok(result.Data) : BadRequest(result); } /// @@ -62,7 +73,7 @@ public class ServicesController : ControllerBase public async Task UpdateService([FromBody] ServiceUpdateDto serviceUpdateDto) { var result = await _serviceService.Update(serviceUpdateDto); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + return result.Success ? Ok(result) : BadRequest(result); } /// @@ -75,6 +86,6 @@ public class ServicesController : ControllerBase public async Task DeleteService(int id) { var result = await _serviceService.Delete(id); - return result.Success ? Ok(result.Message) : BadRequest(result.Message); + return result.Success ? Ok(result) : BadRequest(result); } } \ No newline at end of file diff --git a/ldap-cesi/Controllers/SiteController.cs b/ldap-cesi/Controllers/SiteController.cs index 50664dc..51f4ee4 100644 --- a/ldap-cesi/Controllers/SiteController.cs +++ b/ldap-cesi/Controllers/SiteController.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Mvc; namespace ldap_cesi.Controllers; [ApiController] -[Route("/api/site")] +[Route("/api/sites")] public class SiteController : ControllerBase { private readonly ISiteService _siteService; @@ -21,9 +21,9 @@ public class SiteController : ControllerBase /// /// Retourne une liste de tous les sites. [HttpGet] - public async Task GetSites() + public async Task GetSites([FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 10) { - var result = await _siteService.GetAll(); + var result = await _siteService.GetAll(pageNumber, pageSize); return result.Success ? Ok(result) : BadRequest(result); } @@ -41,6 +41,19 @@ public class SiteController : ControllerBase { var result = await _siteService.GetById(id); return result.Success ? Ok(result) : BadRequest(result); + } + + // GET: api/site/{id} + /// + /// Récupère un site et ses salariés spécifique par son identifiant. + /// + /// L'identifiant du site à récupérer. + /// Retourne le site et ses salariés + [HttpGet("/complete/{id}")] + public async Task GetSiteWithClient(int id) + { + var result = await _siteService.GetByIdWithRelations(id, s => s.Salaries); + return result.Success ? Ok(result) : BadRequest(result); } // POST: api/site @@ -52,7 +65,7 @@ public class SiteController : ControllerBase [HttpPost] public async Task CreateSite([FromBody] SiteCreateDto siteCreateDto) { - var result = await _siteService.CreateSite(siteCreateDto); + var result = await _siteService.Create(siteCreateDto); return result.Success ? Ok(result) : BadRequest(result); } @@ -65,7 +78,7 @@ public class SiteController : ControllerBase [HttpPut] public async Task UpdateSite([FromBody] SiteUpdateDto siteUpdateDto) { - var result = await _siteService.UpdateSite(siteUpdateDto); + var result = await _siteService.Update(siteUpdateDto); return result.Success ? Ok(result) : BadRequest(result); } @@ -78,7 +91,7 @@ public class SiteController : ControllerBase [HttpDelete("{id}")] public async Task DeleteSite(int id) { - var result = await _siteService.DeleteSite(id); + var result = await _siteService.Delete(id); return result.Success ? Ok(result) : BadRequest(result); } } \ No newline at end of file diff --git a/ldap-cesi/Controllers/UtilisateurController.cs b/ldap-cesi/Controllers/UtilisateurController.cs index c56ca6f..660823d 100644 --- a/ldap-cesi/Controllers/UtilisateurController.cs +++ b/ldap-cesi/Controllers/UtilisateurController.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Mvc; namespace ldap_cesi.Controllers; [ApiController] -[Route("api/utilisateur")] +[Route("api/utilisateurs")] public class UtilisateurController : ControllerBase { private IUtilisateurService _utilisateurService; @@ -24,8 +24,8 @@ public class UtilisateurController : ControllerBase [HttpPost("login")] public async Task Login([FromBody] UtilisateurLoginDto utilisateurInput) { - var response = await _utilisateurService.Login(utilisateurInput); - return StatusCode(response.StatusCode, response); + var result = await _utilisateurService.Login(utilisateurInput); + return result.Success ? Ok(result) : BadRequest(result); } /// @@ -37,7 +37,7 @@ public class UtilisateurController : ControllerBase public async Task GetUtilisateurs() { var result = await _utilisateurService.GetAll(); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + return result.Success ? Ok(result) : BadRequest(result); } /// @@ -50,6 +50,6 @@ public class UtilisateurController : ControllerBase public async Task GetUtilisateurById(int id) { var result = await _utilisateurService.GetById(id); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + return result.Success ? Ok(result) : BadRequest(result); } } \ No newline at end of file diff --git a/ldap-cesi/DTOs/Generic/ServiceDto.cs b/ldap-cesi/DTOs/Generic/ServiceDto.cs index f786ae4..61f567b 100644 --- a/ldap-cesi/DTOs/Generic/ServiceDto.cs +++ b/ldap-cesi/DTOs/Generic/ServiceDto.cs @@ -1,3 +1,5 @@ +using ldap_cesi.DTOs.Outputs.Salarie; + namespace ldap_cesi.DTOs; public class ServiceDto @@ -5,4 +7,5 @@ public class ServiceDto public int Id { get; set; } public string Nom { get; set; } + public List Salaries { get; set; } } \ No newline at end of file diff --git a/ldap-cesi/DTOs/Generic/SiteDto.cs b/ldap-cesi/DTOs/Generic/SiteDto.cs index 82fa364..535f886 100644 --- a/ldap-cesi/DTOs/Generic/SiteDto.cs +++ b/ldap-cesi/DTOs/Generic/SiteDto.cs @@ -1,3 +1,5 @@ +using ldap_cesi.DTOs.Outputs.Salarie; + namespace ldap_cesi.DTOs; public class SiteDto @@ -5,4 +7,5 @@ public class SiteDto public int Id { get; set; } public string Ville { get; set; } + public ICollection Salaries { get; set; } } \ No newline at end of file diff --git a/ldap-cesi/DTOs/Outputs/Salarie/SalarieListDto.cs b/ldap-cesi/DTOs/Outputs/Salarie/SalarieListDto.cs index 07fccb5..0615eaa 100644 --- a/ldap-cesi/DTOs/Outputs/Salarie/SalarieListDto.cs +++ b/ldap-cesi/DTOs/Outputs/Salarie/SalarieListDto.cs @@ -1,3 +1,5 @@ +using ldap_cesi.DTOs.Outputs.Service; + namespace ldap_cesi.DTOs.Outputs.Salarie; public class SalarieListDto @@ -7,6 +9,6 @@ public class SalarieListDto public string Nom { get; set; } public string Prenom { get; set; } public string NomComplet => $"{Prenom} {Nom}"; - public ServiceDto Service { get; set; } - public SiteDto Site { get; set; } + public ServiceMinimalDto Service { get; set; } + public SiteMinimalDto Site { get; set; } } \ No newline at end of file diff --git a/ldap-cesi/DTOs/Outputs/Salarie/SalarieMinimalDto.cs b/ldap-cesi/DTOs/Outputs/Salarie/SalarieMinimalDto.cs new file mode 100644 index 0000000..bf4be29 --- /dev/null +++ b/ldap-cesi/DTOs/Outputs/Salarie/SalarieMinimalDto.cs @@ -0,0 +1,17 @@ +namespace ldap_cesi.DTOs.Outputs.Salarie; + +public class SalarieMinimalDto +{ + public int Id { get; set; } + + public string Nom { get; set; } = null!; + + public string Prenom { get; set; } = null!; + + public string TelephoneFixe { get; set; } = null!; + + public string TelephonePortable { get; set; } = null!; + + public string Email { get; set; } = null!; + +} \ No newline at end of file diff --git a/ldap-cesi/DTOs/Outputs/Salarie/SalarieOutputDetail.cs b/ldap-cesi/DTOs/Outputs/Salarie/SalarieOutputDetail.cs index 060b7cd..f7b1bd3 100644 --- a/ldap-cesi/DTOs/Outputs/Salarie/SalarieOutputDetail.cs +++ b/ldap-cesi/DTOs/Outputs/Salarie/SalarieOutputDetail.cs @@ -1,3 +1,5 @@ +using ldap_cesi.DTOs.Outputs.Service; + namespace ldap_cesi.DTOs.Outputs.Salarie; public class SalarieOutputDetail @@ -14,6 +16,6 @@ public class SalarieOutputDetail public string Email { get; set; } - public ServiceDto Service { get; set; } - public SiteDto Site { get; set; } + public ServiceMinimalDto Service { get; set; } + public SiteMinimalDto Site { get; set; } } \ No newline at end of file diff --git a/ldap-cesi/DTOs/Outputs/Service/ServiceMinimalDto.cs b/ldap-cesi/DTOs/Outputs/Service/ServiceMinimalDto.cs new file mode 100644 index 0000000..c373690 --- /dev/null +++ b/ldap-cesi/DTOs/Outputs/Service/ServiceMinimalDto.cs @@ -0,0 +1,8 @@ +namespace ldap_cesi.DTOs.Outputs.Service; + +public class ServiceMinimalDto +{ + public int Id { get; set; } + + public string Nom { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/DTOs/Outputs/Site/SiteMinimalDto.cs b/ldap-cesi/DTOs/Outputs/Site/SiteMinimalDto.cs new file mode 100644 index 0000000..eb6cfb4 --- /dev/null +++ b/ldap-cesi/DTOs/Outputs/Site/SiteMinimalDto.cs @@ -0,0 +1,8 @@ +namespace ldap_cesi.DTOs.Outputs.Service; + +public class SiteMinimalDto +{ + public int Id { get; set; } + + public string Ville { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/Mapper/AutoMapperProfile.cs b/ldap-cesi/Mapper/AutoMapperProfile.cs index 9d159bf..3acd83e 100644 --- a/ldap-cesi/Mapper/AutoMapperProfile.cs +++ b/ldap-cesi/Mapper/AutoMapperProfile.cs @@ -5,6 +5,7 @@ using ldap_cesi.DTOs.Inputs.Salarie; using ldap_cesi.DTOs.Inputs.Service; using ldap_cesi.DTOs.Inputs.Site; using ldap_cesi.DTOs.Outputs.Salarie; +using ldap_cesi.DTOs.Outputs.Service; using ldap_cesi.DTOs.Outputs.Utilisateur; using ldap_cesi.Entities; @@ -34,9 +35,16 @@ public class AutoMapperProfile : Profile CreateMap() .ForMember(dest => dest.Service, opt => opt.MapFrom(src => src.IdServiceNavigation)) .ForMember(dest => dest.Site, opt => opt.MapFrom(src => src.IdSiteNavigation)); + CreateMap() + .ForMember(dest => dest.Service, opt => opt.MapFrom(src => src.IdServiceNavigation)) + .ForMember(dest => dest.Site, opt => opt.MapFrom(src => src.IdSiteNavigation)); CreateMap(); - CreateMap(); + CreateMap(); + CreateMap(); + CreateMap() + .ForMember(dest => dest.Salaries, opt => opt.MapFrom(src => src.Salaries)); CreateMap(); + CreateMap(); CreateMap() .ForMember(dest => dest.Service, opt => opt.MapFrom(src => src.IdServiceNavigation.Nom)) .ForMember(dest => dest.Site, opt => opt.MapFrom(src => src.IdSiteNavigation.Ville)); diff --git a/ldap-cesi/Models/IEntity.cs b/ldap-cesi/Models/IEntity.cs deleted file mode 100644 index 2120b39..0000000 --- a/ldap-cesi/Models/IEntity.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ldap_cesi.Models; - -public interface IEntity -{ - int Id { get; set; } -} \ No newline at end of file diff --git a/ldap-cesi/Models/IResponseDataModel.cs b/ldap-cesi/Models/IResponseDataModel.cs index 1eb89dc..5255852 100644 --- a/ldap-cesi/Models/IResponseDataModel.cs +++ b/ldap-cesi/Models/IResponseDataModel.cs @@ -3,5 +3,7 @@ namespace ldap_cesi.Models; public interface IResponseDataModel : IResponseModel { public T Data { get; set; } + public int? TotalPages { get; set; } + public int? TotalCount { get; set; } string Token { get; set; } } \ No newline at end of file diff --git a/ldap-cesi/Models/PaginatedList.cs b/ldap-cesi/Models/PaginatedList.cs new file mode 100644 index 0000000..ae99066 --- /dev/null +++ b/ldap-cesi/Models/PaginatedList.cs @@ -0,0 +1,21 @@ +namespace ldap_cesi.Models; + +public class PaginatedList +{ + public List Datas { get; } + public int TotalCount { get; } + public int PageNumber { get; } + public int PageSize { get; } + public int TotalPages => (int)Math.Ceiling(TotalCount / (double)PageSize); + + public PaginatedList(List donnees, int totalCount, int pageNumber, int pageSize) + { + Datas = donnees; + TotalCount = totalCount; + PageNumber = pageNumber; + PageSize = pageSize; + } + + public bool HasPreviousPage => PageNumber > 1; + public bool HasNextPage => PageNumber < TotalPages; +} \ No newline at end of file diff --git a/ldap-cesi/Models/ResponseDataModel.cs b/ldap-cesi/Models/ResponseDataModel.cs index 1b415c7..220c124 100644 --- a/ldap-cesi/Models/ResponseDataModel.cs +++ b/ldap-cesi/Models/ResponseDataModel.cs @@ -3,4 +3,6 @@ namespace ldap_cesi.Models; public class ResponseDataModel : ResponseModel, IResponseDataModel where T : class { public T Data { get; set; } = null!; + public int? TotalPages { get; set; } + public int? TotalCount { get; set; } } \ No newline at end of file diff --git a/ldap-cesi/Program.cs b/ldap-cesi/Program.cs index e5ec0b7..0974d7a 100644 --- a/ldap-cesi/Program.cs +++ b/ldap-cesi/Program.cs @@ -1,4 +1,6 @@ using ldap_cesi.Configurations; +using ldap_cesi.Context; +using ldap_cesi.Seeders; var builder = WebApplication.CreateBuilder(args); builder.BuildConf(); @@ -21,8 +23,21 @@ if (app.Environment.IsDevelopment()) }); } +using (var scope = app.Services.CreateScope()) +{ + var services = scope.ServiceProvider; + var context = services.GetRequiredService(); + var seeder = new Seeders(context); + + if (app.Environment.IsDevelopment()) + { + await seeder.GenerateSalaries(500); + } +} + app.UseHttpsRedirection(); app.UseRouting(); +app.UseCors("AllowAll"); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); diff --git a/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs b/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs index 223565b..baf4780 100644 --- a/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs +++ b/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs @@ -7,11 +7,22 @@ public interface IRepositoryBase where TEntity : class Task AddAsync(TEntity entity, CancellationToken cancellationToken = default); Task AnyAsync(Expression> predicate, CancellationToken cancellationToken = default); Task GetByIdAsync(TId id, CancellationToken cancellationToken = default) where TId : notnull; - Task> GetAllAsync(CancellationToken cancellationToken = default); + + Task<(List Data, int TotalPages, int TotalItems)> GetAllAsync(int pageNumber = 1, int pageSize = 10, CancellationToken cancellationToken = default); Task UpdateAsync(TEntity entity, CancellationToken cancellationToken = default); Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default); Task GetWithRelationsAsync(int id, params Expression>[] relationsAInclude); - Task> GetAllWithRelationsAsync(params Expression>[] relationsAInclude); + + Task<(List Data, int TotalPages, int TotalItems)> GetAllWithRelationsAsync(int pageNumber = 1, int pageSize = 10, params Expression>[] relationInclues); + + Task<(List Data, int TotalPages, int TotalItems)> SearchAsync( + Expression> predicate, + int pageNumber = 1, + int pageSize = 10, + params Expression>[] relationsAInclude); + Task FirstOrDefaultAsync(Expression> predicate, CancellationToken cancellationToken = default); + + Task CountAsync(Expression> predicate, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/ldap-cesi/Repositories/RepositoryBase.cs b/ldap-cesi/Repositories/RepositoryBase.cs index d7fc138..886ed2e 100644 --- a/ldap-cesi/Repositories/RepositoryBase.cs +++ b/ldap-cesi/Repositories/RepositoryBase.cs @@ -34,18 +34,39 @@ public class RepositoryBase : IRepositoryBase where TEntity : return await _context.Set().AnyAsync(predicate, cancellationToken); } - - public virtual async Task> GetAllAsync(CancellationToken cancellationToken = default) + public virtual async Task GetByIdAsync(TId id, CancellationToken cancellationToken = default) where TId : notnull { try { - return await _context.Set().ToListAsync(cancellationToken); + return await _context.FindAsync(id, cancellationToken); } catch (Exception ex) { - throw new Exception("Erreur pendant la récupérations des entités.", ex); + throw new Exception($"Erreur lors de la récupération avec l'id : {id}.", ex); } } + + + public virtual async Task<(List Data, int TotalPages, int TotalItems)> GetAllAsync(int pageNumber = 1, int pageSize = 10, CancellationToken cancellationToken = default) + { + try + { + var totalCount = await _dbSet.CountAsync(cancellationToken); + var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize); + + var data = await _dbSet + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize) + .ToListAsync(cancellationToken); + + return (data, totalPages, totalCount); + } + catch (Exception ex) + { + throw new Exception("Erreur pendant la récupération des entités.", ex); + } + } + public virtual async Task FirstOrDefaultAsync(Expression> predicate, CancellationToken cancellationToken = default) { return await _context.Set().FirstOrDefaultAsync(predicate, cancellationToken); @@ -65,16 +86,24 @@ public class RepositoryBase : IRepositoryBase where TEntity : } } - public virtual async Task GetByIdAsync(TId id, CancellationToken cancellationToken = default) where TId : notnull + public virtual async Task<(List Data, int TotalPages, int TotalItems)> GetAllWithRelationsAsync(int pageNumber = 1, int pageSize = 10, params Expression>[] relationInclues) { - try + IQueryable query = _dbSet; + + foreach (var relationInclue in relationInclues) { - return await _context.FindAsync(id, cancellationToken); - } - catch (Exception ex) - { - throw new Exception($"Erreur lors de la récupération avec l'id : {id}.", ex); + query = query.Include(relationInclue); } + + var totalCount = await query.CountAsync(); + var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize); + + var data = await query + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize) + .ToListAsync(); + + return (data, totalPages, totalCount); } public virtual async Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default) @@ -137,5 +166,37 @@ public class RepositoryBase : IRepositoryBase where TEntity : return await query.FirstOrDefaultAsync(e => EF.Property(e, "Id") == id); } + + public virtual async Task<(List Data, int TotalPages, int TotalItems)> SearchAsync( + Expression> predicate, + int pageNumber = 1, + int pageSize = 10, + params Expression>[] relationsAInclude) + { + IQueryable query = _dbSet; + + foreach (var relationInclue in relationsAInclude) + { + query = query.Include(relationInclue); + } + + query = query.Where(predicate); + + var totalCount = await query.CountAsync(); + var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize); + + var data = await query + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize) + .ToListAsync(); + + return (data, totalPages, totalCount); + } + + public virtual async Task CountAsync(Expression> predicate, CancellationToken cancellationToken = default) + { + return await _dbSet.CountAsync(predicate, cancellationToken); + } + } \ No newline at end of file diff --git a/ldap-cesi/Seeders/Seeders.cs b/ldap-cesi/Seeders/Seeders.cs new file mode 100644 index 0000000..27334e3 --- /dev/null +++ b/ldap-cesi/Seeders/Seeders.cs @@ -0,0 +1,49 @@ +using Bogus; +using ldap_cesi.Context; +using ldap_cesi.Entities; +using Microsoft.EntityFrameworkCore; + +namespace ldap_cesi.Seeders; + +public class Seeders +{ + private readonly PgContext _context; + + public Seeders(PgContext context) + { + _context = context; + } + + public async Task GenerateSalaries(int count = 1000) + { + + if (await _context.Salaries.AnyAsync()) + { + Console.WriteLine("Des salariés existent déjà dans la base de données. Aucune donnée insérée."); + return; + } + + var salarieFaker = new Faker("fr") + .RuleFor(s => s.Nom, f => f.Name.LastName()) + .RuleFor(s => s.Prenom, f => f.Name.FirstName()) + .RuleFor(s => s.TelephoneFixe, f => f.Phone.PhoneNumber()) + .RuleFor(s => s.TelephonePortable, f => f.Phone.PhoneNumber()) + .RuleFor(s => s.Email, (f, s) => f.Internet.Email(s.Prenom, s.Nom)); + + var salaries = salarieFaker.Generate(count); + + // on s'assure que les relations (Service, Site) existent avant d'ajouter les salariés + var services = await _context.Services.ToListAsync(); + var sites = await _context.Sites.ToListAsync(); + + var random = new Random(); + foreach (var salarie in salaries) + { + salarie.IdServiceNavigation = services[random.Next(services.Count)]; + salarie.IdSiteNavigation = sites[random.Next(sites.Count)]; + } + + await _context.Salaries.AddRangeAsync(salaries); + await _context.SaveChangesAsync(); + } +} \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/ISalarieService.cs b/ldap-cesi/Services/Interfaces/ISalarieService.cs index af59cd0..1cbff57 100644 --- a/ldap-cesi/Services/Interfaces/ISalarieService.cs +++ b/ldap-cesi/Services/Interfaces/ISalarieService.cs @@ -7,9 +7,8 @@ using ldap_cesi.Models; namespace ldap_cesi.Services.Interfaces; -public interface ISalarieService : IServiceBase +public interface ISalarieService : IServiceBase { - Task>> GetAllWithoutIService(); Task>> GetSalariesBySite(int siteId); Task>> GetSalariesByService(int serviceId); Task> GetCompletById(int id); diff --git a/ldap-cesi/Services/Interfaces/IServiceBase.cs b/ldap-cesi/Services/Interfaces/IServiceBase.cs index a28d769..c00afe3 100644 --- a/ldap-cesi/Services/Interfaces/IServiceBase.cs +++ b/ldap-cesi/Services/Interfaces/IServiceBase.cs @@ -9,10 +9,13 @@ public interface IServiceBase where TCreateDto : class where TUpdateDto : class { - Task>> GetAll(); + Task>> GetAll(int pageNumber, int pageSize); Task> GetById(int id); Task> GetByIdWithRelations(int id, params Expression>[] relationsAInclures); // préciser avec une ou des fonctions lambda les relations à inclure dans la réponse - Task>> GetAllWithRelationsAsync(params Expression>[] relationsAInclure); + Task>> GetAllWithRelationsAsync(int pageNumber, int pageSize, params Expression>[] relationsAInclure); + + Task>> SearchWithRelations(string searchTerm, int pageNumber, int pageSize, + params Expression>[] includeProperties); Task> Create(TCreateDto dto); Task> Update(TUpdateDto dto); Task> Delete(int id); diff --git a/ldap-cesi/Services/Interfaces/ISiteService.cs b/ldap-cesi/Services/Interfaces/ISiteService.cs index cdff833..4c99e84 100644 --- a/ldap-cesi/Services/Interfaces/ISiteService.cs +++ b/ldap-cesi/Services/Interfaces/ISiteService.cs @@ -1,15 +1,15 @@ -using ldap_cesi.DTOs.Inputs.Service; +using ldap_cesi.DTOs; using ldap_cesi.DTOs.Inputs.Site; using ldap_cesi.Entities; using ldap_cesi.Models; namespace ldap_cesi.Services.Interfaces; -public interface ISiteService +public interface ISiteService : IServiceBase { - Task>> GetAll(); - Task> GetById(int id); - Task> CreateSite(SiteCreateDto siteCreateDto); - Task> UpdateSite(SiteUpdateDto siteUpdate); - Task> DeleteSite(int id); + // Task>> GetAll(); + // Task> GetById(int id); + // Task> CreateSite(SiteCreateDto siteCreateDto); + // Task> UpdateSite(SiteUpdateDto siteUpdate); + // Task> DeleteSite(int id); } \ No newline at end of file diff --git a/ldap-cesi/Services/SalarieService.cs b/ldap-cesi/Services/SalarieService.cs index 40a28b7..31b551f 100644 --- a/ldap-cesi/Services/SalarieService.cs +++ b/ldap-cesi/Services/SalarieService.cs @@ -11,7 +11,7 @@ using ldap_cesi.Validator.Salarie; namespace ldap_cesi.Services; -public class SalarieService : ServiceBase, ISalarieService +public class SalarieService : ServiceBase, ISalarieService { private IRepositorySalarie _repositorySalarie; private readonly IRepositorySite _repositorySite; @@ -28,28 +28,6 @@ public class SalarieService : ServiceBase>> GetAllWithoutIService() - { - var salaries = await _repositorySalarie.GetAllAsync(); - return new ResponseDataModel> - { - Success = true, - Data = salaries, - StatusCode = 200, - }; - } - - // public async Task> GetById(int id) - // { - // var salarie = await _repositorySalarie.GetSalarieWithRelationsAsync(id); - // return new ResponseDataModel - // { - // Success = true, - // Data = salarie, - // StatusCode = 200, - // }; - // } - public async Task> GetCompletById(int id) { var salarie = await _repositorySalarie.GetSalarieWithRelationsAsync(id); diff --git a/ldap-cesi/Services/ServiceBase.cs b/ldap-cesi/Services/ServiceBase.cs index c8e444a..e61c6a6 100644 --- a/ldap-cesi/Services/ServiceBase.cs +++ b/ldap-cesi/Services/ServiceBase.cs @@ -1,15 +1,10 @@ using AutoMapper; -using ldap_cesi.DTOs.Inputs.Site; -using ldap_cesi.Entities; using ldap_cesi.Models; using ldap_cesi.Repository.Services; using ldap_cesi.Services.Interfaces; -using ldap_cesi.Validator.Site; -using Microsoft.Extensions.Logging; -using System.Collections.Generic; using System.Linq.Expressions; -using System.Threading.Tasks; using FluentValidation; +using Microsoft.EntityFrameworkCore; namespace ldap_cesi.Services; @@ -34,15 +29,23 @@ public class ServiceBase : IServiceBase>> GetAll() + private Expression> BuildSearchPredicate(string inputSearch) + { + return entity => + EF.Functions.ILike(EF.Property(entity, "Nom"), $"%{inputSearch}%") || + EF.Functions.ILike(EF.Property(entity, "Prenom"), $"%{inputSearch}%"); + } + public virtual async Task>> GetAll(int pageNumber, int pageSize) { try { - var entities = await _repository.GetAllAsync(); + var response = await _repository.GetAllAsync( pageNumber, pageSize); return new ResponseDataModel> { Success = true, - Data = entities, + Data = response.Data, + TotalPages = response.TotalPages, + TotalCount = response.TotalItems, StatusCode = 200, Message = "Liste des entités récupérée avec succès." }; @@ -94,16 +97,18 @@ public class ServiceBase : IServiceBase>> GetAllWithRelationsAsync(params Expression>[] relationsAInclure) + public virtual async Task>> GetAllWithRelationsAsync(int pageNumber, int pageSize,params Expression>[] relationsAInclure) { try { - var entities = await _repository.GetAllWithRelationsAsync(relationsAInclure); - var dtos = _mapper.Map>(entities); + var response = await _repository.GetAllWithRelationsAsync(pageNumber, pageSize,relationsAInclure); + var dtos = _mapper.Map>(response.Data); return new ResponseDataModel> { Success = true, Data = dtos, + TotalPages = response.TotalPages, + TotalCount = response.TotalItems, StatusCode = 200, Message = "Liste des entités récupérée avec succès." }; @@ -263,4 +268,48 @@ public class ServiceBase : IServiceBase>> SearchWithRelations(string searchTerm, int pageNumber, int pageSize, params Expression>[] includeProperties) + { + if (string.IsNullOrWhiteSpace(searchTerm) || searchTerm.Length < 2) + { + return new ResponseDataModel> + { + Success = false, + Message = "Le terme de recherche doit contenir au moins deux caractères.", + StatusCode = 400 + }; + } + + try + { + var predicate = BuildSearchPredicate(searchTerm); + var entities = await _repository.SearchAsync(predicate, pageNumber, pageSize, includeProperties); + var dtos = _mapper.Map>(entities); + var totalCount = await _repository.CountAsync(predicate); + + var response = new PaginatedList(dtos, totalCount, pageNumber, pageSize); + + return new ResponseDataModel> + { + Success = true, + Data = response, + TotalPages = response.TotalPages, + TotalCount = response.TotalCount, + StatusCode = 200, + Message = "Recherche effectuée avec succès." + }; + } + catch (Exception ex) + { + _logger.LogError(ex, "Une erreur s'est produite lors de la recherche des entités."); + return new ResponseDataModel> + { + Success = false, + Message = "Une erreur s'est produite lors de la recherche des entités.", + StatusCode = 500 + }; + } + } + } \ No newline at end of file diff --git a/ldap-cesi/Services/SiteService.cs b/ldap-cesi/Services/SiteService.cs index 5d5628d..246fb98 100644 --- a/ldap-cesi/Services/SiteService.cs +++ b/ldap-cesi/Services/SiteService.cs @@ -1,4 +1,5 @@ using AutoMapper; +using ldap_cesi.DTOs; using ldap_cesi.DTOs.Inputs.Site; using ldap_cesi.Entities; using ldap_cesi.Models; @@ -8,144 +9,143 @@ using ldap_cesi.Validator.Site; namespace ldap_cesi.Services; -public class SiteService : ISiteService +public class SiteService : ServiceBase, ISiteService { private readonly IRepositorySite _repositorySite; - private readonly IMapper _mapper; - public SiteService(IRepositorySite repositorySite, IMapper mapper) + public SiteService(IRepositorySite repositorySite, IMapper mapper, + ILogger logger, SiteCreateValidator siteCreateValidator, SiteUpdateValidator siteUpdateValidator) + : base(repositorySite, mapper, logger, siteCreateValidator, siteUpdateValidator ) { _repositorySite = repositorySite; - _mapper = mapper; } - public async Task>> GetAll() - { - var sites = await _repositorySite.GetAllAsync(); - return new ResponseDataModel> - { - Success = true, - Data = sites, - StatusCode = 200, - }; + // public async Task>> GetAll() + // { + // var sites = await _repositorySite.GetAllAsync(); + // return new ResponseDataModel> + // { + // Success = true, + // Data = sites, + // StatusCode = 200, + // }; + // } + // + // public async Task> GetById(int id) + // { + // var site = await _repositorySite.GetByIdAsync(id); + // return new ResponseDataModel + // { + // Success = true, + // Data = site, + // StatusCode = 200, + // }; } - public async Task> GetById(int id) - { - var site = await _repositorySite.GetByIdAsync(id); - return new ResponseDataModel - { - Success = true, - Data = site, - StatusCode = 200, - }; - } - - public async Task> CreateSite(SiteCreateDto siteCreateDto) - { - var validation = new SiteCreateValidator(); - var result = validation.Validate(siteCreateDto); - if (!result.IsValid) - { - return new ResponseDataModel - { - StatusCode = 400, - Success = false, - Message = "Données du site invalides: " + string.Join(", ", result.Errors) - }; - } - var site = _mapper.Map(siteCreateDto); - var response = await _repositorySite.AddAsync(site); - return new ResponseDataModel - { - StatusCode = 201, - Success = true, - Data = response.Id.ToString(), - }; - } - - public async Task> UpdateSite(SiteUpdateDto siteUpdate) - { - var validation = new SiteUpdateValidator(); - var result = validation.Validate(siteUpdate); - if (!result.IsValid) - { - return new ResponseDataModel - { - StatusCode = 400, - Success = false, - Message = "Données du site invalides: " + string.Join(", ", result.Errors) - }; - } - - var siteFind = await _repositorySite.GetByIdAsync(siteUpdate.Id); - if (siteFind is null) - { - return new ResponseDataModel - { - Success = false, - Message = "Site introuvable.", - StatusCode = 404 - }; - } - - var site = _mapper.Map(siteUpdate, siteFind); - var response = await _repositorySite.UpdateAsync(site); - if (!response) - { - return new ResponseDataModel - { - StatusCode = 500, - Success = false, - Message = "Erreur lors de la mise à jour du site : " + string.Join(", ", result.Errors) - }; - } - return new ResponseDataModel - { - StatusCode = 200, - Success = true, - Data = site, - }; - } - - public async Task> DeleteSite(int id) - { - if (id == null) - { - return new ResponseDataModel - { - StatusCode = 400, - Success = false, - Message = "Id manquant" - }; - } - - var site = await _repositorySite.GetByIdAsync(id); - if (site == null) - { - return new ResponseDataModel - { - Success = false, - Message = "Site introuvable.", - StatusCode = 404 - }; - } - var response = await _repositorySite.DeleteAsync(site); - if (!response) - { - return new ResponseDataModel - { - StatusCode = 500, - Success = false, - Message = "Erreur durant la suppression du site" - }; - } - return new ResponseDataModel - { - StatusCode = 200, - Success = true, - Data = site.Id.ToString(), - }; - } -} \ No newline at end of file + // public async Task> CreateSite(SiteCreateDto siteCreateDto) + // { + // var validation = new SiteCreateValidator(); + // var result = validation.Validate(siteCreateDto); + // if (!result.IsValid) + // { + // return new ResponseDataModel + // { + // StatusCode = 400, + // Success = false, + // Message = "Données du site invalides: " + string.Join(", ", result.Errors) + // }; + // } + // var site = _mapper.Map(siteCreateDto); + // var response = await _repositorySite.AddAsync(site); + // return new ResponseDataModel + // { + // StatusCode = 201, + // Success = true, + // Data = response.Id.ToString(), + // }; + // } + // + // public async Task> UpdateSite(SiteUpdateDto siteUpdate) + // { + // var validation = new SiteUpdateValidator(); + // var result = validation.Validate(siteUpdate); + // if (!result.IsValid) + // { + // return new ResponseDataModel + // { + // StatusCode = 400, + // Success = false, + // Message = "Données du site invalides: " + string.Join(", ", result.Errors) + // }; + // } + // + // var siteFind = await _repositorySite.GetByIdAsync(siteUpdate.Id); + // if (siteFind is null) + // { + // return new ResponseDataModel + // { + // Success = false, + // Message = "Site introuvable.", + // StatusCode = 404 + // }; + // } + // + // var site = _mapper.Map(siteUpdate, siteFind); + // var response = await _repositorySite.UpdateAsync(site); + // if (!response) + // { + // return new ResponseDataModel + // { + // StatusCode = 500, + // Success = false, + // Message = "Erreur lors de la mise à jour du site : " + string.Join(", ", result.Errors) + // }; + // } + // return new ResponseDataModel + // { + // StatusCode = 200, + // Success = true, + // Data = site, + // }; + // } + // + // public async Task> DeleteSite(int id) + // { + // if (id == null) + // { + // return new ResponseDataModel + // { + // StatusCode = 400, + // Success = false, + // Message = "Id manquant" + // }; + // } + // + // var site = await _repositorySite.GetByIdAsync(id); + // if (site == null) + // { + // return new ResponseDataModel + // { + // Success = false, + // Message = "Site introuvable.", + // StatusCode = 404 + // }; + // } + // var response = await _repositorySite.DeleteAsync(site); + // if (!response) + // { + // return new ResponseDataModel + // { + // StatusCode = 500, + // Success = false, + // Message = "Erreur durant la suppression du site" + // }; + // } + // return new ResponseDataModel + // { + // StatusCode = 200, + // Success = true, + // Data = site.Id.ToString(), + // }; + // } diff --git a/ldap-cesi/Services/UtilisateurService.cs b/ldap-cesi/Services/UtilisateurService.cs index 3abf032..364b5f8 100644 --- a/ldap-cesi/Services/UtilisateurService.cs +++ b/ldap-cesi/Services/UtilisateurService.cs @@ -1,7 +1,6 @@ using AutoMapper; using ldap_cesi.DTOs.Inputs; using ldap_cesi.DTOs.Outputs.Utilisateur; -using ldap_cesi.Entities; using ldap_cesi.Models; using ldap_cesi.Repository.Services; using ldap_cesi.Services.Interfaces; @@ -23,7 +22,7 @@ public class UtilisateurService : IUtilisateurService public async Task>> GetAll() { - var utilisateurs = await _repositoryUtilisateur.GetAllAsync(); + var utilisateurs = await _repositoryUtilisateur.GetAllAsync(1,10); var utilisateursOutputDto = _mapper.Map>(utilisateurs); return new ResponseDataModel> { diff --git a/ldap-cesi/ldap-cesi.csproj b/ldap-cesi/ldap-cesi.csproj index 9ef0878..06958b9 100644 --- a/ldap-cesi/ldap-cesi.csproj +++ b/ldap-cesi/ldap-cesi.csproj @@ -12,6 +12,7 @@ +