diff --git a/.gitignore b/.gitignore index 85546c5..c985bbb 100644 --- a/.gitignore +++ b/.gitignore @@ -549,4 +549,19 @@ 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 +.ideaMigration/ Migration/ \ No newline at end of file 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/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/Dto/ActivityDto.cs b/src/Dto/ActivityDto.cs new file mode 100644 index 0000000..d4bf5f1 --- /dev/null +++ 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/Dto/AthleteDto.cs b/src/Dto/AthleteDto.cs new file mode 100644 index 0000000..9ee369d --- /dev/null +++ b/src/Dto/AthleteDto.cs @@ -0,0 +1,23 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dto; + +public class UserDto +{ + public int Id { 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 float Lenght { get; set; } + public float Weight { 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/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 0ae03f5..2ec18e7 100644 --- a/src/HeartTrack.sln +++ b/src/HeartTrack.sln @@ -15,6 +15,26 @@ 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("{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 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestApi", "Tests\TestsAPI\UnitTestApi\UnitTestApi.csproj", "{E515C8B6-6282-4D8B-8523-7B3A13E4AF58}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestsEntities", "Tests\UnitTestsEntities\UnitTestsEntities.csproj", "{31FA8E5E-D642-4C43-A2B2-02B9832B2CEC}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedEF", "SharedEF\SharedEF.csproj", "{55478079-0AA0-47C1-97FF-A048091FD930}" @@ -50,6 +70,42 @@ 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 + {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 + {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 + {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 {31FA8E5E-D642-4C43-A2B2-02B9832B2CEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {31FA8E5E-D642-4C43-A2B2-02B9832B2CEC}.Debug|Any CPU.Build.0 = Debug|Any CPU {31FA8E5E-D642-4C43-A2B2-02B9832B2CEC}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -66,6 +122,10 @@ Global 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} + {E515C8B6-6282-4D8B-8523-7B3A13E4AF58} = {30FC2BE9-7397-445A-84AD-043CE70F4281} {31FA8E5E-D642-4C43-A2B2-02B9832B2CEC} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} EndGlobalSection EndGlobal diff --git a/src/HeartTrackAPI/Controllers/ActivityController.cs b/src/HeartTrackAPI/Controllers/ActivityController.cs new file mode 100644 index 0000000..1848ca9 --- /dev/null +++ b/src/HeartTrackAPI/Controllers/ActivityController.cs @@ -0,0 +1,99 @@ +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 IActivityRepository _activityService; + private readonly ILogger _logger; + + public ActivityController(IActivityRepository 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); + 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 new file mode 100644 index 0000000..7b57283 --- /dev/null +++ b/src/HeartTrackAPI/Controllers/UsersController.cs @@ -0,0 +1,160 @@ +using ApiMappeur; +using Dto; +using HeartTrackAPI.Request; +using HeartTrackAPI.Responce; +using Microsoft.AspNetCore.Mvc; +using Model; +using Model.Manager; +using Model.Repository; +using Shared; + +namespace HeartTrackAPI.Controllers; + +[ApiController] +[Route("api/users")] +public class UsersController : Controller +{ + private readonly ILogger _logger; + private readonly IUserRepository _userService; + public UsersController(ILogger logger, IDataManager dataManager) + { + _logger = logger; + _userService = dataManager.UserRepository; + } + + [HttpGet] + [ProducesResponseType(typeof(PageResponse), 200)] + [ProducesResponseType(400)] + [ProducesResponseType(500)] + public async Task>> Get([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(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())); + 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> GetById(int id) + { + try + { + _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); + 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> Count() + { + try + { + _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(Count), 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)] + public async Task> Update(int id, [FromBody] UserDto user) + { + try + { + _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.UpdateItem(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 Delete(int id) + { + try + { + _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(Delete), null,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.DeleteItem(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 new file mode 100644 index 0000000..f24f646 --- /dev/null +++ b/src/HeartTrackAPI/HeartTrackAPI.csproj @@ -0,0 +1,29 @@ + + + + net8.0 + enable + enable + true + + + + + + + + + + + + + + + + + + ..\..\..\..\..\.nuget\packages\newtonsoft.json\13.0.1\lib\netstandard2.0\Newtonsoft.Json.dll + + + + 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..b396e74 --- /dev/null +++ b/src/HeartTrackAPI/Program.cs @@ -0,0 +1,26 @@ +using Model; +using Model.Manager; +using Model.Repository; +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. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +app.MapControllers(); +app.Run(); \ No newline at end of file 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/Request/PageRequest.cs b/src/HeartTrackAPI/Request/PageRequest.cs new file mode 100644 index 0000000..bc04934 --- /dev/null +++ b/src/HeartTrackAPI/Request/PageRequest.cs @@ -0,0 +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; +} 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/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/Model/Activity.cs b/src/Model/Activity.cs new file mode 100644 index 0000000..06801bf --- /dev/null +++ b/src/Model/Activity.cs @@ -0,0 +1,68 @@ +using System.ComponentModel.DataAnnotations; + +namespace Model; +public class Activity + { + public int Id { get; 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) + { + Id = 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 #{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" + + $" 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/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/EnumMappeur.cs b/src/Model/EnumMappeur.cs new file mode 100644 index 0000000..b939ee9 --- /dev/null +++ b/src/Model/EnumMappeur.cs @@ -0,0 +1,24 @@ +using Model.Repository; + +namespace Model; + +public static class EnumMappeur +{ + public static Shared.AthleteOrderCriteria ToEnum(this IUserRepository repository, 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/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/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/Repository/IActivityRepository.cs b/src/Model/Repository/IActivityRepository.cs new file mode 100644 index 0000000..258bbd9 --- /dev/null +++ b/src/Model/Repository/IActivityRepository.cs @@ -0,0 +1,13 @@ +using Shared; + +namespace Model.Repository; + +public interface IActivityRepository +{ + 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/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/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/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 new file mode 100644 index 0000000..4bc54f0 --- /dev/null +++ b/src/Shared/AthleteOrderCriteria.cs @@ -0,0 +1,45 @@ +namespace Shared +{ + public enum AthleteOrderCriteria + { + None, + ByUsername, + ByFirstName, + ByLastName, + BySexe, + ByLenght, + ByWeight, + ByDateOfBirth, + ByEmail, + ByIsCoach + } + +} + + +/*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/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/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/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 new file mode 100644 index 0000000..b1b1a28 --- /dev/null +++ b/src/StubAPI/AthleteService.cs @@ -0,0 +1,72 @@ +using Model; +using Model.Repository; +using Shared; + +namespace StubAPI; + +public class UserService : IUserRepository +{ + private List athletes = + [ + new User + { + 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 = "john.doe@example.com", Role = new Athlete() + }, + + new User + { + 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 = "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() + } + + ]; + + 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> GetItems(int index, int count, string? orderingProperty = null, + bool descending = false) + { + + return await this.GetUsers(index, count, this.ToEnum(orderingProperty), descending); + + } + + 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(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 DeleteItem(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..9917cac --- /dev/null +++ b/src/StubAPI/Extensions.cs @@ -0,0 +1,70 @@ +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); + } + + 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 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/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/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/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/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/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 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..dd511e7 --- /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