diff --git a/Infrastructure/Entities/Program.cs b/Infrastructure/Entities/TrainingProgram.cs similarity index 91% rename from Infrastructure/Entities/Program.cs rename to Infrastructure/Entities/TrainingProgram.cs index 82398fe..6df8f45 100644 --- a/Infrastructure/Entities/Program.cs +++ b/Infrastructure/Entities/TrainingProgram.cs @@ -4,7 +4,7 @@ using Infrastructure.Base; namespace Infrastructure.Entities; -public class Program : EntityBase +public class TrainingProgram : EntityBase { [Required] public string Name { get; set; } diff --git a/Infrastructure/Migrations/20250109094119_TrainingProgram.Designer.cs b/Infrastructure/Migrations/20250109094119_TrainingProgram.Designer.cs new file mode 100644 index 0000000..6e63217 --- /dev/null +++ b/Infrastructure/Migrations/20250109094119_TrainingProgram.Designer.cs @@ -0,0 +1,191 @@ +// +using Infrastructure; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Infrastructure.Migrations +{ + [DbContext(typeof(OptifitDbContext))] + [Migration("20250109094119_TrainingProgram")] + partial class TrainingProgram + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.1"); + + modelBuilder.Entity("Infrastructure.Entities.Exercice", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Duration") + .HasColumnType("REAL"); + + b.Property("Image") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("NbRepetitions") + .HasColumnType("INTEGER"); + + b.Property("NbSeries") + .HasColumnType("INTEGER"); + + b.Property("SessionId") + .HasColumnType("TEXT"); + + b.Property("Video") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SessionId"); + + b.ToTable("Exercices"); + }); + + modelBuilder.Entity("Infrastructure.Entities.Program", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Difficulty") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("WeekDuration") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Programs"); + }); + + modelBuilder.Entity("Infrastructure.Entities.Session", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Duration") + .HasColumnType("REAL"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ProgramId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ProgramId"); + + b.ToTable("Sessions"); + }); + + modelBuilder.Entity("Infrastructure.Entities.User", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("Age") + .HasColumnType("INTEGER"); + + b.Property("EGoal") + .HasColumnType("TEXT"); + + b.Property("ESleepLevel") + .HasColumnType("TEXT"); + + b.Property("ESportLevel") + .HasColumnType("TEXT"); + + b.Property("HashPassword") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Height") + .HasColumnType("REAL"); + + b.Property("Logo") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("NbSessionPerWeek") + .HasColumnType("INTEGER"); + + b.Property("OAuthId") + .HasColumnType("TEXT"); + + b.Property("OAuthProvider") + .HasColumnType("TEXT"); + + b.Property("Sexe") + .HasColumnType("INTEGER"); + + b.Property("Weight") + .HasColumnType("REAL"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Infrastructure.Entities.Exercice", b => + { + b.HasOne("Infrastructure.Entities.Session", null) + .WithMany("Exercices") + .HasForeignKey("SessionId"); + }); + + modelBuilder.Entity("Infrastructure.Entities.Session", b => + { + b.HasOne("Infrastructure.Entities.Program", null) + .WithMany("Sessions") + .HasForeignKey("ProgramId"); + }); + + modelBuilder.Entity("Infrastructure.Entities.Program", b => + { + b.Navigation("Sessions"); + }); + + modelBuilder.Entity("Infrastructure.Entities.Session", b => + { + b.Navigation("Exercices"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Infrastructure/Migrations/20250109094119_TrainingProgram.cs b/Infrastructure/Migrations/20250109094119_TrainingProgram.cs new file mode 100644 index 0000000..3237c77 --- /dev/null +++ b/Infrastructure/Migrations/20250109094119_TrainingProgram.cs @@ -0,0 +1,94 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Infrastructure.Migrations +{ + /// + public partial class TrainingProgram : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "SessionId", + table: "Exercices", + type: "TEXT", + nullable: true); + + migrationBuilder.CreateTable( + name: "Programs", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", nullable: false), + WeekDuration = table.Column(type: "INTEGER", nullable: false), + Description = table.Column(type: "TEXT", nullable: false), + Difficulty = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Programs", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Sessions", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", nullable: false), + Description = table.Column(type: "TEXT", nullable: false), + Duration = table.Column(type: "REAL", nullable: false), + ProgramId = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Sessions", x => x.Id); + table.ForeignKey( + name: "FK_Sessions_Programs_ProgramId", + column: x => x.ProgramId, + principalTable: "Programs", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_Exercices_SessionId", + table: "Exercices", + column: "SessionId"); + + migrationBuilder.CreateIndex( + name: "IX_Sessions_ProgramId", + table: "Sessions", + column: "ProgramId"); + + migrationBuilder.AddForeignKey( + name: "FK_Exercices_Sessions_SessionId", + table: "Exercices", + column: "SessionId", + principalTable: "Sessions", + principalColumn: "Id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Exercices_Sessions_SessionId", + table: "Exercices"); + + migrationBuilder.DropTable( + name: "Sessions"); + + migrationBuilder.DropTable( + name: "Programs"); + + migrationBuilder.DropIndex( + name: "IX_Exercices_SessionId", + table: "Exercices"); + + migrationBuilder.DropColumn( + name: "SessionId", + table: "Exercices"); + } + } +} diff --git a/Infrastructure/Migrations/OptifitDbContextModelSnapshot.cs b/Infrastructure/Migrations/OptifitDbContextModelSnapshot.cs index 5a17324..c8283ee 100644 --- a/Infrastructure/Migrations/OptifitDbContextModelSnapshot.cs +++ b/Infrastructure/Migrations/OptifitDbContextModelSnapshot.cs @@ -42,15 +42,71 @@ namespace Infrastructure.Migrations b.Property("NbSeries") .HasColumnType("INTEGER"); + b.Property("SessionId") + .HasColumnType("TEXT"); + b.Property("Video") .IsRequired() .HasColumnType("TEXT"); b.HasKey("Id"); + b.HasIndex("SessionId"); + b.ToTable("Exercices"); }); + modelBuilder.Entity("Infrastructure.Entities.Program", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Difficulty") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("WeekDuration") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Programs"); + }); + + modelBuilder.Entity("Infrastructure.Entities.Session", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Duration") + .HasColumnType("REAL"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ProgramId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ProgramId"); + + b.ToTable("Sessions"); + }); + modelBuilder.Entity("Infrastructure.Entities.User", b => { b.Property("Id") @@ -108,6 +164,30 @@ namespace Infrastructure.Migrations b.ToTable("Users"); }); + + modelBuilder.Entity("Infrastructure.Entities.Exercice", b => + { + b.HasOne("Infrastructure.Entities.Session", null) + .WithMany("Exercices") + .HasForeignKey("SessionId"); + }); + + modelBuilder.Entity("Infrastructure.Entities.Session", b => + { + b.HasOne("Infrastructure.Entities.Program", null) + .WithMany("Sessions") + .HasForeignKey("ProgramId"); + }); + + modelBuilder.Entity("Infrastructure.Entities.Program", b => + { + b.Navigation("Sessions"); + }); + + modelBuilder.Entity("Infrastructure.Entities.Session", b => + { + b.Navigation("Exercices"); + }); #pragma warning restore 612, 618 } } diff --git a/Infrastructure/OptifitDbContext.cs b/Infrastructure/OptifitDbContext.cs index b39b5b5..a8c454c 100644 --- a/Infrastructure/OptifitDbContext.cs +++ b/Infrastructure/OptifitDbContext.cs @@ -7,6 +7,8 @@ namespace Infrastructure { public virtual DbSet Users { get; set; } public virtual DbSet Exercices { get; set; } + public virtual DbSet Sessions { get; set; } + public virtual DbSet Programs { get; set; } public OptifitDbContext() { diff --git a/Infrastructure/Repositories/ITrainingProgramRepository.cs b/Infrastructure/Repositories/ITrainingProgramRepository.cs new file mode 100644 index 0000000..24a14d7 --- /dev/null +++ b/Infrastructure/Repositories/ITrainingProgramRepository.cs @@ -0,0 +1,7 @@ +using Infrastructure.Entities; + +namespace Infrastructure.Repositories; + +public interface ITrainingProgramRepository : IRepository +{ +} diff --git a/Infrastructure/Repositories/TrainingProgramRepository.cs b/Infrastructure/Repositories/TrainingProgramRepository.cs new file mode 100644 index 0000000..c742a6b --- /dev/null +++ b/Infrastructure/Repositories/TrainingProgramRepository.cs @@ -0,0 +1,10 @@ +using Infrastructure.Entities; + +namespace Infrastructure.Repositories; + +public class TrainingProgramRepository : GenericRepository, ITrainingProgramRepository +{ + public TrainingProgramRepository(OptifitDbContext context) : base(context) + { + } +} \ No newline at end of file diff --git a/Server/Controller/v1/ExercicesController.cs b/Server/Controller/v1/ExercicesController.cs index 4b7daf7..ef44e5a 100644 --- a/Server/Controller/v1/ExercicesController.cs +++ b/Server/Controller/v1/ExercicesController.cs @@ -24,7 +24,6 @@ public class ExercicesController : ControllerBase [HttpGet] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status204NoContent)] - [RequireHttps] [AllowAnonymous] public async Task GetExercices([FromQuery] int pageIndex = 1, [FromQuery] int pageSize = 5, [FromQuery] bool ascending = true) { @@ -35,7 +34,6 @@ public class ExercicesController : ControllerBase [HttpGet("{id}")] [ProducesResponseType(typeof(ResponseExerciceDto), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - [RequireHttps] [AllowAnonymous] public async Task GetExerciceById(string id) { @@ -59,7 +57,6 @@ public class ExercicesController : ControllerBase [ProducesResponseType(typeof(ResponseExerciceDto), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status400BadRequest)] - [RequireHttps] [AllowAnonymous] public async Task UpdateExercice(string id, [FromBody] RequestExerciceDto request) { diff --git a/Server/Controller/v1/SessionsController.cs b/Server/Controller/v1/SessionsController.cs index b7b348d..04d7511 100644 --- a/Server/Controller/v1/SessionsController.cs +++ b/Server/Controller/v1/SessionsController.cs @@ -1,6 +1,79 @@ -namespace Server.Controller.v1; +using Asp.Versioning; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Server.Dto.Request; +using Server.Dto.Response; +using Server.IServices; -public class SessionsController +namespace Server.Controller.v1 { - + [ApiController] + [ApiVersion("1.0")] + [Route("api/v{version:apiVersion}/[controller]")] + public class SessionsController : ControllerBase + { + private readonly ILogger _logger; + private readonly ISessionService _dataServices; + + public SessionsController(ILogger logger, ISessionService dataServices) + { + _logger = logger; + _dataServices = dataServices; + } + + [HttpGet] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [AllowAnonymous] + public async Task GetSessions([FromQuery] int pageIndex = 1, [FromQuery] int pageSize = 5, [FromQuery] bool ascending = true) + { + var sessions = await _dataServices.GetSessions(pageIndex, pageSize, ascending); + return sessions.TotalCount == 0 ? NoContent() : Ok(sessions); + } + + [HttpGet("{id}")] + [ProducesResponseType(typeof(ResponseSessionDto), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [AllowAnonymous] + public async Task GetSessionById(string id) + { + var session = await _dataServices.GetSessionById(id); + return session == null ? NotFound() : Ok(session); + } + + [HttpPost] + [ProducesResponseType(typeof(ResponseSessionDto), StatusCodes.Status201Created)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [AllowAnonymous] + public async Task CreateSession([FromBody] RequestSessionDto request) + { + if (!ModelState.IsValid) return BadRequest(ModelState); + + var createdSession = await _dataServices.CreateSession(request); + return CreatedAtAction(nameof(GetSessionById), new { id = createdSession.Id }, createdSession); + } + + [HttpPut("{id}")] + [ProducesResponseType(typeof(ResponseSessionDto), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [AllowAnonymous] + public async Task UpdateSession(string id, [FromBody] RequestSessionDto request) + { + if (!ModelState.IsValid) return BadRequest(ModelState); + + var updatedSession = await _dataServices.UpdateSession(id, request); + return updatedSession == null ? NotFound() : Ok(updatedSession); + } + + [HttpDelete("{id}")] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [AllowAnonymous] + public async Task DeleteSession(string id) + { + var deleted = await _dataServices.DeleteSession(id); + return deleted ? NoContent() : NotFound(); + } + } } \ No newline at end of file diff --git a/Server/Controller/v1/TrainingProgramController.cs b/Server/Controller/v1/TrainingProgramController.cs new file mode 100644 index 0000000..cd6cd5f --- /dev/null +++ b/Server/Controller/v1/TrainingProgramController.cs @@ -0,0 +1,79 @@ +using Asp.Versioning; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Server.Dto.Request; +using Server.Dto.Response; +using Server.IServices; + +namespace Server.Controller.v1 +{ + [ApiController] + [ApiVersion("1.0")] + [Route("api/v{version:apiVersion}/[controller]")] + public class TrainingProgramsController : ControllerBase + { + private readonly ILogger _logger; + private readonly ITrainingProgramService _dataServices; + + public TrainingProgramsController(ILogger logger, ITrainingProgramService dataServices) + { + _logger = logger; + _dataServices = dataServices; + } + + [HttpGet] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [AllowAnonymous] + public async Task GetTrainingPrograms([FromQuery] int pageIndex = 1, [FromQuery] int pageSize = 5, [FromQuery] bool ascending = true) + { + var programs = await _dataServices.GetTrainingPrograms(pageIndex, pageSize, ascending); + return programs.TotalCount == 0 ? NoContent() : Ok(programs); + } + + [HttpGet("{id}")] + [ProducesResponseType(typeof(ResponseTrainingProgramDto), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [AllowAnonymous] + public async Task GetTrainingProgramById(string id) + { + var program = await _dataServices.GetTrainingProgramById(id); + return program == null ? NotFound() : Ok(program); + } + + [HttpPost] + [ProducesResponseType(typeof(ResponseTrainingProgramDto), StatusCodes.Status201Created)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [AllowAnonymous] + public async Task CreateTrainingProgram([FromBody] RequestTrainingProgramDto request) + { + if (!ModelState.IsValid) return BadRequest(ModelState); + + var createdProgram = await _dataServices.CreateTrainingProgram(request); + return CreatedAtAction(nameof(GetTrainingProgramById), new { id = createdProgram.Id }, createdProgram); + } + + [HttpPut("{id}")] + [ProducesResponseType(typeof(ResponseTrainingProgramDto), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [AllowAnonymous] + public async Task UpdateTrainingProgram(string id, [FromBody] RequestTrainingProgramDto request) + { + if (!ModelState.IsValid) return BadRequest(ModelState); + + var updatedProgram = await _dataServices.UpdateTrainingProgram(id, request); + return updatedProgram == null ? NotFound() : Ok(updatedProgram); + } + + [HttpDelete("{id}")] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [AllowAnonymous] + public async Task DeleteTrainingProgram(string id) + { + var deleted = await _dataServices.DeleteTrainingProgram(id); + return deleted ? NoContent() : NotFound(); + } + } +} \ No newline at end of file diff --git a/Server/Controller/v1/UsersController.cs b/Server/Controller/v1/UsersController.cs index 6bc7875..4209c78 100644 --- a/Server/Controller/v1/UsersController.cs +++ b/Server/Controller/v1/UsersController.cs @@ -23,7 +23,6 @@ public class UsersController : ControllerBase [HttpGet] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status204NoContent)] - [RequireHttps] public IActionResult GetUsers([FromQuery] int pageIndex = 1, [FromQuery] int pageSize = 5, [FromQuery] bool ascending = true) { var users = _dataServices.GetUsers(pageIndex, pageSize, ascending); @@ -35,8 +34,6 @@ public class UsersController : ControllerBase [HttpGet("{id}")] [ProducesResponseType(typeof(ResponseUserDto), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - - [RequireHttps] public IActionResult GetAlumniById(string id) { var alumni = _dataServices.GetUserById(id); diff --git a/Server/Dto/Request/RequestSessionDto.cs b/Server/Dto/Request/RequestSessionDto.cs index ad334a6..b2d2910 100644 --- a/Server/Dto/Request/RequestSessionDto.cs +++ b/Server/Dto/Request/RequestSessionDto.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace Server.Dto.Request @@ -12,6 +11,6 @@ namespace Server.Dto.Request public float Duration { get; set; } - public List Exercices { get; set; } = new List(); + public List ExerciceIds { get; set; } = new List(); } } \ No newline at end of file diff --git a/Server/Dto/Request/RequestProgramDto.cs b/Server/Dto/Request/RequestTrainingProgramDto.cs similarity index 90% rename from Server/Dto/Request/RequestProgramDto.cs rename to Server/Dto/Request/RequestTrainingProgramDto.cs index 2fd5c59..bbc4b89 100644 --- a/Server/Dto/Request/RequestProgramDto.cs +++ b/Server/Dto/Request/RequestTrainingProgramDto.cs @@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations; namespace Server.Dto.Request { - public class RequestProgramDto + public class RequestTrainingProgramDto { [Required] public string Name { get; set; } diff --git a/Server/Dto/Response/ResponseSessionDto.cs b/Server/Dto/Response/ResponseSessionDto.cs index 351a206..aff29c4 100644 --- a/Server/Dto/Response/ResponseSessionDto.cs +++ b/Server/Dto/Response/ResponseSessionDto.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Server.Dto.Response { public class ResponseSessionDto diff --git a/Server/Dto/Response/ResponseProgramDto.cs b/Server/Dto/Response/ResponseTrainingProgramDto.cs similarity index 89% rename from Server/Dto/Response/ResponseProgramDto.cs rename to Server/Dto/Response/ResponseTrainingProgramDto.cs index 39c8998..ac1ec81 100644 --- a/Server/Dto/Response/ResponseProgramDto.cs +++ b/Server/Dto/Response/ResponseTrainingProgramDto.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; namespace Server.Dto.Response { - public class ResponseProgramDto + public class ResponseTrainingProgramDto { public string Id { get; set; } diff --git a/Server/FirstTest.db b/Server/FirstTest.db index da709d8..10fd111 100644 Binary files a/Server/FirstTest.db and b/Server/FirstTest.db differ diff --git a/Server/IServices/ISessionService.cs b/Server/IServices/ISessionService.cs index 7975f0c..104c5bc 100644 --- a/Server/IServices/ISessionService.cs +++ b/Server/IServices/ISessionService.cs @@ -1,6 +1,15 @@ -namespace Server.IServices; +using Server.Dto.Request; +using Server.Dto.Response; +using Shared; -public class ISessionService +namespace Server.IServices { - + public interface ISessionService + { + Task> GetSessions(int page, int size, bool ascending = true); + Task GetSessionById(string id); + Task CreateSession(RequestSessionDto request); + Task UpdateSession(string id, RequestSessionDto request); + Task DeleteSession(string id); + } } \ No newline at end of file diff --git a/Server/IServices/ITrainingProgramService.cs b/Server/IServices/ITrainingProgramService.cs new file mode 100644 index 0000000..3d78d23 --- /dev/null +++ b/Server/IServices/ITrainingProgramService.cs @@ -0,0 +1,15 @@ +using Server.Dto.Request; +using Server.Dto.Response; +using Shared; + +namespace Server.IServices +{ + public interface ITrainingProgramService + { + Task> GetTrainingPrograms(int page, int size, bool ascending = true); + Task GetTrainingProgramById(string id); + Task CreateTrainingProgram(RequestTrainingProgramDto request); + Task UpdateTrainingProgram(string id, RequestTrainingProgramDto request); + Task DeleteTrainingProgram(string id); + } +} \ No newline at end of file diff --git a/Server/Mappers/PaginatedResultProfile.cs b/Server/Mappers/PaginatedResultProfile.cs index 3f1ec90..abbef06 100644 --- a/Server/Mappers/PaginatedResultProfile.cs +++ b/Server/Mappers/PaginatedResultProfile.cs @@ -1,6 +1,16 @@ -namespace Server.Mappers; +using AutoMapper; +using Shared; +using Infrastructure.Entities; +using Server.Dto.Response; -public class PaginatedResultProfile +namespace Server.Mappers { - + public class PaginatedResultProfile : Profile + { + public PaginatedResultProfile() + { + CreateMap, PaginatedResult>() + .ForMember(dest => dest.Data, opt => opt.MapFrom(src => src.Data)); + } + } } \ No newline at end of file diff --git a/Server/Mappers/SessionProfile.cs b/Server/Mappers/SessionProfile.cs index 16d5291..e57cb4e 100644 --- a/Server/Mappers/SessionProfile.cs +++ b/Server/Mappers/SessionProfile.cs @@ -1,6 +1,19 @@ -namespace Server.Mappers; +using AutoMapper; +using Infrastructure.Entities; +using Server.Dto.Request; +using Server.Dto.Response; -public class SessionProfile +namespace Server.Mappers { - + public class SessionProfile : Profile + { + public SessionProfile() + { + CreateMap() + .ForMember(dest => dest.Exercices, opt => opt.MapFrom(src => src.Exercices)); + + CreateMap() + .ForMember(dest => dest.Exercices, opt => opt.Ignore()); + } + } } \ No newline at end of file diff --git a/Server/Mappers/TrainingProgramProfile.cs b/Server/Mappers/TrainingProgramProfile.cs new file mode 100644 index 0000000..3eb1a08 --- /dev/null +++ b/Server/Mappers/TrainingProgramProfile.cs @@ -0,0 +1,19 @@ +using AutoMapper; +using Infrastructure.Entities; +using Server.Dto.Request; +using Server.Dto.Response; + +namespace Server.Mappers +{ + public class TrainingProgramProfile : Profile + { + public TrainingProgramProfile() + { + CreateMap() + .ForMember(dest => dest.Sessions, opt => opt.MapFrom(src => src.Sessions)); + + CreateMap() + .ForMember(dest => dest, opt => opt.Ignore()); + } + } +} \ No newline at end of file diff --git a/Server/Program.cs b/Server/Program.cs index e4ecf5d..9640653 100644 --- a/Server/Program.cs +++ b/Server/Program.cs @@ -13,18 +13,26 @@ var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddControllers(); builder.Services.AddDbContext(options => - options.UseSqlite("Data Source=FirstTest.db")); + options.UseSqlite("Data Source=../Server/FirstTest.db", b => b.MigrationsAssembly("Infrastructure"))); // Register AutoMapper builder.Services.AddAutoMapper(typeof(UserProfile)); builder.Services.AddAutoMapper(typeof(ExerciceProfile)); +builder.Services.AddAutoMapper(typeof(SessionProfile)); +builder.Services.AddAutoMapper(typeof(PaginatedResultProfile)); +builder.Services.AddAutoMapper(typeof(TrainingProgramProfile)); + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); diff --git a/Server/Services/SessionService.cs b/Server/Services/SessionService.cs index eb953b5..35dd57f 100644 --- a/Server/Services/SessionService.cs +++ b/Server/Services/SessionService.cs @@ -1,6 +1,71 @@ -namespace Server.Services; +using AutoMapper; +using Infrastructure; +using Infrastructure.Entities; +using Infrastructure.Repositories; +using Server.Dto.Request; +using Server.Dto.Response; +using Server.IServices; +using Shared; -public class SessionService +namespace Server.Services { - + public class SessionService : ISessionService + { + private readonly OptifitDbContext _context; + private readonly ISessionRepository _sessionRepository; + private readonly IExerciceRepository _exerciceRepository; + private readonly IMapper _mapper; + + public SessionService(OptifitDbContext context, ISessionRepository sessionRepository, IExerciceRepository exerciceRepository, IMapper mapper) + { + _context = context; + _sessionRepository = sessionRepository; + _exerciceRepository = exerciceRepository; + _mapper = mapper; + } + + public async Task> GetSessions(int page, int size, bool ascending = true) + { + var sessions = await _sessionRepository.GetPaginatedListAsync(page - 1, size, null, null); + var result = _mapper.Map>(sessions); + return result; + } + + public async Task GetSessionById(string id) + { + var session = await _sessionRepository.GetByIdAsync(id, s => s.Exercices); + return session == null ? null : _mapper.Map(session); + } + + public async Task CreateSession(RequestSessionDto request) + { + var session = _mapper.Map(request); + session.Exercices = (ICollection)await _exerciceRepository.GetAllAsync(e => request.ExerciceIds.Contains(e.Id)); + await _sessionRepository.InsertAsync(session); + await _context.SaveChangesAsync(); + return _mapper.Map(session); + } + + public async Task UpdateSession(string id, RequestSessionDto request) + { + var session = await _sessionRepository.GetByIdAsync(id, s => s.Exercices); + if (session == null) return null; + + _mapper.Map(request, session); + session.Exercices = (ICollection)await _exerciceRepository.GetAllAsync(e => request.ExerciceIds.Contains(e.Id)); + _sessionRepository.Update(session); + await _context.SaveChangesAsync(); + return _mapper.Map(session); + } + + public async Task DeleteSession(string id) + { + var session = await _sessionRepository.GetByIdAsync(id); + if (session == null) return false; + + _sessionRepository.Delete(id); + await _context.SaveChangesAsync(); + return true; + } + } } \ No newline at end of file diff --git a/Server/Services/TrainingProgramService.cs b/Server/Services/TrainingProgramService.cs new file mode 100644 index 0000000..8ab11a9 --- /dev/null +++ b/Server/Services/TrainingProgramService.cs @@ -0,0 +1,67 @@ +using AutoMapper; +using Infrastructure; +using Infrastructure.Entities; +using Infrastructure.Repositories; +using Server.Dto.Request; +using Server.Dto.Response; +using Server.IServices; +using Shared; + +namespace Server.Services +{ + public class TrainingProgramService : ITrainingProgramService + { + private readonly OptifitDbContext _context; + private readonly ITrainingProgramRepository _trainingProgramRepository; + private readonly IMapper _mapper; + + public TrainingProgramService(OptifitDbContext context, ITrainingProgramRepository trainingProgramRepository, IMapper mapper) + { + _context = context; + _trainingProgramRepository = trainingProgramRepository; + _mapper = mapper; + } + + public async Task> GetTrainingPrograms(int page, int size, bool ascending = true) + { + var programs = await _trainingProgramRepository.GetPaginatedListAsync(page - 1, size, null, null); + var result = _mapper.Map>(programs); + return result; + } + + public async Task GetTrainingProgramById(string id) + { + var program = await _trainingProgramRepository.GetByIdAsync(id, p => p.Sessions); + return program == null ? null : _mapper.Map(program); + } + + public async Task CreateTrainingProgram(RequestTrainingProgramDto request) + { + var program = _mapper.Map(request); + await _trainingProgramRepository.InsertAsync(program); + await _context.SaveChangesAsync(); + return _mapper.Map(program); + } + + public async Task UpdateTrainingProgram(string id, RequestTrainingProgramDto request) + { + var program = await _trainingProgramRepository.GetByIdAsync(id, p => p.Sessions); + if (program == null) return null; + + _mapper.Map(request, program); + _trainingProgramRepository.Update(program); + await _context.SaveChangesAsync(); + return _mapper.Map(program); + } + + public async Task DeleteTrainingProgram(string id) + { + var program = await _trainingProgramRepository.GetByIdAsync(id); + if (program == null) return false; + + _trainingProgramRepository.Delete(id); + await _context.SaveChangesAsync(); + return true; + } + } +} \ No newline at end of file