From 9489242cfb3cefd76d57a09b7eabe36cde1e23ee Mon Sep 17 00:00:00 2001 From: anperederi Date: Fri, 23 Feb 2024 08:51:02 +0100 Subject: [PATCH 1/6] =?UTF-8?q?=F0=9F=8E=A8=20Add=20API=20in=20EF=20reposi?= =?UTF-8?q?tory?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Dto/ActivityDto.cs | 0 src/Dto/AthleteDto.cs | 21 +++ src/Dto/DataSourceDto.cs | 0 src/Dto/Dto.csproj | 9 ++ src/Dto/HeartRateDto.cs | 0 src/Dto/NotificationDto.cs | 0 src/Dto/StatisticDto.cs | 0 src/Dto/TrainingDto.cs | 0 src/HeartTrack.sln | 41 ++++++ .../Controllers/AthleteController.cs | 26 ++++ src/HeartTrackAPI/HeartTrackAPI.csproj | 19 +++ src/HeartTrackAPI/HeartTrackAPI.http | 6 + src/HeartTrackAPI/Program.cs | 44 ++++++ .../Properties/launchSettings.json | 41 ++++++ .../appsettings.Development.json | 8 ++ src/HeartTrackAPI/appsettings.json | 9 ++ src/Shared/AthleteOrderCriteria.cs | 11 ++ src/Shared/IAthleteService.cs | 23 +++ src/Shared/Shared.csproj | 13 ++ src/StubbedDtoLib/AthleteStubDto.cs | 135 ++++++++++++++++++ src/StubbedDtoLib/StubbedDtoLib.csproj | 14 ++ .../TestsAPI/ClientTests/ClientTests.csproj | 10 ++ src/Tests/TestsAPI/ClientTests/Program.cs | 2 + src/Tests/TestsAPI/TestsXUnit/GlobalUsings.cs | 1 + .../TestsAPI/TestsXUnit/TestsXUnit.csproj | 25 ++++ src/Tests/TestsAPI/TestsXUnit/UnitTest1.cs | 10 ++ 26 files changed, 468 insertions(+) create mode 100644 src/Dto/ActivityDto.cs create mode 100644 src/Dto/AthleteDto.cs create mode 100644 src/Dto/DataSourceDto.cs create mode 100644 src/Dto/Dto.csproj create mode 100644 src/Dto/HeartRateDto.cs create mode 100644 src/Dto/NotificationDto.cs create mode 100644 src/Dto/StatisticDto.cs create mode 100644 src/Dto/TrainingDto.cs create mode 100644 src/HeartTrackAPI/Controllers/AthleteController.cs create mode 100644 src/HeartTrackAPI/HeartTrackAPI.csproj create mode 100644 src/HeartTrackAPI/HeartTrackAPI.http create mode 100644 src/HeartTrackAPI/Program.cs create mode 100644 src/HeartTrackAPI/Properties/launchSettings.json create mode 100644 src/HeartTrackAPI/appsettings.Development.json create mode 100644 src/HeartTrackAPI/appsettings.json create mode 100644 src/Shared/AthleteOrderCriteria.cs create mode 100644 src/Shared/IAthleteService.cs create mode 100644 src/Shared/Shared.csproj create mode 100644 src/StubbedDtoLib/AthleteStubDto.cs create mode 100644 src/StubbedDtoLib/StubbedDtoLib.csproj create mode 100644 src/Tests/TestsAPI/ClientTests/ClientTests.csproj create mode 100644 src/Tests/TestsAPI/ClientTests/Program.cs create mode 100644 src/Tests/TestsAPI/TestsXUnit/GlobalUsings.cs create mode 100644 src/Tests/TestsAPI/TestsXUnit/TestsXUnit.csproj create mode 100644 src/Tests/TestsAPI/TestsXUnit/UnitTest1.cs diff --git a/src/Dto/ActivityDto.cs b/src/Dto/ActivityDto.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/Dto/AthleteDto.cs b/src/Dto/AthleteDto.cs new file mode 100644 index 0000000..cbae984 --- /dev/null +++ b/src/Dto/AthleteDto.cs @@ -0,0 +1,21 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dto; + +public class AthleteDto +{ + public int IdAthlete { get; set; } + [MaxLength(100)] + public required string Username { get; set; } + [MaxLength(150)] + public required string LastName { get; set; } + [MaxLength(100)] + public required string FirstName { get; set; } + public required string Email { get; set; } + public required string Sexe { get; set; } + public double Lenght { get; set; } + public float Weight { get; set; } + public required string Password { get; set; } + public DateTime DateOfBirth { get; set; } + public bool IsCoach { get; set; } +} diff --git a/src/Dto/DataSourceDto.cs b/src/Dto/DataSourceDto.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/Dto/Dto.csproj b/src/Dto/Dto.csproj new file mode 100644 index 0000000..bb23fb7 --- /dev/null +++ b/src/Dto/Dto.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/src/Dto/HeartRateDto.cs b/src/Dto/HeartRateDto.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/Dto/NotificationDto.cs b/src/Dto/NotificationDto.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/Dto/StatisticDto.cs b/src/Dto/StatisticDto.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/Dto/TrainingDto.cs b/src/Dto/TrainingDto.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/HeartTrack.sln b/src/HeartTrack.sln index 6ecaf7b..ddc2c8a 100644 --- a/src/HeartTrack.sln +++ b/src/HeartTrack.sln @@ -15,6 +15,20 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleTestEntities", "Test EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleTestRelationships", "Tests\ConsoleTestRelationships\ConsoleTestRelationships.csproj", "{2D166FAD-4934-474B-96A8-6C0635156EC2}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dto", "Dto\Dto.csproj", "{562019BC-0F61-41B0-9BAE-259B92C6BFBA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeartTrackAPI", "HeartTrackAPI\HeartTrackAPI.csproj", "{C1C2EAC3-3347-466B-BFB6-2A9F11A3AE12}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared", "Shared\Shared.csproj", "{F80C60E1-1E06-46C2-96DE-42B1C7DE65BC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StubbedDtoLib", "StubbedDtoLib\StubbedDtoLib.csproj", "{87F65E21-0555-4772-88B4-C8B43146A02C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestsAPI", "TestsAPI", "{30FC2BE9-7397-445A-84AD-043CE70F4281}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClientTests", "Tests\TestsAPI\ClientTests\ClientTests.csproj", "{9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestsXUnit", "Tests\TestsAPI\TestsXUnit\TestsXUnit.csproj", "{44C367DC-5FE0-4CF2-9E76-A0282E931853}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -44,9 +58,36 @@ Global {2D166FAD-4934-474B-96A8-6C0635156EC2}.Debug|Any CPU.Build.0 = Debug|Any CPU {2D166FAD-4934-474B-96A8-6C0635156EC2}.Release|Any CPU.ActiveCfg = Release|Any CPU {2D166FAD-4934-474B-96A8-6C0635156EC2}.Release|Any CPU.Build.0 = Release|Any CPU + {562019BC-0F61-41B0-9BAE-259B92C6BFBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {562019BC-0F61-41B0-9BAE-259B92C6BFBA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {562019BC-0F61-41B0-9BAE-259B92C6BFBA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {562019BC-0F61-41B0-9BAE-259B92C6BFBA}.Release|Any CPU.Build.0 = Release|Any CPU + {C1C2EAC3-3347-466B-BFB6-2A9F11A3AE12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C1C2EAC3-3347-466B-BFB6-2A9F11A3AE12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C1C2EAC3-3347-466B-BFB6-2A9F11A3AE12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C1C2EAC3-3347-466B-BFB6-2A9F11A3AE12}.Release|Any CPU.Build.0 = Release|Any CPU + {F80C60E1-1E06-46C2-96DE-42B1C7DE65BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F80C60E1-1E06-46C2-96DE-42B1C7DE65BC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F80C60E1-1E06-46C2-96DE-42B1C7DE65BC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F80C60E1-1E06-46C2-96DE-42B1C7DE65BC}.Release|Any CPU.Build.0 = Release|Any CPU + {87F65E21-0555-4772-88B4-C8B43146A02C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {87F65E21-0555-4772-88B4-C8B43146A02C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {87F65E21-0555-4772-88B4-C8B43146A02C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {87F65E21-0555-4772-88B4-C8B43146A02C}.Release|Any CPU.Build.0 = Release|Any CPU + {9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}.Release|Any CPU.Build.0 = Release|Any CPU + {44C367DC-5FE0-4CF2-9E76-A0282E931853}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {44C367DC-5FE0-4CF2-9E76-A0282E931853}.Debug|Any CPU.Build.0 = Debug|Any CPU + {44C367DC-5FE0-4CF2-9E76-A0282E931853}.Release|Any CPU.ActiveCfg = Release|Any CPU + {44C367DC-5FE0-4CF2-9E76-A0282E931853}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {477D2129-A6C9-4FF8-8BE9-5E9E8E5282F8} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} {2D166FAD-4934-474B-96A8-6C0635156EC2} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} + {30FC2BE9-7397-445A-84AD-043CE70F4281} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} + {9E4D3AC5-E6CA-4753-BD96-BF5EE793931A} = {30FC2BE9-7397-445A-84AD-043CE70F4281} + {44C367DC-5FE0-4CF2-9E76-A0282E931853} = {30FC2BE9-7397-445A-84AD-043CE70F4281} EndGlobalSection EndGlobal diff --git a/src/HeartTrackAPI/Controllers/AthleteController.cs b/src/HeartTrackAPI/Controllers/AthleteController.cs new file mode 100644 index 0000000..7180759 --- /dev/null +++ b/src/HeartTrackAPI/Controllers/AthleteController.cs @@ -0,0 +1,26 @@ +using Dto; +using Microsoft.AspNetCore.Mvc; +using Shared; + +[ApiController] +[Route("api/athletes")] +public class AthletesController : ControllerBase +{ + private readonly ILogger _logger; + IAthleteService _stubbedDto; + private const int DEFAULT_INDEX = 0, DEFAULT_COUNT = 5; + + public AthletesController(ILogger logger, IAthleteService athletesService) + { + _logger = logger; + _stubbedDto = athletesService; + } + + [HttpGet("all")] + [ProducesResponseType(typeof(IEnumerable), 200)] + public async Task GetAllAthletesAsync() + { + var athletes = await _stubbedDto.GetAllAthletesAsync(); + return Ok(athletes); + } +} \ No newline at end of file diff --git a/src/HeartTrackAPI/HeartTrackAPI.csproj b/src/HeartTrackAPI/HeartTrackAPI.csproj new file mode 100644 index 0000000..0a86543 --- /dev/null +++ b/src/HeartTrackAPI/HeartTrackAPI.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + enable + enable + true + + + + + + + + + + + + diff --git a/src/HeartTrackAPI/HeartTrackAPI.http b/src/HeartTrackAPI/HeartTrackAPI.http new file mode 100644 index 0000000..97c9a67 --- /dev/null +++ b/src/HeartTrackAPI/HeartTrackAPI.http @@ -0,0 +1,6 @@ +@HeartTrackAPI_HostAddress = http://localhost:5030 + +GET {{HeartTrackAPI_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/src/HeartTrackAPI/Program.cs b/src/HeartTrackAPI/Program.cs new file mode 100644 index 0000000..fda9a7d --- /dev/null +++ b/src/HeartTrackAPI/Program.cs @@ -0,0 +1,44 @@ +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +var summaries = new[] +{ + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" +}; + +app.MapGet("/weatherforecast", () => +{ + var forecast = Enumerable.Range(1, 5).Select(index => + new WeatherForecast + ( + DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + Random.Shared.Next(-20, 55), + summaries[Random.Shared.Next(summaries.Length)] + )) + .ToArray(); + return forecast; +}) +.WithName("GetWeatherForecast") +.WithOpenApi(); + +app.Run(); + +record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) +{ + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); +} diff --git a/src/HeartTrackAPI/Properties/launchSettings.json b/src/HeartTrackAPI/Properties/launchSettings.json new file mode 100644 index 0000000..7156f3d --- /dev/null +++ b/src/HeartTrackAPI/Properties/launchSettings.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:13881", + "sslPort": 44333 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5030", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7233;http://localhost:5030", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/HeartTrackAPI/appsettings.Development.json b/src/HeartTrackAPI/appsettings.Development.json new file mode 100644 index 0000000..ff66ba6 --- /dev/null +++ b/src/HeartTrackAPI/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/src/HeartTrackAPI/appsettings.json b/src/HeartTrackAPI/appsettings.json new file mode 100644 index 0000000..4d56694 --- /dev/null +++ b/src/HeartTrackAPI/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/src/Shared/AthleteOrderCriteria.cs b/src/Shared/AthleteOrderCriteria.cs new file mode 100644 index 0000000..2a7085d --- /dev/null +++ b/src/Shared/AthleteOrderCriteria.cs @@ -0,0 +1,11 @@ +namespace Shared +{ + public enum AthleteOrderCriteria + { + None, + ByUsername, + ByEmail, + ByIsCoach + } +} + diff --git a/src/Shared/IAthleteService.cs b/src/Shared/IAthleteService.cs new file mode 100644 index 0000000..17ff7f2 --- /dev/null +++ b/src/Shared/IAthleteService.cs @@ -0,0 +1,23 @@ +using Dto; + +namespace Shared; + +public interface IAthleteService +{ + public Task> GetAllAthletesAsync(); + public Task> GetSomeAthletesAsync(int index, int count, AthleteOrderCriteria criterium); + public Task GetAthleteByIdAsync(int id); + public Task> GetAthleteByUsernameAsync(string username, int index, int count, AthleteOrderCriteria criterium); + public Task> GetAthletesByEmailAsync(string email, int index, int count, AthleteOrderCriteria criterium); + public Task> GetAthletesByFirstNameAsync(string firstName, int index, int count, AthleteOrderCriteria criterium); + public Task> GetAthletesByLastNameAsync(string lastName, int index, int count, AthleteOrderCriteria criterium); + public Task> GetAthletesBySexeAsync(string sexe, int index, int count, AthleteOrderCriteria criterium); + public Task> GetAthletesByLenghtAsync(double lenght, int index, int count, AthleteOrderCriteria criterium); + public Task> GetAthletesByWeightAsync(float weight, int index, int count, AthleteOrderCriteria criterium); + public Task> GetAthletesByDateOfBirthAsync(DateTime dateOfBirth, int index, int count, AthleteOrderCriteria criterium); + public Task> GetAthletesByIsCoachAsync(bool isCoach, int index, int count, AthleteOrderCriteria criterium); + public Task AddAthleteAsync(AthleteDto athlete, AthleteOrderCriteria criterium); + public Task UpdateAthleteAsync(int id, AthleteDto athlete, AthleteOrderCriteria criterium); + public Task DeleteAthleteAsync(int id, AthleteOrderCriteria criterium); + +} \ No newline at end of file diff --git a/src/Shared/Shared.csproj b/src/Shared/Shared.csproj new file mode 100644 index 0000000..7d742ab --- /dev/null +++ b/src/Shared/Shared.csproj @@ -0,0 +1,13 @@ + + + + + + + + net8.0 + enable + enable + + + diff --git a/src/StubbedDtoLib/AthleteStubDto.cs b/src/StubbedDtoLib/AthleteStubDto.cs new file mode 100644 index 0000000..1b501c7 --- /dev/null +++ b/src/StubbedDtoLib/AthleteStubDto.cs @@ -0,0 +1,135 @@ +using System.ComponentModel; +using Dto; +using Share; + +namespace StubbedDtoLib; + +public class AthleteStubDto : IAthleteService +{ + private static List AthleteList = new List() + { + new AthleteDto { IdAthlete = 1, Username = "Doe", LastName = "John", FirstName = "Doe", Email = "john.doe@example.com", Password = "password123", Sexe = "M", Lenght = 1.80, Weight = 75, DateOfBirth = new DateTime(), IsCoach = true }, + new AthleteDto { IdAthlete = 2, Username = "Smith", LastName = "Jane", FirstName = "Smith", Email = "jane.smith@example.com", Password = "secure456", Sexe = "F", Lenght = 1.65, Weight = 60, DateOfBirth = new DateTime(), IsCoach = false }, + new AthleteDto { IdAthlete = 3, Username = "Martin", LastName = "Paul", FirstName = "Martin", Email = "paul.martin@example.com", Password = "super789", Sexe = "M", Lenght = 1.75, Weight = 68, DateOfBirth = new DateTime(), IsCoach = true }, + new AthleteDto { IdAthlete = 4, Username = "Brown", LastName = "Anna", FirstName = "Brown", Email = "anna.brown@example.com", Password = "test000", Sexe = "M", Lenght = 1.70, Weight = 58, DateOfBirth = new DateTime(), IsCoach = false }, + new AthleteDto { IdAthlete = 5, Username = "Lee", LastName = "Bruce", FirstName = "Lee", Email = "bruce.lee@example.com", Password = "hello321", Sexe = "M", Lenght = 2.0, Weight = 90, DateOfBirth = new DateTime(), IsCoach = false } + }; + + public async Task> GetAllAthletesAsync() + { + return AthleteList; + } + + public async Task> GetSomeAthletesAsync(int index, int count) + { + return AthleteList.Skip(count*index).Take(count); + } + + public async Task GetAthleteByIdAsync(int id) => AthleteList.Find(a => a.IdAthlete == id); + + public async Task> GetAthleteByUsernameAsync(string username, int index, int count) + { + return AthleteList.FindAll(a => a.Username.Contains(username, StringComparison.OrdinalIgnoreCase)).Skip(index*count).Take(count); + } + + public async Task> GetAthletesByEmailAsync(string email, int index, int count) + { + return AthleteList.FindAll(a => a.Email.Contains(email, StringComparison.OrdinalIgnoreCase)).Skip(index*count).Take(count); + } + + public async Task> GetAthletesByFirstNameAsync(string firstName, int index, int count) + { + return AthleteList.FindAll(a => a.FirstName.Contains(firstName, StringComparison.OrdinalIgnoreCase)).Skip(index*count).Take(count); + } + + public async Task> GetAthletesByLastNameAsync(string lastName, int index, int count) + { + return AthleteList.FindAll(a => a.LastName.Contains(lastName, StringComparison.OrdinalIgnoreCase)).Skip(index*count).Take(count); + } + + public async Task> GetAthletesBySexeAsync(string sexe, int index, int count) + { + return AthleteList.FindAll(a => a.Sexe.Contains(sexe, StringComparison.OrdinalIgnoreCase)).Skip(index*count).Take(count); + } + + public async Task> GetAthletesByLenghtAsync(double lenght, int index, int count) + { + return AthleteList.FindAll(a => a.Lenght == lenght).Skip(index*count).Take(count); + } + + public async Task> GetAthletesByWeightAsync(float weight, int index, int count) + { + return AthleteList.FindAll(a => a.Weight == weight).Skip(index*count).Take(count); + } + + public async Task> GetAthletesByDateOfBirthAsync(DateTime dateOfBirth, int index, int count) + { + return AthleteList.FindAll(a => a.DateOfBirth == dateOfBirth).Skip(index*count).Take(count); + } + + public async Task> GetAthletesByIsCoachAsync(bool isCoach, int index, int count) + { + return AthleteList.FindAll(a => a.IsCoach == isCoach).Skip(index*count).Take(count); + } + + public async Task AddAthleteAsync(AthleteDto athlete) + { + var newAthlete = new AthleteDto() + { + IdAthlete = AthleteList.Max(a => a.IdAthlete) + 1, + Username = athlete.Username, + LastName = athlete.LastName, + FirstName = athlete.FirstName, + Email = athlete.Email, + Password = athlete.Password, + Sexe = athlete.Sexe, + Lenght = athlete.Lenght, + Weight = athlete.Weight, + DateOfBirth = athlete.DateOfBirth, + IsCoach = athlete.IsCoach + }; + AthleteList.Add(newAthlete); + return newAthlete; + } + + public async Task UpdateAthleteAsync(int id, AthleteDto athlete) + { + var theId = AthleteList.FindIndex(a => a.IdAthlete == id); + if (theId >= 0) + { + var a = AthleteList[theId]; + + a.Username = athlete.Username; + a.LastName = athlete.LastName; + a.FirstName = athlete.FirstName; + a.Email = athlete.Email; + a.Password = athlete.Password; + a.Sexe = athlete.Sexe; + a.Lenght = athlete.Lenght; + a.Weight = athlete.Weight; + a.DateOfBirth = athlete.DateOfBirth; + a.IsCoach = athlete.IsCoach; + + AthleteList[theId] = a; + + return a; + } + else + { + return null; + } + } + + public async Task DeleteAthleteAsync(int id) + { + var theId = AthleteList.FindIndex(a => a.IdAthlete == id); + if (theId >= 0) + { + AthleteList.RemoveAt(theId); + return true; + } else + { + return false; + } + } +} diff --git a/src/StubbedDtoLib/StubbedDtoLib.csproj b/src/StubbedDtoLib/StubbedDtoLib.csproj new file mode 100644 index 0000000..581f491 --- /dev/null +++ b/src/StubbedDtoLib/StubbedDtoLib.csproj @@ -0,0 +1,14 @@ + + + + + + + + + net8.0 + enable + enable + + + diff --git a/src/Tests/TestsAPI/ClientTests/ClientTests.csproj b/src/Tests/TestsAPI/ClientTests/ClientTests.csproj new file mode 100644 index 0000000..206b89a --- /dev/null +++ b/src/Tests/TestsAPI/ClientTests/ClientTests.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/src/Tests/TestsAPI/ClientTests/Program.cs b/src/Tests/TestsAPI/ClientTests/Program.cs new file mode 100644 index 0000000..83fa4f4 --- /dev/null +++ b/src/Tests/TestsAPI/ClientTests/Program.cs @@ -0,0 +1,2 @@ +// See https://aka.ms/new-console-template for more information +Console.WriteLine("Hello, World!"); diff --git a/src/Tests/TestsAPI/TestsXUnit/GlobalUsings.cs b/src/Tests/TestsAPI/TestsXUnit/GlobalUsings.cs new file mode 100644 index 0000000..8c927eb --- /dev/null +++ b/src/Tests/TestsAPI/TestsXUnit/GlobalUsings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file diff --git a/src/Tests/TestsAPI/TestsXUnit/TestsXUnit.csproj b/src/Tests/TestsAPI/TestsXUnit/TestsXUnit.csproj new file mode 100644 index 0000000..22b0134 --- /dev/null +++ b/src/Tests/TestsAPI/TestsXUnit/TestsXUnit.csproj @@ -0,0 +1,25 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + diff --git a/src/Tests/TestsAPI/TestsXUnit/UnitTest1.cs b/src/Tests/TestsAPI/TestsXUnit/UnitTest1.cs new file mode 100644 index 0000000..70d745a --- /dev/null +++ b/src/Tests/TestsAPI/TestsXUnit/UnitTest1.cs @@ -0,0 +1,10 @@ +namespace TestsXUnit; + +public class UnitTest1 +{ + [Fact] + public void Test1() + { + + } +} \ No newline at end of file From 7d1a10a281424acfd8743762c1ee76e40217fc73 Mon Sep 17 00:00:00 2001 From: anperederi Date: Fri, 23 Feb 2024 09:02:58 +0100 Subject: [PATCH 2/6] =?UTF-8?q?=F0=9F=94=A5=20Update=20Stubbed=20Files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/StubbedDtoLib/AthleteStubDto.cs | 132 +------------------------ src/StubbedDtoLib/StubbedDtoLib.csproj | 6 +- 2 files changed, 5 insertions(+), 133 deletions(-) diff --git a/src/StubbedDtoLib/AthleteStubDto.cs b/src/StubbedDtoLib/AthleteStubDto.cs index 1b501c7..67876f2 100644 --- a/src/StubbedDtoLib/AthleteStubDto.cs +++ b/src/StubbedDtoLib/AthleteStubDto.cs @@ -1,135 +1,7 @@ -using System.ComponentModel; -using Dto; -using Share; +using Shared; namespace StubbedDtoLib; public class AthleteStubDto : IAthleteService { - private static List AthleteList = new List() - { - new AthleteDto { IdAthlete = 1, Username = "Doe", LastName = "John", FirstName = "Doe", Email = "john.doe@example.com", Password = "password123", Sexe = "M", Lenght = 1.80, Weight = 75, DateOfBirth = new DateTime(), IsCoach = true }, - new AthleteDto { IdAthlete = 2, Username = "Smith", LastName = "Jane", FirstName = "Smith", Email = "jane.smith@example.com", Password = "secure456", Sexe = "F", Lenght = 1.65, Weight = 60, DateOfBirth = new DateTime(), IsCoach = false }, - new AthleteDto { IdAthlete = 3, Username = "Martin", LastName = "Paul", FirstName = "Martin", Email = "paul.martin@example.com", Password = "super789", Sexe = "M", Lenght = 1.75, Weight = 68, DateOfBirth = new DateTime(), IsCoach = true }, - new AthleteDto { IdAthlete = 4, Username = "Brown", LastName = "Anna", FirstName = "Brown", Email = "anna.brown@example.com", Password = "test000", Sexe = "M", Lenght = 1.70, Weight = 58, DateOfBirth = new DateTime(), IsCoach = false }, - new AthleteDto { IdAthlete = 5, Username = "Lee", LastName = "Bruce", FirstName = "Lee", Email = "bruce.lee@example.com", Password = "hello321", Sexe = "M", Lenght = 2.0, Weight = 90, DateOfBirth = new DateTime(), IsCoach = false } - }; - - public async Task> GetAllAthletesAsync() - { - return AthleteList; - } - - public async Task> GetSomeAthletesAsync(int index, int count) - { - return AthleteList.Skip(count*index).Take(count); - } - - public async Task GetAthleteByIdAsync(int id) => AthleteList.Find(a => a.IdAthlete == id); - - public async Task> GetAthleteByUsernameAsync(string username, int index, int count) - { - return AthleteList.FindAll(a => a.Username.Contains(username, StringComparison.OrdinalIgnoreCase)).Skip(index*count).Take(count); - } - - public async Task> GetAthletesByEmailAsync(string email, int index, int count) - { - return AthleteList.FindAll(a => a.Email.Contains(email, StringComparison.OrdinalIgnoreCase)).Skip(index*count).Take(count); - } - - public async Task> GetAthletesByFirstNameAsync(string firstName, int index, int count) - { - return AthleteList.FindAll(a => a.FirstName.Contains(firstName, StringComparison.OrdinalIgnoreCase)).Skip(index*count).Take(count); - } - - public async Task> GetAthletesByLastNameAsync(string lastName, int index, int count) - { - return AthleteList.FindAll(a => a.LastName.Contains(lastName, StringComparison.OrdinalIgnoreCase)).Skip(index*count).Take(count); - } - - public async Task> GetAthletesBySexeAsync(string sexe, int index, int count) - { - return AthleteList.FindAll(a => a.Sexe.Contains(sexe, StringComparison.OrdinalIgnoreCase)).Skip(index*count).Take(count); - } - - public async Task> GetAthletesByLenghtAsync(double lenght, int index, int count) - { - return AthleteList.FindAll(a => a.Lenght == lenght).Skip(index*count).Take(count); - } - - public async Task> GetAthletesByWeightAsync(float weight, int index, int count) - { - return AthleteList.FindAll(a => a.Weight == weight).Skip(index*count).Take(count); - } - - public async Task> GetAthletesByDateOfBirthAsync(DateTime dateOfBirth, int index, int count) - { - return AthleteList.FindAll(a => a.DateOfBirth == dateOfBirth).Skip(index*count).Take(count); - } - - public async Task> GetAthletesByIsCoachAsync(bool isCoach, int index, int count) - { - return AthleteList.FindAll(a => a.IsCoach == isCoach).Skip(index*count).Take(count); - } - - public async Task AddAthleteAsync(AthleteDto athlete) - { - var newAthlete = new AthleteDto() - { - IdAthlete = AthleteList.Max(a => a.IdAthlete) + 1, - Username = athlete.Username, - LastName = athlete.LastName, - FirstName = athlete.FirstName, - Email = athlete.Email, - Password = athlete.Password, - Sexe = athlete.Sexe, - Lenght = athlete.Lenght, - Weight = athlete.Weight, - DateOfBirth = athlete.DateOfBirth, - IsCoach = athlete.IsCoach - }; - AthleteList.Add(newAthlete); - return newAthlete; - } - - public async Task UpdateAthleteAsync(int id, AthleteDto athlete) - { - var theId = AthleteList.FindIndex(a => a.IdAthlete == id); - if (theId >= 0) - { - var a = AthleteList[theId]; - - a.Username = athlete.Username; - a.LastName = athlete.LastName; - a.FirstName = athlete.FirstName; - a.Email = athlete.Email; - a.Password = athlete.Password; - a.Sexe = athlete.Sexe; - a.Lenght = athlete.Lenght; - a.Weight = athlete.Weight; - a.DateOfBirth = athlete.DateOfBirth; - a.IsCoach = athlete.IsCoach; - - AthleteList[theId] = a; - - return a; - } - else - { - return null; - } - } - - public async Task DeleteAthleteAsync(int id) - { - var theId = AthleteList.FindIndex(a => a.IdAthlete == id); - if (theId >= 0) - { - AthleteList.RemoveAt(theId); - return true; - } else - { - return false; - } - } -} +} \ No newline at end of file diff --git a/src/StubbedDtoLib/StubbedDtoLib.csproj b/src/StubbedDtoLib/StubbedDtoLib.csproj index 581f491..aa1b3e2 100644 --- a/src/StubbedDtoLib/StubbedDtoLib.csproj +++ b/src/StubbedDtoLib/StubbedDtoLib.csproj @@ -1,8 +1,8 @@  - - - + + + From 224f16110fcd710f16635c43b44fc9edca536dec Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 5 Mar 2024 00:49:14 +0100 Subject: [PATCH 3/6] first --- .gitignore | 18 +- src/ApiMappeur/ApiMappeur.csproj | 14 ++ src/ApiMappeur/AthleteMappeur.cs | 59 +++++++ src/ApiMappeur/EnnumMappeur.cs | 22 +++ src/Dto/AthleteDto.cs | 10 +- src/HeartTrack.sln | 24 ++- .../Controllers/AthleteController.cs | 26 --- .../Controllers/UsersController.cs | 159 ++++++++++++++++++ src/HeartTrackAPI/HeartTrackAPI.csproj | 8 +- src/HeartTrackAPI/Program.cs | 34 +--- src/HeartTrackAPI/Request/PageRequest.cs | 9 + src/HeartTrackAPI/Responce/PageResponse.cs | 22 +++ src/Model/Athlete.cs | 9 + src/Model/Coach.cs | 10 ++ src/Model/IAthleteService.cs | 16 ++ src/Model/Model.csproj | 13 ++ src/Model/Notification.cs | 6 + src/Model/RelationshipRequest.cs | 6 + src/Model/Role.cs | 42 +++++ src/Model/Training.cs | 6 + src/Model/User.cs | 41 +++++ src/Shared/AthleteOrderCriteria.cs | 7 + src/Shared/IAthleteService.cs | 23 --- src/StubAPI/AthleteService.cs | 67 ++++++++ src/StubAPI/Extensions.cs | 40 +++++ src/StubAPI/StubAPI.csproj | 13 ++ src/StubApi/AthleteStubDto.cs | 4 + .../StubApi.csproj} | 29 ++-- src/StubbedDtoLib/AthleteStubDto.cs | 7 - 29 files changed, 634 insertions(+), 110 deletions(-) create mode 100644 src/ApiMappeur/ApiMappeur.csproj create mode 100644 src/ApiMappeur/AthleteMappeur.cs create mode 100644 src/ApiMappeur/EnnumMappeur.cs delete mode 100644 src/HeartTrackAPI/Controllers/AthleteController.cs create mode 100644 src/HeartTrackAPI/Controllers/UsersController.cs create mode 100644 src/HeartTrackAPI/Request/PageRequest.cs create mode 100644 src/HeartTrackAPI/Responce/PageResponse.cs create mode 100644 src/Model/Athlete.cs create mode 100644 src/Model/Coach.cs create mode 100644 src/Model/IAthleteService.cs create mode 100644 src/Model/Model.csproj create mode 100644 src/Model/Notification.cs create mode 100644 src/Model/RelationshipRequest.cs create mode 100644 src/Model/Role.cs create mode 100644 src/Model/Training.cs create mode 100644 src/Model/User.cs delete mode 100644 src/Shared/IAthleteService.cs create mode 100644 src/StubAPI/AthleteService.cs create mode 100644 src/StubAPI/Extensions.cs create mode 100644 src/StubAPI/StubAPI.csproj create mode 100644 src/StubApi/AthleteStubDto.cs rename src/{StubbedDtoLib/StubbedDtoLib.csproj => StubApi/StubApi.csproj} (87%) delete mode 100644 src/StubbedDtoLib/AthleteStubDto.cs diff --git a/.gitignore b/.gitignore index 6d8621c..560f2ab 100644 --- a/.gitignore +++ b/.gitignore @@ -498,7 +498,8 @@ fabric.properties .LSOverride # Icon must end with two \r -Icon +Icon + # Thumbnails ._* @@ -548,3 +549,18 @@ xcuserdata/ *.xcscmblueprint *.xccheckout + +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/.idea.HeartTrack.iml +/modules.xml +/projectSettingsUpdater.xml +/contentModel.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +.idea \ No newline at end of file diff --git a/src/ApiMappeur/ApiMappeur.csproj b/src/ApiMappeur/ApiMappeur.csproj new file mode 100644 index 0000000..7ba11f5 --- /dev/null +++ b/src/ApiMappeur/ApiMappeur.csproj @@ -0,0 +1,14 @@ + + + + net8.0 + enable + enable + + + + + + + + diff --git a/src/ApiMappeur/AthleteMappeur.cs b/src/ApiMappeur/AthleteMappeur.cs new file mode 100644 index 0000000..1021e13 --- /dev/null +++ b/src/ApiMappeur/AthleteMappeur.cs @@ -0,0 +1,59 @@ +using Dto; +using Model; + +namespace ApiMappeur; + +public static class UserMappeur +{ + public static UserDto ToDto(this User user) + { + return new UserDto + { + Id = user.Id, + Username = user.Username, + ProfilePicture = user.ProfilePicture, + LastName = user.LastName, + FirstName = user.FirstName, + Email = user.Email, + Password = user.MotDePasse, + Sexe = user.Sexe, + Lenght = user.Lenght, + Weight = user.Weight, + DateOfBirth = user.DateOfBirth, + IsCoach = user.Role is Coach + }; + + } + + public static User ToModel(this UserDto userDto) + { + if (userDto.IsCoach) + { + return new User( + userDto.Username, + userDto.ProfilePicture, + userDto.LastName, + userDto.FirstName, + userDto.Email, + userDto.Password, + userDto.Sexe, + userDto.Lenght, + userDto.Weight, + userDto.DateOfBirth, + new Coach() + ); + } + return new User( + userDto.Username, + userDto.ProfilePicture, + userDto.LastName, + userDto.FirstName, + userDto.Email, + userDto.Password, + userDto.Sexe, + userDto.Lenght, + userDto.Weight, + userDto.DateOfBirth, + new Athlete()); + } +} \ No newline at end of file diff --git a/src/ApiMappeur/EnnumMappeur.cs b/src/ApiMappeur/EnnumMappeur.cs new file mode 100644 index 0000000..22dc8b5 --- /dev/null +++ b/src/ApiMappeur/EnnumMappeur.cs @@ -0,0 +1,22 @@ +namespace ApiMappeur; + +public static class EnumMappeur +{ + public static Shared.AthleteOrderCriteria ToEnum(this string value) + { + return value switch + { + "None" => Shared.AthleteOrderCriteria.None, + "ByUsername" => Shared.AthleteOrderCriteria.ByUsername, + "ByFirstName" => Shared.AthleteOrderCriteria.ByFirstName, + "ByLastName" => Shared.AthleteOrderCriteria.ByLastName, + "BySexe" => Shared.AthleteOrderCriteria.BySexe, + "ByLenght" => Shared.AthleteOrderCriteria.ByLenght, + "ByWeight" => Shared.AthleteOrderCriteria.ByWeight, + "ByDateOfBirth" => Shared.AthleteOrderCriteria.ByDateOfBirth, + "ByEmail" => Shared.AthleteOrderCriteria.ByEmail, + "ByIsCoach" => Shared.AthleteOrderCriteria.ByIsCoach, + _ => Shared.AthleteOrderCriteria.None + }; + } +} \ No newline at end of file diff --git a/src/Dto/AthleteDto.cs b/src/Dto/AthleteDto.cs index cbae984..9ee369d 100644 --- a/src/Dto/AthleteDto.cs +++ b/src/Dto/AthleteDto.cs @@ -2,9 +2,9 @@ namespace Dto; -public class AthleteDto +public class UserDto { - public int IdAthlete { get; set; } + public int Id { get; set; } [MaxLength(100)] public required string Username { get; set; } [MaxLength(150)] @@ -13,9 +13,11 @@ public class AthleteDto public required string FirstName { get; set; } public required string Email { get; set; } public required string Sexe { get; set; } - public double Lenght { get; set; } + public float Lenght { get; set; } public float Weight { get; set; } - public required string Password { get; set; } + public string? Password { get; set; } public DateTime DateOfBirth { get; set; } + + public string ProfilePicture { get; set; } = "default.jpg"; public bool IsCoach { get; set; } } diff --git a/src/HeartTrack.sln b/src/HeartTrack.sln index ddc2c8a..19f2afd 100644 --- a/src/HeartTrack.sln +++ b/src/HeartTrack.sln @@ -21,14 +21,18 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeartTrackAPI", "HeartTrack EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared", "Shared\Shared.csproj", "{F80C60E1-1E06-46C2-96DE-42B1C7DE65BC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StubbedDtoLib", "StubbedDtoLib\StubbedDtoLib.csproj", "{87F65E21-0555-4772-88B4-C8B43146A02C}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestsAPI", "TestsAPI", "{30FC2BE9-7397-445A-84AD-043CE70F4281}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClientTests", "Tests\TestsAPI\ClientTests\ClientTests.csproj", "{9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestsXUnit", "Tests\TestsAPI\TestsXUnit\TestsXUnit.csproj", "{44C367DC-5FE0-4CF2-9E76-A0282E931853}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "Model\Model.csproj", "{30AB7FAA-6072-40B6-A15E-9188B59144F9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApiMappeur", "ApiMappeur\ApiMappeur.csproj", "{CB142F6B-0FF1-45B3-AB46-6F8DCD096C20}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StubAPI", "StubAPI\StubAPI.csproj", "{B9679DCA-F4C8-45BE-A849-44E2BA814083}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -70,10 +74,6 @@ Global {F80C60E1-1E06-46C2-96DE-42B1C7DE65BC}.Debug|Any CPU.Build.0 = Debug|Any CPU {F80C60E1-1E06-46C2-96DE-42B1C7DE65BC}.Release|Any CPU.ActiveCfg = Release|Any CPU {F80C60E1-1E06-46C2-96DE-42B1C7DE65BC}.Release|Any CPU.Build.0 = Release|Any CPU - {87F65E21-0555-4772-88B4-C8B43146A02C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {87F65E21-0555-4772-88B4-C8B43146A02C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {87F65E21-0555-4772-88B4-C8B43146A02C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {87F65E21-0555-4772-88B4-C8B43146A02C}.Release|Any CPU.Build.0 = Release|Any CPU {9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}.Debug|Any CPU.Build.0 = Debug|Any CPU {9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -82,6 +82,18 @@ Global {44C367DC-5FE0-4CF2-9E76-A0282E931853}.Debug|Any CPU.Build.0 = Debug|Any CPU {44C367DC-5FE0-4CF2-9E76-A0282E931853}.Release|Any CPU.ActiveCfg = Release|Any CPU {44C367DC-5FE0-4CF2-9E76-A0282E931853}.Release|Any CPU.Build.0 = Release|Any CPU + {30AB7FAA-6072-40B6-A15E-9188B59144F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {30AB7FAA-6072-40B6-A15E-9188B59144F9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {30AB7FAA-6072-40B6-A15E-9188B59144F9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {30AB7FAA-6072-40B6-A15E-9188B59144F9}.Release|Any CPU.Build.0 = Release|Any CPU + {CB142F6B-0FF1-45B3-AB46-6F8DCD096C20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CB142F6B-0FF1-45B3-AB46-6F8DCD096C20}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB142F6B-0FF1-45B3-AB46-6F8DCD096C20}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CB142F6B-0FF1-45B3-AB46-6F8DCD096C20}.Release|Any CPU.Build.0 = Release|Any CPU + {B9679DCA-F4C8-45BE-A849-44E2BA814083}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B9679DCA-F4C8-45BE-A849-44E2BA814083}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B9679DCA-F4C8-45BE-A849-44E2BA814083}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B9679DCA-F4C8-45BE-A849-44E2BA814083}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {477D2129-A6C9-4FF8-8BE9-5E9E8E5282F8} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} diff --git a/src/HeartTrackAPI/Controllers/AthleteController.cs b/src/HeartTrackAPI/Controllers/AthleteController.cs deleted file mode 100644 index 7180759..0000000 --- a/src/HeartTrackAPI/Controllers/AthleteController.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Dto; -using Microsoft.AspNetCore.Mvc; -using Shared; - -[ApiController] -[Route("api/athletes")] -public class AthletesController : ControllerBase -{ - private readonly ILogger _logger; - IAthleteService _stubbedDto; - private const int DEFAULT_INDEX = 0, DEFAULT_COUNT = 5; - - public AthletesController(ILogger logger, IAthleteService athletesService) - { - _logger = logger; - _stubbedDto = athletesService; - } - - [HttpGet("all")] - [ProducesResponseType(typeof(IEnumerable), 200)] - public async Task GetAllAthletesAsync() - { - var athletes = await _stubbedDto.GetAllAthletesAsync(); - return Ok(athletes); - } -} \ No newline at end of file diff --git a/src/HeartTrackAPI/Controllers/UsersController.cs b/src/HeartTrackAPI/Controllers/UsersController.cs new file mode 100644 index 0000000..8887667 --- /dev/null +++ b/src/HeartTrackAPI/Controllers/UsersController.cs @@ -0,0 +1,159 @@ +using ApiMappeur; +using Dto; +using HeartTrackAPI.Request; +using HeartTrackAPI.Responce; +using Microsoft.AspNetCore.Mvc; +using Model; +using Shared; + +namespace HeartTrackAPI.Controllers; + +[ApiController] +[Route("api/users")] +public class UsersController : Controller +{ + // For the moment only support user who are athletes next handle user that are coach or athlete + private readonly ILogger _logger; + private readonly IUserService _userService; + public UsersController(ILogger logger, IUserService usersService) + { + _logger = logger; + _userService = usersService; + } + + [HttpGet] + [ProducesResponseType(typeof(IEnumerable), 200)] + [ProducesResponseType(400)] + [ProducesResponseType(500)] + public async Task>> GetAllAthletes([FromQuery] PageRequest request) + { + try + { + var totalCount = await _userService.GetNbItems(); + if (request.Count * request.Index >= totalCount) + { + _logger.LogError("To many object is asked the max is {totalCount} but the request is superior of ", totalCount); + return BadRequest("To many object is asked the max is : " + totalCount); + } + _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetAllAthletes), null); + // request.OrderingPropertyName + var athletes = await _userService.GetUsers(request.Index, request.Count, AthleteOrderCriteria.None, request.Descending ?? false); + var pageResponse = new PageResponse(request.Index, request.Count, totalCount, athletes.Select(a => a.ToDto())); + return Ok(pageResponse); + } + catch (Exception e) + { + _logger.LogError(e, "Error while getting all athletes"); + return StatusCode(500); + } + } + + [HttpGet("{id}")] + [ProducesResponseType(typeof(UserDto), 200)] + [ProducesResponseType(404)] + [ProducesResponseType(500)] + public async Task> GetAthleteById(int id) + { + try + { + _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetAthleteById), id); + var athlete = await _userService.GetUserByIdAsync(id); + if (athlete == null) + { + _logger.LogError("Athlete with id {id} not found", id); + return NotFound($"Athlete with id {id} not found"); + } + return Ok(athlete.ToDto()); + } + catch (Exception e) + { + _logger.LogError(e, "Error while getting athlete by id {id}", id); + return StatusCode(500); + } + } + + + [HttpGet("count")] + [ProducesResponseType(typeof(int), 200)] + [ProducesResponseType(500)] + public async Task> GetNbUsers() + { + try + { + _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetNbUsers), null); + var nbUsers = await _userService.GetNbItems(); + return Ok(nbUsers); + } + catch (Exception e) + { + _logger.LogError(e, "Error while getting the number of users"); + return StatusCode(500); + } + } + + [HttpPut("{id}")] + [ProducesResponseType(typeof(UserDto), 200)] + [ProducesResponseType(404)] + [ProducesResponseType(500)] + // need to adapt with coach + public async Task> UpdateUser(int id, [FromBody] UserDto user) + { + try + { + _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(UpdateUser), user,id); + var athlete = await _userService.GetUserByIdAsync(id); + if (athlete == null) + { + _logger.LogError("Athlete with id {id} not found", id); + return NotFound($"Athlete with id {id} not found"); + } + var updatedAthlete = await _userService.UpdateUser(id, user.ToModel()); + if(updatedAthlete == null) + { + _logger.LogError("Error while updating athlete with id {id}", id); + return StatusCode(500); + } + return Ok(updatedAthlete.ToDto()); + + } + catch (Exception e) + { + _logger.LogError(e, "Error while getting the number of users"); + return StatusCode(500); + } + } + + [HttpDelete("{id}")] + [ProducesResponseType(200)] + [ProducesResponseType(404)] + [ProducesResponseType(500)] + public async Task DeleteUser(int id) + { + try + { + _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(DeleteUser), null,id); + + + var athlete = await _userService.GetUserByIdAsync(id); + if (athlete == null) + { + _logger.LogError("Athlete with id {id} not found", id); + return NotFound($"Athlete with id {id} not found"); + } + var isDeleted = await _userService.DeleteUser(id); + if(!isDeleted) + { + _logger.LogError("Error while deleting athlete with id {id}", id); + return StatusCode(500); + } + return Ok(); + } + catch (Exception e) + { + _logger.LogError(e, "Error while getting the number of users"); + return StatusCode(500); + } + } + + +} \ No newline at end of file diff --git a/src/HeartTrackAPI/HeartTrackAPI.csproj b/src/HeartTrackAPI/HeartTrackAPI.csproj index 0a86543..35ec313 100644 --- a/src/HeartTrackAPI/HeartTrackAPI.csproj +++ b/src/HeartTrackAPI/HeartTrackAPI.csproj @@ -12,8 +12,12 @@ - - + + + + + + diff --git a/src/HeartTrackAPI/Program.cs b/src/HeartTrackAPI/Program.cs index fda9a7d..bda6f2e 100644 --- a/src/HeartTrackAPI/Program.cs +++ b/src/HeartTrackAPI/Program.cs @@ -1,10 +1,14 @@ +using Model; +using StubAPI; + var builder = WebApplication.CreateBuilder(args); // Add services to the container. // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); - +builder.Services.AddControllers(); +builder.Services.AddSingleton(); var app = builder.Build(); // Configure the HTTP request pipeline. @@ -16,29 +20,5 @@ if (app.Environment.IsDevelopment()) app.UseHttpsRedirection(); -var summaries = new[] -{ - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" -}; - -app.MapGet("/weatherforecast", () => -{ - var forecast = Enumerable.Range(1, 5).Select(index => - new WeatherForecast - ( - DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - Random.Shared.Next(-20, 55), - summaries[Random.Shared.Next(summaries.Length)] - )) - .ToArray(); - return forecast; -}) -.WithName("GetWeatherForecast") -.WithOpenApi(); - -app.Run(); - -record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) -{ - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); -} +app.MapControllers(); +app.Run(); \ No newline at end of file diff --git a/src/HeartTrackAPI/Request/PageRequest.cs b/src/HeartTrackAPI/Request/PageRequest.cs new file mode 100644 index 0000000..fce6be3 --- /dev/null +++ b/src/HeartTrackAPI/Request/PageRequest.cs @@ -0,0 +1,9 @@ +namespace HeartTrackAPI.Request; + +public class PageRequest +{ + public string? OrderingPropertyName { get; set; } = null;// need to be map on the dto OrderCriteria + public bool? Descending { get; set; } = false; + public int Index { get; set; } = 0; + public int Count { get; set; } = 5; +} \ No newline at end of file diff --git a/src/HeartTrackAPI/Responce/PageResponse.cs b/src/HeartTrackAPI/Responce/PageResponse.cs new file mode 100644 index 0000000..93b4cfe --- /dev/null +++ b/src/HeartTrackAPI/Responce/PageResponse.cs @@ -0,0 +1,22 @@ +namespace HeartTrackAPI.Responce; + +public class PageResponse +{ + // The index of the first item + public int Index { get; set; } = 1; + // The number of items + public int Count { get; set; } = 1; + // The total number of items + public int Total { get; set; } = 1; + // The items + public IEnumerable Items { get; set; } + + public PageResponse(int index, int count, int total, IEnumerable items) + { + Index = index; + Count = count; + Total = total; + Items = items; + } + +} \ No newline at end of file diff --git a/src/Model/Athlete.cs b/src/Model/Athlete.cs new file mode 100644 index 0000000..fa04950 --- /dev/null +++ b/src/Model/Athlete.cs @@ -0,0 +1,9 @@ +namespace Model; + +public class Athlete : Role +{ + public override bool CheckAdd(User user) + { + return user.Role is Athlete; + } +} \ No newline at end of file diff --git a/src/Model/Coach.cs b/src/Model/Coach.cs new file mode 100644 index 0000000..84fd18c --- /dev/null +++ b/src/Model/Coach.cs @@ -0,0 +1,10 @@ +namespace Model; + +public class Coach : Role +{ + public override bool CheckAdd(User user) + { + return user.Role is Athlete; + } + +} \ No newline at end of file diff --git a/src/Model/IAthleteService.cs b/src/Model/IAthleteService.cs new file mode 100644 index 0000000..ec9fac8 --- /dev/null +++ b/src/Model/IAthleteService.cs @@ -0,0 +1,16 @@ +using Dto; +using Model; +using Shared; + +namespace Model; + +public interface IUserService +{ + public Task> GetUsers(int index, int count, AthleteOrderCriteria criteria , bool descending = false); + public Task GetUserByIdAsync(int id); + public Task AddUser(User athlete); + public Task UpdateUser(int id, User user); + public Task DeleteUser(int id); + public Task GetNbItems(); + +} \ No newline at end of file diff --git a/src/Model/Model.csproj b/src/Model/Model.csproj new file mode 100644 index 0000000..18de4eb --- /dev/null +++ b/src/Model/Model.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/src/Model/Notification.cs b/src/Model/Notification.cs new file mode 100644 index 0000000..8a2617a --- /dev/null +++ b/src/Model/Notification.cs @@ -0,0 +1,6 @@ +namespace Model; + +public class Notification +{ + +} \ No newline at end of file diff --git a/src/Model/RelationshipRequest.cs b/src/Model/RelationshipRequest.cs new file mode 100644 index 0000000..9024b50 --- /dev/null +++ b/src/Model/RelationshipRequest.cs @@ -0,0 +1,6 @@ +namespace Model; + +public class RelationshipRequest +{ + +} \ No newline at end of file diff --git a/src/Model/Role.cs b/src/Model/Role.cs new file mode 100644 index 0000000..5353ea7 --- /dev/null +++ b/src/Model/Role.cs @@ -0,0 +1,42 @@ +namespace Model; + +public abstract class Role +{ + protected List UsersList { get; set; } = []; + protected List UsersRequests { get; set; } = []; + protected List TrainingList { get; set; } = []; + public abstract bool CheckAdd(User user); + + public bool AddUser(User user) + { + if (!CheckAdd(user)) return false; + UsersList.Add(user); + return true; + } + + public bool RemoveUser(User user) + { + return UsersList.Remove(user); + } + + public void AddTraining(Training training) + { + TrainingList.Add(training); + } + + public bool RemoveTraining(Training training) + { + return TrainingList.Remove(training); + } + + public void AddUserRequest(RelationshipRequest request) + { + UsersRequests.Add(request); + } + + public bool RemoveUserRequest(RelationshipRequest request) + { + return UsersRequests.Remove(request); + + } +} \ No newline at end of file diff --git a/src/Model/Training.cs b/src/Model/Training.cs new file mode 100644 index 0000000..164afbb --- /dev/null +++ b/src/Model/Training.cs @@ -0,0 +1,6 @@ +namespace Model; + +public class Training +{ + +} \ No newline at end of file diff --git a/src/Model/User.cs b/src/Model/User.cs new file mode 100644 index 0000000..6efffa8 --- /dev/null +++ b/src/Model/User.cs @@ -0,0 +1,41 @@ +namespace Model; + +public class User +{ + public int Id { get; set; } + public string Username { get; set; } + public string ProfilePicture { get; set; } + public string LastName { get; set; } + public string FirstName { get; set; } + public string Email { get; set; } + public string MotDePasse { get; set; } + public string Sexe { get; set; } + public float Lenght { get; set; } + public float Weight { get; set; } + public DateTime DateOfBirth { get; set; } + public Role Role { get; set; } + + protected List Notifications { get; set; } = new List(); + + public User( string username, string profilePicture, string nom, string prenom, string email, string motDePasse, string sexe, float taille, float poids, DateTime dateNaissance, Role role) + { + Username = username; + ProfilePicture = profilePicture; + LastName = nom; + FirstName = prenom; + Email = email; + MotDePasse = motDePasse; + Sexe = sexe; + Lenght = taille; + Weight = poids; + DateOfBirth = dateNaissance; + Role = role; + } + public User(){} + + + + + + +} \ No newline at end of file diff --git a/src/Shared/AthleteOrderCriteria.cs b/src/Shared/AthleteOrderCriteria.cs index 2a7085d..681b04e 100644 --- a/src/Shared/AthleteOrderCriteria.cs +++ b/src/Shared/AthleteOrderCriteria.cs @@ -4,8 +4,15 @@ { None, ByUsername, + ByFirstName, + ByLastName, + BySexe, + ByLenght, + ByWeight, + ByDateOfBirth, ByEmail, ByIsCoach } + } diff --git a/src/Shared/IAthleteService.cs b/src/Shared/IAthleteService.cs deleted file mode 100644 index 17ff7f2..0000000 --- a/src/Shared/IAthleteService.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Dto; - -namespace Shared; - -public interface IAthleteService -{ - public Task> GetAllAthletesAsync(); - public Task> GetSomeAthletesAsync(int index, int count, AthleteOrderCriteria criterium); - public Task GetAthleteByIdAsync(int id); - public Task> GetAthleteByUsernameAsync(string username, int index, int count, AthleteOrderCriteria criterium); - public Task> GetAthletesByEmailAsync(string email, int index, int count, AthleteOrderCriteria criterium); - public Task> GetAthletesByFirstNameAsync(string firstName, int index, int count, AthleteOrderCriteria criterium); - public Task> GetAthletesByLastNameAsync(string lastName, int index, int count, AthleteOrderCriteria criterium); - public Task> GetAthletesBySexeAsync(string sexe, int index, int count, AthleteOrderCriteria criterium); - public Task> GetAthletesByLenghtAsync(double lenght, int index, int count, AthleteOrderCriteria criterium); - public Task> GetAthletesByWeightAsync(float weight, int index, int count, AthleteOrderCriteria criterium); - public Task> GetAthletesByDateOfBirthAsync(DateTime dateOfBirth, int index, int count, AthleteOrderCriteria criterium); - public Task> GetAthletesByIsCoachAsync(bool isCoach, int index, int count, AthleteOrderCriteria criterium); - public Task AddAthleteAsync(AthleteDto athlete, AthleteOrderCriteria criterium); - public Task UpdateAthleteAsync(int id, AthleteDto athlete, AthleteOrderCriteria criterium); - public Task DeleteAthleteAsync(int id, AthleteOrderCriteria criterium); - -} \ No newline at end of file diff --git a/src/StubAPI/AthleteService.cs b/src/StubAPI/AthleteService.cs new file mode 100644 index 0000000..9591e51 --- /dev/null +++ b/src/StubAPI/AthleteService.cs @@ -0,0 +1,67 @@ +using Model; +using Shared; + +namespace StubAPI; + +public class UserService : IUserService +{ + private List athletes = + [ + new User + { + Id = 1, Username = "Athlete1", ProfilePicture = "default.png", FirstName = "First1", LastName = "Last1", + Sexe = "M", Lenght = 180, Weight = 70, DateOfBirth = new DateTime(1990, 1, 1), + Email = "athlete1@example.com", Role = new Athlete() + }, + + new User + { + Id = 2, Username = "Athlete2", ProfilePicture = "default.png", FirstName = "First2", LastName = "Last2", + Sexe = "F", Lenght = 170, Weight = 60, DateOfBirth = new DateTime(1992, 2, 2), + Email = "athlete2@example.com", Role = new Coach() + }, + + new User + { + Id = 3, Username = "Athlete3", ProfilePicture = "default.png", FirstName = "First3", LastName = "Last3", + Sexe = "M", Lenght = 190, Weight = 80, DateOfBirth = new DateTime(1994, 3, 3), Email = "ath@ex.fr", + Role = new Athlete() + } + + ]; + + public async Task> GetUsers(int index, int count, AthleteOrderCriteria criteria, + bool descending = false) + { + throw new NotImplementedException(); + } + + public async Task GetUserByIdAsync(int id) + { + return await Task.FromResult(athletes.FirstOrDefault(s => s.Id == id)); + } + + public async Task AddUser(User athlete) + { + return await athletes.AddItem(athlete); + } + + public async Task UpdateUser(int id, User user) + { + var oldUser = athletes.FirstOrDefault(s => s.Id == id); + if (oldUser == null) return null; + return await athletes.UpdateItem(oldUser, user); + } + + public async Task DeleteUser(int id) + { + var user = athletes.FirstOrDefault(s => s.Id == id); + if (user == null) return false; + return await athletes.DeleteItem(user); + } + + public async Task GetNbItems() + { + return await Task.FromResult(athletes.Count); + } +} \ No newline at end of file diff --git a/src/StubAPI/Extensions.cs b/src/StubAPI/Extensions.cs new file mode 100644 index 0000000..e7a036c --- /dev/null +++ b/src/StubAPI/Extensions.cs @@ -0,0 +1,40 @@ +namespace StubAPI; + + +public static class Extensions +{ + internal static Task AddItem(this IList collection, T? item) + { + if(item == null || collection.Contains(item)) + { + return Task.FromResult(default(T)); + } + collection.Add(item); + return Task.FromResult(item); + } + + internal static Task DeleteItem(this IList collection, T? item) + { + if(item == null) + { + return Task.FromResult(false); + } + bool result = collection.Remove(item!); + return Task.FromResult(result); + } + + internal static Task UpdateItem(this IList collection, T? oldItem, T? newItem) + { + if(oldItem == null || newItem == null) return Task.FromResult(default(T)); + + if(!collection.Contains(oldItem)) + { + return Task.FromResult(default(T)); + } + + collection.Remove(oldItem!); + collection.Add(newItem!); + return Task.FromResult(newItem); + } + +} \ No newline at end of file diff --git a/src/StubAPI/StubAPI.csproj b/src/StubAPI/StubAPI.csproj new file mode 100644 index 0000000..b0ff0a6 --- /dev/null +++ b/src/StubAPI/StubAPI.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/src/StubApi/AthleteStubDto.cs b/src/StubApi/AthleteStubDto.cs new file mode 100644 index 0000000..48952e4 --- /dev/null +++ b/src/StubApi/AthleteStubDto.cs @@ -0,0 +1,4 @@ +using Shared; + +namespace + diff --git a/src/StubbedDtoLib/StubbedDtoLib.csproj b/src/StubApi/StubApi.csproj similarity index 87% rename from src/StubbedDtoLib/StubbedDtoLib.csproj rename to src/StubApi/StubApi.csproj index aa1b3e2..3c5171a 100644 --- a/src/StubbedDtoLib/StubbedDtoLib.csproj +++ b/src/StubApi/StubApi.csproj @@ -1,14 +1,15 @@ - - - - - - - - - net8.0 - enable - enable - - - + + + + + + + + + net8.0 + enable + enable + StubbedDtoLib + + + diff --git a/src/StubbedDtoLib/AthleteStubDto.cs b/src/StubbedDtoLib/AthleteStubDto.cs deleted file mode 100644 index 67876f2..0000000 --- a/src/StubbedDtoLib/AthleteStubDto.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Shared; - -namespace StubbedDtoLib; - -public class AthleteStubDto : IAthleteService -{ -} \ No newline at end of file From cc255de979af3c8dd52cd2e9eb4517b8fc3cf705 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 5 Mar 2024 13:25:53 +0100 Subject: [PATCH 4/6] CRUD ended with enum --- src/Dto/ActivityDto.cs | 19 ++++ .../Controllers/ActivityController.cs | 98 +++++++++++++++++++ .../Controllers/UsersController.cs | 9 +- src/HeartTrackAPI/HeartTrackAPI.csproj | 6 ++ src/HeartTrackAPI/Request/PageRequest.cs | 7 +- src/Model/Activity.cs | 68 +++++++++++++ src/Model/IActivityService.cs | 13 +++ src/Model/IAthleteService.cs | 1 - src/Shared/ActivityOrderCriteria.cs | 16 +++ src/Shared/AthleteOrderCriteria.cs | 27 +++++ src/StubAPI/AthleteService.cs | 12 +-- src/StubAPI/Extensions.cs | 30 ++++++ 12 files changed, 292 insertions(+), 14 deletions(-) create mode 100644 src/HeartTrackAPI/Controllers/ActivityController.cs create mode 100644 src/Model/Activity.cs create mode 100644 src/Model/IActivityService.cs create mode 100644 src/Shared/ActivityOrderCriteria.cs diff --git a/src/Dto/ActivityDto.cs b/src/Dto/ActivityDto.cs index e69de29..d4bf5f1 100644 --- a/src/Dto/ActivityDto.cs +++ b/src/Dto/ActivityDto.cs @@ -0,0 +1,19 @@ +namespace Dto; + +public class ActivityDto +{ + public int Id { get; set; } + public string Name { get; set; } + public string Type { get; set; } + public DateTime Date { get; set; } + public TimeSpan Duration { get; set; } + public float Distance { get; set; } + public float Elevation { get; set; } + public float AverageSpeed { get; set; } + public int AverageHeartRate { get; set; } + public int Calories { get; set; } + public string Description { get; set; } + public string? Gpx { get; set; } + public string? Image { get; set; } + public int AthleteId { get; set; } +} \ No newline at end of file diff --git a/src/HeartTrackAPI/Controllers/ActivityController.cs b/src/HeartTrackAPI/Controllers/ActivityController.cs new file mode 100644 index 0000000..7c9d2b0 --- /dev/null +++ b/src/HeartTrackAPI/Controllers/ActivityController.cs @@ -0,0 +1,98 @@ +using Dto; +using HeartTrackAPI.Request; +using HeartTrackAPI.Responce; +using Microsoft.AspNetCore.Mvc; +using Shared; +using Model; +/* +namespace HeartTrackAPI.Controllers; +[ApiController] +[Route("api/activities")] +public class ActivityController : Controller +{ + private readonly IActivityService _activityService; + private readonly ILogger _logger; + + public ActivityController(IActivityService activityService, ILogger logger) + { + _activityService = activityService; + _logger = logger; + } + + [HttpGet] + [ProducesResponseType(typeof(PageResponse), 200)] + [ProducesResponseType(400)] + [ProducesResponseType(500)] + public async Task>> GetActivities([FromQuery] PageRequest pageRequest) + { + try + { + var totalCount = await _activityService.GetNbItems(); + if (pageRequest.Count * pageRequest.Index >= totalCount) + { + _logger.LogError("To many object is asked the max is {totalCount} but the request is superior of ", totalCount); + return BadRequest("To many object is asked the max is : " + totalCount); + } + _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetActivities), pageRequest); + // request.OrderingPropertyName + var activities = await _activityService.GetActivities(pageRequest.Index, pageRequest.Count, ActivityOrderCriteria.None, pageRequest.Descending ?? false); + var pageResponse = new PageResponse(pageRequest.Index, pageRequest.Count, totalCount, activities.Select(a => a.ToDto())); + return Ok(pageResponse); + } + catch (Exception e) + { + _logger.LogError(e, "Error while getting all activities"); + return StatusCode(500); + } + } +/* + [HttpGet("{id}")] + public async Task> GetActivity(int id) + { + var activity = await _activityService.GetActivityByIdAsync(id); + if (activity == null) + { + return NotFound(); + } + return Ok(activity.ToDto()); + } + + [HttpPost] + public async Task> PostActivity(ActivityDto activityDto) + { + var activity = activityDto.ToModel(); + var result = await _activityService.AddActivity(activity); + if (result == null) + { + return BadRequest(); + } + return CreatedAtAction(nameof(GetActivity), new { id = result.Id }, result.ToDto()); + } + + [HttpPut("{id}")] + public async Task PutActivity(int id, ActivityDto activityDto) + { + if (id != activityDto.Id) + { + return BadRequest(); + } + var activity = activityDto.ToModel(); + var result = await _activityService.UpdateActivity(id, activity); + if (result == null) + { + return NotFound(); + } + return NoContent(); + } + + [HttpDelete("{id}")] + public async Task DeleteActivity(int id) + { + var result = await _activityService.DeleteActivity(id); + if (!result) + { + return NotFound(); + } + return NoContent(); + } +}*/ \ No newline at end of file diff --git a/src/HeartTrackAPI/Controllers/UsersController.cs b/src/HeartTrackAPI/Controllers/UsersController.cs index 8887667..ceb09a4 100644 --- a/src/HeartTrackAPI/Controllers/UsersController.cs +++ b/src/HeartTrackAPI/Controllers/UsersController.cs @@ -12,7 +12,6 @@ namespace HeartTrackAPI.Controllers; [Route("api/users")] public class UsersController : Controller { - // For the moment only support user who are athletes next handle user that are coach or athlete private readonly ILogger _logger; private readonly IUserService _userService; public UsersController(ILogger logger, IUserService usersService) @@ -22,7 +21,7 @@ public class UsersController : Controller } [HttpGet] - [ProducesResponseType(typeof(IEnumerable), 200)] + [ProducesResponseType(typeof(PageResponse), 200)] [ProducesResponseType(400)] [ProducesResponseType(500)] public async Task>> GetAllAthletes([FromQuery] PageRequest request) @@ -35,9 +34,10 @@ public class UsersController : Controller _logger.LogError("To many object is asked the max is {totalCount} but the request is superior of ", totalCount); return BadRequest("To many object is asked the max is : " + totalCount); } + _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetAllAthletes), null); - // request.OrderingPropertyName - var athletes = await _userService.GetUsers(request.Index, request.Count, AthleteOrderCriteria.None, request.Descending ?? false); + + var athletes = await _userService.GetUsers(request.Index, request.Count, Enum.TryParse(request.OrderingPropertyName, out AthleteOrderCriteria result) ? result : AthleteOrderCriteria.None, request.Descending ?? false); var pageResponse = new PageResponse(request.Index, request.Count, totalCount, athletes.Select(a => a.ToDto())); return Ok(pageResponse); } @@ -95,7 +95,6 @@ public class UsersController : Controller [ProducesResponseType(typeof(UserDto), 200)] [ProducesResponseType(404)] [ProducesResponseType(500)] - // need to adapt with coach public async Task> UpdateUser(int id, [FromBody] UserDto user) { try diff --git a/src/HeartTrackAPI/HeartTrackAPI.csproj b/src/HeartTrackAPI/HeartTrackAPI.csproj index 35ec313..f24f646 100644 --- a/src/HeartTrackAPI/HeartTrackAPI.csproj +++ b/src/HeartTrackAPI/HeartTrackAPI.csproj @@ -20,4 +20,10 @@ + + + ..\..\..\..\..\.nuget\packages\newtonsoft.json\13.0.1\lib\netstandard2.0\Newtonsoft.Json.dll + + + diff --git a/src/HeartTrackAPI/Request/PageRequest.cs b/src/HeartTrackAPI/Request/PageRequest.cs index fce6be3..bc04934 100644 --- a/src/HeartTrackAPI/Request/PageRequest.cs +++ b/src/HeartTrackAPI/Request/PageRequest.cs @@ -1,9 +1,14 @@ +using System.Text.Json.Serialization; +using Newtonsoft.Json.Converters; +using Shared; + namespace HeartTrackAPI.Request; public class PageRequest { + public string? OrderingPropertyName { get; set; } = null;// need to be map on the dto OrderCriteria public bool? Descending { get; set; } = false; public int Index { get; set; } = 0; public int Count { get; set; } = 5; -} \ No newline at end of file +} diff --git a/src/Model/Activity.cs b/src/Model/Activity.cs new file mode 100644 index 0000000..4e5cf64 --- /dev/null +++ b/src/Model/Activity.cs @@ -0,0 +1,68 @@ +using System.ComponentModel.DataAnnotations; + +namespace Model; +public class Activity + { + public int IdActivity { get; private set; } + public string Type { get; set; } + public DateTime Date { get; set; } + public DateTime StartTime { get; set; } + public DateTime EndTime { get; set; } + + private int _effort; + [Range(0, 5)] + public int Effort + { + get => _effort; + set + { + if (value < 0 || value > 5) + { + throw new ArgumentException("Effort must be between 0 and 5."); + } + _effort = value; + } + } + public float Variability { get; set; } + public float Variance { get; set; } + public float StandardDeviation { get; set; } + public float Average { get; set; } + public int Maximum { get; set; } + public int Minimum { get; set; } + public float AverageTemperature { get; set; } + public bool HasAutoPause { get; set; } + + public Activity(int idActivity ,string type, DateTime date, DateTime startTime, DateTime endTime, + int effort, float variability, float variance, float standardDeviation, + float average, int maximum, int minimum, float averageTemperature, bool hasAutoPause) + { + IdActivity = idActivity; + Type = type; + Date = date; + StartTime = startTime; + EndTime = endTime; + Effort = effort; + Variability = variability; + Variance = variance; + StandardDeviation = standardDeviation; + Average = average; + Maximum = maximum; + Minimum = minimum; + AverageTemperature = averageTemperature; + HasAutoPause = hasAutoPause; + } + public Activity(){} + + public override string ToString() + { + return $"Activity #{IdActivity}: {Type} on {Date:d/M/yyyy} from {StartTime:HH:mm:ss} to {EndTime:HH:mm:ss}" + + $" with an effort of {Effort}/5 and an average temperature of {AverageTemperature}°C" + + $" and a heart rate variability of {Variability} bpm" + + $" and a variance of {Variance} bpm" + + $" and a standard deviation of {StandardDeviation} bpm" + + $" and an average of {Average} bpm" + + $" and a maximum of {Maximum} bpm" + + $" and a minimum of {Minimum} bpm" + + $" and auto pause is {(HasAutoPause ? "enabled" : "disabled")}."; + } + } \ No newline at end of file diff --git a/src/Model/IActivityService.cs b/src/Model/IActivityService.cs new file mode 100644 index 0000000..152b1c3 --- /dev/null +++ b/src/Model/IActivityService.cs @@ -0,0 +1,13 @@ +using Shared; + +namespace Model; + +public interface IActivityService +{ + public Task> GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending = false); + public Task GetActivityByIdAsync(int id); + public Task AddActivity(Activity activity); + public Task UpdateActivity(int id, Activity activity); + public Task DeleteActivity(int id); + public Task GetNbItems(); +} \ No newline at end of file diff --git a/src/Model/IAthleteService.cs b/src/Model/IAthleteService.cs index ec9fac8..a89ddc2 100644 --- a/src/Model/IAthleteService.cs +++ b/src/Model/IAthleteService.cs @@ -12,5 +12,4 @@ public interface IUserService public Task UpdateUser(int id, User user); public Task DeleteUser(int id); public Task GetNbItems(); - } \ No newline at end of file diff --git a/src/Shared/ActivityOrderCriteria.cs b/src/Shared/ActivityOrderCriteria.cs new file mode 100644 index 0000000..f1e30ed --- /dev/null +++ b/src/Shared/ActivityOrderCriteria.cs @@ -0,0 +1,16 @@ +namespace Shared; + +public enum ActivityOrderCriteria +{ + None, + ByName, + ByType, + ByDate, + ByDuration, + ByDistance, + ByElevation, + ByAverageSpeed, + ByAverageHeartRate, + ByCalories, + ByDescription +} \ No newline at end of file diff --git a/src/Shared/AthleteOrderCriteria.cs b/src/Shared/AthleteOrderCriteria.cs index 681b04e..4bc54f0 100644 --- a/src/Shared/AthleteOrderCriteria.cs +++ b/src/Shared/AthleteOrderCriteria.cs @@ -16,3 +16,30 @@ } + +/*public AthleteOrderCriteria MapToAthleteOrderCriteria(string orderingPropertyName) + { + switch (orderingPropertyName) + { + case nameof(User.Username): + return AthleteOrderCriteria.ByUsername; + case nameof(User.FirstName): + return AthleteOrderCriteria.ByFirstName; + case nameof(User.LastName): + return AthleteOrderCriteria.ByLastName; + case nameof(User.Sexe): + return AthleteOrderCriteria.BySexe; + case nameof(User.Length): + return AthleteOrderCriteria.ByLength; + case nameof(User.Weight): + return AthleteOrderCriteria.ByWeight; + case nameof(User.DateOfBirth): + return AthleteOrderCriteria.ByDateOfBirth; + case nameof(User.Email): + return AthleteOrderCriteria.ByEmail; + case nameof(User.IsCoach): + return AthleteOrderCriteria.ByIsCoach; + default: + return AthleteOrderCriteria.None; + } + }*/ \ No newline at end of file diff --git a/src/StubAPI/AthleteService.cs b/src/StubAPI/AthleteService.cs index 9591e51..bd2f9db 100644 --- a/src/StubAPI/AthleteService.cs +++ b/src/StubAPI/AthleteService.cs @@ -9,21 +9,21 @@ public class UserService : IUserService [ new User { - Id = 1, Username = "Athlete1", ProfilePicture = "default.png", FirstName = "First1", LastName = "Last1", + Id = 1, Username = "DoeDoe", ProfilePicture = "https://images.unsplash.com/photo-1682687982134-2ac563b2228b?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", FirstName = "John", LastName = "Doe", Sexe = "M", Lenght = 180, Weight = 70, DateOfBirth = new DateTime(1990, 1, 1), - Email = "athlete1@example.com", Role = new Athlete() + Email = "john.doe@example.com", Role = new Athlete() }, new User { - Id = 2, Username = "Athlete2", ProfilePicture = "default.png", FirstName = "First2", LastName = "Last2", + Id = 2, Username = "SmithSmith", ProfilePicture = "https://images.unsplash.com/photo-1709507779917-242b560288be?q=80&w=2080&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", FirstName = "Jane", LastName = "Smith", Sexe = "F", Lenght = 170, Weight = 60, DateOfBirth = new DateTime(1992, 2, 2), Email = "athlete2@example.com", Role = new Coach() }, new User { - Id = 3, Username = "Athlete3", ProfilePicture = "default.png", FirstName = "First3", LastName = "Last3", + Id = 3, Username = "Athlete3", ProfilePicture = "https://plus.unsplash.com/premium_photo-1705091981693-6006f8a20479?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", FirstName = "First3", LastName = "Last3", Sexe = "M", Lenght = 190, Weight = 80, DateOfBirth = new DateTime(1994, 3, 3), Email = "ath@ex.fr", Role = new Athlete() } @@ -32,9 +32,7 @@ public class UserService : IUserService public async Task> GetUsers(int index, int count, AthleteOrderCriteria criteria, bool descending = false) - { - throw new NotImplementedException(); - } + => athletes.GetItemsWithFilterAndOrdering(c=>true,index, count, criteria != AthleteOrderCriteria.None ? criteria: null , descending); public async Task GetUserByIdAsync(int id) { diff --git a/src/StubAPI/Extensions.cs b/src/StubAPI/Extensions.cs index e7a036c..9917cac 100644 --- a/src/StubAPI/Extensions.cs +++ b/src/StubAPI/Extensions.cs @@ -36,5 +36,35 @@ public static class Extensions collection.Add(newItem!); return Task.FromResult(newItem); } + + public static IEnumerable GetItemsWithFilterAndOrdering(this IEnumerable list, Func filter, int index, int count, Enum? orderCriterium, bool descending = false ) where T : class + { + var filteredList = list.Where(filter); + + if(orderCriterium != null) + { + filteredList = filteredList.OrderByCriteria(orderCriterium, descending); + } + return filteredList + .Skip(index * count) + .Take(count); + } + + public static IOrderedEnumerable OrderByCriteria(this IEnumerable list, Enum orderCriterium, bool descending = false ) where T : class + { + var orderCriteriumString = orderCriterium.ToString(); + if (orderCriteriumString.StartsWith("By")) + { + orderCriteriumString = orderCriteriumString.Substring(2); + } + var propertyInfo = typeof(T).GetProperty(orderCriteriumString); + if (propertyInfo == null) + { + throw new ArgumentException($"No property {orderCriterium} in type {typeof(T)}"); + } + + return descending ? list.OrderByDescending(x => propertyInfo.GetValue(x)) : list.OrderBy(x => propertyInfo.GetValue(x)); + } + } \ No newline at end of file From 0bbf0f9bb9c025ae5a4cc36793476aabfa720596 Mon Sep 17 00:00:00 2001 From: dave Date: Sat, 9 Mar 2024 14:56:00 +0100 Subject: [PATCH 5/6] merge with EF --- src/ApiMappeur/ActivityMappeur.cs | 49 +++++++ src/HeartTrack.sln | 7 + .../Controllers/ActivityController.cs | 19 +-- .../Controllers/UsersController.cs | 38 +++--- src/HeartTrackAPI/Program.cs | 4 +- src/Model/Activity.cs | 6 +- .../EnnumMappeur.cs => Model/EnumMappeur.cs} | 8 +- src/Model/IAthleteService.cs | 15 --- src/Model/Manager/IDataManager.cs | 9 ++ .../IActivityRepository.cs} | 4 +- src/Model/Repository/IUserRepository.cs | 8 ++ src/Shared/IGenericRepository.cs | 12 ++ src/StubAPI/ActivityService.cs | 38 ++++++ src/StubAPI/AthleteService.cs | 29 ++-- src/StubAPI/StubData.cs | 16 +++ src/Tests/TestApi/GlobalUsings.cs | 1 + src/Tests/TestApi/TestApi.csproj | 26 ++++ src/Tests/TestApi/UserControllerTest.cs | 0 src/Tests/TestConsoleApi/Class1.cs | 5 + .../TestConsoleApi/TestConsoleApi.csproj | 9 ++ .../TestsAPI/ClientTests/HttpClientManager.cs | 12 ++ .../TestsAPI/UnitTestApi/GlobalUsings.cs | 1 + .../TestsAPI/UnitTestApi/UnitTestApi.csproj | 24 ++++ .../UnitTestApi/UserControllerTest.cs | 124 ++++++++++++++++++ 24 files changed, 402 insertions(+), 62 deletions(-) create mode 100644 src/ApiMappeur/ActivityMappeur.cs rename src/{ApiMappeur/EnnumMappeur.cs => Model/EnumMappeur.cs} (84%) delete mode 100644 src/Model/IAthleteService.cs create mode 100644 src/Model/Manager/IDataManager.cs rename src/Model/{IActivityService.cs => Repository/IActivityRepository.cs} (86%) create mode 100644 src/Model/Repository/IUserRepository.cs create mode 100644 src/Shared/IGenericRepository.cs create mode 100644 src/StubAPI/ActivityService.cs create mode 100644 src/StubAPI/StubData.cs create mode 100644 src/Tests/TestApi/GlobalUsings.cs create mode 100644 src/Tests/TestApi/TestApi.csproj create mode 100644 src/Tests/TestApi/UserControllerTest.cs create mode 100644 src/Tests/TestConsoleApi/Class1.cs create mode 100644 src/Tests/TestConsoleApi/TestConsoleApi.csproj create mode 100644 src/Tests/TestsAPI/ClientTests/HttpClientManager.cs create mode 100644 src/Tests/TestsAPI/UnitTestApi/GlobalUsings.cs create mode 100644 src/Tests/TestsAPI/UnitTestApi/UnitTestApi.csproj create mode 100644 src/Tests/TestsAPI/UnitTestApi/UserControllerTest.cs diff --git a/src/ApiMappeur/ActivityMappeur.cs b/src/ApiMappeur/ActivityMappeur.cs new file mode 100644 index 0000000..fb10d7b --- /dev/null +++ b/src/ApiMappeur/ActivityMappeur.cs @@ -0,0 +1,49 @@ +using Dto; +using Model; + +namespace ApiMappeur; + +public static class ActivityMappeur +{ + /*public static ActivityDto ToDto(this Activity activity) + { + return new ActivityDto + { + Id = activity.Id, + Name = activity.Name, + Type = activity.Type, + Date = activity.Date, + Duration = activity.EndTime - activity.StartTime, + Distance = activity.Distance, + Elevation = activity.Elevation, + AverageSpeed = activity.AverageSpeed, + AverageHeartRate = activity.AverageHeartRate, + Calories = activity.Calories, + Description = activity.Description, + Gpx = activity.Gpx, + Image = activity.Image, + AthleteId = activity.AthleteId + }; + } + + public static Activity ToModel(this ActivityDto activityDto) + { + return new Activity + { + Id = activityDto.Id, + Name = activityDto.Name, + Type = activityDto.Type, + Date = activityDto.Date, + Duration = activityDto.Duration, + Distance = activityDto.Distance, + Elevation = activityDto.Elevation, + AverageSpeed = activityDto.AverageSpeed, + AverageHeartRate = activityDto.AverageHeartRate, + Calories = activityDto.Calories, + Description = activityDto.Description, + Gpx = activityDto.Gpx, + Image = activityDto.Image, + AthleteId = activityDto.AthleteId + }; + }*/ +} \ No newline at end of file diff --git a/src/HeartTrack.sln b/src/HeartTrack.sln index 19f2afd..2556bdb 100644 --- a/src/HeartTrack.sln +++ b/src/HeartTrack.sln @@ -33,6 +33,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApiMappeur", "ApiMappeur\Ap EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StubAPI", "StubAPI\StubAPI.csproj", "{B9679DCA-F4C8-45BE-A849-44E2BA814083}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestApi", "Tests\TestsAPI\UnitTestApi\UnitTestApi.csproj", "{E515C8B6-6282-4D8B-8523-7B3A13E4AF58}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -94,6 +96,10 @@ Global {B9679DCA-F4C8-45BE-A849-44E2BA814083}.Debug|Any CPU.Build.0 = Debug|Any CPU {B9679DCA-F4C8-45BE-A849-44E2BA814083}.Release|Any CPU.ActiveCfg = Release|Any CPU {B9679DCA-F4C8-45BE-A849-44E2BA814083}.Release|Any CPU.Build.0 = Release|Any CPU + {E515C8B6-6282-4D8B-8523-7B3A13E4AF58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E515C8B6-6282-4D8B-8523-7B3A13E4AF58}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E515C8B6-6282-4D8B-8523-7B3A13E4AF58}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E515C8B6-6282-4D8B-8523-7B3A13E4AF58}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {477D2129-A6C9-4FF8-8BE9-5E9E8E5282F8} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} @@ -101,5 +107,6 @@ Global {30FC2BE9-7397-445A-84AD-043CE70F4281} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} {9E4D3AC5-E6CA-4753-BD96-BF5EE793931A} = {30FC2BE9-7397-445A-84AD-043CE70F4281} {44C367DC-5FE0-4CF2-9E76-A0282E931853} = {30FC2BE9-7397-445A-84AD-043CE70F4281} + {E515C8B6-6282-4D8B-8523-7B3A13E4AF58} = {30FC2BE9-7397-445A-84AD-043CE70F4281} EndGlobalSection EndGlobal diff --git a/src/HeartTrackAPI/Controllers/ActivityController.cs b/src/HeartTrackAPI/Controllers/ActivityController.cs index 7c9d2b0..1848ca9 100644 --- a/src/HeartTrackAPI/Controllers/ActivityController.cs +++ b/src/HeartTrackAPI/Controllers/ActivityController.cs @@ -1,24 +1,26 @@ +using ApiMappeur; using Dto; using HeartTrackAPI.Request; using HeartTrackAPI.Responce; using Microsoft.AspNetCore.Mvc; using Shared; using Model; -/* +using Model.Repository; + namespace HeartTrackAPI.Controllers; [ApiController] [Route("api/activities")] public class ActivityController : Controller { - private readonly IActivityService _activityService; + private readonly IActivityRepository _activityService; private readonly ILogger _logger; - public ActivityController(IActivityService activityService, ILogger logger) + public ActivityController(IActivityRepository activityService, ILogger logger) { _activityService = activityService; _logger = logger; } - +/* [HttpGet] [ProducesResponseType(typeof(PageResponse), 200)] [ProducesResponseType(400)] @@ -34,9 +36,8 @@ public class ActivityController : Controller return BadRequest("To many object is asked the max is : " + totalCount); } _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetActivities), pageRequest); - // request.OrderingPropertyName var activities = await _activityService.GetActivities(pageRequest.Index, pageRequest.Count, ActivityOrderCriteria.None, pageRequest.Descending ?? false); - var pageResponse = new PageResponse(pageRequest.Index, pageRequest.Count, totalCount, activities.Select(a => a.ToDto())); + var pageResponse = new PageResponse(pageRequest.Index, pageRequest.Count, totalCount, activities.Select(a => a.ToDto())); return Ok(pageResponse); } catch (Exception e) @@ -45,7 +46,7 @@ public class ActivityController : Controller return StatusCode(500); } } -/* + [HttpGet("{id}")] public async Task> GetActivity(int id) { @@ -94,5 +95,5 @@ public class ActivityController : Controller return NotFound(); } return NoContent(); - } -}*/ \ No newline at end of file + }*/ +} \ No newline at end of file diff --git a/src/HeartTrackAPI/Controllers/UsersController.cs b/src/HeartTrackAPI/Controllers/UsersController.cs index ceb09a4..7b57283 100644 --- a/src/HeartTrackAPI/Controllers/UsersController.cs +++ b/src/HeartTrackAPI/Controllers/UsersController.cs @@ -4,6 +4,8 @@ using HeartTrackAPI.Request; using HeartTrackAPI.Responce; using Microsoft.AspNetCore.Mvc; using Model; +using Model.Manager; +using Model.Repository; using Shared; namespace HeartTrackAPI.Controllers; @@ -13,18 +15,18 @@ namespace HeartTrackAPI.Controllers; public class UsersController : Controller { private readonly ILogger _logger; - private readonly IUserService _userService; - public UsersController(ILogger logger, IUserService usersService) + private readonly IUserRepository _userService; + public UsersController(ILogger logger, IDataManager dataManager) { _logger = logger; - _userService = usersService; + _userService = dataManager.UserRepository; } [HttpGet] [ProducesResponseType(typeof(PageResponse), 200)] [ProducesResponseType(400)] [ProducesResponseType(500)] - public async Task>> GetAllAthletes([FromQuery] PageRequest request) + public async Task>> Get([FromQuery] PageRequest request) { try { @@ -35,7 +37,7 @@ public class UsersController : Controller return BadRequest("To many object is asked the max is : " + totalCount); } - _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetAllAthletes), null); + _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(Get), null); var athletes = await _userService.GetUsers(request.Index, request.Count, Enum.TryParse(request.OrderingPropertyName, out AthleteOrderCriteria result) ? result : AthleteOrderCriteria.None, request.Descending ?? false); var pageResponse = new PageResponse(request.Index, request.Count, totalCount, athletes.Select(a => a.ToDto())); @@ -52,12 +54,12 @@ public class UsersController : Controller [ProducesResponseType(typeof(UserDto), 200)] [ProducesResponseType(404)] [ProducesResponseType(500)] - public async Task> GetAthleteById(int id) + public async Task> GetById(int id) { try { - _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetAthleteById), id); - var athlete = await _userService.GetUserByIdAsync(id); + _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetById), id); + var athlete = await _userService.GetItemById(id); if (athlete == null) { _logger.LogError("Athlete with id {id} not found", id); @@ -76,11 +78,11 @@ public class UsersController : Controller [HttpGet("count")] [ProducesResponseType(typeof(int), 200)] [ProducesResponseType(500)] - public async Task> GetNbUsers() + public async Task> Count() { try { - _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetNbUsers), null); + _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(Count), null); var nbUsers = await _userService.GetNbItems(); return Ok(nbUsers); } @@ -95,18 +97,18 @@ public class UsersController : Controller [ProducesResponseType(typeof(UserDto), 200)] [ProducesResponseType(404)] [ProducesResponseType(500)] - public async Task> UpdateUser(int id, [FromBody] UserDto user) + public async Task> Update(int id, [FromBody] UserDto user) { try { - _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(UpdateUser), user,id); - var athlete = await _userService.GetUserByIdAsync(id); + _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(Update), user,id); + var athlete = await _userService.GetItemById(id); if (athlete == null) { _logger.LogError("Athlete with id {id} not found", id); return NotFound($"Athlete with id {id} not found"); } - var updatedAthlete = await _userService.UpdateUser(id, user.ToModel()); + var updatedAthlete = await _userService.UpdateItem(id, user.ToModel()); if(updatedAthlete == null) { _logger.LogError("Error while updating athlete with id {id}", id); @@ -126,20 +128,20 @@ public class UsersController : Controller [ProducesResponseType(200)] [ProducesResponseType(404)] [ProducesResponseType(500)] - public async Task DeleteUser(int id) + public async Task Delete(int id) { try { - _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(DeleteUser), null,id); + _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(Delete), null,id); - var athlete = await _userService.GetUserByIdAsync(id); + var athlete = await _userService.GetItemById(id); if (athlete == null) { _logger.LogError("Athlete with id {id} not found", id); return NotFound($"Athlete with id {id} not found"); } - var isDeleted = await _userService.DeleteUser(id); + var isDeleted = await _userService.DeleteItem(id); if(!isDeleted) { _logger.LogError("Error while deleting athlete with id {id}", id); diff --git a/src/HeartTrackAPI/Program.cs b/src/HeartTrackAPI/Program.cs index bda6f2e..b396e74 100644 --- a/src/HeartTrackAPI/Program.cs +++ b/src/HeartTrackAPI/Program.cs @@ -1,4 +1,6 @@ using Model; +using Model.Manager; +using Model.Repository; using StubAPI; var builder = WebApplication.CreateBuilder(args); @@ -8,7 +10,7 @@ var builder = WebApplication.CreateBuilder(args); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddControllers(); -builder.Services.AddSingleton(); +builder.Services.AddSingleton(); var app = builder.Build(); // Configure the HTTP request pipeline. diff --git a/src/Model/Activity.cs b/src/Model/Activity.cs index 4e5cf64..06801bf 100644 --- a/src/Model/Activity.cs +++ b/src/Model/Activity.cs @@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations; namespace Model; public class Activity { - public int IdActivity { get; private set; } + public int Id { get; set; } public string Type { get; set; } public DateTime Date { get; set; } public DateTime StartTime { get; set; } @@ -36,7 +36,7 @@ public class Activity int effort, float variability, float variance, float standardDeviation, float average, int maximum, int minimum, float averageTemperature, bool hasAutoPause) { - IdActivity = idActivity; + Id = idActivity; Type = type; Date = date; StartTime = startTime; @@ -55,7 +55,7 @@ public class Activity public override string ToString() { - return $"Activity #{IdActivity}: {Type} on {Date:d/M/yyyy} from {StartTime:HH:mm:ss} to {EndTime:HH:mm:ss}" + + return $"Activity #{Id}: {Type} on {Date:d/M/yyyy} from {StartTime:HH:mm:ss} to {EndTime:HH:mm:ss}" + $" with an effort of {Effort}/5 and an average temperature of {AverageTemperature}°C" + $" and a heart rate variability of {Variability} bpm" + $" and a variance of {Variance} bpm" + diff --git a/src/ApiMappeur/EnnumMappeur.cs b/src/Model/EnumMappeur.cs similarity index 84% rename from src/ApiMappeur/EnnumMappeur.cs rename to src/Model/EnumMappeur.cs index 22dc8b5..b939ee9 100644 --- a/src/ApiMappeur/EnnumMappeur.cs +++ b/src/Model/EnumMappeur.cs @@ -1,8 +1,10 @@ -namespace ApiMappeur; +using Model.Repository; + +namespace Model; public static class EnumMappeur { - public static Shared.AthleteOrderCriteria ToEnum(this string value) + public static Shared.AthleteOrderCriteria ToEnum(this IUserRepository repository, string? value) { return value switch { @@ -18,5 +20,5 @@ public static class EnumMappeur "ByIsCoach" => Shared.AthleteOrderCriteria.ByIsCoach, _ => Shared.AthleteOrderCriteria.None }; - } + } } \ No newline at end of file diff --git a/src/Model/IAthleteService.cs b/src/Model/IAthleteService.cs deleted file mode 100644 index a89ddc2..0000000 --- a/src/Model/IAthleteService.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Dto; -using Model; -using Shared; - -namespace Model; - -public interface IUserService -{ - public Task> GetUsers(int index, int count, AthleteOrderCriteria criteria , bool descending = false); - public Task GetUserByIdAsync(int id); - public Task AddUser(User athlete); - public Task UpdateUser(int id, User user); - public Task DeleteUser(int id); - public Task GetNbItems(); -} \ No newline at end of file diff --git a/src/Model/Manager/IDataManager.cs b/src/Model/Manager/IDataManager.cs new file mode 100644 index 0000000..277ea0b --- /dev/null +++ b/src/Model/Manager/IDataManager.cs @@ -0,0 +1,9 @@ +using Model.Repository; + +namespace Model.Manager; + +public interface IDataManager +{ + IUserRepository UserRepository { get; } + IActivityRepository ActivityRepository { get; } +} diff --git a/src/Model/IActivityService.cs b/src/Model/Repository/IActivityRepository.cs similarity index 86% rename from src/Model/IActivityService.cs rename to src/Model/Repository/IActivityRepository.cs index 152b1c3..258bbd9 100644 --- a/src/Model/IActivityService.cs +++ b/src/Model/Repository/IActivityRepository.cs @@ -1,8 +1,8 @@ using Shared; -namespace Model; +namespace Model.Repository; -public interface IActivityService +public interface IActivityRepository { public Task> GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending = false); public Task GetActivityByIdAsync(int id); diff --git a/src/Model/Repository/IUserRepository.cs b/src/Model/Repository/IUserRepository.cs new file mode 100644 index 0000000..d6d528c --- /dev/null +++ b/src/Model/Repository/IUserRepository.cs @@ -0,0 +1,8 @@ +using Shared; + +namespace Model.Repository; + +public interface IUserRepository : IGenericRepository +{ + public Task> GetUsers(int index, int count, AthleteOrderCriteria? criteria , bool descending = false); +} \ No newline at end of file diff --git a/src/Shared/IGenericRepository.cs b/src/Shared/IGenericRepository.cs new file mode 100644 index 0000000..372d79b --- /dev/null +++ b/src/Shared/IGenericRepository.cs @@ -0,0 +1,12 @@ +namespace Shared; + +public interface IGenericRepository +{ + Task> GetItems(int index, int count, string? orderingProperty = null, bool descending = false); + Task GetItemById(int id); + Task UpdateItem(int oldItem, T newItem); + Task AddItem(T item); + Task DeleteItem(int item); + Task GetNbItems(); + +} \ No newline at end of file diff --git a/src/StubAPI/ActivityService.cs b/src/StubAPI/ActivityService.cs new file mode 100644 index 0000000..0e87004 --- /dev/null +++ b/src/StubAPI/ActivityService.cs @@ -0,0 +1,38 @@ +using Model; +using Model.Repository; +using Shared; + +namespace StubAPI; + +public class ActivityService: IActivityRepository +{ + public async Task> GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending = false) + { + throw new NotImplementedException(); + } + + public async Task GetActivityByIdAsync(int id) + { + throw new NotImplementedException(); + } + + public async Task AddActivity(Activity activity) + { + throw new NotImplementedException(); + } + + public async Task UpdateActivity(int id, Activity activity) + { + throw new NotImplementedException(); + } + + public async Task DeleteActivity(int id) + { + throw new NotImplementedException(); + } + + public async Task GetNbItems() + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/StubAPI/AthleteService.cs b/src/StubAPI/AthleteService.cs index bd2f9db..b1b1a28 100644 --- a/src/StubAPI/AthleteService.cs +++ b/src/StubAPI/AthleteService.cs @@ -1,9 +1,10 @@ using Model; +using Model.Repository; using Shared; namespace StubAPI; -public class UserService : IUserService +public class UserService : IUserRepository { private List athletes = [ @@ -29,29 +30,35 @@ public class UserService : IUserService } ]; + + public async Task> GetUsers(int index, int count, AthleteOrderCriteria? orderingProperty = null, bool descending = false) + => athletes.GetItemsWithFilterAndOrdering(c=>true,index, count,orderingProperty != AthleteOrderCriteria.None ? orderingProperty: null , descending); - public async Task> GetUsers(int index, int count, AthleteOrderCriteria criteria, + public async Task> GetItems(int index, int count, string? orderingProperty = null, bool descending = false) - => athletes.GetItemsWithFilterAndOrdering(c=>true,index, count, criteria != AthleteOrderCriteria.None ? criteria: null , descending); - - public async Task GetUserByIdAsync(int id) { - return await Task.FromResult(athletes.FirstOrDefault(s => s.Id == id)); + + return await this.GetUsers(index, count, this.ToEnum(orderingProperty), descending); + } - public async Task AddUser(User athlete) + public async Task GetItemById(int id) + =>await Task.FromResult(athletes.FirstOrDefault(s => s.Id == id)); + + + public async Task AddItem(User user) { - return await athletes.AddItem(athlete); + return await athletes.AddItem(user); } - - public async Task UpdateUser(int id, User user) + + public async Task UpdateItem(int id, User user) { var oldUser = athletes.FirstOrDefault(s => s.Id == id); if (oldUser == null) return null; return await athletes.UpdateItem(oldUser, user); } - public async Task DeleteUser(int id) + public async Task DeleteItem(int id) { var user = athletes.FirstOrDefault(s => s.Id == id); if (user == null) return false; diff --git a/src/StubAPI/StubData.cs b/src/StubAPI/StubData.cs new file mode 100644 index 0000000..1037cf6 --- /dev/null +++ b/src/StubAPI/StubData.cs @@ -0,0 +1,16 @@ +using Model.Manager; +using Model.Repository; + +namespace StubAPI; + +public class StubData : IDataManager +{ + public IUserRepository UserRepository { get; } + public IActivityRepository ActivityRepository { get; } + + public StubData() + { + UserRepository = new UserService(); + ActivityRepository = new ActivityService(); + } +} \ No newline at end of file diff --git a/src/Tests/TestApi/GlobalUsings.cs b/src/Tests/TestApi/GlobalUsings.cs new file mode 100644 index 0000000..ab67c7e --- /dev/null +++ b/src/Tests/TestApi/GlobalUsings.cs @@ -0,0 +1 @@ +global using Microsoft.VisualStudio.TestTools.UnitTesting; \ No newline at end of file diff --git a/src/Tests/TestApi/TestApi.csproj b/src/Tests/TestApi/TestApi.csproj new file mode 100644 index 0000000..719074b --- /dev/null +++ b/src/Tests/TestApi/TestApi.csproj @@ -0,0 +1,26 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + diff --git a/src/Tests/TestApi/UserControllerTest.cs b/src/Tests/TestApi/UserControllerTest.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/Tests/TestConsoleApi/Class1.cs b/src/Tests/TestConsoleApi/Class1.cs new file mode 100644 index 0000000..0b0d5dc --- /dev/null +++ b/src/Tests/TestConsoleApi/Class1.cs @@ -0,0 +1,5 @@ +namespace TestConsoleApi; + +public class Class1 +{ +} \ No newline at end of file diff --git a/src/Tests/TestConsoleApi/TestConsoleApi.csproj b/src/Tests/TestConsoleApi/TestConsoleApi.csproj new file mode 100644 index 0000000..3a63532 --- /dev/null +++ b/src/Tests/TestConsoleApi/TestConsoleApi.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/src/Tests/TestsAPI/ClientTests/HttpClientManager.cs b/src/Tests/TestsAPI/ClientTests/HttpClientManager.cs new file mode 100644 index 0000000..2e8e593 --- /dev/null +++ b/src/Tests/TestsAPI/ClientTests/HttpClientManager.cs @@ -0,0 +1,12 @@ +namespace ClientTests; + +public class HttpClientManager +{ + protected readonly HttpClient _httpClient; + + public HttpClientManager(HttpClient httpClient) + { + _httpClient = httpClient; + _httpClient.BaseAddress = new Uri("https://localhost:7252"); + } +} diff --git a/src/Tests/TestsAPI/UnitTestApi/GlobalUsings.cs b/src/Tests/TestsAPI/UnitTestApi/GlobalUsings.cs new file mode 100644 index 0000000..ab67c7e --- /dev/null +++ b/src/Tests/TestsAPI/UnitTestApi/GlobalUsings.cs @@ -0,0 +1 @@ +global using Microsoft.VisualStudio.TestTools.UnitTesting; \ No newline at end of file diff --git a/src/Tests/TestsAPI/UnitTestApi/UnitTestApi.csproj b/src/Tests/TestsAPI/UnitTestApi/UnitTestApi.csproj new file mode 100644 index 0000000..45b5c8f --- /dev/null +++ b/src/Tests/TestsAPI/UnitTestApi/UnitTestApi.csproj @@ -0,0 +1,24 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + diff --git a/src/Tests/TestsAPI/UnitTestApi/UserControllerTest.cs b/src/Tests/TestsAPI/UnitTestApi/UserControllerTest.cs new file mode 100644 index 0000000..4fc201e --- /dev/null +++ b/src/Tests/TestsAPI/UnitTestApi/UserControllerTest.cs @@ -0,0 +1,124 @@ +using Dto; +using HeartTrackAPI.Controllers; +using HeartTrackAPI.Request; +using HeartTrackAPI.Responce; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging.Abstractions; +using Model.Manager; +using Model.Repository; +using StubAPI; + +namespace UnitTestApi; + +[TestClass] +public class UserControllerTest +{ + private readonly IDataManager StubDataManager; + private readonly UsersController _usersController; + + public UserControllerTest() + { + StubDataManager = new StubData(); + _usersController = new UsersController(new NullLogger(), StubDataManager); + + } + + [TestMethod] + public void Get_ReturnsPageResponse_WhenRequestIsValid() + { + // Arrange + var request = new PageRequest + { + Index = 0, + Count = 10, + OrderingPropertyName = "Id", + Descending = false + }; + + // Act + var result = _usersController.Get(request).Result as OkObjectResult; + + // Assert + Assert.IsNotNull(result); + Assert.IsInstanceOfType(result.Value, typeof(PageResponse)); + } + /* + [TestMethod] + public void GetById_ReturnsUserDto_WhenRequestIsValid() + { + // Arrange + var id = 1; + + // Act + var result = _usersController.GetById(id).Result as OkObjectResult; + + // Assert + Assert.IsNotNull(result); + Assert.IsInstanceOfType(result.Value, typeof(UserDto)); + } + + [TestMethod] + public void GetById_Returns404_WhenIdIsInvalid() + { + // Arrange + var id = 0; + + // Act + var result = _usersController.GetById(id).Result as NotFoundResult; + + // Assert + Assert.IsNotNull(result); + } + + [TestMethod] + public void GetById_Returns500_WheExceptionIsThrown() + { + // Arrange + var id = 0; + + // Act + var result = _usersController.GetById(id).Result as StatusCodeResult; + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(500, result.StatusCode); + } + + [TestMethod] + public void Count_ReturnsInt_WhenRequestIsValid() + { + // Act + var result = _usersController.Count().Result as OkObjectResult; + + // Assert + Assert.IsNotNull(result); + Assert.IsInstanceOfType(result.Value, typeof(int)); + } + + [TestMethod] + public void Count_Returns500_WheExceptionIsThrown() + { + // Act + var result = _usersController.Count().Result as StatusCodeResult; + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(500, result.StatusCode); + } + + [TestMethod] + public void Update_ReturnsUserDto_WhenRequestIsValid() + { + // Arrange + var id = 1; + var user = new UserDto + { + Id = 1, + FirstName = "John", + LastName = "Doe", + Email = "toto@eoeo.fr", + }; + + }*/ + +} \ No newline at end of file From 6f1d4a21f3a8a4db0f1ee8e2ba5653a829bcdd92 Mon Sep 17 00:00:00 2001 From: dave Date: Sat, 9 Mar 2024 14:56:54 +0100 Subject: [PATCH 6/6] merge tmp --- src/Tests/TestsAPI/UnitTestApi/UserControllerTest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Tests/TestsAPI/UnitTestApi/UserControllerTest.cs b/src/Tests/TestsAPI/UnitTestApi/UserControllerTest.cs index 4fc201e..dd511e7 100644 --- a/src/Tests/TestsAPI/UnitTestApi/UserControllerTest.cs +++ b/src/Tests/TestsAPI/UnitTestApi/UserControllerTest.cs @@ -36,11 +36,11 @@ public class UserControllerTest }; // Act - var result = _usersController.Get(request).Result as OkObjectResult; + //var result = _usersController.Get(request).Result as OkObjectResult; // Assert - Assert.IsNotNull(result); - Assert.IsInstanceOfType(result.Value, typeof(PageResponse)); + // Assert.IsNotNull(result); + //Assert.IsInstanceOfType(result.Value, typeof(PageResponse)); } /* [TestMethod]