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/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/.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..35eb1dd
--- /dev/null
+++ b/.idea/.idea.ldap-cesi/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ 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/Configurations/Conf.cs b/ldap-cesi/Configurations/Conf.cs
new file mode 100644
index 0000000..b7bd501
--- /dev/null
+++ b/ldap-cesi/Configurations/Conf.cs
@@ -0,0 +1,148 @@
+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;
+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;
+
+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();
+ builder.Services.AddValidatorsFromAssemblyContaining();
+ builder.Services.AddFluentValidationAutoValidation();
+ }
+ 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("AllowSpecific",
+ builder => builder
+ .WithOrigins("http://localhost:3000")
+ .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
new file mode 100644
index 0000000..fc8c4c3
--- /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 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.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)
+ .OnDelete(DeleteBehavior.ClientSetNull)
+ .HasConstraintName("utilisateur_role_fk");
+ });
+
+ OnModelCreatingPartial(modelBuilder);
+ }
+
+ partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
+}
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..b163375
--- /dev/null
+++ b/ldap-cesi/Controllers/JwtController.cs
@@ -0,0 +1,29 @@
+using ldap_cesi.Services.Interfaces;
+using Microsoft.AspNetCore.Authorization;
+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/RoleController.cs b/ldap-cesi/Controllers/RoleController.cs
new file mode 100644
index 0000000..213995f
--- /dev/null
+++ b/ldap-cesi/Controllers/RoleController.cs
@@ -0,0 +1,88 @@
+using Microsoft.AspNetCore.Mvc;
+using ldap_cesi.DTOs.Inputs.Role;
+using ldap_cesi.Services.Interfaces;
+using Microsoft.AspNetCore.Authorization;
+
+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
+ ///
+ /// Endpoint qui retourne tous les rôles
+ ///
+ /// Un tableau de rôle
+ [HttpGet]
+ [Authorize(Roles = "admin")]
+ public async Task GetAllRoles([FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 10)
+ {
+ var result = await _roleService.GetAll(pageNumber, pageSize);
+ return result.Success ? Ok(result) : BadRequest(result);
+ }
+
+ // 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);
+ return result.Success ? Ok(result) : BadRequest(result);
+ }
+
+ // 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);
+ return result.Success ? Ok(result) : BadRequest(result);
+ }
+
+ // 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)
+ {
+ var result = await _roleService.Update(roleDto);
+ return result.Success ? Ok(result) : BadRequest(result);
+ }
+
+ // 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);
+ return result.Success ? Ok(result) : BadRequest(result);
+ }
+ }
+}
diff --git a/ldap-cesi/Controllers/SalarieController.cs b/ldap-cesi/Controllers/SalarieController.cs
new file mode 100644
index 0000000..1f831a6
--- /dev/null
+++ b/ldap-cesi/Controllers/SalarieController.cs
@@ -0,0 +1,146 @@
+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;
+[ApiController]
+[Route("api/salaries")]
+public class SalarieController : ControllerBase
+{
+ private ISalarieService _salarieService;
+
+ public SalarieController(ISalarieService salarieService)
+ {
+ _salarieService = salarieService;
+ }
+
+ ///
+ /// Endpoint qui retourne tous les salariés.
+ ///
+ /// Une liste de salariés.
+ [HttpGet]
+ public async Task GetAllSalaries([FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 25)
+ {
+ var result = await _salarieService.GetAll(pageNumber, pageSize);
+ return result.Success ? Ok(result) : BadRequest(result);
+ }
+
+
+ [HttpGet("search")]
+ public async Task SearchSalaries(
+ [FromQuery] string searchTerm,
+ [FromQuery] int pageNumber = 1,
+ [FromQuery] int pageSize = 10)
+ {
+ if (string.IsNullOrWhiteSpace(searchTerm) || searchTerm.Length < 2)
+ {
+ return BadRequest("Votre recherche doit contenir au moins deux caractères.");
+ }
+
+ var result = await _salarieService.SearchWithRelations(
+ searchTerm, pageNumber, pageSize, s => s.IdServiceNavigation, s => s.IdSiteNavigation);
+
+ return result.Success ? Ok(result) : BadRequest(result);
+ }
+
+ ///
+ /// Endpoint qui retourne le salarié correspondant à l'ID en paramètre.
+ ///
+ /// L'ID du salarié.
+ /// Le salarié correspondant à l'ID.
+ [HttpGet("{id}")]
+ public async Task GetById(int id)
+ {
+ var result = await _salarieService.GetById(id);
+ return result.Success ? Ok(result) : BadRequest(result);
+ }
+
+ ///
+ /// Endpoint qui retourne le salarié correspondant à l'ID en paramètre. Avec le nom de service et de site auxquels il apaprtient.
+ ///
+ /// L'ID du salarié.
+ /// Le salarié correspondant à l'ID. Ainsi que son service et son site
+ [HttpGet("/complet/{id}")]
+ public async Task GetSalarieCompletById(int id)
+ {
+ var result = await _salarieService.GetByIdWithRelations(id,s => s.IdServiceNavigation, s => s.IdSiteNavigation);
+ return result.Success ? Ok(result) : BadRequest(result);
+ }
+
+ ///
+ /// 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([FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 25)
+ {
+ var result = await _salarieService.GetAllWithRelationsAsync(pageNumber, pageSize,s => s.IdServiceNavigation, s => s.IdSiteNavigation);
+ return result.Success ? Ok(result) : BadRequest(result);
+ }
+
+ ///
+ /// 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) : BadRequest(result);
+ }
+
+ ///
+ /// 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) : BadRequest(result);
+ }
+
+ ///
+ /// 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) : BadRequest(result);
+ }
+
+ ///
+ /// 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) : NotFound(result);
+ }
+
+ ///
+ /// 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) : NotFound(result);
+ }
+
+}
diff --git a/ldap-cesi/Controllers/ServicesController.cs b/ldap-cesi/Controllers/ServicesController.cs
new file mode 100644
index 0000000..2081b99
--- /dev/null
+++ b/ldap-cesi/Controllers/ServicesController.cs
@@ -0,0 +1,91 @@
+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/services")]
+public class ServicesController : ControllerBase
+{
+ private IServiceService _serviceService;
+
+ public ServicesController(IServiceService serviceService)
+ {
+ _serviceService = serviceService;
+ }
+
+ ///
+ /// Endpoint qui retourne tous les services.
+ ///
+ /// Retourne tous les services.
+ [HttpGet]
+ 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);
+ }
+
+ ///
+ /// Endpoint qui retourne le service correspondant à l'id en paramètre.
+ ///
+ /// L'ID du service.
+ /// Le service correspondant à l'ID.
+ [HttpGet("{id}")]
+ public async Task GetServiceById(int id)
+ {
+ var result = await _serviceService.GetById(id);
+ return result.Success ? Ok(result) : BadRequest(result);
+ }
+
+ ///
+ /// Endpoint qui retourne le service et ses salariés correspondant à l'id en paramètre.
+ ///
+ /// L'ID du service.
+ /// Le service correspondant à l'ID, avec ses salariés
+ [HttpGet("complete/{id}")]
+ public async Task GetServiceByIdWithSalaries(int id)
+ {
+ var result = await _serviceService.GetByIdWithRelations(id, s=>s.Salaries);
+ return result.Success ? Ok(result) : BadRequest(result);
+ }
+
+ ///
+ /// Endpoint qui crée un service.
+ ///
+ /// Les informations du service à créer.
+ /// Le service créé.
+ [HttpPost]
+ [Authorize(Roles = "admin")]
+ public async Task CreateService([FromBody] ServiceCreateDto serviceInputDto)
+ {
+ var result = await _serviceService.Create(serviceInputDto);
+ return result.Success ? Ok(result.Data) : BadRequest(result);
+ }
+
+ ///
+ /// 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.Update(serviceUpdateDto);
+ return result.Success ? Ok(result) : BadRequest(result);
+ }
+
+ ///
+ /// 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.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
new file mode 100644
index 0000000..bcb29c8
--- /dev/null
+++ b/ldap-cesi/Controllers/SiteController.cs
@@ -0,0 +1,101 @@
+using ldap_cesi.DTOs.Inputs.Site;
+using ldap_cesi.Services.Interfaces;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace ldap_cesi.Controllers;
+
+[ApiController]
+[Route("/api/sites")]
+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([FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 10)
+ {
+ var result = await _siteService.GetAll(pageNumber, pageSize);
+ 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);
+ }
+
+ // 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
+ ///
+ /// Crée un nouveau site.
+ ///
+ /// 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);
+ 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]
+ [Authorize(Roles = "admin")]
+ public async Task UpdateSite([FromBody] SiteUpdateDto siteUpdateDto)
+ {
+ var result = await _siteService.Update(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}")]
+ [Authorize(Roles = "admin")]
+ public async Task DeleteSite(int 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
new file mode 100644
index 0000000..0f747bd
--- /dev/null
+++ b/ldap-cesi/Controllers/UtilisateurController.cs
@@ -0,0 +1,131 @@
+using System.Security.Claims;
+using ldap_cesi.DTOs.Inputs;
+using ldap_cesi.Services.Interfaces;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace ldap_cesi.Controllers;
+[ApiController]
+[Route("api/utilisateurs")]
+public class UtilisateurController : ControllerBase
+{
+ private readonly IUtilisateurService _utilisateurService;
+ private readonly IJwtService _jwtService;
+ public UtilisateurController(IUtilisateurService utilisateurService, IJwtService jwtService)
+ {
+ _utilisateurService = utilisateurService;
+ _jwtService = jwtService;
+ }
+
+
+ ///
+ /// 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 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.
+ ///
+ /// Une liste d'utilisateurs.
+ [HttpGet]
+ [Authorize(Roles = "admin")]
+ public async Task GetUtilisateurs()
+ {
+ var result = await _utilisateurService.GetAll();
+ return result.Success ? Ok(result) : BadRequest(result);
+ }
+
+ ///
+ /// Endpoint pour récupérer un utilisateur par son ID.
+ ///
+ /// L'ID de l'utilisateur.
+ /// L'utilisateur correspondant à l'ID.
+ [HttpGet("{id}")]
+ [Authorize(Roles = "admin")]
+ 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/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/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/DTOs/Generic/ServiceDto.cs b/ldap-cesi/DTOs/Generic/ServiceDto.cs
new file mode 100644
index 0000000..61f567b
--- /dev/null
+++ b/ldap-cesi/DTOs/Generic/ServiceDto.cs
@@ -0,0 +1,11 @@
+using ldap_cesi.DTOs.Outputs.Salarie;
+
+namespace ldap_cesi.DTOs;
+
+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
new file mode 100644
index 0000000..535f886
--- /dev/null
+++ b/ldap-cesi/DTOs/Generic/SiteDto.cs
@@ -0,0 +1,11 @@
+using ldap_cesi.DTOs.Outputs.Salarie;
+
+namespace ldap_cesi.DTOs;
+
+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/Inputs/Role/RoleCreateDto.cs b/ldap-cesi/DTOs/Inputs/Role/RoleCreateDto.cs
new file mode 100644
index 0000000..e11af07
--- /dev/null
+++ b/ldap-cesi/DTOs/Inputs/Role/RoleCreateDto.cs
@@ -0,0 +1,7 @@
+
+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/DTOs/Inputs/Salarie/SalarieCreateDto.cs b/ldap-cesi/DTOs/Inputs/Salarie/SalarieCreateDto.cs
new file mode 100644
index 0000000..a8ca3e7
--- /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 TelephoneFixe { get; set; }
+ public string TelephonePortable { 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/Salarie/SalarieListDto.cs b/ldap-cesi/DTOs/Outputs/Salarie/SalarieListDto.cs
new file mode 100644
index 0000000..0615eaa
--- /dev/null
+++ b/ldap-cesi/DTOs/Outputs/Salarie/SalarieListDto.cs
@@ -0,0 +1,14 @@
+using ldap_cesi.DTOs.Outputs.Service;
+
+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 ServiceMinimalDto Service { get; set; }
+ public SiteMinimalDto Site { get; set; }
+}
\ No newline at end of file
diff --git a/ldap-cesi/DTOs/Outputs/Salarie/SalarieMinimalDto.cs b/ldap-cesi/DTOs/Outputs/Salarie/SalarieMinimalDto.cs
new file mode 100644
index 0000000..bf4be29
--- /dev/null
+++ b/ldap-cesi/DTOs/Outputs/Salarie/SalarieMinimalDto.cs
@@ -0,0 +1,17 @@
+namespace ldap_cesi.DTOs.Outputs.Salarie;
+
+public class SalarieMinimalDto
+{
+ public int Id { get; set; }
+
+ public string Nom { get; set; } = null!;
+
+ public string Prenom { get; set; } = null!;
+
+ public string TelephoneFixe { get; set; } = null!;
+
+ public string TelephonePortable { get; set; } = null!;
+
+ public string Email { get; set; } = null!;
+
+}
\ No newline at end of file
diff --git a/ldap-cesi/DTOs/Outputs/Salarie/SalarieOutputDetail.cs b/ldap-cesi/DTOs/Outputs/Salarie/SalarieOutputDetail.cs
new file mode 100644
index 0000000..f7b1bd3
--- /dev/null
+++ b/ldap-cesi/DTOs/Outputs/Salarie/SalarieOutputDetail.cs
@@ -0,0 +1,21 @@
+using ldap_cesi.DTOs.Outputs.Service;
+
+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 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/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/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..1ed7f2a
--- /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..9037a5c
--- /dev/null
+++ b/ldap-cesi/Entities/Utilisateur.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations.Schema;
+
+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 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..d76b6cb
--- /dev/null
+++ b/ldap-cesi/Mapper/AutoMapperProfile.cs
@@ -0,0 +1,55 @@
+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;
+using ldap_cesi.DTOs.Outputs.Salarie;
+using ldap_cesi.DTOs.Outputs.Service;
+using ldap_cesi.DTOs.Outputs.Utilisateur;
+using ldap_cesi.Entities;
+
+namespace ldap_cesi.Mapper;
+
+public class AutoMapperProfile : Profile
+{
+ public AutoMapperProfile()
+ {
+ // INPUTS MAPPER
+ CreateMap();
+ CreateMap();
+ CreateMap();
+ CreateMap();
+ CreateMap();
+ CreateMap()
+ .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))
+ .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()
+ .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()
+ .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))
+ .ForMember(dest => dest.Site, opt => opt.MapFrom(src => src.IdSiteNavigation.Ville));
+ }
+}
\ 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/PaginatedList.cs b/ldap-cesi/Models/PaginatedList.cs
new file mode 100644
index 0000000..cbdb15f
--- /dev/null
+++ b/ldap-cesi/Models/PaginatedList.cs
@@ -0,0 +1,22 @@
+namespace ldap_cesi.Models
+{
+ public class PaginatedList
+ {
+ 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 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
new file mode 100644
index 0000000..973842a
--- /dev/null
+++ b/ldap-cesi/Models/ResponseDataModel.cs
@@ -0,0 +1,10 @@
+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; }
+ public int? PageNumber { get; set; }
+ public int? PageSize { 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..2173782
--- /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? Token { 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
new file mode 100644
index 0000000..0974d7a
--- /dev/null
+++ b/ldap-cesi/Program.cs
@@ -0,0 +1,44 @@
+using ldap_cesi.Configurations;
+using ldap_cesi.Context;
+using ldap_cesi.Seeders;
+
+var builder = WebApplication.CreateBuilder(args);
+builder.BuildConf();
+var app = builder.Build();
+
+// Configure the HTTP request pipeline.
+if (app.Environment.IsDevelopment())
+{
+ app.UseSwagger();
+ app.UseSwaggerUI();
+
+ app.Use(async (context, next) =>
+ {
+ if (context.Request.Path == "/")
+ {
+ context.Response.Redirect("/swagger");
+ return;
+ }
+ await next();
+ });
+}
+
+using (var scope = app.Services.CreateScope())
+{
+ var services = scope.ServiceProvider;
+ var context = services.GetRequiredService();
+ var seeder = new Seeders(context);
+
+ if (app.Environment.IsDevelopment())
+ {
+ await seeder.GenerateSalaries(500);
+ }
+}
+
+app.UseHttpsRedirection();
+app.UseRouting();
+app.UseCors("AllowAll");
+app.UseAuthentication();
+app.UseAuthorization();
+app.MapControllers();
+app.Run();
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/Repositories/Interfaces/IRepositoryBase.cs b/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs
new file mode 100644
index 0000000..17e737d
--- /dev/null
+++ b/ldap-cesi/Repositories/Interfaces/IRepositoryBase.cs
@@ -0,0 +1,29 @@
+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<(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<(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 CountRelatedEntitiesAsync(int id, Expression> predicate) where TRelated : class;
+
+ 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/Interfaces/IRepositoryRole.cs b/ldap-cesi/Repositories/Interfaces/IRepositoryRole.cs
new file mode 100644
index 0000000..e504b27
--- /dev/null
+++ b/ldap-cesi/Repositories/Interfaces/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/Repositories/Interfaces/IRepositorySalarie.cs b/ldap-cesi/Repositories/Interfaces/IRepositorySalarie.cs
new file mode 100644
index 0000000..410c326
--- /dev/null
+++ b/ldap-cesi/Repositories/Interfaces/IRepositorySalarie.cs
@@ -0,0 +1,11 @@
+using ldap_cesi.Entities;
+
+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/Interfaces/IRepositoryService.cs b/ldap-cesi/Repositories/Interfaces/IRepositoryService.cs
new file mode 100644
index 0000000..aba697b
--- /dev/null
+++ b/ldap-cesi/Repositories/Interfaces/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/Repositories/Interfaces/IRepositorySite.cs b/ldap-cesi/Repositories/Interfaces/IRepositorySite.cs
new file mode 100644
index 0000000..cc098f9
--- /dev/null
+++ b/ldap-cesi/Repositories/Interfaces/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/Repositories/Interfaces/IRepositoryUtilisateur.cs b/ldap-cesi/Repositories/Interfaces/IRepositoryUtilisateur.cs
new file mode 100644
index 0000000..dcecf23
--- /dev/null
+++ b/ldap-cesi/Repositories/Interfaces/IRepositoryUtilisateur.cs
@@ -0,0 +1,9 @@
+using ldap_cesi.Entities;
+
+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/RepositoryBase.cs b/ldap-cesi/Repositories/RepositoryBase.cs
new file mode 100644
index 0000000..0b02212
--- /dev/null
+++ b/ldap-cesi/Repositories/RepositoryBase.cs
@@ -0,0 +1,184 @@
+using System.Linq.Expressions;
+using ldap_cesi.Context;
+using ldap_cesi.Models;
+using ldap_cesi.Repository.Services;
+using Microsoft.EntityFrameworkCore;
+
+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)
+ {
+ 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 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<(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);
+ }
+
+ public virtual async Task UpdateAsync(TEntity entity, CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ _context.Set().Update(entity);
+ await SaveChangesAsync(cancellationToken);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ throw new Exception("Erreur pendant la mis à jour", ex);
+ }
+ }
+
+ public virtual async Task<(List Data, int TotalPages, int TotalItems)> GetAllWithRelationsAsync(int pageNumber = 1, int pageSize = 10, params Expression>[] relationInclues)
+ {
+ IQueryable query = _dbSet;
+
+ foreach (var relationInclue in relationInclues)
+ {
+ 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)
+ {
+ try
+ {
+ _context.Set().Remove(entity);
+ await SaveChangesAsync(cancellationToken);
+ return true;
+ }
+ 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 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);
+ }
+
+ public virtual async Task<(List Data, int TotalPages, int TotalItems)> SearchAsync(
+ Expression> predicate,
+ int pageNumber = 1,
+ int pageSize = 10,
+ params Expression>[] relationsAInclude)
+ {
+ IQueryable query = _dbSet;
+
+ foreach (var relationInclue in relationsAInclude)
+ {
+ query = query.Include(relationInclue);
+ }
+
+ query = query.Where(predicate);
+
+ var totalCount = await query.CountAsync();
+ var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize);
+
+ var data = await query
+ .Skip((pageNumber - 1) * pageSize)
+ .Take(pageSize)
+ .ToListAsync();
+
+ return (data, totalPages, totalCount);
+ }
+
+ public virtual async Task CountAsync(Expression> predicate, CancellationToken cancellationToken = default)
+ {
+ return await _dbSet.CountAsync(predicate, cancellationToken);
+ }
+
+ 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/Repositories/RoleRepository.cs b/ldap-cesi/Repositories/RoleRepository.cs
new file mode 100644
index 0000000..2d7ee07
--- /dev/null
+++ b/ldap-cesi/Repositories/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/Repositories/SalarieRepository.cs b/ldap-cesi/Repositories/SalarieRepository.cs
new file mode 100644
index 0000000..cb5d329
--- /dev/null
+++ b/ldap-cesi/Repositories/SalarieRepository.cs
@@ -0,0 +1,49 @@
+using ldap_cesi.Context;
+using ldap_cesi.Entities;
+using ldap_cesi.Repository.Services;
+using Microsoft.EntityFrameworkCore;
+
+namespace ldap_cesi.Repository;
+
+public class SalarieRepository : RepositoryBase, IRepositorySalarie
+{
+ public SalarieRepository(PgContext context) : base(context)
+ {
+
+ }
+
+ 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/Repositories/ServiceRepository.cs b/ldap-cesi/Repositories/ServiceRepository.cs
new file mode 100644
index 0000000..e0f15e8
--- /dev/null
+++ b/ldap-cesi/Repositories/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/Repositories/SiteRepository.cs b/ldap-cesi/Repositories/SiteRepository.cs
new file mode 100644
index 0000000..3b522b8
--- /dev/null
+++ b/ldap-cesi/Repositories/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/Repositories/UtilisateurRepository.cs b/ldap-cesi/Repositories/UtilisateurRepository.cs
new file mode 100644
index 0000000..a86435c
--- /dev/null
+++ b/ldap-cesi/Repositories/UtilisateurRepository.cs
@@ -0,0 +1,27 @@
+using ldap_cesi.Context;
+using ldap_cesi.Entities;
+using ldap_cesi.Repository.Services;
+using Microsoft.EntityFrameworkCore;
+
+namespace ldap_cesi.Repository;
+
+public class UtilisateurRepository : RepositoryBase, IRepositoryUtilisateur
+{
+ public UtilisateurRepository(PgContext context) : base(context)
+ {
+
+ }
+
+ public async Task GetByEmailAsync(string email)
+ {
+ 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/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/IJwtService.cs b/ldap-cesi/Services/Interfaces/IJwtService.cs
new file mode 100644
index 0000000..fcfbc88
--- /dev/null
+++ b/ldap-cesi/Services/Interfaces/IJwtService.cs
@@ -0,0 +1,11 @@
+using ldap_cesi.Entities;
+
+namespace ldap_cesi.Services.Interfaces;
+
+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/IRoleService.cs b/ldap-cesi/Services/Interfaces/IRoleService.cs
new file mode 100644
index 0000000..41e1c2a
--- /dev/null
+++ b/ldap-cesi/Services/Interfaces/IRoleService.cs
@@ -0,0 +1,10 @@
+using ldap_cesi.Entities;
+using ldap_cesi.DTOs;
+using ldap_cesi.DTOs.Inputs.Role;
+
+namespace ldap_cesi.Services.Interfaces
+{
+ public interface IRoleService : IServiceBase
+ {
+ }
+}
\ 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..8386361
--- /dev/null
+++ b/ldap-cesi/Services/Interfaces/ISalarieService.cs
@@ -0,0 +1,17 @@
+using ldap_cesi.DTOs;
+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;
+
+namespace ldap_cesi.Services.Interfaces;
+
+public interface ISalarieService : IServiceBase
+{
+ 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
new file mode 100644
index 0000000..f11aef2
--- /dev/null
+++ b/ldap-cesi/Services/Interfaces/IServiceBase.cs
@@ -0,0 +1,23 @@
+using System.Linq.Expressions;
+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(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(int pageNumber, int pageSize, params Expression>[] relationsAInclure);
+
+ Task>> SearchWithRelations(string searchTerm, int pageNumber, int pageSize,
+ params Expression>[] includeProperties);
+ Task> Create(TCreateDto dto);
+ Task> Update(TUpdateDto dto);
+ Task> Delete(int id);
+ 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
new file mode 100644
index 0000000..d509e38
--- /dev/null
+++ b/ldap-cesi/Services/Interfaces/IServiceService.cs
@@ -0,0 +1,12 @@
+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 : IServiceBase
+ {
+ Task> DeleteWithEntiteCheck(int id);
+ }
+}
diff --git a/ldap-cesi/Services/Interfaces/ISiteService.cs b/ldap-cesi/Services/Interfaces/ISiteService.cs
new file mode 100644
index 0000000..08e3b93
--- /dev/null
+++ b/ldap-cesi/Services/Interfaces/ISiteService.cs
@@ -0,0 +1,11 @@
+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 : IServiceBase
+{
+ Task> DeleteWithEntiteCheck(int id);
+}
\ 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..88d9fa2
--- /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..8464c4b
--- /dev/null
+++ b/ldap-cesi/Services/JwtService.cs
@@ -0,0 +1,167 @@
+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, "Une erreur s'est produitel lors de la génération du token.");
+ throw;
+ }
+ }
+
+ public string GetPublicKey()
+ {
+ try
+ {
+ var publicKey = _rsaKeyService.GetRsaKey().ExportSubjectPublicKeyInfo();
+ return Convert.ToBase64String(publicKey);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Une erreur s'est produite pendant la récupération de la clé.");
+ 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)
+ {
+ 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("Erreur de validation : Id utilisateur invalide.");
+ return false;
+ }
+
+ var utilisateur = await _context.Utilisateurs.FindAsync(userId);
+ if (utilisateur == null)
+ {
+ _logger.LogWarning("Erreur de validation : Utilisateur non trouvé.");
+ return false;
+ }
+
+ utilisateur.AccessToken = token;
+ _context.Utilisateurs.Update(utilisateur);
+ await _context.SaveChangesAsync();
+
+ return true;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Une erreur s'est produite lors pendant la validation du token JWT.");
+ 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..c6e44df
--- /dev/null
+++ b/ldap-cesi/Services/RoleService.cs
@@ -0,0 +1,17 @@
+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;
+using ldap_cesi.Validator.Role;
+
+namespace ldap_cesi.Services;
+
+public class RoleService : ServiceBase,IRoleService
+{
+ 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/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..c339300
--- /dev/null
+++ b/ldap-cesi/Services/SalarieService.cs
@@ -0,0 +1,98 @@
+using AutoMapper;
+using ldap_cesi.DTOs;
+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 : 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,
+ ILogger logger, SalarieCreateValidator salarieCreateValidator, SalarieUpdateValidator salarieUpdateValidator)
+ : base(repositorySalarie, mapper, logger, salarieCreateValidator, salarieUpdateValidator)
+ {
+ _repositorySalarie = repositorySalarie;
+ _repositorySite = repositorySite;
+ _repositoryService = repositoryService;
+ _mapper = mapper;
+ }
+
+ public async Task>> GetSalariesBySite(int siteId, int pageNumber = 1, int pageSize = 25)
+ {
+ 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);
+ 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,
+ TotalPages = (int)Math.Ceiling((double)totalCount / pageSize),
+ TotalCount = totalCount,
+ PageNumber = pageNumber,
+ PageSize = pageSize,
+ StatusCode = 200
+ };
+ }
+
+ public async Task>> GetSalariesByService(int serviceId, int pageNumber = 1, int pageSize = 25)
+ {
+ 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 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, // Les salariés paginés
+ TotalPages = (int)Math.Ceiling((double)totalCount / pageSize),
+ TotalCount = totalCount,
+ PageNumber = pageNumber,
+ PageSize = pageSize,
+ StatusCode = 200
+ };
+ }
+}
\ 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..a8a72c1
--- /dev/null
+++ b/ldap-cesi/Services/ServiceBase.cs
@@ -0,0 +1,360 @@
+using AutoMapper;
+using ldap_cesi.Models;
+using ldap_cesi.Repository.Services;
+using ldap_cesi.Services.Interfaces;
+using System.Linq.Expressions;
+using FluentValidation;
+using Microsoft.EntityFrameworkCore;
+
+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;
+ protected readonly IValidator _createDtoValidator;
+ protected readonly IValidator _updateDtoValidator;
+
+ public ServiceBase(IRepositoryBase repository, IMapper mapper, ILogger> logger, IValidator createDtoValidator, IValidator updateDtoValidator)
+ {
+ _repository = repository;
+ _mapper = mapper;
+ _logger = logger;
+ _createDtoValidator = createDtoValidator;
+ _updateDtoValidator = updateDtoValidator;
+ }
+
+ private Expression> BuildSearchPredicate(string inputSearch)
+ {
+ return entity =>
+ EF.Functions.ILike(EF.Property(entity, "Nom"), $"%{inputSearch}%") ||
+ EF.Functions.ILike(EF.Property(entity, "Prenom"), $"%{inputSearch}%");
+ }
+ public virtual async Task>> GetAll(int pageNumber, int pageSize)
+ {
+ try
+ {
+ var response = await _repository.GetAllAsync( pageNumber, pageSize);
+ return new ResponseDataModel>
+ {
+ Success = true,
+ Data = response.Data,
+ TotalPages = response.TotalPages,
+ TotalCount = response.TotalItems,
+ 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>> GetAllWithRelationsAsync(int pageNumber, int pageSize,params Expression>[] relationsAInclure)
+ {
+ try
+ {
+ 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."
+ };
+ }
+ 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