From 37eca08753ce71ebbb973c52c260c86453a3012d Mon Sep 17 00:00:00 2001 From: BuzzLeclair Date: Wed, 5 Mar 2025 21:00:30 +0100 Subject: [PATCH] =?UTF-8?q?-=20Ajout=20de=20la=20fonctionnalit=C3=A9=20de?= =?UTF-8?q?=20recherche=20-=20Ajout=20du=20Seed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ldap-cesi/Controllers/SalarieController.cs | 45 ++++++++--------- ldap-cesi/Models/IEntity.cs | 6 --- ldap-cesi/Models/PaginatedList.cs | 21 ++++++++ ldap-cesi/Program.cs | 14 ++++++ .../Interfaces/IRepositoryBase.cs | 6 +++ ldap-cesi/Repositories/RepositoryBase.cs | 23 +++++++++ ldap-cesi/Seeders/Seeders.cs | 49 +++++++++++++++++++ ldap-cesi/Services/Interfaces/IServiceBase.cs | 3 ++ ldap-cesi/Services/ServiceBase.cs | 49 +++++++++++++++++++ ldap-cesi/ldap-cesi.csproj | 1 + 10 files changed, 186 insertions(+), 31 deletions(-) delete mode 100644 ldap-cesi/Models/IEntity.cs create mode 100644 ldap-cesi/Models/PaginatedList.cs create mode 100644 ldap-cesi/Seeders/Seeders.cs diff --git a/ldap-cesi/Controllers/SalarieController.cs b/ldap-cesi/Controllers/SalarieController.cs index 6873f7c..4e0a67c 100644 --- a/ldap-cesi/Controllers/SalarieController.cs +++ b/ldap-cesi/Controllers/SalarieController.cs @@ -25,16 +25,24 @@ public class SalarieController : ControllerBase { 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() + } + + + [HttpGet("search")] + [Authorize(Roles = "admin")] + public async Task SearchSalaries( + [FromQuery] string searchTerm, + [FromQuery] int pageNumber = 1, + [FromQuery] int pageSize = 10) { - var result = await _salarieService.GetAllWithoutIService(); + 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.Data) : BadRequest(result.Message); } @@ -54,11 +62,11 @@ public class SalarieController : ControllerBase /// 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); + var result = await _salarieService.GetByIdWithRelations(id,s => s.IdServiceNavigation, s => s.IdSiteNavigation); return result.Success ? Ok(result.Data) : BadRequest(result.Message); } @@ -135,18 +143,5 @@ public class SalarieController : ControllerBase var result = await _salarieService.GetSalariesByService(serviceId); return result.Success ? Ok(result.Data) : NotFound(result.Message); } - - /// - /// 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/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/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/Program.cs b/ldap-cesi/Program.cs index e5ec0b7..350af1f 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,6 +23,18 @@ 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.UseAuthentication(); diff --git a/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs b/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs index 223565b..71ff6f6 100644 --- a/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs +++ b/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs @@ -12,6 +12,12 @@ public interface IRepositoryBase where TEntity : class Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default); Task GetWithRelationsAsync(int id, params Expression>[] relationsAInclude); Task> GetAllWithRelationsAsync(params Expression>[] relationsAInclude); + + Task> SearchAsync(Expression> predicate, int numPage, int taillePage, + 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..ecaf316 100644 --- a/ldap-cesi/Repositories/RepositoryBase.cs +++ b/ldap-cesi/Repositories/RepositoryBase.cs @@ -137,5 +137,28 @@ public class RepositoryBase : IRepositoryBase where TEntity : return await query.FirstOrDefaultAsync(e => EF.Property(e, "Id") == id); } + + public virtual async Task> SearchAsync(Expression> predicate, int numPage, int taillePage, params Expression>[] relationsAInclude) + { + IQueryable query = _dbSet; + + foreach (var relationInclue in relationsAInclude) + { + query = query.Include(relationInclue); + } + + query = query.Where(predicate); + + return await query + .Skip((numPage - 1) * taillePage) + .Take(taillePage) + .ToListAsync(); + } + + 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/IServiceBase.cs b/ldap-cesi/Services/Interfaces/IServiceBase.cs index a28d769..c91635b 100644 --- a/ldap-cesi/Services/Interfaces/IServiceBase.cs +++ b/ldap-cesi/Services/Interfaces/IServiceBase.cs @@ -13,6 +13,9 @@ public interface IServiceBase 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>> 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/ServiceBase.cs b/ldap-cesi/Services/ServiceBase.cs index c8e444a..1904e88 100644 --- a/ldap-cesi/Services/ServiceBase.cs +++ b/ldap-cesi/Services/ServiceBase.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Linq.Expressions; using System.Threading.Tasks; using FluentValidation; +using Microsoft.EntityFrameworkCore; namespace ldap_cesi.Services; @@ -34,6 +35,12 @@ public class ServiceBase : IServiceBase> 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() { try @@ -263,4 +270,46 @@ 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 paginatedList = new PaginatedList(dtos, totalCount, pageNumber, pageSize); + + return new ResponseDataModel> + { + Success = true, + Data = paginatedList, + 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/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 @@ +