From 7cfe9981e2a464a301356fa943fe2526a577bc50 Mon Sep 17 00:00:00 2001 From: Antoine PEREDERII Date: Sat, 16 Mar 2024 21:14:14 +0100 Subject: [PATCH 01/92] Update 'README.md' --- README.md | 76 +++++++++++++++++++++++++++---------------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 2db5c57..d529bdb 100644 --- a/README.md +++ b/README.md @@ -85,49 +85,49 @@ Documentation et informations à propos de `HearthTrack` disponible [ici](https: ### Entity Framework réalisé | niveau | description | coeff | jalon --- | --- | --- | --- | --- -[ ] | ☢️ | Le dépôt doit être accessible par l'enseignant | ☢️ | J1 -[ ] | ☢️ | un .gitignore doit exister au premier push | ☢️ | J1 -[ ] | 🎬 | les *projets* et les tests compilent | 1 | J1 & J2 -[ ] | 🎬 | le projet et le tests s'exécutent sans bug (concernant la partie persistance) | 3 | J1 & J2 -[ ] | 🟢 | Transcription du modèle : Modèle vers entités (et inversement) | 2 | J1 -[ ] | 🟢 | Requêtes CRUD simples (sur une table) | 1 | J1 -[ ] | 🟢 | Utilisation de LINQ to Entities | 2 | J1 -[ ] | 🟡 | Injection / indépendance du fournisseur | 1 | J1 -[ ] | 🟡 | Requêtes CRUD sur des données complexes (images par exemple) | 2 | J1 -[ ] | 🟢 | Tests - Appli Console | 1 | J1 -[ ] | 🟢 | Tests - Tests unitaires (avec SQLite in memory) | 2 | J1 -[ ] | 🟢 | Tests - Données stubbées et/ou Moq | 1 | J1 -[ ] | 🟡 | CI : build, tests, Sonar (doc?) | 1 | J1 -[ ] | 🟡 | Utilisation de relations (One-to-One, One-to-Many, Many-to-Many) (+ mapping, TU, Requêtes) | 4 | J1 -[ ] | 🟢 | Liens avec le web service | 2 | J1 -[ ] | 🟡 | Utilisation d'un *Logger* | 1 | J1 -[ ] | 🟡 | Déploiement | 4 | J2 -[ ] | 🔴 | Unit of Work / Repository + extras (héritage, accès concurrents...) | 8 | J2 -[ ] | 🟢 | Utilisation dans le projet | 2 | J2 -[ ] | 🟢 | mon dépôt possède un readme qui apporte quelque chose... | 2 | J2 +✅ | ☢️ | Le dépôt doit être accessible par l'enseignant | ☢️ | J1 +✅ | ☢️ | un .gitignore doit exister au premier push | ☢️ | J1 +✅ | 🎬 | les *projets* et les tests compilent | 1 | J1 & J2 +✅ | 🎬 | le projet et le tests s'exécutent sans bug (concernant la partie persistance) | 3 | J1 & J2 +✅ | 🟢 | Transcription du modèle : Modèle vers entités (et inversement) | 2 | J1 +✅ | 🟢 | Requêtes CRUD simples (sur une table) | 1 | J1 +✅ | 🟢 | Utilisation de LINQ to Entities | 2 | J1 +✅ | 🟡 | Injection / indépendance du fournisseur | 1 | J1 +❌ | 🟡 | Requêtes CRUD sur des données complexes (images par exemple) | 2 | J1 +✅ | 🟢 | Tests - Appli Console | 1 | J1 +✅ | 🟢 | Tests - Tests unitaires (avec SQLite in memory) | 2 | J1 +❌ | 🟢 | Tests - Données stubbées et/ou Moq | 1 | J1 +✅ | 🟡 | CI : build, tests, Sonar (doc?) | 1 | J1 +✅ | 🟡 | Utilisation de relations (One-to-One, One-to-Many, Many-to-Many) (+ mapping, TU, Requêtes) | 4 | J1 +✅ | 🟢 | Liens avec le web service | 2 | J1 +✅ | 🟡 | Utilisation d'un *Logger* | 1 | J1 +❌ | 🟡 | Déploiement | 4 | J2 +❌ | 🔴 | Unit of Work / Repository + extras (héritage, accès concurrents...) | 8 | J2 +❌ | 🟢 | Utilisation dans le projet | 2 | J2 +❌ | 🟢 | mon dépôt possède un readme qui apporte quelque chose... | 2 | J2 ### API réalisé | niveau | description | coeff | jalon --- | --- | --- | --- | --- -[ ] | ☢️ | Le dépôt doit être accessible par l'enseignant | ☢️ | J1 -[ ] | ☢️ | un .gitignore doit exister au premier push | ☢️ | J1 -[ ] | 🎬 | les *projets* et les tests compilent | 1 | J1 & J2 -[ ] | 🎬 | le projet et le tests s'exécutent sans bug (concernant la partie persistance) | 4 | J1 & J2 -[ ] | 🟢 | Modèle <-> DTO | 1 | J1 -[ ] | 🟢 | Entities <-> DTO | 1 | J1 -[ ] | 🟡 | Authentification | 4 | J1 -[ ] | 🟢 | Requêtes GET, PUT, POST, DELETE sur des données simples (1 seul type d'objet en retour, propriétés de types natifs) | 2 | J1 -[ ] | 🟡 | Pagination & filtrage | 2 | J1 -[ ] | 🟢 | Injection de service | 2 | J1 -[ ] | 🟡 | Requêtes GET, PUT, POST, DELETE sur des données complexes (plusieurs données complexes en retour) | 4 | J1 -[ ] | 🟢 | Tests - Appli Console (consommation des requêtes) | 4 | J1 -[ ] | 🟢 | Tests - Tests unitaires (avec Stub et/ou Moq) | 2 | J1 -[ ] | 🟡 | CI : build, tests, Sonar, Documentation (en particulier Swagger avec exemples...) | 1 | J1 -[ ] | 🟢 | Liens avec la persistance en base de données | 4 | J1 -[ ] | 🟡 | Utilisation d'un *Logger* | 1 | J1 -[ ] | 🟡 | Déploiement | 4 | J2 +✅ | ☢️ | Le dépôt doit être accessible par l'enseignant | ☢️ | J1 +✅ | ☢️ | un .gitignore doit exister au premier push | ☢️ | J1 +✅ | 🎬 | les *projets* et les tests compilent | 1 | J1 & J2 +✅ | 🎬 | le projet et le tests s'exécutent sans bug (concernant la partie persistance) | 4 | J1 & J2 +✅ | 🟢 | Modèle <-> DTO | 1 | J1 +❌ | 🟢 | Entities <-> DTO | 1 | J1 +❌ | 🟡 | Authentification | 4 | J1 +✅ | 🟢 | Requêtes GET, PUT, POST, DELETE sur des données simples (1 seul type d'objet en retour, propriétés de types natifs) | 2 | J1 +✅ | 🟡 | Pagination & filtrage | 2 | J1 +✅ | 🟢 | Injection de service | 2 | J1 +✅ | 🟡 | Requêtes GET, PUT, POST, DELETE sur des données complexes (plusieurs données complexes en retour) | 4 | J1 +✅ | 🟢 | Tests - Appli Console (consommation des requêtes) | 4 | J1 +✅ | 🟢 | Tests - Tests unitaires (avec Stub et/ou Moq) | 2 | J1 +✅ | 🟡 | CI : build, tests, Sonar, Documentation (en particulier Swagger avec exemples...) | 1 | J1 +✅ | 🟢 | Liens avec la persistance en base de données | 4 | J1 +✅ | 🟡 | Utilisation d'un *Logger* | 1 | J1 +❌ | 🟡 | Déploiement | 4 | J2 ❌ | 🟡 | Utilisation dans le projet | 4 | J2 -✅ | 🎬 | mon dépôt possède un readme qui apporte quelque chose... | 1 | J2 +❌ | 🎬 | mon dépôt possède un readme qui apporte quelque chose... | 1 | J2 ## Fabriqué avec ![.NET](https://img.shields.io/badge/Langage-.NET-000?style=for-the-badge&logo=.net&logoColor=white&color=blue) From d4176ee17bc3ec2af062ba2ce78a7a1c325c73e1 Mon Sep 17 00:00:00 2001 From: anperederi Date: Sat, 16 Mar 2024 23:59:01 +0100 Subject: [PATCH 02/92] =?UTF-8?q?=F0=9F=A7=AA=20Add=20somes=20console=20an?= =?UTF-8?q?d=20unit=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/HeartTrack.sln | 14 +++ src/Model/EnumMappeur.cs | 3 +- src/Shared/AthleteOrderCriteria.cs | 5 +- .../ActivityRepository.cs | 112 ++++++++++++++++++ .../RepositoriesUnitTest/GlobalUsings.cs | 1 + .../RepositoriesUnitTest.csproj | 31 +++++ src/Tests/RepositoriesUnitTest/UnitTest1.cs | 10 ++ src/Tests/TestApi/GlobalUsings.cs | 1 - src/Tests/TestApi/TestApi.csproj | 26 ---- src/Tests/TestApi/UserControllerTest.cs | 0 .../Controllers/UsersControllerTest.cs | 95 +++++++-------- .../UnitTestsEntities/DatabaseFixture.cs | 2 +- .../WebAPIConsoleTests/ActivityServiceAPI.cs | 110 +++++++++++++++++ src/Tests/WebAPIConsoleTests/HttpRequest.cs | 99 ++++++++++++++++ src/Tests/WebAPIConsoleTests/Program.cs | 63 ++++++++++ .../WebAPIConsoleTests.csproj | 17 +++ 16 files changed, 505 insertions(+), 84 deletions(-) create mode 100644 src/Tests/RepositoriesUnitTest/ActivityRepository.cs create mode 100644 src/Tests/RepositoriesUnitTest/GlobalUsings.cs create mode 100644 src/Tests/RepositoriesUnitTest/RepositoriesUnitTest.csproj create mode 100644 src/Tests/RepositoriesUnitTest/UnitTest1.cs delete mode 100644 src/Tests/TestApi/GlobalUsings.cs delete mode 100644 src/Tests/TestApi/TestApi.csproj delete mode 100644 src/Tests/TestApi/UserControllerTest.cs create mode 100644 src/Tests/WebAPIConsoleTests/ActivityServiceAPI.cs create mode 100644 src/Tests/WebAPIConsoleTests/HttpRequest.cs create mode 100644 src/Tests/WebAPIConsoleTests/Program.cs create mode 100644 src/Tests/WebAPIConsoleTests/WebAPIConsoleTests.csproj diff --git a/src/HeartTrack.sln b/src/HeartTrack.sln index 8bd8954..403513d 100644 --- a/src/HeartTrack.sln +++ b/src/HeartTrack.sln @@ -43,6 +43,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APIMappers", "APIMappers\AP EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestsModel", "Tests\UnitTestsModel\UnitTestsModel.csproj", "{508D380F-145C-437E-A7DF-7A17C526B2F3}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RepositoriesUnitTest", "Tests\RepositoriesUnitTest\RepositoriesUnitTest.csproj", "{707B1AC4-F896-4270-BC2F-1A589F48979D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebAPIConsoleTests", "Tests\WebAPIConsoleTests\WebAPIConsoleTests.csproj", "{D0EE112F-3151-4C28-A6EC-B1CEC7883FAE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -121,6 +125,14 @@ Global {508D380F-145C-437E-A7DF-7A17C526B2F3}.Debug|Any CPU.Build.0 = Debug|Any CPU {508D380F-145C-437E-A7DF-7A17C526B2F3}.Release|Any CPU.ActiveCfg = Release|Any CPU {508D380F-145C-437E-A7DF-7A17C526B2F3}.Release|Any CPU.Build.0 = Release|Any CPU + {707B1AC4-F896-4270-BC2F-1A589F48979D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {707B1AC4-F896-4270-BC2F-1A589F48979D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {707B1AC4-F896-4270-BC2F-1A589F48979D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {707B1AC4-F896-4270-BC2F-1A589F48979D}.Release|Any CPU.Build.0 = Release|Any CPU + {D0EE112F-3151-4C28-A6EC-B1CEC7883FAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D0EE112F-3151-4C28-A6EC-B1CEC7883FAE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D0EE112F-3151-4C28-A6EC-B1CEC7883FAE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D0EE112F-3151-4C28-A6EC-B1CEC7883FAE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -134,6 +146,8 @@ Global {31FA8E5E-D642-4C43-A2B2-02B9832B2CEC} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} {73EA27F2-9F0C-443F-A5EE-2960C983A422} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} {508D380F-145C-437E-A7DF-7A17C526B2F3} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} + {707B1AC4-F896-4270-BC2F-1A589F48979D} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} + {D0EE112F-3151-4C28-A6EC-B1CEC7883FAE} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {0F3487F4-66CA-4034-AC66-1BC899C9B523} diff --git a/src/Model/EnumMappeur.cs b/src/Model/EnumMappeur.cs index b939ee9..a2b7f26 100644 --- a/src/Model/EnumMappeur.cs +++ b/src/Model/EnumMappeur.cs @@ -9,6 +9,7 @@ public static class EnumMappeur return value switch { "None" => Shared.AthleteOrderCriteria.None, + "ById" => Shared.AthleteOrderCriteria.ById, "ByUsername" => Shared.AthleteOrderCriteria.ByUsername, "ByFirstName" => Shared.AthleteOrderCriteria.ByFirstName, "ByLastName" => Shared.AthleteOrderCriteria.ByLastName, @@ -17,7 +18,7 @@ public static class EnumMappeur "ByWeight" => Shared.AthleteOrderCriteria.ByWeight, "ByDateOfBirth" => Shared.AthleteOrderCriteria.ByDateOfBirth, "ByEmail" => Shared.AthleteOrderCriteria.ByEmail, - "ByIsCoach" => Shared.AthleteOrderCriteria.ByIsCoach, + "ByIsCoach" => Shared.AthleteOrderCriteria.ByRole, _ => Shared.AthleteOrderCriteria.None }; } diff --git a/src/Shared/AthleteOrderCriteria.cs b/src/Shared/AthleteOrderCriteria.cs index 4bc54f0..851fbe2 100644 --- a/src/Shared/AthleteOrderCriteria.cs +++ b/src/Shared/AthleteOrderCriteria.cs @@ -3,15 +3,16 @@ public enum AthleteOrderCriteria { None, + ById, ByUsername, ByFirstName, ByLastName, + ByEmail, BySexe, ByLenght, ByWeight, ByDateOfBirth, - ByEmail, - ByIsCoach + ByRole } } diff --git a/src/Tests/RepositoriesUnitTest/ActivityRepository.cs b/src/Tests/RepositoriesUnitTest/ActivityRepository.cs new file mode 100644 index 0000000..e67b3ce --- /dev/null +++ b/src/Tests/RepositoriesUnitTest/ActivityRepository.cs @@ -0,0 +1,112 @@ +using Xunit; +using Model2Entities; +using Microsoft.EntityFrameworkCore; +using DbContextLib; +using StubbedContextLib; +using System.Linq; +using Microsoft.Data.Sqlite; +using System; +using Shared; +using Model; +using Moq; +using Microsoft.Extensions.Logging; +using Entities; + +namespace UnitTestsEntities +{ + public class ActivityRepositoryTests : IClassFixture + { + private readonly DatabaseFixture _fixture; + + public ActivityRepositoryTests(DatabaseFixture fixture) + { + _fixture = fixture; + } + + [Fact] + public async Task GetActivities_ReturnsActivities() + { + var options = new DbContextOptionsBuilder() + .UseSqlite(_fixture._connection) + .Options; + + using (var context = new HeartTrackContext(options)) + { + context.Database.EnsureCreated(); + } + + using (var context = new HeartTrackContext(options)) + { + var repository = new DbDataManager.ActivityRepository(new DbDataManager(context), null); + var activities = await repository.GetActivities(0, 10, ActivityOrderCriteria.None); + + Assert.NotNull(activities); + Assert.Equal(10, activities.Count()); + } + } + [Fact] + public async Task GetActivityByIdAsync_ReturnsCorrectActivity_WhenIdExists() + { + // Arrange + var activityId = 1; + var expectedActivity = new Activity { Id = activityId, Type = "Running" }; + + var mockDataManager = new Mock(); + mockDataManager.Setup(dm => dm.DbContext.ActivitiesSet.SingleOrDefaultAsync(a => a.IdActivity == activityId)) + .ReturnsAsync(expectedActivity.ToEntity()); + + var loggerMock = new Mock>(); + var activityRepository = new DbDataManager.ActivityRepository(mockDataManager.Object, loggerMock.Object); + + // Act + var result = await activityRepository.GetActivityByIdAsync(activityId); + + // Assert + Assert.NotNull(result); + Assert.Equal(expectedActivity.Id, result.Id); + Assert.Equal(expectedActivity.Type, result.Type); + } + + [Fact] + public async Task GetActivityByIdAsync_ReturnsNull_WhenIdDoesNotExist() + { + // Arrange + var activityId = 999; + + var mockDataManager = new Mock(); + mockDataManager.Setup(dm => dm.DbContext.ActivitiesSet.SingleOrDefaultAsync(a => a.IdActivity == activityId)) + .ReturnsAsync((ActivityEntity)null); + + var loggerMock = new Mock>(); + var activityRepository = new DbDataManager.ActivityRepository(mockDataManager.Object, loggerMock.Object); + + // Act + var result = await activityRepository.GetActivityByIdAsync(activityId); + + // Assert + Assert.Null(result); + } + + [Fact] + public async Task AddActivity_SuccessfullyAddsNewActivity() + { + // Arrange + var newActivity = new Activity { Type = "Walking" }; + + var mockDataManager = new Mock(); + mockDataManager.Setup(dm => dm.DbContext.AddItem(It.IsAny())) + .ReturnsAsync(newActivity.ToEntity()); + + var loggerMock = new Mock>(); + var activityRepository = new DbDataManager.ActivityRepository(mockDataManager.Object, loggerMock.Object); + + // Act + var result = await activityRepository.AddActivity(newActivity); + + // Assert + Assert.NotNull(result); + Assert.Equal(newActivity.Type, result.Type); + } + + } +} diff --git a/src/Tests/RepositoriesUnitTest/GlobalUsings.cs b/src/Tests/RepositoriesUnitTest/GlobalUsings.cs new file mode 100644 index 0000000..8c927eb --- /dev/null +++ b/src/Tests/RepositoriesUnitTest/GlobalUsings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file diff --git a/src/Tests/RepositoriesUnitTest/RepositoriesUnitTest.csproj b/src/Tests/RepositoriesUnitTest/RepositoriesUnitTest.csproj new file mode 100644 index 0000000..417f28f --- /dev/null +++ b/src/Tests/RepositoriesUnitTest/RepositoriesUnitTest.csproj @@ -0,0 +1,31 @@ + + + + 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/RepositoriesUnitTest/UnitTest1.cs b/src/Tests/RepositoriesUnitTest/UnitTest1.cs new file mode 100644 index 0000000..392318c --- /dev/null +++ b/src/Tests/RepositoriesUnitTest/UnitTest1.cs @@ -0,0 +1,10 @@ +namespace RepositoriesUnitTest; + +public class UnitTest1 +{ + [Fact] + public void Test1() + { + + } +} \ No newline at end of file diff --git a/src/Tests/TestApi/GlobalUsings.cs b/src/Tests/TestApi/GlobalUsings.cs deleted file mode 100644 index ab67c7e..0000000 --- a/src/Tests/TestApi/GlobalUsings.cs +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index 719074b..0000000 --- a/src/Tests/TestApi/TestApi.csproj +++ /dev/null @@ -1,26 +0,0 @@ - - - - net8.0 - enable - enable - - false - true - - - - - - - - - - - - - - - - - diff --git a/src/Tests/TestApi/UserControllerTest.cs b/src/Tests/TestApi/UserControllerTest.cs deleted file mode 100644 index e69de29..0000000 diff --git a/src/Tests/TestsAPI/UnitTestApi/Controllers/UsersControllerTest.cs b/src/Tests/TestsAPI/UnitTestApi/Controllers/UsersControllerTest.cs index 0a5eb52..32cade7 100644 --- a/src/Tests/TestsAPI/UnitTestApi/Controllers/UsersControllerTest.cs +++ b/src/Tests/TestsAPI/UnitTestApi/Controllers/UsersControllerTest.cs @@ -86,7 +86,6 @@ public class UsersControllerTest [TestMethod] public async Task Get_ReturnsPageResponse_WhenRequestIsValid() { - var request = new PageRequest { Index = 0, @@ -95,11 +94,10 @@ public class UsersControllerTest Descending = false }; - // Act var result = await _usersController.Get(request); Assert.IsInstanceOfType(result.Result, typeof(OkObjectResult)); var okResult = result.Result as OkObjectResult; - // Assert + Assert.IsNotNull(okResult); Assert.IsInstanceOfType(okResult.Value, typeof(PageResponse)); var pageResponse = okResult.Value as PageResponse; @@ -118,7 +116,6 @@ public class UsersControllerTest public async Task Get_ReturnsCorrectPaginationAndOrdering(int index, int count, string orderingProperty, bool descending, int expectedItemCount) { - var request = new PageRequest { Index = index, @@ -126,11 +123,11 @@ public class UsersControllerTest OrderingPropertyName = orderingProperty, Descending = descending }; - // Act + var result = await _usersController.Get(request); Assert.IsInstanceOfType(result.Result, typeof(OkObjectResult)); var okResult = result.Result as OkObjectResult; - // Assert + Assert.IsNotNull(okResult); Assert.IsInstanceOfType(okResult.Value, typeof(PageResponse)); var pageResponse = okResult.Value as PageResponse; @@ -157,67 +154,59 @@ public class UsersControllerTest - [TestMethod] - public async Task GetById_ReturnsUserDto_WhenRequestIsValid() - { - - var id = 1; - _dataManagerMock.Setup(dm => dm.UserRepo.GetItemById(id)).ReturnsAsync(_users.First(x => x.Id == id)); - - // Act - var result = await _usersController.GetById(id) ; - Assert.IsInstanceOfType(result.Result, typeof(OkObjectResult)); - var okResult = result.Result as OkObjectResult; - - // Assert - Assert.IsNotNull(okResult); - var resultObject = result.Result as OkObjectResult; - Assert.IsNotNull(resultObject); - Assert.IsInstanceOfType(resultObject.Value, typeof(UserDto)); - var user = resultObject.Value as UserDto; - Assert.IsNotNull(user); - var tmp = _users.First(x => x.Id == id).ToDto(); - Assert.AreEqual(tmp.Id, user.Id); - } + [TestMethod] + public async Task GetById_ReturnsUserDto_WhenRequestIsValid() + { + var id = 1; + _dataManagerMock.Setup(dm => dm.UserRepo.GetItemById(id)).ReturnsAsync(_users.First(x => x.Id == id)); + + var result = await _usersController.GetById(id) ; + Assert.IsInstanceOfType(result.Result, typeof(OkObjectResult)); + var okResult = result.Result as OkObjectResult; + + Assert.IsNotNull(okResult); + var resultObject = result.Result as OkObjectResult; + Assert.IsNotNull(resultObject); + Assert.IsInstanceOfType(resultObject.Value, typeof(UserDto)); + var user = resultObject.Value as UserDto; + Assert.IsNotNull(user); + var tmp = _users.First(x => x.Id == id).ToDto(); + Assert.AreEqual(tmp.Id, user.Id); + } - [TestMethod] - public async Task GetById_ReturnsUserDto_WhenRequestUserDoesNotExist() - { - - var id = 0; - _dataManagerMock.Setup(dm => dm.UserRepo.GetItemById(id)).ReturnsAsync((User)null!); + [TestMethod] + public async Task GetById_ReturnsUserDto_WhenRequestUserDoesNotExist() + { + + var id = 0; + _dataManagerMock.Setup(dm => dm.UserRepo.GetItemById(id)).ReturnsAsync((User)null!); - // Act - var result = await _usersController.GetById(id) ; + // Act + var result = await _usersController.GetById(id) ; - // Assert - Assert.IsInstanceOfType(result.Result, typeof(NotFoundObjectResult)); - } + // Assert + Assert.IsInstanceOfType(result.Result, typeof(NotFoundObjectResult)); + } - [TestMethod] - public async Task GetById_Returns404_WhenIdIsInvalid() - { - - var id = -2; - - // Act - var result = await _usersController.GetById(id); - - // Assert - Assert.IsInstanceOfType(result.Result, typeof(NotFoundObjectResult)); - } + [TestMethod] + public async Task GetById_Returns404_WhenIdIsInvalid() + { + var id = -2; + + var result = await _usersController.GetById(id); + + Assert.IsInstanceOfType(result.Result, typeof(NotFoundObjectResult)); + } [TestMethod] public async Task Count_ReturnsInt_WhenRequestIsValid() { - // Act var result = await _usersController.Count(); Assert.IsNotNull(result); result = result.Result as OkObjectResult; - // Assert Assert.IsNotNull(result); Assert.IsInstanceOfType(result.Value, typeof(int)); } diff --git a/src/Tests/UnitTestsEntities/DatabaseFixture.cs b/src/Tests/UnitTestsEntities/DatabaseFixture.cs index eaae26d..00dc9bf 100644 --- a/src/Tests/UnitTestsEntities/DatabaseFixture.cs +++ b/src/Tests/UnitTestsEntities/DatabaseFixture.cs @@ -7,7 +7,7 @@ namespace UnitTestsEntities; public class DatabaseFixture : IDisposable { - private readonly SqliteConnection _connection; + public readonly SqliteConnection _connection; public readonly DbContextOptions _options; public DatabaseFixture() { diff --git a/src/Tests/WebAPIConsoleTests/ActivityServiceAPI.cs b/src/Tests/WebAPIConsoleTests/ActivityServiceAPI.cs new file mode 100644 index 0000000..78f042f --- /dev/null +++ b/src/Tests/WebAPIConsoleTests/ActivityServiceAPI.cs @@ -0,0 +1,110 @@ +/*! + * \file BookDataServiceAPI.cs + * \author HeartTeam + * \brief Fichier contenant la classe BookDataServiceAPI. + */ + +using System.Diagnostics; +using Dto; +using Model.Repository; +using Shared; +using APIMappers; + +/*! + * \brief Implémentation de l'interface IActivityRepository pour récupérer des activités via un service HTTP. + */ +public class ActivityServiceAPI : IActivityRepository +{ + private HttpRequest myRequest = new HttpRequest(); + + /*! + * \brief Constructeur de la classe ActivityServiceAPI. + * Initialise l'adresse de base du client HTTP. + */ + public ActivityServiceAPI() + { + myRequest.HttpClient.BaseAddress = new Uri("http://localhost:5030/api/v1/Activity/"); + } + + /*! + * \brief Récupère toutes les Activités de manière asynchrone. + * \return Une tâche représentant l'opération asynchrone qui retourne une liste d'Activity. + */ + public async Task?> GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending = false) + { + var activityDtos = await myRequest.GetAllAsync(); + return activityDtos?.ToModels(); + } + + /*! + * \brief Récupère les activités par index et compte de manière asynchrone. + * \param index L'index de départ pour la pagination. + * \param count Le nombre d'éléments à récupérer. + * \return Une tâche représentant l'opération asynchrone qui retourne une liste d'Activity. + */ + public async Task> GetBooksAsync(ActivityOrderCriteria criteria, bool descending, int index, int count) + { + var activityDtos = await myRequest.GetAsync(criteria, descending, index, count); + return (List)activityDtos.ToModels(); + } + + /*! + * \brief Récupère une activité par son identifiant de manière asynchrone. + * \param id L'identifiant du livre à récupérer. + * \return Une tâche représentant l'opération asynchrone qui retourne une liste d'Activity. + */ + public async Task?> GetActivityByIdAsync(int id) + { + var activityDtos = await myRequest.GetByIdAsync(id); + return activityDtos.ToModels(); + } + + /*! + * \brief Ajoute une activité de manière asynchrone. + * \param activity L'Activity à ajouter. + * \return Une tâche représentant l'opération asynchrone qui retourne l'activité ajouté (Activity). + */ + public async Task AddActivity(Model.Activity activity) + { + return await myRequest.PostAsync(activity.ToDto()).ToModel(); + } + + /*! + * \brief Met à jour une activité de manière asynchrone. + * \param id L'identifiant de l'activité à mettre à jour. + * \param activity Les nouvelles données de l'activité à mettre à jour. + * \return Une tâche représentant l'opération asynchrone qui retourne l'activité mis à jour (Activity). + */ + public async Task UpdateActivity(int id, Model.Activity activity) + { + var activityDto = activity.ToDto(); + var updatedActivityDto = await myRequest.PutAsync(id, activityDto); + return updatedActivityDto?.ToModel(); + } + + /*! + * \brief Supprime une activité de manière asynchrone. + * \param id L'identifiant de l'activité à supprimer. + * \return Une tâche représentant l'opération asynchrone. + */ + public async Task DeleteActivity(int id) + { + await myRequest.DeleteAsync(id); + return true; + } + + public Task GetNbItems() + { + return myRequest.GetNbItems(); + } + + public Task?> GetActivitiesByUser(int userId, int index, int count, ActivityOrderCriteria orderCriteria, bool descending = false) + { + return (List)myRequest.GetActivitiesByUser(userId, index, count, orderCriteria, descending).ToModels(); + } + + public Task GetNbActivitiesByUser(int userId) + { + return myRequest.GetNbActivitiesByUser(userId); + } +} \ No newline at end of file diff --git a/src/Tests/WebAPIConsoleTests/HttpRequest.cs b/src/Tests/WebAPIConsoleTests/HttpRequest.cs new file mode 100644 index 0000000..ac4f976 --- /dev/null +++ b/src/Tests/WebAPIConsoleTests/HttpRequest.cs @@ -0,0 +1,99 @@ +/*! + * \file HttpRequest.cs + * \author Antoine PEREDERII + * \brief Fichier contenant la classe HttpRequest. + */ + +using System.Diagnostics; +using System.Net.Http.Json; +using Dto; +using Shared; + +/*! + * \brief Classe représentant un client HTTP pour les requêtes vers un service de gestion de livres. + */ +public class HttpRequest where T : class +{ + private HttpClient _httpClient { get; } = new HttpClient(); + public HttpClient HttpClient => _httpClient; + + /*! + * \brief Récupère tous les livres de manière asynchrone. + * \return Une tâche représentant l'opération asynchrone qui retourne une liste de T. + */ + public async Task> GetAllAsync() + { + return await _httpClient.GetFromJsonAsync>(""); + } + + /*! + * \brief Récupère les activités par index et compte de manière asynchrone. + * \param index L'index de départ pour la pagination. + * \param count Le nombre d'éléments à récupérer. + * \return Une tâche représentant l'opération asynchrone qui retourne une liste de T. + */ + public async Task> GetAsync((ActivityOrderCriteria, AthleteOrderCriteria) criteria, bool descending, int index, int count) + { + return await _httpClient.GetFromJsonAsync>($"?OrderingPropertyName={criteria}&Descending={descending}&Index={index}&Count={count}"); + } + + /*! + * \brief Récupère un livre par son identifiant de manière asynchrone. + * \param id L'identifiant du livre à récupérer. + * \return Une tâche représentant l'opération asynchrone qui retourne une liste de T. + */ + public async Task> GetByIdAsync(int id) + { + return await _httpClient.GetFromJsonAsync>($"{id}"); + } + + public Task GetNbItems() + { + return _httpClient.GetFromJsonAsync("count"); + } + + public Task?> GetActivitiesByUser(int userId, int index, int count, (ActivityOrderCriteria, AthleteOrderCriteria) orderCriteria, bool descending = false) + { + return _httpClient.GetFromJsonAsync?>($"?userId={userId}&index={index}&count={count}&orderCriteria={orderCriteria}&descending={descending}"); + } + + public Task GetNbActivitiesByUser(int userId) + { + return _httpClient.GetFromJsonAsync($"count?userId={userId}"); + } + + /*! + * \brief Ajoute un livre de manière asynchrone. + * \param book Le livre à ajouter. + * \return Une tâche représentant l'opération asynchrone qui retourne le livre ajouté (T). + */ + public async Task PostAsync(T activity) + { + var response = await _httpClient.PostAsJsonAsync("", activity); + + return await response.Content.ReadFromJsonAsync(); + } + + /*! + * \brief Met à jour un livre de manière asynchrone. + * \param id L'identifiant du livre à mettre à jour. + * \param book Les nouvelles données du livre à mettre à jour. + * \return Une tâche représentant l'opération asynchrone qui retourne le livre mis à jour (T). + */ + public async Task PutAsync(int id, T activity) + { + var response = await _httpClient.PutAsJsonAsync($"{id}", activity); + + return await response.Content.ReadFromJsonAsync(); + } + + /*! + * \brief Supprime un livre de manière asynchrone. + * \param id L'identifiant du livre à supprimer. + * \return Une tâche représentant l'opération asynchrone. + */ + public async Task DeleteAsync(int id) + { + await _httpClient.DeleteAsync($"{id}"); + } +} \ No newline at end of file diff --git a/src/Tests/WebAPIConsoleTests/Program.cs b/src/Tests/WebAPIConsoleTests/Program.cs new file mode 100644 index 0000000..f421479 --- /dev/null +++ b/src/Tests/WebAPIConsoleTests/Program.cs @@ -0,0 +1,63 @@ +using Dto; +using Model; +using Model.Repository; +using Shared; + +IActivityRepository myConsoleTest = new ActivityServiceAPI(); + +// defini un delais d'attente du déploiement de l'API +await Task.Delay(5000); + +// Affiche toutes les activités +Console.WriteLine("Affichage de toutes les Activités : "); +var res = await myConsoleTest.GetActivities(0, 10, ActivityOrderCriteria.ByAthleteId, false); +foreach(var myActivity in res) +{ + Console.WriteLine(myActivity.Id + ", " + myActivity.Type + ", " + myActivity.StartTime + ", " + myActivity.EndTime + ", " + myActivity.DataSource + ", " + myActivity.Athlete); +} + +// Affiche les activités par id +Console.WriteLine("Affichage du livre d'id 1 : "); +res = (IEnumerable)await myConsoleTest.GetActivityByIdAsync(1); +foreach (var myActivity in res) +{ + Console.WriteLine(myActivity.Id + ", " + myActivity.Type + ", " + myActivity.StartTime + ", " + myActivity.EndTime + ", " + myActivity.DataSource + ", " + myActivity.Athlete); +} + +// Ajouter une nouvelle activité +Console.WriteLine("Ajout d'un nouveau livre : "); +var newActivity = new ActivityDto { Type = "New Activity", StartTime = DateTime.Now, EndTime = DateTime.Now, DataSource = new DataSourceDto{}, Athlete = new UserDto{ Username = "Hello", FirstName = "feee", Email = "exemple.com", LastName = "dddd", Sexe = "M" } }; +var addedActivity = await myConsoleTest.AddActivity(newActivity); +Console.WriteLine($"Id: {addedActivity.Id}, Type: {addedActivity.Type}, StartTime: {addedActivity.StartTime}, EndTime: {addedActivity.EndTime}, DataSource: {addedActivity.DataSource}, Athlete: {addedActivity.Athlete}"); + +// Mettre à jour l'activity ajouté +Console.WriteLine("Mise à jour du livre ajouté : "); +var activity = await myConsoleTest.UpdateActivity(1, new ActivityDto { Id = 1, Type = "Updated Activity", StartTime = DateTime.Now, EndTime = DateTime.Now, DataSource = new DataSourceDto{}, Athlete = new UserDto{ Username = "Hello", FirstName = "feee", Email = "exemple.com", LastName = "dddd", Sexe = "M" } }); +Console.WriteLine($"Id: {activity.Id}, Type: {activity.Type}, StartTime: {activity.StartTime}, EndTime: {activity.EndTime}, DataSource: {activity.DataSource}, Athlete: {activity.Athlete}"); + +// Supprimer l'activity ajouté +Console.WriteLine("Suppression du livre ajouté : "); +await myConsoleTest.DeleteActivity(newActivity.Id); +res = await myConsoleTest.GetActivities(0, 10, ActivityOrderCriteria.ByAthleteId, false); +foreach (var activity1 in res) +{ + Console.WriteLine(activity1.Id + ", " + activity1.Type + ", " + activity1.StartTime + ", " + activity1.EndTime + ", " + activity1.DataSource + ", " + activity1.Athlete); +} + +// Affiche le nombre d'activités +Console.WriteLine("Affichage du nombre d'activités : "); +var nb = await myConsoleTest.GetNbItems(); +Console.WriteLine(nb); + +// Affiche les activités par utilisateur +Console.WriteLine("Affichage des activités par utilisateur : "); +res = await myConsoleTest.GetActivitiesByUser(1, 0, 10, ActivityOrderCriteria.ByAthleteId, false); +foreach (var activity3 in res) +{ + Console.WriteLine(activity3.Id + ", " + activity3.Type + ", " + activity3.StartTime + ", " + activity3.EndTime + ", " + activity3.DataSource + ", " + activity3.Athlete); +} + +// Affiche le nombre d'activités par utilisateur +Console.WriteLine("Affichage du nombre d'activités par utilisateur : "); +nb = await myConsoleTest.GetNbActivitiesByUser(1); +Console.WriteLine(nb); \ No newline at end of file diff --git a/src/Tests/WebAPIConsoleTests/WebAPIConsoleTests.csproj b/src/Tests/WebAPIConsoleTests/WebAPIConsoleTests.csproj new file mode 100644 index 0000000..8f402c3 --- /dev/null +++ b/src/Tests/WebAPIConsoleTests/WebAPIConsoleTests.csproj @@ -0,0 +1,17 @@ + + + + + + + + + + + Exe + net8.0 + enable + enable + + + From bd833445190bb4d426baee9ab96f21db0bb7bffc Mon Sep 17 00:00:00 2001 From: dave Date: Sun, 17 Mar 2024 00:30:20 +0100 Subject: [PATCH 03/92] try --- .../ActivityRepository.cs | 4 +- src/Tests/UnitTestsModel/EnumMapperTest.cs | 2 +- .../WebAPIConsoleTests/ActivityServiceAPI.cs | 11 ++--- src/Tests/WebAPIConsoleTests/HttpRequest.cs | 40 +++++++++---------- src/Tests/WebAPIConsoleTests/Program.cs | 7 ++-- 5 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/Tests/RepositoriesUnitTest/ActivityRepository.cs b/src/Tests/RepositoriesUnitTest/ActivityRepository.cs index e67b3ce..4a93c56 100644 --- a/src/Tests/RepositoriesUnitTest/ActivityRepository.cs +++ b/src/Tests/RepositoriesUnitTest/ActivityRepository.cs @@ -6,12 +6,13 @@ using StubbedContextLib; using System.Linq; using Microsoft.Data.Sqlite; using System; +using EFMappers; using Shared; using Model; using Moq; using Microsoft.Extensions.Logging; using Entities; - +/* namespace UnitTestsEntities { public class ActivityRepositoryTests : IClassFixture @@ -110,3 +111,4 @@ namespace UnitTestsEntities } } +*/ \ No newline at end of file diff --git a/src/Tests/UnitTestsModel/EnumMapperTest.cs b/src/Tests/UnitTestsModel/EnumMapperTest.cs index e2dc382..5d3c0d7 100644 --- a/src/Tests/UnitTestsModel/EnumMapperTest.cs +++ b/src/Tests/UnitTestsModel/EnumMapperTest.cs @@ -17,7 +17,7 @@ namespace UnitTestsModel [InlineData("ByWeight", Shared.AthleteOrderCriteria.ByWeight)] [InlineData("ByDateOfBirth", Shared.AthleteOrderCriteria.ByDateOfBirth)] [InlineData("ByEmail", Shared.AthleteOrderCriteria.ByEmail)] - [InlineData("ByIsCoach", Shared.AthleteOrderCriteria.ByIsCoach)] + [InlineData("ByRole", Shared.AthleteOrderCriteria.ByRole)] [InlineData(null, Shared.AthleteOrderCriteria.None)] [InlineData("InvalidValue", Shared.AthleteOrderCriteria.None)] public void ToEnum_WithValidValue_ReturnsCorrectEnumValue(string? value, Shared.AthleteOrderCriteria expected) diff --git a/src/Tests/WebAPIConsoleTests/ActivityServiceAPI.cs b/src/Tests/WebAPIConsoleTests/ActivityServiceAPI.cs index 78f042f..1ca9031 100644 --- a/src/Tests/WebAPIConsoleTests/ActivityServiceAPI.cs +++ b/src/Tests/WebAPIConsoleTests/ActivityServiceAPI.cs @@ -9,6 +9,7 @@ using Dto; using Model.Repository; using Shared; using APIMappers; +using Model; /*! * \brief Implémentation de l'interface IActivityRepository pour récupérer des activités via un service HTTP. @@ -53,10 +54,10 @@ public class ActivityServiceAPI : IActivityRepository * \param id L'identifiant du livre à récupérer. * \return Une tâche représentant l'opération asynchrone qui retourne une liste d'Activity. */ - public async Task?> GetActivityByIdAsync(int id) + public async Task GetActivityByIdAsync(int id) { var activityDtos = await myRequest.GetByIdAsync(id); - return activityDtos.ToModels(); + return activityDtos.ToModel(); } /*! @@ -66,7 +67,7 @@ public class ActivityServiceAPI : IActivityRepository */ public async Task AddActivity(Model.Activity activity) { - return await myRequest.PostAsync(activity.ToDto()).ToModel(); + return (await myRequest.PostAsync(activity.ToDto())).ToModel(); } /*! @@ -98,9 +99,9 @@ public class ActivityServiceAPI : IActivityRepository return myRequest.GetNbItems(); } - public Task?> GetActivitiesByUser(int userId, int index, int count, ActivityOrderCriteria orderCriteria, bool descending = false) + public async Task?> GetActivitiesByUser(int userId, int index, int count, ActivityOrderCriteria orderCriteria, bool descending = false) { - return (List)myRequest.GetActivitiesByUser(userId, index, count, orderCriteria, descending).ToModels(); + return (await myRequest.GetActivitiesByUser(userId, index, count, orderCriteria, descending)).ToModels(); } public Task GetNbActivitiesByUser(int userId) diff --git a/src/Tests/WebAPIConsoleTests/HttpRequest.cs b/src/Tests/WebAPIConsoleTests/HttpRequest.cs index ac4f976..eff6e00 100644 --- a/src/Tests/WebAPIConsoleTests/HttpRequest.cs +++ b/src/Tests/WebAPIConsoleTests/HttpRequest.cs @@ -1,6 +1,5 @@ /*! * \file HttpRequest.cs - * \author Antoine PEREDERII * \brief Fichier contenant la classe HttpRequest. */ @@ -10,7 +9,7 @@ using Dto; using Shared; /*! - * \brief Classe représentant un client HTTP pour les requêtes vers un service de gestion de livres. + * \brief Classe représentant un client HTTP pour les requêtes vers un service de gestion de elément. */ public class HttpRequest where T : class { @@ -18,7 +17,7 @@ public class HttpRequest where T : class public HttpClient HttpClient => _httpClient; /*! - * \brief Récupère tous les livres de manière asynchrone. + * \brief Récupère tous les activitée de manière asynchrone. * \return Une tâche représentant l'opération asynchrone qui retourne une liste de T. */ public async Task> GetAllAsync() @@ -27,24 +26,25 @@ public class HttpRequest where T : class } /*! - * \brief Récupère les activités par index et compte de manière asynchrone. + * \brief Récupère les élements par index et compte de manière asynchrone. * \param index L'index de départ pour la pagination. * \param count Le nombre d'éléments à récupérer. * \return Une tâche représentant l'opération asynchrone qui retourne une liste de T. - */ - public async Task> GetAsync((ActivityOrderCriteria, AthleteOrderCriteria) criteria, bool descending, int index, int count) + */ + // [TODO] enum + public async Task> GetAsync(Enum criteria, bool descending, int index, int count) { return await _httpClient.GetFromJsonAsync>($"?OrderingPropertyName={criteria}&Descending={descending}&Index={index}&Count={count}"); } /*! - * \brief Récupère un livre par son identifiant de manière asynchrone. - * \param id L'identifiant du livre à récupérer. + * \brief Récupère un elément par son identifiant de manière asynchrone. + * \param id L'identifiant du elément à récupérer. * \return Une tâche représentant l'opération asynchrone qui retourne une liste de T. */ - public async Task> GetByIdAsync(int id) + public async Task GetByIdAsync(int id) { - return await _httpClient.GetFromJsonAsync>($"{id}"); + return await _httpClient.GetFromJsonAsync($"{id}"); } public Task GetNbItems() @@ -52,7 +52,7 @@ public class HttpRequest where T : class return _httpClient.GetFromJsonAsync("count"); } - public Task?> GetActivitiesByUser(int userId, int index, int count, (ActivityOrderCriteria, AthleteOrderCriteria) orderCriteria, bool descending = false) + public Task?> GetActivitiesByUser(int userId, int index, int count, ActivityOrderCriteria orderCriteria, bool descending = false) { return _httpClient.GetFromJsonAsync?>($"?userId={userId}&index={index}&count={count}&orderCriteria={orderCriteria}&descending={descending}"); } @@ -63,9 +63,9 @@ public class HttpRequest where T : class } /*! - * \brief Ajoute un livre de manière asynchrone. - * \param book Le livre à ajouter. - * \return Une tâche représentant l'opération asynchrone qui retourne le livre ajouté (T). + * \brief Ajoute une activity de manière asynchrone. + * \param book Le elément à ajouter. + * \return Une tâche représentant l'opération asynchrone qui retourne le activity ajouté (T). */ public async Task PostAsync(T activity) { @@ -75,10 +75,10 @@ public class HttpRequest where T : class } /*! - * \brief Met à jour un livre de manière asynchrone. - * \param id L'identifiant du livre à mettre à jour. - * \param book Les nouvelles données du livre à mettre à jour. - * \return Une tâche représentant l'opération asynchrone qui retourne le livre mis à jour (T). + * \brief Met à jour un elément de manière asynchrone. + * \param id L'identifiant du elément à mettre à jour. + * \param book Les nouvelles données du elément à mettre à jour. + * \return Une tâche représentant l'opération asynchrone qui retourne le elément mis à jour (T). */ public async Task PutAsync(int id, T activity) { @@ -88,8 +88,8 @@ public class HttpRequest where T : class } /*! - * \brief Supprime un livre de manière asynchrone. - * \param id L'identifiant du livre à supprimer. + * \brief Supprime un elément de manière asynchrone. + * \param id L'identifiant du elément à supprimer. * \return Une tâche représentant l'opération asynchrone. */ public async Task DeleteAsync(int id) diff --git a/src/Tests/WebAPIConsoleTests/Program.cs b/src/Tests/WebAPIConsoleTests/Program.cs index f421479..0d5cb97 100644 --- a/src/Tests/WebAPIConsoleTests/Program.cs +++ b/src/Tests/WebAPIConsoleTests/Program.cs @@ -1,4 +1,5 @@ -using Dto; +using APIMappers; +using Dto; using Model; using Model.Repository; using Shared; @@ -27,12 +28,12 @@ foreach (var myActivity in res) // Ajouter une nouvelle activité Console.WriteLine("Ajout d'un nouveau livre : "); var newActivity = new ActivityDto { Type = "New Activity", StartTime = DateTime.Now, EndTime = DateTime.Now, DataSource = new DataSourceDto{}, Athlete = new UserDto{ Username = "Hello", FirstName = "feee", Email = "exemple.com", LastName = "dddd", Sexe = "M" } }; -var addedActivity = await myConsoleTest.AddActivity(newActivity); +var addedActivity = await myConsoleTest.AddActivity(newActivity.ToModel()); Console.WriteLine($"Id: {addedActivity.Id}, Type: {addedActivity.Type}, StartTime: {addedActivity.StartTime}, EndTime: {addedActivity.EndTime}, DataSource: {addedActivity.DataSource}, Athlete: {addedActivity.Athlete}"); // Mettre à jour l'activity ajouté Console.WriteLine("Mise à jour du livre ajouté : "); -var activity = await myConsoleTest.UpdateActivity(1, new ActivityDto { Id = 1, Type = "Updated Activity", StartTime = DateTime.Now, EndTime = DateTime.Now, DataSource = new DataSourceDto{}, Athlete = new UserDto{ Username = "Hello", FirstName = "feee", Email = "exemple.com", LastName = "dddd", Sexe = "M" } }); +var activity = await myConsoleTest.UpdateActivity(1, new ActivityDto { Id = 1, Type = "Updated Activity", StartTime = DateTime.Now, EndTime = DateTime.Now, DataSource = new DataSourceDto{}, Athlete = new UserDto{ Username = "Hello", FirstName = "feee", Email = "exemple.com", LastName = "dddd", Sexe = "M" } }.ToModel()); Console.WriteLine($"Id: {activity.Id}, Type: {activity.Type}, StartTime: {activity.StartTime}, EndTime: {activity.EndTime}, DataSource: {activity.DataSource}, Athlete: {activity.Athlete}"); // Supprimer l'activity ajouté From 3c1510e0414941753e582952da44774c724bf17d Mon Sep 17 00:00:00 2001 From: dave Date: Sun, 17 Mar 2024 00:38:04 +0100 Subject: [PATCH 04/92] yep --- src/Tests/RepositoriesUnitTest/ActivityRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tests/RepositoriesUnitTest/ActivityRepository.cs b/src/Tests/RepositoriesUnitTest/ActivityRepository.cs index 4a93c56..5cf903b 100644 --- a/src/Tests/RepositoriesUnitTest/ActivityRepository.cs +++ b/src/Tests/RepositoriesUnitTest/ActivityRepository.cs @@ -94,7 +94,7 @@ namespace UnitTestsEntities // Arrange var newActivity = new Activity { Type = "Walking" }; - var mockDataManager = new Mock(); + var mockDataManager = new Mock(); mockDataManager.Setup(dm => dm.DbContext.AddItem(It.IsAny())) .ReturnsAsync(newActivity.ToEntity()); From efab70f9780647df0e65c02db3b05da72dae91de Mon Sep 17 00:00:00 2001 From: dave Date: Sun, 17 Mar 2024 00:39:20 +0100 Subject: [PATCH 05/92] push --- src/Tests/RepositoriesUnitTest/ActivityRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tests/RepositoriesUnitTest/ActivityRepository.cs b/src/Tests/RepositoriesUnitTest/ActivityRepository.cs index 5cf903b..a366bfb 100644 --- a/src/Tests/RepositoriesUnitTest/ActivityRepository.cs +++ b/src/Tests/RepositoriesUnitTest/ActivityRepository.cs @@ -111,4 +111,4 @@ namespace UnitTestsEntities } } -*/ \ No newline at end of file +*/ From a121ec348a39907e739a4afb79bbf6f9bd527bc8 Mon Sep 17 00:00:00 2001 From: anperederi Date: Sun, 17 Mar 2024 00:49:07 +0100 Subject: [PATCH 06/92] =?UTF-8?q?=F0=9F=A7=AA=20Test=20some=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Model/EnumMappeur.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Model/EnumMappeur.cs b/src/Model/EnumMappeur.cs index a2b7f26..38ca1a3 100644 --- a/src/Model/EnumMappeur.cs +++ b/src/Model/EnumMappeur.cs @@ -18,7 +18,7 @@ public static class EnumMappeur "ByWeight" => Shared.AthleteOrderCriteria.ByWeight, "ByDateOfBirth" => Shared.AthleteOrderCriteria.ByDateOfBirth, "ByEmail" => Shared.AthleteOrderCriteria.ByEmail, - "ByIsCoach" => Shared.AthleteOrderCriteria.ByRole, + "ByRole" => Shared.AthleteOrderCriteria.ByRole, _ => Shared.AthleteOrderCriteria.None }; } From cdcd64390ae51b3728ac0d43fffad9dca262db7a Mon Sep 17 00:00:00 2001 From: anperederi Date: Sun, 17 Mar 2024 00:51:41 +0100 Subject: [PATCH 07/92] =?UTF-8?q?=F0=9F=93=9D=20Uncomment=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Tests/ConsoleTestEFMapper/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tests/ConsoleTestEFMapper/Program.cs b/src/Tests/ConsoleTestEFMapper/Program.cs index bc71893..4808f97 100644 --- a/src/Tests/ConsoleTestEFMapper/Program.cs +++ b/src/Tests/ConsoleTestEFMapper/Program.cs @@ -48,7 +48,7 @@ namespace Model2Entities } Console.WriteLine(); - // // Test de la méthode AddActivity + // Test de la méthode AddActivity Console.WriteLine("Testing AddActivity method..."); var user = new User { From 0f5c710acf370df215b4174bed3ac202fd2ac0b8 Mon Sep 17 00:00:00 2001 From: Antoine PEREDERII Date: Sun, 17 Mar 2024 01:06:08 +0100 Subject: [PATCH 08/92] Update 'src/Tests/WebAPIConsoleTests/HttpRequest.cs' --- src/Tests/WebAPIConsoleTests/HttpRequest.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Tests/WebAPIConsoleTests/HttpRequest.cs b/src/Tests/WebAPIConsoleTests/HttpRequest.cs index eff6e00..2b83ab6 100644 --- a/src/Tests/WebAPIConsoleTests/HttpRequest.cs +++ b/src/Tests/WebAPIConsoleTests/HttpRequest.cs @@ -8,6 +8,8 @@ using System.Net.Http.Json; using Dto; using Shared; +namespace WebAPIConsoleTests; + /*! * \brief Classe représentant un client HTTP pour les requêtes vers un service de gestion de elément. */ From b0e0ef69318704821f6131c0c0700a004d4c634b Mon Sep 17 00:00:00 2001 From: Antoine PEREDERII Date: Sun, 17 Mar 2024 01:06:22 +0100 Subject: [PATCH 09/92] Update 'src/Tests/WebAPIConsoleTests/ActivityServiceAPI.cs' --- src/Tests/WebAPIConsoleTests/ActivityServiceAPI.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Tests/WebAPIConsoleTests/ActivityServiceAPI.cs b/src/Tests/WebAPIConsoleTests/ActivityServiceAPI.cs index 1ca9031..976808a 100644 --- a/src/Tests/WebAPIConsoleTests/ActivityServiceAPI.cs +++ b/src/Tests/WebAPIConsoleTests/ActivityServiceAPI.cs @@ -11,6 +11,8 @@ using Shared; using APIMappers; using Model; +namespace WebAPIConsoleTests; + /*! * \brief Implémentation de l'interface IActivityRepository pour récupérer des activités via un service HTTP. */ From d36b6e467e11808099314244101c62594f0a69f0 Mon Sep 17 00:00:00 2001 From: Antoine PEREDERII Date: Sun, 17 Mar 2024 01:06:34 +0100 Subject: [PATCH 10/92] Update 'src/Tests/WebAPIConsoleTests/Program.cs' --- src/Tests/WebAPIConsoleTests/Program.cs | 128 ++++++++++++------------ 1 file changed, 65 insertions(+), 63 deletions(-) diff --git a/src/Tests/WebAPIConsoleTests/Program.cs b/src/Tests/WebAPIConsoleTests/Program.cs index 0d5cb97..adf0070 100644 --- a/src/Tests/WebAPIConsoleTests/Program.cs +++ b/src/Tests/WebAPIConsoleTests/Program.cs @@ -1,64 +1,66 @@ -using APIMappers; -using Dto; -using Model; -using Model.Repository; -using Shared; - -IActivityRepository myConsoleTest = new ActivityServiceAPI(); - -// defini un delais d'attente du déploiement de l'API -await Task.Delay(5000); - -// Affiche toutes les activités -Console.WriteLine("Affichage de toutes les Activités : "); -var res = await myConsoleTest.GetActivities(0, 10, ActivityOrderCriteria.ByAthleteId, false); -foreach(var myActivity in res) -{ - Console.WriteLine(myActivity.Id + ", " + myActivity.Type + ", " + myActivity.StartTime + ", " + myActivity.EndTime + ", " + myActivity.DataSource + ", " + myActivity.Athlete); -} - -// Affiche les activités par id -Console.WriteLine("Affichage du livre d'id 1 : "); -res = (IEnumerable)await myConsoleTest.GetActivityByIdAsync(1); -foreach (var myActivity in res) -{ - Console.WriteLine(myActivity.Id + ", " + myActivity.Type + ", " + myActivity.StartTime + ", " + myActivity.EndTime + ", " + myActivity.DataSource + ", " + myActivity.Athlete); -} - -// Ajouter une nouvelle activité -Console.WriteLine("Ajout d'un nouveau livre : "); -var newActivity = new ActivityDto { Type = "New Activity", StartTime = DateTime.Now, EndTime = DateTime.Now, DataSource = new DataSourceDto{}, Athlete = new UserDto{ Username = "Hello", FirstName = "feee", Email = "exemple.com", LastName = "dddd", Sexe = "M" } }; -var addedActivity = await myConsoleTest.AddActivity(newActivity.ToModel()); -Console.WriteLine($"Id: {addedActivity.Id}, Type: {addedActivity.Type}, StartTime: {addedActivity.StartTime}, EndTime: {addedActivity.EndTime}, DataSource: {addedActivity.DataSource}, Athlete: {addedActivity.Athlete}"); - -// Mettre à jour l'activity ajouté -Console.WriteLine("Mise à jour du livre ajouté : "); -var activity = await myConsoleTest.UpdateActivity(1, new ActivityDto { Id = 1, Type = "Updated Activity", StartTime = DateTime.Now, EndTime = DateTime.Now, DataSource = new DataSourceDto{}, Athlete = new UserDto{ Username = "Hello", FirstName = "feee", Email = "exemple.com", LastName = "dddd", Sexe = "M" } }.ToModel()); -Console.WriteLine($"Id: {activity.Id}, Type: {activity.Type}, StartTime: {activity.StartTime}, EndTime: {activity.EndTime}, DataSource: {activity.DataSource}, Athlete: {activity.Athlete}"); - -// Supprimer l'activity ajouté -Console.WriteLine("Suppression du livre ajouté : "); -await myConsoleTest.DeleteActivity(newActivity.Id); -res = await myConsoleTest.GetActivities(0, 10, ActivityOrderCriteria.ByAthleteId, false); -foreach (var activity1 in res) -{ - Console.WriteLine(activity1.Id + ", " + activity1.Type + ", " + activity1.StartTime + ", " + activity1.EndTime + ", " + activity1.DataSource + ", " + activity1.Athlete); -} - -// Affiche le nombre d'activités -Console.WriteLine("Affichage du nombre d'activités : "); -var nb = await myConsoleTest.GetNbItems(); -Console.WriteLine(nb); - -// Affiche les activités par utilisateur -Console.WriteLine("Affichage des activités par utilisateur : "); -res = await myConsoleTest.GetActivitiesByUser(1, 0, 10, ActivityOrderCriteria.ByAthleteId, false); -foreach (var activity3 in res) -{ - Console.WriteLine(activity3.Id + ", " + activity3.Type + ", " + activity3.StartTime + ", " + activity3.EndTime + ", " + activity3.DataSource + ", " + activity3.Athlete); -} - -// Affiche le nombre d'activités par utilisateur -Console.WriteLine("Affichage du nombre d'activités par utilisateur : "); -nb = await myConsoleTest.GetNbActivitiesByUser(1); +using APIMappers; +using Dto; +using Model; +using Model.Repository; +using Shared; + +namespace WebAPIConsoleTests; + +IActivityRepository myConsoleTest = new ActivityServiceAPI(); + +// defini un delais d'attente du déploiement de l'API +await Task.Delay(5000); + +// Affiche toutes les activités +Console.WriteLine("Affichage de toutes les Activités : "); +var res = await myConsoleTest.GetActivities(0, 10, ActivityOrderCriteria.ByAthleteId, false); +foreach(var myActivity in res) +{ + Console.WriteLine(myActivity.Id + ", " + myActivity.Type + ", " + myActivity.StartTime + ", " + myActivity.EndTime + ", " + myActivity.DataSource + ", " + myActivity.Athlete); +} + +// Affiche les activités par id +Console.WriteLine("Affichage du livre d'id 1 : "); +res = (IEnumerable)await myConsoleTest.GetActivityByIdAsync(1); +foreach (var myActivity in res) +{ + Console.WriteLine(myActivity.Id + ", " + myActivity.Type + ", " + myActivity.StartTime + ", " + myActivity.EndTime + ", " + myActivity.DataSource + ", " + myActivity.Athlete); +} + +// Ajouter une nouvelle activité +Console.WriteLine("Ajout d'un nouveau livre : "); +var newActivity = new ActivityDto { Type = "New Activity", StartTime = DateTime.Now, EndTime = DateTime.Now, DataSource = new DataSourceDto{}, Athlete = new UserDto{ Username = "Hello", FirstName = "feee", Email = "exemple.com", LastName = "dddd", Sexe = "M" } }; +var addedActivity = await myConsoleTest.AddActivity(newActivity.ToModel()); +Console.WriteLine($"Id: {addedActivity.Id}, Type: {addedActivity.Type}, StartTime: {addedActivity.StartTime}, EndTime: {addedActivity.EndTime}, DataSource: {addedActivity.DataSource}, Athlete: {addedActivity.Athlete}"); + +// Mettre à jour l'activity ajouté +Console.WriteLine("Mise à jour du livre ajouté : "); +var activity = await myConsoleTest.UpdateActivity(1, new ActivityDto { Id = 1, Type = "Updated Activity", StartTime = DateTime.Now, EndTime = DateTime.Now, DataSource = new DataSourceDto{}, Athlete = new UserDto{ Username = "Hello", FirstName = "feee", Email = "exemple.com", LastName = "dddd", Sexe = "M" } }.ToModel()); +Console.WriteLine($"Id: {activity.Id}, Type: {activity.Type}, StartTime: {activity.StartTime}, EndTime: {activity.EndTime}, DataSource: {activity.DataSource}, Athlete: {activity.Athlete}"); + +// Supprimer l'activity ajouté +Console.WriteLine("Suppression du livre ajouté : "); +await myConsoleTest.DeleteActivity(newActivity.Id); +res = await myConsoleTest.GetActivities(0, 10, ActivityOrderCriteria.ByAthleteId, false); +foreach (var activity1 in res) +{ + Console.WriteLine(activity1.Id + ", " + activity1.Type + ", " + activity1.StartTime + ", " + activity1.EndTime + ", " + activity1.DataSource + ", " + activity1.Athlete); +} + +// Affiche le nombre d'activités +Console.WriteLine("Affichage du nombre d'activités : "); +var nb = await myConsoleTest.GetNbItems(); +Console.WriteLine(nb); + +// Affiche les activités par utilisateur +Console.WriteLine("Affichage des activités par utilisateur : "); +res = await myConsoleTest.GetActivitiesByUser(1, 0, 10, ActivityOrderCriteria.ByAthleteId, false); +foreach (var activity3 in res) +{ + Console.WriteLine(activity3.Id + ", " + activity3.Type + ", " + activity3.StartTime + ", " + activity3.EndTime + ", " + activity3.DataSource + ", " + activity3.Athlete); +} + +// Affiche le nombre d'activités par utilisateur +Console.WriteLine("Affichage du nombre d'activités par utilisateur : "); +nb = await myConsoleTest.GetNbActivitiesByUser(1); Console.WriteLine(nb); \ No newline at end of file From b769290f577109eb54866b78d7a2be01adabfe20 Mon Sep 17 00:00:00 2001 From: anperederi Date: Sun, 17 Mar 2024 01:10:25 +0100 Subject: [PATCH 11/92] =?UTF-8?q?=F0=9F=90=9B=20Fix=20namespace=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Tests/WebAPIConsoleTests/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tests/WebAPIConsoleTests/Program.cs b/src/Tests/WebAPIConsoleTests/Program.cs index adf0070..8db0f5f 100644 --- a/src/Tests/WebAPIConsoleTests/Program.cs +++ b/src/Tests/WebAPIConsoleTests/Program.cs @@ -3,8 +3,8 @@ using Dto; using Model; using Model.Repository; using Shared; +using WebAPIConsoleTests; -namespace WebAPIConsoleTests; IActivityRepository myConsoleTest = new ActivityServiceAPI(); From 1db4be9e0d831a8025ee5b0819e950496ea07dce Mon Sep 17 00:00:00 2001 From: dave Date: Mon, 18 Mar 2024 21:39:04 +0100 Subject: [PATCH 12/92] finist but not clean --- src/APIMappers/ActivityMapper.cs | 27 ++- src/APIMappers/HeartRateMapper.cs | 1 - src/DbContextLib/HeartTrackContext.cs | 6 +- src/Dto/DataSourceDto.cs | 2 - src/Dto/NewActivityDto.cs | 12 ++ src/Dto/ResponseActivityDto.cs | 25 +++ src/Dto/ResponseDataSourceDto.cs | 18 ++ src/Dto/ResponseUserDto.cs | 28 +++ src/Dto/Tiny/ActivityTinyDto.cs | 19 ++ src/Dto/Tiny/DataSourceTinyDto.cs | 12 ++ src/Dto/Tiny/FriendshipDto.cs | 7 + src/Dto/Tiny/HeartRateTinyDto.cs | 16 ++ src/Dto/Tiny/UserTinyDto.cs | 22 ++ src/EFMappers/AthleteMappeur.cs | 11 - src/Entities/ActivityEntity.cs | 2 +- src/Entities/AthleteEntity.cs | 1 - src/Entities2Dto/ActivityMapper.cs | 102 +++++++++ src/Entities2Dto/DataSourceMapper.cs | 70 ++++++ src/Entities2Dto/FriendshipMapper.cs | 32 +++ src/Entities2Dto/HeartRateMapper.cs | 63 ++++++ src/Entities2Dto/LargeImageMapper.cs | 32 +++ src/Entities2Dto/UserMappeur.cs | 102 +++++++++ src/HeartTrack.sln | 6 + .../Controllers/ActivityController.cs | 95 ++------ .../Controllers/AnalysisController.cs | 70 ++++++ .../Controllers/UsersController.cs | 152 +++++-------- src/Model/Repository/IActivityRepository.cs | 8 +- src/Model/Repository/IUserRepository.cs | 20 +- src/Model2Entities/ActivityRepository.cs | 52 ++++- src/Model2Entities/Extension.cs | 7 +- src/Model2Entities/Model2Entities.csproj | 1 + src/Model2Entities/UserRepository.cs | 202 +++++++++++++----- src/Shared/AthleteOrderCriteria.cs | 28 --- src/Shared/Extension.cs | 8 +- src/Shared/ModelException.cs | 15 ++ src/StubAPI/ActivityService.cs | 53 +++-- src/StubAPI/AthleteService.cs | 38 +++- src/StubAPI/StubAPI.csproj | 1 + .../AthleteStubbedContext.cs | 2 +- .../FriendshipStubbedContext.cs | 5 +- src/Tests/ConsoleTestEFMapper/Program.cs | 3 +- .../Controllers/UsersControllerTest.cs | 10 +- .../FriendshipEntityTests.cs | 2 +- 43 files changed, 1042 insertions(+), 346 deletions(-) create mode 100644 src/Dto/NewActivityDto.cs create mode 100644 src/Dto/ResponseActivityDto.cs create mode 100644 src/Dto/ResponseDataSourceDto.cs create mode 100644 src/Dto/ResponseUserDto.cs create mode 100644 src/Dto/Tiny/ActivityTinyDto.cs create mode 100644 src/Dto/Tiny/DataSourceTinyDto.cs create mode 100644 src/Dto/Tiny/FriendshipDto.cs create mode 100644 src/Dto/Tiny/HeartRateTinyDto.cs create mode 100644 src/Dto/Tiny/UserTinyDto.cs create mode 100644 src/Entities2Dto/ActivityMapper.cs create mode 100644 src/Entities2Dto/DataSourceMapper.cs create mode 100644 src/Entities2Dto/FriendshipMapper.cs create mode 100644 src/Entities2Dto/HeartRateMapper.cs create mode 100644 src/Entities2Dto/LargeImageMapper.cs create mode 100644 src/Entities2Dto/UserMappeur.cs create mode 100644 src/HeartTrackAPI/Controllers/AnalysisController.cs create mode 100644 src/Shared/ModelException.cs diff --git a/src/APIMappers/ActivityMapper.cs b/src/APIMappers/ActivityMapper.cs index 2442a40..21af46d 100644 --- a/src/APIMappers/ActivityMapper.cs +++ b/src/APIMappers/ActivityMapper.cs @@ -1,4 +1,6 @@ using Dto; +using Dto.Tiny; +using Entities; using Model; using Shared; @@ -7,7 +9,8 @@ namespace APIMappers; public static class ActivityMapper { private static GenericMapper _mapper = new(); - + private static GenericMapper _mapperTiny = new (); + public static Activity ToModel(this ActivityDto activityDto, User user) { Func create = activity => new Activity @@ -72,6 +75,28 @@ public static class ActivityMapper return model.ToU(_mapper, create, link); } + public static ActivityEntity ToEntity(this ActivityTinyDto tinyDto) + { + Func create = dto => new ActivityEntity + { + Type = dto.Type, + Date = DateOnly.FromDateTime(dto.Date), + StartTime = TimeOnly.FromDateTime(dto.StartTime), + EndTime = TimeOnly.FromDateTime(dto.EndTime), + EffortFelt = dto.EffortFelt, + Variability = dto.Variability, + Variance = dto.Variance, + StandardDeviation = dto.StandardDeviation, + Average = dto.Average, + Maximum = dto.Maximum, + Minimum = dto.Minimum, + AverageTemperature = dto.AverageTemperature, + HasAutoPause = dto.HasAutoPause + }; + + return tinyDto.ToU(_mapperTiny, create); + } + public static IEnumerable ToModels(this IEnumerable dtos, User user) => dtos.Select(dto => dto.ToModel(user)); diff --git a/src/APIMappers/HeartRateMapper.cs b/src/APIMappers/HeartRateMapper.cs index c5f81a6..bfcaf9f 100644 --- a/src/APIMappers/HeartRateMapper.cs +++ b/src/APIMappers/HeartRateMapper.cs @@ -18,7 +18,6 @@ public static class HeartRateMapper public static HeartRateDto ToDto(this HeartRate model)//Activity activity { - // [TODO] [Dave] fix this should be activity but it boucle indefinitly var activity = new DateTime(); Func create = heartRate => new HeartRateDto diff --git a/src/DbContextLib/HeartTrackContext.cs b/src/DbContextLib/HeartTrackContext.cs index 3e94ae9..2dfb977 100644 --- a/src/DbContextLib/HeartTrackContext.cs +++ b/src/DbContextLib/HeartTrackContext.cs @@ -168,16 +168,16 @@ namespace DbContextLib .ValueGeneratedOnAdd(); modelBuilder.Entity() - .HasKey(f => new { f.FollowingId, f.FollowerId }); + .HasKey(f => new { f.FollowerId, f.FollowingId }); modelBuilder.Entity() .HasOne(fing => fing.Following) - .WithMany(fings => fings.Followings) + .WithMany(fings => fings.Followers) .HasForeignKey(fing => fing.FollowingId); modelBuilder.Entity() .HasOne(fer => fer.Follower) - .WithMany(fers => fers.Followers) + .WithMany(fers => fers.Followings) .HasForeignKey(fing => fing.FollowerId); // ! diff --git a/src/Dto/DataSourceDto.cs b/src/Dto/DataSourceDto.cs index 74705a1..21eb46b 100644 --- a/src/Dto/DataSourceDto.cs +++ b/src/Dto/DataSourceDto.cs @@ -12,11 +12,9 @@ public class DataSourceDto public float Precision { get; set; } - // [TODO] [Dave] Add a property to store the athletes and the activities so maybe adapt to have a tiny DTO [JsonIgnore] public IEnumerable? Athletes { get; set; } - // [TODO] [Dave] Add a property to store the athletes and the activities so maybe adapt to have a tiny DTO [JsonIgnore] public IEnumerable? Activities { get; set; } } \ No newline at end of file diff --git a/src/Dto/NewActivityDto.cs b/src/Dto/NewActivityDto.cs new file mode 100644 index 0000000..e3bd0f1 --- /dev/null +++ b/src/Dto/NewActivityDto.cs @@ -0,0 +1,12 @@ +using Dto.Tiny; + +namespace Dto; + +public class NewActivityDto +{ + public ActivityTinyDto Activity { get; set; } + public HeartRateTinyDto[]? HeartRates { get; set; } + public int? DataSourceId { get; set; } + public int AthleteId { get; set; } + +} \ No newline at end of file diff --git a/src/Dto/ResponseActivityDto.cs b/src/Dto/ResponseActivityDto.cs new file mode 100644 index 0000000..dd92956 --- /dev/null +++ b/src/Dto/ResponseActivityDto.cs @@ -0,0 +1,25 @@ +using Dto.Tiny; + +namespace Dto; + +public class ResponseActivityDto +{ + 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; } + public int EffortFelt { get; set; } + 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 HeartRateTinyDto[]? HeartRates { get; set; } + public DataSourceTinyDto? DataSource { get; set; } + public UserTinyDto? Athlete { get; set; } + +} \ No newline at end of file diff --git a/src/Dto/ResponseDataSourceDto.cs b/src/Dto/ResponseDataSourceDto.cs new file mode 100644 index 0000000..ae260f6 --- /dev/null +++ b/src/Dto/ResponseDataSourceDto.cs @@ -0,0 +1,18 @@ +using Dto.Tiny; + +namespace Dto; + +public class ResponseDataSourceDto +{ + public int Id { get; set; } + + public string Type { get; set; } = "Unknown"; + + public string Model { get; set; } + + public float Precision { get; set; } + + public ActivityTinyDto[]? Activities { get; set; } + + public UserTinyDto[]? Users { get; set; } +} \ No newline at end of file diff --git a/src/Dto/ResponseUserDto.cs b/src/Dto/ResponseUserDto.cs new file mode 100644 index 0000000..673d00f --- /dev/null +++ b/src/Dto/ResponseUserDto.cs @@ -0,0 +1,28 @@ +using System.ComponentModel.DataAnnotations; +using Dto.Tiny; + +namespace Dto; + +public class ResponseUserDto +{ + 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; } = "https://davidalmeida.site/assets/me_avatar.f77af006.png"; + public bool IsCoach { get; set; } + public LargeImageDto? Image { get; set; } + public ActivityTinyDto[] Activities { get; set; } + public DataSourceTinyDto DataSource { get; set; } + public FriendshipDto?[] Followers { get; set; } + public FriendshipDto?[] Followings { get; set; } +} \ No newline at end of file diff --git a/src/Dto/Tiny/ActivityTinyDto.cs b/src/Dto/Tiny/ActivityTinyDto.cs new file mode 100644 index 0000000..2865be0 --- /dev/null +++ b/src/Dto/Tiny/ActivityTinyDto.cs @@ -0,0 +1,19 @@ +namespace Dto.Tiny; + +public class ActivityTinyDto +{ + 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; } + public int EffortFelt { get; set; } + 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; } +} \ No newline at end of file diff --git a/src/Dto/Tiny/DataSourceTinyDto.cs b/src/Dto/Tiny/DataSourceTinyDto.cs new file mode 100644 index 0000000..0cbf471 --- /dev/null +++ b/src/Dto/Tiny/DataSourceTinyDto.cs @@ -0,0 +1,12 @@ +namespace Dto.Tiny; + +public class DataSourceTinyDto +{ + public int Id { get; set; } + + public string Type { get; set; } = "Unknown"; + + public string Model { get; set; } + + public float Precision { get; set; } +} \ No newline at end of file diff --git a/src/Dto/Tiny/FriendshipDto.cs b/src/Dto/Tiny/FriendshipDto.cs new file mode 100644 index 0000000..76deabd --- /dev/null +++ b/src/Dto/Tiny/FriendshipDto.cs @@ -0,0 +1,7 @@ +namespace Dto.Tiny; + +public class FriendshipDto +{ + public int FollowedId { get; set; } + public int FollowerId { get; set; } +} \ No newline at end of file diff --git a/src/Dto/Tiny/HeartRateTinyDto.cs b/src/Dto/Tiny/HeartRateTinyDto.cs new file mode 100644 index 0000000..a80472b --- /dev/null +++ b/src/Dto/Tiny/HeartRateTinyDto.cs @@ -0,0 +1,16 @@ +namespace Dto.Tiny; + +public class HeartRateTinyDto +{ + public int Id { get; set; } + public DateTime Timestamp { get; set; } + public double? Latitude { get; set; } + public double? Longitude { get; set; } + public double? Altitude { get; set; } + public int HeartRate { get; set; } + public int? Cadence { get; set; } + public double? Distance { get; set; } + public double? Speed { get; set; } + public int? Power { get; set; } + public double? Temperature { get; set; } +} \ No newline at end of file diff --git a/src/Dto/Tiny/UserTinyDto.cs b/src/Dto/Tiny/UserTinyDto.cs new file mode 100644 index 0000000..7f5df8f --- /dev/null +++ b/src/Dto/Tiny/UserTinyDto.cs @@ -0,0 +1,22 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dto.Tiny; + +public class UserTinyDto +{ + 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; } = "https://davidalmeida.site/assets/me_avatar.f77af006.png"; + public bool IsCoach { get; set; } +} \ No newline at end of file diff --git a/src/EFMappers/AthleteMappeur.cs b/src/EFMappers/AthleteMappeur.cs index ef779f1..1cd39a8 100644 --- a/src/EFMappers/AthleteMappeur.cs +++ b/src/EFMappers/AthleteMappeur.cs @@ -62,17 +62,6 @@ public static class UserMappeur entity.Activities = user.Activities.ToEntities().ToList(); entity.IsCoach = user.Role is Coach; entity.Image = user.Image.ToEntity(); - /*if (user.Role is Coach) - entity.TrainingsCoach = user.Traning.ToEntities().ToList(); - else - entity.TrainingsAthlete = user.Traning.ToEntities().ToList(); - */ - // entity.NotificationsReceived = user.Notifications.ToEntities().ToList(); - - // entity.DataSource = user.DataSources.ToEntities().ToList(); - - // [TODO] [DAVE] : Add the link to the friendship - }; return model.ToU(_mapper, create, link); diff --git a/src/Entities/ActivityEntity.cs b/src/Entities/ActivityEntity.cs index d1af116..9776074 100644 --- a/src/Entities/ActivityEntity.cs +++ b/src/Entities/ActivityEntity.cs @@ -105,6 +105,6 @@ namespace Entities public int AthleteId { get; set; } - public AthleteEntity Athlete { get; set; } = null!; + public AthleteEntity Athlete { get; set; } } } \ No newline at end of file diff --git a/src/Entities/AthleteEntity.cs b/src/Entities/AthleteEntity.cs index 199d635..3b89fbe 100644 --- a/src/Entities/AthleteEntity.cs +++ b/src/Entities/AthleteEntity.cs @@ -87,7 +87,6 @@ namespace Entities /// public bool IsCoach { get; set; } - // [TODO] [DAVE] Check Image public string? ProfilPicture { get; set; } public LargeImageEntity? Image { get; set; } diff --git a/src/Entities2Dto/ActivityMapper.cs b/src/Entities2Dto/ActivityMapper.cs new file mode 100644 index 0000000..116f63a --- /dev/null +++ b/src/Entities2Dto/ActivityMapper.cs @@ -0,0 +1,102 @@ +using Dto; +using Dto.Tiny; +using Entities; +using Shared; + +namespace Entities2Dto; + +public static class ActivityMapper +{ + private static GenericMapper _mapper = new (); + + private static GenericMapper _mapperFull = new (); + + public static void Reset() + { + _mapper.Reset(); + _mapperFull.Reset(); + } + + public static ActivityTinyDto ToDto(this ActivityEntity entity) + { + Console.WriteLine("dfghf"); + Func create = activityEntity => new ActivityTinyDto + { + Id = activityEntity.IdActivity, + Type = activityEntity.Type, + Date = activityEntity.Date.ToDateTime(TimeOnly.MinValue), + StartTime = activityEntity.Date.ToDateTime(activityEntity.StartTime), + EndTime = activityEntity.Date.ToDateTime(activityEntity.EndTime), + EffortFelt = activityEntity.EffortFelt, + Variability = activityEntity.Variability, + Variance = activityEntity.Variance, + StandardDeviation = activityEntity.StandardDeviation, + Average = activityEntity.Average, + Maximum = activityEntity.Maximum, + Minimum = activityEntity.Minimum, + AverageTemperature = activityEntity.AverageTemperature, + HasAutoPause = activityEntity.HasAutoPause + }; + return entity.ToT(_mapper, create, null, false); + } + + public static ActivityEntity ToEntity(this ActivityTinyDto dto) + { + Func create = activity => new ActivityEntity + { + Type = activity.Type, + Date = DateOnly.FromDateTime(activity.Date), + StartTime = TimeOnly.FromDateTime(activity.StartTime), + EndTime = TimeOnly.FromDateTime(activity.EndTime), + EffortFelt = activity.EffortFelt, + Variability = activity.Variability, + Variance = activity.Variance, + StandardDeviation = activity.StandardDeviation, + Average = activity.Average, + Maximum = activity.Maximum, + Minimum = activity.Minimum, + AverageTemperature = activity.AverageTemperature, + HasAutoPause = activity.HasAutoPause + }; + return dto.ToU(_mapper, create); + } + + public static ResponseActivityDto ToResponseDto(this ActivityEntity entity) + { + Func create = activityEntity => new ResponseActivityDto + { + Id = activityEntity.IdActivity, + Type = activityEntity.Type, + Date = activityEntity.Date.ToDateTime(TimeOnly.MinValue), + StartTime = activityEntity.Date.ToDateTime(activityEntity.StartTime), + EndTime = activityEntity.Date.ToDateTime(activityEntity.EndTime), + EffortFelt = activityEntity.EffortFelt, + Variability = activityEntity.Variability, + Variance = activityEntity.Variance, + StandardDeviation = activityEntity.StandardDeviation, + Average = activityEntity.Average, + Maximum = activityEntity.Maximum, + Minimum = activityEntity.Minimum, + AverageTemperature = activityEntity.AverageTemperature, + HasAutoPause = activityEntity.HasAutoPause + }; + + Action linker = (activityEntity, activity) => + { + if (activityEntity.HeartRates != null) activity.HeartRates = activityEntity.HeartRates.ToTinyDtos().ToArray(); + activity.DataSource = activityEntity.DataSource != null ? activityEntity.DataSource.ToTinyDto() : null; + activity.Athlete = activityEntity.Athlete.ToTinyDto(); + }; + + return entity.ToT(_mapperFull, create, linker, false); + } + + public static IEnumerable ToTinyDtos(this IEnumerable entities) + => entities.Select(a => a.ToDto()); + + public static IEnumerable ToEntities(this IEnumerable dtos) + => dtos.Select(a => a.ToEntity()); + + + +} \ No newline at end of file diff --git a/src/Entities2Dto/DataSourceMapper.cs b/src/Entities2Dto/DataSourceMapper.cs new file mode 100644 index 0000000..2aa5a50 --- /dev/null +++ b/src/Entities2Dto/DataSourceMapper.cs @@ -0,0 +1,70 @@ +using Dto; +using Dto.Tiny; +using Entities; +using Shared; + +namespace Entities2Dto; + +public static class DataSourceMapper +{ + private static GenericMapper _mapper = new(); + + private static GenericMapper _mapperFull = new(); + + public static void Reset() + { + _mapper.Reset(); + _mapperFull.Reset(); + } + + public static DataSourceTinyDto ToTinyDto(this DataSourceEntity entity) + { + Func create = dataSourceEntity => new DataSourceTinyDto + { + Id = dataSourceEntity.IdSource, + Type = dataSourceEntity.Type, + Model = dataSourceEntity.Model, + Precision = dataSourceEntity.Precision + }; + return entity.ToT(_mapper, create, null,false); + } + + public static DataSourceEntity ToEntity(this DataSourceTinyDto dto) + { + Func create = dataSource => new DataSourceEntity + { + IdSource = dataSource.Id, + Type = dataSource.Type, + Model = dataSource.Model, + Precision = dataSource.Precision + }; + return dto.ToU(_mapper, create); + } + + public static ResponseDataSourceDto ToResponseDto(this DataSourceEntity entity) + { + Func create = dataSourceEntity => new ResponseDataSourceDto + { + Id = dataSourceEntity.IdSource, + Type = dataSourceEntity.Type, + Model = dataSourceEntity.Model, + Precision = dataSourceEntity.Precision, + }; + + Action linker = (dataSourceEntity, dto) => + { + dto.Activities = dataSourceEntity.Activities.ToTinyDtos().ToArray(); + dto.Users = dataSourceEntity.Athletes.ToTinyDtos().ToArray(); + }; + + return entity.ToT(_mapperFull, create, linker, false); + } + + public static IEnumerable ToTinyDtos(this IEnumerable entities) + => entities.Select(e => e.ToTinyDto()); + + public static IEnumerable ToEntities(this IEnumerable dtos) + => dtos.Select(d => d.ToEntity()); + + +} \ No newline at end of file diff --git a/src/Entities2Dto/FriendshipMapper.cs b/src/Entities2Dto/FriendshipMapper.cs new file mode 100644 index 0000000..ccc9707 --- /dev/null +++ b/src/Entities2Dto/FriendshipMapper.cs @@ -0,0 +1,32 @@ +using Dto.Tiny; +using Entities; +using Shared; + +namespace Entities2Dto; + +public static class FriendshipMapper +{ + private static GenericMapper _mapper = new(); + + public static void Reset() + { + _mapper.Reset(); + } + + public static FriendshipDto ToTinyDto(this FriendshipEntity entity) + { + Func create = friendshipEntity => new FriendshipDto + { + FollowedId = friendshipEntity.FollowingId, + FollowerId = friendshipEntity.FollowerId, + }; + + return entity.ToT(_mapper, create, null, false); + } + + public static IEnumerable ToTinyDtos(this IEnumerable entities) + => entities.Select(e => e.ToTinyDto()); + + + +} \ No newline at end of file diff --git a/src/Entities2Dto/HeartRateMapper.cs b/src/Entities2Dto/HeartRateMapper.cs new file mode 100644 index 0000000..5ef863c --- /dev/null +++ b/src/Entities2Dto/HeartRateMapper.cs @@ -0,0 +1,63 @@ +using Dto.Tiny; +using Entities; +using Shared; + +namespace Entities2Dto; + +public static class HeartRateMapper +{ + + private static GenericMapper _mapper = new(); + + public static void Reset() + { + _mapper.Reset(); + } + + public static HeartRateTinyDto ToTinyDto(this HeartRateEntity entity) + { + var activityTmp = new DateTime(); + Func create = heartRateEntity => new HeartRateTinyDto + { + Id = heartRateEntity.IdHeartRate, + HeartRate = heartRateEntity.Bpm, + Timestamp = activityTmp, + Latitude = heartRateEntity.Latitude, + Longitude = heartRateEntity.Longitude, + Altitude = heartRateEntity.Altitude, + Cadence = heartRateEntity.Cadence, + Distance = heartRateEntity.Distance, + Speed = heartRateEntity.Speed, + Power = heartRateEntity.Power, + Temperature = heartRateEntity.Temperature + }; + + return entity.ToT(_mapper, create, null, false); + } + + public static HeartRateEntity ToEntity(this HeartRateTinyDto dto) + { + Func create = heartRate => new HeartRateEntity + { + IdHeartRate = heartRate.Id, + Bpm = heartRate.HeartRate, + Time = TimeOnly.FromDateTime(heartRate.Timestamp), + Latitude = heartRate.Latitude, + Longitude = heartRate.Longitude, + Altitude = heartRate.Altitude, + Cadence = heartRate.Cadence, + Distance = heartRate.Distance, + Speed = heartRate.Speed, + Power = heartRate.Power, + Temperature = heartRate.Temperature + }; + return dto.ToU(_mapper, create); + } + + public static IEnumerable ToTinyDtos(this IEnumerable entities) + => entities.Select(e => e.ToTinyDto()); + + public static IEnumerable ToEntities(this IEnumerable dtos) + => dtos.Select(d => d.ToEntity()); + +} \ No newline at end of file diff --git a/src/Entities2Dto/LargeImageMapper.cs b/src/Entities2Dto/LargeImageMapper.cs new file mode 100644 index 0000000..8a225d5 --- /dev/null +++ b/src/Entities2Dto/LargeImageMapper.cs @@ -0,0 +1,32 @@ +using Dto; +using Entities; +using Shared; + +namespace Entities2Dto; + +public static class LargeImageMapper +{ + private static GenericMapper _mapper = new(); + + public static void Reset() + { + _mapper.Reset(); + } + + public static LargeImageDto ToDto(this LargeImageEntity entity) + { + Func create = largeImageEntity => new() { Base64 = largeImageEntity.Base64 }; + + return entity.ToT(_mapper, create, null, false); + } + + public static LargeImageEntity ToEntity(this LargeImageDto dto) + { + Func create = largeImage => new LargeImageEntity + { + Base64 = largeImage.Base64 + }; + + return dto.ToU(_mapper, create); + } +} \ No newline at end of file diff --git a/src/Entities2Dto/UserMappeur.cs b/src/Entities2Dto/UserMappeur.cs new file mode 100644 index 0000000..71b2dcf --- /dev/null +++ b/src/Entities2Dto/UserMappeur.cs @@ -0,0 +1,102 @@ +using Dto; +using Dto.Tiny; +using Entities; +using Shared; + +namespace Entities2Dto; + +public static class UserMappeur +{ + private static GenericMapper _mapper = new(); + private static GenericMapper _mapperFull = new(); + + + public static void Reset() + { + _mapper.Reset(); + _mapperFull.Reset(); + } + + public static UserTinyDto ToTinyDto(this AthleteEntity entity) + { + Func create = athleteEntity => new UserTinyDto + { + Id = athleteEntity.IdAthlete, + FirstName = athleteEntity.FirstName, + LastName = athleteEntity.LastName, + Email = athleteEntity.Email, + Password = athleteEntity.Password, + DateOfBirth = athleteEntity.DateOfBirth.ToDateTime(TimeOnly.MinValue), + Sexe = athleteEntity.Sexe, + Username = athleteEntity.Username, + Weight = athleteEntity.Weight, + Lenght = (float)athleteEntity.Length, + ProfilePicture = athleteEntity.ProfilPicture ?? "", + IsCoach = athleteEntity.IsCoach + }; + + return entity.ToT(_mapper, create, null, false); + } + + public static AthleteEntity ToEntity(this UserTinyDto model) + { + Func create = user => new AthleteEntity + { + IdAthlete = user.Id, + Username = user.Username, + Sexe = user.Sexe, + FirstName = user.FirstName, + LastName = user.LastName, + Email = user.Email, + Password = user.Password ?? "", + DateOfBirth = DateOnly.FromDateTime(user.DateOfBirth), + IsCoach = user.IsCoach, + Weight = user.Weight, + Length = user.Lenght, + ProfilPicture = user.ProfilePicture + }; + + return model.ToU(_mapper, create); + } + + public static ResponseUserDto ToResponseDto(this AthleteEntity entity) + { + Func creator = athleteEntity => new ResponseUserDto + { + Id = athleteEntity.IdAthlete, + FirstName = athleteEntity.FirstName, + LastName = athleteEntity.LastName, + Email = athleteEntity.Email, + Password = athleteEntity.Password, + DateOfBirth = athleteEntity.DateOfBirth.ToDateTime(TimeOnly.MinValue), + Sexe = athleteEntity.Sexe, + Username = athleteEntity.Username, + Weight = athleteEntity.Weight, + Lenght = (float)athleteEntity.Length, + ProfilePicture = athleteEntity.ProfilPicture ?? "", + IsCoach = athleteEntity.IsCoach, + }; + + Action linker = (athleteEntity, userDto) => + { + userDto.Activities = athleteEntity.Activities.ToTinyDtos().ToArray(); + userDto.Image = athleteEntity.Image?.ToDto(); + userDto.DataSource = athleteEntity.DataSource.ToTinyDto(); + userDto.Followers = athleteEntity.Followers.ToTinyDtos().ToArray(); + userDto.Followings = athleteEntity.Followings.ToTinyDtos().ToArray(); + }; + + return entity.ToT(_mapperFull, creator, linker, false); + } + + public static IEnumerable ToTinyDtos(this IEnumerable entities) + => entities.Select(e => e.ToTinyDto()); + + public static IEnumerable ToEntities(this IEnumerable models) + => models.Select(m => m.ToEntity()); + + + + + +} \ No newline at end of file diff --git a/src/HeartTrack.sln b/src/HeartTrack.sln index 8bd8954..a20b9ff 100644 --- a/src/HeartTrack.sln +++ b/src/HeartTrack.sln @@ -43,6 +43,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APIMappers", "APIMappers\AP EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestsModel", "Tests\UnitTestsModel\UnitTestsModel.csproj", "{508D380F-145C-437E-A7DF-7A17C526B2F3}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entities2Dto", "Entities2Dto\Entities2Dto.csproj", "{1B15D383-1DFA-47E8-86EC-AC631B15FBEB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -121,6 +123,10 @@ Global {508D380F-145C-437E-A7DF-7A17C526B2F3}.Debug|Any CPU.Build.0 = Debug|Any CPU {508D380F-145C-437E-A7DF-7A17C526B2F3}.Release|Any CPU.ActiveCfg = Release|Any CPU {508D380F-145C-437E-A7DF-7A17C526B2F3}.Release|Any CPU.Build.0 = Release|Any CPU + {1B15D383-1DFA-47E8-86EC-AC631B15FBEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1B15D383-1DFA-47E8-86EC-AC631B15FBEB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1B15D383-1DFA-47E8-86EC-AC631B15FBEB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1B15D383-1DFA-47E8-86EC-AC631B15FBEB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/HeartTrackAPI/Controllers/ActivityController.cs b/src/HeartTrackAPI/Controllers/ActivityController.cs index b6e160b..79f8654 100644 --- a/src/HeartTrackAPI/Controllers/ActivityController.cs +++ b/src/HeartTrackAPI/Controllers/ActivityController.cs @@ -1,9 +1,9 @@ using APIMappers; using Dto; +using Dto.Tiny; using HeartTrackAPI.Request; using HeartTrackAPI.Responce; using Microsoft.AspNetCore.Mvc; -using Model; using Shared; using Model.Manager; using Model.Repository; @@ -30,7 +30,7 @@ public class ActivityController : Controller [ProducesResponseType(typeof(PageResponse), 200)] [ProducesResponseType(400)] [ProducesResponseType(500)] - public async Task>> GetActivities([FromQuery] PageRequest pageRequest) + public async Task>> GetActivities([FromQuery] PageRequest pageRequest) { try { @@ -46,7 +46,9 @@ public class ActivityController : Controller { return NotFound("No activities found"); } - var pageResponse = new PageResponse(pageRequest.Index, pageRequest.Count, totalCount, activities.Select(a => a.ToDto())); + + var pageResponse = + new PageResponse(pageRequest.Index, pageRequest.Count, totalCount, activities); return Ok(pageResponse); } catch (Exception e) @@ -57,83 +59,30 @@ public class ActivityController : Controller } [HttpPost] - public async Task PostActivity(ActivityDto activityDto) + public async Task PostActivity(NewActivityDto activityDto) { - var user = await _userRepository.GetItemById(activityDto.AthleteId); + + var user = await _userRepository.GetUserById(activityDto.AthleteId); if (user == null) { _logger.LogError("Athlete with id {id} not found", activityDto.AthleteId); return NotFound($"Athlete with id {activityDto.AthleteId} not found"); } - var tmp = user.DataSources.FirstOrDefault(ds => ds.Id == activityDto.DataSourceId); - if (tmp == null) + if (activityDto.DataSourceId != null && user.DataSource.Id != activityDto.DataSourceId) { - _logger.LogError("DataSource with id {id} not found", activityDto.DataSourceId); + _logger.LogError("DataSource with id {id} not found for this user", activityDto.DataSourceId); return NotFound($"DataSource with id {activityDto.DataSourceId} not found"); } - var activity = activityDto.ToModel(user); - var result = await _activityService.AddActivity(activity); + var result = await _activityService.AddActivity(activityDto); + if (result == null) { return BadRequest(); } - return CreatedAtAction(nameof(GetActivity), new { id = result.Id }, result.ToDto()); + return CreatedAtAction(nameof(GetActivity), new { id = result.Id }, result); } - /* - public async Task PostFitFile( Stream file, string contentType) // [FromForm] - { - if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) - { - ModelState.AddModelError("File", - $"The request couldn't be processed (Error 1)."); - // Log error - - return BadRequest(ModelState); - } - if (file == null) - { - return BadRequest("No file was provided"); - } - //var fileUploadSummary = await _fileService.UploadFileAsync(HttpContext.Request.Body, Request.ContentType); -// var activity = await _activityManager.AddActivityFromFitFile(file); - var activity = new Activity - { - Id = 1, - Type = "Running", - Date = new DateTime(2021, 10, 10), - StartTime = new DateTime(2021, 10, 10, 10, 0, 0), - EndTime = new DateTime(2021, 10, 10, 11, 0, 0), - Effort = 3, - Variability = 0.5f, - Variance = 0.5f, - StandardDeviation = 0.5f, - Average = 5.0f, - Maximum = 10, - Minimum = 0, - AverageTemperature = 20.0f, - HasAutoPause = false, - Users = - { - 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() - } - } - }; - if (activity == null) - { - return BadRequest("The file provided is not a valid fit file"); - } - return CreatedAtAction(nameof(GetActivity), new { id = activity.Id }, activity.ToDto()); - }*/ - [HttpGet("{id}")] public async Task> GetActivity(int id) { @@ -158,25 +107,15 @@ public class ActivityController : Controller } [HttpPut("{id}")] - public async Task PutActivity(int id, ActivityDto activityDto) + public async Task PutActivity(int id, ActivityTinyDto activityDto) { - if (id != activityDto.Id) - { - return BadRequest(); - } - var user = await _userRepository.GetItemById(activityDto.AthleteId); - if (user == null) - { - _logger.LogError("Athlete with id {id} not found", activityDto.AthleteId); - return NotFound($"Athlete with id {activityDto.AthleteId} not found"); - } - var activity = activityDto.ToModel(user); - var result = await _activityService.UpdateActivity(id, activity); + var result = await _activityService.UpdateActivity(id, activityDto); if (result == null) { return NotFound(); } - return NoContent(); + + return Ok(result); } /// diff --git a/src/HeartTrackAPI/Controllers/AnalysisController.cs b/src/HeartTrackAPI/Controllers/AnalysisController.cs new file mode 100644 index 0000000..e4f9fcb --- /dev/null +++ b/src/HeartTrackAPI/Controllers/AnalysisController.cs @@ -0,0 +1,70 @@ +using Dto.Tiny; +using Microsoft.AspNetCore.Mvc; + +namespace HeartTrackAPI.Controllers; + +[ApiController] +[ApiVersion("1.0")] +[Route("api/[controller]")] +public class AnalysisController : ControllerBase +{ + private readonly List _heartRateZones = new() + { + new() { Name = "Repos", MinHeartRate = 0, MaxHeartRate = 60 }, + new() { Name = "Aérobie légère", MinHeartRate = 61, MaxHeartRate = 90 }, + new() { Name = "Aérobie", MinHeartRate = 91, MaxHeartRate = 140 }, + new() { Name = "Anaérobie", MinHeartRate = 141, MaxHeartRate = 180 }, + new() { Name = "VO2 Max", MinHeartRate = 181, MaxHeartRate = 220 } + }; + + [HttpGet("heart-rate/zones")] + public IActionResult GetHeartRateZones() + { + var heartRates = GetMockHeartRateData(); + var results = _heartRateZones.Select(zone => new HeartRateZoneResult + { + Zone = zone.Name, + TimeSpent = CalculateTimeInZone(zone, heartRates) + }).ToList(); + return Ok(results); + } + + private TimeSpan CalculateTimeInZone(HeartRateZone zone, List heartRates) + { + var secondsInZone = + heartRates.Count(hr => hr.HeartRate >= zone.MinHeartRate && hr.HeartRate <= zone.MaxHeartRate); + return TimeSpan.FromSeconds(secondsInZone); + } + + private List GetMockHeartRateData() + { + var random = new Random(); + return Enumerable.Range(1, 3600) + .Select(_ => new HeartRateTinyDto + { + HeartRate = random.Next(60, 220), + Timestamp = new DateTime(2021, 1, 1).AddSeconds(random.Next(3600)), + Latitude = random.NextDouble() * 180 - 90, + Longitude = random.NextDouble() * 360 - 180, + Altitude = random.NextDouble() * 1000, + Cadence = random.Next(60, 120), + Distance = random.NextDouble() * 100, + Speed = random.NextDouble() * 30, + Power = random.Next(0, 500), + Temperature = random.NextDouble() * 30 + }).ToList(); + } +} + +public class HeartRateZoneResult +{ + public string Zone { get; set; } + public TimeSpan TimeSpent { get; set; } +} + +internal class HeartRateZone +{ + public string Name { get; set; } + public int MinHeartRate { get; set; } + public int MaxHeartRate { get; set; } +} \ No newline at end of file diff --git a/src/HeartTrackAPI/Controllers/UsersController.cs b/src/HeartTrackAPI/Controllers/UsersController.cs index cd9f0b6..c7daf65 100644 --- a/src/HeartTrackAPI/Controllers/UsersController.cs +++ b/src/HeartTrackAPI/Controllers/UsersController.cs @@ -1,8 +1,11 @@ using System.ComponentModel.DataAnnotations; using APIMappers; using Dto; +using Dto.Tiny; using HeartTrackAPI.Request; using HeartTrackAPI.Responce; +using HeartTrackAPI.Utils; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Model.Manager; @@ -38,10 +41,10 @@ public class UsersController : Controller /// La demande de pagination est invalide. /// Erreur interne du serveur. [HttpGet] - [ProducesResponseType(typeof(PageResponse), 200)] + [ProducesResponseType(typeof(PageResponse), 200)] [ProducesResponseType(400)] [ProducesResponseType(500)] - public async Task>> Get([FromQuery] PageRequest request) + public async Task>> Get([FromQuery] PageRequest request) { try { @@ -54,8 +57,8 @@ public class UsersController : Controller _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())); + var athletes = await _userService.GetUsersTiny(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); return Ok(pageResponse); } catch (Exception e) @@ -74,21 +77,21 @@ public class UsersController : Controller /// Aucun utilisateur trouvé pour l'identifiant spécifié. /// Erreur interne du serveur. [HttpGet("{id}")] - [ProducesResponseType(typeof(UserDto), 200)] + [ProducesResponseType(typeof(ResponseUserDto), 200)] [ProducesResponseType(404)] [ProducesResponseType(500)] - public async Task> GetById([Range(0,int.MaxValue)]int id) + public async Task> GetById([Range(0,int.MaxValue)]int id) { try { _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetById), id); - var athlete = await _userService.GetItemById(id); + var athlete = await _userService.GetUserById(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()); + return Ok(athlete); } catch (Exception e) { @@ -110,7 +113,7 @@ public class UsersController : Controller { try { - _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(Count), null); + _logger.LogInformation("Executing {Action}", nameof(Count)); var nbUsers = await _userService.GetNbItems(); return Ok(nbUsers); } @@ -131,27 +134,27 @@ public class UsersController : Controller /// Utilisateur non trouvé. /// Erreur interne du serveur. [HttpPut("{id}")] - [ProducesResponseType(typeof(UserDto), 200)] + [ProducesResponseType(typeof(UserTinyDto), 200)] [ProducesResponseType(404)] [ProducesResponseType(500)] - public async Task> Update(int id, [FromBody] UserDto user) + public async Task> Update(int id, [FromBody] UserTinyDto user) { try { _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(Update), user,id); - var athlete = await _userService.GetItemById(id); + var athlete = await _userService.GetUserById(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()); + var updatedAthlete = await _userService.UpdateUser(id, user); if(updatedAthlete == null) { _logger.LogError("Error while updating athlete with id {id}", id); return Problem(); } - return Ok(updatedAthlete.ToDto()); + return Ok(updatedAthlete); } catch (Exception e) @@ -178,9 +181,8 @@ public class UsersController : Controller try { _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(Delete), null,id); - - - var athlete = await _userService.GetItemById(id); + + var athlete = await _userService.GetUserById(id); if (athlete == null) { _logger.LogError("Athlete with id {id} not found", id); @@ -211,31 +213,30 @@ public class UsersController : Controller /// Utilisateur non trouvé. /// Erreur interne du serveur. [HttpGet("{id}/friends")] - [ProducesResponseType(typeof(PageResponse), 200)] + [ProducesResponseType(typeof(PageResponse), 200)] [ProducesResponseType(404)] [ProducesResponseType(500)] - public async Task>> GetFriends(int id, [FromQuery] PageRequest request) + public async Task>> GetFriends(int id, [FromQuery] PageRequest request) { try { _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(GetFriends), 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 totalCount = await _userService.GetNbFriends(athlete); + var totalCount = await _userService.GetNbFriends(id); 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); } - var friends = await _userService.GetFriends(athlete, request.Index, request.Count, Enum.TryParse(request.OrderingPropertyName, out AthleteOrderCriteria result) ? result : AthleteOrderCriteria.None, request.Descending ?? false); + var friends = await _userService.GetFriends(id, request.Index, request.Count, Enum.TryParse(request.OrderingPropertyName, out AthleteOrderCriteria result) ? result : AthleteOrderCriteria.None, request.Descending ?? false); if (friends == null) return NotFound(); - var pageResponse = new PageResponse(request.Index, request.Count, totalCount, friends.Select(a => a.ToDto())); + var pageResponse = new PageResponse(request.Index, request.Count, totalCount, friends); return Ok(pageResponse); } + catch(ModelNotFoundException e) + { + _logger.LogError(e, "Error while adding a friend to an athlete"); + return BadRequest(e.Message); + } catch (Exception e) { _logger.LogError(e, "Error while getting the number of users"); @@ -256,24 +257,13 @@ public class UsersController : Controller [ProducesResponseType(200)] [ProducesResponseType(404)] [ProducesResponseType(500)] - public async Task AddFriend(int id, int friendId) + public async Task AddFollowing(int id, int friendId) { try { - _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(AddFriend), friendId,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 friend = await _userService.GetItemById(friendId); - if (friend == null) - { - _logger.LogError("Athlete with id {id} not found", friendId); - return NotFound($"Athlete with id {friendId} not found"); - } - var isAdded = await _userService.AddFriend(athlete, friend); + _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(AddFollowing), friendId,id); + + var isAdded = await _userService.AddFollowing(id, friendId); if(!isAdded) { _logger.LogError("Error while adding friend with id {friendId} to athlete with id {id}", friendId, id); @@ -281,9 +271,14 @@ public class UsersController : Controller } return Ok(); } + catch(FriendShipException e) + { + _logger.LogError(e, "Error while adding a friend to an athlete"); + return BadRequest(e.Message); + } catch (Exception e) { - _logger.LogError(e, "Error while getting the number of users"); + _logger.LogError(e, "Error while attempting to follow a user"); return Problem(); } } @@ -307,19 +302,8 @@ public class UsersController : Controller try { _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(RemoveFriend), friendId,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 friend = await _userService.GetItemById(friendId); - if (friend == null) - { - _logger.LogError("Athlete with id {id} not found", friendId); - return NotFound($"Athlete with id {friendId} not found"); - } - var isRemoved = await _userService.RemoveFriend(athlete, friend); + + var isRemoved = await _userService.RemoveFollowing(id, friendId); if(!isRemoved) { _logger.LogError("Error while removing friend with id {friendId} to athlete with id {id}", friendId, id); @@ -327,55 +311,19 @@ public class UsersController : Controller } return Ok(); } - catch (Exception e) - { - _logger.LogError(e, "Error while getting the number of users"); - return Problem(); - } - } - - /// - /// Obtient la liste des athlètes d'un coach spécifique. - /// - /// L'identifiant du coach. - /// Les critères de pagination et de tri. - /// La liste paginée des athlètes. - /// Retourne la liste paginée des athlètes du coach. - /// Coach non trouvé. - /// Erreur interne du serveur. - [HttpGet("{coachId}/athletes")] - [ProducesResponseType(typeof(PageResponse), 200)] - [ProducesResponseType(404)] - [ProducesResponseType(500)] - public async Task>> GetAthletes(int coachId, [FromQuery] PageRequest request) - { - try + catch(FriendShipException e) { - _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(GetAthletes), null,coachId); - var coach = await _userService.GetItemById(coachId); - if (coach == null) - { - _logger.LogError("Athlete with id {id} not found", coachId); - return NotFound($"Athlete with id {coachId} not found"); - } - var totalCount = await _userService.GetNbFriends(coach); - 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); - } - var athletes = await _userService.GetFriends(coach, request.Index, request.Count, Enum.TryParse(request.OrderingPropertyName, out AthleteOrderCriteria result) ? result : AthleteOrderCriteria.None, request.Descending ?? false); - if (athletes == null) return NotFound(); - var pageResponse = new PageResponse(request.Index, request.Count, totalCount, athletes.Select(a => a.ToDto())); - return Ok(pageResponse); + _logger.LogError(e, "Error while removing a friend to an athlete"); + return BadRequest(e.Message); } catch (Exception e) { - _logger.LogError(e, "Error while getting the number of users"); + _logger.LogError(e, "Error while attempting to unfollow a user"); return Problem(); } } - + + /* /// /// Obtient la liste des activités d'un utilisateur spécifique. /// @@ -387,7 +335,7 @@ public class UsersController : Controller /// Erreur interne du serveur. [HttpGet("{userId}/activities")] // should be tiny DTOActivity returned with only the necessary information (will be used in the list of activities of a user) - public async Task>> GetActivitiesByUser(int userId, [FromQuery] PageRequest pageRequest) + public async Task>> GetActivitiesByUser(int userId, [FromQuery] PageRequest pageRequest) { try { @@ -403,7 +351,7 @@ public class UsersController : Controller { return NotFound("No activities found"); } - 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) @@ -411,7 +359,7 @@ public class UsersController : Controller _logger.LogError(e, "Error while getting all activities"); return Problem(); } - } + }*/ /// /// Déconnecte l'utilisateur actuel. diff --git a/src/Model/Repository/IActivityRepository.cs b/src/Model/Repository/IActivityRepository.cs index eab97da..84c2225 100644 --- a/src/Model/Repository/IActivityRepository.cs +++ b/src/Model/Repository/IActivityRepository.cs @@ -1,13 +1,17 @@ +using Dto; +using Dto.Tiny; using Shared; namespace Model.Repository; public interface IActivityRepository { - public Task?> GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending = false); + 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 AddActivity(NewActivityDto activity); + + public Task UpdateActivity(int id, ActivityTinyDto activity); public Task DeleteActivity(int id); public Task GetNbItems(); public Task?> GetActivitiesByUser(int userId, int index, int count, ActivityOrderCriteria orderCriteria, bool descending= false); diff --git a/src/Model/Repository/IUserRepository.cs b/src/Model/Repository/IUserRepository.cs index dddc19d..a4d3c1a 100644 --- a/src/Model/Repository/IUserRepository.cs +++ b/src/Model/Repository/IUserRepository.cs @@ -1,14 +1,22 @@ -using Shared; +using Dto; +using Dto.Tiny; +using Shared; namespace Model.Repository; -public interface IUserRepository : IGenericRepository +public interface IUserRepository : IGenericRepository // Make it generic { + // [TODO] [Dave] DELETE it use just in the test public Task?> GetUsers(int index, int count, AthleteOrderCriteria? criteria , bool descending = false); - public Task AddFriend(User user, User friend); - public Task RemoveFriend(User user, User friend); - public Task?> GetFriends(User user, int index, int count, AthleteOrderCriteria? criteria, bool descending = false); - public Task GetNbFriends(User user); + public Task?> GetUsersTiny(int index, int count, AthleteOrderCriteria? criteria , bool descending = false); + public Task AddFollowing(int fromUser, int toUser); + public Task RemoveFollowing(int fromUser, int toUser); + + // DELETE + public Task?> GetFriends(int user, int index, int count, AthleteOrderCriteria? criteria, bool descending = false); + public Task GetNbFriends(int user); + public Task UpdateUser(int old,UserTinyDto user); + public Task GetUserById(int id); public Task?> GetAllAthletes(int index, int count, AthleteOrderCriteria? criteria, bool descending = false); public Task?> GetAllCoaches(int index, int count, AthleteOrderCriteria? criteria, bool descending = false); diff --git a/src/Model2Entities/ActivityRepository.cs b/src/Model2Entities/ActivityRepository.cs index d3ba2da..468e334 100644 --- a/src/Model2Entities/ActivityRepository.cs +++ b/src/Model2Entities/ActivityRepository.cs @@ -1,3 +1,5 @@ +using Dto; +using Dto.Tiny; using Model; using Model.Repository; using Shared; @@ -5,6 +7,7 @@ using Model.Manager; using Microsoft.Extensions.Logging; using Entities; using EFMappers; +using Entities2Dto; using Microsoft.EntityFrameworkCore; namespace Model2Entities; @@ -21,13 +24,13 @@ public partial class DbDataManager : IDataManager this._logger = logger; } - public async Task> GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending = false) + public async Task?> GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending = false) { _logger.LogInformation($"GetActivities with index {index} and count {count}", index, count); _logger.LogInformation($"GetActivities with criteria {criteria} and descending {descending}", criteria, descending); var activities = _dataManager.DbContext.ActivitiesSet - .IncludeStandardProperties().GetItemsWithFilterAndOrdering(b => true, index, count, criteria, descending).ToModels(); + .GetItemsWithFilterAndOrdering(b => true, index, count, criteria, descending).ToTinyDtos(); _logger.LogInformation($"Retrieved {activities.Count()} activities"); return await Task.FromResult(activities); @@ -67,18 +70,46 @@ public partial class DbDataManager : IDataManager } } - public async Task UpdateActivity(int id, Activity activity) + public async Task AddActivity(NewActivityDto activity) { try { - _logger.LogInformation($"Updating activity with ID {id}"); - var updatedActivity = await _dataManager.DbContext.UpdateItem(id, activity, (activity, entity) => + _logger.LogInformation("Adding new activity"); + + var addedActivity = activity.Activity.ToEntity(); + addedActivity.DataSourceId = activity.DataSourceId; + addedActivity.AthleteId = activity.AthleteId; + addedActivity.HeartRates = activity.HeartRates.ToEntities().ToList(); + + await _dataManager.DbContext.AddItem(addedActivity); + _logger.LogInformation($"Added activity with ID {addedActivity.IdActivity}"); + _dataManager.DbContext.SaveChanges(); + + return await Task.FromResult(addedActivity.ToResponseDto()); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occurred while adding activity"); + throw; + } + } + + public async Task UpdateActivity(int id, ActivityTinyDto activity) + { + try + { + var entity =await _dataManager.DbContext.ActivitiesSet.IncludeAll(_dataManager.DbContext) + .FirstOrDefaultAsync(a => a.IdActivity == id); + + if (entity != null) { + + _logger.LogInformation($"Updating activity with ID {id}"); entity.Type = activity.Type; entity.Date = DateOnly.FromDateTime(activity.Date); entity.StartTime = TimeOnly.FromDateTime(activity.StartTime); entity.EndTime = TimeOnly.FromDateTime(activity.EndTime); - entity.EffortFelt = activity.Effort; + entity.EffortFelt = activity.EffortFelt; entity.Variability = activity.Variability; entity.Variance = activity.Variance; entity.StandardDeviation = activity.StandardDeviation; @@ -87,16 +118,15 @@ public partial class DbDataManager : IDataManager entity.Minimum = activity.Minimum; entity.AverageTemperature = activity.AverageTemperature; entity.HasAutoPause = activity.HasAutoPause; - }); - if (updatedActivity != null) - { + _dataManager.DbContext.SaveChanges(); + _logger.LogInformation($"Updated activity with ID {id}"); - return await Task.FromResult(updatedActivity.ToModel()); + return await Task.FromResult(entity.ToResponseDto()); } else { _logger.LogError($"Failed to update activity with ID {id}"); - return await Task.FromResult(null); + return await Task.FromResult(null); } } catch (Exception ex) diff --git a/src/Model2Entities/Extension.cs b/src/Model2Entities/Extension.cs index d7341ec..9d2bcf4 100644 --- a/src/Model2Entities/Extension.cs +++ b/src/Model2Entities/Extension.cs @@ -40,13 +40,10 @@ public static class Extensions var existingT = await context.Set().FindAsync(id); if (existingT != null && newItem != null) { - // Appliquer les mises à jour sur l'objet existant en utilisant l'action passée en paramètre updateAction(newItem, existingT); - // Marquer l'objet comme modifié dans le contexte context.Update(existingT); - - // Enregistrer les modifications dans la base de données + await context.SaveChangesAsync(); return existingT; } @@ -84,7 +81,7 @@ public static class Extensions return descending ? list.OrderByDescending(x => propertyInfo.GetValue(x)) : list.OrderBy(x => propertyInfo.GetValue(x)); } - public static IQueryable IncludeAll(this HeartTrackContext dbContext, IQueryable query) where TEntity : class + public static IQueryable IncludeAll(this IQueryable query, HeartTrackContext dbContext) where TEntity : class { var entityType = dbContext.Model.FindEntityType(typeof(TEntity)); foreach (var navigation in entityType.GetNavigations()) diff --git a/src/Model2Entities/Model2Entities.csproj b/src/Model2Entities/Model2Entities.csproj index d1f7751..24879a9 100644 --- a/src/Model2Entities/Model2Entities.csproj +++ b/src/Model2Entities/Model2Entities.csproj @@ -8,6 +8,7 @@ + diff --git a/src/Model2Entities/UserRepository.cs b/src/Model2Entities/UserRepository.cs index 09d2cf2..264da22 100644 --- a/src/Model2Entities/UserRepository.cs +++ b/src/Model2Entities/UserRepository.cs @@ -1,9 +1,12 @@ +using Dto; +using Dto.Tiny; using Microsoft.Extensions.Logging; using Model; using Model.Repository; using Shared; using EFMappers; using Entities; +using Entities2Dto; using Microsoft.EntityFrameworkCore; namespace Model2Entities; @@ -39,6 +42,16 @@ public partial class DbDataManager } + public async Task?> GetUsersTiny(int index, int count, AthleteOrderCriteria? criteria, bool descending = false) + { + + var users = _dataManager.DbContext.AthletesSet.GetItemsWithFilterAndOrdering(b => true, + index, count, + criteria != AthleteOrderCriteria.None ? criteria : null, descending); + _logger.LogInformation($"Retrieved {users.Count()} users"); + return await Task.FromResult(users.ToTinyDtos()); + } + public async Task GetItemById(int id) { @@ -54,6 +67,43 @@ public partial class DbDataManager } + public async Task UpdateUser(int old, UserTinyDto user) + { + _logger.LogInformation($"UpdateUser with id {old}", old); + var originalEntity = _dataManager.DbContext.AthletesSet.Find(old); + if (originalEntity == null) + { + _logger.LogWarning($"No user found with ID {old}"); + return await Task.FromResult(null); + } + var originalEntry = _dataManager.DbContext.Entry(originalEntity); + var values = typeof(AthleteEntity).GetProperties().Where(ppty => ppty.Name != "IdAthlete") + .ToDictionary(ppty => ppty.Name, ppty => ppty.GetValue(user.ToEntity())); + originalEntry.CurrentValues.SetValues(values); + _dataManager.DbContext.AthletesSet.Attach(originalEntity); + _dataManager.DbContext.Entry(originalEntity).State = EntityState.Modified; + _dataManager.DbContext.SaveChanges(); + var updatedUser = originalEntity.ToTinyDto(); + if (updatedUser != null) + _logger.LogInformation($"Updated user with ID {old}"); + else + _logger.LogWarning($"No user found with ID {old}"); + return await Task.FromResult(updatedUser); + } + + public async Task GetUserById(int id) + { + _logger.LogInformation($"GetTinyItemById with id {id}", id); + var userEntity = await _dataManager.DbContext.AthletesSet.IncludeStandardProperties().Include(a => a.Followers).Include(a => a.Followings) + .SingleOrDefaultAsync(a => a.IdAthlete == id); + var user = userEntity != null ? userEntity.ToResponseDto() : null; + if (user != null) + _logger.LogInformation($"Retrieved user with ID {id}"); + else + _logger.LogWarning($"No user found with ID {id}"); + return user; + } + public async Task UpdateItem(int oldItem, User newItem) { _logger.LogInformation($"UpdateItem with id {oldItem}", oldItem); @@ -107,7 +157,6 @@ public partial class DbDataManager public async Task GetNbItems() { - _logger.LogInformation("GetNbItems"); var nbItems = await _dataManager.DbContext.AthletesSet.CountAsync(); _logger.LogInformation($"Retrieved {nbItems} users"); @@ -142,85 +191,136 @@ public partial class DbDataManager return await Task.FromResult(coaches); } + - public async Task AddFriend(User user, User friend) + public async Task AddFollowing(int fromUser, int toUser) { - _logger.LogInformation($"Attempting to add friend: User {user.Id} adding Friend {friend.Id}"); - var userEntity = _dataManager.DbContext.AthletesSet.IncludeStandardProperties().FirstOrDefault(a => a.IdAthlete == user.Id); - var friendEntity = _dataManager.DbContext.AthletesSet.IncludeStandardProperties().FirstOrDefault(a => a.IdAthlete == friend.Id); - if (userEntity == null || friendEntity == null) + _logger.LogInformation($"Attempting to add following: User {fromUser} adding Following {toUser}"); + + var userEntity = _dataManager.DbContext.AthletesSet + .Include(a => a.Followings) + .FirstOrDefault(a => a.IdAthlete == fromUser); + + if (userEntity == null) { - _logger.LogWarning($"User or friend not found: User {user.Id}, Friend {friend.Id}"); - return false; + _logger.LogWarning($"User not found: User {fromUser}"); + throw new FriendShipException("User with id " + fromUser + " not found"); } - if (userEntity.Followings.All(f => f.FollowingId != friend.Id)) + if (userEntity.Followings.Any(f => f.FollowingId == toUser)) { - userEntity.Followings.Add(new FriendshipEntity - { FollowingId = friend.Id, FollowerId = user.Id, StartDate = DateTime.Now }); - await _dataManager.DbContext.SaveChangesAsync(); - _logger.LogInformation($"Successfully added friend: User {user.Id} added Friend {friend.Id}"); - return true; + _logger.LogInformation($"Following already exists: User {fromUser} and Following {toUser}"); + throw new FriendShipException("Following already exists"); } + await _dataManager.DbContext.SaveChangesAsync(); - _logger.LogInformation($"Friendship already exists: User {user.Id} and Friend {friend.Id}"); - return false; + userEntity.Followings.Add(new FriendshipEntity + { + FollowingId = toUser, + FollowerId = fromUser, + StartDate = DateTime.Now + }); + + await _dataManager.DbContext.SaveChangesAsync(); + + _logger.LogInformation($"Successfully following: from User {fromUser} to Following {toUser}"); + return true; } + + public async Task RemoveFollowing(int fromUser, int toUser){ + _logger.LogInformation($"Attempting to remove following: User {fromUser} removing Following {toUser}"); - public async Task RemoveFriend(User user, User friend) - { - _logger.LogInformation($"Attempting to remove friend: User {user.Id} removing Friend {friend.Id}"); - var userEntity = _dataManager.DbContext.AthletesSet.IncludeStandardProperties().FirstOrDefault(a => a.IdAthlete == user.Id); - var friendEntity = _dataManager.DbContext.AthletesSet.IncludeStandardProperties().FirstOrDefault(a => a.IdAthlete == friend.Id); - if (userEntity == null || friendEntity == null) + var userEntity = _dataManager.DbContext.AthletesSet + .Include(a => a.Followings) + .FirstOrDefault(a => a.IdAthlete == fromUser); + + if (userEntity == null) { - _logger.LogWarning($"User or friend not found: User {user.Id}, Friend {friend.Id}"); - return false; + _logger.LogWarning($"User not found: User {fromUser}"); + throw new FriendShipException("User with id " + fromUser + " not found"); } - var friendship = userEntity.Followings.FirstOrDefault(f => f.FollowingId == friend.Id); - if (friendship != null) + var friendship = userEntity.Followings.FirstOrDefault(f => f.FollowingId == toUser); + if (friendship == null) { - userEntity.Followings.Remove(friendship); - await _dataManager.DbContext.SaveChangesAsync(); - _logger.LogInformation($"Successfully removed friend: User {user.Id} removed Friend {friend.Id}"); - return true; + _logger.LogInformation($"Following not found: User {fromUser} and Following {toUser}"); + throw new FriendShipException("Following not found"); } + await _dataManager.DbContext.SaveChangesAsync(); - _logger.LogInformation($"Friendship does not exist: User {user.Id} and Friend {friend.Id}"); - return false; - } + userEntity.Followings.Remove(friendship); - public Task> GetFriends(User user, int index, int count, AthleteOrderCriteria? criteria, + await _dataManager.DbContext.SaveChangesAsync(); + + _logger.LogInformation($"Successfully removed following: from User {fromUser} to Following {toUser}"); + return await Task.FromResult(true); + } + public async Task?> GetFriends(int userId, int index, int count, AthleteOrderCriteria? criteria, bool descending = false) { try { - _logger.LogInformation($"GetFriends with index {index} and count {count}", index, count); - _logger.LogInformation($"GetFriends with criteria {criteria} and descending {descending}", criteria, - descending); - var friends = _dataManager.DbContext.AthletesSet.IncludeStandardProperties().Include(a => a.Followers).Include(a => a.Followings) - .GetItemsWithFilterAndOrdering(a => a.Followers.Any(f => f.FollowingId == user.Id), index, count, - criteria, descending).ToModels(); - _logger.LogInformation($"Retrieved {friends.Count()} friends"); - return Task.FromResult(friends); + _logger.LogInformation($"GetFriends called with index {index}, count {count}, criteria {criteria}, and descending {descending}"); + + var athlete = await _dataManager.DbContext.AthletesSet + .Include(a => a.Followers).ThenInclude(f => f.Follower) + .Include(a => a.Followings).ThenInclude(f => f.Following) + .FirstOrDefaultAsync(a => a.IdAthlete == userId); // Use async version for better performance + + if (athlete == null) + { + _logger.LogError("Athlete with id {id} not found", userId); + throw new ModelNotFoundException($"Athlete with id {userId} not found"); + } + + var friendsDtos = athlete.Followings + .Where(f => athlete.Followers.Any(ff => ff.FollowerId == f.FollowingId)) + .Select(f => f.Following).GetItemsWithFilterAndOrdering(a => true, index, count, + criteria != AthleteOrderCriteria.None ? criteria : null, descending).ToTinyDtos(); + + var userTinyDtos = friendsDtos.ToArray(); + _logger.LogInformation($"Retrieved {userTinyDtos.Count()} friends for user {userId}"); + + return userTinyDtos; } catch (Exception ex) { _logger.LogError(ex.Message, ex.InnerException, ex.StackTrace); - return Task.FromResult>(new List()); + return null; } } - public Task GetNbFriends(User user) + public async Task GetNbFriends(int userId) { - - _logger.LogInformation($"GetNbFriends with user {user}", user); - var nbFriends = _dataManager.DbContext.AthletesSet - .GetItemsWithFilterAndOrdering(a => a.IdAthlete == user.Id, 0, int.MaxValue, - AthleteOrderCriteria.None, false).First().Followings.Count(); - _logger.LogInformation($"Retrieved {nbFriends} friends"); - return Task.FromResult(nbFriends); + try + { + _logger.LogInformation($"GetNbFriends called for user {userId}"); + + var athlete = await _dataManager.DbContext.AthletesSet + .Include(a => a.Followers).ThenInclude(f => f.Follower) + .Include(a => a.Followings).ThenInclude(f => f.Following) + .FirstOrDefaultAsync(a => a.IdAthlete == userId); + + if (athlete == null) + { + _logger.LogError("Athlete with id {id} not found", userId); + throw new ModelNotFoundException($"Athlete with id {userId} not found"); + } + + // Count the number of mutual friendships + var nbFriends = athlete.Followings + .Count(f => athlete.Followers.Any(ff => ff.FollowerId == f.FollowingId)); + + _logger.LogInformation($"User {userId} has {nbFriends} friends"); + + return nbFriends; + } + catch (Exception ex) + { + _logger.LogError(ex, "An error occurred while counting friends for user {UserId}", userId); + throw; // Consider handling the exception outside of this method or logging it accordingly. + } } + } } \ No newline at end of file diff --git a/src/Shared/AthleteOrderCriteria.cs b/src/Shared/AthleteOrderCriteria.cs index 4bc54f0..aad08e4 100644 --- a/src/Shared/AthleteOrderCriteria.cs +++ b/src/Shared/AthleteOrderCriteria.cs @@ -15,31 +15,3 @@ } } - - -/*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/Extension.cs b/src/Shared/Extension.cs index d86ba4d..35a832c 100644 --- a/src/Shared/Extension.cs +++ b/src/Shared/Extension.cs @@ -2,25 +2,25 @@ namespace Shared; public static class Extensions { - public static U ToU(this T t, GenericMapper mapper, Func func,Action? action = null) where U :class where T :class + public static U ToU(this T t, GenericMapper mapper, Func func,Action? action = null,bool useMapper = true) where U :class where T :class { var res = mapper.GetU(t); if (res != null) return res; U u = func(t); - mapper.Add(t, u); + if(useMapper) mapper.Add(t, u); if(action != null) action(t, u); return u; } // , Action action - public static T ToT(this U u, GenericMapper mapper, Func func,Action? action = null) where U :class where T :class + public static T ToT(this U u, GenericMapper mapper, Func func,Action? action = null,bool useMapper = true) where U :class where T :class { var result = mapper.GetT(u); if(result != null) return result; T t = func(u); - mapper.Add(t, u); + if(useMapper) mapper.Add(t, u); if(action != null) action(u, t); return t; diff --git a/src/Shared/ModelException.cs b/src/Shared/ModelException.cs new file mode 100644 index 0000000..4b074f0 --- /dev/null +++ b/src/Shared/ModelException.cs @@ -0,0 +1,15 @@ +namespace Shared; + +public class FriendShipException : ModelNotFoundException +{ + public FriendShipException(string message) : base(message) + { + } +} + +public class ModelNotFoundException : Exception +{ + public ModelNotFoundException(string message) : base(message) + { + } +} diff --git a/src/StubAPI/ActivityService.cs b/src/StubAPI/ActivityService.cs index fe08608..330a3f1 100644 --- a/src/StubAPI/ActivityService.cs +++ b/src/StubAPI/ActivityService.cs @@ -1,3 +1,5 @@ +using Dto; +using Dto.Tiny; using Model; using Model.Repository; using Shared; @@ -6,17 +8,17 @@ namespace StubAPI; public class ActivityService: IActivityRepository { - private List _activities = new List( - new Activity[] + private List _activities = new List( + new ActivityTinyDto[] { - new Activity + new ActivityTinyDto { Id = 1, Type = "Running", Date = new DateTime(2021, 10, 10), StartTime = new DateTime(2021, 10, 10, 10, 0, 0), EndTime = new DateTime(2021, 10, 10, 11, 0, 0), - Effort = 3, + EffortFelt = 3, Variability = 0.5f, Variance = 0.5f, StandardDeviation = 0.5f, @@ -25,33 +27,41 @@ public class ActivityService: IActivityRepository Minimum = 0, AverageTemperature = 20.0f, HasAutoPause = false, - Athlete = 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?> GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending = false) - => await Task.FromResult(_activities.GetItemsWithFilterAndOrdering(c=>true,index, count,criteria != ActivityOrderCriteria.None ? criteria: null , descending)); + public async Task?> GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending = false) + => await Task.FromResult(_activities.GetItemsWithFilterAndOrdering(a => true, index, count, criteria, descending)); public Task GetActivityByIdAsync(int id) { - return Task.FromResult(_activities.FirstOrDefault(s => s.Id == id)); + throw new NotImplementedException(); + // return Task.FromResult(_activities.FirstOrDefault(s => s.Id == id)?.ToModel()); } public Task AddActivity(Activity activity) - => _activities.AddItem(activity); - + => throw new NotImplementedException(); + + + public async Task AddActivity(NewActivityDto activity) + { + throw new NotImplementedException(); + } + + public async Task UpdateActivity(int id, ActivityTinyDto activity) + { + throw new NotImplementedException(); + } + public async Task UpdateActivity(int id, Activity activity) { - var oldActivity = _activities.FirstOrDefault(s => s.Id == id); + throw new NotImplementedException(); + + /*var oldActivity = _activities.FirstOrDefault(s => s.Id == id); if (oldActivity == null) return null; - return await _activities.UpdateItem(oldActivity, activity); + return await _activities.UpdateItem(oldActivity, activity);*/ } public Task DeleteActivity(int id) @@ -66,13 +76,16 @@ public class ActivityService: IActivityRepository public async Task?> GetActivitiesByUser(int userId, int index, int count, ActivityOrderCriteria criteria, bool descending = false) { - var activities = _activities.GetItemsWithFilterAndOrdering(a => a.Athlete.Id == userId, index, count, + throw new NotImplementedException(); + + /* var activities = _activities.GetItemsWithFilterAndOrdering(a => a.Athlete.Id == userId, index, count, criteria != ActivityOrderCriteria.None ? criteria : null, descending); - return await Task.FromResult(activities); + return await Task.FromResult(activities);*/ } public Task GetNbActivitiesByUser(int userId) { - return Task.FromResult(_activities.Count(a => a.Athlete.Id == userId)); + throw new NotImplementedException(); + // return Task.FromResult(_activities.Count(a => a.Athlete.Id == userId)); } } \ No newline at end of file diff --git a/src/StubAPI/AthleteService.cs b/src/StubAPI/AthleteService.cs index 4d8bf29..d51a7c7 100644 --- a/src/StubAPI/AthleteService.cs +++ b/src/StubAPI/AthleteService.cs @@ -1,4 +1,6 @@ -using Model; +using Dto; +using Dto.Tiny; +using Model; using Model.Repository; using Shared; @@ -34,6 +36,26 @@ public class UserService : IUserRepository 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?> GetUsersTiny(int index, int count, AthleteOrderCriteria? criteria, bool descending = false) + { + throw new NotImplementedException(); + } + + public async Task AddFollowing(int fromUser, int toUser) + { + throw new NotImplementedException(); + } + + public async Task RemoveFollowing(int fromUser, int toUser) + { + throw new NotImplementedException(); + } + + public async Task?> GetFriends(int user, int index, int count, AthleteOrderCriteria? criteria, bool descending = false) + { + throw new NotImplementedException(); + } + public async Task AddFriend(User user, User friend) { if (user == null || friend == null) @@ -71,9 +93,19 @@ public class UserService : IUserRepository public async Task?>? GetFriends(User user, int index, int count, AthleteOrderCriteria? criteria, bool descending = false) =>await Task.FromResult(athletes.FirstOrDefault(s => s.Id == user.Id)?.Users.GetItemsWithFilterAndOrdering(c=>true,index, count,criteria, descending)); - public Task GetNbFriends(User user) + public Task GetNbFriends(int user) + { + return Task.FromResult(athletes.FirstOrDefault(s => s.Id == user)?.Users.Count ?? 0); + } + + public async Task UpdateUser(int old, UserTinyDto user) + { + throw new NotImplementedException(); + } + + public async Task GetUserById(int id) { - return Task.FromResult(athletes.FirstOrDefault(s => s.Id == user.Id)?.Users.Count ?? 0); + throw new NotImplementedException(); } public async Task> GetItems(int index, int count, string? orderingProperty = null, diff --git a/src/StubAPI/StubAPI.csproj b/src/StubAPI/StubAPI.csproj index eea9fb7..85860b7 100644 --- a/src/StubAPI/StubAPI.csproj +++ b/src/StubAPI/StubAPI.csproj @@ -7,6 +7,7 @@ + diff --git a/src/StubbedContextLib/AthleteStubbedContext.cs b/src/StubbedContextLib/AthleteStubbedContext.cs index f45140f..3b69133 100644 --- a/src/StubbedContextLib/AthleteStubbedContext.cs +++ b/src/StubbedContextLib/AthleteStubbedContext.cs @@ -43,7 +43,7 @@ namespace StubbedContextLib modelBuilder.Entity().HasData( new AthleteEntity { IdAthlete = 1, Username = "Doe",ProfilPicture = picture2, ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}") ,LastName = "Doe", FirstName = "John", Email = "john.doe@example.com", Password = "password123", Sexe = "M", Length = 1.80, Weight = 75, DateOfBirth = new DateOnly(1990, 01, 01), IsCoach = true , DataSourceId = 1}, - new AthleteEntity { IdAthlete = 2, Username = "Smith",ProfilPicture = picture2,ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}") ,LastName = "Smith", FirstName = "Jane", Email = "jane.smith@exemple.com", Password = "secure456", Sexe = "F", Length = 1.65, Weight = 60, DateOfBirth = new DateOnly(1995, 01, 01), IsCoach = false, DataSourceId = 1 }, + new AthleteEntity { IdAthlete = 2, Username = "Smith",ProfilPicture = picture2,LastName = "Smith", FirstName = "Jane", Email = "jane.smith@exemple.com", Password = "secure456", Sexe = "F", Length = 1.65, Weight = 60, DateOfBirth = new DateOnly(1995, 01, 01), IsCoach = false, DataSourceId = 1 }, new AthleteEntity { IdAthlete = 3, Username = "Martin",ProfilPicture = picture2,ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}") ,LastName = "Martin", FirstName = "Paul", Email = "paul.martin@example.com", Password = "super789", Sexe = "M", Length = 1.75, Weight = 68, DateOfBirth = new DateOnly(1992, 01, 01), IsCoach = true, DataSourceId = 1}, new AthleteEntity { IdAthlete = 4, Username = "Brown",ProfilPicture = picture2, ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}"),LastName = "Brown", FirstName = "Anna", Email = "anna.brown@example.com", Password = "test000", Sexe = "F", Length = 1.70, Weight = 58, DateOfBirth = new DateOnly(1993, 01, 01), IsCoach = false, DataSourceId = 2 }, new AthleteEntity { IdAthlete = 5, Username = "Lee", ProfilPicture = picture2, ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}"),LastName = "Lee", FirstName = "Bruce", Email = "bruce.lee@example.com", Password = "hello321", Sexe = "M", Length = 2.0, Weight = 90, DateOfBirth = new DateOnly(1991, 01, 01), IsCoach = false, DataSourceId = 3 } diff --git a/src/StubbedContextLib/FriendshipStubbedContext.cs b/src/StubbedContextLib/FriendshipStubbedContext.cs index 70eb76f..5631ca1 100644 --- a/src/StubbedContextLib/FriendshipStubbedContext.cs +++ b/src/StubbedContextLib/FriendshipStubbedContext.cs @@ -39,10 +39,7 @@ namespace StubbedContextLib modelBuilder.Entity().HasData( new FriendshipEntity { FollowerId = 1, FollowingId = 2 }, new FriendshipEntity { FollowerId = 1, FollowingId = 3 }, - new FriendshipEntity { FollowerId = 1, FollowingId = 4 }, - new FriendshipEntity { FollowerId = 1, FollowingId = 5 }, - new FriendshipEntity { FollowerId = 2, FollowingId = 1 }, - new FriendshipEntity { FollowerId = 2, FollowingId = 3 } + new FriendshipEntity { FollowerId = 3, FollowingId = 1 } ); } } diff --git a/src/Tests/ConsoleTestEFMapper/Program.cs b/src/Tests/ConsoleTestEFMapper/Program.cs index bc71893..5b3ca01 100644 --- a/src/Tests/ConsoleTestEFMapper/Program.cs +++ b/src/Tests/ConsoleTestEFMapper/Program.cs @@ -10,6 +10,7 @@ using static Model2Entities.DbDataManager; namespace Model2Entities { + /* static class Program { static async Task Main(string[] args) @@ -114,5 +115,5 @@ namespace Model2Entities } static void UsersTest() {} - } + }*/ } \ No newline at end of file diff --git a/src/Tests/TestsAPI/UnitTestApi/Controllers/UsersControllerTest.cs b/src/Tests/TestsAPI/UnitTestApi/Controllers/UsersControllerTest.cs index 0a5eb52..bff2e2d 100644 --- a/src/Tests/TestsAPI/UnitTestApi/Controllers/UsersControllerTest.cs +++ b/src/Tests/TestsAPI/UnitTestApi/Controllers/UsersControllerTest.cs @@ -74,14 +74,6 @@ public class UsersControllerTest _usersController = new UsersController(new NullLogger(), _dataManagerMock.Object); } -/* - [TestInitialize] - public void SetUp() - { - _dataManager = new StubData(); - _usersController = new UsersController(new NullLogger(), _dataManager); - }*/ - [TestMethod] public async Task Get_ReturnsPageResponse_WhenRequestIsValid() @@ -103,7 +95,7 @@ public class UsersControllerTest Assert.IsNotNull(okResult); Assert.IsInstanceOfType(okResult.Value, typeof(PageResponse)); var pageResponse = okResult.Value as PageResponse; - Assert.IsNotNull(pageResponse); + Assert.IsNotNull(pageResponse); Assert.AreEqual(3, pageResponse.Items.Count()); Assert.AreEqual(3, pageResponse.Total); Assert.AreEqual(0, pageResponse.Index); diff --git a/src/Tests/UnitTestsEntities/FriendshipEntityTests.cs b/src/Tests/UnitTestsEntities/FriendshipEntityTests.cs index 10cfc00..2a0db78 100644 --- a/src/Tests/UnitTestsEntities/FriendshipEntityTests.cs +++ b/src/Tests/UnitTestsEntities/FriendshipEntityTests.cs @@ -63,7 +63,7 @@ public class FriendshipEntityTests (DatabaseFixture fixture) : IClassFixture a.Followers).Include(a => a.Followings).FirstOrDefault(a => a.Username == "follower_user1").Followers.FirstOrDefault(f => f.FollowerId == follower.IdAthlete && f.FollowingId == following.IdAthlete); + var savedFriendship = context.AthletesSet.Include(a => a.Followers).Include(a => a.Followings).FirstOrDefault(a => a.Username == "follower_user1").Followings.FirstOrDefault(f => f.FollowerId == follower.IdAthlete && f.FollowingId == following.IdAthlete); Assert.NotNull(savedFriendship); if (savedFriendship != null) From 28418d3513e69c119f1a0987a83486bcd87f2ff2 Mon Sep 17 00:00:00 2001 From: dave Date: Mon, 18 Mar 2024 21:47:32 +0100 Subject: [PATCH 13/92] tempory ugly --- .../Controllers/UsersControllerTest.cs | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/Tests/TestsAPI/UnitTestApi/Controllers/UsersControllerTest.cs b/src/Tests/TestsAPI/UnitTestApi/Controllers/UsersControllerTest.cs index bff2e2d..3a9ce3a 100644 --- a/src/Tests/TestsAPI/UnitTestApi/Controllers/UsersControllerTest.cs +++ b/src/Tests/TestsAPI/UnitTestApi/Controllers/UsersControllerTest.cs @@ -1,5 +1,6 @@ using APIMappers; using Dto; +using Dto.Tiny; using HeartTrackAPI.Controllers; using HeartTrackAPI.Request; using HeartTrackAPI.Responce; @@ -74,7 +75,7 @@ public class UsersControllerTest _usersController = new UsersController(new NullLogger(), _dataManagerMock.Object); } - +/* [TestMethod] public async Task Get_ReturnsPageResponse_WhenRequestIsValid() { @@ -93,8 +94,8 @@ public class UsersControllerTest var okResult = result.Result as OkObjectResult; // Assert Assert.IsNotNull(okResult); - Assert.IsInstanceOfType(okResult.Value, typeof(PageResponse)); - var pageResponse = okResult.Value as PageResponse; + Assert.IsInstanceOfType(okResult.Value, typeof(PageResponse)); + var pageResponse = okResult.Value as PageResponse; Assert.IsNotNull(pageResponse); Assert.AreEqual(3, pageResponse.Items.Count()); Assert.AreEqual(3, pageResponse.Total); @@ -124,8 +125,8 @@ public class UsersControllerTest var okResult = result.Result as OkObjectResult; // Assert Assert.IsNotNull(okResult); - Assert.IsInstanceOfType(okResult.Value, typeof(PageResponse)); - var pageResponse = okResult.Value as PageResponse; + Assert.IsInstanceOfType(okResult.Value, typeof(PageResponse)); + var pageResponse = okResult.Value as PageResponse; Assert.IsNotNull(pageResponse); Assert.AreEqual(expectedItemCount, pageResponse.Items.Count()); } @@ -154,7 +155,10 @@ public class UsersControllerTest { var id = 1; - _dataManagerMock.Setup(dm => dm.UserRepo.GetItemById(id)).ReturnsAsync(_users.First(x => x.Id == id)); + _dataManagerMock.Setup(dm => dm.UserRepo.GetUserById(id)).ReturnsAsync(List() + { + + }); // Act var result = await _usersController.GetById(id) ; @@ -165,12 +169,12 @@ public class UsersControllerTest Assert.IsNotNull(okResult); var resultObject = result.Result as OkObjectResult; Assert.IsNotNull(resultObject); - Assert.IsInstanceOfType(resultObject.Value, typeof(UserDto)); - var user = resultObject.Value as UserDto; + Assert.IsInstanceOfType(resultObject.Value, typeof(ResponseUserDto)); + var user = resultObject.Value as ResponseUserDto; Assert.IsNotNull(user); var tmp = _users.First(x => x.Id == id).ToDto(); Assert.AreEqual(tmp.Id, user.Id); - } + }*/ [TestMethod] public async Task GetById_ReturnsUserDto_WhenRequestUserDoesNotExist() From 8aed0d790cb0b31f0db4e4ee79be53a7bb742fb9 Mon Sep 17 00:00:00 2001 From: dave Date: Mon, 18 Mar 2024 21:49:34 +0100 Subject: [PATCH 14/92] Entities2Dto add --- src/Entities2Dto/Entities2Dto.csproj | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/Entities2Dto/Entities2Dto.csproj diff --git a/src/Entities2Dto/Entities2Dto.csproj b/src/Entities2Dto/Entities2Dto.csproj new file mode 100644 index 0000000..e3d0baf --- /dev/null +++ b/src/Entities2Dto/Entities2Dto.csproj @@ -0,0 +1,14 @@ + + + + net8.0 + enable + enable + + + + + + + + From 209ded5c08a378c8d42501d34b3218c4c1ba1397 Mon Sep 17 00:00:00 2001 From: David D'ALMEIDA Date: Mon, 18 Mar 2024 21:52:35 +0100 Subject: [PATCH 15/92] =?UTF-8?q?Mise=20=C3=A0=20jour=20de=20'.drone.yml'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .drone.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.drone.yml b/.drone.yml index 5fa128c..339e9e8 100644 --- a/.drone.yml +++ b/.drone.yml @@ -2,11 +2,11 @@ kind: pipeline type: docker name: HeartTrack-API -trigger: - branch: - - master - event: - - push +#trigger: +# branch: +# - master +# event: +# - push steps: - name: build From ce99685034bc18124aae97bb8402949283edad30 Mon Sep 17 00:00:00 2001 From: dave Date: Mon, 18 Mar 2024 22:31:49 +0100 Subject: [PATCH 16/92] test to fix 404 --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index c629f5e..51e7e79 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -156,6 +156,7 @@ public class AppBootstrap(IConfiguration configuration) new List() } }; + options.AddSecurityRequirement(scheme); }); services.AddTransient, SwaggerOptions>(); @@ -187,10 +188,12 @@ public class AppBootstrap(IConfiguration configuration) { var apiVersionDescriptionProvider = app.Services.GetRequiredService(); app.UseSwagger(); - app.UseSwaggerUI(); + app.MapSwagger(); app.UseSwaggerUI(options => - { + { + if(Environment.GetEnvironmentVariable("TYPE") == "STUB") + options.RoutePrefix = "containers/HeartDev-heart_stub"; foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions) { options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", From 428e6c8565312decd25a56809a83f6f7367b2554 Mon Sep 17 00:00:00 2001 From: dave Date: Mon, 18 Mar 2024 23:00:26 +0100 Subject: [PATCH 17/92] test ci --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 51e7e79..48c7272 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -191,12 +191,10 @@ public class AppBootstrap(IConfiguration configuration) app.MapSwagger(); app.UseSwaggerUI(options => - { - if(Environment.GetEnvironmentVariable("TYPE") == "STUB") - options.RoutePrefix = "containers/HeartDev-heart_stub"; + { foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions) { - options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", + options.SwaggerEndpoint($"./swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant()); } }); From 39e4658c30e4827286e74ef5a81703b0e3bb0162 Mon Sep 17 00:00:00 2001 From: dave Date: Mon, 18 Mar 2024 23:07:57 +0100 Subject: [PATCH 18/92] no comprendo --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 48c7272..419fe44 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -196,6 +196,7 @@ public class AppBootstrap(IConfiguration configuration) { options.SwaggerEndpoint($"./swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant()); + options.RoutePrefix = string.Empty; } }); From e5eb1b64e0cd0ca00cf2b4200ad3bded698bb666 Mon Sep 17 00:00:00 2001 From: dave Date: Mon, 18 Mar 2024 23:11:54 +0100 Subject: [PATCH 19/92] maybe --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 419fe44..05cf606 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -194,7 +194,7 @@ public class AppBootstrap(IConfiguration configuration) { foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions) { - options.SwaggerEndpoint($"./swagger/{description.GroupName}/swagger.json", + options.SwaggerEndpoint($"/containers/HeartDev-heart_stub/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant()); options.RoutePrefix = string.Empty; } From 656ceb2f9eacd0dae8e76697d64548ef3061add2 Mon Sep 17 00:00:00 2001 From: dave Date: Mon, 18 Mar 2024 23:14:52 +0100 Subject: [PATCH 20/92] fuck --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 05cf606..0e57f42 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -188,15 +188,13 @@ public class AppBootstrap(IConfiguration configuration) { var apiVersionDescriptionProvider = app.Services.GetRequiredService(); app.UseSwagger(); - app.MapSwagger(); app.UseSwaggerUI(options => { foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions) { - options.SwaggerEndpoint($"/containers/HeartDev-heart_stub/swagger/{description.GroupName}/swagger.json", + options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant()); - options.RoutePrefix = string.Empty; } }); From 3ded27e17cc1c93beddd40719af11bf7d79b60b1 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 00:01:50 +0100 Subject: [PATCH 21/92] make it work --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 0e57f42..39f4458 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -82,9 +82,6 @@ public class AppBootstrap(IConfiguration configuration) case "BDD": services.AddSingleton(provider => new DbDataManager(provider.GetRequiredService())); break; - case "STUB": - services.AddSingleton(); - break; default: services.AddSingleton(provider => { From 9b1b416fa9664a8dbd0d855c6f12afa02dc4d166 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 00:07:43 +0100 Subject: [PATCH 22/92] ok --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 39f4458..858caed 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -82,6 +82,9 @@ public class AppBootstrap(IConfiguration configuration) case "BDD": services.AddSingleton(provider => new DbDataManager(provider.GetRequiredService())); break; + case "STUB-MODEL": + services.AddSingleton(); + break; default: services.AddSingleton(provider => { From 0f9911844099cd2c5a62cb26be70fd92f8e93f0b Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 00:13:02 +0100 Subject: [PATCH 23/92] test --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 858caed..b0211ff 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -59,6 +59,7 @@ public class AppBootstrap(IConfiguration configuration) default: Console.WriteLine("====== RUNNING USING THE IN SQLITE DATABASE ======"); connectionString = Configuration.GetConnectionString("HeartTrackAuthConnection"); + Console.WriteLine(connectionString); if (!string.IsNullOrWhiteSpace(connectionString)) { services.AddDbContext(options => options.UseInMemoryDatabase("AuthDb")); From c60eecfb11de25172947ab0cbcc9c1d5db1ea8a7 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 03:24:59 +0100 Subject: [PATCH 24/92] clean --- src/Tests/ConsoleTestEFMapper/Program.cs | 5 ++--- src/Tests/TestStubEF/Program.cs | 4 ++-- src/Tests/TestStubEF/TestStubEF.csproj | 20 ++++++++++---------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/Tests/ConsoleTestEFMapper/Program.cs b/src/Tests/ConsoleTestEFMapper/Program.cs index 5b3ca01..e5acca0 100644 --- a/src/Tests/ConsoleTestEFMapper/Program.cs +++ b/src/Tests/ConsoleTestEFMapper/Program.cs @@ -8,8 +8,8 @@ using Shared; using StubbedContextLib; using static Model2Entities.DbDataManager; -namespace Model2Entities -{ +namespace ConsoleTestEFMapper; + /* static class Program { @@ -116,4 +116,3 @@ namespace Model2Entities static void UsersTest() {} }*/ -} \ No newline at end of file diff --git a/src/Tests/TestStubEF/Program.cs b/src/Tests/TestStubEF/Program.cs index 83fa4f4..3751555 100644 --- a/src/Tests/TestStubEF/Program.cs +++ b/src/Tests/TestStubEF/Program.cs @@ -1,2 +1,2 @@ -// See https://aka.ms/new-console-template for more information -Console.WriteLine("Hello, World!"); +// See https://aka.ms/new-console-template for more information +Console.WriteLine("Hello, World!"); diff --git a/src/Tests/TestStubEF/TestStubEF.csproj b/src/Tests/TestStubEF/TestStubEF.csproj index 206b89a..2150e37 100644 --- a/src/Tests/TestStubEF/TestStubEF.csproj +++ b/src/Tests/TestStubEF/TestStubEF.csproj @@ -1,10 +1,10 @@ - - - - Exe - net8.0 - enable - enable - - - + + + + Exe + net8.0 + enable + enable + + + From 94b3f2054f79955e1b4037cab2e4f3b5300a7d3f Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 03:35:22 +0100 Subject: [PATCH 25/92] clean --- src/HeartTrack.sln | 14 +++---- src/Tests/ConsoleTestEFMapper/Program.cs | 14 +++---- .../TestsAPI/ClientTests/ClientTests.csproj | 10 ----- .../TestsAPI/ClientTests/HttpClientManager.cs | 12 ------ src/Tests/TestsAPI/ClientTests/Program.cs | 2 - .../WebAPIConsoleTests/ActivityServiceAPI.cs | 38 +++++++++++++------ src/Tests/WebAPIConsoleTests/Program.cs | 6 +-- 7 files changed, 43 insertions(+), 53 deletions(-) delete mode 100644 src/Tests/TestsAPI/ClientTests/ClientTests.csproj delete mode 100644 src/Tests/TestsAPI/ClientTests/HttpClientManager.cs delete mode 100644 src/Tests/TestsAPI/ClientTests/Program.cs diff --git a/src/HeartTrack.sln b/src/HeartTrack.sln index f9c60dd..31d8733 100644 --- a/src/HeartTrack.sln +++ b/src/HeartTrack.sln @@ -23,8 +23,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "Shared\Shared.csp EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestsAPI", "TestsAPI", "{30FC2BE9-7397-445A-84AD-043CE70F4281}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClientTests", "Tests\TestsAPI\ClientTests\ClientTests.csproj", "{9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model", "Model\Model.csproj", "{30AB7FAA-6072-40B6-A15E-9188B59144F9}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTestApi", "Tests\TestsAPI\UnitTestApi\UnitTestApi.csproj", "{E515C8B6-6282-4D8B-8523-7B3A13E4AF58}" @@ -87,10 +85,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 - {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 {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 @@ -127,6 +121,12 @@ Global {508D380F-145C-437E-A7DF-7A17C526B2F3}.Debug|Any CPU.Build.0 = Debug|Any CPU {508D380F-145C-437E-A7DF-7A17C526B2F3}.Release|Any CPU.ActiveCfg = Release|Any CPU {508D380F-145C-437E-A7DF-7A17C526B2F3}.Release|Any CPU.Build.0 = Release|Any CPU + {1B15D383-1DFA-47E8-86EC-AC631B15FBEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1B15D383-1DFA-47E8-86EC-AC631B15FBEB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {707B1AC4-F896-4270-BC2F-1A589F48979D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {707B1AC4-F896-4270-BC2F-1A589F48979D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D0EE112F-3151-4C28-A6EC-B1CEC7883FAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D0EE112F-3151-4C28-A6EC-B1CEC7883FAE}.Debug|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -135,11 +135,11 @@ Global {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} {E515C8B6-6282-4D8B-8523-7B3A13E4AF58} = {30FC2BE9-7397-445A-84AD-043CE70F4281} {31FA8E5E-D642-4C43-A2B2-02B9832B2CEC} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} {73EA27F2-9F0C-443F-A5EE-2960C983A422} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} {508D380F-145C-437E-A7DF-7A17C526B2F3} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} + {D0EE112F-3151-4C28-A6EC-B1CEC7883FAE} = {30FC2BE9-7397-445A-84AD-043CE70F4281} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {0F3487F4-66CA-4034-AC66-1BC899C9B523} diff --git a/src/Tests/ConsoleTestEFMapper/Program.cs b/src/Tests/ConsoleTestEFMapper/Program.cs index 5079527..c1fb1ff 100644 --- a/src/Tests/ConsoleTestEFMapper/Program.cs +++ b/src/Tests/ConsoleTestEFMapper/Program.cs @@ -10,19 +10,17 @@ using static Model2Entities.DbDataManager; namespace ConsoleTestEFMapper; - /* + static class Program { + static async Task Main(string[] args) { // Instanciation de DbDataManager et ActivityRepository - var dataManager = new DbDataManager(new TrainingStubbedContext()); - var logger = new Logger(new LoggerFactory()); - - // Test de la méthode GetActivities - await ActivitiesTestAsync(dataManager, logger); + Console.WriteLine(""); } + /* static async Task ActivitiesTestAsync(DbDataManager dataManager, ILogger logger) { var activityRepository = new ActivityRepository(dataManager, logger); @@ -114,5 +112,5 @@ namespace ConsoleTestEFMapper; Console.WriteLine($"Total number of activities: {itemCount}"); } static void UsersTest() - {} - }*/ + {}*/ + } diff --git a/src/Tests/TestsAPI/ClientTests/ClientTests.csproj b/src/Tests/TestsAPI/ClientTests/ClientTests.csproj deleted file mode 100644 index 206b89a..0000000 --- a/src/Tests/TestsAPI/ClientTests/ClientTests.csproj +++ /dev/null @@ -1,10 +0,0 @@ - - - - Exe - net8.0 - enable - enable - - - diff --git a/src/Tests/TestsAPI/ClientTests/HttpClientManager.cs b/src/Tests/TestsAPI/ClientTests/HttpClientManager.cs deleted file mode 100644 index 2e8e593..0000000 --- a/src/Tests/TestsAPI/ClientTests/HttpClientManager.cs +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 83fa4f4..0000000 --- a/src/Tests/TestsAPI/ClientTests/Program.cs +++ /dev/null @@ -1,2 +0,0 @@ -// See https://aka.ms/new-console-template for more information -Console.WriteLine("Hello, World!"); diff --git a/src/Tests/WebAPIConsoleTests/ActivityServiceAPI.cs b/src/Tests/WebAPIConsoleTests/ActivityServiceAPI.cs index 976808a..159805d 100644 --- a/src/Tests/WebAPIConsoleTests/ActivityServiceAPI.cs +++ b/src/Tests/WebAPIConsoleTests/ActivityServiceAPI.cs @@ -1,21 +1,22 @@ -/*! +/*/*! * \file BookDataServiceAPI.cs * \author HeartTeam * \brief Fichier contenant la classe BookDataServiceAPI. - */ + #1# using System.Diagnostics; using Dto; using Model.Repository; using Shared; using APIMappers; +using Dto.Tiny; using Model; namespace WebAPIConsoleTests; /*! * \brief Implémentation de l'interface IActivityRepository pour récupérer des activités via un service HTTP. - */ + #1# public class ActivityServiceAPI : IActivityRepository { private HttpRequest myRequest = new HttpRequest(); @@ -23,7 +24,7 @@ public class ActivityServiceAPI : IActivityRepository /*! * \brief Constructeur de la classe ActivityServiceAPI. * Initialise l'adresse de base du client HTTP. - */ + #1# public ActivityServiceAPI() { myRequest.HttpClient.BaseAddress = new Uri("http://localhost:5030/api/v1/Activity/"); @@ -32,7 +33,7 @@ public class ActivityServiceAPI : IActivityRepository /*! * \brief Récupère toutes les Activités de manière asynchrone. * \return Une tâche représentant l'opération asynchrone qui retourne une liste d'Activity. - */ + #1# public async Task?> GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending = false) { var activityDtos = await myRequest.GetAllAsync(); @@ -44,7 +45,7 @@ public class ActivityServiceAPI : IActivityRepository * \param index L'index de départ pour la pagination. * \param count Le nombre d'éléments à récupérer. * \return Une tâche représentant l'opération asynchrone qui retourne une liste d'Activity. - */ + #1# public async Task> GetBooksAsync(ActivityOrderCriteria criteria, bool descending, int index, int count) { var activityDtos = await myRequest.GetAsync(criteria, descending, index, count); @@ -55,7 +56,12 @@ public class ActivityServiceAPI : IActivityRepository * \brief Récupère une activité par son identifiant de manière asynchrone. * \param id L'identifiant du livre à récupérer. * \return Une tâche représentant l'opération asynchrone qui retourne une liste d'Activity. - */ + #1# + async Task?> IActivityRepository.GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending) + { + throw new NotImplementedException(); + } + public async Task GetActivityByIdAsync(int id) { var activityDtos = await myRequest.GetByIdAsync(id); @@ -66,18 +72,28 @@ public class ActivityServiceAPI : IActivityRepository * \brief Ajoute une activité de manière asynchrone. * \param activity L'Activity à ajouter. * \return Une tâche représentant l'opération asynchrone qui retourne l'activité ajouté (Activity). - */ + #1# public async Task AddActivity(Model.Activity activity) { return (await myRequest.PostAsync(activity.ToDto())).ToModel(); } + public async Task AddActivity(NewActivityDto activity) + { + throw new NotImplementedException(); + } + + public async Task UpdateActivity(int id, ActivityTinyDto activity) + { + throw new NotImplementedException(); + } + /*! * \brief Met à jour une activité de manière asynchrone. * \param id L'identifiant de l'activité à mettre à jour. * \param activity Les nouvelles données de l'activité à mettre à jour. * \return Une tâche représentant l'opération asynchrone qui retourne l'activité mis à jour (Activity). - */ + #1# public async Task UpdateActivity(int id, Model.Activity activity) { var activityDto = activity.ToDto(); @@ -89,7 +105,7 @@ public class ActivityServiceAPI : IActivityRepository * \brief Supprime une activité de manière asynchrone. * \param id L'identifiant de l'activité à supprimer. * \return Une tâche représentant l'opération asynchrone. - */ + #1# public async Task DeleteActivity(int id) { await myRequest.DeleteAsync(id); @@ -110,4 +126,4 @@ public class ActivityServiceAPI : IActivityRepository { return myRequest.GetNbActivitiesByUser(userId); } -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/src/Tests/WebAPIConsoleTests/Program.cs b/src/Tests/WebAPIConsoleTests/Program.cs index 8db0f5f..a7f9075 100644 --- a/src/Tests/WebAPIConsoleTests/Program.cs +++ b/src/Tests/WebAPIConsoleTests/Program.cs @@ -4,8 +4,8 @@ using Model; using Model.Repository; using Shared; using WebAPIConsoleTests; - - +Console.WriteLine(""); +/* IActivityRepository myConsoleTest = new ActivityServiceAPI(); // defini un delais d'attente du déploiement de l'API @@ -63,4 +63,4 @@ foreach (var activity3 in res) // Affiche le nombre d'activités par utilisateur Console.WriteLine("Affichage du nombre d'activités par utilisateur : "); nb = await myConsoleTest.GetNbActivitiesByUser(1); -Console.WriteLine(nb); \ No newline at end of file +Console.WriteLine(nb);*/ \ No newline at end of file From a24704c787e58e15a4ec4e86eb4e3e427b7cc2bd Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 03:37:02 +0100 Subject: [PATCH 26/92] clean --- src/StubApi/AthleteStubDto.cs | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 src/StubApi/AthleteStubDto.cs diff --git a/src/StubApi/AthleteStubDto.cs b/src/StubApi/AthleteStubDto.cs deleted file mode 100644 index 5725d31..0000000 --- a/src/StubApi/AthleteStubDto.cs +++ /dev/null @@ -1,4 +0,0 @@ -// using Shared; - -// namespace - From d666e7396436bf5db1c0ed50ea2d9525f7119ff4 Mon Sep 17 00:00:00 2001 From: David D'ALMEIDA Date: Tue, 19 Mar 2024 03:46:31 +0100 Subject: [PATCH 27/92] =?UTF-8?q?Mise=20=C3=A0=20jour=20de=20'.drone.yml'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .drone.yml | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/.drone.yml b/.drone.yml index 339e9e8..d24d79e 100644 --- a/.drone.yml +++ b/.drone.yml @@ -168,7 +168,24 @@ steps: IMAGENAME: hub.codefirst.iut.uca.fr/david.d_almeida/api:latest CONTAINERNAME: api CODEFIRST_CLIENTDRONE_ENV_PORT: 8080 - ADMINS: davidd_almeida,kevinmonteiro,antoineperederii,paullevrault,antoinepinagot,nicolasraymond,camillepetitalot + ADMINS: davidd_almeida,kevinmonteiro,antoineperederii,paullevrault,antoinepinagot,nicolasraymond + COMMAND: create + OVERWRITE: true + depends_on: [deploy-container-mysql, docker-build-and-push, deploy-container-stub] + - name: deploy-container-phpmyadmin + image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dockerproxy-clientdrone:latest + environment: + IMAGENAME: phpmyadmin/phpmyadmin + CONTAINERNAME: phpmyadmin COMMAND: create OVERWRITE: true - depends_on: [deploy-container-mysql, docker-build-and-push, deploy-container-stub] \ No newline at end of file + PRIVATE: false + CODEFIRST_CLIENTDRONE_ENV_PMA_HOST: mysql + CODEFIRST_CLIENTDRONE_ENV_PMA_PORT: 3306 + CODEFIRST_CLIENTDRONE_ENV_PMA_USER: + from_secret: db_user + CODEFIRST_CLIENTDRONE_ENV_PMA_PASSWORD: + from_secret: db_password + CODEFIRST_CLIENTDRONE_ENV_PMA_ABSOLUTE_URI: /phpmyadmin + ADMINS: davidd_almeida,kevinmonteiro,antoineperederii,paullevrault,antoinepinagot,nicolasraymond + depends_on: [deploy-container-mysql] \ No newline at end of file From 26d5968f9a40dcaa109dc97719e22033b9ddfbf8 Mon Sep 17 00:00:00 2001 From: David D'ALMEIDA Date: Tue, 19 Mar 2024 03:48:36 +0100 Subject: [PATCH 28/92] =?UTF-8?q?Mise=20=C3=A0=20jour=20de=20'.drone.yml'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index d24d79e..140fea9 100644 --- a/.drone.yml +++ b/.drone.yml @@ -172,6 +172,7 @@ steps: COMMAND: create OVERWRITE: true depends_on: [deploy-container-mysql, docker-build-and-push, deploy-container-stub] + - name: deploy-container-phpmyadmin image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dockerproxy-clientdrone:latest environment: @@ -179,7 +180,6 @@ steps: CONTAINERNAME: phpmyadmin COMMAND: create OVERWRITE: true - PRIVATE: false CODEFIRST_CLIENTDRONE_ENV_PMA_HOST: mysql CODEFIRST_CLIENTDRONE_ENV_PMA_PORT: 3306 CODEFIRST_CLIENTDRONE_ENV_PMA_USER: From 87a7e34ea807164094010e40d338eb4a8ef32235 Mon Sep 17 00:00:00 2001 From: David D'ALMEIDA Date: Tue, 19 Mar 2024 03:55:44 +0100 Subject: [PATCH 29/92] =?UTF-8?q?Mise=20=C3=A0=20jour=20de=20'.drone.yml'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .drone.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.drone.yml b/.drone.yml index 140fea9..9dfd5cb 100644 --- a/.drone.yml +++ b/.drone.yml @@ -182,6 +182,7 @@ steps: OVERWRITE: true CODEFIRST_CLIENTDRONE_ENV_PMA_HOST: mysql CODEFIRST_CLIENTDRONE_ENV_PMA_PORT: 3306 + CODEFIRST_CLIENTDRONE_ENV_PMA_ABSOLUTE_URI: /containers/HeartDev-phpmyadmin CODEFIRST_CLIENTDRONE_ENV_PMA_USER: from_secret: db_user CODEFIRST_CLIENTDRONE_ENV_PMA_PASSWORD: From d95d89c817b13e16be376f0ab8300c71b0096f21 Mon Sep 17 00:00:00 2001 From: David D'ALMEIDA Date: Tue, 19 Mar 2024 04:00:07 +0100 Subject: [PATCH 30/92] =?UTF-8?q?Mise=20=C3=A0=20jour=20de=20'.drone.yml'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 9dfd5cb..c1eeb92 100644 --- a/.drone.yml +++ b/.drone.yml @@ -140,7 +140,7 @@ steps: CONTAINERNAME: mysql COMMAND: create OVERWRITE: true - PRIVATE: false + # PRIVATE: false CODEFIRST_CLIENTDRONE_ENV_MARIADB_ROOT_PASSWORD: from_secret: db_root_password CODEFIRST_CLIENTDRONE_ENV_MARIADB_DATABASE: From db99e9404f93df8024aba0391e0edabdeedd6bf6 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 04:04:18 +0100 Subject: [PATCH 31/92] CI --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index b0211ff..2039fa0 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -81,7 +81,11 @@ public class AppBootstrap(IConfiguration configuration) switch (Environment.GetEnvironmentVariable("TYPE")) { case "BDD": - services.AddSingleton(provider => new DbDataManager(provider.GetRequiredService())); + services.AddSingleton(provider => + { + provider.GetRequiredService().Database.EnsureCreated(); + return new DbDataManager(provider.GetRequiredService()); + }); break; case "STUB-MODEL": services.AddSingleton(); From e727c083f5f7f89544b1833e02910db0b0268abc Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 04:07:48 +0100 Subject: [PATCH 32/92] CI --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 2039fa0..e10d710 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -81,9 +81,13 @@ public class AppBootstrap(IConfiguration configuration) switch (Environment.GetEnvironmentVariable("TYPE")) { case "BDD": + Console.WriteLine("====== RUNNING USING THE MYSQL SERVER Here ensure created ======"); services.AddSingleton(provider => { provider.GetRequiredService().Database.EnsureCreated(); + Console.WriteLine(provider.GetRequiredService().Database.EnsureCreated()); + + Console.WriteLine(provider.GetRequiredService().Database.GetPendingMigrations()); return new DbDataManager(provider.GetRequiredService()); }); break; From 8649b76ba571c1b7e467beff16c1bc57a151ec40 Mon Sep 17 00:00:00 2001 From: David D'ALMEIDA Date: Tue, 19 Mar 2024 04:13:04 +0100 Subject: [PATCH 33/92] =?UTF-8?q?Mise=20=C3=A0=20jour=20de=20'.drone.yml'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index c1eeb92..26e48dd 100644 --- a/.drone.yml +++ b/.drone.yml @@ -180,7 +180,7 @@ steps: CONTAINERNAME: phpmyadmin COMMAND: create OVERWRITE: true - CODEFIRST_CLIENTDRONE_ENV_PMA_HOST: mysql + CODEFIRST_CLIENTDRONE_ENV_PMA_HOST: https://codefirst.iut.uca.fr/containers/HeartDev-mysql CODEFIRST_CLIENTDRONE_ENV_PMA_PORT: 3306 CODEFIRST_CLIENTDRONE_ENV_PMA_ABSOLUTE_URI: /containers/HeartDev-phpmyadmin CODEFIRST_CLIENTDRONE_ENV_PMA_USER: From 062446a1a8a627c8d4bc701c0d7b165de528048f Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 04:20:18 +0100 Subject: [PATCH 34/92] CI --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index e10d710..20c3a2a 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -81,13 +81,27 @@ public class AppBootstrap(IConfiguration configuration) switch (Environment.GetEnvironmentVariable("TYPE")) { case "BDD": - Console.WriteLine("====== RUNNING USING THE MYSQL SERVER Here ensure created ======"); + Console.WriteLine("====== RUNNING USING THE MYSQL SERVER. Ensuring database is created ======"); + + var serviceProvider = services.BuildServiceProvider(); + var dbContext = serviceProvider.GetRequiredService(); + + var databaseCreated = dbContext.Database.EnsureCreated(); + Console.WriteLine(databaseCreated ? "Database created or already exists." : "Database not created."); + + var pendingMigrations = dbContext.Database.GetPendingMigrations().ToList(); + if (pendingMigrations.Any()) + { + Console.WriteLine("Pending migrations: " + string.Join(", ", pendingMigrations)); + } + else + { + Console.WriteLine("No pending migrations."); + } + services.AddSingleton(provider => { provider.GetRequiredService().Database.EnsureCreated(); - Console.WriteLine(provider.GetRequiredService().Database.EnsureCreated()); - - Console.WriteLine(provider.GetRequiredService().Database.GetPendingMigrations()); return new DbDataManager(provider.GetRequiredService()); }); break; From 62c774b3c5e38c07336411f9ec7e7b528f9224c4 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 04:41:43 +0100 Subject: [PATCH 35/92] CI --- src/HeartTrackAPI/Program.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/HeartTrackAPI/Program.cs b/src/HeartTrackAPI/Program.cs index b0010a6..6cd94a6 100644 --- a/src/HeartTrackAPI/Program.cs +++ b/src/HeartTrackAPI/Program.cs @@ -1,4 +1,6 @@ +using DbContextLib; using HeartTrackAPI.Utils; +using StubbedContextLib; var builder = WebApplication.CreateBuilder(args); @@ -16,4 +18,8 @@ var app = builder.Build(); init.Configure(app, app.Environment); +var context = app.Services.GetService() ?? app.Services.GetService(); +context!.Database.EnsureCreated(); + + app.Run(); \ No newline at end of file From 5e5b86dbb05bd141e6724a845e2e5e270671fb19 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 04:47:27 +0100 Subject: [PATCH 36/92] ci --- src/HeartTrackAPI/Program.cs | 4 +--- src/HeartTrackAPI/Utils/AppBootstrap.cs | 27 ++----------------------- 2 files changed, 3 insertions(+), 28 deletions(-) diff --git a/src/HeartTrackAPI/Program.cs b/src/HeartTrackAPI/Program.cs index 6cd94a6..90e1b5a 100644 --- a/src/HeartTrackAPI/Program.cs +++ b/src/HeartTrackAPI/Program.cs @@ -1,5 +1,5 @@ using DbContextLib; -using HeartTrackAPI.Utils; +using HeartTrackAPI; using StubbedContextLib; var builder = WebApplication.CreateBuilder(args); @@ -20,6 +20,4 @@ init.Configure(app, app.Environment); var context = app.Services.GetService() ?? app.Services.GetService(); context!.Database.EnsureCreated(); - - app.Run(); \ No newline at end of file diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 20c3a2a..c86a276 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -14,8 +14,7 @@ using StubAPI; using StubbedContextLib; using Swashbuckle.AspNetCore.SwaggerGen; -namespace HeartTrackAPI.Utils; - +namespace HeartTrackAPI; public class AppBootstrap(IConfiguration configuration) { private IConfiguration Configuration { get; } = configuration; @@ -81,29 +80,7 @@ public class AppBootstrap(IConfiguration configuration) switch (Environment.GetEnvironmentVariable("TYPE")) { case "BDD": - Console.WriteLine("====== RUNNING USING THE MYSQL SERVER. Ensuring database is created ======"); - - var serviceProvider = services.BuildServiceProvider(); - var dbContext = serviceProvider.GetRequiredService(); - - var databaseCreated = dbContext.Database.EnsureCreated(); - Console.WriteLine(databaseCreated ? "Database created or already exists." : "Database not created."); - - var pendingMigrations = dbContext.Database.GetPendingMigrations().ToList(); - if (pendingMigrations.Any()) - { - Console.WriteLine("Pending migrations: " + string.Join(", ", pendingMigrations)); - } - else - { - Console.WriteLine("No pending migrations."); - } - - services.AddSingleton(provider => - { - provider.GetRequiredService().Database.EnsureCreated(); - return new DbDataManager(provider.GetRequiredService()); - }); + services.AddSingleton(provider => new DbDataManager(provider.GetRequiredService())); break; case "STUB-MODEL": services.AddSingleton(); From d0cea334e39fe28efea36870d9349b31fb314bc5 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 04:49:07 +0100 Subject: [PATCH 37/92] CI - SAME NAMESPACE --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index c86a276..dab484a 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -80,7 +80,29 @@ public class AppBootstrap(IConfiguration configuration) switch (Environment.GetEnvironmentVariable("TYPE")) { case "BDD": - services.AddSingleton(provider => new DbDataManager(provider.GetRequiredService())); + Console.WriteLine("====== RUNNING USING THE MYSQL SERVER. Ensuring database is created ======"); + + var serviceProvider = services.BuildServiceProvider(); + var dbContext = serviceProvider.GetRequiredService(); + + var databaseCreated = dbContext.Database.EnsureCreated(); + Console.WriteLine(databaseCreated ? "Database created or already exists." : "Database not created."); + + var pendingMigrations = dbContext.Database.GetPendingMigrations().ToList(); + if (pendingMigrations.Any()) + { + Console.WriteLine("Pending migrations: " + string.Join(", ", pendingMigrations)); + } + else + { + Console.WriteLine("No pending migrations."); + } + + services.AddSingleton(provider => + { + provider.GetRequiredService().Database.EnsureCreated(); + return new DbDataManager(provider.GetRequiredService()); + }); break; case "STUB-MODEL": services.AddSingleton(); From 605bab3241e90d38d3ed8beeba1c74f6f4c310bd Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 04:52:03 +0100 Subject: [PATCH 38/92] CI TEST --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 26 ++----------------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index dab484a..f7f501a 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -14,7 +14,7 @@ using StubAPI; using StubbedContextLib; using Swashbuckle.AspNetCore.SwaggerGen; -namespace HeartTrackAPI; +namespace HeartTrackAPI.Utils; public class AppBootstrap(IConfiguration configuration) { private IConfiguration Configuration { get; } = configuration; @@ -80,29 +80,7 @@ public class AppBootstrap(IConfiguration configuration) switch (Environment.GetEnvironmentVariable("TYPE")) { case "BDD": - Console.WriteLine("====== RUNNING USING THE MYSQL SERVER. Ensuring database is created ======"); - - var serviceProvider = services.BuildServiceProvider(); - var dbContext = serviceProvider.GetRequiredService(); - - var databaseCreated = dbContext.Database.EnsureCreated(); - Console.WriteLine(databaseCreated ? "Database created or already exists." : "Database not created."); - - var pendingMigrations = dbContext.Database.GetPendingMigrations().ToList(); - if (pendingMigrations.Any()) - { - Console.WriteLine("Pending migrations: " + string.Join(", ", pendingMigrations)); - } - else - { - Console.WriteLine("No pending migrations."); - } - - services.AddSingleton(provider => - { - provider.GetRequiredService().Database.EnsureCreated(); - return new DbDataManager(provider.GetRequiredService()); - }); + services.AddSingleton(provider => new DbDataManager(provider.GetRequiredService())); break; case "STUB-MODEL": services.AddSingleton(); From 084ce29b4ee978a7b5cd6d37be2f9d6cdc54fb05 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 04:55:30 +0100 Subject: [PATCH 39/92] CI - TEST --- src/HeartTrackAPI/Program.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/HeartTrackAPI/Program.cs b/src/HeartTrackAPI/Program.cs index 90e1b5a..75b6942 100644 --- a/src/HeartTrackAPI/Program.cs +++ b/src/HeartTrackAPI/Program.cs @@ -1,5 +1,6 @@ using DbContextLib; using HeartTrackAPI; +using HeartTrackAPI.Utils; using StubbedContextLib; var builder = WebApplication.CreateBuilder(args); From f3a2c231660eb049c033d4a402569a962a9e17eb Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 04:58:24 +0100 Subject: [PATCH 40/92] CI - without ensure in Program.cs --- src/HeartTrackAPI/Program.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HeartTrackAPI/Program.cs b/src/HeartTrackAPI/Program.cs index 75b6942..d259a76 100644 --- a/src/HeartTrackAPI/Program.cs +++ b/src/HeartTrackAPI/Program.cs @@ -19,6 +19,6 @@ var app = builder.Build(); init.Configure(app, app.Environment); -var context = app.Services.GetService() ?? app.Services.GetService(); -context!.Database.EnsureCreated(); +//var context = app.Services.GetService() ?? app.Services.GetService(); +//context!.Database.EnsureCreated(); app.Run(); \ No newline at end of file From 62d33ab92225b89f6726a8037bde348ba9f2cec6 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 05:03:08 +0100 Subject: [PATCH 41/92] CI - EnsureCreated in create service --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index f7f501a..d24d155 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -14,7 +14,7 @@ using StubAPI; using StubbedContextLib; using Swashbuckle.AspNetCore.SwaggerGen; -namespace HeartTrackAPI.Utils; +namespace HeartTrackAPI; public class AppBootstrap(IConfiguration configuration) { private IConfiguration Configuration { get; } = configuration; @@ -80,7 +80,12 @@ public class AppBootstrap(IConfiguration configuration) switch (Environment.GetEnvironmentVariable("TYPE")) { case "BDD": - services.AddSingleton(provider => new DbDataManager(provider.GetRequiredService())); + // services.AddSingleton(provider => new DbDataManager(provider.GetRequiredService())); + services.AddSingleton(provider => + { + provider.GetRequiredService().Database.EnsureCreated(); + return new DbDataManager(provider.GetRequiredService()); + }); break; case "STUB-MODEL": services.AddSingleton(); From fe29cce7e2f153c4fc32dae018d2ba8547716c77 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 05:09:59 +0100 Subject: [PATCH 42/92] CI -should really Work --- src/HeartTrackAPI/Program.cs | 4 ++-- src/HeartTrackAPI/Utils/AppBootstrap.cs | 13 ++----------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/HeartTrackAPI/Program.cs b/src/HeartTrackAPI/Program.cs index d259a76..75b6942 100644 --- a/src/HeartTrackAPI/Program.cs +++ b/src/HeartTrackAPI/Program.cs @@ -19,6 +19,6 @@ var app = builder.Build(); init.Configure(app, app.Environment); -//var context = app.Services.GetService() ?? app.Services.GetService(); -//context!.Database.EnsureCreated(); +var context = app.Services.GetService() ?? app.Services.GetService(); +context!.Database.EnsureCreated(); app.Run(); \ No newline at end of file diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index d24d155..f2861b5 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -80,22 +80,13 @@ public class AppBootstrap(IConfiguration configuration) switch (Environment.GetEnvironmentVariable("TYPE")) { case "BDD": - // services.AddSingleton(provider => new DbDataManager(provider.GetRequiredService())); - services.AddSingleton(provider => - { - provider.GetRequiredService().Database.EnsureCreated(); - return new DbDataManager(provider.GetRequiredService()); - }); + services.AddSingleton(provider => new DbDataManager(provider.GetRequiredService())); break; case "STUB-MODEL": services.AddSingleton(); break; default: - services.AddSingleton(provider => - { - provider.GetRequiredService().Database.EnsureCreated(); - return new DbDataManager(provider.GetRequiredService()); - }); + services.AddSingleton(provider => new DbDataManager(provider.GetRequiredService())); break; } From e9088d303f9956493edb36574843af75851a3a7d Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 05:13:49 +0100 Subject: [PATCH 43/92] CI. --- src/HeartTrackAPI/Program.cs | 1 - src/HeartTrackAPI/Utils/AppBootstrap.cs | 8 ++------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/HeartTrackAPI/Program.cs b/src/HeartTrackAPI/Program.cs index 75b6942..8e84534 100644 --- a/src/HeartTrackAPI/Program.cs +++ b/src/HeartTrackAPI/Program.cs @@ -1,5 +1,4 @@ using DbContextLib; -using HeartTrackAPI; using HeartTrackAPI.Utils; using StubbedContextLib; diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index f2861b5..3edfe09 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -1,7 +1,6 @@ using System.Reflection; using DbContextLib; using DbContextLib.Identity; -using HeartTrackAPI.Utils; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.Versioning; @@ -14,7 +13,7 @@ using StubAPI; using StubbedContextLib; using Swashbuckle.AspNetCore.SwaggerGen; -namespace HeartTrackAPI; +namespace HeartTrackAPI.Utils; public class AppBootstrap(IConfiguration configuration) { private IConfiguration Configuration { get; } = configuration; @@ -48,8 +47,7 @@ public class AppBootstrap(IConfiguration configuration) connectionString = $"Server={host};port={port};database={database};user={username};password={password}"; Console.WriteLine("========RUNNING USING THE MYSQL SERVER=============="); Console.WriteLine(connectionString); - Console.WriteLine(connectionString); - Console.WriteLine("======================"); + Console.WriteLine("===================================================="); services.AddDbContext(options => options.UseInMemoryDatabase("AuthDb")); services.AddDbContext(options => options.UseMySql($"{connectionString}", new MySqlServerVersion(new Version(10, 11, 1))) @@ -89,8 +87,6 @@ public class AppBootstrap(IConfiguration configuration) services.AddSingleton(provider => new DbDataManager(provider.GetRequiredService())); break; } - - //services.AddTransient(); } private void AddIdentityServices(IServiceCollection services) From fca04ca17907150e2376c55864033bd1b7f353af Mon Sep 17 00:00:00 2001 From: David D'ALMEIDA Date: Tue, 19 Mar 2024 05:20:25 +0100 Subject: [PATCH 44/92] =?UTF-8?q?Mise=20=C3=A0=20jour=20de=20'.drone.yml'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .drone.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 26e48dd..29c8bda 100644 --- a/.drone.yml +++ b/.drone.yml @@ -7,7 +7,6 @@ name: HeartTrack-API # - master # event: # - push - steps: - name: build image: mcr.microsoft.com/dotnet/sdk:8.0 From 96a5dbbb9c718d8d33a07a8bc0ed6209776122f8 Mon Sep 17 00:00:00 2001 From: David D'ALMEIDA Date: Tue, 19 Mar 2024 05:25:58 +0100 Subject: [PATCH 45/92] =?UTF-8?q?Mise=20=C3=A0=20jour=20de=20'.drone.yml'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 29c8bda..26837ac 100644 --- a/.drone.yml +++ b/.drone.yml @@ -179,7 +179,7 @@ steps: CONTAINERNAME: phpmyadmin COMMAND: create OVERWRITE: true - CODEFIRST_CLIENTDRONE_ENV_PMA_HOST: https://codefirst.iut.uca.fr/containers/HeartDev-mysql + CODEFIRST_CLIENTDRONE_ENV_PMA_HOST: HeartDev-mysql CODEFIRST_CLIENTDRONE_ENV_PMA_PORT: 3306 CODEFIRST_CLIENTDRONE_ENV_PMA_ABSOLUTE_URI: /containers/HeartDev-phpmyadmin CODEFIRST_CLIENTDRONE_ENV_PMA_USER: From 173b13add71fe3b690b883ad031ba3b85e81cfab Mon Sep 17 00:00:00 2001 From: David D'ALMEIDA Date: Tue, 19 Mar 2024 05:28:28 +0100 Subject: [PATCH 46/92] =?UTF-8?q?Mise=20=C3=A0=20jour=20de=20'.drone.yml'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .drone.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.drone.yml b/.drone.yml index 26837ac..a8ef5dd 100644 --- a/.drone.yml +++ b/.drone.yml @@ -181,11 +181,11 @@ steps: OVERWRITE: true CODEFIRST_CLIENTDRONE_ENV_PMA_HOST: HeartDev-mysql CODEFIRST_CLIENTDRONE_ENV_PMA_PORT: 3306 - CODEFIRST_CLIENTDRONE_ENV_PMA_ABSOLUTE_URI: /containers/HeartDev-phpmyadmin + # CODEFIRST_CLIENTDRONE_ENV_PMA_ABSOLUTE_URI: /containers/HeartDev-phpmyadmin CODEFIRST_CLIENTDRONE_ENV_PMA_USER: from_secret: db_user CODEFIRST_CLIENTDRONE_ENV_PMA_PASSWORD: from_secret: db_password - CODEFIRST_CLIENTDRONE_ENV_PMA_ABSOLUTE_URI: /phpmyadmin + # CODEFIRST_CLIENTDRONE_ENV_PMA_ABSOLUTE_URI: /phpmyadmin ADMINS: davidd_almeida,kevinmonteiro,antoineperederii,paullevrault,antoinepinagot,nicolasraymond depends_on: [deploy-container-mysql] \ No newline at end of file From 2ac5772d2a0e5205b9c043a8dc5b6d4457b63c63 Mon Sep 17 00:00:00 2001 From: David D'ALMEIDA Date: Tue, 19 Mar 2024 05:31:32 +0100 Subject: [PATCH 47/92] =?UTF-8?q?Mise=20=C3=A0=20jour=20de=20'.drone.yml'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index a8ef5dd..aa63cb0 100644 --- a/.drone.yml +++ b/.drone.yml @@ -139,7 +139,7 @@ steps: CONTAINERNAME: mysql COMMAND: create OVERWRITE: true - # PRIVATE: false + PRIVATE: true CODEFIRST_CLIENTDRONE_ENV_MARIADB_ROOT_PASSWORD: from_secret: db_root_password CODEFIRST_CLIENTDRONE_ENV_MARIADB_DATABASE: From 2f1dc9e2ddcbf0fe76013c8186ca3eeefc8737f3 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 05:35:50 +0100 Subject: [PATCH 48/92] CI --- src/Entities2Dto/ActivityMapper.cs | 1 - src/HeartTrackAPI/Program.cs | 2 ++ src/HeartTrackAPI/Utils/AppBootstrap.cs | 8 +++++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Entities2Dto/ActivityMapper.cs b/src/Entities2Dto/ActivityMapper.cs index 116f63a..43243a1 100644 --- a/src/Entities2Dto/ActivityMapper.cs +++ b/src/Entities2Dto/ActivityMapper.cs @@ -19,7 +19,6 @@ public static class ActivityMapper public static ActivityTinyDto ToDto(this ActivityEntity entity) { - Console.WriteLine("dfghf"); Func create = activityEntity => new ActivityTinyDto { Id = activityEntity.IdActivity, diff --git a/src/HeartTrackAPI/Program.cs b/src/HeartTrackAPI/Program.cs index 8e84534..a0b177e 100644 --- a/src/HeartTrackAPI/Program.cs +++ b/src/HeartTrackAPI/Program.cs @@ -19,5 +19,7 @@ var app = builder.Build(); init.Configure(app, app.Environment); var context = app.Services.GetService() ?? app.Services.GetService(); + context!.Database.EnsureCreated(); + app.Run(); \ No newline at end of file diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 3edfe09..7e81215 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -84,7 +84,13 @@ public class AppBootstrap(IConfiguration configuration) services.AddSingleton(); break; default: - services.AddSingleton(provider => new DbDataManager(provider.GetRequiredService())); + services.AddSingleton(provider => + { + provider.GetRequiredService().Database.EnsureCreated(); + return new DbDataManager(provider.GetRequiredService()); + }); + + // services.AddSingleton(provider => new DbDataManager(provider.GetRequiredService())); break; } } From 25081267b99bea72b5986bdc22ecfe0c3578f449 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 06:03:06 +0100 Subject: [PATCH 49/92] clean --- src/HeartTrackAPI/Request/PageRequest.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/HeartTrackAPI/Request/PageRequest.cs b/src/HeartTrackAPI/Request/PageRequest.cs index a4399f4..e7651d4 100644 --- a/src/HeartTrackAPI/Request/PageRequest.cs +++ b/src/HeartTrackAPI/Request/PageRequest.cs @@ -7,10 +7,6 @@ public class PageRequest { public string? OrderingPropertyName { get; set; } = null; public bool? Descending { get; set; } = false; - -// [Range(0, int.MaxValue, ErrorMessage = "Count must be greater than 0")] public int Index { get; set; } = 0; - -// [Range(0, int.MaxValue, ErrorMessage = "Count must be greater than 0")] public int Count { get; set; } = 1; } From 0922d1cfda0f5443147b2da667ece4d5422ea3bf Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 06:08:49 +0100 Subject: [PATCH 50/92] CI --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 7e81215..82bffdb 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -186,6 +186,7 @@ public class AppBootstrap(IConfiguration configuration) { var apiVersionDescriptionProvider = app.Services.GetRequiredService(); app.UseSwagger(); + app.UseSwaggerUI(); app.MapSwagger(); app.UseSwaggerUI(options => { From 4eb9edd4b592476fb414a2c1b2275f91ee060a80 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 06:09:25 +0100 Subject: [PATCH 51/92] CI --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 82bffdb..1282ad4 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -28,7 +28,6 @@ public class AppBootstrap(IConfiguration configuration) AddIdentityServices(services); AddApiVersioning(services); services.AddHealthChecks(); - } private void AddHeartTrackContextServices(IServiceCollection services) From 12e0bb8962a2bc669155188ec3025ad2a0798ed2 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 06:11:27 +0100 Subject: [PATCH 52/92] CI --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 1282ad4..dc74a9e 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -185,8 +185,6 @@ public class AppBootstrap(IConfiguration configuration) { var apiVersionDescriptionProvider = app.Services.GetRequiredService(); app.UseSwagger(); - app.UseSwaggerUI(); - app.MapSwagger(); app.UseSwaggerUI(options => { foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions) @@ -195,6 +193,8 @@ public class AppBootstrap(IConfiguration configuration) description.GroupName.ToUpperInvariant()); } }); + app.MapSwagger(); + } From eb1ed934b353514489b96a452ed9e72889a9ebda Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 06:14:18 +0100 Subject: [PATCH 53/92] OK --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index dc74a9e..dff78fd 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -194,6 +194,8 @@ public class AppBootstrap(IConfiguration configuration) } }); app.MapSwagger(); + app.UseSwaggerUI(); + } From b3e1f5c60251b2176140df1a54234479e658dd86 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 06:15:50 +0100 Subject: [PATCH 54/92] KO --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index dff78fd..1282ad4 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -185,6 +185,8 @@ public class AppBootstrap(IConfiguration configuration) { var apiVersionDescriptionProvider = app.Services.GetRequiredService(); app.UseSwagger(); + app.UseSwaggerUI(); + app.MapSwagger(); app.UseSwaggerUI(options => { foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions) @@ -193,10 +195,6 @@ public class AppBootstrap(IConfiguration configuration) description.GroupName.ToUpperInvariant()); } }); - app.MapSwagger(); - app.UseSwaggerUI(); - - } From 2511471ec6599c2e5f653983ffe8a51e2d7de767 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 06:17:42 +0100 Subject: [PATCH 55/92] Test --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 1282ad4..c41d828 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -183,19 +183,9 @@ public class AppBootstrap(IConfiguration configuration) // Configure the HTTP request pipeline. if (true) { - var apiVersionDescriptionProvider = app.Services.GetRequiredService(); app.UseSwagger(); app.UseSwaggerUI(); app.MapSwagger(); - app.UseSwaggerUI(options => - { - foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions) - { - options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", - description.GroupName.ToUpperInvariant()); - } - }); - } From 885ddfd4a16595993ff0d316d0395d3b30521d60 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 06:31:38 +0100 Subject: [PATCH 56/92] Swag --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index c41d828..73640c3 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -172,6 +172,7 @@ public class AppBootstrap(IConfiguration configuration) public void Configure(WebApplication app, IWebHostEnvironment env) { + app.UsePathBase("/codefirst"); app.UseHttpsRedirection(); app.MapIdentityApi(); @@ -183,9 +184,21 @@ public class AppBootstrap(IConfiguration configuration) // Configure the HTTP request pipeline. if (true) { + var apiVersionDescriptionProvider = app.Services.GetRequiredService(); app.UseSwagger(); - app.UseSwaggerUI(); + app.UseSwaggerUI(c => { + c.SwaggerEndpoint($"./v1/swagger.json", "SapWeb v1"); + }); app.MapSwagger(); +/* app.UseSwaggerUI(options => + { + foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions) + { + options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", + description.GroupName.ToUpperInvariant()); + } + });*/ + } From 56b65ff45bf84eed6a6e80ae5bdc21a6aed0c562 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 06:32:10 +0100 Subject: [PATCH 57/92] swagger --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 73640c3..156dd23 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -172,7 +172,7 @@ public class AppBootstrap(IConfiguration configuration) public void Configure(WebApplication app, IWebHostEnvironment env) { - app.UsePathBase("/codefirst"); + app.UsePathBase("/containers/HeartDev-api"); app.UseHttpsRedirection(); app.MapIdentityApi(); From 05c048451488f50369d78d074aad900d80a39050 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 06:41:19 +0100 Subject: [PATCH 58/92] try --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 156dd23..fd57adb 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -186,9 +186,7 @@ public class AppBootstrap(IConfiguration configuration) { var apiVersionDescriptionProvider = app.Services.GetRequiredService(); app.UseSwagger(); - app.UseSwaggerUI(c => { - c.SwaggerEndpoint($"./v1/swagger.json", "SapWeb v1"); - }); + app.UseSwaggerUI(); app.MapSwagger(); /* app.UseSwaggerUI(options => { From ecc4079700b95efa497f4f7c3793e83cfe7fd9b4 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 06:48:44 +0100 Subject: [PATCH 59/92] try --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index fd57adb..8b54334 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -172,7 +172,6 @@ public class AppBootstrap(IConfiguration configuration) public void Configure(WebApplication app, IWebHostEnvironment env) { - app.UsePathBase("/containers/HeartDev-api"); app.UseHttpsRedirection(); app.MapIdentityApi(); From 997c06b69399bc1921d6560bb0d9ce932a102baf Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 06:51:44 +0100 Subject: [PATCH 60/92] try --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 8b54334..c41052e 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -172,6 +172,7 @@ public class AppBootstrap(IConfiguration configuration) public void Configure(WebApplication app, IWebHostEnvironment env) { +// app.UsePathBase("/containers/HeartDev-api"); app.UseHttpsRedirection(); app.MapIdentityApi(); @@ -184,8 +185,28 @@ public class AppBootstrap(IConfiguration configuration) if (true) { var apiVersionDescriptionProvider = app.Services.GetRequiredService(); - app.UseSwagger(); - app.UseSwaggerUI(); + app.UseSwagger(options => + { + options.PreSerializeFilters.Add((swagger, httpReq) => + { + if (httpReq.Headers.ContainsKey("X-Forwarded-Host")) + { + //The httpReq.PathBase and httpReq.Headers["X-Forwarded-Prefix"] is what we need to get the base path. + //For some reason, they returning as null/blank. Perhaps this has something to do with how the proxy is configured which we don't have control. + //For the time being, the base path is manually set here that corresponds to the APIM API Url Prefix. + //In this case we set it to 'sample-app'. + + var basePath = "/containers/HeartDev-api"; + var serverUrl = $"{httpReq.Scheme}://{httpReq.Headers["X-Forwarded-Host"]}/{basePath}"; + swagger.Servers = new List { new OpenApiServer { Url = serverUrl } }; + } + }); + }); + app.UseSwaggerUI(options => + { + options.RoutePrefix = string.Empty; + options.SwaggerEndpoint("swagger/v1/swagger.json", "My Api (v1)"); + }); app.MapSwagger(); /* app.UseSwaggerUI(options => { From 6dd73d34a74df607da93103e1152705f82068104 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 06:53:45 +0100 Subject: [PATCH 61/92] small change on try --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index c41052e..b49cc5f 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -196,7 +196,7 @@ public class AppBootstrap(IConfiguration configuration) //For the time being, the base path is manually set here that corresponds to the APIM API Url Prefix. //In this case we set it to 'sample-app'. - var basePath = "/containers/HeartDev-api"; + var basePath = "containers/HeartDev-api"; var serverUrl = $"{httpReq.Scheme}://{httpReq.Headers["X-Forwarded-Host"]}/{basePath}"; swagger.Servers = new List { new OpenApiServer { Url = serverUrl } }; } From 3849147b2d76f065ee1490bbf63fa01e470503d9 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 07:15:25 +0100 Subject: [PATCH 62/92] try --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index b49cc5f..81213ca 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -189,8 +189,8 @@ public class AppBootstrap(IConfiguration configuration) { options.PreSerializeFilters.Add((swagger, httpReq) => { - if (httpReq.Headers.ContainsKey("X-Forwarded-Host")) - { + //if (httpReq.Headers.ContainsKey("X-Forwarded-Host")) + // { //The httpReq.PathBase and httpReq.Headers["X-Forwarded-Prefix"] is what we need to get the base path. //For some reason, they returning as null/blank. Perhaps this has something to do with how the proxy is configured which we don't have control. //For the time being, the base path is manually set here that corresponds to the APIM API Url Prefix. @@ -198,15 +198,11 @@ public class AppBootstrap(IConfiguration configuration) var basePath = "containers/HeartDev-api"; var serverUrl = $"{httpReq.Scheme}://{httpReq.Headers["X-Forwarded-Host"]}/{basePath}"; - swagger.Servers = new List { new OpenApiServer { Url = serverUrl } }; - } + swagger.Servers = new List { new() { Url = serverUrl }, new() { Url = $"{httpReq.Scheme}://{httpReq.Host.Value}" },new() { Url = $"{httpReq.Scheme}://{httpReq.Host.Value}/{basePath}" } }; + //} }); }); - app.UseSwaggerUI(options => - { - options.RoutePrefix = string.Empty; - options.SwaggerEndpoint("swagger/v1/swagger.json", "My Api (v1)"); - }); + app.UseSwaggerUI(); app.MapSwagger(); /* app.UseSwaggerUI(options => { From d20f23478fa9555372676ad70e5bb91a564c480c Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 07:20:41 +0100 Subject: [PATCH 63/92] just to see --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 81213ca..9c91653 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -197,8 +197,8 @@ public class AppBootstrap(IConfiguration configuration) //In this case we set it to 'sample-app'. var basePath = "containers/HeartDev-api"; - var serverUrl = $"{httpReq.Scheme}://{httpReq.Headers["X-Forwarded-Host"]}/{basePath}"; - swagger.Servers = new List { new() { Url = serverUrl }, new() { Url = $"{httpReq.Scheme}://{httpReq.Host.Value}" },new() { Url = $"{httpReq.Scheme}://{httpReq.Host.Value}/{basePath}" } }; + var serverUrl = $"{httpReq.Scheme}://{httpReq.Headers["X-Forwarded-Host"]}/3{basePath}"; + swagger.Servers = new List { new() { Url = serverUrl }, new() { Url = $"{httpReq.Scheme}://1{httpReq.Host.Value}" },new() { Url = $"{httpReq.Scheme}://2{httpReq.Host.Value}/{basePath}" } }; //} }); }); From 4e6ab80d581af6da9b1f1ca15ab1e5916c872a26 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 07:25:43 +0100 Subject: [PATCH 64/92] end --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 9c91653..ffc84b9 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -172,7 +172,6 @@ public class AppBootstrap(IConfiguration configuration) public void Configure(WebApplication app, IWebHostEnvironment env) { -// app.UsePathBase("/containers/HeartDev-api"); app.UseHttpsRedirection(); app.MapIdentityApi(); @@ -189,29 +188,24 @@ public class AppBootstrap(IConfiguration configuration) { options.PreSerializeFilters.Add((swagger, httpReq) => { - //if (httpReq.Headers.ContainsKey("X-Forwarded-Host")) - // { - //The httpReq.PathBase and httpReq.Headers["X-Forwarded-Prefix"] is what we need to get the base path. - //For some reason, they returning as null/blank. Perhaps this has something to do with how the proxy is configured which we don't have control. - //For the time being, the base path is manually set here that corresponds to the APIM API Url Prefix. - //In this case we set it to 'sample-app'. - + if (httpReq.Headers.ContainsKey("X-Forwarded-Host")) + { var basePath = "containers/HeartDev-api"; var serverUrl = $"{httpReq.Scheme}://{httpReq.Headers["X-Forwarded-Host"]}/3{basePath}"; - swagger.Servers = new List { new() { Url = serverUrl }, new() { Url = $"{httpReq.Scheme}://1{httpReq.Host.Value}" },new() { Url = $"{httpReq.Scheme}://2{httpReq.Host.Value}/{basePath}" } }; - //} + swagger.Servers = new List { new() { Url = serverUrl } }; + } }); }); app.UseSwaggerUI(); app.MapSwagger(); -/* app.UseSwaggerUI(options => + app.UseSwaggerUI(options => { foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions) { options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant()); } - });*/ + }); } From cff1484c4aab72018c5305a7178fe727ac1ab0c1 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 07:37:28 +0100 Subject: [PATCH 65/92] https --- src/HeartTrackAPI/Properties/launchSettings.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/HeartTrackAPI/Properties/launchSettings.json b/src/HeartTrackAPI/Properties/launchSettings.json index 7156f3d..9fa5871 100644 --- a/src/HeartTrackAPI/Properties/launchSettings.json +++ b/src/HeartTrackAPI/Properties/launchSettings.json @@ -9,26 +9,27 @@ } }, "profiles": { - "http": { + "https": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "launchUrl": "swagger", - "applicationUrl": "http://localhost:5030", + "applicationUrl": "https://localhost:8080;http://localhost:5030", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, - "https": { + "http": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "launchUrl": "swagger", - "applicationUrl": "https://localhost:7233;http://localhost:5030", + "applicationUrl": "http://localhost:5030", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, + "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, From 2486e6b7eb4af5fff2b1bf2e9130057561eedc90 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 07:39:51 +0100 Subject: [PATCH 66/92] how --- src/HeartTrackAPI/Properties/launchSettings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HeartTrackAPI/Properties/launchSettings.json b/src/HeartTrackAPI/Properties/launchSettings.json index 9fa5871..e100332 100644 --- a/src/HeartTrackAPI/Properties/launchSettings.json +++ b/src/HeartTrackAPI/Properties/launchSettings.json @@ -24,7 +24,7 @@ "dotnetRunMessages": true, "launchBrowser": true, "launchUrl": "swagger", - "applicationUrl": "http://localhost:5030", + "applicationUrl": "http://localhost:5033", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } From 04a1d7e1073d5d639efaa443b1ca598e26b4ec65 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 07:43:44 +0100 Subject: [PATCH 67/92] try --- src/HeartTrackAPI/Properties/launchSettings.json | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/HeartTrackAPI/Properties/launchSettings.json b/src/HeartTrackAPI/Properties/launchSettings.json index e100332..ab36185 100644 --- a/src/HeartTrackAPI/Properties/launchSettings.json +++ b/src/HeartTrackAPI/Properties/launchSettings.json @@ -9,27 +9,26 @@ } }, "profiles": { - "https": { + "http": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "launchUrl": "swagger", - "applicationUrl": "https://localhost:8080;http://localhost:5030", + "applicationUrl": "http://localhost:5030", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, - "http": { + "https": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "launchUrl": "swagger", - "applicationUrl": "http://localhost:5033", + "applicationUrl": "https://localhost:7233;http://localhost:5030,https://codefirst.iut.uca.fr/containers/HeartDev-api:8080, https://codefirst.iut.uca.fr:8080", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, - "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, From 84515d656ef909b00e7e9250e08a86ed253dc40e Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 07:48:21 +0100 Subject: [PATCH 68/92] https in string --- src/HeartTrackAPI/Properties/launchSettings.json | 2 +- src/HeartTrackAPI/Utils/AppBootstrap.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HeartTrackAPI/Properties/launchSettings.json b/src/HeartTrackAPI/Properties/launchSettings.json index ab36185..7156f3d 100644 --- a/src/HeartTrackAPI/Properties/launchSettings.json +++ b/src/HeartTrackAPI/Properties/launchSettings.json @@ -24,7 +24,7 @@ "dotnetRunMessages": true, "launchBrowser": true, "launchUrl": "swagger", - "applicationUrl": "https://localhost:7233;http://localhost:5030,https://codefirst.iut.uca.fr/containers/HeartDev-api:8080, https://codefirst.iut.uca.fr:8080", + "applicationUrl": "https://localhost:7233;http://localhost:5030", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index ffc84b9..1041212 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -191,7 +191,7 @@ public class AppBootstrap(IConfiguration configuration) if (httpReq.Headers.ContainsKey("X-Forwarded-Host")) { var basePath = "containers/HeartDev-api"; - var serverUrl = $"{httpReq.Scheme}://{httpReq.Headers["X-Forwarded-Host"]}/3{basePath}"; + var serverUrl = $"https://{httpReq.Headers["X-Forwarded-Host"]}/{basePath}"; swagger.Servers = new List { new() { Url = serverUrl } }; } }); From ea245802a9597825615fe17c9006dea1b59d85f4 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 08:16:24 +0100 Subject: [PATCH 69/92] FINE --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 1041212..422024e 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -188,9 +188,22 @@ public class AppBootstrap(IConfiguration configuration) { options.PreSerializeFilters.Add((swagger, httpReq) => { + if (httpReq.Headers.ContainsKey("X-Forwarded-Host")) { - var basePath = "containers/HeartDev-api"; + string basePath; + switch (Environment.GetEnvironmentVariable("TYPE")) // httpReq.Host.Value + { + case "STUB" : + basePath = "containers/HeartDev-heart_stub"; + break; + case "BDD": + basePath = "containers/HeartDev-api"; + break; + default: + basePath = httpReq.Host.Value; + break; + } var serverUrl = $"https://{httpReq.Headers["X-Forwarded-Host"]}/{basePath}"; swagger.Servers = new List { new() { Url = serverUrl } }; } From 5c415991c15e4dbb54d3d2b5be18dc7f5ff01cdf Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 08:18:45 +0100 Subject: [PATCH 70/92] what --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 422024e..5c02ed1 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -209,7 +209,7 @@ public class AppBootstrap(IConfiguration configuration) } }); }); - app.UseSwaggerUI(); + // app.UseSwaggerUI(); app.MapSwagger(); app.UseSwaggerUI(options => { From 5dfb8d03f7832460aab761036aca72f238742366 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 08:20:16 +0100 Subject: [PATCH 71/92] ok --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 5c02ed1..e45e18f 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -183,7 +183,6 @@ public class AppBootstrap(IConfiguration configuration) // Configure the HTTP request pipeline. if (true) { - var apiVersionDescriptionProvider = app.Services.GetRequiredService(); app.UseSwagger(options => { options.PreSerializeFilters.Add((swagger, httpReq) => @@ -209,17 +208,8 @@ public class AppBootstrap(IConfiguration configuration) } }); }); - // app.UseSwaggerUI(); + app.UseSwaggerUI(); app.MapSwagger(); - app.UseSwaggerUI(options => - { - foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions) - { - options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", - description.GroupName.ToUpperInvariant()); - } - }); - } From e6c1c16f6f413e7aeae9c7bf9e59386107c78bde Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Mar 2024 08:25:17 +0100 Subject: [PATCH 72/92] Make DataSourceEntity for athlete nullable so required False --- src/DbContextLib/HeartTrackContext.cs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/DbContextLib/HeartTrackContext.cs b/src/DbContextLib/HeartTrackContext.cs index 2dfb977..1cec4ca 100644 --- a/src/DbContextLib/HeartTrackContext.cs +++ b/src/DbContextLib/HeartTrackContext.cs @@ -233,16 +233,7 @@ namespace DbContextLib .HasMany(ds => ds.Athletes) .WithOne(at => at.DataSource) .HasForeignKey(at => at.DataSourceId) - .IsRequired(); - - // modelBuilder.Entity() - // .HasMany(fer => fer.Followers) - // .WithMany(fing => fing.Followings) - // .UsingEntity( - // l => l.HasOne().WithMany().HasForeignKey(fer => fer.FollowerId), - // r => r.HasOne().WithMany().HasForeignKey(fing => fing.FollowingId), - // j => j.Property(f => f.StartDate).HasDefaultValueSql("CURRENT_TIMESTAMP") - // ); + .IsRequired(false); } } } \ No newline at end of file From fcf7182a7a25ca14efb9054a0816bdbbcc38cef0 Mon Sep 17 00:00:00 2001 From: David D'ALMEIDA Date: Tue, 19 Mar 2024 08:58:17 +0100 Subject: [PATCH 73/92] =?UTF-8?q?Mise=20=C3=A0=20jour=20de=20'.drone.yml'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index aa63cb0..c964f81 100644 --- a/.drone.yml +++ b/.drone.yml @@ -46,7 +46,7 @@ steps: depends_on: [ tests ] - name: swagger - image: mcr.microsoft.com/dotnet/sdk:8.0 + image: mcr.microsoft.com/dotnet/sdk:7.0 failure: ignore volumes: - name: docs From dff77f80c592aa9e52278f7c763f61ba793a26d3 Mon Sep 17 00:00:00 2001 From: David D'ALMEIDA Date: Wed, 20 Mar 2024 12:49:27 +0100 Subject: [PATCH 74/92] =?UTF-8?q?Mise=20=C3=A0=20jour=20de=20'.drone.yml'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index c964f81..842a40e 100644 --- a/.drone.yml +++ b/.drone.yml @@ -138,7 +138,7 @@ steps: IMAGENAME: mariadb:10 CONTAINERNAME: mysql COMMAND: create - OVERWRITE: true + OVERWRITE: false PRIVATE: true CODEFIRST_CLIENTDRONE_ENV_MARIADB_ROOT_PASSWORD: from_secret: db_root_password From 49110b2e474da8dc08821d45958380e6871abcd5 Mon Sep 17 00:00:00 2001 From: dave Date: Thu, 28 Mar 2024 02:04:31 +0100 Subject: [PATCH 75/92] auth working --- src/DbContextLib/HeartTrackContext.cs | 14 ++- src/DbContextLib/Identity/AuthDbContext.cs | 25 ------ src/EFMappers/AthleteMappeur.cs | 12 +-- src/Entities/AthleteEntity.cs | 22 ++--- src/Entities/Entities.csproj | 10 +++ src/Entities2Dto/Entities2Dto.csproj | 6 ++ src/Entities2Dto/UserMappeur.cs | 18 ++-- .../Controllers/ActivityController.cs | 4 +- .../Controllers/AnalysisController.cs | 23 ++++- .../Controllers/UsersController.cs | 21 +---- src/HeartTrackAPI/HeartTrackAPI.csproj | 2 + src/HeartTrackAPI/Utils/AppBootstrap.cs | 88 ++++++++++++++----- src/HeartTrackAPI/appsettings.json | 7 +- src/Model2Entities/UserRepository.cs | 12 +-- .../AthleteStubbedContext.cs | 10 +-- src/Tests/ConsoleTestEntities/Program.cs | 36 ++++---- src/Tests/ConsoleTestRelationships/Program.cs | 12 +-- .../UnitTestsEntities/AthleteEntityTests.cs | 42 ++++----- .../FriendshipEntityTests.cs | 34 +++---- .../NotificationEntityTests.cs | 16 ++-- .../UnitTestsEntities/StatisticEntityTests.cs | 16 ++-- .../UnitTestsEntities/TrainingEntityTests.cs | 32 +++---- 22 files changed, 258 insertions(+), 204 deletions(-) delete mode 100644 src/DbContextLib/Identity/AuthDbContext.cs diff --git a/src/DbContextLib/HeartTrackContext.cs b/src/DbContextLib/HeartTrackContext.cs index 1cec4ca..a9c6ad7 100644 --- a/src/DbContextLib/HeartTrackContext.cs +++ b/src/DbContextLib/HeartTrackContext.cs @@ -7,6 +7,8 @@ //----------------------------------------------------------------------- using Entities; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; namespace DbContextLib @@ -14,7 +16,7 @@ namespace DbContextLib /// /// Represents the database context for the FitnessApp. /// - public class HeartTrackContext : DbContext + public class HeartTrackContext : IdentityDbContext,int> { /// /// Gets or sets the set of athletes. @@ -132,10 +134,10 @@ namespace DbContextLib //primary key of AthleteEntity modelBuilder.Entity() - .HasKey(at => at.IdAthlete); + .HasKey(at => at.Id); //generation mode (at insertion) modelBuilder.Entity() - .Property(at => at.IdAthlete) + .Property(at => at.Id) .ValueGeneratedOnAdd(); // add image column type // modelBuilder.Entity() @@ -234,6 +236,12 @@ namespace DbContextLib .WithOne(at => at.DataSource) .HasForeignKey(at => at.DataSourceId) .IsRequired(false); + List roles = new List + { + new ("Athlete"), + new ("Coach") + }; + modelBuilder.Entity().HasData(roles); } } } \ No newline at end of file diff --git a/src/DbContextLib/Identity/AuthDbContext.cs b/src/DbContextLib/Identity/AuthDbContext.cs deleted file mode 100644 index 89924a7..0000000 --- a/src/DbContextLib/Identity/AuthDbContext.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Entities; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Identity.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore; - -namespace DbContextLib.Identity; - -public class AuthDbContext: IdentityDbContext -{ - - public AuthDbContext(DbContextOptions options) : base(options) { } - public AuthDbContext() { } - /* - /// - /// Configures the database options if they are not already configured. - /// - /// The options builder instance. - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - if (!optionsBuilder.IsConfigured) - { - optionsBuilder.UseSqlite($"Data Source=uca.HeartTrack.db"); - } - }*/ -} \ No newline at end of file diff --git a/src/EFMappers/AthleteMappeur.cs b/src/EFMappers/AthleteMappeur.cs index 1cd39a8..f6a2198 100644 --- a/src/EFMappers/AthleteMappeur.cs +++ b/src/EFMappers/AthleteMappeur.cs @@ -13,14 +13,14 @@ public static class UserMappeur { Func create = athleteEntity => new User { - Id = athleteEntity.IdAthlete, + Id = athleteEntity.Id, FirstName = athleteEntity.FirstName, LastName = athleteEntity.LastName, Email = athleteEntity.Email, - MotDePasse = athleteEntity.Password, + MotDePasse = athleteEntity.PasswordHash, DateOfBirth = athleteEntity.DateOfBirth.ToDateTime(TimeOnly.MinValue), Sexe = athleteEntity.Sexe, - Username = athleteEntity.Username, + Username = athleteEntity.UserName, Weight = athleteEntity.Weight, Lenght = (float)athleteEntity.Length, ProfilePicture = athleteEntity.ProfilPicture, @@ -42,13 +42,13 @@ public static class UserMappeur { Func create = user => new AthleteEntity { - IdAthlete = user.Id, - Username = user.Username, + Id = user.Id, + UserName = user.Username, Sexe = user.Sexe, FirstName = user.FirstName, LastName = user.LastName, Email = user.Email, - Password = user.MotDePasse, + PasswordHash = user.MotDePasse, DateOfBirth = DateOnly.FromDateTime(user.DateOfBirth), IsCoach = user.Role is Coach, Weight = user.Weight, diff --git a/src/Entities/AthleteEntity.cs b/src/Entities/AthleteEntity.cs index 3b89fbe..7d1977d 100644 --- a/src/Entities/AthleteEntity.cs +++ b/src/Entities/AthleteEntity.cs @@ -8,56 +8,58 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.AspNetCore.Identity; namespace Entities { + //dentityRole,int /// /// Represents an athlete entity in the database. /// [Table("Athlete")] - public class AthleteEntity + public class AthleteEntity : IdentityUser { /// /// Gets or sets the unique identifier of the athlete. /// [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int IdAthlete { get; set; } + public override int Id { get; set; } /// /// Gets or sets the username of the athlete. /// [MaxLength(100)] [Required(ErrorMessage = "Athlete Username is ")] - public required string Username { get; set; } + public override string UserName { get; set; } /// /// Gets or sets the last name of the athlete. /// [MaxLength(100)] [Required(ErrorMessage = "Athlete Last Name is ")] - public required string LastName { get; set; } + public string LastName { get; set; } /// /// Gets or sets the first name of the athlete. /// [MaxLength(150)] [Required(ErrorMessage = "Athlete First Name is ")] - public required string FirstName { get; set; } + public string FirstName { get; set; } /// /// Gets or sets the email of the athlete. /// [MaxLength(100)] [Required(ErrorMessage = "Athlete Email is ")] - public required string Email { get; set; } + public override string Email { get; set; } /// /// Gets or sets the gender of the athlete. /// [MaxLength(1)] [Required(ErrorMessage = "Athlete Sexe is ")] - public required string Sexe { get; set; } + public string Sexe { get; set; } /// /// Gets or sets the height of the athlete. @@ -68,12 +70,12 @@ namespace Entities /// Gets or sets the weight of the athlete. /// public float Weight { get; set; } - +/* /// /// Gets or sets the password of the athlete. /// - [Required(ErrorMessage = "Athlete Password is ")] - public required string Password { get; set; } + [Required(ErrorMessage = "Athlete PasswordHash is ")] + public string PasswordHash { get; set; }*/ /// /// Gets or sets the date of birth of the athlete. diff --git a/src/Entities/Entities.csproj b/src/Entities/Entities.csproj index b007a4d..7fbb47d 100644 --- a/src/Entities/Entities.csproj +++ b/src/Entities/Entities.csproj @@ -5,4 +5,14 @@ enable enable + + + + + + + + ..\..\..\.nuget\packages\microsoft.extensions.identity.stores\8.0.2\lib\net8.0\Microsoft.Extensions.Identity.Stores.dll + + diff --git a/src/Entities2Dto/Entities2Dto.csproj b/src/Entities2Dto/Entities2Dto.csproj index e3d0baf..e879b8a 100644 --- a/src/Entities2Dto/Entities2Dto.csproj +++ b/src/Entities2Dto/Entities2Dto.csproj @@ -11,4 +11,10 @@ + + + ..\..\..\.nuget\packages\microsoft.extensions.identity.stores\8.0.2\lib\net8.0\Microsoft.Extensions.Identity.Stores.dll + + + diff --git a/src/Entities2Dto/UserMappeur.cs b/src/Entities2Dto/UserMappeur.cs index 71b2dcf..edc6b8c 100644 --- a/src/Entities2Dto/UserMappeur.cs +++ b/src/Entities2Dto/UserMappeur.cs @@ -21,14 +21,14 @@ public static class UserMappeur { Func create = athleteEntity => new UserTinyDto { - Id = athleteEntity.IdAthlete, + Id = athleteEntity.Id, FirstName = athleteEntity.FirstName, LastName = athleteEntity.LastName, Email = athleteEntity.Email, - Password = athleteEntity.Password, + Password = athleteEntity.PasswordHash, DateOfBirth = athleteEntity.DateOfBirth.ToDateTime(TimeOnly.MinValue), Sexe = athleteEntity.Sexe, - Username = athleteEntity.Username, + Username = athleteEntity.UserName, Weight = athleteEntity.Weight, Lenght = (float)athleteEntity.Length, ProfilePicture = athleteEntity.ProfilPicture ?? "", @@ -42,13 +42,13 @@ public static class UserMappeur { Func create = user => new AthleteEntity { - IdAthlete = user.Id, - Username = user.Username, + Id = user.Id, + UserName = user.Username, Sexe = user.Sexe, FirstName = user.FirstName, LastName = user.LastName, Email = user.Email, - Password = user.Password ?? "", + PasswordHash = user.Password ?? "", DateOfBirth = DateOnly.FromDateTime(user.DateOfBirth), IsCoach = user.IsCoach, Weight = user.Weight, @@ -63,14 +63,14 @@ public static class UserMappeur { Func creator = athleteEntity => new ResponseUserDto { - Id = athleteEntity.IdAthlete, + Id = athleteEntity.Id, FirstName = athleteEntity.FirstName, LastName = athleteEntity.LastName, Email = athleteEntity.Email, - Password = athleteEntity.Password, + Password = athleteEntity.PasswordHash, DateOfBirth = athleteEntity.DateOfBirth.ToDateTime(TimeOnly.MinValue), Sexe = athleteEntity.Sexe, - Username = athleteEntity.Username, + Username = athleteEntity.UserName, Weight = athleteEntity.Weight, Lenght = (float)athleteEntity.Length, ProfilePicture = athleteEntity.ProfilPicture ?? "", diff --git a/src/HeartTrackAPI/Controllers/ActivityController.cs b/src/HeartTrackAPI/Controllers/ActivityController.cs index 79f8654..40d5bc4 100644 --- a/src/HeartTrackAPI/Controllers/ActivityController.cs +++ b/src/HeartTrackAPI/Controllers/ActivityController.cs @@ -27,9 +27,9 @@ public class ActivityController : Controller } [HttpGet] - [ProducesResponseType(typeof(PageResponse), 200)] + [ProducesResponseType(typeof(PageResponse), 200)] [ProducesResponseType(400)] - [ProducesResponseType(500)] + [ProducesResponseType(500)] public async Task>> GetActivities([FromQuery] PageRequest pageRequest) { try diff --git a/src/HeartTrackAPI/Controllers/AnalysisController.cs b/src/HeartTrackAPI/Controllers/AnalysisController.cs index e4f9fcb..9a7d433 100644 --- a/src/HeartTrackAPI/Controllers/AnalysisController.cs +++ b/src/HeartTrackAPI/Controllers/AnalysisController.cs @@ -6,7 +6,7 @@ namespace HeartTrackAPI.Controllers; [ApiController] [ApiVersion("1.0")] [Route("api/[controller]")] -public class AnalysisController : ControllerBase +public class AnalysisController : Controller { private readonly List _heartRateZones = new() { @@ -34,8 +34,27 @@ public class AnalysisController : ControllerBase var secondsInZone = heartRates.Count(hr => hr.HeartRate >= zone.MinHeartRate && hr.HeartRate <= zone.MaxHeartRate); return TimeSpan.FromSeconds(secondsInZone); - } + } + /* + [HttpGet("getOptimizedPath")] + public IActionResult GetOptimizedPath(int activityId) + { + var heartRateData = GetMockHeartRateData(); + var sortedData = heartRateData.OrderBy(x => x.Timestamp).ToList(); + + var path = new GeoJsonPath(); + foreach (var item in sortedData) + { + if (item.Latitude.HasValue && item.Longitude.HasValue) + { + path.Coordinates.Add(new GeoJsonCoordinate(item.Longitude.Value, item.Latitude.Value)); + } + } + + return Ok(path.ToGeoJson()); + } +*/ private List GetMockHeartRateData() { var random = new Random(); diff --git a/src/HeartTrackAPI/Controllers/UsersController.cs b/src/HeartTrackAPI/Controllers/UsersController.cs index c7daf65..0463765 100644 --- a/src/HeartTrackAPI/Controllers/UsersController.cs +++ b/src/HeartTrackAPI/Controllers/UsersController.cs @@ -360,25 +360,6 @@ public class UsersController : Controller return Problem(); } }*/ - - /// - /// Déconnecte l'utilisateur actuel. - /// - /// Le gestionnaire de connexion. - /// Paramètre vide utilisé pour s'assurer que la requête provient bien d'un client. - /// Action result. - /// Déconnexion réussie. - /// Déconnexion non autorisée. - /// Erreur interne du serveur. - [HttpPost("logout")] - [ProducesResponseType(200)] - [ProducesResponseType(401)] - [ProducesResponseType(500)] - public async Task Logout(SignInManager signInManager, [FromBody] object? empty) - { - if (empty == null) return Unauthorized(); - await signInManager.SignOutAsync(); - return Ok(); - } + } \ No newline at end of file diff --git a/src/HeartTrackAPI/HeartTrackAPI.csproj b/src/HeartTrackAPI/HeartTrackAPI.csproj index e815c27..ab6b8d3 100644 --- a/src/HeartTrackAPI/HeartTrackAPI.csproj +++ b/src/HeartTrackAPI/HeartTrackAPI.csproj @@ -10,11 +10,13 @@ + + diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index e45e18f..22c75a5 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -1,11 +1,12 @@ using System.Reflection; using DbContextLib; -using DbContextLib.Identity; +using Entities; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.Versioning; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; using Model.Manager; using Model2Entities; @@ -20,14 +21,17 @@ public class AppBootstrap(IConfiguration configuration) public void ConfigureServices(IServiceCollection services) { + services.AddControllers(); + services.AddEndpointsApiExplorer(); AddSwagger(services); AddHeartTrackContextServices(services); AddModelService(services); - AddIdentityServices(services); + AddIdentityServices(services,configuration); AddApiVersioning(services); services.AddHealthChecks(); + } private void AddHeartTrackContextServices(IServiceCollection services) @@ -47,7 +51,6 @@ public class AppBootstrap(IConfiguration configuration) Console.WriteLine("========RUNNING USING THE MYSQL SERVER=============="); Console.WriteLine(connectionString); Console.WriteLine("===================================================="); - services.AddDbContext(options => options.UseInMemoryDatabase("AuthDb")); services.AddDbContext(options => options.UseMySql($"{connectionString}", new MySqlServerVersion(new Version(10, 11, 1))) , ServiceLifetime.Singleton); @@ -58,13 +61,11 @@ public class AppBootstrap(IConfiguration configuration) Console.WriteLine(connectionString); if (!string.IsNullOrWhiteSpace(connectionString)) { - services.AddDbContext(options => options.UseInMemoryDatabase("AuthDb")); services.AddDbContext(options => options.UseSqlite(connectionString), ServiceLifetime.Singleton); } else { - services.AddDbContext(options => options.UseInMemoryDatabase("AuthDb")); services.AddDbContext(); } break; @@ -94,14 +95,61 @@ public class AppBootstrap(IConfiguration configuration) } } - private void AddIdentityServices(IServiceCollection services) + private void AddIdentityServices(IServiceCollection services, IConfiguration config) { -// services.AddTransient, EmailSender>(); services.AddAuthorization(); + services.AddIdentityApiEndpoints() + .AddEntityFrameworkStores(); + + /*services.AddIdentity>(options => + { + options.PasswordHash.RequireDigit = true; + options.PasswordHash.RequireLowercase = true; + options.PasswordHash.RequireUppercase = true; + options.PasswordHash.RequireNonAlphanumeric = true; + options.PasswordHash.RequiredLength = 8; + + }) + .AddEntityFrameworkStores(); + + + services.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = + options.DefaultChallengeScheme = + options.DefaultForbidScheme = + options.DefaultScheme = + options.DefaultSignInScheme = + options.DefaultSignOutScheme = JwtBearerDefaults.AuthenticationScheme; + }).AddJwtBearer(options => + { + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuer = true, + //ValidIssuer =config["JWT:Issuer"], + ValidateAudience = true, + //ValidAudience = config["JWT:Audience"], + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey( + System.Text.Encoding.UTF8.GetBytes(config["JWT:SigningKey"]) + ) + }; + });*/ + + /* + app.UseCors(x => x + .AllowAnyMethod() + .AllowAnyHeader() + .AllowCredentials() + //.WithOrigins("https://localhost:44351)) + .SetIsOriginAllowed(origin => true));*/ - services.AddIdentityApiEndpoints() - .AddEntityFrameworkStores(); - // .AddEntityFrameworkStores().AddDefaultTokenProviders(); +// services.AddTransient, EmailSender>(); + // services.AddAuthorization(); + +// services.AddIdentityApiEndpoints() + // .AddEntityFrameworkStores(); + // .AddEntityFrameworkStores().AddDefaultTokenProviders(); } private void AddApiVersioning(IServiceCollection services) @@ -122,8 +170,6 @@ public class AppBootstrap(IConfiguration configuration) { services.AddSwaggerGen(options => { - options.OperationFilter(); - var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); options.IncludeXmlComments(xmlPath); @@ -155,28 +201,28 @@ public class AppBootstrap(IConfiguration configuration) }; options.AddSecurityRequirement(scheme); - }); - services.AddTransient, SwaggerOptions>(); - services.AddSwaggerGen(options => - { options.OperationFilter(); + }); - + //services.AddTransient, SwaggerOptions>(); + /* services.AddVersionedApiExplorer(setup => { setup.GroupNameFormat = "'v'VVV"; setup.SubstituteApiVersionInUrl = true; - }); + });*/ } public void Configure(WebApplication app, IWebHostEnvironment env) { app.UseHttpsRedirection(); - app.MapIdentityApi(); + + app.UseAuthentication(); + app.UseAuthorization(); + app.MapIdentityApi(); app.MapControllers(); - app.UseAuthorization(); app.MapHealthChecks("/health"); diff --git a/src/HeartTrackAPI/appsettings.json b/src/HeartTrackAPI/appsettings.json index 5fb6b3c..1178611 100644 --- a/src/HeartTrackAPI/appsettings.json +++ b/src/HeartTrackAPI/appsettings.json @@ -8,5 +8,10 @@ "AllowedHosts": "*", "ConnectionStrings": { "HeartTrackAuthConnection": "Data Source=uca_HeartTrack.db" - } + }, + "Jwt": { + "Issuer": "HeartTrack", + "Audience": "HeartTrack", + "SigningKey": "ThisIsMySuperKey" + } } diff --git a/src/Model2Entities/UserRepository.cs b/src/Model2Entities/UserRepository.cs index 264da22..51391c3 100644 --- a/src/Model2Entities/UserRepository.cs +++ b/src/Model2Entities/UserRepository.cs @@ -57,7 +57,7 @@ public partial class DbDataManager _logger.LogInformation($"GetItemById with id {id}", id); var userEntity = await _dataManager.DbContext.AthletesSet.IncludeStandardProperties() - .SingleOrDefaultAsync(a => a.IdAthlete == id); + .SingleOrDefaultAsync(a => a.Id == id); var user = userEntity != null ? userEntity.ToModel() : null; if (user != null) _logger.LogInformation($"Retrieved user with ID {id}"); @@ -95,7 +95,7 @@ public partial class DbDataManager { _logger.LogInformation($"GetTinyItemById with id {id}", id); var userEntity = await _dataManager.DbContext.AthletesSet.IncludeStandardProperties().Include(a => a.Followers).Include(a => a.Followings) - .SingleOrDefaultAsync(a => a.IdAthlete == id); + .SingleOrDefaultAsync(a => a.Id == id); var user = userEntity != null ? userEntity.ToResponseDto() : null; if (user != null) _logger.LogInformation($"Retrieved user with ID {id}"); @@ -199,7 +199,7 @@ public partial class DbDataManager var userEntity = _dataManager.DbContext.AthletesSet .Include(a => a.Followings) - .FirstOrDefault(a => a.IdAthlete == fromUser); + .FirstOrDefault(a => a.Id == fromUser); if (userEntity == null) { @@ -232,7 +232,7 @@ public partial class DbDataManager var userEntity = _dataManager.DbContext.AthletesSet .Include(a => a.Followings) - .FirstOrDefault(a => a.IdAthlete == fromUser); + .FirstOrDefault(a => a.Id == fromUser); if (userEntity == null) { @@ -265,7 +265,7 @@ public partial class DbDataManager var athlete = await _dataManager.DbContext.AthletesSet .Include(a => a.Followers).ThenInclude(f => f.Follower) .Include(a => a.Followings).ThenInclude(f => f.Following) - .FirstOrDefaultAsync(a => a.IdAthlete == userId); // Use async version for better performance + .FirstOrDefaultAsync(a => a.Id == userId); // Use async version for better performance if (athlete == null) { @@ -299,7 +299,7 @@ public partial class DbDataManager var athlete = await _dataManager.DbContext.AthletesSet .Include(a => a.Followers).ThenInclude(f => f.Follower) .Include(a => a.Followings).ThenInclude(f => f.Following) - .FirstOrDefaultAsync(a => a.IdAthlete == userId); + .FirstOrDefaultAsync(a => a.Id == userId); if (athlete == null) { diff --git a/src/StubbedContextLib/AthleteStubbedContext.cs b/src/StubbedContextLib/AthleteStubbedContext.cs index 3b69133..b87b4b4 100644 --- a/src/StubbedContextLib/AthleteStubbedContext.cs +++ b/src/StubbedContextLib/AthleteStubbedContext.cs @@ -42,11 +42,11 @@ namespace StubbedContextLib modelBuilder.Entity().HasData(picture); modelBuilder.Entity().HasData( - new AthleteEntity { IdAthlete = 1, Username = "Doe",ProfilPicture = picture2, ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}") ,LastName = "Doe", FirstName = "John", Email = "john.doe@example.com", Password = "password123", Sexe = "M", Length = 1.80, Weight = 75, DateOfBirth = new DateOnly(1990, 01, 01), IsCoach = true , DataSourceId = 1}, - new AthleteEntity { IdAthlete = 2, Username = "Smith",ProfilPicture = picture2,LastName = "Smith", FirstName = "Jane", Email = "jane.smith@exemple.com", Password = "secure456", Sexe = "F", Length = 1.65, Weight = 60, DateOfBirth = new DateOnly(1995, 01, 01), IsCoach = false, DataSourceId = 1 }, - new AthleteEntity { IdAthlete = 3, Username = "Martin",ProfilPicture = picture2,ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}") ,LastName = "Martin", FirstName = "Paul", Email = "paul.martin@example.com", Password = "super789", Sexe = "M", Length = 1.75, Weight = 68, DateOfBirth = new DateOnly(1992, 01, 01), IsCoach = true, DataSourceId = 1}, - new AthleteEntity { IdAthlete = 4, Username = "Brown",ProfilPicture = picture2, ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}"),LastName = "Brown", FirstName = "Anna", Email = "anna.brown@example.com", Password = "test000", Sexe = "F", Length = 1.70, Weight = 58, DateOfBirth = new DateOnly(1993, 01, 01), IsCoach = false, DataSourceId = 2 }, - new AthleteEntity { IdAthlete = 5, Username = "Lee", ProfilPicture = picture2, ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}"),LastName = "Lee", FirstName = "Bruce", Email = "bruce.lee@example.com", Password = "hello321", Sexe = "M", Length = 2.0, Weight = 90, DateOfBirth = new DateOnly(1991, 01, 01), IsCoach = false, DataSourceId = 3 } + new AthleteEntity { Id = 1, UserName = "Doe",ProfilPicture = picture2, ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}") ,LastName = "Doe", FirstName = "John", Email = "john.doe@example.com", PasswordHash = "password123", Sexe = "M", Length = 1.80, Weight = 75, DateOfBirth = new DateOnly(1990, 01, 01), IsCoach = true , DataSourceId = 1}, + new AthleteEntity { Id = 2, UserName = "Smith",ProfilPicture = picture2,LastName = "Smith", FirstName = "Jane", Email = "jane.smith@exemple.com", PasswordHash = "secure456", Sexe = "F", Length = 1.65, Weight = 60, DateOfBirth = new DateOnly(1995, 01, 01), IsCoach = false, DataSourceId = 1 }, + new AthleteEntity { Id = 3, UserName = "Martin",ProfilPicture = picture2,ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}") ,LastName = "Martin", FirstName = "Paul", Email = "paul.martin@example.com", PasswordHash = "super789", Sexe = "M", Length = 1.75, Weight = 68, DateOfBirth = new DateOnly(1992, 01, 01), IsCoach = true, DataSourceId = 1}, + new AthleteEntity { Id = 4, UserName = "Brown",ProfilPicture = picture2, ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}"),LastName = "Brown", FirstName = "Anna", Email = "anna.brown@example.com", PasswordHash = "test000", Sexe = "F", Length = 1.70, Weight = 58, DateOfBirth = new DateOnly(1993, 01, 01), IsCoach = false, DataSourceId = 2 }, + new AthleteEntity { Id = 5, UserName = "Lee", ProfilPicture = picture2, ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}"),LastName = "Lee", FirstName = "Bruce", Email = "bruce.lee@example.com", PasswordHash = "hello321", Sexe = "M", Length = 2.0, Weight = 90, DateOfBirth = new DateOnly(1991, 01, 01), IsCoach = false, DataSourceId = 3 } ); } } diff --git a/src/Tests/ConsoleTestEntities/Program.cs b/src/Tests/ConsoleTestEntities/Program.cs index 826f345..44bc88b 100644 --- a/src/Tests/ConsoleTestEntities/Program.cs +++ b/src/Tests/ConsoleTestEntities/Program.cs @@ -56,25 +56,25 @@ class Program foreach (var athlete in db.AthletesSet) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.Id} - {athlete.UserName}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); Console.WriteLine("Accès à l'athlete d'id '2' :"); Console.WriteLine("---------------------------------"); - foreach (var athlete in db.AthletesSet.Where(a => a.IdAthlete == 2)) + foreach (var athlete in db.AthletesSet.Where(a => a.Id == 2)) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.Id} - {athlete.UserName}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); Console.WriteLine("Accès à l'athlete de username 'Doe' :"); Console.WriteLine("---------------------------------"); - foreach (var athlete in db.AthletesSet.Where(a => a.Username == "Doe")) + foreach (var athlete in db.AthletesSet.Where(a => a.UserName == "Doe")) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.Id} - {athlete.UserName}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); @@ -83,7 +83,7 @@ class Program Console.WriteLine("---------------------------------"); foreach (var athlete in db.AthletesSet.Where(a => a.Sexe == "F")) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.Id} - {athlete.UserName}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); @@ -92,7 +92,7 @@ class Program Console.WriteLine("---------------------------------"); foreach (var athlete in db.AthletesSet.Where(a => a.Email == "bruce.lee@example.com")) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.Id} - {athlete.UserName}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); @@ -101,7 +101,7 @@ class Program Console.WriteLine("---------------------------------"); foreach (var athlete in db.AthletesSet.Where(a => a.Weight == 90)) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.Id} - {athlete.UserName}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); @@ -110,7 +110,7 @@ class Program Console.WriteLine("---------------------------------"); foreach (var athlete in db.AthletesSet.Where(a => a.Length == 1.80)) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.Id} - {athlete.UserName}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); @@ -119,7 +119,7 @@ class Program Console.WriteLine("---------------------------------"); foreach (var athlete in db.AthletesSet.Where(a => a.DateOfBirth == new DateOnly(1990, 01, 01))) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.Id} - {athlete.UserName}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); @@ -128,7 +128,7 @@ class Program Console.WriteLine("---------------------------------"); foreach (var athlete in db.AthletesSet.Where(a => a.LastName == "Martin")) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.Id} - {athlete.UserName}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); @@ -137,7 +137,7 @@ class Program Console.WriteLine("---------------------------------"); foreach (var athlete in db.AthletesSet.Where(a => a.FirstName == "Anna")) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.Id} - {athlete.UserName}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); @@ -146,7 +146,7 @@ class Program Console.WriteLine("---------------------------------"); foreach (var athlete in db.AthletesSet.Where(a => a.LastName == "Brown" && a.FirstName == "Anna")) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.Id} - {athlete.UserName}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); @@ -155,7 +155,7 @@ class Program Console.WriteLine("---------------------------------"); foreach (var athlete in db.AthletesSet.Where(a => a.IsCoach == true)) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.Id} - {athlete.UserName}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); @@ -755,7 +755,7 @@ class Program Console.WriteLine("Test d'ajout, de modification et de suppression des athletes :"); var picture = "https://davidalmeida.site/assets/me_avatar.f77af006.png"; // Ajout d'un nouveau livre - var newAthlete = new AthleteEntity { Username = "Doe", LastName = "Doe",ProfilPicture = picture,FirstName = "John", Email = "essaie.example.com", Password = "TheNewPassword", Sexe = "M", Length = 1.80, Weight = 90, DateOfBirth = new DateOnly(2024, 02, 22), IsCoach = false }; + var newAthlete = new AthleteEntity { UserName = "Doe", LastName = "Doe",ProfilPicture = picture,FirstName = "John", Email = "essaie.example.com", PasswordHash = "TheNewPassword", Sexe = "M", Length = 1.80, Weight = 90, DateOfBirth = new DateOnly(2024, 02, 22), IsCoach = false }; db.AthletesSet.Add(newAthlete); db.SaveChanges(); @@ -763,7 +763,7 @@ class Program Console.WriteLine("Athlete après ajout :"); foreach (var athlete in db.AthletesSet) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.Id} - {athlete.UserName}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } // Modification du titre du nouveau livre @@ -774,7 +774,7 @@ class Program Console.WriteLine("Livres après modification :"); foreach (var athlete in db.AthletesSet) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.Id} - {athlete.UserName}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } // Suppression du nouveau livre @@ -785,7 +785,7 @@ class Program Console.WriteLine("Livres après suppression :"); foreach (var athlete in db.AthletesSet) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.Id} - {athlete.UserName}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } } diff --git a/src/Tests/ConsoleTestRelationships/Program.cs b/src/Tests/ConsoleTestRelationships/Program.cs index fa9797e..5ff197e 100644 --- a/src/Tests/ConsoleTestRelationships/Program.cs +++ b/src/Tests/ConsoleTestRelationships/Program.cs @@ -96,7 +96,7 @@ class Program foreach (var athlete in dataSource.Athletes) { - Console.WriteLine($"\t\t\t{athlete.IdAthlete} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); + Console.WriteLine($"\t\t\t{athlete.Id} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); } } @@ -122,7 +122,7 @@ class Program foreach (var athlete in dataSource.Athletes) { - Console.WriteLine($"\t\t\t{athlete.IdAthlete} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); + Console.WriteLine($"\t\t\t{athlete.Id} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); } } @@ -138,7 +138,7 @@ class Program foreach (var athlete in db.AthletesSet.Include(a => a.Statistics).Include(a => a.Activities).Include(a => a.TrainingsAthlete).Include(a => a.NotificationsSent).Include(a => a.DataSource).Include(a => a.TrainingsCoach).Include(a => a.NotificationsReceived)) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.Id} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); Console.WriteLine("\t\tStatistiques :"); Console.WriteLine("\t\t---------------------------------"); @@ -199,9 +199,9 @@ class Program Console.WriteLine("Accès à l'athlète d'id '2' :"); Console.WriteLine("---------------------------------"); - foreach (var athlete in db.AthletesSet.Where(a => a.IdAthlete == 2).Include(a => a.Statistics).Include(a => a.Activities).Include(a => a.TrainingsAthlete).Include(a => a.NotificationsSent).Include(a => a.DataSource).Include(a => a.TrainingsCoach).Include(a => a.NotificationsReceived)) + foreach (var athlete in db.AthletesSet.Where(a => a.Id == 2).Include(a => a.Statistics).Include(a => a.Activities).Include(a => a.TrainingsAthlete).Include(a => a.NotificationsSent).Include(a => a.DataSource).Include(a => a.TrainingsCoach).Include(a => a.NotificationsReceived)) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.Id} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); Console.WriteLine("\t\tStatistiques :"); Console.WriteLine("\t\t---------------------------------"); @@ -269,7 +269,7 @@ class Program foreach (var athlete in db.AthletesSet.Include(f => f.Followers).Include(f => f.Followings)) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.Id} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); Console.WriteLine($""); Console.WriteLine($""); diff --git a/src/Tests/UnitTestsEntities/AthleteEntityTests.cs b/src/Tests/UnitTestsEntities/AthleteEntityTests.cs index 1f67d03..2bced05 100644 --- a/src/Tests/UnitTestsEntities/AthleteEntityTests.cs +++ b/src/Tests/UnitTestsEntities/AthleteEntityTests.cs @@ -12,14 +12,14 @@ public class AthleteEntityTests (DatabaseFixture fixture) : IClassFixture a.Username == "john_doe"); + var savedAthlete = context.AthletesSet.First(a => a.UserName == "john_doe"); Assert.NotNull(savedAthlete); - Assert.Equal("john_doe", savedAthlete.Username); + Assert.Equal("john_doe", savedAthlete.UserName); } } @@ -47,14 +47,14 @@ public class AthleteEntityTests (DatabaseFixture fixture) : IClassFixture a.Username == "jane_smith"); - savedAthlete.Username = "jane_doe"; + var savedAthlete = context.AthletesSet.First(a => a.UserName == "jane_smith"); + savedAthlete.UserName = "jane_doe"; context.SaveChanges(); } using (var context = new TrainingStubbedContext(fixture._options)) { - var updatedAthlete = context.AthletesSet.First(a => a.Username == "jane_doe"); + var updatedAthlete = context.AthletesSet.First(a => a.UserName == "jane_doe"); Assert.NotNull(updatedAthlete); - Assert.Equal("jane_doe", updatedAthlete.Username); + Assert.Equal("jane_doe", updatedAthlete.UserName); Assert.Equal("Smith", updatedAthlete.LastName); } } @@ -89,14 +89,14 @@ public class AthleteEntityTests (DatabaseFixture fixture) : IClassFixture a.Username == "test_user"); + var savedAthlete = context.AthletesSet.First(a => a.UserName == "test_user"); context.AthletesSet.Remove(savedAthlete); context.SaveChanges(); } using (var context = new TrainingStubbedContext(fixture._options)) { - var deletedAthlete = context.AthletesSet.FirstOrDefault(a => a.Username == "test_user"); + var deletedAthlete = context.AthletesSet.FirstOrDefault(a => a.UserName == "test_user"); Assert.Null(deletedAthlete); } } @@ -128,14 +128,14 @@ public class AthleteEntityTests (DatabaseFixture fixture) : IClassFixture a.Username == "john_doe"); + var savedAthlete = context.AthletesSet.First(a => a.UserName == "john_doe"); Assert.NotNull(savedAthlete); - Assert.Equal("john_doe", savedAthlete.Username); + Assert.Equal("john_doe", savedAthlete.UserName); Assert.Equal("Doe", savedAthlete.LastName); Assert.Equal("John", savedAthlete.FirstName); Assert.Equal("john.doe@example.com", savedAthlete.Email); Assert.Equal("M", savedAthlete.Sexe); Assert.Equal(180.0, savedAthlete.Length); Assert.Equal(75.5f, savedAthlete.Weight); - Assert.Equal("password", savedAthlete.Password); + Assert.Equal("password", savedAthlete.PasswordHash); Assert.Equal(new DateOnly(1990, 1, 1), savedAthlete.DateOfBirth); Assert.False(savedAthlete.IsCoach); } @@ -170,14 +170,14 @@ public class AthleteEntityTests (DatabaseFixture fixture) : IClassFixture a.Followers).Include(a => a.Followings).FirstOrDefault(a => a.Username == "follower_user1").Followings.FirstOrDefault(f => f.FollowerId == follower.IdAthlete && f.FollowingId == following.IdAthlete); + var savedFriendship = context.AthletesSet.Include(a => a.Followers).Include(a => a.Followings).FirstOrDefault(a => a.UserName == "follower_user1").Followings.FirstOrDefault(f => f.FollowerId == follower.Id && f.FollowingId == following.Id); Assert.NotNull(savedFriendship); if (savedFriendship != null) { - Assert.Equal(follower.IdAthlete, savedFriendship.FollowerId); - Assert.Equal(following.IdAthlete, savedFriendship.FollowingId); + Assert.Equal(follower.Id, savedFriendship.FollowerId); + Assert.Equal(following.Id, savedFriendship.FollowingId); } } } @@ -79,42 +79,42 @@ public class FriendshipEntityTests (DatabaseFixture fixture) : IClassFixture Date: Thu, 28 Mar 2024 04:29:54 +0100 Subject: [PATCH 76/92] seems to work not tested for the moment --- src/DbContextLib/HeartTrackContext.cs | 23 +++-- src/Dto/Auth/AuthResponseDto.cs | 23 +++++ src/Dto/Auth/RegisterRequestDto.cs | 33 +++++++ .../Controllers/ActivityController.cs | 3 + .../Controllers/AnalysisController.cs | 2 + .../Controllers/UsersController.cs | 1 + src/HeartTrackAPI/Services/TokenService.cs | 48 ++++++++++ src/HeartTrackAPI/Utils/AppBootstrap.cs | 93 ++++++++++--------- src/HeartTrackAPI/appsettings.json | 4 +- 9 files changed, 176 insertions(+), 54 deletions(-) create mode 100644 src/Dto/Auth/AuthResponseDto.cs create mode 100644 src/Dto/Auth/RegisterRequestDto.cs create mode 100644 src/HeartTrackAPI/Services/TokenService.cs diff --git a/src/DbContextLib/HeartTrackContext.cs b/src/DbContextLib/HeartTrackContext.cs index a9c6ad7..8001980 100644 --- a/src/DbContextLib/HeartTrackContext.cs +++ b/src/DbContextLib/HeartTrackContext.cs @@ -236,12 +236,23 @@ namespace DbContextLib .WithOne(at => at.DataSource) .HasForeignKey(at => at.DataSourceId) .IsRequired(false); - List roles = new List - { - new ("Athlete"), - new ("Coach") - }; - modelBuilder.Entity().HasData(roles); + List> roles = + [ + new() + { + Id = 1, + Name = "Athlete", + NormalizedName = "ATHLETE" + }, + + new() + { + Id = 2, + Name = "Coach", + NormalizedName = "COACH" + } + ]; + modelBuilder.Entity>().HasData(roles); } } } \ No newline at end of file diff --git a/src/Dto/Auth/AuthResponseDto.cs b/src/Dto/Auth/AuthResponseDto.cs new file mode 100644 index 0000000..7cab2a4 --- /dev/null +++ b/src/Dto/Auth/AuthResponseDto.cs @@ -0,0 +1,23 @@ +namespace Dto.Auth; + +public class AuthResponseDto +{ + /// + /// Gets or sets the access token issued by the OAuth provider. + /// + public string AccessToken { get; set; } + + /// Gets or sets the token type. + /// Typically the string “bearer”. + public string? TokenType { get; set; } + + /// + /// Gets or sets a refresh token that applications can use to obtain another access token if tokens can expire. + /// + public string? RefreshToken { get; set; } + + /// + /// Gets or sets the validatity lifetime of the token in seconds. + /// + public string? ExpiresIn { get; set; } +} \ No newline at end of file diff --git a/src/Dto/Auth/RegisterRequestDto.cs b/src/Dto/Auth/RegisterRequestDto.cs new file mode 100644 index 0000000..ccd837e --- /dev/null +++ b/src/Dto/Auth/RegisterRequestDto.cs @@ -0,0 +1,33 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dto.Auth; + +public class RegisterRequestDto +{ + + [MaxLength(100)] + [Required(ErrorMessage = "Username is required")] + public string Username { get; set; } + [MaxLength(150)] + [Required(ErrorMessage = "LastName is required")] + public string LastName { get; set; } + [MaxLength(100)] + [Required(ErrorMessage = "FirstName is required")] + public string FirstName { get; set; } + [Required(ErrorMessage = "Email is required")] + [EmailAddress] + public string Email { get; set; } + [Required(ErrorMessage = "Sexe is required")] + public string Sexe { get; set; } + [Required(ErrorMessage = "Size is required")] + public float Size { get; set; } + [Required(ErrorMessage = "Weight is required")] + public float Weight { get; set; } + [Required(ErrorMessage = "Password is required")] + public string Password { get; set; } + [Required(ErrorMessage = "DateOfBirth is required")] + public DateTime DateOfBirth { get; set; } + public string ProfilePicture { get; set; } = "https://davidalmeida.site/assets/me_avatar.f77af006.png"; + [Required(ErrorMessage = "Role is required")] + public bool IsCoach { get; set; } +} \ No newline at end of file diff --git a/src/HeartTrackAPI/Controllers/ActivityController.cs b/src/HeartTrackAPI/Controllers/ActivityController.cs index 40d5bc4..f117dfb 100644 --- a/src/HeartTrackAPI/Controllers/ActivityController.cs +++ b/src/HeartTrackAPI/Controllers/ActivityController.cs @@ -3,6 +3,7 @@ using Dto; using Dto.Tiny; using HeartTrackAPI.Request; using HeartTrackAPI.Responce; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Shared; using Model.Manager; @@ -12,6 +13,8 @@ namespace HeartTrackAPI.Controllers; [ApiController] [ApiVersion("1.0")] [Route("api/v{version:apiVersion}/[controller]")] +[Authorize] + public class ActivityController : Controller { private readonly IActivityRepository _activityService; diff --git a/src/HeartTrackAPI/Controllers/AnalysisController.cs b/src/HeartTrackAPI/Controllers/AnalysisController.cs index 9a7d433..11c3be3 100644 --- a/src/HeartTrackAPI/Controllers/AnalysisController.cs +++ b/src/HeartTrackAPI/Controllers/AnalysisController.cs @@ -1,4 +1,5 @@ using Dto.Tiny; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace HeartTrackAPI.Controllers; @@ -6,6 +7,7 @@ namespace HeartTrackAPI.Controllers; [ApiController] [ApiVersion("1.0")] [Route("api/[controller]")] +[Authorize] public class AnalysisController : Controller { private readonly List _heartRateZones = new() diff --git a/src/HeartTrackAPI/Controllers/UsersController.cs b/src/HeartTrackAPI/Controllers/UsersController.cs index 0463765..6f74657 100644 --- a/src/HeartTrackAPI/Controllers/UsersController.cs +++ b/src/HeartTrackAPI/Controllers/UsersController.cs @@ -20,6 +20,7 @@ namespace HeartTrackAPI.Controllers; [ApiController] [ApiVersion("1.0")] [Route("api/v{version:apiVersion}/[controller]")] +[Authorize] public class UsersController : Controller { private readonly ILogger _logger; diff --git a/src/HeartTrackAPI/Services/TokenService.cs b/src/HeartTrackAPI/Services/TokenService.cs new file mode 100644 index 0000000..c2ce989 --- /dev/null +++ b/src/HeartTrackAPI/Services/TokenService.cs @@ -0,0 +1,48 @@ +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; +using Entities; +using Microsoft.IdentityModel.Tokens; + +namespace HeartTrackAPI.Services; +public interface ITokenService +{ + string CreateToken(AthleteEntity user); +} + +public class TokenService : ITokenService +{ + private readonly IConfiguration _config; + private readonly SymmetricSecurityKey _key; + + public TokenService(IConfiguration config) + { + _config = config; + _key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["JWT:SigningKey"])); + } + public string CreateToken(AthleteEntity user) + { + var claims = new List + { + new (JwtRegisteredClaimNames.Email, user.Email), + new (JwtRegisteredClaimNames.GivenName, user.UserName) + }; + + var creds = new SigningCredentials(_key, SecurityAlgorithms.HmacSha512Signature); + + var tokenDescriptor = new SecurityTokenDescriptor + { + Subject = new ClaimsIdentity(claims), + Expires = DateTime.Now.AddDays(7), + SigningCredentials = creds, + Issuer = _config["JWT:Issuer"], + Audience = _config["JWT:Audience"] + }; + + var tokenHandler = new JwtSecurityTokenHandler(); + + var token = tokenHandler.CreateToken(tokenDescriptor); + + return tokenHandler.WriteToken(token); + } +} \ No newline at end of file diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 22c75a5..6ad72db 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -1,6 +1,7 @@ using System.Reflection; using DbContextLib; using Entities; +using HeartTrackAPI.Services; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc.Versioning; @@ -15,28 +16,27 @@ using StubbedContextLib; using Swashbuckle.AspNetCore.SwaggerGen; namespace HeartTrackAPI.Utils; + public class AppBootstrap(IConfiguration configuration) { private IConfiguration Configuration { get; } = configuration; public void ConfigureServices(IServiceCollection services) { - services.AddControllers(); - + services.AddEndpointsApiExplorer(); AddSwagger(services); AddHeartTrackContextServices(services); AddModelService(services); - AddIdentityServices(services,configuration); + AddIdentityServices(services, configuration); AddApiVersioning(services); services.AddHealthChecks(); - } private void AddHeartTrackContextServices(IServiceCollection services) { - string? connectionString; + string? connectionString; switch (Environment.GetEnvironmentVariable("TYPE")) { @@ -52,8 +52,8 @@ public class AppBootstrap(IConfiguration configuration) Console.WriteLine(connectionString); Console.WriteLine("===================================================="); services.AddDbContext(options => - options.UseMySql($"{connectionString}", new MySqlServerVersion(new Version(10, 11, 1))) - , ServiceLifetime.Singleton); + options.UseMySql($"{connectionString}", new MySqlServerVersion(new Version(10, 11, 1))) + , ServiceLifetime.Singleton); break; default: Console.WriteLine("====== RUNNING USING THE IN SQLITE DATABASE ======"); @@ -68,17 +68,18 @@ public class AppBootstrap(IConfiguration configuration) { services.AddDbContext(); } + break; - } } - + private void AddModelService(IServiceCollection services) { switch (Environment.GetEnvironmentVariable("TYPE")) { case "BDD": - services.AddSingleton(provider => new DbDataManager(provider.GetRequiredService())); + services.AddSingleton(provider => + new DbDataManager(provider.GetRequiredService())); break; case "STUB-MODEL": services.AddSingleton(); @@ -93,26 +94,28 @@ public class AppBootstrap(IConfiguration configuration) // services.AddSingleton(provider => new DbDataManager(provider.GetRequiredService())); break; } + // Auth + + services.AddScoped(); } private void AddIdentityServices(IServiceCollection services, IConfiguration config) { - services.AddAuthorization(); + /*services.AddAuthorization(); services.AddIdentityApiEndpoints() - .AddEntityFrameworkStores(); + .AddEntityFrameworkStores();*/ - /*services.AddIdentity>(options => + services.AddIdentity>(options => { - options.PasswordHash.RequireDigit = true; - options.PasswordHash.RequireLowercase = true; - options.PasswordHash.RequireUppercase = true; - options.PasswordHash.RequireNonAlphanumeric = true; - options.PasswordHash.RequiredLength = 8; - + options.Password.RequireDigit = true; + options.Password.RequireLowercase = true; + options.Password.RequireUppercase = true; + options.Password.RequireNonAlphanumeric = true; + options.Password.RequiredLength = 8; }) - .AddEntityFrameworkStores(); - - + .AddEntityFrameworkStores(); + + services.AddAuthentication(options => { options.DefaultAuthenticateScheme = @@ -126,16 +129,16 @@ public class AppBootstrap(IConfiguration configuration) options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, - //ValidIssuer =config["JWT:Issuer"], + ValidIssuer =config["JWT:Issuer"], ValidateAudience = true, - //ValidAudience = config["JWT:Audience"], + ValidAudience = config["JWT:Audience"], ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey( System.Text.Encoding.UTF8.GetBytes(config["JWT:SigningKey"]) ) }; - });*/ - + }); + /* app.UseCors(x => x .AllowAnyMethod() @@ -151,10 +154,9 @@ public class AppBootstrap(IConfiguration configuration) // .AddEntityFrameworkStores(); // .AddEntityFrameworkStores().AddDefaultTokenProviders(); } - + private void AddApiVersioning(IServiceCollection services) { - services.AddApiVersioning(opt => { opt.ReportApiVersions = true; @@ -164,8 +166,8 @@ public class AppBootstrap(IConfiguration configuration) new HeaderApiVersionReader("x-api-version"), new MediaTypeApiVersionReader("x-api-version")); }); - } + private void AddSwagger(IServiceCollection services) { services.AddSwaggerGen(options => @@ -173,14 +175,16 @@ public class AppBootstrap(IConfiguration configuration) var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); options.IncludeXmlComments(xmlPath); - + options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", Name = "Authorization", In = ParameterLocation.Header, - Type = SecuritySchemeType.ApiKey + Type = SecuritySchemeType.Http, + Scheme = "Bearer", + BearerFormat = "JWT" }); var scheme = new OpenApiSecurityRequirement { @@ -199,33 +203,32 @@ public class AppBootstrap(IConfiguration configuration) new List() } }; - + options.AddSecurityRequirement(scheme); options.OperationFilter(); - }); - //services.AddTransient, SwaggerOptions>(); - /* + services.AddTransient, SwaggerOptions>(); + services.AddVersionedApiExplorer(setup => { setup.GroupNameFormat = "'v'VVV"; setup.SubstituteApiVersionInUrl = true; - });*/ - + }); } public void Configure(WebApplication app, IWebHostEnvironment env) { app.UseHttpsRedirection(); - + app.UseAuthentication(); app.UseAuthorization(); - app.MapIdentityApi(); + +// app.MapIdentityApi(); app.MapControllers(); app.MapHealthChecks("/health"); - + // Configure the HTTP request pipeline. if (true) { @@ -233,13 +236,12 @@ public class AppBootstrap(IConfiguration configuration) { options.PreSerializeFilters.Add((swagger, httpReq) => { - if (httpReq.Headers.ContainsKey("X-Forwarded-Host")) { string basePath; switch (Environment.GetEnvironmentVariable("TYPE")) // httpReq.Host.Value { - case "STUB" : + case "STUB": basePath = "containers/HeartDev-heart_stub"; break; case "BDD": @@ -249,15 +251,14 @@ public class AppBootstrap(IConfiguration configuration) basePath = httpReq.Host.Value; break; } + var serverUrl = $"https://{httpReq.Headers["X-Forwarded-Host"]}/{basePath}"; - swagger.Servers = new List { new() { Url = serverUrl } }; + swagger.Servers = new List { new() { Url = serverUrl } }; } }); }); app.UseSwaggerUI(); app.MapSwagger(); } - - } -} +} \ No newline at end of file diff --git a/src/HeartTrackAPI/appsettings.json b/src/HeartTrackAPI/appsettings.json index 1178611..17437fa 100644 --- a/src/HeartTrackAPI/appsettings.json +++ b/src/HeartTrackAPI/appsettings.json @@ -9,9 +9,9 @@ "ConnectionStrings": { "HeartTrackAuthConnection": "Data Source=uca_HeartTrack.db" }, - "Jwt": { + "JWT": { "Issuer": "HeartTrack", "Audience": "HeartTrack", - "SigningKey": "ThisIsMySuperKey" + "SigningKey": "jythgfbhtgdfytrhdgfythrydfghtrydfythrjgfytjgfjkhljkloijijlijoukhjuhygyhdhcesxeqaewxsfcgevfbtgjnh61689346843njfdvcgdv" } } From 0ae475613cb1456de621858171b68fe83d9143e4 Mon Sep 17 00:00:00 2001 From: dave Date: Thu, 28 Mar 2024 04:35:42 +0100 Subject: [PATCH 77/92] normally fix conditional for auth --- src/HeartTrackAPI/Utils/AppBootstrap.cs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs index 6ad72db..e15d89f 100644 --- a/src/HeartTrackAPI/Utils/AppBootstrap.cs +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -105,16 +105,23 @@ public class AppBootstrap(IConfiguration configuration) services.AddIdentityApiEndpoints() .AddEntityFrameworkStores();*/ - services.AddIdentity>(options => - { - options.Password.RequireDigit = true; - options.Password.RequireLowercase = true; - options.Password.RequireUppercase = true; - options.Password.RequireNonAlphanumeric = true; - options.Password.RequiredLength = 8; - }) - .AddEntityFrameworkStores(); + var identityBuilder = services.AddIdentity>(options => + { + options.Password.RequireDigit = true; + options.Password.RequireLowercase = true; + options.Password.RequireUppercase = true; + options.Password.RequireNonAlphanumeric = true; + options.Password.RequiredLength = 8; + }); + if (Environment.GetEnvironmentVariable("TYPE") == "BDD") + { + identityBuilder.AddEntityFrameworkStores(); + } + else + { + identityBuilder.AddEntityFrameworkStores(); + } services.AddAuthentication(options => { From d13cae449b797bd2ddeebdb2c750ccb151078da3 Mon Sep 17 00:00:00 2001 From: dave Date: Thu, 28 Mar 2024 04:36:35 +0100 Subject: [PATCH 78/92] add missing file --- src/Dto/Auth/AuthRequest.cs | 13 ++ .../Controllers/AuthController.cs | 152 ++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 src/Dto/Auth/AuthRequest.cs create mode 100644 src/HeartTrackAPI/Controllers/AuthController.cs diff --git a/src/Dto/Auth/AuthRequest.cs b/src/Dto/Auth/AuthRequest.cs new file mode 100644 index 0000000..af99599 --- /dev/null +++ b/src/Dto/Auth/AuthRequest.cs @@ -0,0 +1,13 @@ + +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; + +namespace Dto.Auth; + +public class LoginRequestDto +{ + [Required(ErrorMessage = "Username is required")] + public string Username { get; set; } + [Required(ErrorMessage = "Password is required")] + public string Password { get; set; } +} diff --git a/src/HeartTrackAPI/Controllers/AuthController.cs b/src/HeartTrackAPI/Controllers/AuthController.cs new file mode 100644 index 0000000..3b796a0 --- /dev/null +++ b/src/HeartTrackAPI/Controllers/AuthController.cs @@ -0,0 +1,152 @@ +using System.Globalization; +using Dto.Auth; +using Dto.Tiny; +using Entities; +using HeartTrackAPI.Request; +using HeartTrackAPI.Services; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace HeartTrackAPI.Controllers; +[ApiController] +public class AuthController : Controller +{ + + private readonly UserManager _userManager; + private readonly ITokenService _tokenService; + private readonly SignInManager _signinManager; + + public AuthController(UserManager userManager,ITokenService tokenService, SignInManager signinManager) + { + _userManager = userManager; + _tokenService = tokenService; + _signinManager = signinManager; + } + [HttpPost("login")] + public async Task Login(LoginRequestDto loginDto) + { + if (!ModelState.IsValid) + return BadRequest(ModelState); + + var user = await _userManager.Users.FirstOrDefaultAsync(x => x.UserName == loginDto.Username.ToLower()); + + if (user == null) return Unauthorized("Invalid username!"); + + var result = await _signinManager.CheckPasswordSignInAsync(user, loginDto.Password, false); + + if (!result.Succeeded) return Unauthorized("Username not found and/or password incorrect"); + + return Ok(new AuthResponseDto + { + AccessToken = _tokenService.CreateToken(user), + ExpiresIn = DateTime.Now.AddDays(7).ToString(CultureInfo.InvariantCulture), + TokenType = "Bearer" + } + ); + } + + [HttpPost("register")] + public async Task Register([FromBody] RegisterRequestDto request) + { + try + { + if (!ModelState.IsValid) + return BadRequest(ModelState); + // just for testing + // the good way is to use the repository and give him the userManager + var user = new AthleteEntity + { + Email = request.Email, + UserName = request.Username, + LastName = request.LastName, + FirstName = request.FirstName, + Sexe = request.Sexe, + Length = request.Size, + Weight = request.Weight, + DateOfBirth = DateOnly.FromDateTime(request.DateOfBirth), + IsCoach = request.IsCoach + }; + var createdUser = _userManager.CreateAsync(user, request.Password).Result; + if (createdUser.Succeeded) + { + var roleResult = await _userManager.AddToRoleAsync(user, request.IsCoach ? "Coach" : "Athlete"); + if (roleResult.Succeeded) + { + return Ok( + new AuthResponseDto + { + AccessToken = _tokenService.CreateToken(user), + ExpiresIn = DateTime.Now.AddDays(7).ToString(), + TokenType = "Bearer" + } + ); + } + { + return StatusCode(500, roleResult.Errors); + } + } + { + return StatusCode(500, createdUser.Errors); + } + } + catch (Exception e) + { + return StatusCode(500, e.Message); + } + + + /* var user = _userRepository.GetByEmail(request.Email); + if (user != null) + { + return BadRequest("User already exists"); + } + var newUser = new User + { + Email = request.Email, + PasswordHash = BCrypt.Net.BCrypt.HashPassword(request.PasswordHash), + FirstName = request.FirstName, + LastName = request.LastName + }; + _userRepository.Add(newUser); + return Ok();*/ + } + /* + [HttpPost("refresh")] + public IActionResult Refresh([FromBody] RefreshRequest request) + { + var user = _userRepository.GetByEmail(request.Email); + if (user == null) + { + return Unauthorized(); + } + if (!BCrypt.Net.BCrypt.Verify(request.PasswordHash, user.PasswordHash)) + { + return Unauthorized(); + } + var token = _jwtService.GenerateToken(user); + return Ok(new { token }); + } + */ + [HttpPost("logout")] + public IActionResult Logout() + { + return Ok(); + } + /* + + [HttpPost("forgot-password")] + public IActionResult ForgotPassword([FromBody] ForgotPasswordRequest request) + { + var user = _userRepository.GetByEmail(request.Email); + if (user == null) + { + return BadRequest("User not found"); + } + var token = _jwtService.GenerateToken(user); + // send email with token + return Ok(); + }*/ + + +} \ No newline at end of file From c5fd7c16a051e61272d37bf5e4e63048affdab91 Mon Sep 17 00:00:00 2001 From: dave Date: Thu, 28 Mar 2024 04:53:00 +0100 Subject: [PATCH 79/92] fix deps --- src/Entities/Entities.csproj | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Entities/Entities.csproj b/src/Entities/Entities.csproj index 7fbb47d..86792f8 100644 --- a/src/Entities/Entities.csproj +++ b/src/Entities/Entities.csproj @@ -8,11 +8,7 @@ + - - - - ..\..\..\.nuget\packages\microsoft.extensions.identity.stores\8.0.2\lib\net8.0\Microsoft.Extensions.Identity.Stores.dll - - + From 9cddc063436a86c4679c0befa8c46730dabacd2c Mon Sep 17 00:00:00 2001 From: dave Date: Thu, 28 Mar 2024 04:48:09 +0100 Subject: [PATCH 80/92] minor update (sexe string to char) --- src/Dto/AthleteDto.cs | 2 +- src/Dto/Auth/RegisterRequestDto.cs | 2 +- src/Dto/ResponseUserDto.cs | 2 +- src/Dto/Tiny/UserTinyDto.cs | 2 +- src/Entities/AthleteEntity.cs | 2 +- src/Model/User.cs | 4 ++-- src/StubAPI/AthleteService.cs | 6 +++--- src/StubbedContextLib/AthleteStubbedContext.cs | 10 +++++----- src/Tests/ConsoleTestEntities/Program.cs | 4 ++-- .../Controllers/UsersControllerTest.cs | 6 +++--- .../UnitTestsEntities/AthleteEntityTests.cs | 12 ++++++------ .../UnitTestsEntities/FriendshipEntityTests.cs | 14 +++++++------- .../UnitTestsEntities/NotificationEntityTests.cs | 8 ++++---- .../UnitTestsEntities/StatisticEntityTests.cs | 8 ++++---- .../UnitTestsEntities/TrainingEntityTests.cs | 16 ++++++++-------- src/Tests/UnitTestsModel/AthleteTest.cs | 4 ++-- src/Tests/UnitTestsModel/RoleTest.cs | 2 +- src/Tests/UnitTestsModel/UserTest.cs | 2 +- 18 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/Dto/AthleteDto.cs b/src/Dto/AthleteDto.cs index d5c94c0..be49bf5 100644 --- a/src/Dto/AthleteDto.cs +++ b/src/Dto/AthleteDto.cs @@ -12,7 +12,7 @@ public class UserDto [MaxLength(100)] public required string FirstName { get; set; } public required string Email { get; set; } - public required string Sexe { get; set; } + public required char Sexe { get; set; } public float Lenght { get; set; } public float Weight { get; set; } public string? Password { get; set; } diff --git a/src/Dto/Auth/RegisterRequestDto.cs b/src/Dto/Auth/RegisterRequestDto.cs index ccd837e..c6af1ab 100644 --- a/src/Dto/Auth/RegisterRequestDto.cs +++ b/src/Dto/Auth/RegisterRequestDto.cs @@ -18,7 +18,7 @@ public class RegisterRequestDto [EmailAddress] public string Email { get; set; } [Required(ErrorMessage = "Sexe is required")] - public string Sexe { get; set; } + public char Sexe { get; set; } [Required(ErrorMessage = "Size is required")] public float Size { get; set; } [Required(ErrorMessage = "Weight is required")] diff --git a/src/Dto/ResponseUserDto.cs b/src/Dto/ResponseUserDto.cs index 673d00f..79285f6 100644 --- a/src/Dto/ResponseUserDto.cs +++ b/src/Dto/ResponseUserDto.cs @@ -13,7 +13,7 @@ public class ResponseUserDto [MaxLength(100)] public required string FirstName { get; set; } public required string Email { get; set; } - public required string Sexe { get; set; } + public required char Sexe { get; set; } public float Lenght { get; set; } public float Weight { get; set; } public string? Password { get; set; } diff --git a/src/Dto/Tiny/UserTinyDto.cs b/src/Dto/Tiny/UserTinyDto.cs index 7f5df8f..6ca667f 100644 --- a/src/Dto/Tiny/UserTinyDto.cs +++ b/src/Dto/Tiny/UserTinyDto.cs @@ -12,7 +12,7 @@ public class UserTinyDto [MaxLength(100)] public required string FirstName { get; set; } public required string Email { get; set; } - public required string Sexe { get; set; } + public required char Sexe { get; set; } public float Lenght { get; set; } public float Weight { get; set; } public string? Password { get; set; } diff --git a/src/Entities/AthleteEntity.cs b/src/Entities/AthleteEntity.cs index 7d1977d..a661ea8 100644 --- a/src/Entities/AthleteEntity.cs +++ b/src/Entities/AthleteEntity.cs @@ -59,7 +59,7 @@ namespace Entities /// [MaxLength(1)] [Required(ErrorMessage = "Athlete Sexe is ")] - public string Sexe { get; set; } + public char Sexe { get; set; } /// /// Gets or sets the height of the athlete. diff --git a/src/Model/User.cs b/src/Model/User.cs index 3a8acd6..ccccf3f 100644 --- a/src/Model/User.cs +++ b/src/Model/User.cs @@ -9,7 +9,7 @@ public class User public string FirstName { get; set; } public string Email { get; set; } public string? MotDePasse { get; set; } - public string Sexe { get; set; } + public char Sexe { get; set; } public float Lenght { get; set; } public float Weight { get; set; } public DateTime DateOfBirth { get; set; } @@ -22,7 +22,7 @@ public class User public List Users { get; set; } = new List(); public List DataSources { 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) + public User( string username, string profilePicture, string nom, string prenom, string email, string motDePasse, char sexe, float taille, float poids, DateTime dateNaissance, Role role) { Username = username; ProfilePicture = profilePicture; diff --git a/src/StubAPI/AthleteService.cs b/src/StubAPI/AthleteService.cs index d51a7c7..43673e2 100644 --- a/src/StubAPI/AthleteService.cs +++ b/src/StubAPI/AthleteService.cs @@ -13,21 +13,21 @@ public class UserService : IUserRepository 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), + 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), + 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", + Sexe = 'M', Lenght = 190, Weight = 80, DateOfBirth = new DateTime(1994, 3, 3), Email = "ath@ex.fr", Role = new Athlete() } diff --git a/src/StubbedContextLib/AthleteStubbedContext.cs b/src/StubbedContextLib/AthleteStubbedContext.cs index b87b4b4..2644757 100644 --- a/src/StubbedContextLib/AthleteStubbedContext.cs +++ b/src/StubbedContextLib/AthleteStubbedContext.cs @@ -42,11 +42,11 @@ namespace StubbedContextLib modelBuilder.Entity().HasData(picture); modelBuilder.Entity().HasData( - new AthleteEntity { Id = 1, UserName = "Doe",ProfilPicture = picture2, ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}") ,LastName = "Doe", FirstName = "John", Email = "john.doe@example.com", PasswordHash = "password123", Sexe = "M", Length = 1.80, Weight = 75, DateOfBirth = new DateOnly(1990, 01, 01), IsCoach = true , DataSourceId = 1}, - new AthleteEntity { Id = 2, UserName = "Smith",ProfilPicture = picture2,LastName = "Smith", FirstName = "Jane", Email = "jane.smith@exemple.com", PasswordHash = "secure456", Sexe = "F", Length = 1.65, Weight = 60, DateOfBirth = new DateOnly(1995, 01, 01), IsCoach = false, DataSourceId = 1 }, - new AthleteEntity { Id = 3, UserName = "Martin",ProfilPicture = picture2,ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}") ,LastName = "Martin", FirstName = "Paul", Email = "paul.martin@example.com", PasswordHash = "super789", Sexe = "M", Length = 1.75, Weight = 68, DateOfBirth = new DateOnly(1992, 01, 01), IsCoach = true, DataSourceId = 1}, - new AthleteEntity { Id = 4, UserName = "Brown",ProfilPicture = picture2, ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}"),LastName = "Brown", FirstName = "Anna", Email = "anna.brown@example.com", PasswordHash = "test000", Sexe = "F", Length = 1.70, Weight = 58, DateOfBirth = new DateOnly(1993, 01, 01), IsCoach = false, DataSourceId = 2 }, - new AthleteEntity { Id = 5, UserName = "Lee", ProfilPicture = picture2, ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}"),LastName = "Lee", FirstName = "Bruce", Email = "bruce.lee@example.com", PasswordHash = "hello321", Sexe = "M", Length = 2.0, Weight = 90, DateOfBirth = new DateOnly(1991, 01, 01), IsCoach = false, DataSourceId = 3 } + new AthleteEntity { Id = 1, UserName = "Doe",ProfilPicture = picture2, ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}") ,LastName = "Doe", FirstName = "John", Email = "john.doe@example.com", PasswordHash = "password123", Sexe = 'M', Length = 1.80, Weight = 75, DateOfBirth = new DateOnly(1990, 01, 01), IsCoach = true , DataSourceId = 1}, + new AthleteEntity { Id = 2, UserName = "Smith",ProfilPicture = picture2,LastName = "Smith", FirstName = "Jane", Email = "jane.smith@exemple.com", PasswordHash = "secure456", Sexe = 'F', Length = 1.65, Weight = 60, DateOfBirth = new DateOnly(1995, 01, 01), IsCoach = false, DataSourceId = 1 }, + new AthleteEntity { Id = 3, UserName = "Martin",ProfilPicture = picture2,ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}") ,LastName = "Martin", FirstName = "Paul", Email = "paul.martin@example.com", PasswordHash = "super789", Sexe = 'M', Length = 1.75, Weight = 68, DateOfBirth = new DateOnly(1992, 01, 01), IsCoach = true, DataSourceId = 1}, + new AthleteEntity { Id = 4, UserName = "Brown",ProfilPicture = picture2, ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}"),LastName = "Brown", FirstName = "Anna", Email = "anna.brown@example.com", PasswordHash = "test000", Sexe = 'F', Length = 1.70, Weight = 58, DateOfBirth = new DateOnly(1993, 01, 01), IsCoach = false, DataSourceId = 2 }, + new AthleteEntity { Id = 5, UserName = "Lee", ProfilPicture = picture2, ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}"),LastName = "Lee", FirstName = "Bruce", Email = "bruce.lee@example.com", PasswordHash = "hello321", Sexe = 'M', Length = 2.0, Weight = 90, DateOfBirth = new DateOnly(1991, 01, 01), IsCoach = false, DataSourceId = 3 } ); } } diff --git a/src/Tests/ConsoleTestEntities/Program.cs b/src/Tests/ConsoleTestEntities/Program.cs index 44bc88b..12ac022 100644 --- a/src/Tests/ConsoleTestEntities/Program.cs +++ b/src/Tests/ConsoleTestEntities/Program.cs @@ -81,7 +81,7 @@ class Program Console.WriteLine("Accès à l'athlete de sexe 'F' :"); Console.WriteLine("---------------------------------"); - foreach (var athlete in db.AthletesSet.Where(a => a.Sexe == "F")) + foreach (var athlete in db.AthletesSet.Where(a => a.Sexe == 'F')) { Console.WriteLine($"\t{athlete.Id} - {athlete.UserName}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } @@ -755,7 +755,7 @@ class Program Console.WriteLine("Test d'ajout, de modification et de suppression des athletes :"); var picture = "https://davidalmeida.site/assets/me_avatar.f77af006.png"; // Ajout d'un nouveau livre - var newAthlete = new AthleteEntity { UserName = "Doe", LastName = "Doe",ProfilPicture = picture,FirstName = "John", Email = "essaie.example.com", PasswordHash = "TheNewPassword", Sexe = "M", Length = 1.80, Weight = 90, DateOfBirth = new DateOnly(2024, 02, 22), IsCoach = false }; + var newAthlete = new AthleteEntity { UserName = "Doe", LastName = "Doe",ProfilPicture = picture,FirstName = "John", Email = "essaie.example.com", PasswordHash = "TheNewPassword", Sexe = 'M', Length = 1.80, Weight = 90, DateOfBirth = new DateOnly(2024, 02, 22), IsCoach = false }; db.AthletesSet.Add(newAthlete); db.SaveChanges(); diff --git a/src/Tests/TestsAPI/UnitTestApi/Controllers/UsersControllerTest.cs b/src/Tests/TestsAPI/UnitTestApi/Controllers/UsersControllerTest.cs index 3a9ce3a..5896ea3 100644 --- a/src/Tests/TestsAPI/UnitTestApi/Controllers/UsersControllerTest.cs +++ b/src/Tests/TestsAPI/UnitTestApi/Controllers/UsersControllerTest.cs @@ -32,7 +32,7 @@ public class UsersControllerTest 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), + Sexe = 'M', Lenght = 180, Weight = 70, DateOfBirth = new DateTime(1990, 1, 1), Email = "john.doe@example.com", Role = new Athlete() }, @@ -42,7 +42,7 @@ public class UsersControllerTest 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), + Sexe = 'F', Lenght = 170, Weight = 60, DateOfBirth = new DateTime(1992, 2, 2), Email = "athlete2@example.com", Role = new Coach() }, @@ -52,7 +52,7 @@ public class UsersControllerTest 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", + Sexe = 'M', Lenght = 190, Weight = 80, DateOfBirth = new DateTime(1994, 3, 3), Email = "ath@ex.fr", Role = new Athlete() } ]; diff --git a/src/Tests/UnitTestsEntities/AthleteEntityTests.cs b/src/Tests/UnitTestsEntities/AthleteEntityTests.cs index 2bced05..81a6d6b 100644 --- a/src/Tests/UnitTestsEntities/AthleteEntityTests.cs +++ b/src/Tests/UnitTestsEntities/AthleteEntityTests.cs @@ -16,7 +16,7 @@ public class AthleteEntityTests (DatabaseFixture fixture) : IClassFixture Date: Thu, 28 Mar 2024 04:59:55 +0100 Subject: [PATCH 81/92] fix null for dataSource --- src/Dto/ResponseUserDto.cs | 2 +- src/Entities2Dto/UserMappeur.cs | 2 +- src/HeartTrackAPI/Controllers/ActivityController.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Dto/ResponseUserDto.cs b/src/Dto/ResponseUserDto.cs index 79285f6..59a9117 100644 --- a/src/Dto/ResponseUserDto.cs +++ b/src/Dto/ResponseUserDto.cs @@ -22,7 +22,7 @@ public class ResponseUserDto public bool IsCoach { get; set; } public LargeImageDto? Image { get; set; } public ActivityTinyDto[] Activities { get; set; } - public DataSourceTinyDto DataSource { get; set; } + public DataSourceTinyDto? DataSource { get; set; } public FriendshipDto?[] Followers { get; set; } public FriendshipDto?[] Followings { get; set; } } \ No newline at end of file diff --git a/src/Entities2Dto/UserMappeur.cs b/src/Entities2Dto/UserMappeur.cs index edc6b8c..0e8e4fe 100644 --- a/src/Entities2Dto/UserMappeur.cs +++ b/src/Entities2Dto/UserMappeur.cs @@ -81,7 +81,7 @@ public static class UserMappeur { userDto.Activities = athleteEntity.Activities.ToTinyDtos().ToArray(); userDto.Image = athleteEntity.Image?.ToDto(); - userDto.DataSource = athleteEntity.DataSource.ToTinyDto(); + userDto.DataSource = athleteEntity.DataSource?.ToTinyDto(); userDto.Followers = athleteEntity.Followers.ToTinyDtos().ToArray(); userDto.Followings = athleteEntity.Followings.ToTinyDtos().ToArray(); }; diff --git a/src/HeartTrackAPI/Controllers/ActivityController.cs b/src/HeartTrackAPI/Controllers/ActivityController.cs index f117dfb..39f633d 100644 --- a/src/HeartTrackAPI/Controllers/ActivityController.cs +++ b/src/HeartTrackAPI/Controllers/ActivityController.cs @@ -71,7 +71,7 @@ public class ActivityController : Controller _logger.LogError("Athlete with id {id} not found", activityDto.AthleteId); return NotFound($"Athlete with id {activityDto.AthleteId} not found"); } - if (activityDto.DataSourceId != null && user.DataSource.Id != activityDto.DataSourceId) + if (activityDto.DataSourceId != null && user.DataSource?.Id != activityDto.DataSourceId) { _logger.LogError("DataSource with id {id} not found for this user", activityDto.DataSourceId); return NotFound($"DataSource with id {activityDto.DataSourceId} not found"); From 61ae846238300b03464c984de203db61591f75d2 Mon Sep 17 00:00:00 2001 From: dave Date: Thu, 28 Mar 2024 05:33:53 +0100 Subject: [PATCH 82/92] add id in the Token [:warning] --- src/HeartTrackAPI/Services/TokenService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/HeartTrackAPI/Services/TokenService.cs b/src/HeartTrackAPI/Services/TokenService.cs index c2ce989..92de2f7 100644 --- a/src/HeartTrackAPI/Services/TokenService.cs +++ b/src/HeartTrackAPI/Services/TokenService.cs @@ -25,6 +25,7 @@ public class TokenService : ITokenService var claims = new List { new (JwtRegisteredClaimNames.Email, user.Email), + new (JwtRegisteredClaimNames.NameId, user.Id.ToString()), new (JwtRegisteredClaimNames.GivenName, user.UserName) }; From 5e007ece9fde75eccd1a80ef57bca25b9c8b92d9 Mon Sep 17 00:00:00 2001 From: dave Date: Thu, 28 Mar 2024 15:54:42 +0100 Subject: [PATCH 83/92] changes url path --- src/HeartTrackAPI/Controllers/AuthController.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/HeartTrackAPI/Controllers/AuthController.cs b/src/HeartTrackAPI/Controllers/AuthController.cs index 3b796a0..27a1e85 100644 --- a/src/HeartTrackAPI/Controllers/AuthController.cs +++ b/src/HeartTrackAPI/Controllers/AuthController.cs @@ -10,6 +10,8 @@ using Microsoft.EntityFrameworkCore; namespace HeartTrackAPI.Controllers; [ApiController] +[ApiVersion("1.0")] +[Route("api/v{version:apiVersion}/[controller]")] public class AuthController : Controller { From f74e5dbd40c5a56ce1d6727f91b4957d9bfcaaf9 Mon Sep 17 00:00:00 2001 From: dave Date: Fri, 29 Mar 2024 05:22:44 +0100 Subject: [PATCH 84/92] goooooodd --- src/HeartTrackAPI/Controllers/ActivityController.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/HeartTrackAPI/Controllers/ActivityController.cs b/src/HeartTrackAPI/Controllers/ActivityController.cs index 39f633d..2c1a142 100644 --- a/src/HeartTrackAPI/Controllers/ActivityController.cs +++ b/src/HeartTrackAPI/Controllers/ActivityController.cs @@ -64,7 +64,7 @@ public class ActivityController : Controller [HttpPost] public async Task PostActivity(NewActivityDto activityDto) { - + _logger.LogInformation("Executing {Action} with parameters: {Parameters}, {add}", nameof(PostActivity), activityDto.Activity.Average, activityDto.HeartRates[0].HeartRate); var user = await _userRepository.GetUserById(activityDto.AthleteId); if (user == null) { @@ -83,6 +83,8 @@ public class ActivityController : Controller { return BadRequest(); } + _logger.LogInformation("Activity added with id {id}", result.Id); + return CreatedAtAction(nameof(GetActivity), new { id = result.Id }, result); } From cbc961d0e29591373d7c70f555677ae12a79892a Mon Sep 17 00:00:00 2001 From: dave Date: Mon, 1 Apr 2024 16:38:23 +0200 Subject: [PATCH 85/92] fix get ByID --- .../Controllers/ActivityController.cs | 6 +++--- src/Model/Repository/IActivityRepository.cs | 1 + src/Model2Entities/ActivityRepository.cs | 14 ++++++++++++++ src/StubAPI/ActivityService.cs | 5 +++++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/HeartTrackAPI/Controllers/ActivityController.cs b/src/HeartTrackAPI/Controllers/ActivityController.cs index 2c1a142..1a9f7de 100644 --- a/src/HeartTrackAPI/Controllers/ActivityController.cs +++ b/src/HeartTrackAPI/Controllers/ActivityController.cs @@ -89,20 +89,20 @@ public class ActivityController : Controller } [HttpGet("{id}")] - public async Task> GetActivity(int id) + public async Task> GetActivity(int id) { try { _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetActivity), id); - var activity = await _activityService.GetActivityByIdAsync(id); + var activity = await _activityService.GetActivityById(id); if (activity == null) { _logger.LogError("Activity with id {id} not found", id); return NotFound($"Activity with id {id} not found"); } - return Ok(activity.ToDto()); + return Ok(activity); } catch (Exception e) { diff --git a/src/Model/Repository/IActivityRepository.cs b/src/Model/Repository/IActivityRepository.cs index 84c2225..2175392 100644 --- a/src/Model/Repository/IActivityRepository.cs +++ b/src/Model/Repository/IActivityRepository.cs @@ -8,6 +8,7 @@ public interface IActivityRepository { public Task?> GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending = false); public Task GetActivityByIdAsync(int id); + public Task GetActivityById(int id); public Task AddActivity(Activity activity); public Task AddActivity(NewActivityDto activity); diff --git a/src/Model2Entities/ActivityRepository.cs b/src/Model2Entities/ActivityRepository.cs index 468e334..a53c22f 100644 --- a/src/Model2Entities/ActivityRepository.cs +++ b/src/Model2Entities/ActivityRepository.cs @@ -50,6 +50,20 @@ public partial class DbDataManager : IDataManager return await Task.FromResult(activity); } + public async Task GetActivityById(int id) + { + _logger.LogInformation($"GetActivityByIdAsync with id {id}", id); + + var activityEntity = await _dataManager.DbContext.ActivitiesSet.IncludeAll(_dataManager.DbContext).SingleOrDefaultAsync(a => a.IdActivity == id); + var activity = activityEntity != null ? activityEntity.ToResponseDto() : null; + + if (activity != null) + _logger.LogInformation($"Retrieved activity with ID {id}"); + else + _logger.LogWarning($"No activity found with ID {id}"); + + return await Task.FromResult(activity); + } public async Task AddActivity(Activity activity) { diff --git a/src/StubAPI/ActivityService.cs b/src/StubAPI/ActivityService.cs index 330a3f1..334e320 100644 --- a/src/StubAPI/ActivityService.cs +++ b/src/StubAPI/ActivityService.cs @@ -40,6 +40,11 @@ public class ActivityService: IActivityRepository // return Task.FromResult(_activities.FirstOrDefault(s => s.Id == id)?.ToModel()); } + public async Task GetActivityById(int id) + { + throw new NotImplementedException(); + } + public Task AddActivity(Activity activity) => throw new NotImplementedException(); From b7efc56fc3a141f44cd673dcb3b66f41eae6de96 Mon Sep 17 00:00:00 2001 From: David D'ALMEIDA Date: Mon, 1 Apr 2024 16:43:51 +0200 Subject: [PATCH 86/92] =?UTF-8?q?Mise=20=C3=A0=20jour=20de=20'.drone.yml'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .drone.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 842a40e..8a32992 100644 --- a/.drone.yml +++ b/.drone.yml @@ -138,7 +138,6 @@ steps: IMAGENAME: mariadb:10 CONTAINERNAME: mysql COMMAND: create - OVERWRITE: false PRIVATE: true CODEFIRST_CLIENTDRONE_ENV_MARIADB_ROOT_PASSWORD: from_secret: db_root_password From 15173c2cbca84c0d25266d4a7709b91cf656cfc1 Mon Sep 17 00:00:00 2001 From: David D'ALMEIDA Date: Mon, 1 Apr 2024 16:51:20 +0200 Subject: [PATCH 87/92] =?UTF-8?q?Mise=20=C3=A0=20jour=20de=20'.drone.yml'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .drone.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.drone.yml b/.drone.yml index 8a32992..0a4f499 100644 --- a/.drone.yml +++ b/.drone.yml @@ -129,8 +129,6 @@ steps: # OVERWRITE: true # depends_on: [ docker-build-and-push, deploy-container-stub ] - - # database container deployment - name: deploy-container-mysql image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dockerproxy-clientdrone:latest From d61ec723b234bc72f9d7561a4760d35515e521c4 Mon Sep 17 00:00:00 2001 From: dave Date: Mon, 1 Apr 2024 18:20:39 +0200 Subject: [PATCH 88/92] typo fix --- src/Dto/Tiny/UserTinyDto.cs | 2 +- src/Entities2Dto/UserMappeur.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Dto/Tiny/UserTinyDto.cs b/src/Dto/Tiny/UserTinyDto.cs index 6ca667f..789efb8 100644 --- a/src/Dto/Tiny/UserTinyDto.cs +++ b/src/Dto/Tiny/UserTinyDto.cs @@ -13,7 +13,7 @@ public class UserTinyDto public required string FirstName { get; set; } public required string Email { get; set; } public required char Sexe { get; set; } - public float Lenght { get; set; } + public float Length { get; set; } public float Weight { get; set; } public string? Password { get; set; } public DateTime DateOfBirth { get; set; } diff --git a/src/Entities2Dto/UserMappeur.cs b/src/Entities2Dto/UserMappeur.cs index 0e8e4fe..fc5eb53 100644 --- a/src/Entities2Dto/UserMappeur.cs +++ b/src/Entities2Dto/UserMappeur.cs @@ -30,7 +30,7 @@ public static class UserMappeur Sexe = athleteEntity.Sexe, Username = athleteEntity.UserName, Weight = athleteEntity.Weight, - Lenght = (float)athleteEntity.Length, + Length = (float)athleteEntity.Length, ProfilePicture = athleteEntity.ProfilPicture ?? "", IsCoach = athleteEntity.IsCoach }; @@ -52,7 +52,7 @@ public static class UserMappeur DateOfBirth = DateOnly.FromDateTime(user.DateOfBirth), IsCoach = user.IsCoach, Weight = user.Weight, - Length = user.Lenght, + Length = user.Length, ProfilPicture = user.ProfilePicture }; From 7677bb26aed439130c86526db50b195b228b6c24 Mon Sep 17 00:00:00 2001 From: David D'ALMEIDA Date: Mon, 1 Apr 2024 18:23:53 +0200 Subject: [PATCH 89/92] =?UTF-8?q?Mise=20=C3=A0=20jour=20de=20'.drone.yml'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .drone.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 0a4f499..9ee248d 100644 --- a/.drone.yml +++ b/.drone.yml @@ -83,7 +83,6 @@ volumes: --- - kind: pipeline type: docker name: HeartTrack-API-CD From f9a8dc18b0d93cdb2d95a0b078118b8853cf53b5 Mon Sep 17 00:00:00 2001 From: David D'ALMEIDA Date: Tue, 2 Apr 2024 03:23:30 +0200 Subject: [PATCH 90/92] =?UTF-8?q?Mise=20=C3=A0=20jour=20de=20'README.md'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2db5c57..457f8ae 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ ### Contexte HeartTrack est une application web PHP et mobile Android destinée aux sportifs et aux coachs afin de permettre l'analyse de courbes de fréquences cardiaques et le suivi d'équipe sportive. L'objectif principal de cette application est de récupérer les données de fréquence cardiaque à partir de fichiers .FIT, de les afficher sous forme de courbes, d'identifier des paternes, de fournir des statistiques et de réaliser des prédictions liées à l'effort physique, à la chaleur, à la récupération, etc. +!! Fuseaux horaires de base ### Récapitulatif du Projet From 578be65f84675659a4365e09da98e3e5e4f2485a Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 2 Apr 2024 04:00:40 +0200 Subject: [PATCH 91/92] try to optimize --- src/EFMappers/AthleteMappeur.cs | 5 + .../Controllers/ActivityController.cs | 17 +- .../Controllers/AnalysisController.cs | 135 +++++---- .../Controllers/UsersController.cs | 4 +- src/Model/Manager/IDataManager.cs | 3 + src/Model/Repository/IDataSourceRepository.cs | 6 + src/Model/Repository/IUserRepository.cs | 1 + src/Model/utils/ActivityAnalysis.cs | 63 ++++ src/Model/utils/HeartRateAdvise.cs | 278 ++++++++++++++++++ src/Model2Entities/DataSourceRepository.cs | 34 +++ src/Model2Entities/DbDataManager.cs | 6 + src/Model2Entities/UserRepository.cs | 12 + src/StubAPI/AthleteService.cs | 5 + src/StubAPI/StubData.cs | 2 + 14 files changed, 509 insertions(+), 62 deletions(-) create mode 100644 src/Model/Repository/IDataSourceRepository.cs create mode 100644 src/Model/utils/ActivityAnalysis.cs create mode 100644 src/Model/utils/HeartRateAdvise.cs create mode 100644 src/Model2Entities/DataSourceRepository.cs diff --git a/src/EFMappers/AthleteMappeur.cs b/src/EFMappers/AthleteMappeur.cs index f6a2198..136c457 100644 --- a/src/EFMappers/AthleteMappeur.cs +++ b/src/EFMappers/AthleteMappeur.cs @@ -9,6 +9,11 @@ public static class UserMappeur { private static GenericMapper _mapper = new (); + public static void Reset() + { + _mapper.Reset(); + } + public static User ToModel(this AthleteEntity entity) { Func create = athleteEntity => new User diff --git a/src/HeartTrackAPI/Controllers/ActivityController.cs b/src/HeartTrackAPI/Controllers/ActivityController.cs index 1a9f7de..41d51af 100644 --- a/src/HeartTrackAPI/Controllers/ActivityController.cs +++ b/src/HeartTrackAPI/Controllers/ActivityController.cs @@ -20,12 +20,14 @@ public class ActivityController : Controller private readonly IActivityRepository _activityService; private readonly ILogger _logger; private readonly IUserRepository _userRepository; + private readonly IDataSourceRepository _dataSourceRepository; public ActivityController(IDataManager dataManager, ILogger logger) { _activityService = dataManager.ActivityRepo; _userRepository = dataManager.UserRepo; + _dataSourceRepository = dataManager.DataSourceRepo; _logger = logger; } @@ -64,17 +66,22 @@ public class ActivityController : Controller [HttpPost] public async Task PostActivity(NewActivityDto activityDto) { - _logger.LogInformation("Executing {Action} with parameters: {Parameters}, {add}", nameof(PostActivity), activityDto.Activity.Average, activityDto.HeartRates[0].HeartRate); - var user = await _userRepository.GetUserById(activityDto.AthleteId); + _logger.LogInformation("Executing {Action} with parameters: {Parameters}, {add}", nameof(PostActivity), activityDto.Activity.Average, activityDto.HeartRates[0].Timestamp); + var user = await _userRepository.GetUserTinyById(activityDto.AthleteId); if (user == null) { _logger.LogError("Athlete with id {id} not found", activityDto.AthleteId); return NotFound($"Athlete with id {activityDto.AthleteId} not found"); } - if (activityDto.DataSourceId != null && user.DataSource?.Id != activityDto.DataSourceId) + if (activityDto.DataSourceId != null) { - _logger.LogError("DataSource with id {id} not found for this user", activityDto.DataSourceId); - return NotFound($"DataSource with id {activityDto.DataSourceId} not found"); + var dataSource = await _dataSourceRepository.GetItemById(activityDto.DataSourceId.Value); + + if (dataSource == null) + { + _logger.LogError("DataSource with id {id} not found", activityDto.DataSourceId); + return NotFound($"DataSource with id {activityDto.DataSourceId} not found"); + } } var result = await _activityService.AddActivity(activityDto); diff --git a/src/HeartTrackAPI/Controllers/AnalysisController.cs b/src/HeartTrackAPI/Controllers/AnalysisController.cs index 11c3be3..96fe0aa 100644 --- a/src/HeartTrackAPI/Controllers/AnalysisController.cs +++ b/src/HeartTrackAPI/Controllers/AnalysisController.cs @@ -1,6 +1,10 @@ +using Dto; using Dto.Tiny; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Model.Manager; +using Model.Repository; +using Model.utils; namespace HeartTrackAPI.Controllers; @@ -10,34 +14,87 @@ namespace HeartTrackAPI.Controllers; [Authorize] public class AnalysisController : Controller { - private readonly List _heartRateZones = new() + + private readonly IActivityRepository _activityService; + private readonly ILogger _logger; + + + public AnalysisController(IDataManager dataManager, ILogger logger) { - new() { Name = "Repos", MinHeartRate = 0, MaxHeartRate = 60 }, - new() { Name = "Aérobie légère", MinHeartRate = 61, MaxHeartRate = 90 }, - new() { Name = "Aérobie", MinHeartRate = 91, MaxHeartRate = 140 }, - new() { Name = "Anaérobie", MinHeartRate = 141, MaxHeartRate = 180 }, - new() { Name = "VO2 Max", MinHeartRate = 181, MaxHeartRate = 220 } - }; + _activityService = dataManager.ActivityRepo; + _logger = logger; + } + + - [HttpGet("heart-rate/zones")] - public IActionResult GetHeartRateZones() + + [HttpGet("activity/{activityId}")] + public async Task AnalyseByActivityId(int activityId) { - var heartRates = GetMockHeartRateData(); - var results = _heartRateZones.Select(zone => new HeartRateZoneResult + var activity = await _activityService.GetActivityById(activityId); + if (activity == null) + { + _logger.LogInformation($"Activity with ID {activityId} not found."); + return NotFound($"Activity with ID {activityId} not found."); + } + // for the moment no need to get the user Entity [Dave] + var user = activity.Athlete; + if (user == null) { - Zone = zone.Name, - TimeSpent = CalculateTimeInZone(zone, heartRates) - }).ToList(); - return Ok(results); + _logger.LogInformation($"User not found for activity ID {activityId}."); + return NotFound($"User not found for activity ID {activityId}."); + } + + var analysis = ActivityAnalysis.FromActivityData(activity); + return Ok(analysis); } + - private TimeSpan CalculateTimeInZone(HeartRateZone zone, List heartRates) - { - var secondsInZone = - heartRates.Count(hr => hr.HeartRate >= zone.MinHeartRate && hr.HeartRate <= zone.MaxHeartRate); - return TimeSpan.FromSeconds(secondsInZone); - } - /* +} + + +/* + /* + public class HeartRateZoneResult + { + public string Zone { get; set; } + public TimeSpan TimeSpent { get; set; } + } + + private readonly List _heartRateZones = new() + { + new() { Name = "Repos", MinHeartRate = 0, MaxHeartRate = 60 }, + new() { Name = "Aérobie légère", MinHeartRate = 61, MaxHeartRate = 90 }, + new() { Name = "Aérobie", MinHeartRate = 91, MaxHeartRate = 140 }, + new() { Name = "Anaérobie", MinHeartRate = 141, MaxHeartRate = 180 }, + new() { Name = "VO2 Max", MinHeartRate = 181, MaxHeartRate = 220 } + }; + [HttpGet("heart-rate/zones/{activityId}")] + public IActionResult GetActivityHeartRateZones(int activityId) + { + var heartRateTinyDtos = _activityService.GetActivityById(activityId).Result?.HeartRates; + if (heartRateTinyDtos != null) + { + var heartRates = heartRateTinyDtos.ToList(); + var results = _heartRateZones.Select(zone => new HeartRateZoneResult + { + Zone = zone.Name, + TimeSpent = CalculateTimeInZone(zone, heartRates) + }).ToList(); + + return Ok(results); + } + + return NotFound("Not heart rates"); + + } + private TimeSpan CalculateTimeInZone(HeartRateZone zone, List heartRates) + { + var secondsInZone = + heartRates.Count(hr => hr.HeartRate >= zone.MinHeartRate && hr.HeartRate <= zone.MaxHeartRate); + return TimeSpan.FromSeconds(secondsInZone); + }* / + [HttpGet("getOptimizedPath")] public IActionResult GetOptimizedPath(int activityId) { @@ -56,36 +113,4 @@ public class AnalysisController : Controller return Ok(path.ToGeoJson()); } -*/ - private List GetMockHeartRateData() - { - var random = new Random(); - return Enumerable.Range(1, 3600) - .Select(_ => new HeartRateTinyDto - { - HeartRate = random.Next(60, 220), - Timestamp = new DateTime(2021, 1, 1).AddSeconds(random.Next(3600)), - Latitude = random.NextDouble() * 180 - 90, - Longitude = random.NextDouble() * 360 - 180, - Altitude = random.NextDouble() * 1000, - Cadence = random.Next(60, 120), - Distance = random.NextDouble() * 100, - Speed = random.NextDouble() * 30, - Power = random.Next(0, 500), - Temperature = random.NextDouble() * 30 - }).ToList(); - } -} - -public class HeartRateZoneResult -{ - public string Zone { get; set; } - public TimeSpan TimeSpent { get; set; } -} - -internal class HeartRateZone -{ - public string Name { get; set; } - public int MinHeartRate { get; set; } - public int MaxHeartRate { get; set; } -} \ 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 6f74657..8f723ac 100644 --- a/src/HeartTrackAPI/Controllers/UsersController.cs +++ b/src/HeartTrackAPI/Controllers/UsersController.cs @@ -143,7 +143,7 @@ public class UsersController : Controller try { _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(Update), user,id); - var athlete = await _userService.GetUserById(id); + var athlete = await _userService.GetUserTinyById(id); if (athlete == null) { _logger.LogError("Athlete with id {id} not found", id); @@ -183,7 +183,7 @@ public class UsersController : Controller { _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(Delete), null,id); - var athlete = await _userService.GetUserById(id); + var athlete = await _userService.GetUserTinyById(id); if (athlete == null) { _logger.LogError("Athlete with id {id} not found", id); diff --git a/src/Model/Manager/IDataManager.cs b/src/Model/Manager/IDataManager.cs index 6fc8532..9a7b6cc 100644 --- a/src/Model/Manager/IDataManager.cs +++ b/src/Model/Manager/IDataManager.cs @@ -1,3 +1,4 @@ +using Dto.Tiny; using Model.Repository; namespace Model.Manager; @@ -6,4 +7,6 @@ public interface IDataManager { IUserRepository UserRepo { get; } IActivityRepository ActivityRepo { get; } + + IDataSourceRepository DataSourceRepo { get; } } diff --git a/src/Model/Repository/IDataSourceRepository.cs b/src/Model/Repository/IDataSourceRepository.cs new file mode 100644 index 0000000..6a442ae --- /dev/null +++ b/src/Model/Repository/IDataSourceRepository.cs @@ -0,0 +1,6 @@ +namespace Model.Repository; + +public interface IDataSourceRepository +{ + Task GetItemById(int id); +} \ No newline at end of file diff --git a/src/Model/Repository/IUserRepository.cs b/src/Model/Repository/IUserRepository.cs index a4d3c1a..0541afa 100644 --- a/src/Model/Repository/IUserRepository.cs +++ b/src/Model/Repository/IUserRepository.cs @@ -17,6 +17,7 @@ public interface IUserRepository : IGenericRepository // Make it generic public Task GetNbFriends(int user); public Task UpdateUser(int old,UserTinyDto user); public Task GetUserById(int id); + public Task GetUserTinyById(int id); public Task?> GetAllAthletes(int index, int count, AthleteOrderCriteria? criteria, bool descending = false); public Task?> GetAllCoaches(int index, int count, AthleteOrderCriteria? criteria, bool descending = false); diff --git a/src/Model/utils/ActivityAnalysis.cs b/src/Model/utils/ActivityAnalysis.cs new file mode 100644 index 0000000..1634dbb --- /dev/null +++ b/src/Model/utils/ActivityAnalysis.cs @@ -0,0 +1,63 @@ +using Model.utils; + +namespace Dto.Tiny; + +public class ActivityAnalysis +{ + public double AverageHeartRate { get; private set; } + public string AverageHeartRateAdvice { get; private set; } + public double Vo2Max { get; private set; } + public string Vo2MaxAdvice { get; private set; } + public double NormalBpm { get; private set; } + public string NormalBpmAdvice { get; private set; } + public double HeartRateVariability { get; private set; } + public string HeartRateVariabilityAdvice { get; private set; } + public string HeartRateZone { get; private set; } + public string HeartRateZoneAdvice { get; private set; } + public double Duration { get; private set; } + public string DurationAdvice { get; private set; } + public double Effort { get; private set; } + public string EffortAdvice { get; private set; } + public static ActivityAnalysis FromActivityData(ResponseActivityDto activity) + { + double dureeActivity = (activity.EndTime - activity.StartTime).TotalMinutes; + var age = DateTime.Today.Year - activity.Athlete.DateOfBirth.Year; + var gender = activity.Athlete.Sexe; + var poids = activity.Athlete.Weight; + var effortFelt = activity.EffortFelt; + var averageHeartRate = activity.Average; + var heartRateVariability = activity.Variability; + + var heartRateZones = HeartRateAdvise.CalculateHeartRateZones(age); + + var effortScore = HeartRateAdvise.EvaluateEffort(activity); + + var (seuilBPM, vo2Max) = HeartRateAdvise.SeuilBPMavance(gender, age, poids, dureeActivity); + string averageHeartRateAdvice = HeartRateAdvise.GenerateAverageHeartRateAdvice(averageHeartRate, seuilBPM); + string vo2MaxAdvice = HeartRateAdvise.GenerateVo2MaxAdvice(vo2Max); + string normalBpmAdvice = HeartRateAdvise.GenerateNormalBpmAdvice(seuilBPM, averageHeartRate); + string hrvAdvice = HeartRateAdvise.GenerateHrvAdvice(heartRateVariability); + HeartRateAdvise.HeartRateZone currentZone = heartRateZones.Find(zone => averageHeartRate >= zone.MinHeartRate && averageHeartRate <= zone.MaxHeartRate); + string heartRateZoneAdvice = HeartRateAdvise.GenerateHeartRateZoneAdvice(currentZone?.Name); + var effortAccuracy = HeartRateAdvise.CompareEffort(effortFelt, (int)effortScore); + var analysis = new ActivityAnalysis + { + AverageHeartRate = averageHeartRate, + AverageHeartRateAdvice = averageHeartRateAdvice, + Vo2Max = vo2Max, + Vo2MaxAdvice = vo2MaxAdvice, + NormalBpm = seuilBPM, + NormalBpmAdvice = normalBpmAdvice, + HeartRateVariability = heartRateVariability, + HeartRateVariabilityAdvice = hrvAdvice, + HeartRateZone = currentZone != null ? currentZone.Name : "N/A", + HeartRateZoneAdvice = heartRateZoneAdvice, + Duration = dureeActivity, + DurationAdvice =HeartRateAdvise.GenerateDurationAdvice(dureeActivity), + Effort = effortScore, + EffortAdvice = HeartRateAdvise.GenerateEffortAdvice(effortAccuracy) + }; + + return analysis; + } +} \ No newline at end of file diff --git a/src/Model/utils/HeartRateAdvise.cs b/src/Model/utils/HeartRateAdvise.cs new file mode 100644 index 0000000..10d8b61 --- /dev/null +++ b/src/Model/utils/HeartRateAdvise.cs @@ -0,0 +1,278 @@ +using Dto; + +namespace Model.utils; + +public class HeartRateAdvise +{ + public class HeartRateZone + { + public string Name { get; set; } + public int MinHeartRate { get; set; } + public int MaxHeartRate { get; set; } + } + + public string getAdvise(Activity activity) + { + return "You should take a break"; + } + public static List CalculateHeartRateZones(int age) + { + int fcm = 220 - age; // Estimation de la FCM + List zones = new List + { + new HeartRateZone { Name = "Très Légère", MinHeartRate = (int)(fcm * 0.50), MaxHeartRate = (int)(fcm * 0.60) }, + new HeartRateZone { Name = "Aérobie légère", MinHeartRate = (int)(fcm * 0.60), MaxHeartRate = (int)(fcm * 0.70) }, + new HeartRateZone { Name = "Aérobie", MinHeartRate = (int)(fcm * 0.70), MaxHeartRate = (int)(fcm * 0.80) }, + new HeartRateZone { Name = "Anaérobie", MinHeartRate = (int)(fcm * 0.80), MaxHeartRate = (int)(fcm * 0.90) }, + new HeartRateZone { Name = "Maximum", MinHeartRate = (int)(fcm * 0.90), MaxHeartRate = (int)(fcm * 1.00) } + }; + + return zones; + } + public static double EvaluateEffort(ResponseActivityDto stats) + { + double score = 0; + + score += stats.Average * 0.3; // Exemple de poids + score += stats.HeartRates.Average(speed => speed.Speed ?? 0) * 0.25; + score += stats.HeartRates.Sum(dist => dist.Distance ?? 0) * 0.15; + score += stats.HeartRates.Average(hr => hr.Cadence ?? 0) * 0.1; + score += stats.HeartRates.Average(hr => hr.Power ?? 0) * 0.15; + score += stats.StandardDeviation * 0.05; + + return score; + } + + public static string CompareEffort(int perceivedEffort, int objectiveEffort) + { + if (perceivedEffort == objectiveEffort) return "Accurate"; + if (perceivedEffort > objectiveEffort) return "Overestimated"; + if (perceivedEffort < objectiveEffort) return "Underestimated"; + return "Unknown"; + } + + +// Faible intensité : 50-60% de la FCM +// Intensité modérée : 60-70% de la FCM +// Haute intensité : 70-85% de la FCM + public static double CalculerVo2Max(char sexe, int age, double poids) + { + if (sexe == 'M') + { + return (poids * 0.198) + (age * -0.193) + 24.489; + } + + // sexe == "F" + { + return (poids * 0.201) + (age * -0.217) + 20.453; + } + } + + public static (double SeuilBPM, double Vo2Max) SeuilBPMavance(char sexe, int age, double poids, double dureeActivite) + { + double fcm = sexe == 'M' ? 207 - (0.7 * age) : 206 - (0.88 * age); + double vo2Max = CalculerVo2Max(sexe, age, poids); + + double zone = dureeActivite <= 30 ? 0.8 : dureeActivite <= 60 ? 0.7 : 0.6; + double seuilBpm = fcm * zone; + + return (seuilBpm, vo2Max); + } + + public static Dictionary GenerateAdvice(ResponseActivityDto activity) + { + int dureeActivity = (activity.EndTime - activity.StartTime).Minutes; + var age = DateTime.Today.Year - activity.Athlete.DateOfBirth.Year; + var gender = activity.Athlete.Sexe; + var poids = activity.Athlete.Weight; + var effortFelt = activity.EffortFelt; + var averageHeartRate = activity.Average; + var heartRateVariability = activity.Variability; + var heartRateZones = CalculateHeartRateZones(age); + var effortScore = EvaluateEffort(activity); + + + var (seuilBPM, vo2Max) = SeuilBPMavance(gender, age, poids, dureeActivity); + Dictionary healthMetrics = new Dictionary(); + + // Conseil pour AverageHeartRate + string averageHeartRateAdvice = averageHeartRate > seuilBPM + ? "Votre rythme cardiaque moyen est supérieur au seuil recommandé. Envisagez de réduire l'intensité." + : "Votre rythme cardiaque moyen est dans une bonne plage. Continuez à maintenir votre intensité actuelle."; + + // Conseil pour Vo2Max + string vo2MaxAdvice; + if (vo2Max < 30) + vo2MaxAdvice = + "Votre Vo2 max est faible, envisagez d'augmenter progressivement l'intensité de vos entraînements."; + else if (vo2Max < 40) + vo2MaxAdvice = "Votre Vo2 max est dans la moyenne. Continuez de travailler sur votre endurance."; + else vo2MaxAdvice = "Votre Vo2 max est excellente. Vous pourriez bénéficier d'entraînements à haute intensité."; + + // Conseil basé sur la comparaison avec NormalBpm + string normalBpmAdvice = seuilBPM > averageHeartRate + ? "Votre BPM normal est plus élevé que la moyenne, ce qui peut indiquer un bon niveau de forme physique." + : "Votre BPM normal est inférieur à la moyenne, assurez-vous de surveiller votre intensité d'entraînement."; + // Conseil pour HeartRateVariability + string hrvAdvice = heartRateVariability < 40 + ? "Votre HRV est basse, ce qui peut indiquer un stress élevé ou une récupération insuffisante. Envisagez d'améliorer votre récupération." + : heartRateVariability < 60 + ? "Votre HRV est dans une plage moyenne. Continuez de surveiller votre récupération et votre stress." + : "Votre HRV est élevée, indiquant une bonne récupération et une gestion du stress. Continuez vos bonnes pratiques de gestion de la santé."; + + HeartRateZone currentZone = heartRateZones.Find(zone => + averageHeartRate >= zone.MinHeartRate && averageHeartRate <= zone.MaxHeartRate); + string heartRateZoneAdvice; + if (currentZone != null) + { + heartRateZoneAdvice = $"Votre BPM moyen est dans la zone '{currentZone.Name}', qui est idéale pour "; + switch (currentZone.Name) + { + case "Repos": + heartRateZoneAdvice += "favoriser la récupération."; + break; + case "Endurance": + heartRateZoneAdvice += "améliorer l'endurance cardiovasculaire et brûler des graisses."; + break; + case "Aérobie": + heartRateZoneAdvice += "améliorer votre capacité aérobie."; + break; + case "Anaérobie": + heartRateZoneAdvice += "améliorer la performance à haute intensité."; + break; + case "VO2 Max": + heartRateZoneAdvice += "maximiser la performance et la capacité aérobie."; + break; + default: + heartRateZoneAdvice = + "Cette zone est spécifique et peut avoir différents objectifs en fonction de votre plan d'entraînement."; + break; + } + } + else + { + heartRateZoneAdvice = + "Vous n'êtes dans aucune zone spécifique. Assurez-vous que votre BPM moyen est correctement mesuré."; + } + + // Comparaison de l'effort objectif avec l'effort perçu + var effortAccuracy = CompareEffort(effortFelt, (int)effortScore); + + // Remplissage du dictionnaire + healthMetrics.Add("AverageHeartRate", (averageHeartRate, averageHeartRateAdvice)); + healthMetrics.Add("Vo2Max", (vo2Max, vo2MaxAdvice)); + healthMetrics.Add("NormalBpm", (seuilBPM, normalBpmAdvice)); + healthMetrics.Add("HeartRateVariability", (heartRateVariability, hrvAdvice)); + healthMetrics.Add("HeartRateZone", (averageHeartRate, heartRateZoneAdvice)); + healthMetrics.Add("Duration", + (dureeActivity, + dureeActivity < 75 + ? "Vous pourriez augmenter la durée de vos activités pour atteindre les recommandations." + : "Votre durée d'activité est conforme aux recommandations.")); + healthMetrics.Add("Effort", (effortScore, GenerateEffortAdvice(effortAccuracy))); + return healthMetrics; + } + public static string GenerateAverageHeartRateAdvice(float averageHeartRate, double seuilBPM) + { + return averageHeartRate > seuilBPM + ? "Votre rythme cardiaque moyen est supérieur au seuil recommandé. Envisagez de réduire l'intensité." + : "Votre rythme cardiaque moyen est dans une bonne plage. Continuez à maintenir votre intensité actuelle."; + } + public static string GenerateVo2MaxAdvice(double vo2Max) + { + if (vo2Max < 30) + return "Votre Vo2 max est faible, envisagez d'augmenter progressivement l'intensité de vos entraînements."; + if (vo2Max < 40) + return "Votre Vo2 max est dans la moyenne. Continuez de travailler sur votre endurance."; + return "Votre Vo2 max est excellente. Vous pourriez bénéficier d'entraînements à haute intensité."; + } + public static string GenerateNormalBpmAdvice(double normalBpm,double averageHeartRate) + { + return normalBpm > averageHeartRate + ? "Votre BPM normal est plus élevé que la moyenne, ce qui peut indiquer un bon niveau de forme physique." + : "Votre BPM normal est inférieur à la moyenne, assurez-vous de surveiller votre intensité d'entraînement."; + } + + public static string GenerateHrvAdvice(double heartRateVariability) + { + return heartRateVariability < 40 + ? "Votre HRV est basse, ce qui peut indiquer un stress élevé ou une récupération insuffisante. Envisagez d'améliorer votre récupération." + : heartRateVariability < 60 + ? "Votre HRV est dans une plage moyenne. Continuez de surveiller votre récupération et votre stress." + : "Votre HRV est élevée, indiquant une bonne récupération et une gestion du stress. Continuez vos bonnes pratiques de gestion de la santé."; + } + public static string GenerateHeartRateZoneAdvice(string? heartRateZone) + { + return heartRateZone switch + { + "Repos" => "Favoriser la récupération.", + "Endurance" => "Améliorer l'endurance cardiovasculaire et brûler des graisses.", + "Aérobie" => "Améliorer votre capacité aérobie.", + "Anaérobie" => "Améliorer la performance à haute intensité.", + "VO2 Max" => "Maximiser la performance et la capacité aérobie.", + _ => "Cette zone est spécifique et peut avoir différents objectifs en fonction de votre plan d'entraînement." + }; + } + public static string GenerateDurationAdvice(double dureeActivity) + { + return dureeActivity < 75 + ? "Vous pourriez augmenter la durée de vos activités pour atteindre les recommandations." + : "Votre durée d'activité est conforme aux recommandations."; + } + + public static string GenerateEffortAdvice(string effortAccuracy) + { + return effortAccuracy switch + { + "Accurate" => "Votre perception de l'effort est précise. Continuez ainsi!", + "Overestimated" => "Vous surestimez votre effort. Essayez de pousser un peu plus lors de vos prochaines activités.", + "Underestimated" => "Vous sous-estimez votre effort. Vous pourriez être plus proche de vos limites que vous ne le pensez.", + _ => "Continuez à surveiller et ajuster votre effort pour de meilleurs résultats." + }; + } +} + +/* +public class EffortAnalysisResult +{ + public string EffortAccuracy { get; set; } + public string Advice { get; set; } +} + +public EffortAnalysisResult AnalyzeActivityEffort(ResponseActivityDto activity) +{ + + + var effortScore = EvaluateEffort(activity); + + // Comparaison de l'effort objectif avec l'effort perçu + var effortAccuracy = CompareEffort(activity.EffortFelt, (int)effortScore); + var result = new EffortAnalysisResult + { + EffortAccuracy = effortAccuracy, + Advice = GenerateEffortAdvice(effortAccuracy) + }; + + return result; +} +public List GetMockHeartRateData() + { + var random = new Random(); + return Enumerable.Range(1, 3600) + .Select(_ => new HeartRateTinyDto + { + HeartRate = random.Next(60, 220), + Timestamp = new DateTime(2021, 1, 1).AddSeconds(random.Next(3600)), + Latitude = random.NextDouble() * 180 - 90, + Longitude = random.NextDouble() * 360 - 180, + Altitude = random.NextDouble() * 1000, + Cadence = random.Next(60, 120), + Distance = random.NextDouble() * 100, + Speed = random.NextDouble() * 30, + Power = random.Next(0, 500), + Temperature = random.NextDouble() * 30 + }).ToList(); + } + +*/ + diff --git a/src/Model2Entities/DataSourceRepository.cs b/src/Model2Entities/DataSourceRepository.cs new file mode 100644 index 0000000..4630d12 --- /dev/null +++ b/src/Model2Entities/DataSourceRepository.cs @@ -0,0 +1,34 @@ +using Dto.Tiny; +using Entities2Dto; +using Microsoft.Extensions.Logging; +using Model.Repository; + +namespace Model2Entities; + +public partial class DbDataManager +{ + public class DataSourceRepository : IDataSourceRepository + { + private readonly DbDataManager _dataManager; + private readonly ILogger _logger; + + public DataSourceRepository(DbDataManager dbDataManager, ILogger logger) + { + _dataManager = dbDataManager; + _logger = logger; + } + + + public async Task GetItemById(int id) + { + var dataSource = await _dataManager.DbContext.DataSourcesSet.FindAsync(id); + if (dataSource == null) + { + _logger.LogInformation($"DataSource with ID {id} not found."); + return null; + } + + return dataSource.ToTinyDto(); + } + } +} \ No newline at end of file diff --git a/src/Model2Entities/DbDataManager.cs b/src/Model2Entities/DbDataManager.cs index bf1e4fd..3968739 100644 --- a/src/Model2Entities/DbDataManager.cs +++ b/src/Model2Entities/DbDataManager.cs @@ -1,4 +1,5 @@ using DbContextLib; +using Dto.Tiny; using EFMappers; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; @@ -11,6 +12,8 @@ public partial class DbDataManager: IDataManager { public IActivityRepository ActivityRepo { get; } public IUserRepository UserRepo { get; } + + public IDataSourceRepository DataSourceRepo { get; } protected HeartTrackContext DbContext { get; } protected readonly ILogger _logger = new Logger(new LoggerFactory()); @@ -21,7 +24,9 @@ public partial class DbDataManager: IDataManager DbContext = dbContext; ActivityRepo = new ActivityRepository(this, _logger); UserRepo = new UserRepository(this, _logger); + DataSourceRepo = new DataSourceRepository(this, _logger); ActivityMapper.Reset(); + UserMappeur.Reset(); // Faire pour les autres reset() des autres mappers } @@ -34,5 +39,6 @@ public partial class DbDataManager: IDataManager DbContext = new HeartTrackContext(); ActivityRepo = new ActivityRepository(this, _logger); UserRepo= new UserRepository(this, _logger); + DataSourceRepo = new DataSourceRepository(this, _logger); } } diff --git a/src/Model2Entities/UserRepository.cs b/src/Model2Entities/UserRepository.cs index 51391c3..e27b9af 100644 --- a/src/Model2Entities/UserRepository.cs +++ b/src/Model2Entities/UserRepository.cs @@ -104,6 +104,18 @@ public partial class DbDataManager return user; } + public Task GetUserTinyById(int id) + { + _logger.LogInformation($"GetTinyItemById with id {id}", id); + var userEntity = _dataManager.DbContext.AthletesSet.FindAsync(id).Result; + var user = userEntity != null ? userEntity.ToTinyDto() : null; + if (user != null) + _logger.LogInformation($"Retrieved user with ID {id}"); + else + _logger.LogWarning($"No user found with ID {id}"); + return Task.FromResult(user); + } + public async Task UpdateItem(int oldItem, User newItem) { _logger.LogInformation($"UpdateItem with id {oldItem}", oldItem); diff --git a/src/StubAPI/AthleteService.cs b/src/StubAPI/AthleteService.cs index 43673e2..2416b66 100644 --- a/src/StubAPI/AthleteService.cs +++ b/src/StubAPI/AthleteService.cs @@ -108,6 +108,11 @@ public class UserService : IUserRepository throw new NotImplementedException(); } + public Task GetUserTinyById(int id) + { + throw new NotImplementedException(); + } + public async Task> GetItems(int index, int count, string? orderingProperty = null, bool descending = false) =>await GetUsers(index, count, this.ToEnum(orderingProperty), descending); diff --git a/src/StubAPI/StubData.cs b/src/StubAPI/StubData.cs index bceb496..f21772c 100644 --- a/src/StubAPI/StubData.cs +++ b/src/StubAPI/StubData.cs @@ -1,3 +1,4 @@ +using Dto.Tiny; using Model.Manager; using Model.Repository; @@ -7,6 +8,7 @@ public class StubData : IDataManager { public IUserRepository UserRepo { get; } public IActivityRepository ActivityRepo { get; } + public IDataSourceRepository DataSourceRepo { get; } public StubData() { From f213f8c8a78ff845d56761595bd31e9c37e0c676 Mon Sep 17 00:00:00 2001 From: dave Date: Thu, 4 Apr 2024 21:23:50 +0200 Subject: [PATCH 92/92] text fix --- src/Model/utils/HeartRateAdvise.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Model/utils/HeartRateAdvise.cs b/src/Model/utils/HeartRateAdvise.cs index 10d8b61..1439f12 100644 --- a/src/Model/utils/HeartRateAdvise.cs +++ b/src/Model/utils/HeartRateAdvise.cs @@ -111,8 +111,8 @@ public class HeartRateAdvise // Conseil basé sur la comparaison avec NormalBpm string normalBpmAdvice = seuilBPM > averageHeartRate - ? "Votre BPM normal est plus élevé que la moyenne, ce qui peut indiquer un bon niveau de forme physique." - : "Votre BPM normal est inférieur à la moyenne, assurez-vous de surveiller votre intensité d'entraînement."; + ? "Votre BPM normal est plus élevé que la moyenne, assurez-vous de surveiller votre intensité d'entraînement." + : "Votre BPM normal est inférieur à la moyenne, ce qui peut indiquer un bon niveau de forme physique."; // Conseil pour HeartRateVariability string hrvAdvice = heartRateVariability < 40 ? "Votre HRV est basse, ce qui peut indiquer un stress élevé ou une récupération insuffisante. Envisagez d'améliorer votre récupération."