From 365bc98215a35f51ea326a2e9596428269480162 Mon Sep 17 00:00:00 2001 From: BuzzLeclair Date: Fri, 28 Feb 2025 12:00:33 +0100 Subject: [PATCH 01/17] Premier push --- .idea/.idea.ldap-cesi/.idea/.gitignore | 13 +++++++ .idea/.idea.ldap-cesi/.idea/encodings.xml | 4 ++ .idea/.idea.ldap-cesi/.idea/indexLayout.xml | 8 ++++ .idea/.idea.ldap-cesi/.idea/misc.xml | 26 +++++++++++++ .idea/.idea.ldap-cesi/.idea/vcs.xml | 4 ++ ldap-cesi.sln | 16 ++++++++ ldap-cesi/.gitignore | 9 +++++ ldap-cesi/Program.cs | 41 +++++++++++++++++++++ ldap-cesi/Properties/launchSettings.json | 23 ++++++++++++ ldap-cesi/ldap-cesi.csproj | 14 +++++++ ldap-cesi/ldap-cesi.http | 6 +++ 11 files changed, 164 insertions(+) create mode 100644 .idea/.idea.ldap-cesi/.idea/.gitignore create mode 100644 .idea/.idea.ldap-cesi/.idea/encodings.xml create mode 100644 .idea/.idea.ldap-cesi/.idea/indexLayout.xml create mode 100644 .idea/.idea.ldap-cesi/.idea/misc.xml create mode 100644 .idea/.idea.ldap-cesi/.idea/vcs.xml create mode 100644 ldap-cesi.sln create mode 100644 ldap-cesi/.gitignore create mode 100644 ldap-cesi/Program.cs create mode 100644 ldap-cesi/Properties/launchSettings.json create mode 100644 ldap-cesi/ldap-cesi.csproj create mode 100644 ldap-cesi/ldap-cesi.http diff --git a/.idea/.idea.ldap-cesi/.idea/.gitignore b/.idea/.idea.ldap-cesi/.idea/.gitignore new file mode 100644 index 0000000..8700c2a --- /dev/null +++ b/.idea/.idea.ldap-cesi/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/modules.xml +/.idea.ldap-cesi.iml +/projectSettingsUpdater.xml +/contentModel.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.idea.ldap-cesi/.idea/encodings.xml b/.idea/.idea.ldap-cesi/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/.idea/.idea.ldap-cesi/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.ldap-cesi/.idea/indexLayout.xml b/.idea/.idea.ldap-cesi/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/.idea/.idea.ldap-cesi/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.ldap-cesi/.idea/misc.xml b/.idea/.idea.ldap-cesi/.idea/misc.xml new file mode 100644 index 0000000..0cfc445 --- /dev/null +++ b/.idea/.idea.ldap-cesi/.idea/misc.xml @@ -0,0 +1,26 @@ + + + {} + + + + + + Android Lint: Security + + + Code Coverage + + + HTML + + + + + AndroidLintBadHostnameVerifier + + + + + + \ No newline at end of file diff --git a/.idea/.idea.ldap-cesi/.idea/vcs.xml b/.idea/.idea.ldap-cesi/.idea/vcs.xml new file mode 100644 index 0000000..d843f34 --- /dev/null +++ b/.idea/.idea.ldap-cesi/.idea/vcs.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/ldap-cesi.sln b/ldap-cesi.sln new file mode 100644 index 0000000..4509d4e --- /dev/null +++ b/ldap-cesi.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ldap-cesi", "ldap-cesi\ldap-cesi.csproj", "{0AE1CE6A-DF41-4377-92A9-80E130D27F8B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0AE1CE6A-DF41-4377-92A9-80E130D27F8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0AE1CE6A-DF41-4377-92A9-80E130D27F8B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0AE1CE6A-DF41-4377-92A9-80E130D27F8B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0AE1CE6A-DF41-4377-92A9-80E130D27F8B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/ldap-cesi/.gitignore b/ldap-cesi/.gitignore new file mode 100644 index 0000000..3775ac8 --- /dev/null +++ b/ldap-cesi/.gitignore @@ -0,0 +1,9 @@ +bin/ +obj/ +/packages/ +riderModule.iml +/_ReSharper.Caches/ +appsettings.json +appsettings.Development.json +/.env +/logs \ No newline at end of file diff --git a/ldap-cesi/Program.cs b/ldap-cesi/Program.cs new file mode 100644 index 0000000..d5e0ef3 --- /dev/null +++ b/ldap-cesi/Program.cs @@ -0,0 +1,41 @@ +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi +builder.Services.AddOpenApi(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.MapOpenApi(); +} + +app.UseHttpsRedirection(); + +var summaries = new[] +{ + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" +}; + +app.MapGet("/weatherforecast", () => + { + var forecast = Enumerable.Range(1, 5).Select(index => + new WeatherForecast + ( + DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + Random.Shared.Next(-20, 55), + summaries[Random.Shared.Next(summaries.Length)] + )) + .ToArray(); + return forecast; + }) + .WithName("GetWeatherForecast"); + +app.Run(); + +record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) +{ + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); +} \ No newline at end of file diff --git a/ldap-cesi/Properties/launchSettings.json b/ldap-cesi/Properties/launchSettings.json new file mode 100644 index 0000000..584f844 --- /dev/null +++ b/ldap-cesi/Properties/launchSettings.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "http://localhost:5080", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "https://localhost:7079;http://localhost:5080", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/ldap-cesi/ldap-cesi.csproj b/ldap-cesi/ldap-cesi.csproj new file mode 100644 index 0000000..ab3c826 --- /dev/null +++ b/ldap-cesi/ldap-cesi.csproj @@ -0,0 +1,14 @@ + + + + net9.0 + enable + enable + ldap_cesi + + + + + + + diff --git a/ldap-cesi/ldap-cesi.http b/ldap-cesi/ldap-cesi.http new file mode 100644 index 0000000..352c4f9 --- /dev/null +++ b/ldap-cesi/ldap-cesi.http @@ -0,0 +1,6 @@ +@ldap_cesi_HostAddress = http://localhost:5080 + +GET {{ldap_cesi_HostAddress}}/weatherforecast/ +Accept: application/json + +### From 64fa663501f03eb085af7810c0f34dda1f6d97f7 Mon Sep 17 00:00:00 2001 From: BuzzLeclair Date: Sat, 1 Mar 2025 12:45:48 +0100 Subject: [PATCH 02/17] =?UTF-8?q?Ajout=20des=20entit=C3=A9s=20du=20PgConte?= =?UTF-8?q?xt=20directemen=20g=C3=A9n=C3=A9r=C3=A9=20via=20EfCore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.idea.ldap-cesi/.idea/dataSources.xml | 18 +++ ldap-cesi/Configurations/Conf.cs | 19 +++ ldap-cesi/Context/PgContext.cs | 135 ++++++++++++++++++++ ldap-cesi/Entities/Role.cs | 13 ++ ldap-cesi/Entities/Salarie.cs | 27 ++++ ldap-cesi/Entities/Service.cs | 13 ++ ldap-cesi/Entities/Site.cs | 13 ++ ldap-cesi/Entities/Utilisateur.cs | 19 +++ ldap-cesi/Program.cs | 29 +---- ldap-cesi/ldap-cesi.csproj | 17 +++ 10 files changed, 277 insertions(+), 26 deletions(-) create mode 100644 .idea/.idea.ldap-cesi/.idea/dataSources.xml create mode 100644 ldap-cesi/Configurations/Conf.cs create mode 100644 ldap-cesi/Context/PgContext.cs create mode 100644 ldap-cesi/Entities/Role.cs create mode 100644 ldap-cesi/Entities/Salarie.cs create mode 100644 ldap-cesi/Entities/Service.cs create mode 100644 ldap-cesi/Entities/Site.cs create mode 100644 ldap-cesi/Entities/Utilisateur.cs diff --git a/.idea/.idea.ldap-cesi/.idea/dataSources.xml b/.idea/.idea.ldap-cesi/.idea/dataSources.xml new file mode 100644 index 0000000..62b6f3e --- /dev/null +++ b/.idea/.idea.ldap-cesi/.idea/dataSources.xml @@ -0,0 +1,18 @@ + + + + + postgresql + true + org.postgresql.Driver + jdbc:postgresql://192.168.1.196:5432/ldap + + + + + + + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/ldap-cesi/Configurations/Conf.cs b/ldap-cesi/Configurations/Conf.cs new file mode 100644 index 0000000..d1dbb77 --- /dev/null +++ b/ldap-cesi/Configurations/Conf.cs @@ -0,0 +1,19 @@ +using ldap_cesi.Context; +using ldap_cesi.Entities; +using Microsoft.EntityFrameworkCore; + +namespace ldap_cesi.Configurations; + +public static class Conf +{ + public static void BuildConf(this WebApplicationBuilder builder) + { + builder.AddEFCoreConfiguration(); + } + + public static void AddEFCoreConfiguration(this WebApplicationBuilder builder) + { + string connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); + builder.Services.AddDbContext(options => options.UseNpgsql(connectionString)); + } +} \ No newline at end of file diff --git a/ldap-cesi/Context/PgContext.cs b/ldap-cesi/Context/PgContext.cs new file mode 100644 index 0000000..778e575 --- /dev/null +++ b/ldap-cesi/Context/PgContext.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using ldap_cesi.Entities; +using Microsoft.EntityFrameworkCore; + +namespace ldap_cesi.Context; + +public partial class PgContext : DbContext +{ + public PgContext() + { + } + + public PgContext(DbContextOptions options) + : base(options) + { + } + + public virtual DbSet Roles { get; set; } + + public virtual DbSet Salaries { get; set; } + + public virtual DbSet Services { get; set; } + + public virtual DbSet Sites { get; set; } + + public virtual DbSet Utilisateurs { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) +#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see https://go.microsoft.com/fwlink/?LinkId=723263. + => optionsBuilder.UseNpgsql("Host=192.168.1.196;Database=ldap;Username=postgres;Password=pimer0-buzz"); + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("role_pk"); + + entity.ToTable("role"); + + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.Nom) + .HasMaxLength(50) + .HasColumnName("nom"); + }); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("salarie_pk"); + + entity.ToTable("salarie"); + + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.Email) + .HasMaxLength(50) + .HasColumnName("email"); + entity.Property(e => e.IdService).HasColumnName("id_service"); + entity.Property(e => e.IdSite).HasColumnName("id_site"); + entity.Property(e => e.Nom) + .HasMaxLength(50) + .HasColumnName("nom"); + entity.Property(e => e.Prenom) + .HasMaxLength(50) + .HasColumnName("prenom"); + entity.Property(e => e.TelephoneFixe) + .HasMaxLength(50) + .HasColumnName("telephone_fixe"); + entity.Property(e => e.TelephonePortable) + .HasMaxLength(50) + .HasColumnName("telephone_portable"); + + entity.HasOne(d => d.IdServiceNavigation).WithMany(p => p.Salaries) + .HasForeignKey(d => d.IdService) + .OnDelete(DeleteBehavior.ClientSetNull) + .HasConstraintName("salarie_service0_fk"); + + entity.HasOne(d => d.IdSiteNavigation).WithMany(p => p.Salaries) + .HasForeignKey(d => d.IdSite) + .OnDelete(DeleteBehavior.ClientSetNull) + .HasConstraintName("salarie_site_fk"); + }); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("service_pk"); + + entity.ToTable("service"); + + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.Nom) + .HasMaxLength(50) + .HasColumnName("nom"); + }); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("site_pk"); + + entity.ToTable("site"); + + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.Ville) + .HasMaxLength(150) + .HasColumnName("ville"); + }); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("utilisateur_pk"); + + entity.ToTable("utilisateur"); + + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.IdRole).HasColumnName("id_role"); + entity.Property(e => e.MotDePasse) + .HasMaxLength(50) + .HasColumnName("mot_de_passe"); + entity.Property(e => e.Nom) + .HasMaxLength(50) + .HasColumnName("nom"); + entity.Property(e => e.Prenom) + .HasMaxLength(50) + .HasColumnName("prenom"); + + entity.HasOne(d => d.IdRoleNavigation).WithMany(p => p.Utilisateurs) + .HasForeignKey(d => d.IdRole) + .OnDelete(DeleteBehavior.ClientSetNull) + .HasConstraintName("utilisateur_role_fk"); + }); + + OnModelCreatingPartial(modelBuilder); + } + + partial void OnModelCreatingPartial(ModelBuilder modelBuilder); +} diff --git a/ldap-cesi/Entities/Role.cs b/ldap-cesi/Entities/Role.cs new file mode 100644 index 0000000..bd74754 --- /dev/null +++ b/ldap-cesi/Entities/Role.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; + +namespace ldap_cesi.Entities; + +public partial class Role +{ + public int Id { get; set; } + + public string Nom { get; set; } = null!; + + public virtual ICollection Utilisateurs { get; set; } = new List(); +} diff --git a/ldap-cesi/Entities/Salarie.cs b/ldap-cesi/Entities/Salarie.cs new file mode 100644 index 0000000..9ccc76a --- /dev/null +++ b/ldap-cesi/Entities/Salarie.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; + +namespace ldap_cesi.Entities; + +public partial class Salarie +{ + 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!; + + public int IdSite { get; set; } + + public int IdService { get; set; } + + public virtual Service IdServiceNavigation { get; set; } = null!; + + public virtual Site IdSiteNavigation { get; set; } = null!; +} diff --git a/ldap-cesi/Entities/Service.cs b/ldap-cesi/Entities/Service.cs new file mode 100644 index 0000000..912f597 --- /dev/null +++ b/ldap-cesi/Entities/Service.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; + +namespace ldap_cesi.Entities; + +public partial class Service +{ + public int Id { get; set; } + + public string Nom { get; set; } = null!; + + public virtual ICollection Salaries { get; set; } = new List(); +} diff --git a/ldap-cesi/Entities/Site.cs b/ldap-cesi/Entities/Site.cs new file mode 100644 index 0000000..40c7f26 --- /dev/null +++ b/ldap-cesi/Entities/Site.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; + +namespace ldap_cesi.Entities; + +public partial class Site +{ + public int Id { get; set; } + + public string? Ville { get; set; } + + public virtual ICollection Salaries { get; set; } = new List(); +} diff --git a/ldap-cesi/Entities/Utilisateur.cs b/ldap-cesi/Entities/Utilisateur.cs new file mode 100644 index 0000000..8f2223b --- /dev/null +++ b/ldap-cesi/Entities/Utilisateur.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; + +namespace ldap_cesi.Entities; + +public partial class Utilisateur +{ + public int Id { get; set; } + + public string? Nom { get; set; } + + public string? Prenom { get; set; } + + public string? MotDePasse { get; set; } + + public int IdRole { get; set; } + + public virtual Role IdRoleNavigation { get; set; } = null!; +} diff --git a/ldap-cesi/Program.cs b/ldap-cesi/Program.cs index d5e0ef3..5881c4b 100644 --- a/ldap-cesi/Program.cs +++ b/ldap-cesi/Program.cs @@ -1,7 +1,8 @@ +using ldap_cesi.Configurations; + var builder = WebApplication.CreateBuilder(args); -// Add services to the container. -// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi +builder.BuildConf(); builder.Services.AddOpenApi(); var app = builder.Build(); @@ -14,28 +15,4 @@ if (app.Environment.IsDevelopment()) app.UseHttpsRedirection(); -var summaries = new[] -{ - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" -}; - -app.MapGet("/weatherforecast", () => - { - var forecast = Enumerable.Range(1, 5).Select(index => - new WeatherForecast - ( - DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - Random.Shared.Next(-20, 55), - summaries[Random.Shared.Next(summaries.Length)] - )) - .ToArray(); - return forecast; - }) - .WithName("GetWeatherForecast"); - app.Run(); - -record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) -{ - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); -} \ No newline at end of file diff --git a/ldap-cesi/ldap-cesi.csproj b/ldap-cesi/ldap-cesi.csproj index ab3c826..e7d67ee 100644 --- a/ldap-cesi/ldap-cesi.csproj +++ b/ldap-cesi/ldap-cesi.csproj @@ -8,7 +8,24 @@ + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + From 66a00c60145c388107a6dee3ae304db9b2e184de Mon Sep 17 00:00:00 2001 From: BuzzLeclair Date: Sat, 1 Mar 2025 12:49:59 +0100 Subject: [PATCH 03/17] =?UTF-8?q?Ajout=20des=20r=C3=A9pertoires=20n=C3=A9c?= =?UTF-8?q?essaires=20au=20clean=20design=20pattern?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ldap-cesi/ldap-cesi.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ldap-cesi/ldap-cesi.csproj b/ldap-cesi/ldap-cesi.csproj index e7d67ee..b240452 100644 --- a/ldap-cesi/ldap-cesi.csproj +++ b/ldap-cesi/ldap-cesi.csproj @@ -25,7 +25,11 @@ + + + + From 6d3717db74d807b281686adbd5d379fb1c4ff6cb Mon Sep 17 00:00:00 2001 From: BuzzLeclair Date: Sat, 1 Mar 2025 13:20:28 +0100 Subject: [PATCH 04/17] =?UTF-8?q?-=20Ajout=20de=20toutes=20les=20classes?= =?UTF-8?q?=20Repository=20n=C3=A9cessaires=20au=20projet=20-=20Ajout=20d'?= =?UTF-8?q?une=20classe=20et=20d'une=20interface=20Repo=20g=C3=A9n=C3=A9ri?= =?UTF-8?q?ques=20pour=20=C3=A9viter=20la=20r=C3=A9=C3=A9criture=20des=20f?= =?UTF-8?q?onctions=20CRUD=20de=20base?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ldap-cesi/Repository/RepositoryBase.cs | 114 ++++++++++++++++++ ldap-cesi/Repository/RoleRepository.cs | 13 ++ ldap-cesi/Repository/SalarieRepository.cs | 13 ++ ldap-cesi/Repository/ServiceRepository.cs | 13 ++ .../Repository/Services/IRepositoryBase.cs | 15 +++ .../Repository/Services/IRepositoryRole.cs | 8 ++ .../Repository/Services/IRepositorySalarie.cs | 8 ++ .../Repository/Services/IRepositoryService.cs | 8 ++ .../Repository/Services/IRepositorySite.cs | 8 ++ .../Services/IRepositoryUtilisateur.cs | 8 ++ ldap-cesi/Repository/SiteRepository.cs | 13 ++ ldap-cesi/Repository/UtilisateurRepository.cs | 13 ++ ldap-cesi/ldap-cesi.csproj | 1 - 13 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 ldap-cesi/Repository/RepositoryBase.cs create mode 100644 ldap-cesi/Repository/RoleRepository.cs create mode 100644 ldap-cesi/Repository/SalarieRepository.cs create mode 100644 ldap-cesi/Repository/ServiceRepository.cs create mode 100644 ldap-cesi/Repository/Services/IRepositoryBase.cs create mode 100644 ldap-cesi/Repository/Services/IRepositoryRole.cs create mode 100644 ldap-cesi/Repository/Services/IRepositorySalarie.cs create mode 100644 ldap-cesi/Repository/Services/IRepositoryService.cs create mode 100644 ldap-cesi/Repository/Services/IRepositorySite.cs create mode 100644 ldap-cesi/Repository/Services/IRepositoryUtilisateur.cs create mode 100644 ldap-cesi/Repository/SiteRepository.cs create mode 100644 ldap-cesi/Repository/UtilisateurRepository.cs diff --git a/ldap-cesi/Repository/RepositoryBase.cs b/ldap-cesi/Repository/RepositoryBase.cs new file mode 100644 index 0000000..911ddcd --- /dev/null +++ b/ldap-cesi/Repository/RepositoryBase.cs @@ -0,0 +1,114 @@ +using System.Linq.Expressions; +using ldap_cesi.Context; +using ldap_cesi.Repository.Services; +using Microsoft.EntityFrameworkCore; + +namespace ldap_cesi.Repository; + +public class RepositoryBase : IRepositoryBase where TEntity : class +{ + protected readonly PgContext _context; + + public RepositoryBase(PgContext context) + { + _context = context ?? throw new ArgumentNullException(nameof(context)); + } + public virtual async Task AddAsync(TEntity entity, CancellationToken cancellationToken = default) + { + try + { + _context.Set().Add(entity); + await SaveChangesAsync(cancellationToken); + return entity; + } + catch (Exception ex) + { + throw new Exception("Erreur pendant l'ajout de l'entité.", ex); + } + } + + public virtual async Task AnyAsync(Expression> predicate, CancellationToken cancellationToken = default) + { + return await _context.Set().AnyAsync(predicate, cancellationToken); + } + + + public virtual async Task> GetAllAsync(CancellationToken cancellationToken = default) + { + try + { + return await _context.Set().ToListAsync(cancellationToken); + } + catch (Exception ex) + { + throw new Exception("Erreur pendant la récupérations des entités.", ex); + } + } + public virtual async Task FirstOrDefaultAsync(Expression> predicate, CancellationToken cancellationToken = default) + { + return await _context.Set().FirstOrDefaultAsync(predicate, cancellationToken); + } + + public virtual async Task UpdateAsync(TEntity entity, CancellationToken cancellationToken = default) + { + try + { + _context.Set().Update(entity); + await SaveChangesAsync(cancellationToken); + } + catch (Exception ex) + { + throw new Exception("Erreur pendant la mis à jour", ex); + } + } + + public virtual async Task GetByIdAsync(TId id, CancellationToken cancellationToken = default) where TId : notnull + { + try + { + return await _context.FindAsync(id, cancellationToken); + } + catch (Exception ex) + { + throw new Exception($"Erreur lors de la récupération avec l'id : {id}.", ex); + } + } + + public virtual async Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default) + { + try + { + _context.Set().Remove(entity); + await SaveChangesAsync(cancellationToken); + } + catch (Exception ex) + { + throw new Exception("Erreur pendant la suppression de l'entité", ex); + } + } + + protected async Task SaveChangesAsync(CancellationToken cancellationToken = default) + { + try + { + return await _context.SaveChangesAsync(cancellationToken); + } + catch (Exception ex) + { + throw new Exception("Erreur pendant le sauvegarde en base de donnése.", ex); + } + } + + public virtual async Task> ListAsync(CancellationToken cancellationToken = default) + { + try + { + return await _context.Set().ToListAsync(cancellationToken); + } + catch (Exception ex) + { + throw new Exception("Erreur qui concerne le listing des entités", ex); + } + } + +} \ No newline at end of file diff --git a/ldap-cesi/Repository/RoleRepository.cs b/ldap-cesi/Repository/RoleRepository.cs new file mode 100644 index 0000000..2d7ee07 --- /dev/null +++ b/ldap-cesi/Repository/RoleRepository.cs @@ -0,0 +1,13 @@ +using ldap_cesi.Context; +using ldap_cesi.Entities; +using ldap_cesi.Repository.Services; + +namespace ldap_cesi.Repository; + +public class RoleRepository : RepositoryBase, IRepositoryRole +{ + public RoleRepository(PgContext context) : base(context) + { + + } +} \ No newline at end of file diff --git a/ldap-cesi/Repository/SalarieRepository.cs b/ldap-cesi/Repository/SalarieRepository.cs new file mode 100644 index 0000000..bb84bb1 --- /dev/null +++ b/ldap-cesi/Repository/SalarieRepository.cs @@ -0,0 +1,13 @@ +using ldap_cesi.Context; +using ldap_cesi.Entities; +using ldap_cesi.Repository.Services; + +namespace ldap_cesi.Repository; + +public class SalarieRepository : RepositoryBase, IRepositorySalarie +{ + public SalarieRepository(PgContext context) : base(context) + { + + } +} \ No newline at end of file diff --git a/ldap-cesi/Repository/ServiceRepository.cs b/ldap-cesi/Repository/ServiceRepository.cs new file mode 100644 index 0000000..e0f15e8 --- /dev/null +++ b/ldap-cesi/Repository/ServiceRepository.cs @@ -0,0 +1,13 @@ +using ldap_cesi.Context; +using ldap_cesi.Entities; +using ldap_cesi.Repository.Services; + +namespace ldap_cesi.Repository; + +public class ServiceRepository : RepositoryBase, IRepositoryService +{ + public ServiceRepository(PgContext context) : base(context) + { + + } +} \ No newline at end of file diff --git a/ldap-cesi/Repository/Services/IRepositoryBase.cs b/ldap-cesi/Repository/Services/IRepositoryBase.cs new file mode 100644 index 0000000..1057e98 --- /dev/null +++ b/ldap-cesi/Repository/Services/IRepositoryBase.cs @@ -0,0 +1,15 @@ +using System.Linq.Expressions; + +namespace ldap_cesi.Repository.Services; + +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 UpdateAsync(TEntity entity, CancellationToken cancellationToken = default); + Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default); + Task FirstOrDefaultAsync(Expression> predicate, + CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/ldap-cesi/Repository/Services/IRepositoryRole.cs b/ldap-cesi/Repository/Services/IRepositoryRole.cs new file mode 100644 index 0000000..e504b27 --- /dev/null +++ b/ldap-cesi/Repository/Services/IRepositoryRole.cs @@ -0,0 +1,8 @@ +using ldap_cesi.Entities; + +namespace ldap_cesi.Repository.Services; + +public interface IRepositoryRole : IRepositoryBase +{ + +} \ No newline at end of file diff --git a/ldap-cesi/Repository/Services/IRepositorySalarie.cs b/ldap-cesi/Repository/Services/IRepositorySalarie.cs new file mode 100644 index 0000000..c281f5f --- /dev/null +++ b/ldap-cesi/Repository/Services/IRepositorySalarie.cs @@ -0,0 +1,8 @@ +using ldap_cesi.Entities; + +namespace ldap_cesi.Repository.Services; + +public interface IRepositorySalarie : IRepositoryBase +{ + +} \ No newline at end of file diff --git a/ldap-cesi/Repository/Services/IRepositoryService.cs b/ldap-cesi/Repository/Services/IRepositoryService.cs new file mode 100644 index 0000000..aba697b --- /dev/null +++ b/ldap-cesi/Repository/Services/IRepositoryService.cs @@ -0,0 +1,8 @@ +using ldap_cesi.Entities; + +namespace ldap_cesi.Repository.Services; + +public interface IRepositoryService : IRepositoryBase +{ + +} \ No newline at end of file diff --git a/ldap-cesi/Repository/Services/IRepositorySite.cs b/ldap-cesi/Repository/Services/IRepositorySite.cs new file mode 100644 index 0000000..cc098f9 --- /dev/null +++ b/ldap-cesi/Repository/Services/IRepositorySite.cs @@ -0,0 +1,8 @@ +using ldap_cesi.Entities; + +namespace ldap_cesi.Repository.Services; + +public interface IRepositorySite : IRepositoryBase +{ + +} \ No newline at end of file diff --git a/ldap-cesi/Repository/Services/IRepositoryUtilisateur.cs b/ldap-cesi/Repository/Services/IRepositoryUtilisateur.cs new file mode 100644 index 0000000..4235770 --- /dev/null +++ b/ldap-cesi/Repository/Services/IRepositoryUtilisateur.cs @@ -0,0 +1,8 @@ +using ldap_cesi.Entities; + +namespace ldap_cesi.Repository.Services; + +public interface IRepositoryUtilisateur : IRepositoryBase +{ + +} \ No newline at end of file diff --git a/ldap-cesi/Repository/SiteRepository.cs b/ldap-cesi/Repository/SiteRepository.cs new file mode 100644 index 0000000..3b522b8 --- /dev/null +++ b/ldap-cesi/Repository/SiteRepository.cs @@ -0,0 +1,13 @@ +using ldap_cesi.Context; +using ldap_cesi.Entities; +using ldap_cesi.Repository.Services; + +namespace ldap_cesi.Repository; + +public class SiteRepository : RepositoryBase, IRepositorySite +{ + public SiteRepository(PgContext context) : base(context) + { + + } +} \ No newline at end of file diff --git a/ldap-cesi/Repository/UtilisateurRepository.cs b/ldap-cesi/Repository/UtilisateurRepository.cs new file mode 100644 index 0000000..57cf96c --- /dev/null +++ b/ldap-cesi/Repository/UtilisateurRepository.cs @@ -0,0 +1,13 @@ +using ldap_cesi.Context; +using ldap_cesi.Entities; +using ldap_cesi.Repository.Services; + +namespace ldap_cesi.Repository; + +public class UtilisateurRepository : RepositoryBase, IRepositoryUtilisateur +{ + public UtilisateurRepository(PgContext context) : base(context) + { + + } +} \ No newline at end of file diff --git a/ldap-cesi/ldap-cesi.csproj b/ldap-cesi/ldap-cesi.csproj index b240452..99d7a59 100644 --- a/ldap-cesi/ldap-cesi.csproj +++ b/ldap-cesi/ldap-cesi.csproj @@ -28,7 +28,6 @@ - From 31292344b0f4760c02ee826af14b0541112d92ff Mon Sep 17 00:00:00 2001 From: BuzzLeclair Date: Sat, 1 Mar 2025 13:21:05 +0100 Subject: [PATCH 05/17] - Correction du nom du package.... --- ldap-cesi/Repository/{Services => Interfaces}/IRepositoryBase.cs | 0 ldap-cesi/Repository/{Services => Interfaces}/IRepositoryRole.cs | 0 .../Repository/{Services => Interfaces}/IRepositorySalarie.cs | 0 .../Repository/{Services => Interfaces}/IRepositoryService.cs | 0 ldap-cesi/Repository/{Services => Interfaces}/IRepositorySite.cs | 0 .../Repository/{Services => Interfaces}/IRepositoryUtilisateur.cs | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename ldap-cesi/Repository/{Services => Interfaces}/IRepositoryBase.cs (100%) rename ldap-cesi/Repository/{Services => Interfaces}/IRepositoryRole.cs (100%) rename ldap-cesi/Repository/{Services => Interfaces}/IRepositorySalarie.cs (100%) rename ldap-cesi/Repository/{Services => Interfaces}/IRepositoryService.cs (100%) rename ldap-cesi/Repository/{Services => Interfaces}/IRepositorySite.cs (100%) rename ldap-cesi/Repository/{Services => Interfaces}/IRepositoryUtilisateur.cs (100%) diff --git a/ldap-cesi/Repository/Services/IRepositoryBase.cs b/ldap-cesi/Repository/Interfaces/IRepositoryBase.cs similarity index 100% rename from ldap-cesi/Repository/Services/IRepositoryBase.cs rename to ldap-cesi/Repository/Interfaces/IRepositoryBase.cs diff --git a/ldap-cesi/Repository/Services/IRepositoryRole.cs b/ldap-cesi/Repository/Interfaces/IRepositoryRole.cs similarity index 100% rename from ldap-cesi/Repository/Services/IRepositoryRole.cs rename to ldap-cesi/Repository/Interfaces/IRepositoryRole.cs diff --git a/ldap-cesi/Repository/Services/IRepositorySalarie.cs b/ldap-cesi/Repository/Interfaces/IRepositorySalarie.cs similarity index 100% rename from ldap-cesi/Repository/Services/IRepositorySalarie.cs rename to ldap-cesi/Repository/Interfaces/IRepositorySalarie.cs diff --git a/ldap-cesi/Repository/Services/IRepositoryService.cs b/ldap-cesi/Repository/Interfaces/IRepositoryService.cs similarity index 100% rename from ldap-cesi/Repository/Services/IRepositoryService.cs rename to ldap-cesi/Repository/Interfaces/IRepositoryService.cs diff --git a/ldap-cesi/Repository/Services/IRepositorySite.cs b/ldap-cesi/Repository/Interfaces/IRepositorySite.cs similarity index 100% rename from ldap-cesi/Repository/Services/IRepositorySite.cs rename to ldap-cesi/Repository/Interfaces/IRepositorySite.cs diff --git a/ldap-cesi/Repository/Services/IRepositoryUtilisateur.cs b/ldap-cesi/Repository/Interfaces/IRepositoryUtilisateur.cs similarity index 100% rename from ldap-cesi/Repository/Services/IRepositoryUtilisateur.cs rename to ldap-cesi/Repository/Interfaces/IRepositoryUtilisateur.cs From 8901f921c7e9dd586e6ab534f556e53badeee59b Mon Sep 17 00:00:00 2001 From: BuzzLeclair Date: Sun, 2 Mar 2025 16:50:53 +0100 Subject: [PATCH 06/17] =?UTF-8?q?-=20Ajout=20d'automapper=20pour=20convert?= =?UTF-8?q?ir=20les=20dto=20en=20entit=C3=A9=20et=20inversement=20-=20Ajou?= =?UTF-8?q?t=20des=20m=C3=A9thodes=20n=C3=A9cessaire=20pour=20la=20gestion?= =?UTF-8?q?=20de=20JWT?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ldap-cesi/Configurations/Conf.cs | 126 +++++++++++++++++- ldap-cesi/Context/PgContext.cs | 8 +- ldap-cesi/Controllers/HashController.cs | 22 +++ ldap-cesi/Controllers/JwtController.cs | 28 ++++ ldap-cesi/Controllers/SalarieController.cs | 39 ++++++ ldap-cesi/Controllers/ServicesController.cs | 55 ++++++++ .../Controllers/UtilisateurController.cs | 47 +++++++ .../DTOs/Inputs/Salarie/SalarieCreateDto.cs | 12 ++ .../DTOs/Inputs/Salarie/SalarieUpdateDto.cs | 20 +++ .../DTOs/Inputs/Service/ServiceCreateDto.cs | 6 + .../DTOs/Inputs/Service/ServiceUpdateDto.cs | 8 ++ ldap-cesi/DTOs/Inputs/Site/SiteCreateDto.cs | 6 + ldap-cesi/DTOs/Inputs/Site/SiteUpdateDto.cs | 9 ++ .../Inputs/Utilisateur/UtilisateurLoginDto.cs | 7 + .../Utilisateur/UtilisateurOutputDto.cs | 9 ++ ldap-cesi/Entities/Site.cs | 2 +- ldap-cesi/Entities/Utilisateur.cs | 11 +- ldap-cesi/Mapper/AutoMapperProfile.cs | 16 +++ ldap-cesi/Models/IResponseDataModel.cs | 7 + ldap-cesi/Models/IResponseModel.cs | 8 ++ ldap-cesi/Models/ResponseDataModel.cs | 7 + ldap-cesi/Models/ResponseModel.cs | 10 ++ ldap-cesi/Program.cs | 21 ++- .../Interfaces/IRepositoryBase.cs | 0 .../Interfaces/IRepositoryRole.cs | 0 .../Interfaces/IRepositorySalarie.cs | 0 .../Interfaces/IRepositoryService.cs | 0 .../Interfaces/IRepositorySite.cs | 0 .../Interfaces/IRepositoryUtilisateur.cs | 2 +- .../RepositoryBase.cs | 0 .../RoleRepository.cs | 0 .../SalarieRepository.cs | 0 .../ServiceRepository.cs | 0 .../SiteRepository.cs | 0 .../UtilisateurRepository.cs | 7 + ldap-cesi/Services/Interfaces/IJwtService.cs | 10 ++ ldap-cesi/Services/Interfaces/IRoleService.cs | 6 + .../Services/Interfaces/IRsaKeyService.cs | 8 ++ .../Services/Interfaces/ISalarieService.cs | 10 ++ .../Services/Interfaces/IServiceService.cs | 12 ++ ldap-cesi/Services/Interfaces/ISiteService.cs | 6 + .../Interfaces/IUtilisateurService.cs | 13 ++ ldap-cesi/Services/JwtService.cs | 126 ++++++++++++++++++ ldap-cesi/Services/RoleService.cs | 15 +++ ldap-cesi/Services/RsaKeyService.cs | 36 +++++ ldap-cesi/Services/SalarieService.cs | 38 ++++++ ldap-cesi/Services/ServiceService.cs | 54 ++++++++ ldap-cesi/Services/UtilisateurService.cs | 80 +++++++++++ ldap-cesi/ldap-cesi.csproj | 16 ++- ldap-cesi/ldap-cesi.http | 6 - 50 files changed, 900 insertions(+), 29 deletions(-) create mode 100644 ldap-cesi/Controllers/HashController.cs create mode 100644 ldap-cesi/Controllers/JwtController.cs create mode 100644 ldap-cesi/Controllers/SalarieController.cs create mode 100644 ldap-cesi/Controllers/ServicesController.cs create mode 100644 ldap-cesi/Controllers/UtilisateurController.cs create mode 100644 ldap-cesi/DTOs/Inputs/Salarie/SalarieCreateDto.cs create mode 100644 ldap-cesi/DTOs/Inputs/Salarie/SalarieUpdateDto.cs create mode 100644 ldap-cesi/DTOs/Inputs/Service/ServiceCreateDto.cs create mode 100644 ldap-cesi/DTOs/Inputs/Service/ServiceUpdateDto.cs create mode 100644 ldap-cesi/DTOs/Inputs/Site/SiteCreateDto.cs create mode 100644 ldap-cesi/DTOs/Inputs/Site/SiteUpdateDto.cs create mode 100644 ldap-cesi/DTOs/Inputs/Utilisateur/UtilisateurLoginDto.cs create mode 100644 ldap-cesi/DTOs/Outputs/Utilisateur/UtilisateurOutputDto.cs create mode 100644 ldap-cesi/Mapper/AutoMapperProfile.cs create mode 100644 ldap-cesi/Models/IResponseDataModel.cs create mode 100644 ldap-cesi/Models/IResponseModel.cs create mode 100644 ldap-cesi/Models/ResponseDataModel.cs create mode 100644 ldap-cesi/Models/ResponseModel.cs rename ldap-cesi/{Repository => Repositories}/Interfaces/IRepositoryBase.cs (100%) rename ldap-cesi/{Repository => Repositories}/Interfaces/IRepositoryRole.cs (100%) rename ldap-cesi/{Repository => Repositories}/Interfaces/IRepositorySalarie.cs (100%) rename ldap-cesi/{Repository => Repositories}/Interfaces/IRepositoryService.cs (100%) rename ldap-cesi/{Repository => Repositories}/Interfaces/IRepositorySite.cs (100%) rename ldap-cesi/{Repository => Repositories}/Interfaces/IRepositoryUtilisateur.cs (72%) rename ldap-cesi/{Repository => Repositories}/RepositoryBase.cs (100%) rename ldap-cesi/{Repository => Repositories}/RoleRepository.cs (100%) rename ldap-cesi/{Repository => Repositories}/SalarieRepository.cs (100%) rename ldap-cesi/{Repository => Repositories}/ServiceRepository.cs (100%) rename ldap-cesi/{Repository => Repositories}/SiteRepository.cs (100%) rename ldap-cesi/{Repository => Repositories}/UtilisateurRepository.cs (54%) create mode 100644 ldap-cesi/Services/Interfaces/IJwtService.cs create mode 100644 ldap-cesi/Services/Interfaces/IRoleService.cs create mode 100644 ldap-cesi/Services/Interfaces/IRsaKeyService.cs create mode 100644 ldap-cesi/Services/Interfaces/ISalarieService.cs create mode 100644 ldap-cesi/Services/Interfaces/IServiceService.cs create mode 100644 ldap-cesi/Services/Interfaces/ISiteService.cs create mode 100644 ldap-cesi/Services/Interfaces/IUtilisateurService.cs create mode 100644 ldap-cesi/Services/JwtService.cs create mode 100644 ldap-cesi/Services/RoleService.cs create mode 100644 ldap-cesi/Services/RsaKeyService.cs create mode 100644 ldap-cesi/Services/SalarieService.cs create mode 100644 ldap-cesi/Services/ServiceService.cs create mode 100644 ldap-cesi/Services/UtilisateurService.cs delete mode 100644 ldap-cesi/ldap-cesi.http diff --git a/ldap-cesi/Configurations/Conf.cs b/ldap-cesi/Configurations/Conf.cs index d1dbb77..e4f5b10 100644 --- a/ldap-cesi/Configurations/Conf.cs +++ b/ldap-cesi/Configurations/Conf.cs @@ -1,6 +1,16 @@ +using System.Reflection; +using System.Security.Cryptography; +using System.Text; using ldap_cesi.Context; -using ldap_cesi.Entities; +using ldap_cesi.Repository; +using ldap_cesi.Repository.Services; +using ldap_cesi.Services; +using ldap_cesi.Services.Interfaces; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; +using Serilog; namespace ldap_cesi.Configurations; @@ -8,12 +18,126 @@ public static class Conf { public static void BuildConf(this WebApplicationBuilder builder) { + builder.AddRepositories(); + builder.AddServices(); + builder.Services.AddControllers(); builder.AddEFCoreConfiguration(); + builder.CorseConfiguration(); + builder.AddSwagger(); + builder.AddSerilog(); + builder.AddJwt(); + builder.Services.AddAutoMapper(typeof(Program)); + } + + public static void AddRepositories(this WebApplicationBuilder builder) + { + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); } + public static void AddServices(this WebApplicationBuilder builder) + { + builder.Services.AddScoped(); + // builder.Services.AddScoped(); + // builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddSingleton(); + } public static void AddEFCoreConfiguration(this WebApplicationBuilder builder) { string connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); builder.Services.AddDbContext(options => options.UseNpgsql(connectionString)); } + public static void CorseConfiguration(this WebApplicationBuilder builder) + { + builder.Services.AddCors(options => + { + options.AddPolicy("AllowAll", + builder => builder + .AllowAnyOrigin() + .AllowAnyMethod() + .AllowAnyHeader()); + }); + } + + public static void AddSerilog(this WebApplicationBuilder builder) + { + var loggerConfiguration = new LoggerConfiguration() + .WriteTo.Console() + .WriteTo.File("logs/log.txt", rollingInterval: RollingInterval.Hour); + var logger = loggerConfiguration.CreateLogger(); + builder.Logging.AddSerilog(logger); + builder.Services.AddLogging(); + } + + public static void AddJwt(this WebApplicationBuilder builder) + { + var rsaKeyService = builder.Services.BuildServiceProvider().GetRequiredService(); + var rsaKey = rsaKeyService.GetRsaKey(); + + builder.Services.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + }) + .AddJwtBearer(options => + { + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuer = true, + ValidateAudience = true, + ValidateLifetime = true, + ValidateIssuerSigningKey = true, + ValidIssuer = builder.Configuration["Jwt:Issuer"], + ValidAudience = builder.Configuration["Jwt:Audience"], + IssuerSigningKey = new RsaSecurityKey(rsaKey) + }; + }); + } + + public static void AddSwagger(this WebApplicationBuilder builder) + { + // Add services to the container. + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + builder.Services.AddEndpointsApiExplorer(); + builder.Services.AddAuthorization(); + builder.Configuration.AddEnvironmentVariables(); + builder.Services.AddSwaggerGen(c => + { + c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme + { + Name = "Authorization", + In = ParameterLocation.Header, + Type = SecuritySchemeType.ApiKey, + Scheme = "Bearer", + Description = "JWT Token. Use \"Bearer {token}\"" + }); + c.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Id = "Bearer", + Type = ReferenceType.SecurityScheme + } + }, + new List() + } + }); + c.SwaggerDoc("v1", new OpenApiInfo + { + Title = "LDAP - Backend", + Version = "v1" + }); + var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; + c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename)); + }); + } } \ No newline at end of file diff --git a/ldap-cesi/Context/PgContext.cs b/ldap-cesi/Context/PgContext.cs index 778e575..fc8c4c3 100644 --- a/ldap-cesi/Context/PgContext.cs +++ b/ldap-cesi/Context/PgContext.cs @@ -26,10 +26,6 @@ public partial class PgContext : DbContext public virtual DbSet Utilisateurs { get; set; } - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) -#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see https://go.microsoft.com/fwlink/?LinkId=723263. - => optionsBuilder.UseNpgsql("Host=192.168.1.196;Database=ldap;Username=postgres;Password=pimer0-buzz"); - protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity(entity => @@ -118,9 +114,13 @@ public partial class PgContext : DbContext entity.Property(e => e.Nom) .HasMaxLength(50) .HasColumnName("nom"); + entity.Property(e => e.Email) + .HasMaxLength(50) + .HasColumnName("email"); entity.Property(e => e.Prenom) .HasMaxLength(50) .HasColumnName("prenom"); + entity.Ignore(e => e.AccessToken); entity.HasOne(d => d.IdRoleNavigation).WithMany(p => p.Utilisateurs) .HasForeignKey(d => d.IdRole) diff --git a/ldap-cesi/Controllers/HashController.cs b/ldap-cesi/Controllers/HashController.cs new file mode 100644 index 0000000..35c7594 --- /dev/null +++ b/ldap-cesi/Controllers/HashController.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Mvc; + +namespace ldap_cesi.Controllers; + + +[ApiController] +[Route("api/[controller]")] +public class HashController : ControllerBase +{ + [HttpPost("hash")] + public IActionResult HashString([FromBody] string StringToHash) + { + if (string.IsNullOrEmpty(StringToHash)) + { + return BadRequest("Vous devez fournir une chaine de caractere pour la hasher."); + } + + string hashedString = BCrypt.Net.BCrypt.HashPassword(StringToHash); + + return Ok(new { HashedString = hashedString }); + } +} \ No newline at end of file diff --git a/ldap-cesi/Controllers/JwtController.cs b/ldap-cesi/Controllers/JwtController.cs new file mode 100644 index 0000000..55fad8d --- /dev/null +++ b/ldap-cesi/Controllers/JwtController.cs @@ -0,0 +1,28 @@ +using ldap_cesi.Services.Interfaces; +using Microsoft.AspNetCore.Mvc; + +namespace ldap_cesi.Controllers; + +[ApiController] +[Route("/api/jwt")] +public class JwtController : ControllerBase +{ + private readonly IJwtService _jwtService; + + public JwtController(IJwtService jwtService) + { + _jwtService = jwtService; + } + + [HttpGet("public-key")] + public IActionResult GetPublicKey() + { + var publicKey = _jwtService.GetPublicKey(); + if (string.IsNullOrEmpty(publicKey)) + { + return BadRequest("Impossible de récupérer la clé publique"); + } + + return Ok(publicKey); + } +} \ No newline at end of file diff --git a/ldap-cesi/Controllers/SalarieController.cs b/ldap-cesi/Controllers/SalarieController.cs new file mode 100644 index 0000000..fdf1cf7 --- /dev/null +++ b/ldap-cesi/Controllers/SalarieController.cs @@ -0,0 +1,39 @@ +using ldap_cesi.Services.Interfaces; +using Microsoft.AspNetCore.Mvc; + +namespace ldap_cesi.Controllers; +[ApiController] +[Route("api/salarie")] +public class SalarieController : ControllerBase +{ + private ISalarieService _salarieService; + + public SalarieController(ISalarieService salarieService) + { + _salarieService = salarieService; + } + + // GET: api/salaries + /// + /// Endpoint qui retournes tous les salaries + /// + /// List + [HttpGet] + public async Task GetUtilisateurs() + { + var result = await _salarieService.GetAll(); + return result.Success ? Ok(result) : BadRequest(result); + } + + // GET: api/salaries + /// + /// Endpoint retourne le salarie correspondant à l'id en param + /// + /// Salarie + [HttpGet("{id}")] + public async Task GetUtilisateurById(int id) + { + var result = await _salarieService.GetById(id); + return result.Success ? Ok(result) : BadRequest(result); + } +} \ No newline at end of file diff --git a/ldap-cesi/Controllers/ServicesController.cs b/ldap-cesi/Controllers/ServicesController.cs new file mode 100644 index 0000000..0d0e987 --- /dev/null +++ b/ldap-cesi/Controllers/ServicesController.cs @@ -0,0 +1,55 @@ +using ldap_cesi.DTOs.Inputs.Service; +using ldap_cesi.Services.Interfaces; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace ldap_cesi.Controllers; + +[ApiController] +[Route("api/service")] +public class ServicesController : ControllerBase +{ + private IServiceService _serviceService; + + public ServicesController(IServiceService serviceService) + { + _serviceService = serviceService; + } + + // GET: api/services + /// + /// Endpoint qui retournes tous les services + /// + /// Retourne tous les services + [HttpGet] + // [Authorize(Roles = "admin")] + public async Task GetServices() + { + var result = await _serviceService.GetAll(); + return result.Success ? Ok(result) : BadRequest(result); + } + + // GET: api/services + /// + /// Endpoint retourne le service correspondant à l'id en param + /// + /// Service + [HttpGet("{id}")] + public async Task GetServices(int id) + { + var result = await _serviceService.GetById(id); + return result.Success ? Ok(result) : BadRequest(result); + } + + // {POST}: api/services + /// + /// Endpoint qui créé un service + /// + /// Retourne tous les services + [HttpPost] + public async Task CreateService([FromBody] ServiceCreateDto serviceInputDto) + { + var result = await _serviceService.CreateService(serviceInputDto); + 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 new file mode 100644 index 0000000..f9b5a51 --- /dev/null +++ b/ldap-cesi/Controllers/UtilisateurController.cs @@ -0,0 +1,47 @@ +using ldap_cesi.DTOs.Inputs; +using ldap_cesi.Services.Interfaces; +using Microsoft.AspNetCore.Mvc; + +namespace ldap_cesi.Controllers; +[ApiController] +[Route("api/utilisateur")] +public class UtilisateurController : ControllerBase +{ + private IUtilisateurService _utilisateurService; + + public UtilisateurController(IUtilisateurService utilisateurService) + { + _utilisateurService = utilisateurService; + } + + [HttpPost("login")] + public async Task Login([FromBody] UtilisateurLoginDto utilisateurInput) + { + var response = await _utilisateurService.Login(utilisateurInput); + return StatusCode(response.StatusCode, response); + } + + // GET: api/utilisateurs + /// + /// Endpoint qui retournes tous les utilisateurs + /// + /// List + [HttpGet] + public async Task GetUtilisateurs() + { + var result = await _utilisateurService.GetAll(); + return result.Success ? Ok(result) : BadRequest(result); + } + + // GET: api/utilisateur + /// + /// Endpoint retourne l'utilisateur correspondant à l'id en param + /// + /// Utilisateur + [HttpGet("{id}")] + public async Task GetUtilisateurById(int id) + { + var result = await _utilisateurService.GetById(id); + return result.Success ? Ok(result) : BadRequest(result); + } +} \ No newline at end of file diff --git a/ldap-cesi/DTOs/Inputs/Salarie/SalarieCreateDto.cs b/ldap-cesi/DTOs/Inputs/Salarie/SalarieCreateDto.cs new file mode 100644 index 0000000..7804ce4 --- /dev/null +++ b/ldap-cesi/DTOs/Inputs/Salarie/SalarieCreateDto.cs @@ -0,0 +1,12 @@ +namespace ldap_cesi.DTOs.Inputs.Salarie; + +public class SalarieCreateDto +{ + public string Nom { get; set; } + public string Prenom { get; set; } + public string Telephone_fix { get; set; } + public string Telephone_portable { get; set; } + public string Email { get; set; } + public int IdSite { get; set; } + public int IdService { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/DTOs/Inputs/Salarie/SalarieUpdateDto.cs b/ldap-cesi/DTOs/Inputs/Salarie/SalarieUpdateDto.cs new file mode 100644 index 0000000..3245bfd --- /dev/null +++ b/ldap-cesi/DTOs/Inputs/Salarie/SalarieUpdateDto.cs @@ -0,0 +1,20 @@ +namespace ldap_cesi.DTOs.Inputs.Service; + +public class SalarieUpdateDto +{ + 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!; + + public int IdSite { get; set; } + + public int IdService { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/DTOs/Inputs/Service/ServiceCreateDto.cs b/ldap-cesi/DTOs/Inputs/Service/ServiceCreateDto.cs new file mode 100644 index 0000000..11d3052 --- /dev/null +++ b/ldap-cesi/DTOs/Inputs/Service/ServiceCreateDto.cs @@ -0,0 +1,6 @@ +namespace ldap_cesi.DTOs.Inputs.Service; + +public class ServiceCreateDto +{ + public string Nom { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/DTOs/Inputs/Service/ServiceUpdateDto.cs b/ldap-cesi/DTOs/Inputs/Service/ServiceUpdateDto.cs new file mode 100644 index 0000000..37e44b5 --- /dev/null +++ b/ldap-cesi/DTOs/Inputs/Service/ServiceUpdateDto.cs @@ -0,0 +1,8 @@ +namespace ldap_cesi.DTOs.Inputs.Service; + +public class ServiceUpdateDto +{ + public int Id { get; set; } + + public string Nom { get; set; } = null!; +} \ No newline at end of file diff --git a/ldap-cesi/DTOs/Inputs/Site/SiteCreateDto.cs b/ldap-cesi/DTOs/Inputs/Site/SiteCreateDto.cs new file mode 100644 index 0000000..706affd --- /dev/null +++ b/ldap-cesi/DTOs/Inputs/Site/SiteCreateDto.cs @@ -0,0 +1,6 @@ +namespace ldap_cesi.DTOs.Inputs.Site; + +public class SiteCreateDto +{ + public string Ville { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/DTOs/Inputs/Site/SiteUpdateDto.cs b/ldap-cesi/DTOs/Inputs/Site/SiteUpdateDto.cs new file mode 100644 index 0000000..bcd5fb7 --- /dev/null +++ b/ldap-cesi/DTOs/Inputs/Site/SiteUpdateDto.cs @@ -0,0 +1,9 @@ +namespace ldap_cesi.DTOs.Inputs.Site; + +public class SiteUpdateDto +{ + public int Id { get; set; } + + public string Ville { get; set; } + +} \ No newline at end of file diff --git a/ldap-cesi/DTOs/Inputs/Utilisateur/UtilisateurLoginDto.cs b/ldap-cesi/DTOs/Inputs/Utilisateur/UtilisateurLoginDto.cs new file mode 100644 index 0000000..2ce64f1 --- /dev/null +++ b/ldap-cesi/DTOs/Inputs/Utilisateur/UtilisateurLoginDto.cs @@ -0,0 +1,7 @@ +namespace ldap_cesi.DTOs.Inputs; + +public class UtilisateurLoginDto +{ + public string Email { get; set; } + public string MotDePasse { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/DTOs/Outputs/Utilisateur/UtilisateurOutputDto.cs b/ldap-cesi/DTOs/Outputs/Utilisateur/UtilisateurOutputDto.cs new file mode 100644 index 0000000..b508c8d --- /dev/null +++ b/ldap-cesi/DTOs/Outputs/Utilisateur/UtilisateurOutputDto.cs @@ -0,0 +1,9 @@ +namespace ldap_cesi.DTOs.Outputs.Utilisateur; + +public class UtilisateurOutputDto +{ + public int Id { get; set; } + public string Email { get; set; } + public string Nom { get; set; } + public string RoleNom { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/Entities/Site.cs b/ldap-cesi/Entities/Site.cs index 40c7f26..1ed7f2a 100644 --- a/ldap-cesi/Entities/Site.cs +++ b/ldap-cesi/Entities/Site.cs @@ -7,7 +7,7 @@ public partial class Site { public int Id { get; set; } - public string? Ville { get; set; } + public string Ville { get; set; } public virtual ICollection Salaries { get; set; } = new List(); } diff --git a/ldap-cesi/Entities/Utilisateur.cs b/ldap-cesi/Entities/Utilisateur.cs index 8f2223b..9037a5c 100644 --- a/ldap-cesi/Entities/Utilisateur.cs +++ b/ldap-cesi/Entities/Utilisateur.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; namespace ldap_cesi.Entities; @@ -7,13 +8,15 @@ public partial class Utilisateur { public int Id { get; set; } - public string? Nom { get; set; } + public string Nom { get; set; } - public string? Prenom { get; set; } + public string Prenom { get; set; } - public string? MotDePasse { get; set; } + public string MotDePasse { get; set; } + public string Email { get; set; } public int IdRole { get; set; } - + [NotMapped] + public string AccessToken { get; set; } public virtual Role IdRoleNavigation { get; set; } = null!; } diff --git a/ldap-cesi/Mapper/AutoMapperProfile.cs b/ldap-cesi/Mapper/AutoMapperProfile.cs new file mode 100644 index 0000000..15fc504 --- /dev/null +++ b/ldap-cesi/Mapper/AutoMapperProfile.cs @@ -0,0 +1,16 @@ +using AutoMapper; +using ldap_cesi.DTOs.Inputs.Service; +using ldap_cesi.DTOs.Outputs.Utilisateur; +using ldap_cesi.Entities; + +namespace ldap_cesi.Mapper; + +public class AutoMapperProfile : Profile +{ + public AutoMapperProfile() + { + CreateMap() + .ForMember(dest => dest.RoleNom, opt => opt.MapFrom(src => src.IdRoleNavigation.Nom)); + CreateMap(); + } +} \ No newline at end of file diff --git a/ldap-cesi/Models/IResponseDataModel.cs b/ldap-cesi/Models/IResponseDataModel.cs new file mode 100644 index 0000000..1eb89dc --- /dev/null +++ b/ldap-cesi/Models/IResponseDataModel.cs @@ -0,0 +1,7 @@ +namespace ldap_cesi.Models; + +public interface IResponseDataModel : IResponseModel +{ + public T Data { get; set; } + string Token { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/Models/IResponseModel.cs b/ldap-cesi/Models/IResponseModel.cs new file mode 100644 index 0000000..1cb04de --- /dev/null +++ b/ldap-cesi/Models/IResponseModel.cs @@ -0,0 +1,8 @@ +namespace ldap_cesi.Models; + +public interface IResponseModel +{ + public int StatusCode { get; set; } + public string? Message { get; set; } + public bool Success { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/Models/ResponseDataModel.cs b/ldap-cesi/Models/ResponseDataModel.cs new file mode 100644 index 0000000..eb66c0f --- /dev/null +++ b/ldap-cesi/Models/ResponseDataModel.cs @@ -0,0 +1,7 @@ +namespace ldap_cesi.Models; + +public class ResponseDataModel : ResponseModel, IResponseDataModel where T : class +{ + public T Data { get; set; } = null!; + public string Token { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/Models/ResponseModel.cs b/ldap-cesi/Models/ResponseModel.cs new file mode 100644 index 0000000..57393de --- /dev/null +++ b/ldap-cesi/Models/ResponseModel.cs @@ -0,0 +1,10 @@ +namespace ldap_cesi.Models; + +public class ResponseModel : IResponseModel +{ + public bool Success { get; set; } + public string? Message { get; set; } + public string? TokenJWT { get; set; } + + public int StatusCode { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/Program.cs b/ldap-cesi/Program.cs index 5881c4b..e5ec0b7 100644 --- a/ldap-cesi/Program.cs +++ b/ldap-cesi/Program.cs @@ -1,18 +1,29 @@ using ldap_cesi.Configurations; var builder = WebApplication.CreateBuilder(args); - builder.BuildConf(); -builder.Services.AddOpenApi(); - var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { - app.MapOpenApi(); + app.UseSwagger(); + app.UseSwaggerUI(); + + app.Use(async (context, next) => + { + if (context.Request.Path == "/") + { + context.Response.Redirect("/swagger"); + return; + } + await next(); + }); } app.UseHttpsRedirection(); - +app.UseRouting(); +app.UseAuthentication(); +app.UseAuthorization(); +app.MapControllers(); app.Run(); diff --git a/ldap-cesi/Repository/Interfaces/IRepositoryBase.cs b/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs similarity index 100% rename from ldap-cesi/Repository/Interfaces/IRepositoryBase.cs rename to ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs diff --git a/ldap-cesi/Repository/Interfaces/IRepositoryRole.cs b/ldap-cesi/Repositories/Interfaces/IRepositoryRole.cs similarity index 100% rename from ldap-cesi/Repository/Interfaces/IRepositoryRole.cs rename to ldap-cesi/Repositories/Interfaces/IRepositoryRole.cs diff --git a/ldap-cesi/Repository/Interfaces/IRepositorySalarie.cs b/ldap-cesi/Repositories/Interfaces/IRepositorySalarie.cs similarity index 100% rename from ldap-cesi/Repository/Interfaces/IRepositorySalarie.cs rename to ldap-cesi/Repositories/Interfaces/IRepositorySalarie.cs diff --git a/ldap-cesi/Repository/Interfaces/IRepositoryService.cs b/ldap-cesi/Repositories/Interfaces/IRepositoryService.cs similarity index 100% rename from ldap-cesi/Repository/Interfaces/IRepositoryService.cs rename to ldap-cesi/Repositories/Interfaces/IRepositoryService.cs diff --git a/ldap-cesi/Repository/Interfaces/IRepositorySite.cs b/ldap-cesi/Repositories/Interfaces/IRepositorySite.cs similarity index 100% rename from ldap-cesi/Repository/Interfaces/IRepositorySite.cs rename to ldap-cesi/Repositories/Interfaces/IRepositorySite.cs diff --git a/ldap-cesi/Repository/Interfaces/IRepositoryUtilisateur.cs b/ldap-cesi/Repositories/Interfaces/IRepositoryUtilisateur.cs similarity index 72% rename from ldap-cesi/Repository/Interfaces/IRepositoryUtilisateur.cs rename to ldap-cesi/Repositories/Interfaces/IRepositoryUtilisateur.cs index 4235770..e05950f 100644 --- a/ldap-cesi/Repository/Interfaces/IRepositoryUtilisateur.cs +++ b/ldap-cesi/Repositories/Interfaces/IRepositoryUtilisateur.cs @@ -4,5 +4,5 @@ namespace ldap_cesi.Repository.Services; public interface IRepositoryUtilisateur : IRepositoryBase { - + Task GetByEmailAsync(string email); } \ No newline at end of file diff --git a/ldap-cesi/Repository/RepositoryBase.cs b/ldap-cesi/Repositories/RepositoryBase.cs similarity index 100% rename from ldap-cesi/Repository/RepositoryBase.cs rename to ldap-cesi/Repositories/RepositoryBase.cs diff --git a/ldap-cesi/Repository/RoleRepository.cs b/ldap-cesi/Repositories/RoleRepository.cs similarity index 100% rename from ldap-cesi/Repository/RoleRepository.cs rename to ldap-cesi/Repositories/RoleRepository.cs diff --git a/ldap-cesi/Repository/SalarieRepository.cs b/ldap-cesi/Repositories/SalarieRepository.cs similarity index 100% rename from ldap-cesi/Repository/SalarieRepository.cs rename to ldap-cesi/Repositories/SalarieRepository.cs diff --git a/ldap-cesi/Repository/ServiceRepository.cs b/ldap-cesi/Repositories/ServiceRepository.cs similarity index 100% rename from ldap-cesi/Repository/ServiceRepository.cs rename to ldap-cesi/Repositories/ServiceRepository.cs diff --git a/ldap-cesi/Repository/SiteRepository.cs b/ldap-cesi/Repositories/SiteRepository.cs similarity index 100% rename from ldap-cesi/Repository/SiteRepository.cs rename to ldap-cesi/Repositories/SiteRepository.cs diff --git a/ldap-cesi/Repository/UtilisateurRepository.cs b/ldap-cesi/Repositories/UtilisateurRepository.cs similarity index 54% rename from ldap-cesi/Repository/UtilisateurRepository.cs rename to ldap-cesi/Repositories/UtilisateurRepository.cs index 57cf96c..0cf84cf 100644 --- a/ldap-cesi/Repository/UtilisateurRepository.cs +++ b/ldap-cesi/Repositories/UtilisateurRepository.cs @@ -1,6 +1,7 @@ using ldap_cesi.Context; using ldap_cesi.Entities; using ldap_cesi.Repository.Services; +using Microsoft.EntityFrameworkCore; namespace ldap_cesi.Repository; @@ -10,4 +11,10 @@ public class UtilisateurRepository : RepositoryBase, IRepositoryUti { } + + public async Task GetByEmailAsync(string email) + { + return await _context.Utilisateurs.Include(u => u.IdRoleNavigation) + .FirstOrDefaultAsync(u => u.Email == email); + } } \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/IJwtService.cs b/ldap-cesi/Services/Interfaces/IJwtService.cs new file mode 100644 index 0000000..1ba65ee --- /dev/null +++ b/ldap-cesi/Services/Interfaces/IJwtService.cs @@ -0,0 +1,10 @@ +using ldap_cesi.Entities; + +namespace ldap_cesi.Services.Interfaces; + +public interface IJwtService +{ + string GenerateToken(Utilisateur utilisateur); + string GetPublicKey(); + Task ValidateToken(string token, int userId); +} \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/IRoleService.cs b/ldap-cesi/Services/Interfaces/IRoleService.cs new file mode 100644 index 0000000..b558e3b --- /dev/null +++ b/ldap-cesi/Services/Interfaces/IRoleService.cs @@ -0,0 +1,6 @@ +namespace ldap_cesi.Services.Interfaces; + +public interface IRoleService +{ + +} \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/IRsaKeyService.cs b/ldap-cesi/Services/Interfaces/IRsaKeyService.cs new file mode 100644 index 0000000..a08d475 --- /dev/null +++ b/ldap-cesi/Services/Interfaces/IRsaKeyService.cs @@ -0,0 +1,8 @@ +using System.Security.Cryptography; + +namespace ldap_cesi.Services.Interfaces; + +public interface IRsaKeyService +{ + RSA GetRsaKey(); +} \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/ISalarieService.cs b/ldap-cesi/Services/Interfaces/ISalarieService.cs new file mode 100644 index 0000000..c6bce16 --- /dev/null +++ b/ldap-cesi/Services/Interfaces/ISalarieService.cs @@ -0,0 +1,10 @@ +using ldap_cesi.Entities; +using ldap_cesi.Models; + +namespace ldap_cesi.Services.Interfaces; + +public interface ISalarieService +{ + Task>> GetAll(); + Task> GetById(int id); +} \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/IServiceService.cs b/ldap-cesi/Services/Interfaces/IServiceService.cs new file mode 100644 index 0000000..f44a387 --- /dev/null +++ b/ldap-cesi/Services/Interfaces/IServiceService.cs @@ -0,0 +1,12 @@ +using ldap_cesi.DTOs.Inputs.Service; +using ldap_cesi.Entities; +using ldap_cesi.Models; + +namespace ldap_cesi.Services.Interfaces; + +public interface IServiceService +{ + Task>> GetAll(); + Task> GetById(int id); + Task> CreateService(ServiceCreateDto serviceCreateDto); +} \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/ISiteService.cs b/ldap-cesi/Services/Interfaces/ISiteService.cs new file mode 100644 index 0000000..2b37660 --- /dev/null +++ b/ldap-cesi/Services/Interfaces/ISiteService.cs @@ -0,0 +1,6 @@ +namespace ldap_cesi.Services.Interfaces; + +public interface ISiteService +{ + +} \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/IUtilisateurService.cs b/ldap-cesi/Services/Interfaces/IUtilisateurService.cs new file mode 100644 index 0000000..fb93caf --- /dev/null +++ b/ldap-cesi/Services/Interfaces/IUtilisateurService.cs @@ -0,0 +1,13 @@ +using ldap_cesi.DTOs.Inputs; +using ldap_cesi.DTOs.Outputs.Utilisateur; +using ldap_cesi.Entities; +using ldap_cesi.Models; + +namespace ldap_cesi.Services.Interfaces; + +public interface IUtilisateurService +{ + Task>> GetAll(); + Task> GetById(int id); + Task> Login(UtilisateurLoginDto utilisateurInput); +} \ No newline at end of file diff --git a/ldap-cesi/Services/JwtService.cs b/ldap-cesi/Services/JwtService.cs new file mode 100644 index 0000000..085d41e --- /dev/null +++ b/ldap-cesi/Services/JwtService.cs @@ -0,0 +1,126 @@ +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Security.Cryptography; +using ldap_cesi.Context; +using ldap_cesi.Entities; +using ldap_cesi.Services.Interfaces; +using Microsoft.IdentityModel.Tokens; + +namespace ldap_cesi.Services; + +public class JwtService : IJwtService +{ + private readonly IRsaKeyService _rsaKeyService; + private readonly IConfiguration _configuration; + private readonly PgContext _context; + private readonly ILogger _logger; + + public JwtService( + IConfiguration configuration, + PgContext context, + IRsaKeyService rsaKeyService, + ILogger logger) + { + _configuration = configuration; + _context = context; + _rsaKeyService = rsaKeyService; + _logger = logger; + } + + public string GenerateToken(Utilisateur utilisateur) + { + try + { + var claims = new[] + { + new Claim(JwtRegisteredClaimNames.Sub, utilisateur.Email), + new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), + new Claim(ClaimTypes.Name, utilisateur.Nom), + new Claim(ClaimTypes.Role, utilisateur.IdRoleNavigation.Nom), + new Claim(ClaimTypes.NameIdentifier, utilisateur.Id.ToString()) + }; + + var key = new RsaSecurityKey(_rsaKeyService.GetRsaKey()); + var creds = new SigningCredentials(key, SecurityAlgorithms.RsaSha256); + + var tokenExpiryMinutes = _configuration.GetValue("Jwt:TokenExpiryMinutes", 30); + var token = new JwtSecurityToken( + issuer: _configuration["Jwt:Issuer"], + audience: _configuration["Jwt:Audience"], + claims: claims, + expires: DateTime.UtcNow.AddMinutes(tokenExpiryMinutes), + signingCredentials: creds); + + var tokenString = new JwtSecurityTokenHandler().WriteToken(token); + utilisateur.AccessToken = tokenString; + _context.Utilisateurs.Update(utilisateur); + _context.SaveChanges(); + + return tokenString; + } + catch (Exception ex) + { + _logger.LogError(ex, "An error occurred while generating the JWT token."); + throw; + } + } + + public string GetPublicKey() + { + try + { + var publicKey = _rsaKeyService.GetRsaKey().ExportSubjectPublicKeyInfo(); + return Convert.ToBase64String(publicKey); + } + catch (Exception ex) + { + _logger.LogError(ex, "An error occurred while retrieving the public key."); + throw; + } + } + + public async Task ValidateToken(string token, int userId) + { + try + { + var tokenHandler = new JwtSecurityTokenHandler(); + var validationParameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new RsaSecurityKey(_rsaKeyService.GetRsaKey()), + ValidateIssuer = true, + ValidateAudience = true, + ValidIssuer = _configuration["Jwt:Issuer"], + ValidAudience = _configuration["Jwt:Audience"], + ClockSkew = TimeSpan.Zero, + ValidateLifetime = true + }; + + var principal = tokenHandler.ValidateToken(token, validationParameters, out var validatedToken); + var nameIdClaim = principal.FindFirst(ClaimTypes.NameIdentifier); + if (nameIdClaim == null || !int.TryParse(nameIdClaim.Value, out var tokenUserId) || tokenUserId != userId) + { + _logger.LogWarning("Token validation failed: Invalid user ID."); + return false; + } + + var utilisateur = await _context.Utilisateurs.FindAsync(userId); + if (utilisateur == null) + { + _logger.LogWarning("Token validation failed: User not found."); + return false; + } + + utilisateur.AccessToken = token; + _context.Utilisateurs.Update(utilisateur); + await _context.SaveChangesAsync(); + + return true; + } + catch (Exception ex) + { + _logger.LogError(ex, "An error occurred while validating the JWT token."); + return false; + } + } +} \ No newline at end of file diff --git a/ldap-cesi/Services/RoleService.cs b/ldap-cesi/Services/RoleService.cs new file mode 100644 index 0000000..b388bae --- /dev/null +++ b/ldap-cesi/Services/RoleService.cs @@ -0,0 +1,15 @@ +using ldap_cesi.Repository.Services; +using ldap_cesi.Services.Interfaces; + +namespace ldap_cesi.Services; + +public class RoleService : IRoleService +{ + private IRepositoryRole _repositoryRole; + + public RoleService(IRepositoryRole repositoryRole) + { + _repositoryRole = repositoryRole; + } + +} \ No newline at end of file diff --git a/ldap-cesi/Services/RsaKeyService.cs b/ldap-cesi/Services/RsaKeyService.cs new file mode 100644 index 0000000..a71da2f --- /dev/null +++ b/ldap-cesi/Services/RsaKeyService.cs @@ -0,0 +1,36 @@ +using System.Security.Cryptography; +using ldap_cesi.Services.Interfaces; + +namespace ldap_cesi.Services; + +public class RsaKeyService : IRsaKeyService +{ + private readonly RSA _rsa; + private readonly string _keyPath; + + public RsaKeyService(IConfiguration configuration) + { + _rsa = RSA.Create(); + _keyPath = configuration["Jwt:KeyPath"] ?? "cle.bin"; + LoadOrCreateRsaKey(); + } + + private void LoadOrCreateRsaKey() + { + if (File.Exists(_keyPath)) + { + var keyBytes = File.ReadAllBytes(_keyPath); + _rsa.ImportRSAPrivateKey(keyBytes, out _); + } + else + { + var keyBytes = _rsa.ExportRSAPrivateKey(); + File.WriteAllBytes(_keyPath, keyBytes); + } + } + + public RSA GetRsaKey() + { + return _rsa; + } +} \ No newline at end of file diff --git a/ldap-cesi/Services/SalarieService.cs b/ldap-cesi/Services/SalarieService.cs new file mode 100644 index 0000000..be4410a --- /dev/null +++ b/ldap-cesi/Services/SalarieService.cs @@ -0,0 +1,38 @@ +using ldap_cesi.Entities; +using ldap_cesi.Models; +using ldap_cesi.Repository.Services; +using ldap_cesi.Services.Interfaces; + +namespace ldap_cesi.Services; + +public class SalarieService : ISalarieService +{ + private IRepositorySalarie _repositorySalarie; + + public SalarieService(IRepositorySalarie repositorySalarie) + { + _repositorySalarie = repositorySalarie; + } + + public async Task>> GetAll() + { + var salaries = await _repositorySalarie.GetAllAsync(); + return new ResponseDataModel> + { + Success = true, + Data = salaries, + StatusCode = 200, + }; + } + + public async Task> GetById(int id) + { + var service = await _repositorySalarie.GetByIdAsync(id); + return new ResponseDataModel + { + Success = true, + Data = service, + StatusCode = 200, + }; + } +} \ No newline at end of file diff --git a/ldap-cesi/Services/ServiceService.cs b/ldap-cesi/Services/ServiceService.cs new file mode 100644 index 0000000..c29cb22 --- /dev/null +++ b/ldap-cesi/Services/ServiceService.cs @@ -0,0 +1,54 @@ +using AutoMapper; +using ldap_cesi.DTOs.Inputs.Service; +using ldap_cesi.Entities; +using ldap_cesi.Models; +using ldap_cesi.Repository.Services; +using ldap_cesi.Services.Interfaces; + +namespace ldap_cesi.Services; + +public class ServiceService : IServiceService +{ + private readonly IRepositoryService _repositoryService; + private readonly IMapper _mapper; + + public ServiceService(IRepositoryService repositoryService, IMapper mapper) + { + _repositoryService = repositoryService; + _mapper = mapper; + } + + + public async Task>> GetAll() + { + var services = await _repositoryService.GetAllAsync(); + return new ResponseDataModel> + { + Success = true, + Data = services, + StatusCode = 200, + }; + } + + public async Task> GetById(int id) + { + var service = await _repositoryService.GetByIdAsync(id); + return new ResponseDataModel + { + Success = true, + Data = service, + StatusCode = 200, + }; + } + + public async Task> CreateService(ServiceCreateDto serviceCreateDto) + { + var service = _mapper.Map(serviceCreateDto); + var response = await _repositoryService.AddAsync(service); + return new ResponseDataModel + { + Success = true, + Data = response.Id.ToString(), + }; + } +} \ No newline at end of file diff --git a/ldap-cesi/Services/UtilisateurService.cs b/ldap-cesi/Services/UtilisateurService.cs new file mode 100644 index 0000000..bc7a00f --- /dev/null +++ b/ldap-cesi/Services/UtilisateurService.cs @@ -0,0 +1,80 @@ +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; + +namespace ldap_cesi.Services; + +public class UtilisateurService : IUtilisateurService +{ + private readonly IRepositoryUtilisateur _repositoryUtilisateur; + private readonly IJwtService _jwtService; + private readonly IMapper _mapper; + public UtilisateurService(IRepositoryUtilisateur repositoryUtilisateur, IJwtService jwtService, IMapper mapper) + { + _repositoryUtilisateur = repositoryUtilisateur; + _jwtService = jwtService; + _mapper = mapper; + } + + public async Task>> GetAll() + { + var utilisateurs = await _repositoryUtilisateur.GetAllAsync(); + return new ResponseDataModel> + { + Success = true, + StatusCode = 200, + Data = utilisateurs, + }; + } + + public async Task> GetById(int id) + { + var utililisateur = await _repositoryUtilisateur.GetByIdAsync(id); + return new ResponseDataModel + { + Success = true, + StatusCode = 200, + Data = utililisateur, + }; + } + + public async Task> Login(UtilisateurLoginDto utilisateurInput) + { + var utilisateur = await _repositoryUtilisateur.GetByEmailAsync(utilisateurInput.Email); + + if (utilisateur == null) + { + return new ResponseDataModel + { + Success = false, + StatusCode = 404, + Message = "Utilisateur non trouvé." + }; + } + + if (!BCrypt.Net.BCrypt.Verify(utilisateurInput.MotDePasse, utilisateur.MotDePasse)) + { + return new ResponseDataModel + { + Success = false, + StatusCode = 401, + Message = "Mot de passe incorrect." + }; + } + var token = _jwtService.GenerateToken(utilisateur); + var utilisateurOutputDto = _mapper.Map(utilisateur); + + return new ResponseDataModel + { + Success = true, + StatusCode = 200, + Data = utilisateurOutputDto, + Token = token, + Message = "Connexion réussie." + }; + } +} \ No newline at end of file diff --git a/ldap-cesi/ldap-cesi.csproj b/ldap-cesi/ldap-cesi.csproj index 99d7a59..0d8adcc 100644 --- a/ldap-cesi/ldap-cesi.csproj +++ b/ldap-cesi/ldap-cesi.csproj @@ -5,30 +5,32 @@ enable enable ldap_cesi + true - + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + + + - - - + diff --git a/ldap-cesi/ldap-cesi.http b/ldap-cesi/ldap-cesi.http deleted file mode 100644 index 352c4f9..0000000 --- a/ldap-cesi/ldap-cesi.http +++ /dev/null @@ -1,6 +0,0 @@ -@ldap_cesi_HostAddress = http://localhost:5080 - -GET {{ldap_cesi_HostAddress}}/weatherforecast/ -Accept: application/json - -### From 272e9283040e935cb4b065c48bcb250d91437138 Mon Sep 17 00:00:00 2001 From: BuzzLeclair Date: Sun, 2 Mar 2025 17:18:54 +0100 Subject: [PATCH 07/17] - Ajout de fluent validator - Ajout d'une validation sur le dtoLogin --- ldap-cesi/Configurations/Conf.cs | 1 + ldap-cesi/Models/ResponseDataModel.cs | 1 - ldap-cesi/Models/ResponseModel.cs | 2 +- .../Interfaces/IUtilisateurService.cs | 4 +-- ldap-cesi/Services/UtilisateurService.cs | 27 ++++++++++++++----- .../Utilisateur/UtilisateurCreateValidator.cs | 18 +++++++++++++ ldap-cesi/ldap-cesi.csproj | 4 ++- 7 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 ldap-cesi/Validator/Utilisateur/UtilisateurCreateValidator.cs diff --git a/ldap-cesi/Configurations/Conf.cs b/ldap-cesi/Configurations/Conf.cs index e4f5b10..64e7298 100644 --- a/ldap-cesi/Configurations/Conf.cs +++ b/ldap-cesi/Configurations/Conf.cs @@ -27,6 +27,7 @@ public static class Conf builder.AddSerilog(); builder.AddJwt(); builder.Services.AddAutoMapper(typeof(Program)); + } public static void AddRepositories(this WebApplicationBuilder builder) diff --git a/ldap-cesi/Models/ResponseDataModel.cs b/ldap-cesi/Models/ResponseDataModel.cs index eb66c0f..1b415c7 100644 --- a/ldap-cesi/Models/ResponseDataModel.cs +++ b/ldap-cesi/Models/ResponseDataModel.cs @@ -3,5 +3,4 @@ namespace ldap_cesi.Models; public class ResponseDataModel : ResponseModel, IResponseDataModel where T : class { public T Data { get; set; } = null!; - public string Token { get; set; } } \ No newline at end of file diff --git a/ldap-cesi/Models/ResponseModel.cs b/ldap-cesi/Models/ResponseModel.cs index 57393de..2173782 100644 --- a/ldap-cesi/Models/ResponseModel.cs +++ b/ldap-cesi/Models/ResponseModel.cs @@ -4,7 +4,7 @@ public class ResponseModel : IResponseModel { public bool Success { get; set; } public string? Message { get; set; } - public string? TokenJWT { get; set; } + public string? Token { get; set; } public int StatusCode { get; set; } } \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/IUtilisateurService.cs b/ldap-cesi/Services/Interfaces/IUtilisateurService.cs index fb93caf..88d9fa2 100644 --- a/ldap-cesi/Services/Interfaces/IUtilisateurService.cs +++ b/ldap-cesi/Services/Interfaces/IUtilisateurService.cs @@ -7,7 +7,7 @@ namespace ldap_cesi.Services.Interfaces; public interface IUtilisateurService { - Task>> GetAll(); - Task> GetById(int id); + Task>> GetAll(); + Task> GetById(int id); Task> Login(UtilisateurLoginDto utilisateurInput); } \ No newline at end of file diff --git a/ldap-cesi/Services/UtilisateurService.cs b/ldap-cesi/Services/UtilisateurService.cs index bc7a00f..b908c5a 100644 --- a/ldap-cesi/Services/UtilisateurService.cs +++ b/ldap-cesi/Services/UtilisateurService.cs @@ -5,6 +5,7 @@ using ldap_cesi.Entities; using ldap_cesi.Models; using ldap_cesi.Repository.Services; using ldap_cesi.Services.Interfaces; +using ldap_cesi.Validator.Utilisateur; namespace ldap_cesi.Services; @@ -20,30 +21,44 @@ public class UtilisateurService : IUtilisateurService _mapper = mapper; } - public async Task>> GetAll() + public async Task>> GetAll() { var utilisateurs = await _repositoryUtilisateur.GetAllAsync(); - return new ResponseDataModel> + var utilisateursOutputDto = _mapper.Map>(utilisateurs); + return new ResponseDataModel> { Success = true, StatusCode = 200, - Data = utilisateurs, + Data = utilisateursOutputDto, }; } - public async Task> GetById(int id) + public async Task> GetById(int id) { var utililisateur = await _repositoryUtilisateur.GetByIdAsync(id); - return new ResponseDataModel + var utilisateurOutput = _mapper.Map(utililisateur); + return new ResponseDataModel { Success = true, StatusCode = 200, - Data = utililisateur, + Data = utilisateurOutput, }; } public async Task> Login(UtilisateurLoginDto utilisateurInput) { + var validation = new UtilisateurCreateValidator(); + var result = validation.Validate(utilisateurInput); + if (!result.IsValid) + { + return new ResponseDataModel + { + StatusCode = 400, + Success = false, + Message = "Données utilisateur invalides: " + string.Join(", ", result.Errors) + }; + } + var utilisateur = await _repositoryUtilisateur.GetByEmailAsync(utilisateurInput.Email); if (utilisateur == null) diff --git a/ldap-cesi/Validator/Utilisateur/UtilisateurCreateValidator.cs b/ldap-cesi/Validator/Utilisateur/UtilisateurCreateValidator.cs new file mode 100644 index 0000000..154b071 --- /dev/null +++ b/ldap-cesi/Validator/Utilisateur/UtilisateurCreateValidator.cs @@ -0,0 +1,18 @@ +using FluentValidation; +using ldap_cesi.DTOs.Inputs; + +namespace ldap_cesi.Validator.Utilisateur; + +public class UtilisateurCreateValidator : AbstractValidator +{ + public UtilisateurCreateValidator() + { + RuleFor(x => x.Email) + .NotEmpty().WithMessage("L'email est requis.") + .EmailAddress().WithMessage("L'email n'est pas valide."); + + RuleFor(x => x.MotDePasse) + .NotEmpty().WithMessage("Le mot de passe est requis.") + .MinimumLength(6).WithMessage("Le mot de passe doit contenir au moins 6 caractères."); + } +} \ No newline at end of file diff --git a/ldap-cesi/ldap-cesi.csproj b/ldap-cesi/ldap-cesi.csproj index 0d8adcc..f06e052 100644 --- a/ldap-cesi/ldap-cesi.csproj +++ b/ldap-cesi/ldap-cesi.csproj @@ -11,8 +11,10 @@ + + - + all From 1fb1f49f9dca3acd6cc146713ca708729cd24abe Mon Sep 17 00:00:00 2001 From: BuzzLeclair Date: Mon, 3 Mar 2025 00:56:59 +0100 Subject: [PATCH 08/17] - Ajout de tous les crud //TODO : revoir le retour des fonctions getSSalarieByService/site --- .idea/.idea.ldap-cesi/.idea/vcs.xml | 4 +- ldap-cesi/Configurations/Conf.cs | 4 +- ldap-cesi/Controllers/SalarieController.cs | 121 ++++++++-- ldap-cesi/Controllers/ServicesController.cs | 69 ++++-- ldap-cesi/Controllers/SiteController.cs | 84 +++++++ .../Controllers/UtilisateurController.cs | 36 +-- ldap-cesi/DTOs/Generic/ServiceDto.cs | 8 + ldap-cesi/DTOs/Generic/SiteDto.cs | 8 + .../DTOs/Inputs/Salarie/SalarieCreateDto.cs | 4 +- .../DTOs/Outputs/Salarie/SalarieListDto.cs | 12 + .../Outputs/Salarie/SalarieOutputDetail.cs | 19 ++ ldap-cesi/Mapper/AutoMapperProfile.cs | 28 ++- ldap-cesi/Models/IEntity.cs | 6 + .../Interfaces/IRepositoryBase.cs | 4 +- .../Interfaces/IRepositorySalarie.cs | 5 +- ldap-cesi/Repositories/RepositoryBase.cs | 7 +- ldap-cesi/Repositories/SalarieRepository.cs | 36 +++ .../Services/Interfaces/ISalarieService.cs | 9 + .../Services/Interfaces/IServiceService.cs | 2 + ldap-cesi/Services/Interfaces/ISiteService.cs | 11 +- ldap-cesi/Services/SalarieService.cs | 207 +++++++++++++++++- ldap-cesi/Services/ServiceService.cs | 96 ++++++++ ldap-cesi/Services/SiteService.cs | 151 +++++++++++++ .../Salarie/SalarieCreateValidator.cs | 37 ++++ .../Salarie/SalarieUpdateValidator.cs | 39 ++++ .../Service/ServiceCreateValidator.cs | 14 ++ .../Service/ServiceUpdateValidator.cs | 18 ++ .../Validator/Site/SiteCreateValidator.cs | 14 ++ .../Validator/Site/SiteUpdateValidator.cs | 16 ++ ldap-cesi/ldap-cesi.csproj | 1 - 30 files changed, 1004 insertions(+), 66 deletions(-) create mode 100644 ldap-cesi/Controllers/SiteController.cs create mode 100644 ldap-cesi/DTOs/Generic/ServiceDto.cs create mode 100644 ldap-cesi/DTOs/Generic/SiteDto.cs create mode 100644 ldap-cesi/DTOs/Outputs/Salarie/SalarieListDto.cs create mode 100644 ldap-cesi/DTOs/Outputs/Salarie/SalarieOutputDetail.cs create mode 100644 ldap-cesi/Models/IEntity.cs create mode 100644 ldap-cesi/Services/SiteService.cs create mode 100644 ldap-cesi/Validator/Salarie/SalarieCreateValidator.cs create mode 100644 ldap-cesi/Validator/Salarie/SalarieUpdateValidator.cs create mode 100644 ldap-cesi/Validator/Service/ServiceCreateValidator.cs create mode 100644 ldap-cesi/Validator/Service/ServiceUpdateValidator.cs create mode 100644 ldap-cesi/Validator/Site/SiteCreateValidator.cs create mode 100644 ldap-cesi/Validator/Site/SiteUpdateValidator.cs diff --git a/.idea/.idea.ldap-cesi/.idea/vcs.xml b/.idea/.idea.ldap-cesi/.idea/vcs.xml index d843f34..35eb1dd 100644 --- a/.idea/.idea.ldap-cesi/.idea/vcs.xml +++ b/.idea/.idea.ldap-cesi/.idea/vcs.xml @@ -1,4 +1,6 @@ - + + + \ No newline at end of file diff --git a/ldap-cesi/Configurations/Conf.cs b/ldap-cesi/Configurations/Conf.cs index 64e7298..32e91c3 100644 --- a/ldap-cesi/Configurations/Conf.cs +++ b/ldap-cesi/Configurations/Conf.cs @@ -43,7 +43,7 @@ public static class Conf { builder.Services.AddScoped(); // builder.Services.AddScoped(); - // builder.Services.AddScoped(); + builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); @@ -53,7 +53,7 @@ public static class Conf { string connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); builder.Services.AddDbContext(options => options.UseNpgsql(connectionString)); - } + } public static void CorseConfiguration(this WebApplicationBuilder builder) { builder.Services.AddCors(options => diff --git a/ldap-cesi/Controllers/SalarieController.cs b/ldap-cesi/Controllers/SalarieController.cs index fdf1cf7..63d9120 100644 --- a/ldap-cesi/Controllers/SalarieController.cs +++ b/ldap-cesi/Controllers/SalarieController.cs @@ -1,4 +1,7 @@ +using ldap_cesi.DTOs.Inputs.Salarie; +using ldap_cesi.DTOs.Inputs.Service; using ldap_cesi.Services.Interfaces; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace ldap_cesi.Controllers; @@ -13,27 +16,115 @@ public class SalarieController : ControllerBase _salarieService = salarieService; } - // GET: api/salaries - /// - /// Endpoint qui retournes tous les salaries + /// + /// Endpoint qui retourne tous les salariés. /// - /// List + /// Une liste de salariés. [HttpGet] - public async Task GetUtilisateurs() + public async Task GetAllSalaries() { var result = await _salarieService.GetAll(); - return result.Success ? Ok(result) : BadRequest(result); - } - - // GET: api/salaries + return result.Success ? Ok(result.Data) : BadRequest(result.Message); + } + /// - /// Endpoint retourne le salarie correspondant à l'id en param + /// Endpoint qui retourne le salarié correspondant à l'ID en paramètre. /// - /// Salarie + /// L'ID du salarié. + /// Le salarié correspondant à l'ID. [HttpGet("{id}")] - public async Task GetUtilisateurById(int id) + public async Task GetSalarieById(int id) { var result = await _salarieService.GetById(id); - return result.Success ? Ok(result) : BadRequest(result); - } -} \ No newline at end of file + return result.Success ? Ok(result.Data) : BadRequest(result.Message); + } + + /// + /// 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. + [HttpGet("/complet/{id}")] + public async Task GetSalarieCompletById(int id) + { + var result = await _salarieService.GetCompletById(id); + return result.Success ? Ok(result.Data) : BadRequest(result.Message); + } + + /// + /// Endpoint qui crée un salarié. + /// + /// Les informations du salarié à créer. + /// Le salarié créé. + [HttpPost] + [Authorize(Roles = "admin")] + public async Task CreateSalarie([FromBody] SalarieCreateDto salarieInput) + { + var result = await _salarieService.Create(salarieInput); + return result.Success ? Ok(result.Data) : BadRequest(result.Message); + } + + /// + /// Endpoint qui met à jour un salarié. + /// + /// Les informations du salarié à mettre à jour. + /// Le salarié mis à jour. + [HttpPut] + [Authorize(Roles = "admin")] + public async Task UpdateSalarie([FromBody] SalarieUpdateDto salarieInput) + { + var result = await _salarieService.Update(salarieInput); + return result.Success ? Ok(result.Data) : BadRequest(result.Message); + } + + /// + /// Endpoint qui supprime un salarié. + /// + /// L'ID du salarié à supprimer. + /// Un message de confirmation de suppression. + [HttpDelete("{id}")] + [Authorize(Roles = "admin")] + public async Task DeleteSalarie(int id) + { + var result = await _salarieService.Delete(id); + return result.Success ? Ok(result.Data) : BadRequest(result.Message); + } + + /// + /// Récupère les salariés appartenant à un site spécifique + /// + /// Identifiant du site + /// Liste des salariés du site + [HttpGet("site/{siteId}")] + public async Task GetSalariesBySite(int siteId) + { + var result = await _salarieService.GetSalariesBySite(siteId); + return result.Success ? Ok(result.Data) : NotFound(result.Message); + } + + /// + /// Récupère les salariés appartenant à un service spécifique + /// + /// Identifiant du service + /// Liste des salariés du service + [HttpGet("service/{serviceId}")] + public async Task GetSalariesByService(int serviceId) + { + 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/Controllers/ServicesController.cs b/ldap-cesi/Controllers/ServicesController.cs index 0d0e987..d9c3c84 100644 --- a/ldap-cesi/Controllers/ServicesController.cs +++ b/ldap-cesi/Controllers/ServicesController.cs @@ -16,40 +16,67 @@ public class ServicesController : ControllerBase _serviceService = serviceService; } - // GET: api/services /// - /// Endpoint qui retournes tous les services + /// Endpoint qui retourne tous les services. /// - /// Retourne tous les services + /// Retourne tous les services. [HttpGet] - // [Authorize(Roles = "admin")] - public async Task GetServices() + [Authorize(Roles = "admin")] + public async Task GetServices() { var result = await _serviceService.GetAll(); - return result.Success ? Ok(result) : BadRequest(result); - } - - // GET: api/services + return result.Success ? Ok(result.Data) : BadRequest(result.Message); + } + /// - /// Endpoint retourne le service correspondant à l'id en param + /// Endpoint qui retourne le service correspondant à l'id en paramètre. /// - /// Service + /// L'ID du service. + /// Le service correspondant à l'ID. [HttpGet("{id}")] - public async Task GetServices(int id) + [Authorize(Roles = "admin")] + public async Task GetServiceById(int id) { var result = await _serviceService.GetById(id); - return result.Success ? Ok(result) : BadRequest(result); - } - - // {POST}: api/services + return result.Success ? Ok(result.Data) : BadRequest(result.Message); + } + /// - /// Endpoint qui créé un service + /// Endpoint qui crée un service. /// - /// Retourne tous les services + /// Les informations du service à créer. + /// Le service créé. [HttpPost] - public async Task CreateService([FromBody] ServiceCreateDto serviceInputDto) + [Authorize(Roles = "admin")] + public async Task CreateService([FromBody] ServiceCreateDto serviceInputDto) { var result = await _serviceService.CreateService(serviceInputDto); - return result.Success ? Ok(result) : BadRequest(result); - } + return result.Success ? Ok(result.Data) : BadRequest(result.Message); + } + + /// + /// Endpoint qui met à jour un service. + /// + /// Les informations du service à mettre à jour. + /// Le service mis à jour. + [HttpPut] + [Authorize(Roles = "admin")] + public async Task UpdateService([FromBody] ServiceUpdateDto serviceUpdateDto) + { + var result = await _serviceService.UpdateService(serviceUpdateDto); + return result.Success ? Ok(result.Data) : BadRequest(result.Message); + } + + /// + /// Endpoint qui supprime un service. + /// + /// L'ID du service à supprimer. + /// Un message de confirmation de suppression. + [HttpDelete("{id}")] + [Authorize(Roles = "admin")] + public async Task DeleteService(int id) + { + var result = await _serviceService.DeleteService(id); + return result.Success ? Ok(result.Message) : BadRequest(result.Message); + } } \ No newline at end of file diff --git a/ldap-cesi/Controllers/SiteController.cs b/ldap-cesi/Controllers/SiteController.cs new file mode 100644 index 0000000..50664dc --- /dev/null +++ b/ldap-cesi/Controllers/SiteController.cs @@ -0,0 +1,84 @@ +using ldap_cesi.DTOs.Inputs.Site; +using ldap_cesi.Services.Interfaces; +using Microsoft.AspNetCore.Mvc; + +namespace ldap_cesi.Controllers; + +[ApiController] +[Route("/api/site")] +public class SiteController : ControllerBase +{ + private readonly ISiteService _siteService; + + public SiteController(ISiteService siteService) + { + _siteService = siteService; + } + + // GET: api/site + /// + /// Récupère la liste de tous les sites. + /// + /// Retourne une liste de tous les sites. + [HttpGet] + public async Task GetSites() + { + var result = await _siteService.GetAll(); + return result.Success ? Ok(result) : BadRequest(result); + } + + // GET: api/site/{id} + /// + /// Récupère un site spécifique par son identifiant. + /// + /// L'identifiant du site à récupérer. + /// Retourne le site correspondant à l'identifiant. + /// Le site a été récupéré avec succès. + /// Une erreur s'est produite lors de la récupération du site. + /// Le site n'a pas été trouvé. + [HttpGet("{id}")] + public async Task GetSite(int id) + { + var result = await _siteService.GetById(id); + return result.Success ? Ok(result) : BadRequest(result); + } + + // POST: api/site + /// + /// Crée un nouveau site. + /// + /// Les données du site à créer. + /// Retourne l'identifiant du site créé. + [HttpPost] + public async Task CreateSite([FromBody] SiteCreateDto siteCreateDto) + { + var result = await _siteService.CreateSite(siteCreateDto); + return result.Success ? Ok(result) : BadRequest(result); + } + + // PUT: api/site + /// + /// Met à jour un site existant. + /// + /// Les données du site à mettre à jour. + /// Retourne l'objet ou une erreur. + [HttpPut] + public async Task UpdateSite([FromBody] SiteUpdateDto siteUpdateDto) + { + var result = await _siteService.UpdateSite(siteUpdateDto); + return result.Success ? Ok(result) : BadRequest(result); + } + + // DELETE: api/site/{id} + /// + /// Supprime un site par son identifiant. + /// + /// L'identifiant du site à supprimer. + /// Retourne l'id, ou l'erreur + [HttpDelete("{id}")] + public async Task DeleteSite(int id) + { + var result = await _siteService.DeleteSite(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 f9b5a51..c56ca6f 100644 --- a/ldap-cesi/Controllers/UtilisateurController.cs +++ b/ldap-cesi/Controllers/UtilisateurController.cs @@ -1,5 +1,6 @@ using ldap_cesi.DTOs.Inputs; using ldap_cesi.Services.Interfaces; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace ldap_cesi.Controllers; @@ -13,35 +14,42 @@ public class UtilisateurController : ControllerBase { _utilisateurService = utilisateurService; } - + + + /// + /// Endpoint pour la connexion des utilisateurs. + /// + /// Les informations de connexion de l'utilisateur. + /// Un token JWT si la connexion est réussie. [HttpPost("login")] public async Task Login([FromBody] UtilisateurLoginDto utilisateurInput) { var response = await _utilisateurService.Login(utilisateurInput); return StatusCode(response.StatusCode, response); } - - // GET: api/utilisateurs + /// - /// Endpoint qui retournes tous les utilisateurs + /// Endpoint pour récupérer tous les utilisateurs. /// - /// List + /// Une liste d'utilisateurs. [HttpGet] - public async Task GetUtilisateurs() + [Authorize(Roles = "admin")] + public async Task GetUtilisateurs() { var result = await _utilisateurService.GetAll(); - return result.Success ? Ok(result) : BadRequest(result); - } - - // GET: api/utilisateur + return result.Success ? Ok(result.Data) : BadRequest(result.Message); + } + /// - /// Endpoint retourne l'utilisateur correspondant à l'id en param + /// Endpoint pour récupérer un utilisateur par son ID. /// - /// Utilisateur + /// L'ID de l'utilisateur. + /// L'utilisateur correspondant à l'ID. [HttpGet("{id}")] - public async Task GetUtilisateurById(int id) + [Authorize(Roles = "admin")] + public async Task GetUtilisateurById(int id) { var result = await _utilisateurService.GetById(id); - return result.Success ? Ok(result) : BadRequest(result); + return result.Success ? Ok(result.Data) : BadRequest(result.Message); } } \ No newline at end of file diff --git a/ldap-cesi/DTOs/Generic/ServiceDto.cs b/ldap-cesi/DTOs/Generic/ServiceDto.cs new file mode 100644 index 0000000..f786ae4 --- /dev/null +++ b/ldap-cesi/DTOs/Generic/ServiceDto.cs @@ -0,0 +1,8 @@ +namespace ldap_cesi.DTOs; + +public class ServiceDto +{ + public int Id { get; set; } + + public string Nom { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/DTOs/Generic/SiteDto.cs b/ldap-cesi/DTOs/Generic/SiteDto.cs new file mode 100644 index 0000000..82fa364 --- /dev/null +++ b/ldap-cesi/DTOs/Generic/SiteDto.cs @@ -0,0 +1,8 @@ +namespace ldap_cesi.DTOs; + +public class SiteDto +{ + public int Id { get; set; } + + public string Ville { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/DTOs/Inputs/Salarie/SalarieCreateDto.cs b/ldap-cesi/DTOs/Inputs/Salarie/SalarieCreateDto.cs index 7804ce4..9842778 100644 --- a/ldap-cesi/DTOs/Inputs/Salarie/SalarieCreateDto.cs +++ b/ldap-cesi/DTOs/Inputs/Salarie/SalarieCreateDto.cs @@ -4,8 +4,8 @@ public class SalarieCreateDto { public string Nom { get; set; } public string Prenom { get; set; } - public string Telephone_fix { get; set; } - public string Telephone_portable { get; set; } + public string TelephoneFix { get; set; } + public string TelephonePortable { get; set; } public string Email { get; set; } public int IdSite { get; set; } public int IdService { get; set; } diff --git a/ldap-cesi/DTOs/Outputs/Salarie/SalarieListDto.cs b/ldap-cesi/DTOs/Outputs/Salarie/SalarieListDto.cs new file mode 100644 index 0000000..07fccb5 --- /dev/null +++ b/ldap-cesi/DTOs/Outputs/Salarie/SalarieListDto.cs @@ -0,0 +1,12 @@ +namespace ldap_cesi.DTOs.Outputs.Salarie; + +public class SalarieListDto +{ + + public int Id { get; set; } + 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; } +} \ No newline at end of file diff --git a/ldap-cesi/DTOs/Outputs/Salarie/SalarieOutputDetail.cs b/ldap-cesi/DTOs/Outputs/Salarie/SalarieOutputDetail.cs new file mode 100644 index 0000000..060b7cd --- /dev/null +++ b/ldap-cesi/DTOs/Outputs/Salarie/SalarieOutputDetail.cs @@ -0,0 +1,19 @@ +namespace ldap_cesi.DTOs.Outputs.Salarie; + +public class SalarieOutputDetail +{ + public int Id { get; set; } + + public string Nom { get; set; } + + public string Prenom { get; set; } + + public string TelephoneFixe { get; set; } + + public string TelephonePortable { get; set; } + + public string Email { get; set; } + + public ServiceDto Service { get; set; } + public SiteDto Site { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/Mapper/AutoMapperProfile.cs b/ldap-cesi/Mapper/AutoMapperProfile.cs index 15fc504..8d3924e 100644 --- a/ldap-cesi/Mapper/AutoMapperProfile.cs +++ b/ldap-cesi/Mapper/AutoMapperProfile.cs @@ -1,5 +1,9 @@ using AutoMapper; +using ldap_cesi.DTOs; +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.Utilisateur; using ldap_cesi.Entities; @@ -9,8 +13,30 @@ public class AutoMapperProfile : Profile { public AutoMapperProfile() { + // INPUTS MAPPER + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap() + .ForMember(dest => dest.TelephoneFixe, opt => opt.MapFrom(src => src.TelephoneFix)) + .ForMember(dest => dest.TelephonePortable, opt => opt.MapFrom(src => src.TelephonePortable)); + CreateMap() + .ForMember(dest => dest.TelephoneFixe, opt => opt.MapFrom(src => src.TelephoneFixe)) + .ForMember(dest => dest.TelephonePortable, opt => opt.MapFrom(src => src.TelephonePortable)); + + + //OUTPUTS MAPPER CreateMap() .ForMember(dest => dest.RoleNom, opt => opt.MapFrom(src => src.IdRoleNavigation.Nom)); - CreateMap(); + 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.Nom)) + .ForMember(dest => dest.Site, opt => opt.MapFrom(src => src.IdSiteNavigation.Ville)); + CreateMap(); + CreateMap(); + CreateMap(); } } \ No newline at end of file diff --git a/ldap-cesi/Models/IEntity.cs b/ldap-cesi/Models/IEntity.cs new file mode 100644 index 0000000..2120b39 --- /dev/null +++ b/ldap-cesi/Models/IEntity.cs @@ -0,0 +1,6 @@ +namespace ldap_cesi.Models; + +public interface IEntity +{ + int Id { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs b/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs index 1057e98..1daf9fb 100644 --- a/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs +++ b/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs @@ -8,8 +8,8 @@ public interface IRepositoryBase where TEntity : class Task AnyAsync(Expression> predicate, CancellationToken cancellationToken = default); Task GetByIdAsync(TId id, CancellationToken cancellationToken = default) where TId : notnull; Task> GetAllAsync(CancellationToken cancellationToken = default); - Task UpdateAsync(TEntity entity, CancellationToken cancellationToken = default); - Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default); + Task UpdateAsync(TEntity entity, CancellationToken cancellationToken = default); + Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default); Task FirstOrDefaultAsync(Expression> predicate, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/ldap-cesi/Repositories/Interfaces/IRepositorySalarie.cs b/ldap-cesi/Repositories/Interfaces/IRepositorySalarie.cs index c281f5f..410c326 100644 --- a/ldap-cesi/Repositories/Interfaces/IRepositorySalarie.cs +++ b/ldap-cesi/Repositories/Interfaces/IRepositorySalarie.cs @@ -4,5 +4,8 @@ namespace ldap_cesi.Repository.Services; public interface IRepositorySalarie : IRepositoryBase { - + Task GetSalarieWithRelationsAsync(int id); + Task> SearchByNameAsync(string inputRecherche); + Task> GetSalariesBySiteAsync(int siteId); + Task> GetSalariesByServiceAsync(int serviceId); } \ No newline at end of file diff --git a/ldap-cesi/Repositories/RepositoryBase.cs b/ldap-cesi/Repositories/RepositoryBase.cs index 911ddcd..3253321 100644 --- a/ldap-cesi/Repositories/RepositoryBase.cs +++ b/ldap-cesi/Repositories/RepositoryBase.cs @@ -1,5 +1,6 @@ using System.Linq.Expressions; using ldap_cesi.Context; +using ldap_cesi.Models; using ldap_cesi.Repository.Services; using Microsoft.EntityFrameworkCore; @@ -49,12 +50,13 @@ public class RepositoryBase : IRepositoryBase where TEntity : return await _context.Set().FirstOrDefaultAsync(predicate, cancellationToken); } - public virtual async Task UpdateAsync(TEntity entity, CancellationToken cancellationToken = default) + public virtual async Task UpdateAsync(TEntity entity, CancellationToken cancellationToken = default) { try { _context.Set().Update(entity); await SaveChangesAsync(cancellationToken); + return true; } catch (Exception ex) { @@ -74,12 +76,13 @@ public class RepositoryBase : IRepositoryBase where TEntity : } } - public virtual async Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default) + public virtual async Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default) { try { _context.Set().Remove(entity); await SaveChangesAsync(cancellationToken); + return true; } catch (Exception ex) { diff --git a/ldap-cesi/Repositories/SalarieRepository.cs b/ldap-cesi/Repositories/SalarieRepository.cs index bb84bb1..cb5d329 100644 --- a/ldap-cesi/Repositories/SalarieRepository.cs +++ b/ldap-cesi/Repositories/SalarieRepository.cs @@ -1,6 +1,7 @@ using ldap_cesi.Context; using ldap_cesi.Entities; using ldap_cesi.Repository.Services; +using Microsoft.EntityFrameworkCore; namespace ldap_cesi.Repository; @@ -10,4 +11,39 @@ public class SalarieRepository : RepositoryBase, IRepositorySalarie { } + + public async Task GetSalarieWithRelationsAsync(int id) + { + return await _context.Salaries + .Include(s => s.IdServiceNavigation) + .Include(s => s.IdSiteNavigation) + .FirstOrDefaultAsync(s => s.Id == id); + } + + public async Task> SearchByNameAsync(string inputRecherche) + { + return await _context.Salaries + .Where(s => s.Nom.Contains(inputRecherche) || s.Prenom.Contains(inputRecherche)) + .Include(s => s.IdServiceNavigation) + .Include(s => s.IdSiteNavigation) + .ToListAsync(); + } + + public async Task> GetSalariesBySiteAsync(int siteId) + { + return await _context.Salaries + .Where(s => s.IdSite == siteId) + .Include(s => s.IdServiceNavigation) + .Include(s => s.IdSiteNavigation) + .ToListAsync(); + } + + public async Task> GetSalariesByServiceAsync(int serviceId) + { + return await _context.Salaries + .Where(s => s.IdService == serviceId) + .Include(s => s.IdServiceNavigation) + .Include(s => s.IdSiteNavigation) + .ToListAsync(); + } } \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/ISalarieService.cs b/ldap-cesi/Services/Interfaces/ISalarieService.cs index c6bce16..5318fa7 100644 --- a/ldap-cesi/Services/Interfaces/ISalarieService.cs +++ b/ldap-cesi/Services/Interfaces/ISalarieService.cs @@ -1,3 +1,6 @@ +using ldap_cesi.DTOs.Inputs.Salarie; +using ldap_cesi.DTOs.Inputs.Service; +using ldap_cesi.DTOs.Outputs.Salarie; using ldap_cesi.Entities; using ldap_cesi.Models; @@ -7,4 +10,10 @@ public interface ISalarieService { Task>> GetAll(); Task> GetById(int id); + Task>> GetSalariesBySite(int siteId); + Task>> GetSalariesByService(int serviceId); + Task> Create(SalarieCreateDto salarieInput); + Task> Update(SalarieUpdateDto salarieInput); + Task> Delete(int id); + Task> GetCompletById(int id); } \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/IServiceService.cs b/ldap-cesi/Services/Interfaces/IServiceService.cs index f44a387..4247928 100644 --- a/ldap-cesi/Services/Interfaces/IServiceService.cs +++ b/ldap-cesi/Services/Interfaces/IServiceService.cs @@ -9,4 +9,6 @@ public interface IServiceService Task>> GetAll(); Task> GetById(int id); Task> CreateService(ServiceCreateDto serviceCreateDto); + Task> UpdateService(ServiceUpdateDto serviceUpdateDto); + Task> DeleteService(int id); } \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/ISiteService.cs b/ldap-cesi/Services/Interfaces/ISiteService.cs index 2b37660..cdff833 100644 --- a/ldap-cesi/Services/Interfaces/ISiteService.cs +++ b/ldap-cesi/Services/Interfaces/ISiteService.cs @@ -1,6 +1,15 @@ +using ldap_cesi.DTOs.Inputs.Service; +using ldap_cesi.DTOs.Inputs.Site; +using ldap_cesi.Entities; +using ldap_cesi.Models; + namespace ldap_cesi.Services.Interfaces; public interface ISiteService { - + 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 be4410a..69c8108 100644 --- a/ldap-cesi/Services/SalarieService.cs +++ b/ldap-cesi/Services/SalarieService.cs @@ -1,17 +1,28 @@ +using AutoMapper; +using ldap_cesi.DTOs.Inputs.Salarie; +using ldap_cesi.DTOs.Inputs.Service; +using ldap_cesi.DTOs.Outputs.Salarie; using ldap_cesi.Entities; using ldap_cesi.Models; using ldap_cesi.Repository.Services; using ldap_cesi.Services.Interfaces; +using ldap_cesi.Validator.Salarie; namespace ldap_cesi.Services; public class SalarieService : ISalarieService { private IRepositorySalarie _repositorySalarie; + private readonly IRepositorySite _repositorySite; + private readonly IRepositoryService _repositoryService; + private readonly IMapper _mapper; - public SalarieService(IRepositorySalarie repositorySalarie) + public SalarieService(IRepositorySalarie repositorySalarie, IMapper mapper, IRepositorySite repositorySite, IRepositoryService repositoryService) { _repositorySalarie = repositorySalarie; + _repositorySite = repositorySite; + _repositoryService = repositoryService; + _mapper = mapper; } public async Task>> GetAll() @@ -27,12 +38,202 @@ public class SalarieService : ISalarieService public async Task> GetById(int id) { - var service = await _repositorySalarie.GetByIdAsync(id); + var salarie = await _repositorySalarie.GetSalarieWithRelationsAsync(id); return new ResponseDataModel { Success = true, - Data = service, + Data = salarie, + StatusCode = 200, + }; + } + + public async Task> GetCompletById(int id) + { + var salarie = await _repositorySalarie.GetSalarieWithRelationsAsync(id); + var salarieOutput = _mapper.Map(salarie); + return new ResponseDataModel + { + Success = true, + Data = salarieOutput, StatusCode = 200, }; } + + public async Task>> GetSalariesBySite(int siteId) + { + var site = await _repositorySite.GetByIdAsync(siteId); + if (site == null) + { + return new ResponseDataModel> + { + Success = false, + Message = "Site non trouvé", + StatusCode = 404 + }; + } + + var salaries = await _repositorySalarie.GetSalariesBySiteAsync(siteId); + if (!salaries.Any()) + { + return new ResponseDataModel> + { + Success = true, + Message = "Aucun salarié trouvé pour ce site", + Data = new List(), + StatusCode = 200 + }; + } + + var salariesDto = _mapper.Map>(salaries); + + return new ResponseDataModel> + { + Success = true, + Data = salariesDto, + StatusCode = 200 + }; + } + + public async Task>> GetSalariesByService(int serviceId) + { + var service = await _repositoryService.GetByIdAsync(serviceId); + if (service == null) + { + return new ResponseDataModel> + { + Success = false, + Message = "Service non trouvé", + StatusCode = 404 + }; + } + + var salaries = await _repositorySalarie.GetSalariesByServiceAsync(serviceId); + var salariesDto = _mapper.Map>(salaries); + + return new ResponseDataModel> + { + Success = true, + Data = salariesDto, + StatusCode = 200 + }; + } + + public async Task>> RechercherParNom(string nom) + { + var salaries = await _repositorySalarie.SearchByNameAsync(nom); + var salariesDto = _mapper.Map>(salaries); + + return new ResponseDataModel> + { + Success = true, + Data = salariesDto, + StatusCode = 200 + }; + } + + public async Task> Create(SalarieCreateDto salarieInput) + { + var validation = new SalarieCreateValidator(); + var result = validation.Validate(salarieInput); + if (!result.IsValid) + { + return new ResponseDataModel + { + StatusCode = 400, + Success = false, + Message = "Données salariées invalides: " + string.Join(", ", result.Errors) + }; + } + var service = _mapper.Map(salarieInput); + var response = await _repositorySalarie.AddAsync(service); + return new ResponseDataModel + { + StatusCode = 201, + Success = true, + Data = response.Id.ToString(), + }; + } + + public async Task> Update(SalarieUpdateDto salarieInput) + { + var validation = new SalarieUpdateValidator(); + var result = validation.Validate(salarieInput); + if (!result.IsValid) + { + return new ResponseDataModel + { + StatusCode = 400, + Success = false, + Message = "Données salariées invalides: " + string.Join(", ", result.Errors) + }; + } + + var salarieFind = await _repositorySalarie.GetByIdAsync(salarieInput.Id); + if (salarieFind == null) + { + return new ResponseDataModel + { + Success = false, + Message = "Salarié introuvable.", + StatusCode = 404 + }; + } + + var salarie = _mapper.Map(salarieInput, salarieFind); + var response = await _repositorySalarie.UpdateAsync(salarie); + if (!response) + { + return new ResponseDataModel + { + StatusCode = 500, + Success = false, + Message = "Erreur lors de la mise à jour du salarié : " + string.Join(", ", result.Errors) + }; + } + return new ResponseDataModel + { + StatusCode = 200, + Success = true, + Data = salarie, + }; + } + + public async Task> Delete(int id) + { + if (id == null) + { + return new ResponseDataModel + { + StatusCode = 400, + Success = false, + Message = "Id manquant" + }; + } + var salarie = await _repositorySalarie.GetByIdAsync(id); + if (salarie == null) + { + return new ResponseDataModel + { + Success = false, + Message = "Salarié introuvable.", + StatusCode = 404 + }; + } + var response = await _repositorySalarie.DeleteAsync(salarie); + if (!response) + { + return new ResponseDataModel + { + StatusCode = 500, + Success = false, + Message = "Erreur durant la suppression du service" + }; + } + return new ResponseDataModel + { + StatusCode = 200, + Success = true, + Data = salarie.Id.ToString(), + }; + } } \ No newline at end of file diff --git a/ldap-cesi/Services/ServiceService.cs b/ldap-cesi/Services/ServiceService.cs index c29cb22..608496f 100644 --- a/ldap-cesi/Services/ServiceService.cs +++ b/ldap-cesi/Services/ServiceService.cs @@ -4,6 +4,7 @@ using ldap_cesi.Entities; using ldap_cesi.Models; using ldap_cesi.Repository.Services; using ldap_cesi.Services.Interfaces; +using ldap_cesi.Validator.Service; namespace ldap_cesi.Services; @@ -43,12 +44,107 @@ public class ServiceService : IServiceService public async Task> CreateService(ServiceCreateDto serviceCreateDto) { + var validation = new ServiceCreateValidator(); + var result = validation.Validate(serviceCreateDto); + if (!result.IsValid) + { + return new ResponseDataModel + { + StatusCode = 400, + Success = false, + Message = "Données du service invalides: " + string.Join(", ", result.Errors) + }; + } var service = _mapper.Map(serviceCreateDto); var response = await _repositoryService.AddAsync(service); return new ResponseDataModel { + StatusCode = 201, Success = true, Data = response.Id.ToString(), }; } + + public async Task> UpdateService(ServiceUpdateDto serviceUpdateDto) + { + var validation = new ServiceUpdateValidator(); + var result = validation.Validate(serviceUpdateDto); + if (!result.IsValid) + { + return new ResponseDataModel + { + StatusCode = 400, + Success = false, + Message = "Données du service invalides: " + string.Join(", ", result.Errors) + }; + } + var serviceFind = await _repositoryService.GetByIdAsync(serviceUpdateDto.Id); + if (serviceFind is null) + { + return new ResponseDataModel + { + Success = false, + Message = "Service introuvable.", + StatusCode = 404 + }; + } + + var service = _mapper.Map(serviceUpdateDto, serviceFind); + var response = await _repositoryService.UpdateAsync(service); + if (!response) + { + return new ResponseDataModel + { + StatusCode = 500, + Success = false, + Message = "Erreur lors de la mise à jour du service : " + string.Join(", ", result.Errors) + }; + } + return new ResponseDataModel + { + StatusCode = 200, + Success = true, + Data = service, + }; + } + + public async Task> DeleteService(int idService) + { + if (idService == null) + { + return new ResponseDataModel + { + StatusCode = 400, + Success = false, + Message = "Id manquant" + }; + } + + var service = await _repositoryService.GetByIdAsync(idService); + if (service == null) + { + return new ResponseDataModel + { + Success = false, + Message = "Service introuvable.", + StatusCode = 404 + }; + } + var response = await _repositoryService.DeleteAsync(service); + if (!response) + { + return new ResponseDataModel + { + StatusCode = 500, + Success = false, + Message = "Erreur durant la suppression du service" + }; + } + return new ResponseDataModel + { + StatusCode = 200, + Success = true, + Data = service.Id.ToString(), + }; + } } \ No newline at end of file diff --git a/ldap-cesi/Services/SiteService.cs b/ldap-cesi/Services/SiteService.cs new file mode 100644 index 0000000..5d5628d --- /dev/null +++ b/ldap-cesi/Services/SiteService.cs @@ -0,0 +1,151 @@ +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; + +namespace ldap_cesi.Services; + +public class SiteService : ISiteService +{ + + private readonly IRepositorySite _repositorySite; + private readonly IMapper _mapper; + + public SiteService(IRepositorySite repositorySite, IMapper mapper) + { + _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> 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 diff --git a/ldap-cesi/Validator/Salarie/SalarieCreateValidator.cs b/ldap-cesi/Validator/Salarie/SalarieCreateValidator.cs new file mode 100644 index 0000000..a53fc1c --- /dev/null +++ b/ldap-cesi/Validator/Salarie/SalarieCreateValidator.cs @@ -0,0 +1,37 @@ +using FluentValidation; +using ldap_cesi.DTOs.Inputs.Salarie; + +namespace ldap_cesi.Validator.Salarie; + +public class SalarieCreateValidator : AbstractValidator +{ + public SalarieCreateValidator() + { + RuleFor(x => x.Nom) + .NotEmpty().WithMessage("Le nom est requis.") + .MaximumLength(50).WithMessage("Le nom ne doit pas dépasser 50 caractères."); + + RuleFor(x => x.Prenom) + .NotEmpty().WithMessage("Le prénom est requis.") + .MaximumLength(50).WithMessage("Le prénom ne doit pas dépasser 50 caractères."); + + RuleFor(x => x.TelephoneFix) + .NotEmpty().WithMessage("Le téléphone fixe est requis.") + .MaximumLength(15).WithMessage("Le téléphone fixe ne doit pas dépasser 15 caractères."); + + RuleFor(x => x.TelephonePortable) + .NotEmpty().WithMessage("Le téléphone portable est requis.") + .MaximumLength(15).WithMessage("Le téléphone portable ne doit pas dépasser 15 caractères."); + + RuleFor(x => x.Email) + .NotEmpty().WithMessage("L'email est requis.") + .EmailAddress().WithMessage("L'email n'est pas valide.") + .MaximumLength(50).WithMessage("L'email ne doit pas dépasser 50 caractères."); + + RuleFor(x => x.IdSite) + .NotEmpty().WithMessage("L'ID du site est requis."); + + RuleFor(x => x.IdService) + .NotEmpty().WithMessage("L'ID du service est requis."); + } +} \ No newline at end of file diff --git a/ldap-cesi/Validator/Salarie/SalarieUpdateValidator.cs b/ldap-cesi/Validator/Salarie/SalarieUpdateValidator.cs new file mode 100644 index 0000000..a755c82 --- /dev/null +++ b/ldap-cesi/Validator/Salarie/SalarieUpdateValidator.cs @@ -0,0 +1,39 @@ +using FluentValidation; +using ldap_cesi.DTOs.Inputs.Service; + +namespace ldap_cesi.Validator.Salarie; + +public class SalarieUpdateValidator : AbstractValidator +{ + public SalarieUpdateValidator() + { + RuleFor(x => x.Id) + .NotEmpty().WithMessage("L'identifiant du salarié est requis."); + RuleFor(x => x.Nom) + .NotEmpty().WithMessage("Le nom est requis.") + .MaximumLength(50).WithMessage("Le nom ne doit pas dépasser 50 caractères."); + + RuleFor(x => x.Prenom) + .NotEmpty().WithMessage("Le prénom est requis.") + .MaximumLength(50).WithMessage("Le prénom ne doit pas dépasser 50 caractères."); + + RuleFor(x => x.TelephoneFixe) + .NotEmpty().WithMessage("Le téléphone fixe est requis.") + .MaximumLength(15).WithMessage("Le téléphone fixe ne doit pas dépasser 15 caractères."); + + RuleFor(x => x.TelephonePortable) + .NotEmpty().WithMessage("Le téléphone portable est requis.") + .MaximumLength(15).WithMessage("Le téléphone portable ne doit pas dépasser 15 caractères."); + + RuleFor(x => x.Email) + .NotEmpty().WithMessage("L'email est requis.") + .EmailAddress().WithMessage("L'email n'est pas valide.") + .MaximumLength(50).WithMessage("L'email ne doit pas dépasser 50 caractères."); + + RuleFor(x => x.IdSite) + .NotEmpty().WithMessage("L'ID du site est requis."); + + RuleFor(x => x.IdService) + .NotEmpty().WithMessage("L'ID du service est requis."); + } +} \ No newline at end of file diff --git a/ldap-cesi/Validator/Service/ServiceCreateValidator.cs b/ldap-cesi/Validator/Service/ServiceCreateValidator.cs new file mode 100644 index 0000000..48f58dd --- /dev/null +++ b/ldap-cesi/Validator/Service/ServiceCreateValidator.cs @@ -0,0 +1,14 @@ +using FluentValidation; +using ldap_cesi.DTOs.Inputs.Service; + +namespace ldap_cesi.Validator.Service; + +public class ServiceCreateValidator : AbstractValidator +{ + public ServiceCreateValidator() + { + RuleFor(x => x.Nom) + .NotEmpty().WithMessage("Le nom est requis.") + .MaximumLength(50).WithMessage("Le nom ne doit pas dépasser 50 caractères."); + } +} \ No newline at end of file diff --git a/ldap-cesi/Validator/Service/ServiceUpdateValidator.cs b/ldap-cesi/Validator/Service/ServiceUpdateValidator.cs new file mode 100644 index 0000000..a2362f5 --- /dev/null +++ b/ldap-cesi/Validator/Service/ServiceUpdateValidator.cs @@ -0,0 +1,18 @@ +using FluentValidation; +using ldap_cesi.DTOs.Inputs.Service; + +namespace ldap_cesi.Validator.Service; + +public class ServiceUpdateValidator : AbstractValidator +{ + public ServiceUpdateValidator() + { + RuleFor(x => x.Nom) + .NotEmpty().WithMessage("Le nom est requis.") + .MaximumLength(50).WithMessage("Le nom ne doit pas dépasser 50 caractères."); + RuleFor(x => x.Id) + .NotEmpty().WithMessage("L'identifiant du service est requis."); + + } + +} \ No newline at end of file diff --git a/ldap-cesi/Validator/Site/SiteCreateValidator.cs b/ldap-cesi/Validator/Site/SiteCreateValidator.cs new file mode 100644 index 0000000..16ea713 --- /dev/null +++ b/ldap-cesi/Validator/Site/SiteCreateValidator.cs @@ -0,0 +1,14 @@ +using FluentValidation; +using ldap_cesi.DTOs.Inputs.Site; + +namespace ldap_cesi.Validator.Site; + +public class SiteCreateValidator : AbstractValidator +{ + public SiteCreateValidator() + { + RuleFor(x => x.Ville) + .NotEmpty().WithMessage("Le nom est requis.") + .MaximumLength(150).WithMessage("Le nom de la ville ne doit pas dépasser 150 caractères."); + } +} \ No newline at end of file diff --git a/ldap-cesi/Validator/Site/SiteUpdateValidator.cs b/ldap-cesi/Validator/Site/SiteUpdateValidator.cs new file mode 100644 index 0000000..1efd5a5 --- /dev/null +++ b/ldap-cesi/Validator/Site/SiteUpdateValidator.cs @@ -0,0 +1,16 @@ +using FluentValidation; +using ldap_cesi.DTOs.Inputs.Site; + +namespace ldap_cesi.Validator.Site; + +public class SiteUpdateValidator : AbstractValidator +{ + public SiteUpdateValidator() + { + RuleFor(x => x.Ville) + .NotEmpty().WithMessage("Le nom est requis.") + .MaximumLength(150).WithMessage("Le nom de la ville ne doit pas dépasser 150 caractères."); + RuleFor(x => x.Id) + .NotEmpty().WithMessage("L'identifiant du site est requis."); + } +} \ No newline at end of file diff --git a/ldap-cesi/ldap-cesi.csproj b/ldap-cesi/ldap-cesi.csproj index f06e052..5070353 100644 --- a/ldap-cesi/ldap-cesi.csproj +++ b/ldap-cesi/ldap-cesi.csproj @@ -31,7 +31,6 @@ - From fe91908098a2811c9f07f058f1b951a085618889 Mon Sep 17 00:00:00 2001 From: yoannlgd Date: Mon, 3 Mar 2025 18:31:37 +0100 Subject: [PATCH 09/17] =?UTF-8?q?-=20Ajout=20d'un=20service=20base=20pour?= =?UTF-8?q?=20plus=20de=20scalabilit=C3=A9=20et=20de=20duplication=20de=20?= =?UTF-8?q?code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ldap-cesi/Configurations/Conf.cs | 2 +- ldap-cesi/Controllers/SalarieController.cs | 16 +- ldap-cesi/Controllers/ServicesController.cs | 8 +- ldap-cesi/DTOs/Generic/SalarieDto.cs | 19 ++ ldap-cesi/Services/Interfaces/IRoleService.cs | 13 +- .../Services/Interfaces/ISalarieService.cs | 9 +- .../Services/Interfaces/IServiceService.cs | 15 +- ldap-cesi/Services/JwtService.cs | 10 +- ldap-cesi/Services/RoleService.cs | 13 +- ldap-cesi/Services/SalarieService.cs | 229 ++++++++-------- ldap-cesi/Services/ServiceService.cs | 252 +++++++++--------- ldap-cesi/ldap-cesi.csproj | 1 + 12 files changed, 309 insertions(+), 278 deletions(-) create mode 100644 ldap-cesi/DTOs/Generic/SalarieDto.cs diff --git a/ldap-cesi/Configurations/Conf.cs b/ldap-cesi/Configurations/Conf.cs index 32e91c3..0798afe 100644 --- a/ldap-cesi/Configurations/Conf.cs +++ b/ldap-cesi/Configurations/Conf.cs @@ -42,7 +42,7 @@ public static class Conf public static void AddServices(this WebApplicationBuilder builder) { builder.Services.AddScoped(); - // builder.Services.AddScoped(); + builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); diff --git a/ldap-cesi/Controllers/SalarieController.cs b/ldap-cesi/Controllers/SalarieController.cs index 63d9120..3928aa0 100644 --- a/ldap-cesi/Controllers/SalarieController.cs +++ b/ldap-cesi/Controllers/SalarieController.cs @@ -16,7 +16,7 @@ public class SalarieController : ControllerBase _salarieService = salarieService; } - /// + /// /// Endpoint qui retourne tous les salariés. /// /// Une liste de salariés. @@ -25,6 +25,17 @@ 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() + { + var result = await _salarieService.GetAllWithoutIService(); + return result.Success ? Ok(result.Data) : BadRequest(result.Message); } /// @@ -33,7 +44,7 @@ public class SalarieController : ControllerBase /// L'ID du salarié. /// Le salarié correspondant à l'ID. [HttpGet("{id}")] - public async Task GetSalarieById(int id) + public async Task GetById(int id) { var result = await _salarieService.GetById(id); return result.Success ? Ok(result.Data) : BadRequest(result.Message); @@ -45,6 +56,7 @@ public class SalarieController : ControllerBase /// L'ID du salarié. /// Le salarié correspondant à l'ID. [HttpGet("/complet/{id}")] + [Authorize(Roles = "admin")] public async Task GetSalarieCompletById(int id) { var result = await _salarieService.GetCompletById(id); diff --git a/ldap-cesi/Controllers/ServicesController.cs b/ldap-cesi/Controllers/ServicesController.cs index d9c3c84..8f2ec66 100644 --- a/ldap-cesi/Controllers/ServicesController.cs +++ b/ldap-cesi/Controllers/ServicesController.cs @@ -21,7 +21,6 @@ public class ServicesController : ControllerBase /// /// Retourne tous les services. [HttpGet] - [Authorize(Roles = "admin")] public async Task GetServices() { var result = await _serviceService.GetAll(); @@ -34,7 +33,6 @@ public class ServicesController : ControllerBase /// L'ID du service. /// Le service correspondant à l'ID. [HttpGet("{id}")] - [Authorize(Roles = "admin")] public async Task GetServiceById(int id) { var result = await _serviceService.GetById(id); @@ -50,7 +48,7 @@ public class ServicesController : ControllerBase [Authorize(Roles = "admin")] public async Task CreateService([FromBody] ServiceCreateDto serviceInputDto) { - var result = await _serviceService.CreateService(serviceInputDto); + var result = await _serviceService.Create(serviceInputDto); return result.Success ? Ok(result.Data) : BadRequest(result.Message); } @@ -63,7 +61,7 @@ public class ServicesController : ControllerBase [Authorize(Roles = "admin")] public async Task UpdateService([FromBody] ServiceUpdateDto serviceUpdateDto) { - var result = await _serviceService.UpdateService(serviceUpdateDto); + var result = await _serviceService.Update(serviceUpdateDto); return result.Success ? Ok(result.Data) : BadRequest(result.Message); } @@ -76,7 +74,7 @@ public class ServicesController : ControllerBase [Authorize(Roles = "admin")] public async Task DeleteService(int id) { - var result = await _serviceService.DeleteService(id); + var result = await _serviceService.Delete(id); return result.Success ? Ok(result.Message) : BadRequest(result.Message); } } \ No newline at end of file diff --git a/ldap-cesi/DTOs/Generic/SalarieDto.cs b/ldap-cesi/DTOs/Generic/SalarieDto.cs new file mode 100644 index 0000000..542bd7c --- /dev/null +++ b/ldap-cesi/DTOs/Generic/SalarieDto.cs @@ -0,0 +1,19 @@ +namespace ldap_cesi.DTOs; + +public class SalarieDto +{ + 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!; + + public ServiceDto Service { get; set; } + public SiteDto Site { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/IRoleService.cs b/ldap-cesi/Services/Interfaces/IRoleService.cs index b558e3b..e4b46ab 100644 --- a/ldap-cesi/Services/Interfaces/IRoleService.cs +++ b/ldap-cesi/Services/Interfaces/IRoleService.cs @@ -1,6 +1,13 @@ -namespace ldap_cesi.Services.Interfaces; +using ldap_cesi.Repository.Services; +using ldap_cesi.Services.Interfaces; +using ldap_cesi.Entities; +using ldap_cesi.DTOs; +using ldap_cesi.DTOs.Inputs.Role; +using AutoMapper; -public interface IRoleService +namespace ldap_cesi.Services.Interfaces { - + public interface IRoleService : IServiceBase + { + } } \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/ISalarieService.cs b/ldap-cesi/Services/Interfaces/ISalarieService.cs index 5318fa7..893a742 100644 --- a/ldap-cesi/Services/Interfaces/ISalarieService.cs +++ b/ldap-cesi/Services/Interfaces/ISalarieService.cs @@ -1,3 +1,4 @@ +using ldap_cesi.DTOs; using ldap_cesi.DTOs.Inputs.Salarie; using ldap_cesi.DTOs.Inputs.Service; using ldap_cesi.DTOs.Outputs.Salarie; @@ -6,14 +7,10 @@ using ldap_cesi.Models; namespace ldap_cesi.Services.Interfaces; -public interface ISalarieService +public interface ISalarieService : IServiceBase { - Task>> GetAll(); - Task> GetById(int id); + Task>> GetAllWithoutIService(); Task>> GetSalariesBySite(int siteId); Task>> GetSalariesByService(int serviceId); - Task> Create(SalarieCreateDto salarieInput); - Task> Update(SalarieUpdateDto salarieInput); - Task> Delete(int id); Task> GetCompletById(int id); } \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/IServiceService.cs b/ldap-cesi/Services/Interfaces/IServiceService.cs index 4247928..4cd3a7c 100644 --- a/ldap-cesi/Services/Interfaces/IServiceService.cs +++ b/ldap-cesi/Services/Interfaces/IServiceService.cs @@ -1,14 +1,11 @@ using ldap_cesi.DTOs.Inputs.Service; +using ldap_cesi.DTOs; using ldap_cesi.Entities; using ldap_cesi.Models; -namespace ldap_cesi.Services.Interfaces; - -public interface IServiceService +namespace ldap_cesi.Services.Interfaces { - Task>> GetAll(); - Task> GetById(int id); - Task> CreateService(ServiceCreateDto serviceCreateDto); - Task> UpdateService(ServiceUpdateDto serviceUpdateDto); - Task> DeleteService(int id); -} \ No newline at end of file + public interface IServiceService : IServiceBase + { + } +} diff --git a/ldap-cesi/Services/JwtService.cs b/ldap-cesi/Services/JwtService.cs index 085d41e..8ef0ec2 100644 --- a/ldap-cesi/Services/JwtService.cs +++ b/ldap-cesi/Services/JwtService.cs @@ -60,7 +60,7 @@ public class JwtService : IJwtService } catch (Exception ex) { - _logger.LogError(ex, "An error occurred while generating the JWT token."); + _logger.LogError(ex, "Une erreur s'est produitel lors de la génération du token."); throw; } } @@ -74,7 +74,7 @@ public class JwtService : IJwtService } catch (Exception ex) { - _logger.LogError(ex, "An error occurred while retrieving the public key."); + _logger.LogError(ex, "Une erreur s'est produite pendant la récupération de la clé."); throw; } } @@ -100,14 +100,14 @@ public class JwtService : IJwtService var nameIdClaim = principal.FindFirst(ClaimTypes.NameIdentifier); if (nameIdClaim == null || !int.TryParse(nameIdClaim.Value, out var tokenUserId) || tokenUserId != userId) { - _logger.LogWarning("Token validation failed: Invalid user ID."); + _logger.LogWarning("Erreur de validation : Id utilisateur invalide."); return false; } var utilisateur = await _context.Utilisateurs.FindAsync(userId); if (utilisateur == null) { - _logger.LogWarning("Token validation failed: User not found."); + _logger.LogWarning("Erreur de validation : Utilisateur non trouvé."); return false; } @@ -119,7 +119,7 @@ public class JwtService : IJwtService } catch (Exception ex) { - _logger.LogError(ex, "An error occurred while validating the JWT token."); + _logger.LogError(ex, "Une erreur s'est produite lors pendant la validation du token JWT."); return false; } } diff --git a/ldap-cesi/Services/RoleService.cs b/ldap-cesi/Services/RoleService.cs index b388bae..43eba92 100644 --- a/ldap-cesi/Services/RoleService.cs +++ b/ldap-cesi/Services/RoleService.cs @@ -1,15 +1,16 @@ using ldap_cesi.Repository.Services; using ldap_cesi.Services.Interfaces; +using ldap_cesi.Entities; +using ldap_cesi.DTOs; +using ldap_cesi.DTOs.Inputs.Role; +using AutoMapper; namespace ldap_cesi.Services; -public class RoleService : IRoleService +public class RoleService : ServiceBase,IRoleService { - private IRepositoryRole _repositoryRole; - - public RoleService(IRepositoryRole repositoryRole) + public RoleService(IRepositoryRole repositoryRole, IMapper mapper, ILogger logger) + : base(repositoryRole, mapper, logger) { - _repositoryRole = repositoryRole; } - } \ No newline at end of file diff --git a/ldap-cesi/Services/SalarieService.cs b/ldap-cesi/Services/SalarieService.cs index 69c8108..1d8a393 100644 --- a/ldap-cesi/Services/SalarieService.cs +++ b/ldap-cesi/Services/SalarieService.cs @@ -1,4 +1,5 @@ using AutoMapper; +using ldap_cesi.DTOs; using ldap_cesi.DTOs.Inputs.Salarie; using ldap_cesi.DTOs.Inputs.Service; using ldap_cesi.DTOs.Outputs.Salarie; @@ -10,14 +11,14 @@ using ldap_cesi.Validator.Salarie; namespace ldap_cesi.Services; -public class SalarieService : ISalarieService +public class SalarieService : ServiceBase, ISalarieService { private IRepositorySalarie _repositorySalarie; private readonly IRepositorySite _repositorySite; private readonly IRepositoryService _repositoryService; private readonly IMapper _mapper; - public SalarieService(IRepositorySalarie repositorySalarie, IMapper mapper, IRepositorySite repositorySite, IRepositoryService repositoryService) + public SalarieService(IRepositorySalarie repositorySalarie, IMapper mapper, IRepositorySite repositorySite, IRepositoryService repositoryService, ILogger logger) : base(repositorySalarie, mapper, logger) { _repositorySalarie = repositorySalarie; _repositorySite = repositorySite; @@ -25,7 +26,7 @@ public class SalarieService : ISalarieService _mapper = mapper; } - public async Task>> GetAll() + public async Task>> GetAllWithoutIService() { var salaries = await _repositorySalarie.GetAllAsync(); return new ResponseDataModel> @@ -36,16 +37,16 @@ public class SalarieService : ISalarieService }; } - public async Task> GetById(int id) - { - var salarie = await _repositorySalarie.GetSalarieWithRelationsAsync(id); - return new ResponseDataModel - { - Success = true, - Data = salarie, - 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) { @@ -131,109 +132,109 @@ public class SalarieService : ISalarieService }; } - public async Task> Create(SalarieCreateDto salarieInput) - { - var validation = new SalarieCreateValidator(); - var result = validation.Validate(salarieInput); - if (!result.IsValid) - { - return new ResponseDataModel - { - StatusCode = 400, - Success = false, - Message = "Données salariées invalides: " + string.Join(", ", result.Errors) - }; - } - var service = _mapper.Map(salarieInput); - var response = await _repositorySalarie.AddAsync(service); - return new ResponseDataModel - { - StatusCode = 201, - Success = true, - Data = response.Id.ToString(), - }; - } + // public async Task> Create(SalarieCreateDto salarieInput) + // { + // var validation = new SalarieCreateValidator(); + // var result = validation.Validate(salarieInput); + // if (!result.IsValid) + // { + // return new ResponseDataModel + // { + // StatusCode = 400, + // Success = false, + // Message = "Données salariées invalides: " + string.Join(", ", result.Errors) + // }; + // } + // var service = _mapper.Map(salarieInput); + // var response = await _repositorySalarie.AddAsync(service); + // return new ResponseDataModel + // { + // StatusCode = 201, + // Success = true, + // Data = response.Id.ToString(), + // }; + // } - public async Task> Update(SalarieUpdateDto salarieInput) - { - var validation = new SalarieUpdateValidator(); - var result = validation.Validate(salarieInput); - if (!result.IsValid) - { - return new ResponseDataModel - { - StatusCode = 400, - Success = false, - Message = "Données salariées invalides: " + string.Join(", ", result.Errors) - }; - } + // public async Task> Update(SalarieUpdateDto salarieInput) + // { + // var validation = new SalarieUpdateValidator(); + // var result = validation.Validate(salarieInput); + // if (!result.IsValid) + // { + // return new ResponseDataModel + // { + // StatusCode = 400, + // Success = false, + // Message = "Données salariées invalides: " + string.Join(", ", result.Errors) + // }; + // } - var salarieFind = await _repositorySalarie.GetByIdAsync(salarieInput.Id); - if (salarieFind == null) - { - return new ResponseDataModel - { - Success = false, - Message = "Salarié introuvable.", - StatusCode = 404 - }; - } + // var salarieFind = await _repositorySalarie.GetByIdAsync(salarieInput.Id); + // if (salarieFind == null) + // { + // return new ResponseDataModel + // { + // Success = false, + // Message = "Salarié introuvable.", + // StatusCode = 404 + // }; + // } - var salarie = _mapper.Map(salarieInput, salarieFind); - var response = await _repositorySalarie.UpdateAsync(salarie); - if (!response) - { - return new ResponseDataModel - { - StatusCode = 500, - Success = false, - Message = "Erreur lors de la mise à jour du salarié : " + string.Join(", ", result.Errors) - }; - } - return new ResponseDataModel - { - StatusCode = 200, - Success = true, - Data = salarie, - }; - } + // var salarie = _mapper.Map(salarieInput, salarieFind); + // var response = await _repositorySalarie.UpdateAsync(salarie); + // if (!response) + // { + // return new ResponseDataModel + // { + // StatusCode = 500, + // Success = false, + // Message = "Erreur lors de la mise à jour du salarié : " + string.Join(", ", result.Errors) + // }; + // } + // return new ResponseDataModel + // { + // StatusCode = 200, + // Success = true, + // Data = salarie, + // }; + // } - public async Task> Delete(int id) - { - if (id == null) - { - return new ResponseDataModel - { - StatusCode = 400, - Success = false, - Message = "Id manquant" - }; - } - var salarie = await _repositorySalarie.GetByIdAsync(id); - if (salarie == null) - { - return new ResponseDataModel - { - Success = false, - Message = "Salarié introuvable.", - StatusCode = 404 - }; - } - var response = await _repositorySalarie.DeleteAsync(salarie); - if (!response) - { - return new ResponseDataModel - { - StatusCode = 500, - Success = false, - Message = "Erreur durant la suppression du service" - }; - } - return new ResponseDataModel - { - StatusCode = 200, - Success = true, - Data = salarie.Id.ToString(), - }; - } + // public async Task> Delete(int id) + // { + // if (id == null) + // { + // return new ResponseDataModel + // { + // StatusCode = 400, + // Success = false, + // Message = "Id manquant" + // }; + // } + // var salarie = await _repositorySalarie.GetByIdAsync(id); + // if (salarie == null) + // { + // return new ResponseDataModel + // { + // Success = false, + // Message = "Salarié introuvable.", + // StatusCode = 404 + // }; + // } + // var response = await _repositorySalarie.DeleteAsync(salarie); + // if (!response) + // { + // return new ResponseDataModel + // { + // StatusCode = 500, + // Success = false, + // Message = "Erreur durant la suppression du service" + // }; + // } + // return new ResponseDataModel + // { + // StatusCode = 200, + // Success = true, + // Data = salarie.Id.ToString(), + // }; + // } } \ No newline at end of file diff --git a/ldap-cesi/Services/ServiceService.cs b/ldap-cesi/Services/ServiceService.cs index 608496f..7cb9b6e 100644 --- a/ldap-cesi/Services/ServiceService.cs +++ b/ldap-cesi/Services/ServiceService.cs @@ -5,146 +5,144 @@ using ldap_cesi.Models; using ldap_cesi.Repository.Services; using ldap_cesi.Services.Interfaces; using ldap_cesi.Validator.Service; +using ldap_cesi.DTOs; +using ldap_cesi.DTOs.Inputs.Service; namespace ldap_cesi.Services; -public class ServiceService : IServiceService +public class ServiceService : ServiceBase, IServiceService { - private readonly IRepositoryService _repositoryService; - private readonly IMapper _mapper; - public ServiceService(IRepositoryService repositoryService, IMapper mapper) + public ServiceService(IRepositoryService repositoryService, IMapper mapper, ILogger logger) : base(repositoryService, mapper, logger) { - _repositoryService = repositoryService; - _mapper = mapper; } - public async Task>> GetAll() - { - var services = await _repositoryService.GetAllAsync(); - return new ResponseDataModel> - { - Success = true, - Data = services, - StatusCode = 200, - }; - } + // public async Task>> GetAll() + // { + // var services = await _repositoryService.GetAllAsync(); + // return new ResponseDataModel> + // { + // Success = true, + // Data = services, + // StatusCode = 200, + // }; + // } - public async Task> GetById(int id) - { - var service = await _repositoryService.GetByIdAsync(id); - return new ResponseDataModel - { - Success = true, - Data = service, - StatusCode = 200, - }; - } + // public async Task> GetById(int id) + // { + // var service = await _repositoryService.GetByIdAsync(id); + // return new ResponseDataModel + // { + // Success = true, + // Data = service, + // StatusCode = 200, + // }; + // } - public async Task> CreateService(ServiceCreateDto serviceCreateDto) - { - var validation = new ServiceCreateValidator(); - var result = validation.Validate(serviceCreateDto); - if (!result.IsValid) - { - return new ResponseDataModel - { - StatusCode = 400, - Success = false, - Message = "Données du service invalides: " + string.Join(", ", result.Errors) - }; - } - var service = _mapper.Map(serviceCreateDto); - var response = await _repositoryService.AddAsync(service); - return new ResponseDataModel - { - StatusCode = 201, - Success = true, - Data = response.Id.ToString(), - }; - } + // public async Task> CreateService(ServiceCreateDto serviceCreateDto) + // { + // var validation = new ServiceCreateValidator(); + // var result = validation.Validate(serviceCreateDto); + // if (!result.IsValid) + // { + // return new ResponseDataModel + // { + // StatusCode = 400, + // Success = false, + // Message = "Données du service invalides: " + string.Join(", ", result.Errors) + // }; + // } + // var service = _mapper.Map(serviceCreateDto); + // var response = await _repositoryService.AddAsync(service); + // return new ResponseDataModel + // { + // StatusCode = 201, + // Success = true, + // Data = response.Id.ToString(), + // }; + // } - public async Task> UpdateService(ServiceUpdateDto serviceUpdateDto) - { - var validation = new ServiceUpdateValidator(); - var result = validation.Validate(serviceUpdateDto); - if (!result.IsValid) - { - return new ResponseDataModel - { - StatusCode = 400, - Success = false, - Message = "Données du service invalides: " + string.Join(", ", result.Errors) - }; - } - var serviceFind = await _repositoryService.GetByIdAsync(serviceUpdateDto.Id); - if (serviceFind is null) - { - return new ResponseDataModel - { - Success = false, - Message = "Service introuvable.", - StatusCode = 404 - }; - } + // public async Task> UpdateService(ServiceUpdateDto serviceUpdateDto) + // { + // var validation = new ServiceUpdateValidator(); + // var result = validation.Validate(serviceUpdateDto); + // if (!result.IsValid) + // { + // return new ResponseDataModel + // { + // StatusCode = 400, + // Success = false, + // Message = "Données du service invalides: " + string.Join(", ", result.Errors) + // }; + // } + // var serviceFind = await _repositoryService.GetByIdAsync(serviceUpdateDto.Id); + // if (serviceFind is null) + // { + // return new ResponseDataModel + // { + // Success = false, + // Message = "Service introuvable.", + // StatusCode = 404 + // }; + // } - var service = _mapper.Map(serviceUpdateDto, serviceFind); - var response = await _repositoryService.UpdateAsync(service); - if (!response) - { - return new ResponseDataModel - { - StatusCode = 500, - Success = false, - Message = "Erreur lors de la mise à jour du service : " + string.Join(", ", result.Errors) - }; - } - return new ResponseDataModel - { - StatusCode = 200, - Success = true, - Data = service, - }; - } + // var service = _mapper.Map(serviceUpdateDto, serviceFind); + // var response = await _repositoryService.UpdateAsync(service); + // if (!response) + // { + // return new ResponseDataModel + // { + // StatusCode = 500, + // Success = false, + // Message = "Erreur lors de la mise à jour du service : " + string.Join(", ", result.Errors) + // }; + // } + // return new ResponseDataModel + // { + // StatusCode = 200, + // Success = true, + // Data = service, + // }; + // } - public async Task> DeleteService(int idService) - { - if (idService == null) - { - return new ResponseDataModel - { - StatusCode = 400, - Success = false, - Message = "Id manquant" - }; - } + // public async Task> DeleteService(int idService) + // { + // if (idService == null) + // { + // return new ResponseDataModel + // { + // StatusCode = 400, + // Success = false, + // Message = "Id manquant" + // }; + // } - var service = await _repositoryService.GetByIdAsync(idService); - if (service == null) - { - return new ResponseDataModel - { - Success = false, - Message = "Service introuvable.", - StatusCode = 404 - }; - } - var response = await _repositoryService.DeleteAsync(service); - if (!response) - { - return new ResponseDataModel - { - StatusCode = 500, - Success = false, - Message = "Erreur durant la suppression du service" - }; - } - return new ResponseDataModel - { - StatusCode = 200, - Success = true, - Data = service.Id.ToString(), - }; - } + // var service = await _repositoryService.GetByIdAsync(idService); + // if (service == null) + // { + // return new ResponseDataModel + // { + // Success = false, + // Message = "Service introuvable.", + // StatusCode = 404 + // }; + // } + // var response = await _repositoryService.DeleteAsync(service); + // if (!response) + // { + // return new ResponseDataModel + // { + // StatusCode = 500, + // Success = false, + // Message = "Erreur durant la suppression du service" + // }; + // } + // return new ResponseDataModel + // { + // StatusCode = 200, + // Success = true, + // Data = service.Id.ToString(), + // }; + // } } \ No newline at end of file diff --git a/ldap-cesi/ldap-cesi.csproj b/ldap-cesi/ldap-cesi.csproj index 5070353..9ef0878 100644 --- a/ldap-cesi/ldap-cesi.csproj +++ b/ldap-cesi/ldap-cesi.csproj @@ -5,6 +5,7 @@ enable enable ldap_cesi + CS0472,CS1591,CS1587 true From f0928aae3bd82dd6c8845fa9a0d0a4e30678c7c1 Mon Sep 17 00:00:00 2001 From: yoannlgd Date: Tue, 4 Mar 2025 09:11:23 +0100 Subject: [PATCH 10/17] =?UTF-8?q?-=20Push=20des=20classes=20qui=20n'ont=20?= =?UTF-8?q?pas=20=C3=A9t=C3=A9=20jet=C3=A9es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ldap-cesi/Controllers/RoleController.cs | 84 +++++++++ ldap-cesi/DTOs/Generic/RoleDto.cs | 8 + ldap-cesi/DTOs/Inputs/Role/RoleCreateDto.cs | 6 + ldap-cesi/DTOs/Inputs/Role/RoleUpdateDto.cs | 7 + ldap-cesi/Services/Interfaces/IServiceBase.cs | 16 ++ ldap-cesi/Services/ServiceBase.cs | 178 ++++++++++++++++++ 6 files changed, 299 insertions(+) create mode 100644 ldap-cesi/Controllers/RoleController.cs create mode 100644 ldap-cesi/DTOs/Generic/RoleDto.cs create mode 100644 ldap-cesi/DTOs/Inputs/Role/RoleCreateDto.cs create mode 100644 ldap-cesi/DTOs/Inputs/Role/RoleUpdateDto.cs create mode 100644 ldap-cesi/Services/Interfaces/IServiceBase.cs create mode 100644 ldap-cesi/Services/ServiceBase.cs diff --git a/ldap-cesi/Controllers/RoleController.cs b/ldap-cesi/Controllers/RoleController.cs new file mode 100644 index 0000000..28d6554 --- /dev/null +++ b/ldap-cesi/Controllers/RoleController.cs @@ -0,0 +1,84 @@ +using Microsoft.AspNetCore.Mvc; +using ldap_cesi.DTOs.Inputs.Role; +using ldap_cesi.Services.Interfaces; +using System.Threading.Tasks; + +namespace ldap_cesi.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class RoleController : ControllerBase + { + private readonly IRoleService _roleService; + + public RoleController(IRoleService roleService) + { + _roleService = roleService; + } + + // GET: api/Role + [HttpGet] + public async Task GetAllRoles() + { + var result = await _roleService.GetAll(); + if (result.Success) + { + return Ok(result.Data); + } + return StatusCode(result.StatusCode, result.Message); + } + + // GET: api/Role/{id} + [HttpGet("{id}")] + public async Task GetRoleById(int id) + { + var result = await _roleService.GetById(id); + if (result.Success) + { + return Ok(result.Data); + } + return StatusCode(result.StatusCode, result.Message); + } + + // POST: api/Role + [HttpPost] + public async Task CreateRole([FromBody] RoleCreateDto roleDto) + { + var result = await _roleService.Create(roleDto); + if (result.Success) + { + return CreatedAtAction(nameof(GetRoleById), new { id = result.Data }, result.Data); + } + return StatusCode(result.StatusCode, result.Message); + } + + // PUT: api/Role/{id} + [HttpPut("{id}")] + public async Task UpdateRole(int id, [FromBody] RoleUpdateDto roleDto) + { + if (id != roleDto.Id) + { + return BadRequest("Role ID mismatch"); + } + + var result = await _roleService.Update(roleDto); + if (result.Success) + { + return NoContent(); + } + return StatusCode(result.StatusCode, result.Message); + } + + // DELETE: api/Role/{id} + [HttpDelete("{id}")] + public async Task DeleteRole(int id) + { + var result = await _roleService.Delete(id); + if (result.Success) + { + return NoContent(); + } + return StatusCode(result.StatusCode, result.Message); + } + } +} diff --git a/ldap-cesi/DTOs/Generic/RoleDto.cs b/ldap-cesi/DTOs/Generic/RoleDto.cs new file mode 100644 index 0000000..3465bd6 --- /dev/null +++ b/ldap-cesi/DTOs/Generic/RoleDto.cs @@ -0,0 +1,8 @@ +namespace ldap_cesi.DTOs; + +public class RoleDto +{ + public int Id { get; set; } + + public string Nom { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/DTOs/Inputs/Role/RoleCreateDto.cs b/ldap-cesi/DTOs/Inputs/Role/RoleCreateDto.cs new file mode 100644 index 0000000..59652a2 --- /dev/null +++ b/ldap-cesi/DTOs/Inputs/Role/RoleCreateDto.cs @@ -0,0 +1,6 @@ +namespace ldap_cesi.DTOs.Inputs.Role; + +public class RoleCreateDto +{ + public string Nom { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/DTOs/Inputs/Role/RoleUpdateDto.cs b/ldap-cesi/DTOs/Inputs/Role/RoleUpdateDto.cs new file mode 100644 index 0000000..c7b5b00 --- /dev/null +++ b/ldap-cesi/DTOs/Inputs/Role/RoleUpdateDto.cs @@ -0,0 +1,7 @@ +namespace ldap_cesi.DTOs.Inputs.Role; + +public class RoleUpdateDto +{ + public int Id { get; set; } + public string Nom { get; set; } +} \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/IServiceBase.cs b/ldap-cesi/Services/Interfaces/IServiceBase.cs new file mode 100644 index 0000000..f1f4df4 --- /dev/null +++ b/ldap-cesi/Services/Interfaces/IServiceBase.cs @@ -0,0 +1,16 @@ +using ldap_cesi.Models; + +namespace ldap_cesi.Services.Interfaces; + +public interface IServiceBase + where T : class + where TDto : class + where TCreateDto : class + where TUpdateDto : class +{ + Task>> GetAll(); + Task> GetById(int id); + Task> Create(TCreateDto dto); + Task> Update(TUpdateDto dto); + Task> Delete(int id); +} \ No newline at end of file diff --git a/ldap-cesi/Services/ServiceBase.cs b/ldap-cesi/Services/ServiceBase.cs new file mode 100644 index 0000000..e560fd3 --- /dev/null +++ b/ldap-cesi/Services/ServiceBase.cs @@ -0,0 +1,178 @@ +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.Threading.Tasks; + +namespace ldap_cesi.Services; + +public class ServiceBase : IServiceBase + where T : class + where TDto : class + where TCreateDto : class + where TUpdateDto : class +{ + protected readonly IRepositoryBase _repository; + protected readonly IMapper _mapper; + protected readonly ILogger> _logger; + + public ServiceBase(IRepositoryBase repository, IMapper mapper, ILogger> logger) + { + _repository = repository; + _mapper = mapper; + _logger = logger; + } + + public virtual async Task>> GetAll() + { + try + { + var entities = await _repository.GetAllAsync(); + return new ResponseDataModel> + { + Success = true, + Data = entities, + StatusCode = 200, + Message = "Liste des entités récupérée avec succès." + }; + } + catch (Exception ex) + { + _logger.LogError(ex, "Une erreur s'est produite lors de la récupération des entités."); + return new ResponseDataModel> + { + Success = false, + Message = "Une erreur s'est produite lors de la récupération des entités.", + StatusCode = 500 + }; + } + } + + public virtual async Task> GetById(int id) + { + try + { + var entity = await _repository.GetByIdAsync(id); + if (entity == null) + { + return new ResponseDataModel + { + Success = false, + Message = $"Aucune entité trouvée avec l'identifiant {id}.", + StatusCode = 404 + }; + } + + return new ResponseDataModel + { + Success = true, + Data = entity, + StatusCode = 200, + Message = "Entité récupérée avec succès." + }; + } + catch (Exception ex) + { + _logger.LogError(ex, $"Une erreur s'est produite lors de la récupération de l'entité avec l'identifiant {id}."); + return new ResponseDataModel + { + Success = false, + Message = "Une erreur s'est produite lors de la récupération de l'entité.", + StatusCode = 500 + }; + } + } + + public virtual async Task> Create(TCreateDto dto) + { + try + { + var entity = _mapper.Map(dto); + var createdEntity = await _repository.AddAsync(entity); + return new ResponseDataModel + { + Success = createdEntity != null, + Data = createdEntity, + StatusCode = createdEntity != null ? 201 : 500, + Message = createdEntity != null ? "Entité créée avec succès." : "Échec de la création de l'entité." + }; + } + catch (Exception ex) + { + _logger.LogError(ex, "Une erreur s'est produite lors de la création de l'entité."); + return new ResponseDataModel + { + Success = false, + Message = "Une erreur s'est produite lors de la création de l'entité.", + StatusCode = 500 + }; + } + } + + public virtual async Task> Update(TUpdateDto dto) + { + try + { + var entity = _mapper.Map(dto); + bool isUpdated = await _repository.UpdateAsync(entity); + return new ResponseDataModel + { + Success = isUpdated, + Data = isUpdated ? entity : default, + StatusCode = isUpdated ? 200 : 500, + Message = isUpdated ? "Entité mise à jour avec succès." : "Échec de la mise à jour de l'entité." + }; + } + catch (Exception ex) + { + _logger.LogError(ex, "Une erreur s'est produite lors de la mise à jour de l'entité."); + return new ResponseDataModel + { + Success = false, + Message = "Une erreur s'est produite lors de la mise à jour de l'entité.", + StatusCode = 500 + }; + } + } + + public virtual async Task> Delete(int id) + { + try + { + var entity = await _repository.GetByIdAsync(id); + if (entity == null) + { + return new ResponseDataModel + { + Success = false, + Message = $"Aucune entité trouvée avec l'identifiant {id}.", + StatusCode = 404 + }; + } + + var isDeleted = await _repository.DeleteAsync(entity); + return new ResponseDataModel + { + Success = isDeleted, + Data = isDeleted ? id.ToString() : null, + StatusCode = isDeleted ? 200 : 500, + Message = isDeleted ? "Entité supprimée avec succès." : "Échec de la suppression de l'entité." + }; + } + catch (Exception ex) + { + _logger.LogError(ex, $"Une erreur s'est produite lors de la suppression de l'entité avec l'identifiant {id}."); + return new ResponseDataModel + { + Success = false, + Message = "Une erreur s'est produite lors de la suppression de l'entité.", + StatusCode = 500 + }; + } + } +} \ No newline at end of file From 3041e85addf6852a4cae28edfdce40fbf0eff9a8 Mon Sep 17 00:00:00 2001 From: BuzzLeclair Date: Wed, 5 Mar 2025 14:07:23 +0100 Subject: [PATCH 11/17] =?UTF-8?q?-=20Ajout=20des=20m=C3=A9thodes=20dans=20?= =?UTF-8?q?le=20I/RepositoryBase.cs=20et=20dans=20le=20ServiceBase.cs=20:?= =?UTF-8?q?=20ces=20m=C3=A9thodes=20permettent=20de=20retourner=20les=20re?= =?UTF-8?q?lations=20pr=C3=A9cis=C3=A9es=20en=20argumant=20des=20fonctions?= =?UTF-8?q?=20GetAllWithRelations=20et=20GetByIdWithRelations.=20-=20Ajout?= =?UTF-8?q?=20d'une=20v=C3=A9rification=20des=20entr=C3=A9es=20dans=20les?= =?UTF-8?q?=20m=C3=A9thodes=20g=C3=A9n=C3=A9riques.=20On=20passe=20par=20d?= =?UTF-8?q?es=20inputDto=20qui?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ldap-cesi/Configurations/Conf.cs | 4 + ldap-cesi/Controllers/RoleController.cs | 72 ++++++++------- ldap-cesi/Controllers/SalarieController.cs | 12 ++- ldap-cesi/DTOs/Inputs/Role/RoleCreateDto.cs | 1 + ldap-cesi/Mapper/AutoMapperProfile.cs | 10 ++- .../Interfaces/IRepositoryBase.cs | 2 + ldap-cesi/Repositories/RepositoryBase.cs | 26 +++++- ldap-cesi/Services/Interfaces/IRoleService.cs | 3 - .../Services/Interfaces/ISalarieService.cs | 2 +- ldap-cesi/Services/Interfaces/IServiceBase.cs | 3 + ldap-cesi/Services/RoleService.cs | 5 +- ldap-cesi/Services/SalarieService.cs | 10 ++- ldap-cesi/Services/ServiceBase.cs | 90 ++++++++++++++++++- ldap-cesi/Services/ServiceService.cs | 3 +- ldap-cesi/Services/UtilisateurService.cs | 2 +- .../Validator/Role/RoleCreateValidator.cs | 14 +++ .../Validator/Role/RoleUpdateValidator.cs | 16 ++++ .../Salarie/SalarieCreateValidator.cs | 6 +- .../Salarie/SalarieUpdateValidator.cs | 6 +- ...idator.cs => UtilisateurLoginValidator.cs} | 10 ++- 20 files changed, 238 insertions(+), 59 deletions(-) create mode 100644 ldap-cesi/Validator/Role/RoleCreateValidator.cs create mode 100644 ldap-cesi/Validator/Role/RoleUpdateValidator.cs rename ldap-cesi/Validator/Utilisateur/{UtilisateurCreateValidator.cs => UtilisateurLoginValidator.cs} (54%) diff --git a/ldap-cesi/Configurations/Conf.cs b/ldap-cesi/Configurations/Conf.cs index 0798afe..fa10ddd 100644 --- a/ldap-cesi/Configurations/Conf.cs +++ b/ldap-cesi/Configurations/Conf.cs @@ -1,6 +1,8 @@ using System.Reflection; using System.Security.Cryptography; using System.Text; +using FluentValidation; +using FluentValidation.AspNetCore; using ldap_cesi.Context; using ldap_cesi.Repository; using ldap_cesi.Repository.Services; @@ -48,6 +50,8 @@ public static class Conf builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddSingleton(); + builder.Services.AddValidatorsFromAssemblyContaining(); + builder.Services.AddFluentValidationAutoValidation(); } public static void AddEFCoreConfiguration(this WebApplicationBuilder builder) { diff --git a/ldap-cesi/Controllers/RoleController.cs b/ldap-cesi/Controllers/RoleController.cs index 28d6554..d865d03 100644 --- a/ldap-cesi/Controllers/RoleController.cs +++ b/ldap-cesi/Controllers/RoleController.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Mvc; using ldap_cesi.DTOs.Inputs.Role; using ldap_cesi.Services.Interfaces; -using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; namespace ldap_cesi.Controllers { @@ -17,68 +17,72 @@ namespace ldap_cesi.Controllers } // GET: api/Role + /// + /// Endpoint qui retourne tous les rôles + /// + /// Un tableau de rôle [HttpGet] + [Authorize(Roles = "admin")] public async Task GetAllRoles() { var result = await _roleService.GetAll(); - if (result.Success) - { - return Ok(result.Data); - } - return StatusCode(result.StatusCode, result.Message); + return result.Success ? Ok(result.Data) : BadRequest(result.Message); } // GET: api/Role/{id} + /// + /// Endpoint qui retourne le role + /// + /// L'id du rôle. + /// Le role update [HttpGet("{id}")] + [Authorize(Roles = "admin")] public async Task GetRoleById(int id) { var result = await _roleService.GetById(id); - if (result.Success) - { - return Ok(result.Data); - } - return StatusCode(result.StatusCode, result.Message); + return result.Success ? Ok(result.Data) : BadRequest(result.Message); } // POST: api/Role + /// + /// Endpoint créer le Role + /// + /// Le nom du rôle. + /// Response. [HttpPost] + [Authorize(Roles = "admin")] public async Task CreateRole([FromBody] RoleCreateDto roleDto) { var result = await _roleService.Create(roleDto); - if (result.Success) - { - return CreatedAtAction(nameof(GetRoleById), new { id = result.Data }, result.Data); - } - return StatusCode(result.StatusCode, result.Message); + return result.Success ? Ok(result.Data) : BadRequest(result.Message); } - // PUT: api/Role/{id} - [HttpPut("{id}")] - public async Task UpdateRole(int id, [FromBody] RoleUpdateDto roleDto) + // PUT: api/Role + /// + /// Endpoint qui met à jour un role. + /// + /// Les informations du role à mettre à jour. Id, nom + /// Le role mis à jour. + [HttpPut] + [Authorize(Roles = "admin")] + public async Task UpdateRole([FromBody] RoleUpdateDto roleDto) { - if (id != roleDto.Id) - { - return BadRequest("Role ID mismatch"); - } - var result = await _roleService.Update(roleDto); - if (result.Success) - { - return NoContent(); - } - return StatusCode(result.StatusCode, result.Message); + return result.Success ? Ok(result.Data) : BadRequest(result.Message); } // DELETE: api/Role/{id} + /// + /// Endpoint qui supprime un rôle. + /// + /// L'ID du rôle à supprimer. + /// Un message de confirmation de suppression. [HttpDelete("{id}")] + [Authorize(Roles = "admin")] public async Task DeleteRole(int id) { var result = await _roleService.Delete(id); - if (result.Success) - { - return NoContent(); - } - return StatusCode(result.StatusCode, result.Message); + return result.Success ? Ok(result.Data) : BadRequest(result.Message); } } } diff --git a/ldap-cesi/Controllers/SalarieController.cs b/ldap-cesi/Controllers/SalarieController.cs index 3928aa0..6873f7c 100644 --- a/ldap-cesi/Controllers/SalarieController.cs +++ b/ldap-cesi/Controllers/SalarieController.cs @@ -56,11 +56,21 @@ public class SalarieController : ControllerBase /// L'ID du salarié. /// Le salarié correspondant à l'ID. [HttpGet("/complet/{id}")] - [Authorize(Roles = "admin")] public async Task GetSalarieCompletById(int id) { var result = await _salarieService.GetCompletById(id); return result.Success ? Ok(result.Data) : BadRequest(result.Message); + } + + /// + /// Endpoint qui retourne tout les salariés et les relations qu'il détient + /// + /// Tous les salariés avec leurs relations + [HttpGet("all")] + public async Task GetAllSariesWithRelations() + { + var result = await _salarieService.GetAllWithRelationsAsync(s => s.IdServiceNavigation, s => s.IdSiteNavigation); + return result.Success ? Ok(result.Data) : BadRequest(result.Message); } /// diff --git a/ldap-cesi/DTOs/Inputs/Role/RoleCreateDto.cs b/ldap-cesi/DTOs/Inputs/Role/RoleCreateDto.cs index 59652a2..e11af07 100644 --- a/ldap-cesi/DTOs/Inputs/Role/RoleCreateDto.cs +++ b/ldap-cesi/DTOs/Inputs/Role/RoleCreateDto.cs @@ -1,3 +1,4 @@ + namespace ldap_cesi.DTOs.Inputs.Role; public class RoleCreateDto diff --git a/ldap-cesi/Mapper/AutoMapperProfile.cs b/ldap-cesi/Mapper/AutoMapperProfile.cs index 8d3924e..9d159bf 100644 --- a/ldap-cesi/Mapper/AutoMapperProfile.cs +++ b/ldap-cesi/Mapper/AutoMapperProfile.cs @@ -1,5 +1,6 @@ using AutoMapper; using ldap_cesi.DTOs; +using ldap_cesi.DTOs.Inputs.Role; using ldap_cesi.DTOs.Inputs.Salarie; using ldap_cesi.DTOs.Inputs.Service; using ldap_cesi.DTOs.Inputs.Site; @@ -17,6 +18,7 @@ public class AutoMapperProfile : Profile CreateMap(); CreateMap(); CreateMap(); + CreateMap(); CreateMap(); CreateMap() .ForMember(dest => dest.TelephoneFixe, opt => opt.MapFrom(src => src.TelephoneFix)) @@ -29,14 +31,14 @@ public class AutoMapperProfile : Profile //OUTPUTS MAPPER CreateMap() .ForMember(dest => dest.RoleNom, opt => opt.MapFrom(src => src.IdRoleNavigation.Nom)); - CreateMap() + 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() .ForMember(dest => dest.Service, opt => opt.MapFrom(src => src.IdServiceNavigation.Nom)) .ForMember(dest => dest.Site, opt => opt.MapFrom(src => src.IdSiteNavigation.Ville)); - CreateMap(); - CreateMap(); - CreateMap(); } } \ No newline at end of file diff --git a/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs b/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs index 1daf9fb..223565b 100644 --- a/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs +++ b/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs @@ -10,6 +10,8 @@ public interface IRepositoryBase where TEntity : class Task> GetAllAsync(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 FirstOrDefaultAsync(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 3253321..d7fc138 100644 --- a/ldap-cesi/Repositories/RepositoryBase.cs +++ b/ldap-cesi/Repositories/RepositoryBase.cs @@ -9,10 +9,11 @@ namespace ldap_cesi.Repository; public class RepositoryBase : IRepositoryBase where TEntity : class { protected readonly PgContext _context; - + protected readonly DbSet _dbSet; public RepositoryBase(PgContext context) { _context = context ?? throw new ArgumentNullException(nameof(context)); + _dbSet = context.Set(); } public virtual async Task AddAsync(TEntity entity, CancellationToken cancellationToken = default) { @@ -113,5 +114,28 @@ public class RepositoryBase : IRepositoryBase where TEntity : throw new Exception("Erreur qui concerne le listing des entités", ex); } } + public virtual async Task> GetAllWithRelationsAsync(params Expression>[] relationInclues) + { + IQueryable query = _dbSet; + + foreach (var relationInclue in relationInclues) + { + query = query.Include(relationInclue); + } + + return await query.ToListAsync(); + } + + public virtual async Task GetWithRelationsAsync(int id, params Expression>[] relationInclues) + { + IQueryable query = _dbSet; + + foreach (var relationInclue in relationInclues) + { + query = query.Include(relationInclue); + } + + return await query.FirstOrDefaultAsync(e => EF.Property(e, "Id") == id); + } } \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/IRoleService.cs b/ldap-cesi/Services/Interfaces/IRoleService.cs index e4b46ab..41e1c2a 100644 --- a/ldap-cesi/Services/Interfaces/IRoleService.cs +++ b/ldap-cesi/Services/Interfaces/IRoleService.cs @@ -1,9 +1,6 @@ -using ldap_cesi.Repository.Services; -using ldap_cesi.Services.Interfaces; using ldap_cesi.Entities; using ldap_cesi.DTOs; using ldap_cesi.DTOs.Inputs.Role; -using AutoMapper; namespace ldap_cesi.Services.Interfaces { diff --git a/ldap-cesi/Services/Interfaces/ISalarieService.cs b/ldap-cesi/Services/Interfaces/ISalarieService.cs index 893a742..af59cd0 100644 --- a/ldap-cesi/Services/Interfaces/ISalarieService.cs +++ b/ldap-cesi/Services/Interfaces/ISalarieService.cs @@ -12,5 +12,5 @@ public interface ISalarieService : IServiceBase>> GetAllWithoutIService(); Task>> GetSalariesBySite(int siteId); Task>> GetSalariesByService(int serviceId); - Task> GetCompletById(int id); + Task> GetCompletById(int id); } \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/IServiceBase.cs b/ldap-cesi/Services/Interfaces/IServiceBase.cs index f1f4df4..a28d769 100644 --- a/ldap-cesi/Services/Interfaces/IServiceBase.cs +++ b/ldap-cesi/Services/Interfaces/IServiceBase.cs @@ -1,3 +1,4 @@ +using System.Linq.Expressions; using ldap_cesi.Models; namespace ldap_cesi.Services.Interfaces; @@ -10,6 +11,8 @@ public interface IServiceBase { Task>> GetAll(); 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> Create(TCreateDto dto); Task> Update(TUpdateDto dto); Task> Delete(int id); diff --git a/ldap-cesi/Services/RoleService.cs b/ldap-cesi/Services/RoleService.cs index 43eba92..c6e44df 100644 --- a/ldap-cesi/Services/RoleService.cs +++ b/ldap-cesi/Services/RoleService.cs @@ -4,13 +4,14 @@ using ldap_cesi.Entities; using ldap_cesi.DTOs; using ldap_cesi.DTOs.Inputs.Role; using AutoMapper; +using ldap_cesi.Validator.Role; namespace ldap_cesi.Services; public class RoleService : ServiceBase,IRoleService { - public RoleService(IRepositoryRole repositoryRole, IMapper mapper, ILogger logger) - : base(repositoryRole, mapper, logger) + public RoleService(IRepositoryRole repositoryRole, IMapper mapper, ILogger logger, RoleCreateValidator roleCreateValidator, RoleUpdateValidator roleUpdateValidator) + : base(repositoryRole, mapper, logger, roleCreateValidator, roleUpdateValidator) { } } \ No newline at end of file diff --git a/ldap-cesi/Services/SalarieService.cs b/ldap-cesi/Services/SalarieService.cs index 1d8a393..40a28b7 100644 --- a/ldap-cesi/Services/SalarieService.cs +++ b/ldap-cesi/Services/SalarieService.cs @@ -18,7 +18,9 @@ public class SalarieService : ServiceBase logger) : base(repositorySalarie, mapper, logger) + public SalarieService(IRepositorySalarie repositorySalarie, IMapper mapper, IRepositorySite repositorySite, IRepositoryService repositoryService, + ILogger logger, SalarieCreateValidator salarieCreateValidator, SalarieUpdateValidator salarieUpdateValidator) + : base(repositorySalarie, mapper, logger, salarieCreateValidator, salarieUpdateValidator) { _repositorySalarie = repositorySalarie; _repositorySite = repositorySite; @@ -48,11 +50,11 @@ public class SalarieService : ServiceBase> GetCompletById(int id) + public async Task> GetCompletById(int id) { var salarie = await _repositorySalarie.GetSalarieWithRelationsAsync(id); - var salarieOutput = _mapper.Map(salarie); - return new ResponseDataModel + var salarieOutput = _mapper.Map(salarie); + return new ResponseDataModel { Success = true, Data = salarieOutput, diff --git a/ldap-cesi/Services/ServiceBase.cs b/ldap-cesi/Services/ServiceBase.cs index e560fd3..c8e444a 100644 --- a/ldap-cesi/Services/ServiceBase.cs +++ b/ldap-cesi/Services/ServiceBase.cs @@ -7,7 +7,9 @@ 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; namespace ldap_cesi.Services; @@ -20,12 +22,16 @@ public class ServiceBase : IServiceBase _repository; protected readonly IMapper _mapper; protected readonly ILogger> _logger; + protected readonly IValidator _createDtoValidator; + protected readonly IValidator _updateDtoValidator; - public ServiceBase(IRepositoryBase repository, IMapper mapper, ILogger> logger) + public ServiceBase(IRepositoryBase repository, IMapper mapper, ILogger> logger, IValidator createDtoValidator, IValidator updateDtoValidator) { _repository = repository; _mapper = mapper; _logger = logger; + _createDtoValidator = createDtoValidator; + _updateDtoValidator = updateDtoValidator; } public virtual async Task>> GetAll() @@ -87,11 +93,83 @@ public class ServiceBase : IServiceBase>> GetAllWithRelationsAsync(params Expression>[] relationsAInclure) + { + try + { + var entities = await _repository.GetAllWithRelationsAsync(relationsAInclure); + var dtos = _mapper.Map>(entities); + return new ResponseDataModel> + { + Success = true, + Data = dtos, + StatusCode = 200, + Message = "Liste des entités récupérée avec succès." + }; + } + catch (Exception ex) + { + _logger.LogError(ex, "Une erreur s'est produite lors de la récupération des entités."); + return new ResponseDataModel> + { + Success = false, + Message = "Une erreur s'est produite lors de la récupération des entités.", + StatusCode = 500 + }; + } + } + + public virtual async Task> GetByIdWithRelations(int id, params Expression>[] relationsAInclure) + { + try + { + var entity = await _repository.GetWithRelationsAsync(id, relationsAInclure); + if (entity == null) + { + return new ResponseDataModel + { + Success = false, + Message = $"Aucune entité trouvée avec l'identifiant {id}.", + StatusCode = 404 + }; + } + + var dto = _mapper.Map(entity); + return new ResponseDataModel + { + Success = true, + Data = dto, + StatusCode = 200, + Message = "Entité avec relations récupérée avec succès." + }; + } + catch (Exception ex) + { + _logger.LogError(ex, $"Une erreur s'est produite lors de la récupération de l'entité avec l'identifiant {id}."); + return new ResponseDataModel + { + Success = false, + Message = "Une erreur s'est produite lors de la récupération de l'entité avec relations.", + StatusCode = 500 + }; + } + } public virtual async Task> Create(TCreateDto dto) { try { + var validationResult = _createDtoValidator.Validate(dto); + if (!validationResult.IsValid) + { + return new ResponseDataModel + { + Success = false, + Message = string.Join("; ", validationResult.Errors.Select(e => e.ErrorMessage)), + StatusCode = 400 + }; + } var entity = _mapper.Map(dto); var createdEntity = await _repository.AddAsync(entity); return new ResponseDataModel @@ -118,6 +196,16 @@ public class ServiceBase : IServiceBase + { + Success = false, + Message = string.Join("; ", validationResult.Errors.Select(e => e.ErrorMessage)), + StatusCode = 400 + }; + } var entity = _mapper.Map(dto); bool isUpdated = await _repository.UpdateAsync(entity); return new ResponseDataModel diff --git a/ldap-cesi/Services/ServiceService.cs b/ldap-cesi/Services/ServiceService.cs index 7cb9b6e..193fe2c 100644 --- a/ldap-cesi/Services/ServiceService.cs +++ b/ldap-cesi/Services/ServiceService.cs @@ -13,7 +13,8 @@ namespace ldap_cesi.Services; public class ServiceService : ServiceBase, IServiceService { - public ServiceService(IRepositoryService repositoryService, IMapper mapper, ILogger logger) : base(repositoryService, mapper, logger) + public ServiceService(IRepositoryService repositoryService, IMapper mapper, ILogger logger, ServiceCreateValidator serviceCreateValidator, ServiceUpdateValidator serviceUpdateValidator) + : base(repositoryService, mapper, logger, serviceCreateValidator, serviceUpdateValidator) { } diff --git a/ldap-cesi/Services/UtilisateurService.cs b/ldap-cesi/Services/UtilisateurService.cs index b908c5a..3abf032 100644 --- a/ldap-cesi/Services/UtilisateurService.cs +++ b/ldap-cesi/Services/UtilisateurService.cs @@ -47,7 +47,7 @@ public class UtilisateurService : IUtilisateurService public async Task> Login(UtilisateurLoginDto utilisateurInput) { - var validation = new UtilisateurCreateValidator(); + var validation = new UtilisateurLoginValidator(); var result = validation.Validate(utilisateurInput); if (!result.IsValid) { diff --git a/ldap-cesi/Validator/Role/RoleCreateValidator.cs b/ldap-cesi/Validator/Role/RoleCreateValidator.cs new file mode 100644 index 0000000..ff2e572 --- /dev/null +++ b/ldap-cesi/Validator/Role/RoleCreateValidator.cs @@ -0,0 +1,14 @@ +using FluentValidation; +using ldap_cesi.DTOs.Inputs.Role; + +namespace ldap_cesi.Validator.Role; + +public class RoleCreateValidator : AbstractValidator +{ + public RoleCreateValidator() + { + RuleFor(x => x.Nom) + .NotEmpty().WithMessage("Le nom est requis.") + .MaximumLength(50).WithMessage("Le nom ne doit pas dépasser 50 caractères."); + } +} \ No newline at end of file diff --git a/ldap-cesi/Validator/Role/RoleUpdateValidator.cs b/ldap-cesi/Validator/Role/RoleUpdateValidator.cs new file mode 100644 index 0000000..1bdec9d --- /dev/null +++ b/ldap-cesi/Validator/Role/RoleUpdateValidator.cs @@ -0,0 +1,16 @@ +using FluentValidation; +using ldap_cesi.DTOs.Inputs.Role; + +namespace ldap_cesi.Validator.Role; + +public class RoleUpdateValidator : AbstractValidator +{ + public RoleUpdateValidator() + { + RuleFor(x => x.Nom) + .NotEmpty().WithMessage("Le nom est requis.") + .MaximumLength(50).WithMessage("Le nom ne doit pas dépasser 50 caractères."); + RuleFor(x => x.Id) + .NotEmpty().WithMessage("L'identifiant du Rôle est requis."); + } +} \ No newline at end of file diff --git a/ldap-cesi/Validator/Salarie/SalarieCreateValidator.cs b/ldap-cesi/Validator/Salarie/SalarieCreateValidator.cs index a53fc1c..c23c02a 100644 --- a/ldap-cesi/Validator/Salarie/SalarieCreateValidator.cs +++ b/ldap-cesi/Validator/Salarie/SalarieCreateValidator.cs @@ -16,11 +16,15 @@ public class SalarieCreateValidator : AbstractValidator .MaximumLength(50).WithMessage("Le prénom ne doit pas dépasser 50 caractères."); RuleFor(x => x.TelephoneFix) - .NotEmpty().WithMessage("Le téléphone fixe est requis.") + .NotEmpty().WithMessage("Le téléphone fixe est requis.") + .Matches(@"^(\+33|0)[1-9](\d{2}){4}$") + .WithMessage("Le numéro de téléphone fixe n'est pas valide. Format attendu : +33XXXXXXXXX ou 0XXXXXXXXX.") .MaximumLength(15).WithMessage("Le téléphone fixe ne doit pas dépasser 15 caractères."); RuleFor(x => x.TelephonePortable) .NotEmpty().WithMessage("Le téléphone portable est requis.") + .Matches(@"^(\+33|0)[6-7](\d{2}){4}$") + .WithMessage("Le numéro de téléphone portable n'est pas valide. Format attendu : +33XXXXXXXXX ou 0XXXXXXXXX.") .MaximumLength(15).WithMessage("Le téléphone portable ne doit pas dépasser 15 caractères."); RuleFor(x => x.Email) diff --git a/ldap-cesi/Validator/Salarie/SalarieUpdateValidator.cs b/ldap-cesi/Validator/Salarie/SalarieUpdateValidator.cs index a755c82..d364149 100644 --- a/ldap-cesi/Validator/Salarie/SalarieUpdateValidator.cs +++ b/ldap-cesi/Validator/Salarie/SalarieUpdateValidator.cs @@ -18,11 +18,15 @@ public class SalarieUpdateValidator : AbstractValidator .MaximumLength(50).WithMessage("Le prénom ne doit pas dépasser 50 caractères."); RuleFor(x => x.TelephoneFixe) - .NotEmpty().WithMessage("Le téléphone fixe est requis.") + .NotEmpty().WithMessage("Le téléphone fixe est requis.") + .Matches(@"^(\+33|0)[1-9](\d{2}){4}$") + .WithMessage("Le numéro de téléphone fixe n'est pas valide. Format attendu : +33XXXXXXXXX ou 0XXXXXXXXX.") .MaximumLength(15).WithMessage("Le téléphone fixe ne doit pas dépasser 15 caractères."); RuleFor(x => x.TelephonePortable) .NotEmpty().WithMessage("Le téléphone portable est requis.") + .Matches(@"^(\+33|0)[6-7](\d{2}){4}$") + .WithMessage("Le numéro de téléphone portable n'est pas valide. Format attendu : +33XXXXXXXXX ou 0XXXXXXXXX.") .MaximumLength(15).WithMessage("Le téléphone portable ne doit pas dépasser 15 caractères."); RuleFor(x => x.Email) diff --git a/ldap-cesi/Validator/Utilisateur/UtilisateurCreateValidator.cs b/ldap-cesi/Validator/Utilisateur/UtilisateurLoginValidator.cs similarity index 54% rename from ldap-cesi/Validator/Utilisateur/UtilisateurCreateValidator.cs rename to ldap-cesi/Validator/Utilisateur/UtilisateurLoginValidator.cs index 154b071..aa2e28f 100644 --- a/ldap-cesi/Validator/Utilisateur/UtilisateurCreateValidator.cs +++ b/ldap-cesi/Validator/Utilisateur/UtilisateurLoginValidator.cs @@ -3,16 +3,18 @@ using ldap_cesi.DTOs.Inputs; namespace ldap_cesi.Validator.Utilisateur; -public class UtilisateurCreateValidator : AbstractValidator +public class UtilisateurLoginValidator : AbstractValidator { - public UtilisateurCreateValidator() + public UtilisateurLoginValidator() { RuleFor(x => x.Email) .NotEmpty().WithMessage("L'email est requis.") - .EmailAddress().WithMessage("L'email n'est pas valide."); + .EmailAddress().WithMessage("L'email n'est pas valide.") + .MaximumLength(50).WithMessage("L'email ne doit pas dépasser 50 caractères."); RuleFor(x => x.MotDePasse) .NotEmpty().WithMessage("Le mot de passe est requis.") - .MinimumLength(6).WithMessage("Le mot de passe doit contenir au moins 6 caractères."); + .MinimumLength(6).WithMessage("Le mot de passe doit contenir au moins 6 caractères.") + .MaximumLength(20).WithMessage("Le mot de passe ne doit pas dépasser 20 caractères."); } } \ No newline at end of file From 37eca08753ce71ebbb973c52c260c86453a3012d Mon Sep 17 00:00:00 2001 From: BuzzLeclair Date: Wed, 5 Mar 2025 21:00:30 +0100 Subject: [PATCH 12/17] =?UTF-8?q?-=20Ajout=20de=20la=20fonctionnalit=C3=A9?= =?UTF-8?q?=20de=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 @@ + From 285063ebcdafb580b409f71020f57ab9272555b7 Mon Sep 17 00:00:00 2001 From: BuzzLeclair Date: Thu, 6 Mar 2025 00:12:23 +0100 Subject: [PATCH 13/17] - Endpoints fini.. --- ldap-cesi/Controllers/ServicesController.cs | 12 ++++++++++++ ldap-cesi/Controllers/SiteController.cs | 13 +++++++++++++ ldap-cesi/DTOs/Generic/ServiceDto.cs | 3 +++ ldap-cesi/DTOs/Generic/SiteDto.cs | 3 +++ .../DTOs/Outputs/Salarie/SalarieMinimalDto.cs | 17 +++++++++++++++++ ldap-cesi/Mapper/AutoMapperProfile.cs | 4 +++- ldap-cesi/Services/Interfaces/ISiteService.cs | 4 ++-- ldap-cesi/Services/SiteService.cs | 9 +++++---- 8 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 ldap-cesi/DTOs/Outputs/Salarie/SalarieMinimalDto.cs diff --git a/ldap-cesi/Controllers/ServicesController.cs b/ldap-cesi/Controllers/ServicesController.cs index 8f2ec66..bc7aa95 100644 --- a/ldap-cesi/Controllers/ServicesController.cs +++ b/ldap-cesi/Controllers/ServicesController.cs @@ -37,6 +37,18 @@ public class ServicesController : ControllerBase { var result = await _serviceService.GetById(id); return result.Success ? Ok(result.Data) : BadRequest(result.Message); + } + + /// + /// 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.Data) : BadRequest(result.Message); } /// diff --git a/ldap-cesi/Controllers/SiteController.cs b/ldap-cesi/Controllers/SiteController.cs index 50664dc..722ad3f 100644 --- a/ldap-cesi/Controllers/SiteController.cs +++ b/ldap-cesi/Controllers/SiteController.cs @@ -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 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/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/Mapper/AutoMapperProfile.cs b/ldap-cesi/Mapper/AutoMapperProfile.cs index 9d159bf..bc500ef 100644 --- a/ldap-cesi/Mapper/AutoMapperProfile.cs +++ b/ldap-cesi/Mapper/AutoMapperProfile.cs @@ -35,8 +35,10 @@ public class AutoMapperProfile : Profile .ForMember(dest => dest.Service, opt => opt.MapFrom(src => src.IdServiceNavigation)) .ForMember(dest => dest.Site, opt => opt.MapFrom(src => src.IdSiteNavigation)); 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/Services/Interfaces/ISiteService.cs b/ldap-cesi/Services/Interfaces/ISiteService.cs index cdff833..521892e 100644 --- a/ldap-cesi/Services/Interfaces/ISiteService.cs +++ b/ldap-cesi/Services/Interfaces/ISiteService.cs @@ -1,11 +1,11 @@ -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); diff --git a/ldap-cesi/Services/SiteService.cs b/ldap-cesi/Services/SiteService.cs index 5d5628d..4bf5e51 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,16 +9,16 @@ 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() From 14bc105042298c5fff9eef8e549158bff8b1dd97 Mon Sep 17 00:00:00 2001 From: BuzzLeclair Date: Sat, 8 Mar 2025 18:33:08 +0100 Subject: [PATCH 14/17] =?UTF-8?q?-=20Int=C3=A9gration=20de=20la=20paginati?= =?UTF-8?q?on=20dans=20les=20fonctions=20getAll=20-=20Modification=20du=20?= =?UTF-8?q?dto=20de=20sorti=20pour=20salarie.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ldap-cesi/Configurations/Conf.cs | 4 +- ldap-cesi/Controllers/RoleController.cs | 14 +- ldap-cesi/Controllers/SalarieController.cs | 31 ++- ldap-cesi/Controllers/ServicesController.cs | 19 +- ldap-cesi/Controllers/SiteController.cs | 12 +- .../Controllers/UtilisateurController.cs | 10 +- .../DTOs/Outputs/Salarie/SalarieListDto.cs | 6 +- .../Outputs/Salarie/SalarieOutputDetail.cs | 6 +- .../DTOs/Outputs/Service/ServiceMinimalDto.cs | 8 + ldap-cesi/DTOs/Outputs/Site/SiteMinimalDto.cs | 8 + ldap-cesi/Mapper/AutoMapperProfile.cs | 6 + ldap-cesi/Models/IResponseDataModel.cs | 2 + ldap-cesi/Models/ResponseDataModel.cs | 2 + ldap-cesi/Program.cs | 1 + .../Interfaces/IRepositoryBase.cs | 11 +- ldap-cesi/Repositories/RepositoryBase.cs | 68 +++-- .../Services/Interfaces/ISalarieService.cs | 3 +- ldap-cesi/Services/Interfaces/IServiceBase.cs | 4 +- ldap-cesi/Services/Interfaces/ISiteService.cs | 10 +- ldap-cesi/Services/SalarieService.cs | 24 +- ldap-cesi/Services/ServiceBase.cs | 28 +- ldap-cesi/Services/SiteService.cs | 253 +++++++++--------- ldap-cesi/Services/UtilisateurService.cs | 3 +- 23 files changed, 290 insertions(+), 243 deletions(-) create mode 100644 ldap-cesi/DTOs/Outputs/Service/ServiceMinimalDto.cs create mode 100644 ldap-cesi/DTOs/Outputs/Site/SiteMinimalDto.cs 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 4e0a67c..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,15 +21,14 @@ 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); + var result = await _salarieService.GetAll(pageNumber, pageSize); + return result.Success ? Ok(result) : BadRequest(result); } [HttpGet("search")] - [Authorize(Roles = "admin")] public async Task SearchSalaries( [FromQuery] string searchTerm, [FromQuery] int pageNumber = 1, @@ -43,7 +42,7 @@ public class SalarieController : ControllerBase var result = await _salarieService.SearchWithRelations( searchTerm, pageNumber, pageSize, s => s.IdServiceNavigation, s => s.IdSiteNavigation); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + return result.Success ? Ok(result) : BadRequest(result); } /// @@ -55,7 +54,7 @@ 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); } /// @@ -67,7 +66,7 @@ public class SalarieController : ControllerBase public async Task GetSalarieCompletById(int id) { var result = await _salarieService.GetByIdWithRelations(id,s => s.IdServiceNavigation, s => s.IdSiteNavigation); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + return result.Success ? Ok(result) : BadRequest(result); } /// @@ -75,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); } /// @@ -91,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); } /// @@ -104,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); } /// @@ -117,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); } /// @@ -129,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); } /// @@ -141,7 +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); } } diff --git a/ldap-cesi/Controllers/ServicesController.cs b/ldap-cesi/Controllers/ServicesController.cs index bc7aa95..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,7 @@ 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); } /// @@ -48,7 +47,7 @@ public class ServicesController : ControllerBase public async Task GetServiceByIdWithSalaries(int id) { var result = await _serviceService.GetByIdWithRelations(id, s=>s.Salaries); - return result.Success ? Ok(result.Data) : BadRequest(result.Message); + return result.Success ? Ok(result) : BadRequest(result); } /// @@ -61,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); } /// @@ -74,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); } /// @@ -87,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 722ad3f..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); } @@ -65,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); } @@ -78,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); } @@ -91,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/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/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 bc500ef..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,7 +35,12 @@ 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() .ForMember(dest => dest.Salaries, opt => opt.MapFrom(src => src.Salaries)); CreateMap(); 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/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 350af1f..0974d7a 100644 --- a/ldap-cesi/Program.cs +++ b/ldap-cesi/Program.cs @@ -37,6 +37,7 @@ using (var scope = app.Services.CreateScope()) 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 71ff6f6..baf4780 100644 --- a/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs +++ b/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs @@ -7,13 +7,18 @@ 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> SearchAsync(Expression> predicate, int numPage, int taillePage, + 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, diff --git a/ldap-cesi/Repositories/RepositoryBase.cs b/ldap-cesi/Repositories/RepositoryBase.cs index ecaf316..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) @@ -138,7 +167,11 @@ 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) + 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; @@ -149,10 +182,15 @@ public class RepositoryBase : IRepositoryBase where TEntity : query = query.Where(predicate); - return await query - .Skip((numPage - 1) * taillePage) - .Take(taillePage) + 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) 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 c91635b..c00afe3 100644 --- a/ldap-cesi/Services/Interfaces/IServiceBase.cs +++ b/ldap-cesi/Services/Interfaces/IServiceBase.cs @@ -9,10 +9,10 @@ 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); diff --git a/ldap-cesi/Services/Interfaces/ISiteService.cs b/ldap-cesi/Services/Interfaces/ISiteService.cs index 521892e..4c99e84 100644 --- a/ldap-cesi/Services/Interfaces/ISiteService.cs +++ b/ldap-cesi/Services/Interfaces/ISiteService.cs @@ -7,9 +7,9 @@ namespace ldap_cesi.Services.Interfaces; 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 1904e88..e61c6a6 100644 --- a/ldap-cesi/Services/ServiceBase.cs +++ b/ldap-cesi/Services/ServiceBase.cs @@ -1,14 +1,8 @@ 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; @@ -41,15 +35,17 @@ public class ServiceBase : IServiceBase(entity, "Nom"), $"%{inputSearch}%") || EF.Functions.ILike(EF.Property(entity, "Prenom"), $"%{inputSearch}%"); } - public virtual async Task>> GetAll() + 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." }; @@ -101,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." }; @@ -290,12 +288,14 @@ public class ServiceBase : IServiceBase>(entities); var totalCount = await _repository.CountAsync(predicate); - var paginatedList = new PaginatedList(dtos, totalCount, pageNumber, pageSize); + var response = new PaginatedList(dtos, totalCount, pageNumber, pageSize); return new ResponseDataModel> { Success = true, - Data = paginatedList, + Data = response, + TotalPages = response.TotalPages, + TotalCount = response.TotalCount, StatusCode = 200, Message = "Recherche effectuée avec succès." }; diff --git a/ldap-cesi/Services/SiteService.cs b/ldap-cesi/Services/SiteService.cs index 4bf5e51..246fb98 100644 --- a/ldap-cesi/Services/SiteService.cs +++ b/ldap-cesi/Services/SiteService.cs @@ -21,132 +21,131 @@ public class SiteService : ServiceBase>> 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> { From 9803ef0af6618209db9c7fdb065daecfd51c6ad2 Mon Sep 17 00:00:00 2001 From: BuzzLeclair Date: Sat, 8 Mar 2025 18:57:22 +0100 Subject: [PATCH 15/17] - Changement du typage --- ldap-cesi/Services/Interfaces/IServiceBase.cs | 2 +- ldap-cesi/Services/ServiceBase.cs | 19 ++++++++----------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/ldap-cesi/Services/Interfaces/IServiceBase.cs b/ldap-cesi/Services/Interfaces/IServiceBase.cs index c00afe3..db8cb40 100644 --- a/ldap-cesi/Services/Interfaces/IServiceBase.cs +++ b/ldap-cesi/Services/Interfaces/IServiceBase.cs @@ -14,7 +14,7 @@ public interface IServiceBase Task> GetByIdWithRelations(int id, params Expression>[] relationsAInclures); // préciser avec une ou des fonctions lambda les relations à inclure dans la réponse Task>> GetAllWithRelationsAsync(int pageNumber, int pageSize, params Expression>[] relationsAInclure); - Task>> SearchWithRelations(string searchTerm, int pageNumber, int pageSize, + Task>> SearchWithRelations(string searchTerm, int pageNumber, int pageSize, params Expression>[] includeProperties); Task> Create(TCreateDto dto); Task> Update(TUpdateDto dto); diff --git a/ldap-cesi/Services/ServiceBase.cs b/ldap-cesi/Services/ServiceBase.cs index e61c6a6..20908ea 100644 --- a/ldap-cesi/Services/ServiceBase.cs +++ b/ldap-cesi/Services/ServiceBase.cs @@ -269,11 +269,11 @@ public class ServiceBase : IServiceBase>> SearchWithRelations(string searchTerm, int pageNumber, int pageSize, params Expression>[] includeProperties) + public virtual async Task>> SearchWithRelations(string searchTerm, int pageNumber, int pageSize, params Expression>[] includeProperties) { if (string.IsNullOrWhiteSpace(searchTerm) || searchTerm.Length < 2) { - return new ResponseDataModel> + return new ResponseDataModel> { Success = false, Message = "Le terme de recherche doit contenir au moins deux caractères.", @@ -284,18 +284,15 @@ public class ServiceBase : IServiceBase>(entities); - var totalCount = await _repository.CountAsync(predicate); - - var response = new PaginatedList(dtos, totalCount, pageNumber, pageSize); + var response = await _repository.SearchAsync(predicate, pageNumber, pageSize, includeProperties); + var dtos = _mapper.Map>(response.Data); - return new ResponseDataModel> + return new ResponseDataModel> { Success = true, - Data = response, + Data = dtos, TotalPages = response.TotalPages, - TotalCount = response.TotalCount, + TotalCount = response.TotalItems, StatusCode = 200, Message = "Recherche effectuée avec succès." }; @@ -303,7 +300,7 @@ public class ServiceBase : IServiceBase> + return new ResponseDataModel> { Success = false, Message = "Une erreur s'est produite lors de la recherche des entités.", From 40972cad0d3e45e9a2efef9691a15f3e97578c8f Mon Sep 17 00:00:00 2001 From: BuzzLeclair Date: Mon, 10 Mar 2025 17:47:13 +0100 Subject: [PATCH 16/17] =?UTF-8?q?-=20V=C3=A9rification=20s'il=20y=20a=20de?= =?UTF-8?q?s=20salari=C3=A9s=20contenus=20dans=20les=20services=20ou=20les?= =?UTF-8?q?=20sites=20avant=20la=20suppression.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ldap-cesi/Controllers/JwtController.cs | 1 + ldap-cesi/Controllers/ServicesController.cs | 2 +- ldap-cesi/Controllers/SiteController.cs | 6 +- .../Controllers/UtilisateurController.cs | 82 +++++++- .../DTOs/Inputs/Salarie/SalarieCreateDto.cs | 2 +- ldap-cesi/Mapper/AutoMapperProfile.cs | 7 +- ldap-cesi/Models/IResponseDataModel.cs | 2 - ldap-cesi/Models/PaginatedList.cs | 35 ++-- ldap-cesi/Models/ResponseDataModel.cs | 2 + .../Interfaces/IRepositoryBase.cs | 1 + ldap-cesi/Repositories/RepositoryBase.cs | 26 +-- ldap-cesi/Services/Interfaces/IJwtService.cs | 1 + .../Services/Interfaces/ISalarieService.cs | 8 +- ldap-cesi/Services/Interfaces/IServiceBase.cs | 1 + .../Services/Interfaces/IServiceService.cs | 1 + ldap-cesi/Services/Interfaces/ISiteService.cs | 6 +- ldap-cesi/Services/JwtService.cs | 41 ++++ ldap-cesi/Services/SalarieService.cs | 182 +++--------------- ldap-cesi/Services/ServiceBase.cs | 48 +++++ ldap-cesi/Services/ServiceService.cs | 9 +- ldap-cesi/Services/SiteService.cs | 8 + .../Salarie/SalarieCreateValidator.cs | 2 +- 22 files changed, 262 insertions(+), 211 deletions(-) diff --git a/ldap-cesi/Controllers/JwtController.cs b/ldap-cesi/Controllers/JwtController.cs index 55fad8d..b163375 100644 --- a/ldap-cesi/Controllers/JwtController.cs +++ b/ldap-cesi/Controllers/JwtController.cs @@ -1,4 +1,5 @@ using ldap_cesi.Services.Interfaces; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace ldap_cesi.Controllers; diff --git a/ldap-cesi/Controllers/ServicesController.cs b/ldap-cesi/Controllers/ServicesController.cs index 19ff669..2081b99 100644 --- a/ldap-cesi/Controllers/ServicesController.cs +++ b/ldap-cesi/Controllers/ServicesController.cs @@ -85,7 +85,7 @@ public class ServicesController : ControllerBase [Authorize(Roles = "admin")] public async Task DeleteService(int id) { - var result = await _serviceService.Delete(id); + var result = await _serviceService.DeleteWithEntiteCheck(id); 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 51f4ee4..bcb29c8 100644 --- a/ldap-cesi/Controllers/SiteController.cs +++ b/ldap-cesi/Controllers/SiteController.cs @@ -1,5 +1,6 @@ using ldap_cesi.DTOs.Inputs.Site; using ldap_cesi.Services.Interfaces; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace ldap_cesi.Controllers; @@ -63,6 +64,7 @@ public class SiteController : ControllerBase /// Les données du site à créer. /// Retourne l'identifiant du site créé. [HttpPost] + [Authorize(Roles = "admin")] public async Task CreateSite([FromBody] SiteCreateDto siteCreateDto) { var result = await _siteService.Create(siteCreateDto); @@ -76,6 +78,7 @@ public class SiteController : ControllerBase /// Les données du site à mettre à jour. /// Retourne l'objet ou une erreur. [HttpPut] + [Authorize(Roles = "admin")] public async Task UpdateSite([FromBody] SiteUpdateDto siteUpdateDto) { var result = await _siteService.Update(siteUpdateDto); @@ -89,9 +92,10 @@ public class SiteController : ControllerBase /// L'identifiant du site à supprimer. /// Retourne l'id, ou l'erreur [HttpDelete("{id}")] + [Authorize(Roles = "admin")] public async Task DeleteSite(int id) { - var result = await _siteService.Delete(id); + var result = await _siteService.DeleteWithEntiteCheck(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 660823d..0f747bd 100644 --- a/ldap-cesi/Controllers/UtilisateurController.cs +++ b/ldap-cesi/Controllers/UtilisateurController.cs @@ -1,3 +1,4 @@ +using System.Security.Claims; using ldap_cesi.DTOs.Inputs; using ldap_cesi.Services.Interfaces; using Microsoft.AspNetCore.Authorization; @@ -8,11 +9,12 @@ namespace ldap_cesi.Controllers; [Route("api/utilisateurs")] public class UtilisateurController : ControllerBase { - private IUtilisateurService _utilisateurService; - - public UtilisateurController(IUtilisateurService utilisateurService) + private readonly IUtilisateurService _utilisateurService; + private readonly IJwtService _jwtService; + public UtilisateurController(IUtilisateurService utilisateurService, IJwtService jwtService) { _utilisateurService = utilisateurService; + _jwtService = jwtService; } @@ -27,6 +29,80 @@ public class UtilisateurController : ControllerBase var result = await _utilisateurService.Login(utilisateurInput); return result.Success ? Ok(result) : BadRequest(result); } + + [HttpGet("me")] + [Authorize] + public async Task GetCurrentUser() + { + try { + // rçupère tous les claims de type NameIdentifier + var nameIdClaims = User.FindAll(ClaimTypes.NameIdentifier).ToList(); + + // cherche le claim qui contient un nombre entier + int userId = 0; + bool foundValidId = false; + + foreach (var claim in nameIdClaims) + { + if (int.TryParse(claim.Value, out userId)) + { + foundValidId = true; + break; + } + } + + if (!foundValidId) + { + return BadRequest(new { + Success = false, + Message = "Utilisateur non identifié. Aucun ID numérique trouvé." + }); + } + + // rçupère les informations utilisateur + var result = await _utilisateurService.GetById(userId); + return result.Success ? Ok(result) : BadRequest(result); + } + catch (Exception ex) { + return BadRequest(new { Success = false, Message = $"Erreur: {ex.Message}" }); + } + } + + /// + /// Endpoint pour déconnecter un utilisateur (invalider son token). + /// + /// Un statut indiquant que la déconnexion a réussi. + [HttpPost("logout")] + [Authorize] + public async Task Logout() + { + try + { + var authHeader = Request.Headers["Authorization"].ToString(); + if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer ")) + { + return BadRequest(new { Success = false, Message = "Token non fourni" }); + } + + var token = authHeader.Substring("Bearer ".Length).Trim(); + + // rendre le tokenm invalide + var result = await _jwtService.InvalidateToken(token); + + if (result) + { + return Ok(new { Success = true, Message = "Déconnexion réussie" }); + } + else + { + return BadRequest(new { Success = false, Message = "Échec de la déconnexion" }); + } + } + catch (Exception ex) + { + return StatusCode(500, new { Success = false, Message = "Erreur interne du serveur" }); + } + } /// /// Endpoint pour récupérer tous les utilisateurs. diff --git a/ldap-cesi/DTOs/Inputs/Salarie/SalarieCreateDto.cs b/ldap-cesi/DTOs/Inputs/Salarie/SalarieCreateDto.cs index 9842778..a8ca3e7 100644 --- a/ldap-cesi/DTOs/Inputs/Salarie/SalarieCreateDto.cs +++ b/ldap-cesi/DTOs/Inputs/Salarie/SalarieCreateDto.cs @@ -4,7 +4,7 @@ public class SalarieCreateDto { public string Nom { get; set; } public string Prenom { get; set; } - public string TelephoneFix { get; set; } + public string TelephoneFixe { get; set; } public string TelephonePortable { get; set; } public string Email { get; set; } public int IdSite { get; set; } diff --git a/ldap-cesi/Mapper/AutoMapperProfile.cs b/ldap-cesi/Mapper/AutoMapperProfile.cs index 3acd83e..d76b6cb 100644 --- a/ldap-cesi/Mapper/AutoMapperProfile.cs +++ b/ldap-cesi/Mapper/AutoMapperProfile.cs @@ -22,7 +22,7 @@ public class AutoMapperProfile : Profile CreateMap(); CreateMap(); CreateMap() - .ForMember(dest => dest.TelephoneFixe, opt => opt.MapFrom(src => src.TelephoneFix)) + .ForMember(dest => dest.TelephoneFixe, opt => opt.MapFrom(src => src.TelephoneFixe)) .ForMember(dest => dest.TelephonePortable, opt => opt.MapFrom(src => src.TelephonePortable)); CreateMap() .ForMember(dest => dest.TelephoneFixe, opt => opt.MapFrom(src => src.TelephoneFixe)) @@ -43,7 +43,10 @@ public class AutoMapperProfile : Profile CreateMap(); CreateMap() .ForMember(dest => dest.Salaries, opt => opt.MapFrom(src => src.Salaries)); - CreateMap(); + CreateMap() + .ForMember(dest => dest.Service, opt => opt.MapFrom(src => src.IdServiceNavigation)) + .ForMember(dest => dest.Site, opt => opt.MapFrom(src => src.IdSiteNavigation)); + CreateMap(); CreateMap(); CreateMap() .ForMember(dest => dest.Service, opt => opt.MapFrom(src => src.IdServiceNavigation.Nom)) diff --git a/ldap-cesi/Models/IResponseDataModel.cs b/ldap-cesi/Models/IResponseDataModel.cs index 5255852..1eb89dc 100644 --- a/ldap-cesi/Models/IResponseDataModel.cs +++ b/ldap-cesi/Models/IResponseDataModel.cs @@ -3,7 +3,5 @@ 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 index ae99066..cbdb15f 100644 --- a/ldap-cesi/Models/PaginatedList.cs +++ b/ldap-cesi/Models/PaginatedList.cs @@ -1,21 +1,22 @@ -namespace ldap_cesi.Models; - -public class PaginatedList +namespace ldap_cesi.Models { - 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) + public class PaginatedList { - Datas = donnees; - TotalCount = totalCount; - PageNumber = pageNumber; - PageSize = pageSize; - } + public List Data { get; } + public int TotalCount { get; } + public int PageNumber { get; } + public int PageSize { get; } + public int TotalPages => (int)Math.Ceiling((double)TotalCount / PageSize); - public bool HasPreviousPage => PageNumber > 1; - public bool HasNextPage => PageNumber < TotalPages; + public PaginatedList(List data, int totalCount, int pageNumber, int pageSize) + { + Data = data; + 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 220c124..973842a 100644 --- a/ldap-cesi/Models/ResponseDataModel.cs +++ b/ldap-cesi/Models/ResponseDataModel.cs @@ -5,4 +5,6 @@ public class ResponseDataModel : ResponseModel, IResponseDataModel where T public T Data { get; set; } = null!; public int? TotalPages { get; set; } public int? TotalCount { get; set; } + public int? PageNumber { get; set; } + public int? PageSize { get; set; } } \ No newline at end of file diff --git a/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs b/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs index baf4780..17e737d 100644 --- a/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs +++ b/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs @@ -20,6 +20,7 @@ public interface IRepositoryBase where TEntity : class int pageNumber = 1, int pageSize = 10, params Expression>[] relationsAInclude); + Task CountRelatedEntitiesAsync(int id, Expression> predicate) where TRelated : class; Task FirstOrDefaultAsync(Expression> predicate, CancellationToken cancellationToken = default); diff --git a/ldap-cesi/Repositories/RepositoryBase.cs b/ldap-cesi/Repositories/RepositoryBase.cs index 886ed2e..0b02212 100644 --- a/ldap-cesi/Repositories/RepositoryBase.cs +++ b/ldap-cesi/Repositories/RepositoryBase.cs @@ -132,28 +132,6 @@ public class RepositoryBase : IRepositoryBase where TEntity : } } - public virtual async Task> ListAsync(CancellationToken cancellationToken = default) - { - try - { - return await _context.Set().ToListAsync(cancellationToken); - } - catch (Exception ex) - { - throw new Exception("Erreur qui concerne le listing des entités", ex); - } - } - public virtual async Task> GetAllWithRelationsAsync(params Expression>[] relationInclues) - { - IQueryable query = _dbSet; - - foreach (var relationInclue in relationInclues) - { - query = query.Include(relationInclue); - } - - return await query.ToListAsync(); - } public virtual async Task GetWithRelationsAsync(int id, params Expression>[] relationInclues) { @@ -198,5 +176,9 @@ public class RepositoryBase : IRepositoryBase where TEntity : return await _dbSet.CountAsync(predicate, cancellationToken); } + public virtual async Task CountRelatedEntitiesAsync(int id, Expression> predicate) where TRelated : class + { + return await _context.Set().CountAsync(predicate); + } } \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/IJwtService.cs b/ldap-cesi/Services/Interfaces/IJwtService.cs index 1ba65ee..fcfbc88 100644 --- a/ldap-cesi/Services/Interfaces/IJwtService.cs +++ b/ldap-cesi/Services/Interfaces/IJwtService.cs @@ -7,4 +7,5 @@ public interface IJwtService string GenerateToken(Utilisateur utilisateur); string GetPublicKey(); Task ValidateToken(string token, int userId); + Task InvalidateToken(string token); } \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/ISalarieService.cs b/ldap-cesi/Services/Interfaces/ISalarieService.cs index 1cbff57..8386361 100644 --- a/ldap-cesi/Services/Interfaces/ISalarieService.cs +++ b/ldap-cesi/Services/Interfaces/ISalarieService.cs @@ -9,7 +9,9 @@ namespace ldap_cesi.Services.Interfaces; public interface ISalarieService : IServiceBase { - Task>> GetSalariesBySite(int siteId); - Task>> GetSalariesByService(int serviceId); - Task> GetCompletById(int id); + Task>> GetSalariesByService(int serviceId, int pageNumber = 1, + int pageSize = 25); + + Task>> GetSalariesBySite(int siteId, int pageNumber = 1, + int pageSize = 25); } \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/IServiceBase.cs b/ldap-cesi/Services/Interfaces/IServiceBase.cs index db8cb40..f11aef2 100644 --- a/ldap-cesi/Services/Interfaces/IServiceBase.cs +++ b/ldap-cesi/Services/Interfaces/IServiceBase.cs @@ -19,4 +19,5 @@ public interface IServiceBase Task> Create(TCreateDto dto); Task> Update(TUpdateDto dto); Task> Delete(int id); + Task> DeleteWithDependencyCheck(int id, Expression> relationPredicate, string relationErrorMessage) where TRelated : class; } \ No newline at end of file diff --git a/ldap-cesi/Services/Interfaces/IServiceService.cs b/ldap-cesi/Services/Interfaces/IServiceService.cs index 4cd3a7c..d509e38 100644 --- a/ldap-cesi/Services/Interfaces/IServiceService.cs +++ b/ldap-cesi/Services/Interfaces/IServiceService.cs @@ -7,5 +7,6 @@ namespace ldap_cesi.Services.Interfaces { public interface IServiceService : IServiceBase { + Task> DeleteWithEntiteCheck(int id); } } diff --git a/ldap-cesi/Services/Interfaces/ISiteService.cs b/ldap-cesi/Services/Interfaces/ISiteService.cs index 4c99e84..08e3b93 100644 --- a/ldap-cesi/Services/Interfaces/ISiteService.cs +++ b/ldap-cesi/Services/Interfaces/ISiteService.cs @@ -7,9 +7,5 @@ namespace ldap_cesi.Services.Interfaces; public interface ISiteService : IServiceBase { - // Task>> GetAll(); - // Task> GetById(int id); - // Task> CreateSite(SiteCreateDto siteCreateDto); - // Task> UpdateSite(SiteUpdateDto siteUpdate); - // Task> DeleteSite(int id); + Task> DeleteWithEntiteCheck(int id); } \ No newline at end of file diff --git a/ldap-cesi/Services/JwtService.cs b/ldap-cesi/Services/JwtService.cs index 8ef0ec2..8464c4b 100644 --- a/ldap-cesi/Services/JwtService.cs +++ b/ldap-cesi/Services/JwtService.cs @@ -78,6 +78,47 @@ public class JwtService : IJwtService throw; } } + + // Ajouter cette méthode à votre JwtService.cs + public async Task InvalidateToken(string token) + { + try + { + var tokenHandler = new JwtSecurityTokenHandler(); + + // récupération du token + var jwtToken = tokenHandler.ReadJwtToken(token); + + // identifiant de l'utilisateur + var userIdClaim = jwtToken.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier); + + if (userIdClaim == null || !int.TryParse(userIdClaim.Value, out var userId)) + { + _logger.LogWarning("Erreur d'invalidation du token : Id utilisateur non trouvé ou invalide."); + return false; + } + + var utilisateur = await _context.Utilisateurs.FindAsync(userId); + if (utilisateur == null) + { + _logger.LogWarning("Erreur d'invalidation du token : Utilisateur non trouvé."); + return false; + } + + // delte le token stocké + utilisateur.AccessToken = null; + _context.Utilisateurs.Update(utilisateur); + await _context.SaveChangesAsync(); + + _logger.LogInformation($"Token invalidé pour l'utilisateur {userId}."); + return true; + } + catch (Exception ex) + { + _logger.LogError(ex, "Une erreur s'est produite pendant l'invalidation du token JWT."); + return false; + } + } public async Task ValidateToken(string token, int userId) { diff --git a/ldap-cesi/Services/SalarieService.cs b/ldap-cesi/Services/SalarieService.cs index 31b551f..c339300 100644 --- a/ldap-cesi/Services/SalarieService.cs +++ b/ldap-cesi/Services/SalarieService.cs @@ -27,25 +27,13 @@ public class SalarieService : ServiceBase> GetCompletById(int id) - { - var salarie = await _repositorySalarie.GetSalarieWithRelationsAsync(id); - var salarieOutput = _mapper.Map(salarie); - return new ResponseDataModel - { - Success = true, - Data = salarieOutput, - StatusCode = 200, - }; - } - public async Task>> GetSalariesBySite(int siteId) + public async Task>> GetSalariesBySite(int siteId, int pageNumber = 1, int pageSize = 25) { var site = await _repositorySite.GetByIdAsync(siteId); if (site == null) { - return new ResponseDataModel> + return new ResponseDataModel> { Success = false, Message = "Site non trouvé", @@ -54,33 +42,32 @@ public class SalarieService : ServiceBase> - { - Success = true, - Message = "Aucun salarié trouvé pour ce site", - Data = new List(), - StatusCode = 200 - }; - } + var totalCount = salaries.Count; + var paginatedSalaries = salaries + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize) + .ToList(); - var salariesDto = _mapper.Map>(salaries); - - return new ResponseDataModel> + var salariesDto = _mapper.Map>(paginatedSalaries); + + return new ResponseDataModel> { Success = true, Data = salariesDto, + TotalPages = (int)Math.Ceiling((double)totalCount / pageSize), + TotalCount = totalCount, + PageNumber = pageNumber, + PageSize = pageSize, StatusCode = 200 }; } - public async Task>> GetSalariesByService(int serviceId) + public async Task>> GetSalariesByService(int serviceId, int pageNumber = 1, int pageSize = 25) { var service = await _repositoryService.GetByIdAsync(serviceId); if (service == null) { - return new ResponseDataModel> + return new ResponseDataModel> { Success = false, Message = "Service non trouvé", @@ -89,132 +76,23 @@ public class SalarieService : ServiceBase>(salaries); - - return new ResponseDataModel> + var totalCount = salaries.Count; + var paginatedSalaries = salaries + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize) + .ToList(); + + var salariesDto = _mapper.Map>(paginatedSalaries); + + return new ResponseDataModel> { Success = true, - Data = salariesDto, + Data = salariesDto, // Les salariés paginés + TotalPages = (int)Math.Ceiling((double)totalCount / pageSize), + TotalCount = totalCount, + PageNumber = pageNumber, + PageSize = pageSize, StatusCode = 200 }; } - - public async Task>> RechercherParNom(string nom) - { - var salaries = await _repositorySalarie.SearchByNameAsync(nom); - var salariesDto = _mapper.Map>(salaries); - - return new ResponseDataModel> - { - Success = true, - Data = salariesDto, - StatusCode = 200 - }; - } - - // public async Task> Create(SalarieCreateDto salarieInput) - // { - // var validation = new SalarieCreateValidator(); - // var result = validation.Validate(salarieInput); - // if (!result.IsValid) - // { - // return new ResponseDataModel - // { - // StatusCode = 400, - // Success = false, - // Message = "Données salariées invalides: " + string.Join(", ", result.Errors) - // }; - // } - // var service = _mapper.Map(salarieInput); - // var response = await _repositorySalarie.AddAsync(service); - // return new ResponseDataModel - // { - // StatusCode = 201, - // Success = true, - // Data = response.Id.ToString(), - // }; - // } - - // public async Task> Update(SalarieUpdateDto salarieInput) - // { - // var validation = new SalarieUpdateValidator(); - // var result = validation.Validate(salarieInput); - // if (!result.IsValid) - // { - // return new ResponseDataModel - // { - // StatusCode = 400, - // Success = false, - // Message = "Données salariées invalides: " + string.Join(", ", result.Errors) - // }; - // } - - // var salarieFind = await _repositorySalarie.GetByIdAsync(salarieInput.Id); - // if (salarieFind == null) - // { - // return new ResponseDataModel - // { - // Success = false, - // Message = "Salarié introuvable.", - // StatusCode = 404 - // }; - // } - - // var salarie = _mapper.Map(salarieInput, salarieFind); - // var response = await _repositorySalarie.UpdateAsync(salarie); - // if (!response) - // { - // return new ResponseDataModel - // { - // StatusCode = 500, - // Success = false, - // Message = "Erreur lors de la mise à jour du salarié : " + string.Join(", ", result.Errors) - // }; - // } - // return new ResponseDataModel - // { - // StatusCode = 200, - // Success = true, - // Data = salarie, - // }; - // } - - // public async Task> Delete(int id) - // { - // if (id == null) - // { - // return new ResponseDataModel - // { - // StatusCode = 400, - // Success = false, - // Message = "Id manquant" - // }; - // } - // var salarie = await _repositorySalarie.GetByIdAsync(id); - // if (salarie == null) - // { - // return new ResponseDataModel - // { - // Success = false, - // Message = "Salarié introuvable.", - // StatusCode = 404 - // }; - // } - // var response = await _repositorySalarie.DeleteAsync(salarie); - // if (!response) - // { - // return new ResponseDataModel - // { - // StatusCode = 500, - // Success = false, - // Message = "Erreur durant la suppression du service" - // }; - // } - // return new ResponseDataModel - // { - // StatusCode = 200, - // Success = true, - // Data = salarie.Id.ToString(), - // }; - // } } \ No newline at end of file diff --git a/ldap-cesi/Services/ServiceBase.cs b/ldap-cesi/Services/ServiceBase.cs index 20908ea..a8a72c1 100644 --- a/ldap-cesi/Services/ServiceBase.cs +++ b/ldap-cesi/Services/ServiceBase.cs @@ -308,5 +308,53 @@ public class ServiceBase : IServiceBase> DeleteWithDependencyCheck(int id, Expression> relationPredicate, string relationErrorMessage) where TRelated : class + { + try + { + var entity = await _repository.GetByIdAsync(id); + if (entity == null) + { + return new ResponseDataModel + { + Success = false, + Message = $"Aucune entité trouvée avec l'identifiant {id}.", + StatusCode = 404 + }; + } + + // Vérifier si des entités dépendantes existent + var relatedCount = await (_repository as IRepositoryBase).CountRelatedEntitiesAsync(id, relationPredicate); + if (relatedCount > 0) + { + return new ResponseDataModel + { + Success = false, + Message = relationErrorMessage, + StatusCode = 400 + }; + } + + var isDeleted = await _repository.DeleteAsync(entity); + return new ResponseDataModel + { + Success = isDeleted, + Data = isDeleted ? id.ToString() : null, + StatusCode = isDeleted ? 200 : 500, + Message = isDeleted ? "Entité supprimée avec succès." : "Échec de la suppression de l'entité." + }; + } + catch (Exception ex) + { + _logger.LogError(ex, $"Une erreur s'est produite lors de la suppression de l'entité avec l'identifiant {id}."); + return new ResponseDataModel + { + Success = false, + Message = "Une erreur s'est produite lors de la suppression de l'entité.", + StatusCode = 500 + }; + } + } } \ No newline at end of file diff --git a/ldap-cesi/Services/ServiceService.cs b/ldap-cesi/Services/ServiceService.cs index 193fe2c..b2dae4b 100644 --- a/ldap-cesi/Services/ServiceService.cs +++ b/ldap-cesi/Services/ServiceService.cs @@ -17,7 +17,14 @@ public class ServiceService : ServiceBase> DeleteWithEntiteCheck(int id) + { + return await DeleteWithDependencyCheck( + id, + salarie => salarie.IdServiceNavigation.Id == id, + "Impossible de supprimer ce service car des salariés y sont affectés." + ); + } // public async Task>> GetAll() // { diff --git a/ldap-cesi/Services/SiteService.cs b/ldap-cesi/Services/SiteService.cs index 246fb98..441fd6e 100644 --- a/ldap-cesi/Services/SiteService.cs +++ b/ldap-cesi/Services/SiteService.cs @@ -20,6 +20,14 @@ public class SiteService : ServiceBase> DeleteWithEntiteCheck(int id) + { + return await DeleteWithDependencyCheck( + id, + salarie => salarie.IdSiteNavigation.Id == id, + "Impossible de supprimer ce site car des salariés y sont affectés." + ); + } // public async Task>> GetAll() // { diff --git a/ldap-cesi/Validator/Salarie/SalarieCreateValidator.cs b/ldap-cesi/Validator/Salarie/SalarieCreateValidator.cs index c23c02a..d07721f 100644 --- a/ldap-cesi/Validator/Salarie/SalarieCreateValidator.cs +++ b/ldap-cesi/Validator/Salarie/SalarieCreateValidator.cs @@ -15,7 +15,7 @@ public class SalarieCreateValidator : AbstractValidator .NotEmpty().WithMessage("Le prénom est requis.") .MaximumLength(50).WithMessage("Le prénom ne doit pas dépasser 50 caractères."); - RuleFor(x => x.TelephoneFix) + RuleFor(x => x.TelephoneFixe) .NotEmpty().WithMessage("Le téléphone fixe est requis.") .Matches(@"^(\+33|0)[1-9](\d{2}){4}$") .WithMessage("Le numéro de téléphone fixe n'est pas valide. Format attendu : +33XXXXXXXXX ou 0XXXXXXXXX.") From 00f09a98f0b5202ad20b88bb0297d378971efa5d Mon Sep 17 00:00:00 2001 From: BuzzLeclair Date: Sat, 15 Mar 2025 20:35:59 +0100 Subject: [PATCH 17/17] =?UTF-8?q?-=20Ajout=20d'une=20fonction=20pour=20r?= =?UTF-8?q?=C3=A9cup=C3=A9rer=20le=20r=C3=B4le=20de=20l'utilisateur=20-=20?= =?UTF-8?q?Clean=20du=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Interfaces/IRepositoryUtilisateur.cs | 1 + .../Repositories/UtilisateurRepository.cs | 9 +- ldap-cesi/Services/ServiceService.cs | 130 +--------------- ldap-cesi/Services/SiteService.cs | 143 +----------------- ldap-cesi/Services/UtilisateurService.cs | 2 +- 5 files changed, 19 insertions(+), 266 deletions(-) diff --git a/ldap-cesi/Repositories/Interfaces/IRepositoryUtilisateur.cs b/ldap-cesi/Repositories/Interfaces/IRepositoryUtilisateur.cs index e05950f..dcecf23 100644 --- a/ldap-cesi/Repositories/Interfaces/IRepositoryUtilisateur.cs +++ b/ldap-cesi/Repositories/Interfaces/IRepositoryUtilisateur.cs @@ -5,4 +5,5 @@ namespace ldap_cesi.Repository.Services; public interface IRepositoryUtilisateur : IRepositoryBase { Task GetByEmailAsync(string email); + Task GetByIdIncludeRoleAsync(int id); } \ No newline at end of file diff --git a/ldap-cesi/Repositories/UtilisateurRepository.cs b/ldap-cesi/Repositories/UtilisateurRepository.cs index 0cf84cf..a86435c 100644 --- a/ldap-cesi/Repositories/UtilisateurRepository.cs +++ b/ldap-cesi/Repositories/UtilisateurRepository.cs @@ -14,7 +14,14 @@ public class UtilisateurRepository : RepositoryBase, IRepositoryUti public async Task GetByEmailAsync(string email) { - return await _context.Utilisateurs.Include(u => u.IdRoleNavigation) + return await _context.Utilisateurs + .Include(u => u.IdRoleNavigation) .FirstOrDefaultAsync(u => u.Email == email); } + public async Task GetByIdIncludeRoleAsync(int id) + { + return await _context.Utilisateurs + .Include(u => u.IdRoleNavigation) + .FirstOrDefaultAsync(u => u.Id == id); + } } \ No newline at end of file diff --git a/ldap-cesi/Services/ServiceService.cs b/ldap-cesi/Services/ServiceService.cs index b2dae4b..fd8de3a 100644 --- a/ldap-cesi/Services/ServiceService.cs +++ b/ldap-cesi/Services/ServiceService.cs @@ -22,135 +22,7 @@ public class ServiceService : ServiceBase( id, salarie => salarie.IdServiceNavigation.Id == id, - "Impossible de supprimer ce service car des salariés y sont affectés." + "il n'est pas possible de supprimer ce service car des salariés y sont liés" ); } - - // public async Task>> GetAll() - // { - // var services = await _repositoryService.GetAllAsync(); - // return new ResponseDataModel> - // { - // Success = true, - // Data = services, - // StatusCode = 200, - // }; - // } - - // public async Task> GetById(int id) - // { - // var service = await _repositoryService.GetByIdAsync(id); - // return new ResponseDataModel - // { - // Success = true, - // Data = service, - // StatusCode = 200, - // }; - // } - - // public async Task> CreateService(ServiceCreateDto serviceCreateDto) - // { - // var validation = new ServiceCreateValidator(); - // var result = validation.Validate(serviceCreateDto); - // if (!result.IsValid) - // { - // return new ResponseDataModel - // { - // StatusCode = 400, - // Success = false, - // Message = "Données du service invalides: " + string.Join(", ", result.Errors) - // }; - // } - // var service = _mapper.Map(serviceCreateDto); - // var response = await _repositoryService.AddAsync(service); - // return new ResponseDataModel - // { - // StatusCode = 201, - // Success = true, - // Data = response.Id.ToString(), - // }; - // } - - // public async Task> UpdateService(ServiceUpdateDto serviceUpdateDto) - // { - // var validation = new ServiceUpdateValidator(); - // var result = validation.Validate(serviceUpdateDto); - // if (!result.IsValid) - // { - // return new ResponseDataModel - // { - // StatusCode = 400, - // Success = false, - // Message = "Données du service invalides: " + string.Join(", ", result.Errors) - // }; - // } - // var serviceFind = await _repositoryService.GetByIdAsync(serviceUpdateDto.Id); - // if (serviceFind is null) - // { - // return new ResponseDataModel - // { - // Success = false, - // Message = "Service introuvable.", - // StatusCode = 404 - // }; - // } - - // var service = _mapper.Map(serviceUpdateDto, serviceFind); - // var response = await _repositoryService.UpdateAsync(service); - // if (!response) - // { - // return new ResponseDataModel - // { - // StatusCode = 500, - // Success = false, - // Message = "Erreur lors de la mise à jour du service : " + string.Join(", ", result.Errors) - // }; - // } - // return new ResponseDataModel - // { - // StatusCode = 200, - // Success = true, - // Data = service, - // }; - // } - - // public async Task> DeleteService(int idService) - // { - // if (idService == null) - // { - // return new ResponseDataModel - // { - // StatusCode = 400, - // Success = false, - // Message = "Id manquant" - // }; - // } - - // var service = await _repositoryService.GetByIdAsync(idService); - // if (service == null) - // { - // return new ResponseDataModel - // { - // Success = false, - // Message = "Service introuvable.", - // StatusCode = 404 - // }; - // } - // var response = await _repositoryService.DeleteAsync(service); - // if (!response) - // { - // return new ResponseDataModel - // { - // StatusCode = 500, - // Success = false, - // Message = "Erreur durant la suppression du service" - // }; - // } - // return new ResponseDataModel - // { - // StatusCode = 200, - // Success = true, - // Data = service.Id.ToString(), - // }; - // } } \ No newline at end of file diff --git a/ldap-cesi/Services/SiteService.cs b/ldap-cesi/Services/SiteService.cs index 441fd6e..f5c99dc 100644 --- a/ldap-cesi/Services/SiteService.cs +++ b/ldap-cesi/Services/SiteService.cs @@ -14,146 +14,19 @@ public class SiteService : ServiceBase logger, SiteCreateValidator siteCreateValidator, SiteUpdateValidator siteUpdateValidator) - : base(repositorySite, mapper, logger, siteCreateValidator, siteUpdateValidator ) - { + public SiteService(IRepositorySite repositorySite, IMapper mapper, + ILogger logger, SiteCreateValidator siteCreateValidator, SiteUpdateValidator siteUpdateValidator) + : base(repositorySite, mapper, logger, siteCreateValidator, siteUpdateValidator) + { _repositorySite = repositorySite; } + public async Task> DeleteWithEntiteCheck(int id) { return await DeleteWithDependencyCheck( - id, + id, salarie => salarie.IdSiteNavigation.Id == id, - "Impossible de supprimer ce site car des salariés y sont affectés." + "il n'est pas possible de supprimer ce site car des salariés y sont liés" ); } - - // 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> 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 364b5f8..d18ff73 100644 --- a/ldap-cesi/Services/UtilisateurService.cs +++ b/ldap-cesi/Services/UtilisateurService.cs @@ -34,7 +34,7 @@ public class UtilisateurService : IUtilisateurService public async Task> GetById(int id) { - var utililisateur = await _repositoryUtilisateur.GetByIdAsync(id); + var utililisateur = await _repositoryUtilisateur.GetByIdIncludeRoleAsync(id); var utilisateurOutput = _mapper.Map(utililisateur); return new ResponseDataModel {