Merge remote-tracking branch 'origin/WORK-KEV' into WORK-APE

WORK-APE
Antoine PEREDERII 1 year ago
commit de458a8f35

@ -3,9 +3,6 @@ type: docker
name: HeartTrack-API name: HeartTrack-API
trigger: trigger:
branch:
- WORK-CD
- WORK-EF_WebAPI
event: event:
- push - push
@ -18,6 +15,14 @@ steps:
- dotnet build HeartTrack.sln -c Release --no-restore - dotnet build HeartTrack.sln -c Release --no-restore
- dotnet publish HeartTrack.sln -c Release --no-restore -o CI_PROJECT_DIR/build/release - dotnet publish HeartTrack.sln -c Release --no-restore -o CI_PROJECT_DIR/build/release
- name: tests
image: mcr.microsoft.com/dotnet/sdk:8.0
commands:
- cd src/
- dotnet restore HeartTrack.sln
- dotnet test HeartTrack.sln --no-restore
depends_on: [build]
- name: code-analysis - name: code-analysis
image: hub.codefirst.iut.uca.fr/marc.chevaldonne/codefirst-dronesonarplugin-dotnet8 image: hub.codefirst.iut.uca.fr/marc.chevaldonne/codefirst-dronesonarplugin-dotnet8
secrets: [ SECRET_SONAR_LOGIN ] secrets: [ SECRET_SONAR_LOGIN ]
@ -36,8 +41,55 @@ steps:
- reportgenerator -reports:"**/coverage.cobertura.xml" -reporttypes:SonarQube -targetdir:"coveragereport" - reportgenerator -reports:"**/coverage.cobertura.xml" -reporttypes:SonarQube -targetdir:"coveragereport"
- dotnet publish HeartTrack.sln -c Release --no-restore -o $CI_PROJECT_DIR/build/release - dotnet publish HeartTrack.sln -c Release --no-restore -o $CI_PROJECT_DIR/build/release
- dotnet sonarscanner end /d:sonar.login=$${PLUGIN_SONAR_TOKEN} - dotnet sonarscanner end /d:sonar.login=$${PLUGIN_SONAR_TOKEN}
depends_on: [ tests ]
- name: swagger
image: mcr.microsoft.com/dotnet/sdk:8.0
failure: ignore
volumes:
- name: docs
path: /docs
environment:
CODEFIRST_CLIENTDRONE_ENV_DOTNET_ROLL_FORWARD: LatestMajor
CODEFIRST_CLIENTDRONE_ENV_DOTNET_ROLL_FORWARD_TO_PRERELEASE: 1
commands:
- cd src/
- dotnet restore HeartTrack.sln
- cd HeartTrackAPI
- dotnet new tool-manifest
- dotnet tool install -g --version 6.5.0 Swashbuckle.AspNetCore.Cli
- cd ../
- dotnet build HeartTrack.sln -c Release --no-restore
- dotnet publish HeartTrack.sln -c Release --no-restore -o CI_PROJECT_DIR/build/release
- export PATH="$PATH:/root/.dotnet/tools"
- swagger tofile --output /docs/swagger.json HeartTrackAPI/bin/Release/net8.0/HeartTrackAPI.dll v1
depends_on: [build,tests]
- name: generate-and-deploy-docs
image: hub.codefirst.iut.uca.fr/maxime.batista/codefirst-docdeployer
failure: ignore
commands:
- /entrypoint.sh -l docs/doxygen -t doxygen
when:
event:
- push
depends_on: [ build ] depends_on: [ build ]
volumes:
- name: docs
temp: {}
---
kind: pipeline
type: docker
name: HeartTrack-API-CD
trigger:
event:
- push
steps:
- name: docker-build-and-push - name: docker-build-and-push
image: plugins/docker image: plugins/docker
settings: settings:
@ -49,25 +101,70 @@ steps:
from_secret: SECRET_REGISTRY_USERNAME from_secret: SECRET_REGISTRY_USERNAME
password: password:
from_secret: SECRET_REGISTRY_PASSWORD from_secret: SECRET_REGISTRY_PASSWORD
depends_on: [ build ]
- name: deploy-container # database container stub
- name: deploy-container-stub
image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dockerproxy-clientdrone:latest image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dockerproxy-clientdrone:latest
environment: environment:
CODEFIRST_CLIENTDRONE_ENV_TYPE: STUB
IMAGENAME: hub.codefirst.iut.uca.fr/david.d_almeida/api:latest
CONTAINERNAME: heart_stub
COMMAND: create
ADMINS: davidd_almeida,kevinmonteiro,antoineperederii,paullevrault,antoinepinagot,nicolas.raymond
OVERWRITE: true
depends_on: [ docker-build-and-push ]
# - name: deploy-container
# image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dockerproxy-clientdrone:latest
# environment:
# IMAGENAME: hub.codefirst.iut.uca.fr/david.d_almeida/api:latest
# CONTAINERNAME: heart_api
# CODEFIRST_CLIENTDRONE_ENV_TYPE: API
# CODEFIRST_CLIENTDRONE_ENV_PORT: 8080
# ADMINS: davidd_almeida,kevinmonteiro,antoineperederii,paullevrault,antoinepinagot,nicolas.raymond
# COMMAND: create
# 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
environment:
IMAGENAME: mariadb:10
CONTAINERNAME: mysql
COMMAND: create
OVERWRITE: true
PRIVATE: false
CODEFIRST_CLIENTDRONE_ENV_MARIADB_ROOT_PASSWORD:
from_secret: db_root_password
CODEFIRST_CLIENTDRONE_ENV_MARIADB_DATABASE:
from_secret: db_database
CODEFIRST_CLIENTDRONE_ENV_MARIADB_USER:
from_secret: db_user
CODEFIRST_CLIENTDRONE_ENV_MARIADB_PASSWORD:
from_secret: db_password
ADMINS: davidd_almeida,kevinmonteiro,antoineperederii,paullevrault,antoinepinagot,nicolas.raymond
# database container bdd
- name: deploy-container-bdd
image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dockerproxy-clientdrone:latest
environment:
CODEFIRST_CLIENTDRONE_ENV_TYPE: BDD
CODEFIRST_CLIENTDRONE_ENV_HOST: HeartDev-mysql
CODEFIRST_CLIENTDRONE_ENV_PORTDB: 3306
CODEFIRST_CLIENTDRONE_ENV_DATABASE:
from_secret: db_database
CODEFIRST_CLIENTDRONE_ENV_USERNAME:
from_secret: db_user
CODEFIRST_CLIENTDRONE_ENV_PASSWORD:
from_secret: db_password
IMAGENAME: hub.codefirst.iut.uca.fr/david.d_almeida/api:latest IMAGENAME: hub.codefirst.iut.uca.fr/david.d_almeida/api:latest
CONTAINERNAME: api CONTAINERNAME: api
CODEFIRST_CLIENTDRONE_ENV_PORT: 8080 CODEFIRST_CLIENTDRONE_ENV_PORT: 8080
ADMINS: davidd_almeida,kevinmonteiro,antoineperederii,paullevrault,antoinepinagot,nicolas.raymond ADMINS: davidd_almeida,kevinmonteiro,antoineperederii,paullevrault,antoinepinagot,nicolas.raymond
COMMAND: create COMMAND: create
OVERWRITE: true OVERWRITE: true
depends_on: [ docker-build-and-push ] depends_on: [deploy-container-mysql, docker-build-and-push, deploy-container-stub]
- name: generate-and-deploy-docs
image: hub.codefirst.iut.uca.fr/maxime.batista/codefirst-docdeployer
failure: ignore
commands:
- /entrypoint.sh -l docs/doxygen -t doxygen
when:
event:
- push
depends_on: [ build ]

3
.gitignore vendored

@ -565,4 +565,7 @@ xcuserdata/
/dataSources.local.xml /dataSources.local.xml
.ideaMigration/ .ideaMigration/
Migration/ Migration/
Migrations/
*.db *.db

@ -1,3 +1,16 @@
# EF_WebAPI # EF_WebAPI
This repository make a meeting of EF and WebAPI parts. This repository make a meeting of EF and WebAPI parts.
FROM /src dir
do
```bash
dotnet ef migrations add --project StubbedContextLib/StubbedContextLib.csproj --startup-project HeartTrackAPI/HeartTrackAPI.csproj --context StubbedContextLib.TrainingStubbedContext --configuration Debug Initial --output-dir Migrations
```
then
```bash
dotnet ef database update --project StubbedContextLib/StubbedContextLib.csproj --startup-project HeartTrackAPI/HeartTrackAPI.csproj --context StubbedContextLib.TrainingStubbedContext --configuration Debug
```

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Model\Model.csproj" />
<ProjectReference Include="..\Shared\Shared.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,53 @@
using Dto;
using Model;
using Shared;
namespace APIMappers;
public static class ActivityMapper
{
private static GenericMapper<Activity, ActivityDto> _mapper = new GenericMapper<Activity, ActivityDto>();
public static ActivityDto ToDto(this Activity activity)
{
return activity.ToU(_mapper, activityDto => new ActivityDto
{
Id = activity.Id,
Type = activity.Type,
Date = activity.Date,
StartTime = activity.StartTime,
EndTime = activity.EndTime,
EffortFelt = activity.Effort,
Variability = activity.Variability,
Variance = activity.Variance,
StandardDeviation = activity.StandardDeviation,
Average = activity.Average,
Maximum = activity.Maximum,
Minimum = activity.Minimum,
AverageTemperature = activity.AverageTemperature,
HasAutoPause = activity.HasAutoPause
});
}
public static Activity ToModel(this ActivityDto activityDto)
{
return activityDto.ToT(_mapper, activity => new Activity
{
Id = activityDto.Id,
Type = activityDto.Type,
Date = activityDto.Date,
StartTime = activityDto.StartTime,
EndTime = activityDto.EndTime,
Effort = activityDto.EffortFelt,
Variability = activityDto.Variability,
Variance = activityDto.Variance,
StandardDeviation = activityDto.StandardDeviation,
Average = activityDto.Average,
Maximum = activityDto.Maximum,
Minimum = activityDto.Minimum,
AverageTemperature = activityDto.AverageTemperature,
HasAutoPause = activityDto.HasAutoPause
});
}
}

@ -0,0 +1,51 @@
using Dto;
using Model;
using Shared;
namespace APIMappers;
public static class UserMappeur
{
private static GenericMapper<User, UserDto> _mapper = new GenericMapper<User, UserDto>();
public static UserDto ToDto(this User user)
{
return user.ToU(_mapper, userDto => new UserDto
{
Id = user.Id,
Username = user.Username,
ProfilePicture = user.ProfilePicture,
LastName = user.LastName,
FirstName = user.FirstName,
Email = user.Email,
Password = user.MotDePasse,
Sexe = user.Sexe,
Lenght = user.Lenght,
Weight = user.Weight,
DateOfBirth = user.DateOfBirth,
IsCoach = user.Role is Coach
});
}
public static User ToModel(this UserDto userDto)
{
return userDto.ToT(_mapper, user => new User
{
Username = userDto.Username,
ProfilePicture = userDto.ProfilePicture,
LastName = userDto.LastName,
FirstName = userDto.FirstName,
Email = userDto.Email,
MotDePasse = userDto.Password,
Sexe = userDto.Sexe,
Lenght = userDto.Lenght,
Weight = userDto.Weight,
DateOfBirth = userDto.DateOfBirth,
Role = userDto.IsCoach ? new Coach() : new Athlete()
});
}
}

@ -7,8 +7,10 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.2" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.2" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.2" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

@ -55,13 +55,31 @@ namespace DbContextLib
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HeartTrackContext"/> class. /// Initializes a new instance of the <see cref="HeartTrackContext"/> class.
/// </summary> /// </summary>
public HeartTrackContext() : base() { } public HeartTrackContext() : base()
{ }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HeartTrackContext"/> class with the specified options. /// Initializes a new instance of the <see cref="HeartTrackContext"/> class with the specified options.
/// </summary> /// </summary>
/// <param name="options">The options for the context.</param> /// <param name="options">The options for the context.</param>
public HeartTrackContext(DbContextOptions<HeartTrackContext> options) : base(options) { } public HeartTrackContext(DbContextOptions<HeartTrackContext> options) : base(options)
{ }
public HeartTrackContext(string dbPlatformPath)
: this(InitPlaformDb(dbPlatformPath))
{
}
private static DbContextOptions<HeartTrackContext> InitPlaformDb(string dbPlatformPath)
{
var options = new DbContextOptionsBuilder<HeartTrackContext>()
.UseMySql($"{dbPlatformPath}", new MySqlServerVersion(new Version(10, 11, 1)))
.Options;
return options;
}
/// <summary> /// <summary>
/// Configures the database options if they are not already configured. /// Configures the database options if they are not already configured.

@ -0,0 +1,25 @@
using Entities;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace DbContextLib.Identity;
public class AuthDbContext: IdentityDbContext<IdentityUser>
{
public AuthDbContext(DbContextOptions<AuthDbContext> options) : base(options) { }
public AuthDbContext() { }
/*
/// <summary>
/// Configures the database options if they are not already configured.
/// </summary>
/// <param name="optionsBuilder">The options builder instance.</param>
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlite($"Data Source=uca.HeartTrack.db");
}
}*/
}

@ -3,17 +3,17 @@ namespace Dto;
public class ActivityDto public class ActivityDto
{ {
public int Id { get; set; } public int Id { get; set; }
public string Name { get; set; } public string? Type { get; set; }
public string Type { get; set; }
public DateTime Date { get; set; } public DateTime Date { get; set; }
public TimeSpan Duration { get; set; } public DateTime StartTime { get; set; }
public float Distance { get; set; } public DateTime EndTime { get; set; }
public float Elevation { get; set; } public int EffortFelt { get; set; }
public float AverageSpeed { get; set; } public float Variability { get; set; }
public int AverageHeartRate { get; set; } public float Variance { get; set; }
public int Calories { get; set; } public float StandardDeviation { get; set; }
public string Description { get; set; } public float Average { get; set; }
public string? Gpx { get; set; } public int Maximum { get; set; }
public string? Image { get; set; } public int Minimum { get; set; }
public int AthleteId { get; set; } public float AverageTemperature { get; set; }
public bool HasAutoPause { get; set; }
} }

@ -0,0 +1,16 @@
namespace Dto;
public class ActivityFitFileDto
{
public ActivityFitFileDto(string activityName, string activityType, int effortFeel)
{
ActivityName = activityName;
ActivityType = activityType;
EffortFeel = effortFeel;
}
public string ActivityName { get; set; }
public string ActivityType { get; set; }
public int EffortFeel { get; set; }
//public IFormFile
}

@ -1,10 +1,13 @@
using Dto; using System.Buffers;
using Dto;
using Model; using Model;
namespace ApiMappeur; namespace ApiMappeur;
// anotine
public static class UserMappeur public static class UserMappeur
{ {
private static readonly ArrayPool<UserDto> UserDtoPool = ArrayPool<UserDto>.Create();
private static readonly Dictionary<User, UserDto> userToDtoMap = new Dictionary<User, UserDto>();
private static readonly Dictionary<UserDto, User> dtoToUserMap = new Dictionary<UserDto, User>();
public static UserDto ToDto(this User user) public static UserDto ToDto(this User user)
{ {
return new UserDto return new UserDto
@ -26,8 +29,71 @@ public static class UserMappeur
public static User ToModel(this UserDto userDto) public static User ToModel(this UserDto userDto)
{ {
if (userDto.IsCoach) return new User
{ {
Username = userDto.Username,
ProfilePicture = userDto.ProfilePicture,
LastName = userDto.LastName,
FirstName = userDto.FirstName,
Email = userDto.Email,
MotDePasse = userDto.Password,
Sexe = userDto.Sexe,
Lenght = userDto.Lenght,
Weight = userDto.Weight,
DateOfBirth = userDto.DateOfBirth,
Role = userDto.IsCoach ? new Coach() : new Athlete()
};
}
}
/*
using Dto;
using Model;
using System.Buffers;
namespace ApiMappeur
{
// anotine
public static class UserMappeur
{
private static readonly ArrayPool<UserDto> UserDtoPool = ArrayPool<UserDto>.Create();
public static UserDto ToDto(this User user)
{
UserDto userDto = UserDtoPool.Rent();
userDto.Id = user.Id;
userDto.Username = user.Username;
userDto.ProfilePicture = user.ProfilePicture;
userDto.LastName = user.LastName;
userDto.FirstName = user.FirstName;
userDto.Email = user.Email;
userDto.Password = user.MotDePasse;
userDto.Sexe = user.Sexe;
userDto.Lenght = user.Lenght;
userDto.Weight = user.Weight;
userDto.DateOfBirth = user.DateOfBirth;
userDto.IsCoach = user.Role is Coach;
return userDto;
}
public static User ToModel(this UserDto userDto)
{
if (userDto.IsCoach)
{
return new User(
userDto.Username,
userDto.ProfilePicture,
userDto.LastName,
userDto.FirstName,
userDto.Email,
userDto.Password,
userDto.Sexe,
userDto.Lenght,
userDto.Weight,
userDto.DateOfBirth,
new Coach()
);
}
return new User( return new User(
userDto.Username, userDto.Username,
userDto.ProfilePicture, userDto.ProfilePicture,
@ -39,20 +105,13 @@ public static class UserMappeur
userDto.Lenght, userDto.Lenght,
userDto.Weight, userDto.Weight,
userDto.DateOfBirth, userDto.DateOfBirth,
new Coach() new Athlete());
); }
public static void ReturnToPool(this UserDto userDto)
{
UserDtoPool.Return(userDto);
} }
return new User(
userDto.Username,
userDto.ProfilePicture,
userDto.LastName,
userDto.FirstName,
userDto.Email,
userDto.Password,
userDto.Sexe,
userDto.Lenght,
userDto.Weight,
userDto.DateOfBirth,
new Athlete());
} }
} }
*/

@ -29,7 +29,7 @@ namespace Entities
/// </summary> /// </summary>
[Required] [Required]
[MaxLength(100)] [MaxLength(100)]
public string Type { get; set; } = null!; public string? Type { get; set; } = null!;
/// <summary> /// <summary>
/// Gets or sets the date of the activity. /// Gets or sets the date of the activity.

@ -17,6 +17,8 @@ namespace Entities
[Table("Athlete")] [Table("Athlete")]
public class AthleteEntity public class AthleteEntity
{ {
public AthleteEntity() : base() { }
/// <summary> /// <summary>
/// Gets or sets the unique identifier of the athlete. /// Gets or sets the unique identifier of the athlete.
/// </summary> /// </summary>
@ -28,35 +30,35 @@ namespace Entities
/// Gets or sets the username of the athlete. /// Gets or sets the username of the athlete.
/// </summary> /// </summary>
[MaxLength(100)] [MaxLength(100)]
[Required(ErrorMessage = "Athlete Username is required")] [Required(ErrorMessage = "Athlete Username is ")]
public required string Username { get; set; } public required string Username { get; set; }
/// <summary> /// <summary>
/// Gets or sets the last name of the athlete. /// Gets or sets the last name of the athlete.
/// </summary> /// </summary>
[MaxLength(100)] [MaxLength(100)]
[Required(ErrorMessage = "Athlete Last Name is required")] [Required(ErrorMessage = "Athlete Last Name is ")]
public required string LastName { get; set; } public required string LastName { get; set; }
/// <summary> /// <summary>
/// Gets or sets the first name of the athlete. /// Gets or sets the first name of the athlete.
/// </summary> /// </summary>
[MaxLength(150)] [MaxLength(150)]
[Required(ErrorMessage = "Athlete First Name is required")] [Required(ErrorMessage = "Athlete First Name is ")]
public required string FirstName { get; set; } public required string FirstName { get; set; }
/// <summary> /// <summary>
/// Gets or sets the email of the athlete. /// Gets or sets the email of the athlete.
/// </summary> /// </summary>
[MaxLength(100)] [MaxLength(100)]
[Required(ErrorMessage = "Athlete Email is required")] [Required(ErrorMessage = "Athlete Email is ")]
public required string Email { get; set; } public required string Email { get; set; }
/// <summary> /// <summary>
/// Gets or sets the gender of the athlete. /// Gets or sets the gender of the athlete.
/// </summary> /// </summary>
[MaxLength(1)] [MaxLength(1)]
[Required(ErrorMessage = "Athlete Sexe is required")] [Required(ErrorMessage = "Athlete Sexe is ")]
public required string Sexe { get; set; } public required string Sexe { get; set; }
/// <summary> /// <summary>
@ -72,13 +74,13 @@ namespace Entities
/// <summary> /// <summary>
/// Gets or sets the password of the athlete. /// Gets or sets the password of the athlete.
/// </summary> /// </summary>
[Required(ErrorMessage = "Athlete Password is required")] [Required(ErrorMessage = "Athlete Password is ")]
public required string Password { get; set; } public required string Password { get; set; }
/// <summary> /// <summary>
/// Gets or sets the date of birth of the athlete. /// Gets or sets the date of birth of the athlete.
/// </summary> /// </summary>
[Required(ErrorMessage = "Athlete Date of Birth is required")] [Required(ErrorMessage = "Athlete Date of Birth is ")]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)] [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
public DateOnly DateOfBirth { get; set; } public DateOnly DateOfBirth { get; set; }
@ -87,7 +89,7 @@ namespace Entities
/// </summary> /// </summary>
public bool IsCoach { get; set; } public bool IsCoach { get; set; }
public required byte[] ProfilPicture { get; set; } public byte[]? ProfilPicture { get; set; }

@ -5,5 +5,4 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

@ -3,52 +3,49 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59 VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DbContextLib", "DbContextLib\DbContextLib.csproj", "{330A5DA0-0B4E-48D4-9AF3-6DCB39EE9622}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DbContextLib", "DbContextLib\DbContextLib.csproj", "{330A5DA0-0B4E-48D4-9AF3-6DCB39EE9622}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entities", "Entities\Entities.csproj", "{A07F86B3-555B-4B35-8BB1-25E844825A38}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Entities", "Entities\Entities.csproj", "{A07F86B3-555B-4B35-8BB1-25E844825A38}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StubbedContextLib", "StubbedContextLib\StubbedContextLib.csproj", "{2F44DE6E-EFFC-42FE-AFF6-79CDC762E6D8}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StubbedContextLib", "StubbedContextLib\StubbedContextLib.csproj", "{2F44DE6E-EFFC-42FE-AFF6-79CDC762E6D8}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{2B227C67-3BEC-4A83-BDA0-F3918FBC0D18}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{2B227C67-3BEC-4A83-BDA0-F3918FBC0D18}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleTestEntities", "Tests\ConsoleTestEntities\ConsoleTestEntities.csproj", "{477D2129-A6C9-4FF8-8BE9-5E9E8E5282F8}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleTestEntities", "Tests\ConsoleTestEntities\ConsoleTestEntities.csproj", "{477D2129-A6C9-4FF8-8BE9-5E9E8E5282F8}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleTestRelationships", "Tests\ConsoleTestRelationships\ConsoleTestRelationships.csproj", "{2D166FAD-4934-474B-96A8-6C0635156EC2}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleTestRelationships", "Tests\ConsoleTestRelationships\ConsoleTestRelationships.csproj", "{2D166FAD-4934-474B-96A8-6C0635156EC2}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dto", "Dto\Dto.csproj", "{562019BC-0F61-41B0-9BAE-259B92C6BFBA}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dto", "Dto\Dto.csproj", "{562019BC-0F61-41B0-9BAE-259B92C6BFBA}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeartTrackAPI", "HeartTrackAPI\HeartTrackAPI.csproj", "{C1C2EAC3-3347-466B-BFB6-2A9F11A3AE12}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HeartTrackAPI", "HeartTrackAPI\HeartTrackAPI.csproj", "{C1C2EAC3-3347-466B-BFB6-2A9F11A3AE12}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared", "Shared\Shared.csproj", "{F80C60E1-1E06-46C2-96DE-42B1C7DE65BC}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "Shared\Shared.csproj", "{F80C60E1-1E06-46C2-96DE-42B1C7DE65BC}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestsAPI", "TestsAPI", "{30FC2BE9-7397-445A-84AD-043CE70F4281}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestsAPI", "TestsAPI", "{30FC2BE9-7397-445A-84AD-043CE70F4281}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClientTests", "Tests\TestsAPI\ClientTests\ClientTests.csproj", "{9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClientTests", "Tests\TestsAPI\ClientTests\ClientTests.csproj", "{9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestsXUnit", "Tests\TestsAPI\TestsXUnit\TestsXUnit.csproj", "{44C367DC-5FE0-4CF2-9E76-A0282E931853}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model", "Model\Model.csproj", "{30AB7FAA-6072-40B6-A15E-9188B59144F9}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "Model\Model.csproj", "{30AB7FAA-6072-40B6-A15E-9188B59144F9}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTestApi", "Tests\TestsAPI\UnitTestApi\UnitTestApi.csproj", "{E515C8B6-6282-4D8B-8523-7B3A13E4AF58}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestApi", "Tests\TestsAPI\UnitTestApi\UnitTestApi.csproj", "{E515C8B6-6282-4D8B-8523-7B3A13E4AF58}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTestsEntities", "Tests\UnitTestsEntities\UnitTestsEntities.csproj", "{31FA8E5E-D642-4C43-A2B2-02B9832B2CEC}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestsEntities", "Tests\UnitTestsEntities\UnitTestsEntities.csproj", "{31FA8E5E-D642-4C43-A2B2-02B9832B2CEC}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model2Entities", "Model2Entities\Model2Entities.csproj", "{FA329DEF-4756-4A8B-84E9-5A625FF94CBF}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model2Entities", "Model2Entities\Model2Entities.csproj", "{FA329DEF-4756-4A8B-84E9-5A625FF94CBF}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StubAPI", "StubAPI\StubAPI.csproj", "{C9BD0310-DC18-4356-B8A7-2B6959AF7813}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StubAPI", "StubAPI\StubAPI.csproj", "{C9BD0310-DC18-4356-B8A7-2B6959AF7813}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleTestEFMapper", "Tests\ConsoleTestEFMapper\ConsoleTestEFMapper.csproj", "{73EA27F2-9F0C-443F-A5EE-2960C983A422}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleTestEFMapper", "Tests\ConsoleTestEFMapper\ConsoleTestEFMapper.csproj", "{73EA27F2-9F0C-443F-A5EE-2960C983A422}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EFMappers", "EFMappers\EFMappers.csproj", "{9397795D-F482-44C4-8443-A20AC26671AA}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EFMappers", "EFMappers\EFMappers.csproj", "{9397795D-F482-44C4-8443-A20AC26671AA}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APIMappers", "APIMappers\APIMappers.csproj", "{41D18203-1688-43BD-A3AC-FD0C2BD81909}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{330A5DA0-0B4E-48D4-9AF3-6DCB39EE9622}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {330A5DA0-0B4E-48D4-9AF3-6DCB39EE9622}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{330A5DA0-0B4E-48D4-9AF3-6DCB39EE9622}.Debug|Any CPU.Build.0 = Debug|Any CPU {330A5DA0-0B4E-48D4-9AF3-6DCB39EE9622}.Debug|Any CPU.Build.0 = Debug|Any CPU
@ -86,22 +83,10 @@ Global
{9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
{9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}.Release|Any CPU.Build.0 = Release|Any CPU {9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}.Release|Any CPU.Build.0 = Release|Any CPU
{44C367DC-5FE0-4CF2-9E76-A0282E931853}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{44C367DC-5FE0-4CF2-9E76-A0282E931853}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44C367DC-5FE0-4CF2-9E76-A0282E931853}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44C367DC-5FE0-4CF2-9E76-A0282E931853}.Release|Any CPU.Build.0 = Release|Any CPU
{30AB7FAA-6072-40B6-A15E-9188B59144F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {30AB7FAA-6072-40B6-A15E-9188B59144F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{30AB7FAA-6072-40B6-A15E-9188B59144F9}.Debug|Any CPU.Build.0 = Debug|Any CPU {30AB7FAA-6072-40B6-A15E-9188B59144F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{30AB7FAA-6072-40B6-A15E-9188B59144F9}.Release|Any CPU.ActiveCfg = Release|Any CPU {30AB7FAA-6072-40B6-A15E-9188B59144F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{30AB7FAA-6072-40B6-A15E-9188B59144F9}.Release|Any CPU.Build.0 = Release|Any CPU {30AB7FAA-6072-40B6-A15E-9188B59144F9}.Release|Any CPU.Build.0 = Release|Any CPU
{CB142F6B-0FF1-45B3-AB46-6F8DCD096C20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB142F6B-0FF1-45B3-AB46-6F8DCD096C20}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB142F6B-0FF1-45B3-AB46-6F8DCD096C20}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CB142F6B-0FF1-45B3-AB46-6F8DCD096C20}.Release|Any CPU.Build.0 = Release|Any CPU
{B9679DCA-F4C8-45BE-A849-44E2BA814083}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B9679DCA-F4C8-45BE-A849-44E2BA814083}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B9679DCA-F4C8-45BE-A849-44E2BA814083}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B9679DCA-F4C8-45BE-A849-44E2BA814083}.Release|Any CPU.Build.0 = Release|Any CPU
{E515C8B6-6282-4D8B-8523-7B3A13E4AF58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E515C8B6-6282-4D8B-8523-7B3A13E4AF58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E515C8B6-6282-4D8B-8523-7B3A13E4AF58}.Debug|Any CPU.Build.0 = Debug|Any CPU {E515C8B6-6282-4D8B-8523-7B3A13E4AF58}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E515C8B6-6282-4D8B-8523-7B3A13E4AF58}.Release|Any CPU.ActiveCfg = Release|Any CPU {E515C8B6-6282-4D8B-8523-7B3A13E4AF58}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -118,31 +103,32 @@ Global
{C9BD0310-DC18-4356-B8A7-2B6959AF7813}.Debug|Any CPU.Build.0 = Debug|Any CPU {C9BD0310-DC18-4356-B8A7-2B6959AF7813}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C9BD0310-DC18-4356-B8A7-2B6959AF7813}.Release|Any CPU.ActiveCfg = Release|Any CPU {C9BD0310-DC18-4356-B8A7-2B6959AF7813}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C9BD0310-DC18-4356-B8A7-2B6959AF7813}.Release|Any CPU.Build.0 = Release|Any CPU {C9BD0310-DC18-4356-B8A7-2B6959AF7813}.Release|Any CPU.Build.0 = Release|Any CPU
{06DBE9E4-6AA5-4D09-8544-D3ED91E2D980}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{06DBE9E4-6AA5-4D09-8544-D3ED91E2D980}.Debug|Any CPU.Build.0 = Debug|Any CPU
{06DBE9E4-6AA5-4D09-8544-D3ED91E2D980}.Release|Any CPU.ActiveCfg = Release|Any CPU
{06DBE9E4-6AA5-4D09-8544-D3ED91E2D980}.Release|Any CPU.Build.0 = Release|Any CPU
{73EA27F2-9F0C-443F-A5EE-2960C983A422}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {73EA27F2-9F0C-443F-A5EE-2960C983A422}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{73EA27F2-9F0C-443F-A5EE-2960C983A422}.Debug|Any CPU.Build.0 = Debug|Any CPU {73EA27F2-9F0C-443F-A5EE-2960C983A422}.Debug|Any CPU.Build.0 = Debug|Any CPU
{73EA27F2-9F0C-443F-A5EE-2960C983A422}.Release|Any CPU.ActiveCfg = Release|Any CPU {73EA27F2-9F0C-443F-A5EE-2960C983A422}.Release|Any CPU.ActiveCfg = Release|Any CPU
{73EA27F2-9F0C-443F-A5EE-2960C983A422}.Release|Any CPU.Build.0 = Release|Any CPU {73EA27F2-9F0C-443F-A5EE-2960C983A422}.Release|Any CPU.Build.0 = Release|Any CPU
{C9C9F2A5-9132-4067-B240-B299D2FCF4E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C9C9F2A5-9132-4067-B240-B299D2FCF4E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C9C9F2A5-9132-4067-B240-B299D2FCF4E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C9C9F2A5-9132-4067-B240-B299D2FCF4E9}.Release|Any CPU.Build.0 = Release|Any CPU
{9397795D-F482-44C4-8443-A20AC26671AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9397795D-F482-44C4-8443-A20AC26671AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9397795D-F482-44C4-8443-A20AC26671AA}.Debug|Any CPU.Build.0 = Debug|Any CPU {9397795D-F482-44C4-8443-A20AC26671AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9397795D-F482-44C4-8443-A20AC26671AA}.Release|Any CPU.ActiveCfg = Release|Any CPU {9397795D-F482-44C4-8443-A20AC26671AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9397795D-F482-44C4-8443-A20AC26671AA}.Release|Any CPU.Build.0 = Release|Any CPU {9397795D-F482-44C4-8443-A20AC26671AA}.Release|Any CPU.Build.0 = Release|Any CPU
{41D18203-1688-43BD-A3AC-FD0C2BD81909}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{41D18203-1688-43BD-A3AC-FD0C2BD81909}.Debug|Any CPU.Build.0 = Debug|Any CPU
{41D18203-1688-43BD-A3AC-FD0C2BD81909}.Release|Any CPU.ActiveCfg = Release|Any CPU
{41D18203-1688-43BD-A3AC-FD0C2BD81909}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{477D2129-A6C9-4FF8-8BE9-5E9E8E5282F8} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} {477D2129-A6C9-4FF8-8BE9-5E9E8E5282F8} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18}
{2D166FAD-4934-474B-96A8-6C0635156EC2} = {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} {30FC2BE9-7397-445A-84AD-043CE70F4281} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18}
{9E4D3AC5-E6CA-4753-BD96-BF5EE793931A} = {30FC2BE9-7397-445A-84AD-043CE70F4281} {9E4D3AC5-E6CA-4753-BD96-BF5EE793931A} = {30FC2BE9-7397-445A-84AD-043CE70F4281}
{44C367DC-5FE0-4CF2-9E76-A0282E931853} = {30FC2BE9-7397-445A-84AD-043CE70F4281}
{E515C8B6-6282-4D8B-8523-7B3A13E4AF58} = {30FC2BE9-7397-445A-84AD-043CE70F4281} {E515C8B6-6282-4D8B-8523-7B3A13E4AF58} = {30FC2BE9-7397-445A-84AD-043CE70F4281}
{31FA8E5E-D642-4C43-A2B2-02B9832B2CEC} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} {31FA8E5E-D642-4C43-A2B2-02B9832B2CEC} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18}
{73EA27F2-9F0C-443F-A5EE-2960C983A422} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} {73EA27F2-9F0C-443F-A5EE-2960C983A422} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0F3487F4-66CA-4034-AC66-1BC899C9B523}
EndGlobalSection
EndGlobal EndGlobal

@ -0,0 +1,224 @@
using System.Reflection;
using DbContextLib;
using DbContextLib.Identity;
using Entities;
using HeartTrackAPI.Utils;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Model.Manager;
using Model2Entities;
using StubAPI;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace HeartTrackAPI;
public class AppBootstrap(IConfiguration configuration)
{
private IConfiguration Configuration { get; } = configuration;
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddEndpointsApiExplorer();
AddSwagger(services);
// include Xml comment
// addsecurityRequiment
// securityDef
AddHeartTrackContextServices(services);
AddModelService(services);
AddIdentityServices(services);
AddApiVersioning(services);
services.AddHealthChecks();
}
private void AddHeartTrackContextServices(IServiceCollection services)
{
string connectionString;
switch (Environment.GetEnvironmentVariable("TYPE"))
{
case "BDD":
var HOST = System.Environment.GetEnvironmentVariable("HOST");
var PORT = System.Environment.GetEnvironmentVariable("PORTDB");
var DATABASE = System.Environment.GetEnvironmentVariable("DATABASE");
var USERNAME = System.Environment.GetEnvironmentVariable("USERNAME");
var PASSWORD = System.Environment.GetEnvironmentVariable("PASSWORD");
connectionString = $"Server={HOST};port={PORT};database={DATABASE};user={USERNAME};password={PASSWORD}";
Console.WriteLine(connectionString);
Console.WriteLine("======================");
Console.WriteLine($"server={HOST};port={PORT};database={DATABASE};user={USERNAME};password={PASSWORD}");
Console.WriteLine(connectionString);
services.AddDbContext<HeartTrackContext>(options =>
options.UseMySql($"{connectionString}", new MySqlServerVersion(new Version(10, 11, 1)))
, ServiceLifetime.Singleton);
break;
default:
connectionString = Configuration.GetConnectionString("HeartTrackAuthConnection");
if (!string.IsNullOrWhiteSpace(connectionString))
{
services.AddDbContext<AuthDbContext>(options => options.UseInMemoryDatabase("AuthDb"));
Console.WriteLine(connectionString);
Console.WriteLine("======================");
//options => options.UseSqlite(connectionString)
//services.AddDbContext<HeartTrackContext>();
services.AddDbContext<HeartTrackContext>(options =>
options.UseSqlite(connectionString), ServiceLifetime.Singleton);
}
else
{
services.AddDbContext<AuthDbContext>(options => options.UseInMemoryDatabase("AuthDb"));
services.AddDbContext<HeartTrackContext>(options => options.UseInMemoryDatabase("HeartTrackDb"));
}
break;
}
/*
services.AddSingleton<DbContextOptions<HeartTrackContext>>(provider =>
{
var connection = new SqliteConnection("DataSource=:memory:");
connection.Open();
var options = new DbContextOptionsBuilder<HeartTrackContext>()
.UseSqlite(connection)
.Options;
return options;
});*/
}
private void AddModelService(IServiceCollection services)
{
//services.AddSingleton<IDataManager>(provider => new DbDataManager(provider.GetService<HeartTrackContext>()));
//services.AddSingleton<IDataManager, StubData>();
services.AddSingleton<IDataManager>(provider => new DbDataManager(provider.GetRequiredService<HeartTrackContext>()));
//services.AddTransient<IActivityManager, ActivityManager>();
}
private void AddIdentityServices(IServiceCollection services)
{
// services.AddTransient<IEmailSender<AthleteEntity>, EmailSender>();
services.AddAuthorization();
services.AddIdentityApiEndpoints<IdentityUser>()
.AddEntityFrameworkStores<AuthDbContext>();
//services.AddIdentity<AthleteEntity, IdentityRole>()
// .AddEntityFrameworkStores<AuthDbContext>().AddDefaultTokenProviders();
}
private void AddApiVersioning(IServiceCollection services)
{
services.AddApiVersioning(opt =>
{
opt.ReportApiVersions = true;
opt.AssumeDefaultVersionWhenUnspecified = true;
opt.DefaultApiVersion = new Microsoft.AspNetCore.Mvc.ApiVersion(1, 0);
// options.ApiVersionReader = new HeaderApiVersionReader("api-version");
opt.ApiVersionReader = ApiVersionReader.Combine(new UrlSegmentApiVersionReader(),
new HeaderApiVersionReader("x-api-version"),
new MediaTypeApiVersionReader("x-api-version"));
});
}
private void AddSwagger(IServiceCollection services)
{
services.AddSwaggerGen(options =>
{
options.OperationFilter<SwaggerDefaultValues>();
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
});
var scheme = new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Scheme = "oauth2",
Name = "Bearer",
In = ParameterLocation.Header,
},
new List<string>()
}
};
options.AddSecurityRequirement(scheme);
});
services.AddTransient<IConfigureOptions<SwaggerGenOptions>, SwaggerOptions>();
services.AddSwaggerGen(options =>
{
options.OperationFilter<SwaggerDefaultValues>();
});
/* services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "HeartTrackAPI", Version = "v1" });
options.SwaggerDoc("v2", new OpenApiInfo { Title = "HeartTrackAPI", Version = "v2" });
});*/
services.AddVersionedApiExplorer(setup =>
{
setup.GroupNameFormat = "'v'VVV";
setup.SubstituteApiVersionInUrl = true;
});
}
public void Configure(WebApplication app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.MapIdentityApi<IdentityUser>();
app.MapControllers();
app.UseAuthorization();
app.MapHealthChecks("/health");
// Configure the HTTP request pipeline.
if (true)
{
var apiVersionDescriptionProvider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>();
app.UseSwagger();
app.UseSwaggerUI();
app.MapSwagger();
app.UseSwaggerUI(options =>
{
foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions)
//foreach (var description in apiVersionDescriptionProvider)
{
options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json",
description.GroupName.ToUpperInvariant());
}
});
}
}
}

@ -1,22 +1,25 @@
using APIMappers;
using Dto; using Dto;
using HeartTrackAPI.Request; using HeartTrackAPI.Request;
using HeartTrackAPI.Responce; using HeartTrackAPI.Responce;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Shared;
using Model; using Model;
using Shared;
using Model.Manager;
using Model.Repository; using Model.Repository;
namespace HeartTrackAPI.Controllers; namespace HeartTrackAPI.Controllers;
[ApiController] [ApiController]
[Route("api/activities")] [ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class ActivityController : Controller public class ActivityController : Controller
{ {
private readonly IActivityRepository _activityService; private readonly IActivityRepository _activityService;
private readonly ILogger<ActivityController> _logger; private readonly ILogger<ActivityController> _logger;
public ActivityController(IActivityRepository activityService, ILogger<ActivityController> logger) public ActivityController(IDataManager dataManager, ILogger<ActivityController> logger)
{ {
_activityService = activityService; _activityService = dataManager.ActivityRepo;
_logger = logger; _logger = logger;
} }
@ -36,9 +39,12 @@ public class ActivityController : Controller
} }
_logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetActivities), pageRequest); _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetActivities), pageRequest);
var activities = await _activityService.GetActivities(pageRequest.Index, pageRequest.Count, ActivityOrderCriteria.None, pageRequest.Descending ?? false); var activities = await _activityService.GetActivities(pageRequest.Index, pageRequest.Count, ActivityOrderCriteria.None, pageRequest.Descending ?? false);
// var pageResponse = new PageResponse<ActivityDto>(pageRequest.Index, pageRequest.Count, totalCount, activities.Select(a => a.ToDto())); if(activities == null)
// return Ok(pageResponse); {
return Ok(); return NotFound("No activities found");
}
var pageResponse = new PageResponse<ActivityDto>(pageRequest.Index, pageRequest.Count, totalCount, activities.Select(a => a.ToDto()));
return Ok(pageResponse);
} }
catch (Exception e) catch (Exception e)
{ {
@ -46,7 +52,64 @@ public class ActivityController : Controller
return StatusCode(500); return StatusCode(500);
} }
} }
/* /*
[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status415UnsupportedMediaType)]
[MultipartFormData]
[DisableFormValueModelBinding]
public async Task<IActionResult> 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}")] [HttpGet("{id}")]
public async Task<ActionResult<ActivityDto>> GetActivity(int id) public async Task<ActionResult<ActivityDto>> GetActivity(int id)
{ {
@ -58,18 +121,6 @@ public class ActivityController : Controller
return Ok(activity.ToDto()); return Ok(activity.ToDto());
} }
[HttpPost]
public async Task<ActionResult<ActivityDto>> PostActivity(ActivityDto activityDto)
{
var activity = activityDto.ToModel();
var result = await _activityService.AddActivity(activity);
if (result == null)
{
return BadRequest();
}
return CreatedAtAction(nameof(GetActivity), new { id = result.Id }, result.ToDto());
}
[HttpPut("{id}")] [HttpPut("{id}")]
public async Task<IActionResult> PutActivity(int id, ActivityDto activityDto) public async Task<IActionResult> PutActivity(int id, ActivityDto activityDto)
{ {
@ -95,5 +146,35 @@ public class ActivityController : Controller
return NotFound(); return NotFound();
} }
return NoContent(); return NoContent();
}
/*
public async Task<FileUploadSummary> UploadFileAsync(Stream fileStream, string contentType)
{
var fileCount = 0;
long totalSizeInBytes = 0;
var boundary = GetBoundary(MediaTypeHeaderValue.Parse(contentType));
var multipartReader = new MultipartReader(boundary, fileStream);
var section = await multipartReader.ReadNextSectionAsync();
var filePaths = new List<string>();
var notUploadedFiles = new List<string>();
while (section != null)
{
var fileSection = section.AsFileSection();
if (fileSection != null)
{
totalSizeInBytes += await SaveFileAsync(fileSection, filePaths, notUploadedFiles);
fileCount++;
}
section = await multipartReader.ReadNextSectionAsync();
}
return new FileUploadSummary
{
TotalFilesUploaded = fileCount,
TotalSizeUploaded = ConvertSizeToString(totalSizeInBytes),
FilePaths = filePaths,
NotUploadedFiles = notUploadedFiles
};
}*/ }*/
} }

@ -1,26 +1,42 @@
using System.ComponentModel.DataAnnotations;
using APIMappers;
using Dto; using Dto;
using HeartTrackAPI.Request; using HeartTrackAPI.Request;
using HeartTrackAPI.Responce; using HeartTrackAPI.Responce;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Model;
using Model.Manager; using Model.Manager;
using Model.Repository; using Model.Repository;
using Shared; using Shared;
namespace HeartTrackAPI.Controllers; namespace HeartTrackAPI.Controllers;
/// <summary>
/// Contrôle les actions liées aux utilisateurs dans l'application HeartTrack.
/// Gère les opérations CRUD sur les utilisateurs, leurs amis, et leurs activités.
/// </summary>
[ApiController] [ApiController]
[Route("api/users")] [ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class UsersController : Controller public class UsersController : Controller
{ {
private readonly ILogger<UsersController> _logger; private readonly ILogger<UsersController> _logger;
private readonly IActivityRepository _activityService;
private readonly IUserRepository _userService; private readonly IUserRepository _userService;
public UsersController(ILogger<UsersController> logger, IDataManager dataManager) public UsersController(ILogger<UsersController> logger, IDataManager dataManager)
{ {
_logger = logger; _logger = logger;
_userService = dataManager.UserRepo; _userService = dataManager.UserRepo;
_activityService = dataManager.ActivityRepo;
} }
/// <summary>
/// Récupère une page d'utilisateurs en fonction des critères de pagination et de tri fournis.
/// </summary>
/// <param name="request">Les critères de pagination et de tri pour les utilisateurs.</param>
/// <returns>Une page de données utilisateur selon les critères spécifiés.</returns>
/// <response code="200">Retourne la page demandée d'utilisateurs.</response>
/// <response code="400">La demande de pagination est invalide.</response>
/// <response code="500">Erreur interne du serveur.</response>
[HttpGet] [HttpGet]
[ProducesResponseType(typeof(PageResponse<UserDto>), 200)] [ProducesResponseType(typeof(PageResponse<UserDto>), 200)]
[ProducesResponseType(400)] [ProducesResponseType(400)]
@ -39,22 +55,29 @@ public class UsersController : Controller
_logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(Get), null); _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(Get), null);
var athletes = await _userService.GetUsers(request.Index, request.Count, Enum.TryParse(request.OrderingPropertyName, out AthleteOrderCriteria result) ? result : AthleteOrderCriteria.None, request.Descending ?? false); var 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<UserDto>(request.Index, request.Count, totalCount, athletes.Select(a => a.ToDto())); var pageResponse = new PageResponse<UserDto>(request.Index, request.Count, totalCount, athletes!.Select(a => a.ToDto()));
// return Ok(pageResponse); return Ok(pageResponse);
return Ok();
} }
catch (Exception e) catch (Exception e)
{ {
_logger.LogError(e, "Error while getting all athletes"); _logger.LogError(e, "Error while getting all athletes");
return StatusCode(500); return Problem();
} }
} }
/// <summary>
/// Récupère un utilisateur spécifique par son identifiant.
/// </summary>
/// <param name="id">L'identifiant de l'utilisateur à récupérer.</param>
/// <returns>L'utilisateur correspondant à l'identifiant spécifié.</returns>
/// <response code="200">Retourne l'utilisateur demandé.</response>
/// <response code="404">Aucun utilisateur trouvé pour l'identifiant spécifié.</response>
/// <response code="500">Erreur interne du serveur.</response>
[HttpGet("{id}")] [HttpGet("{id}")]
[ProducesResponseType(typeof(UserDto), 200)] [ProducesResponseType(typeof(UserDto), 200)]
[ProducesResponseType(404)] [ProducesResponseType(404)]
[ProducesResponseType(500)] [ProducesResponseType(500)]
public async Task<ActionResult<UserDto>> GetById(int id) public async Task<ActionResult<UserDto>> GetById([Range(0,int.MaxValue)]int id)
{ {
try try
{ {
@ -65,17 +88,21 @@ public class UsersController : Controller
_logger.LogError("Athlete with id {id} not found", id); _logger.LogError("Athlete with id {id} not found", id);
return NotFound($"Athlete with id {id} not found"); return NotFound($"Athlete with id {id} not found");
} }
// return Ok(athlete.ToDto()); return Ok(athlete.ToDto());
return Ok();
} }
catch (Exception e) catch (Exception e)
{ {
_logger.LogError(e, "Error while getting athlete by id {id}", id); _logger.LogError(e, "Error while getting athlete by id {id}", id);
return StatusCode(500); return Problem();
} }
} }
/// <summary>
/// Obtient le nombre total d'utilisateurs.
/// </summary>
/// <returns>Le nombre total d'utilisateurs.</returns>
/// <response code="200">Retourne le nombre total d'utilisateurs.</response>
/// <response code="500">Erreur interne du serveur.</response>
[HttpGet("count")] [HttpGet("count")]
[ProducesResponseType(typeof(int), 200)] [ProducesResponseType(typeof(int), 200)]
[ProducesResponseType(500)] [ProducesResponseType(500)]
@ -90,10 +117,19 @@ public class UsersController : Controller
catch (Exception e) catch (Exception e)
{ {
_logger.LogError(e, "Error while getting the number of users"); _logger.LogError(e, "Error while getting the number of users");
return StatusCode(500); return Problem();
} }
} }
/// <summary>
/// Met à jour les informations d'un utilisateur spécifique.
/// </summary>
/// <param name="id">L'identifiant de l'utilisateur à mettre à jour.</param>
/// <param name="user">Les données de l'utilisateur pour la mise à jour.</param>
/// <returns>L'utilisateur mis à jour.</returns>
/// <response code="200">Retourne l'utilisateur mis à jour.</response>
/// <response code="404">Utilisateur non trouvé.</response>
/// <response code="500">Erreur interne du serveur.</response>
[HttpPut("{id}")] [HttpPut("{id}")]
[ProducesResponseType(typeof(UserDto), 200)] [ProducesResponseType(typeof(UserDto), 200)]
[ProducesResponseType(404)] [ProducesResponseType(404)]
@ -109,23 +145,30 @@ public class UsersController : Controller
_logger.LogError("Athlete with id {id} not found", id); _logger.LogError("Athlete with id {id} not found", id);
return NotFound($"Athlete with id {id} not found"); return NotFound($"Athlete with id {id} not found");
} }
// var updatedAthlete = await _userService.UpdateItem(id, user.ToModel()); var updatedAthlete = await _userService.UpdateItem(id, user.ToModel());
// if(updatedAthlete == null) if(updatedAthlete == null)
// { {
// _logger.LogError("Error while updating athlete with id {id}", id); _logger.LogError("Error while updating athlete with id {id}", id);
// return StatusCode(500); return Problem();
// } }
// return Ok(updatedAthlete.ToDto()); return Ok(updatedAthlete.ToDto());
return Ok();
} }
catch (Exception e) catch (Exception e)
{ {
_logger.LogError(e, "Error while getting the number of users"); _logger.LogError(e, "Error while getting the number of users");
return StatusCode(500); return Problem();
} }
} }
/// <summary>
/// Supprime un utilisateur spécifique.
/// </summary>
/// <param name="id">L'identifiant de l'utilisateur à supprimer.</param>
/// <returns>Action result.</returns>
/// <response code="200">Utilisateur supprimé avec succès.</response>
/// <response code="404">Utilisateur non trouvé.</response>
/// <response code="500">Erreur interne du serveur.</response>
[HttpDelete("{id}")] [HttpDelete("{id}")]
[ProducesResponseType(200)] [ProducesResponseType(200)]
[ProducesResponseType(404)] [ProducesResponseType(404)]
@ -147,16 +190,256 @@ public class UsersController : Controller
if(!isDeleted) if(!isDeleted)
{ {
_logger.LogError("Error while deleting athlete with id {id}", id); _logger.LogError("Error while deleting athlete with id {id}", id);
return StatusCode(500); return Problem();
}
return Ok();
}
catch (Exception e)
{
_logger.LogError(e, "Error while getting the number of users");
return Problem();
}
}
/// <summary>
/// Obtient la liste des amis d'un utilisateur spécifique.
/// </summary>
/// <param name="id">L'identifiant de l'utilisateur.</param>
/// <param name="request">Les critères de pagination et de tri.</param>
/// <returns>La liste paginée des amis.</returns>
/// <response code="200">Retourne la liste paginée des amis de l'utilisateur.</response>
/// <response code="404">Utilisateur non trouvé.</response>
/// <response code="500">Erreur interne du serveur.</response>
[HttpGet("{id}/friends")]
[ProducesResponseType(typeof(PageResponse<UserDto>), 200)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task<ActionResult<PageResponse<UserDto>>> 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);
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);
if (friends == null) return NotFound();
var pageResponse = new PageResponse<UserDto>(request.Index, request.Count, totalCount, friends.Select(a => a.ToDto()));
return Ok(pageResponse);
}
catch (Exception e)
{
_logger.LogError(e, "Error while getting the number of users");
return Problem();
}
}
/// <summary>
/// Ajoute un ami à un utilisateur spécifique.
/// </summary>
/// <param name="id">L'identifiant de l'utilisateur.</param>
/// <param name="friendId">L'identifiant de l'ami à ajouter.</param>
/// <returns>Action result.</returns>
/// <response code="200">Ami ajouté avec succès.</response>
/// <response code="404">Utilisateur ou ami non trouvé.</response>
/// <response code="500">Erreur interne du serveur.</response>
[HttpPost("{id}/friend/{friendId}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task<IActionResult> AddFriend(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);
if(!isAdded)
{
_logger.LogError("Error while adding friend with id {friendId} to athlete with id {id}", friendId, id);
return Problem();
}
return Ok();
}
catch (Exception e)
{
_logger.LogError(e, "Error while getting the number of users");
return Problem();
}
}
/// <summary>
/// Supprime un ami d'un utilisateur spécifique.
/// </summary>
/// <param name="id">L'identifiant de l'utilisateur.</param>
/// <param name="friendId">L'identifiant de l'ami à supprimer.</param>
/// <returns>Action result.</returns>
/// <response code="200">Ami supprimé avec succès.</response>
/// <response code="404">Utilisateur ou ami non trouvé.</response>
/// <response code="500">Erreur interne du serveur.</response>
[HttpDelete("{id}/friend/{friendId}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task<IActionResult> RemoveFriend(int id, int friendId)
{
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);
if(!isRemoved)
{
_logger.LogError("Error while removing friend with id {friendId} to athlete with id {id}", friendId, id);
return Problem();
} }
return Ok(); return Ok();
} }
catch (Exception e) catch (Exception e)
{ {
_logger.LogError(e, "Error while getting the number of users"); _logger.LogError(e, "Error while getting the number of users");
return StatusCode(500); return Problem();
} }
} }
// #[TODO] [Dave] ou faire un get qui si le role est coach resend les athletes et si le role est athlete resend les coach
/// <summary>
/// Obtient la liste des athlètes d'un coach spécifique.
/// </summary>
/// <param name="coachId">L'identifiant du coach.</param>
/// <param name="request">Les critères de pagination et de tri.</param>
/// <returns>La liste paginée des athlètes.</returns>
/// <response code="200">Retourne la liste paginée des athlètes du coach.</response>
/// <response code="404">Coach non trouvé.</response>
/// <response code="500">Erreur interne du serveur.</response>
[HttpGet("{coachId}/athletes")]
[ProducesResponseType(typeof(PageResponse<UserDto>), 200)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task<ActionResult<PageResponse<UserDto>>> GetAthletes(int coachId, [FromQuery] PageRequest request)
{
try
{
_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<UserDto>(request.Index, request.Count, totalCount, athletes.Select(a => a.ToDto()));
return Ok(pageResponse);
}
catch (Exception e)
{
_logger.LogError(e, "Error while getting the number of users");
return Problem();
}
}
/// <summary>
/// Obtient la liste des activités d'un utilisateur spécifique.
/// </summary>
/// <param name="userId">L'identifiant de l'utilisateur.</param>
/// <param name="pageRequest">Les critères de pagination et de tri.</param>
/// <returns>La liste paginée des activités de l'utilisateur.</returns>
/// <response code="200">Retourne la liste paginée des activités.</response>
/// <response code="404">Aucune activité trouvée.</response>
/// <response code="500">Erreur interne du serveur.</response>
[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<ActionResult<PageResponse<ActivityDto>>> GetActivitiesByUser(int userId, [FromQuery] PageRequest pageRequest)
{
try
{
var totalCount = await _activityService.GetNbActivitiesByUser(userId);
if (pageRequest.Count * pageRequest.Index >= totalCount)
{
_logger.LogError("To many object is asked the max is {totalCount} but the request is superior of ", totalCount);
return BadRequest("To many object is asked the max is : " + totalCount);
}
_logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetActivitiesByUser), pageRequest);
var activities = await _activityService.GetActivitiesByUser(userId, pageRequest.Index, pageRequest.Count, ActivityOrderCriteria.None, pageRequest.Descending ?? false);
if(activities == null)
{
return NotFound("No activities found");
}
var pageResponse = new PageResponse<ActivityDto>(pageRequest.Index, pageRequest.Count, totalCount, activities.Select(a => a.ToDto()));
return Ok(pageResponse);
}
catch (Exception e)
{
_logger.LogError(e, "Error while getting all activities");
return Problem();
}
}
/* [TODO] [Dave]
[HttpGet("{userId}/trainings")]
[ProducesResponseType(typeof(PageResponse<TrainingDto>), 200)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task<ActionResult<PageResponse<TrainingDto>> GetTrainings(int userId, [FromQuery] PageRequest request)
*/
/// <summary>
/// Déconnecte l'utilisateur actuel.
/// </summary>
/// <param name="signInManager">Le gestionnaire de connexion.</param>
/// <param name="empty">Paramètre vide utilisé pour s'assurer que la requête provient bien d'un client.</param>
/// <returns>Action result.</returns>
/// <response code="200">Déconnexion réussie.</response>
/// <response code="401">Déconnexion non autorisée.</response>
/// <response code="500">Erreur interne du serveur.</response>
[HttpPost("logout")]
[ProducesResponseType(200)]
[ProducesResponseType(401)]
[ProducesResponseType(500)]
public async Task<IActionResult> Logout(SignInManager<IdentityUser> signInManager, [FromBody] object? empty)
{
if (empty == null) return Unauthorized();
await signInManager.SignOutAsync();
return Ok();
}
} }

@ -12,25 +12,34 @@ COPY ["StubbedContextLib/StubbedContextLib.csproj", "StubbedContextLib/"]
COPY ["Shared/Shared.csproj", "Shared/"] COPY ["Shared/Shared.csproj", "Shared/"]
COPY ["Entities/Entities.csproj", "Entities/"] COPY ["Entities/Entities.csproj", "Entities/"]
COPY ["Dto/Dto.csproj", "Dto/"] COPY ["Dto/Dto.csproj", "Dto/"]
COPY ["ApiMappeur/ApiMappeur.csproj", "ApiMappeur/"] COPY ["APIMappers/APIMappers.csproj", "APIMappers/"]
COPY ["EFMappers/EFMappers.csproj", "EFMappers/"]
COPY ["DbContextLib/DbContextLib.csproj", "DbContextLib/"] COPY ["DbContextLib/DbContextLib.csproj", "DbContextLib/"]
COPY ["Model/Model.csproj", "Model/"] COPY ["Model/Model.csproj", "Model/"]
COPY ["Model2Entities/Model2Entities.csproj", "Model2Entities/"] COPY ["Model2Entities/Model2Entities.csproj", "Model2Entities/"]
COPY ["StubAPI/StubAPI.csproj", "StubAPI/"] COPY ["StubAPI/StubAPI.csproj", "StubAPI/"]
COPY ["StubbedContextLib/StubbedContextLib.csproj", "StubbedContextLib/"] COPY ["StubbedContextLib/StubbedContextLib.csproj", "StubbedContextLib/"]
RUN dotnet restore "HeartTrackAPI/HeartTrackAPI.csproj" RUN dotnet restore "HeartTrackAPI/HeartTrackAPI.csproj"
COPY . . COPY . .
RUN dotnet tool install --global dotnet-ef --version 8.0
ENV PATH="${PATH}:/root/.dotnet/tools"
# Add the migrations
RUN dotnet-ef migrations add --project StubbedContextLib/StubbedContextLib.csproj --startup-project HeartTrackAPI/HeartTrackAPI.csproj --context StubbedContextLib.TrainingStubbedContext --configuration Debug Initial
# Update the database
RUN dotnet-ef database update --project StubbedContextLib/StubbedContextLib.csproj --startup-project HeartTrackAPI/HeartTrackAPI.csproj --context StubbedContextLib.TrainingStubbedContext --configuration Debug
RUN chmod 777 HeartTrackAPI/uca.HeartTrack.db
WORKDIR "/src/HeartTrackAPI" WORKDIR "/src/HeartTrackAPI"
RUN ls
RUN dotnet build "HeartTrackAPI.csproj" -c $BUILD_CONFIGURATION -o /app/build RUN dotnet build "HeartTrackAPI.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish FROM build AS publish
ARG BUILD_CONFIGURATION=Release ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "HeartTrackAPI.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false RUN dotnet publish "HeartTrackAPI.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM base AS final FROM base AS final
WORKDIR /app WORKDIR /app
COPY --from=publish /app/publish . COPY --from=publish /app/publish .
RUN ls COPY --from=publish /src/HeartTrackAPI/uca.HeartTrack.db .
RUN ls -l uca.HeartTrack.db
ENTRYPOINT ["dotnet", "HeartTrackAPI.dll"] ENTRYPOINT ["dotnet", "HeartTrackAPI.dll"]

@ -0,0 +1,44 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace HeartTrackAPI;
public class FileUploadSummary
{
public int TotalFilesUploaded { get; set; }
public string TotalSizeUploaded { get; set; }
public IList<string> FilePaths { get; set; } = new List<string>();
public IList<string> NotUploadedFiles { get; set; } = new List<string>();
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class MultipartFormDataAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var request = context.HttpContext.Request;
if (request.HasFormContentType
&& request.ContentType.StartsWith("multipart/form-data", StringComparison.OrdinalIgnoreCase))
{
return;
}
context.Result = new StatusCodeResult(StatusCodes.Status415UnsupportedMediaType);
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
{
public void OnResourceExecuting(ResourceExecutingContext context)
{
var factories = context.ValueProviderFactories;
factories.RemoveType<FormValueProviderFactory>();
factories.RemoveType<FormFileValueProviderFactory>();
factories.RemoveType<JQueryFormValueProviderFactory>();
}
public void OnResourceExecuted(ResourceExecutedContext context)
{
}
}

@ -5,24 +5,31 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization> <InvariantGlobalization>true</InvariantGlobalization>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="5.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.1.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.2" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\APIMappers\APIMappers.csproj" />
<ProjectReference Include="..\DbContextLib\DbContextLib.csproj" />
<ProjectReference Include="..\Dto\Dto.csproj" /> <ProjectReference Include="..\Dto\Dto.csproj" />
<ProjectReference Include="..\Model2Entities\Model2Entities.csproj" />
<ProjectReference Include="..\Model\Model.csproj" /> <ProjectReference Include="..\Model\Model.csproj" />
<ProjectReference Include="..\Shared\Shared.csproj" /> <ProjectReference Include="..\Shared\Shared.csproj" />
<ProjectReference Include="..\StubAPI\StubAPI.csproj" /> <ProjectReference Include="..\StubAPI\StubAPI.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json" Version="13.0.1">
<HintPath>..\..\..\..\..\.nuget\packages\newtonsoft.json\13.0.1\lib\netstandard2.0\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
</Project> </Project>

@ -1,6 +0,0 @@
@HeartTrackAPI_HostAddress = http://localhost:5030
GET {{HeartTrackAPI_HostAddress}}/weatherforecast/
Accept: application/json
###

@ -1,25 +1,22 @@
using Model; using DbContextLib;
using Model.Manager; using HeartTrackAPI;
using Model.Repository;
using StubAPI;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
// Add services to the container. builder.Logging.AddConsole();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.WebHost.ConfigureKestrel(serverOptions =>
builder.Services.AddEndpointsApiExplorer(); {
builder.Services.AddSwaggerGen(); serverOptions.Limits.MaxRequestBodySize = long.MaxValue;
builder.Services.AddControllers(); });
builder.Services.AddSingleton<IDataManager, StubData>();
var app = builder.Build(); var init = new AppBootstrap(builder.Configuration);
// Configure the HTTP request pipeline. init.ConfigureServices(builder.Services);
app.UseSwagger(); var app = builder.Build();
app.UseSwaggerUI();
init.Configure(app, app.Environment);
app.UseHttpsRedirection(); app.Services.GetService<HeartTrackContext>()!.Database.EnsureCreated();
app.MapControllers();
app.Run(); app.Run();

@ -1,10 +1,16 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace HeartTrackAPI.Request; namespace HeartTrackAPI.Request;
public class PageRequest public class PageRequest
{ {
public string? OrderingPropertyName { get; set; } = null;
public string? OrderingPropertyName { get; set; } = null;// need to be map on the dto OrderCriteria
public bool? Descending { get; set; } = false; public bool? Descending { get; set; } = false;
// [Range(0, int.MaxValue, ErrorMessage = "Count must be greater than 0")]
public int Index { get; set; } = 0; public int Index { get; set; } = 0;
public int Count { get; set; } = 5;
// [Range(0, int.MaxValue, ErrorMessage = "Count must be greater than 0")]
public int Count { get; set; } = 1;
} }

@ -0,0 +1,53 @@
using System.Text.Json;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace HeartTrackAPI.Utils;
public class SwaggerDefaultValues : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var apiDescription = context.ApiDescription;
operation.Deprecated |= apiDescription.IsDeprecated();
foreach (var responseType in context.ApiDescription.SupportedResponseTypes)
{
var responseKey = responseType.IsDefaultResponse ? "default" : responseType.StatusCode.ToString();
var response = operation.Responses[responseKey];
foreach (var contentType in response.Content.Keys)
{
if (responseType.ApiResponseFormats.All(x => x.MediaType != contentType))
{
response.Content.Remove(contentType);
}
}
}
if (operation.Parameters == null)
{
return;
}
foreach (var parameter in operation.Parameters)
{
var description = apiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name);
parameter.Description ??= description.ModelMetadata?.Description;
if (parameter.Schema.Default == null &&
description.DefaultValue != null &&
description.DefaultValue is not DBNull &&
description.ModelMetadata is ModelMetadata modelMetadata)
{
var json = JsonSerializer.Serialize(description.DefaultValue, modelMetadata.ModelType);
parameter.Schema.Default = OpenApiAnyFactory.CreateFromJson(json);
}
parameter.Required |= description.IsRequired;
}
}
}

@ -0,0 +1,68 @@
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace HeartTrackAPI.Utils;
public class SwaggerOptions: IConfigureNamedOptions<SwaggerGenOptions>
{
private readonly IApiVersionDescriptionProvider _provider;
public SwaggerOptions(
IApiVersionDescriptionProvider provider)
{
_provider = provider;
}
/// <summary>
/// Configure each API discovered for Swagger Documentation
/// </summary>
/// <param name="options"></param>
public void Configure(SwaggerGenOptions options)
{
// add swagger document for every API version discovered
foreach (var description in _provider.ApiVersionDescriptions)
{
options.SwaggerDoc(
description.GroupName,
CreateVersionInfo(description));
}
}
/// <summary>
/// Configure Swagger Options. Inherited from the Interface
/// </summary>
/// <param name="name"></param>
/// <param name="options"></param>
public void Configure(string? name, SwaggerGenOptions options)
{
Configure(options);
}
/// <summary>
/// Create information about the version of the API
/// </summary>
/// <param name="description"></param>
/// <returns>Information about the API</returns>
private OpenApiInfo CreateVersionInfo(
ApiVersionDescription desc)
{
var info = new OpenApiInfo()
{
Title = "Web API For HeartTrack .NET 8",
Version = desc.ApiVersion.ToString(),
Description = "The HeartTrack project API, aims to provide an Open Source solution for heart rate data analysis.",
Contact = new OpenApiContact { Name = "HeartTrackDev", Email = "toto@toto.fr" },
License = new OpenApiLicense { Name = "MIT", Url = new Uri("https://opensource.org/licenses/MIT") }
};
if (desc.IsDeprecated)
{
info.Description += " This API version has been deprecated. Please use one of the new APIs available from the explorer.";
}
return info;
}
}

@ -4,5 +4,8 @@
"Default": "Information", "Default": "Information",
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Warning"
} }
},
"ConnectionStrings": {
"HeartTrackAuthConnection": "Data Source=uca.HeartTrack.db"
} }
} }

@ -5,5 +5,8 @@
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Warning"
} }
}, },
"AllowedHosts": "*" "AllowedHosts": "*",
"ConnectionStrings": {
"HeartTrackAuthConnection": "Data Source=uca.HeartTrack.db"
}
} }

@ -4,7 +4,7 @@ namespace Model;
public class Activity public class Activity
{ {
public int Id { get; set; } public int Id { get; set; }
public string Type { get; set; } public string? Type { get; set; }
public DateTime Date { get; set; } public DateTime Date { get; set; }
public DateTime StartTime { get; set; } public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; } public DateTime EndTime { get; set; }
@ -32,7 +32,8 @@ public class Activity
public float AverageTemperature { get; set; } public float AverageTemperature { get; set; }
public bool HasAutoPause { get; set; } public bool HasAutoPause { get; set; }
public Activity(int idActivity ,string type, DateTime date, DateTime startTime, DateTime endTime, public HashSet<User> Users { get; private set; } = new HashSet<User>();
public Activity(int idActivity ,string? type, DateTime date, DateTime startTime, DateTime endTime,
int effort, float variability, float variance, float standardDeviation, int effort, float variability, float variance, float standardDeviation,
float average, int maximum, int minimum, float averageTemperature, bool hasAutoPause) float average, int maximum, int minimum, float averageTemperature, bool hasAutoPause)
{ {

@ -0,0 +1,9 @@
namespace Model.Manager;
public class ActivityManager : IActivityManager
{
public void AddActivityFromFitFile(byte filePath)
{
throw new NotImplementedException();
}
}

@ -0,0 +1,6 @@
namespace Model.Manager;
public interface IActivityManager
{
public void AddActivityFromFitFile(byte filePath);
}

@ -0,0 +1,6 @@
namespace Model.Manager;
public class UserManager
{
}

@ -7,7 +7,12 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Shared\Shared.csproj" /> <ProjectReference Include="..\Entities\Entities.csproj" />
<ProjectReference Include="..\Shared\Shared.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.2" />
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -4,10 +4,12 @@ namespace Model.Repository;
public interface IActivityRepository public interface IActivityRepository
{ {
public Task<IEnumerable<Activity>> GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending = false); public Task<IEnumerable<Activity>?> GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending = false);
public Task<Activity?> GetActivityByIdAsync(int id); public Task<Activity?> GetActivityByIdAsync(int id);
public Task<Activity?> AddActivity(Activity activity); public Task<Activity?> AddActivity(Activity activity);
public Task<Activity?> UpdateActivity(int id, Activity activity); public Task<Activity?> UpdateActivity(int id, Activity activity);
public Task<bool> DeleteActivity(int id); public Task<bool> DeleteActivity(int id);
public Task<int> GetNbItems(); public Task<int> GetNbItems();
public Task<IEnumerable<Activity>?> GetActivitiesByUser(int userId, int index, int count, ActivityOrderCriteria orderCriteria, bool descending= false);
public Task<int> GetNbActivitiesByUser(int userId);
} }

@ -4,5 +4,14 @@ namespace Model.Repository;
public interface IUserRepository : IGenericRepository<User> public interface IUserRepository : IGenericRepository<User>
{ {
public Task<IEnumerable<User>> GetUsers(int index, int count, AthleteOrderCriteria? criteria , bool descending = false); public Task<IEnumerable<User>?> GetUsers(int index, int count, AthleteOrderCriteria? criteria , bool descending = false);
public Task<bool> AddFriend(User user, User friend);
public Task<bool> RemoveFriend(User user, User friend);
// should be removed cause i just have to call the GetItem then get the friends
public Task<IEnumerable<User>?> GetFriends(User user, int index, int count, AthleteOrderCriteria? criteria, bool descending = false);
public Task<int> GetNbFriends(User user);
} }

@ -8,7 +8,7 @@ public class User
public string LastName { get; set; } public string LastName { get; set; }
public string FirstName { get; set; } public string FirstName { get; set; }
public string Email { get; set; } public string Email { get; set; }
public string MotDePasse { get; set; } public string? MotDePasse { get; set; }
public string Sexe { get; set; } public string Sexe { get; set; }
public float Lenght { get; set; } public float Lenght { get; set; }
public float Weight { get; set; } public float Weight { get; set; }
@ -17,6 +17,8 @@ public class User
protected List<Notification> Notifications { get; set; } = new List<Notification>(); protected List<Notification> Notifications { get; set; } = new List<Notification>();
public List<User> Users { get; set; } = new List<User>();
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, string sexe, float taille, float poids, DateTime dateNaissance, Role role)
{ {
Username = username; Username = username;

@ -38,7 +38,7 @@ public partial class DbDataManager : IDataManager
{ {
_logger.LogInformation($"GetActivityByIdAsync with id {id}", id); _logger.LogInformation($"GetActivityByIdAsync with id {id}", id);
// ! By None don't pass the filter // ! By None don't pass the filter
var activity = _dataManager.DbContext.ActivitiesSet.GetItemsWithFilterAndOrdering(b => b.IdActivity == id, 0, 1, ActivityOrderCriteria.ByType, false).First().ToModel(); var activity = _dataManager.DbContext.ActivitiesSet.GetItemsWithFilterAndOrdering(b => b.IdActivity == id, 0, 1, ActivityOrderCriteria.None, false).First().ToModel();
if (activity != null) if (activity != null)
_logger.LogInformation($"Retrieved activity with ID {id}"); _logger.LogInformation($"Retrieved activity with ID {id}");
@ -121,5 +121,15 @@ public partial class DbDataManager : IDataManager
throw; throw;
} }
} }
public Task<IEnumerable<Activity>> GetActivitiesByUser(int userId, int index, int count, ActivityOrderCriteria criteria, bool descending = false)
{
throw new NotImplementedException();
}
public Task<int> GetNbActivitiesByUser(int userId)
{
throw new NotImplementedException();
}
} }
} }

@ -10,22 +10,30 @@ public partial class DbDataManager: IDataManager
{ {
public IActivityRepository ActivityRepo { get; } public IActivityRepository ActivityRepo { get; }
public IUserRepository UserRepo { get; } public IUserRepository UserRepo { get; }
protected HeartTrackContext DbContext { get; } protected HeartTrackContext DbContext { get; }
// mettre si pb lors d'une requete si rollback ou pas // mettre si pb lors d'une requete si rollback ou pas
public DbDataManager(HeartTrackContext dbContext) public DbDataManager(HeartTrackContext dbContext)
{ {
DbContext = dbContext; DbContext = dbContext;
Console.WriteLine("Contexttttttttt");
Console.WriteLine($"Database created Context: {DbContext.Database.EnsureCreated()}");
ActivityRepo = new ActivityRepository(this); ActivityRepo = new ActivityRepository(this);
UserRepo = new UserRepository(this); UserRepo = new UserRepository(this);
ActivityMapper.Reset(); ActivityMapper.Reset();
// Faire pour les autres reset() des autres mappers // Faire pour les autres reset() des autres mappers
} }
public DbDataManager(string dbPlatformPath)
: this(new HeartTrackContext(dbPlatformPath))
{
Console.WriteLine($"Database created String: {DbContext.Database.EnsureCreated()}"); }
public DbDataManager() public DbDataManager()
{ {
DbContext = new HeartTrackContext(); DbContext = new HeartTrackContext();
Console.WriteLine($"Database created None: {DbContext.Database.EnsureCreated()}");
ActivityRepo = new ActivityRepository(this); ActivityRepo = new ActivityRepository(this);
UserRepo= new UserRepository(this); UserRepo= new UserRepository(this);
} }

@ -7,28 +7,25 @@ namespace Model2Entities;
public static class Extensions public static class Extensions
{ {
internal static Task<T?> AddItem<T>(this HeartTrackContext context, T? item) where T :class internal static async Task<T?> AddItem<T>(this HeartTrackContext context, T? item) where T :class
{ {
if(item == null || context.Set<T>().Contains(item)) if(item == null || context.Set<T>().Contains(item))
{ {
return Task.FromResult<T?>(default(T)); return await Task.FromResult<T?>(null);
} }
context.Set<T>().Add(item); var entry = context.Set<T>().Add(item);
context.SaveChangesAsync(); await context.SaveChangesAsync();
return Task.FromResult<T?>(item); return await Task.FromResult<T?>(entry.Entity);
} }
internal static Task<bool> DeleteItem<T>(this HeartTrackContext context, int? id) where T:class internal static async Task<bool> DeleteItem<T>(this HeartTrackContext context, int? id) where T:class
{ {
var item = context.Set<T>().Find(id); var item = await context.Set<T>().FindAsync(id);
if(item == null) if(item == null) return await Task.FromResult(false);
{
return Task.FromResult(false);
}
context.Set<T>().Remove(item); context.Set<T>().Remove(item);
context.SaveChangesAsync(); await context.SaveChangesAsync();
return Task.FromResult(true); return await Task.FromResult(true);
} }
internal static async Task<T?> UpdateItem<T>(this IList<T> collection, T? oldItem, T? newItem) where T : class internal static async Task<T?> UpdateItem<T>(this IList<T> collection, T? oldItem, T? newItem) where T : class
@ -50,10 +47,11 @@ public static class Extensions
{ {
var filteredList = list.Where(filter); var filteredList = list.Where(filter);
if(orderCriterium != null) if(orderCriterium != null && orderCriterium.ToString() != "None")
{ {
filteredList = filteredList.OrderByCriteria(orderCriterium, descending); filteredList = filteredList.OrderByCriteria(orderCriterium, descending);
} }
return filteredList return filteredList
.Skip(index * count) .Skip(index * count)
.Take(count); .Take(count);

@ -10,6 +10,14 @@
<ProjectReference Include="..\DbContextLib\DbContextLib.csproj" /> <ProjectReference Include="..\DbContextLib\DbContextLib.csproj" />
<ProjectReference Include="..\Model\Model.csproj" /> <ProjectReference Include="..\Model\Model.csproj" />
<ProjectReference Include="..\EFMappers\EFMappers.csproj" /> <ProjectReference Include="..\EFMappers\EFMappers.csproj" />
<ProjectReference Include="..\StubbedContextLib\StubbedContextLib.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -49,5 +49,25 @@ public partial class DbDataManager
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public async Task<bool> AddFriend(User user, User friend)
{
throw new NotImplementedException();
}
public async Task<bool> RemoveFriend(User user, User friend)
{
throw new NotImplementedException();
}
public Task<IEnumerable<User>?>? GetFriends(User user, int index, int count, AthleteOrderCriteria? criteria, bool descending = false)
{
throw new NotImplementedException();
}
public Task<int> GetNbFriends(User user)
{
throw new NotImplementedException();
}
} }
} }

@ -2,7 +2,7 @@ namespace Shared;
public static class Extensions public static class Extensions
{ {
public static U? ToU<T, U>(this T t, GenericMapper<T, U> mapper, Func<T, U> func) where U :class where T :class public static U ToU<T, U>(this T t, GenericMapper<T, U> mapper, Func<T, U> func) where U :class where T :class
{ {
var u = mapper.GetU(t); var u = mapper.GetU(t);
if (u != null) { if (u != null) {
@ -14,7 +14,7 @@ public static class Extensions
return u; return u;
} }
// , Action<T, U> action // , Action<T, U> action
public static T? ToT<T,U>(this U u, GenericMapper<T, U> mapper, Func<U, T> func) where U :class where T :class public static T ToT<T,U>(this U u, GenericMapper<T, U> mapper, Func<U, T> func) where U :class where T :class
{ {
var t = mapper.GetT(u); var t = mapper.GetT(u);
if (t != null) { if (t != null) {

@ -6,33 +6,73 @@ namespace StubAPI;
public class ActivityService: IActivityRepository public class ActivityService: IActivityRepository
{ {
public async Task<IEnumerable<Activity>> GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending = false) private List<Activity> _activities = new List<Activity>(
{ new Activity[]
throw new NotImplementedException(); {
} 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()
}}
},
}
);
public async Task<Activity?> GetActivityByIdAsync(int id) public async Task<IEnumerable<Activity>?> 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 Task<Activity?> GetActivityByIdAsync(int id)
{ {
throw new NotImplementedException(); return Task.FromResult(_activities.FirstOrDefault(s => s.Id == id));
} }
public async Task<Activity?> AddActivity(Activity activity) public Task<Activity?> AddActivity(Activity activity)
=> _activities.AddItem(activity);
public async Task<Activity?> UpdateActivity(int id, Activity activity)
{ {
throw new NotImplementedException(); var oldActivity = _activities.FirstOrDefault(s => s.Id == id);
if (oldActivity == null) return null;
return await _activities.UpdateItem(oldActivity, activity);
} }
public async Task<Activity?> UpdateActivity(int id, Activity activity) public Task<bool> DeleteActivity(int id)
{ {
throw new NotImplementedException(); var activity = _activities.FirstOrDefault(s => s.Id == id);
if (activity == null) return Task.FromResult(false);
return _activities.DeleteItem(activity);
} }
public async Task<bool> DeleteActivity(int id) public Task<int> GetNbItems()
=> Task.FromResult(_activities.Count);
public async Task<IEnumerable<Activity>?> GetActivitiesByUser(int userId, int index, int count, ActivityOrderCriteria criteria, bool descending = false)
{ {
throw new NotImplementedException(); var activities = _activities.GetItemsWithFilterAndOrdering(c => c.Users.Any(u => u.Id == userId), index, count,
criteria != ActivityOrderCriteria.None ? criteria : null, descending);
return await Task.FromResult(activities);
} }
public async Task<int> GetNbItems() public Task<int> GetNbActivitiesByUser(int userId)
{ {
throw new NotImplementedException(); return Task.FromResult(_activities.Count(a => a.Users.Any(u => u.Id == userId)));
} }
} }

@ -34,14 +34,53 @@ public class UserService : IUserRepository
public async Task<IEnumerable<User>> GetUsers(int index, int count, AthleteOrderCriteria? orderingProperty = null, bool descending = false) public async Task<IEnumerable<User>> GetUsers(int index, int count, AthleteOrderCriteria? orderingProperty = null, bool descending = false)
=> athletes.GetItemsWithFilterAndOrdering(c=>true,index, count,orderingProperty != AthleteOrderCriteria.None ? orderingProperty: null , descending); => athletes.GetItemsWithFilterAndOrdering(c=>true,index, count,orderingProperty != AthleteOrderCriteria.None ? orderingProperty: null , descending);
public async Task<IEnumerable<User>> GetItems(int index, int count, string? orderingProperty = null, public async Task<bool> AddFriend(User user, User friend)
bool descending = false)
{ {
if (user == null || friend == null)
{
return false;
}
if (user.Users.Contains(friend))
{
return false;
}
return await this.GetUsers(index, count, this.ToEnum(orderingProperty), descending); user.Users.Add(friend);
return true;
} }
public async Task<bool> RemoveFriend(User user, User friend)
{
if (user == null || friend == null)
{
return false;
}
if (!user.Users.Contains(friend))
{
return false;
}
user.Users.Remove(friend);
return true;
}
public async Task<IEnumerable<User>?>? 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<int> GetNbFriends(User user)
{
return Task.FromResult(athletes.FirstOrDefault(s => s.Id == user.Id)?.Users.Count ?? 0);
}
public async Task<IEnumerable<User>> GetItems(int index, int count, string? orderingProperty = null,
bool descending = false)
=>await GetUsers(index, count, this.ToEnum(orderingProperty), descending);
public async Task<User?> GetItemById(int id) public async Task<User?> GetItemById(int id)
=>await Task.FromResult(athletes.FirstOrDefault(s => s.Id == id)); =>await Task.FromResult(athletes.FirstOrDefault(s => s.Id == id));

@ -39,13 +39,15 @@ public static class Extensions
public static IEnumerable<T> GetItemsWithFilterAndOrdering<T>(this IEnumerable<T> list, Func<T, bool> filter, int index, int count, Enum? orderCriterium, bool descending = false ) where T : class public static IEnumerable<T> GetItemsWithFilterAndOrdering<T>(this IEnumerable<T> list, Func<T, bool> filter, int index, int count, Enum? orderCriterium, bool descending = false ) where T : class
{ {
var filteredList = list.Where(filter); IEnumerable<T> query = list;
query = query.Where(filter);
if(orderCriterium != null) if(orderCriterium != null)
{ {
filteredList = filteredList.OrderByCriteria(orderCriterium, descending); query = query.OrderByCriteria(orderCriterium, descending);
} }
return filteredList return query
.Skip(index * count) .Skip(index * count)
.Take(count); .Take(count);
} }

@ -13,6 +13,10 @@
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Migrations\" />
</ItemGroup>
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>

@ -1,10 +0,0 @@
namespace TestsXUnit;
public class UnitTest1
{
[Fact]
public void Test1()
{
}
}

@ -0,0 +1,225 @@
using ApiMappeur;
using Dto;
using HeartTrackAPI.Controllers;
using HeartTrackAPI.Request;
using HeartTrackAPI.Responce;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging.Abstractions;
using Model;
using Model.Manager;
using Model.Repository;
using Moq;
using Shared;
using StubAPI;
namespace UnitTestApi.Controllers;
[TestClass]
[TestSubject(typeof(UsersController))]
public class UsersControllerTest
{
private Mock<IDataManager> _dataManagerMock;
private IDataManager _dataManager;
private UsersController _usersController;
private readonly List<User> _users =
[
new User
{
Id = 1, Username = "DoeDoe",
ProfilePicture =
"https://images.unsplash.com/photo-1682687982134-2ac563b2228b?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
FirstName = "John", LastName = "Doe",
Sexe = "M", Lenght = 180, Weight = 70, DateOfBirth = new DateTime(1990, 1, 1),
Email = "john.doe@example.com", Role = new Athlete()
},
new User
{
Id = 2, Username = "SmithSmith",
ProfilePicture =
"https://images.unsplash.com/photo-1709507779917-242b560288be?q=80&w=2080&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
FirstName = "Jane", LastName = "Smith",
Sexe = "F", Lenght = 170, Weight = 60, DateOfBirth = new DateTime(1992, 2, 2),
Email = "athlete2@example.com", Role = new Coach()
},
new User
{
Id = 3, Username = "Athlete3",
ProfilePicture =
"https://plus.unsplash.com/premium_photo-1705091981693-6006f8a20479?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
FirstName = "First3", LastName = "Last3",
Sexe = "M", Lenght = 190, Weight = 80, DateOfBirth = new DateTime(1994, 3, 3), Email = "ath@ex.fr",
Role = new Athlete()
}
];
[TestInitialize]
public void SetUp()
{
_dataManagerMock = new Mock<IDataManager>();
_dataManagerMock.Setup(dm => dm.UserRepo.GetNbItems()).ReturnsAsync(_users.Count);
_dataManagerMock.Setup(dm =>
dm.UserRepo.GetUsers(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<AthleteOrderCriteria>(),
It.IsAny<bool>())).ReturnsAsync(
(int index, int count, AthleteOrderCriteria criteria, bool descending) =>
_users.GetItemsWithFilterAndOrdering(c => true, index, count,
criteria != AthleteOrderCriteria.None ? criteria : null, descending)
);
_usersController = new UsersController(new NullLogger<UsersController>(), _dataManagerMock.Object);
}
/*
[TestInitialize]
public void SetUp()
{
_dataManager = new StubData();
_usersController = new UsersController(new NullLogger<UsersController>(), _dataManager);
}*/
[TestMethod]
public async Task Get_ReturnsPageResponse_WhenRequestIsValid()
{
// Arrange
var request = new PageRequest
{
Index = 0,
Count = 3,
OrderingPropertyName = "Id",
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<UserDto>));
var pageResponse = okResult.Value as PageResponse<UserDto>;
Assert.IsNotNull(pageResponse);
Assert.AreEqual(3, pageResponse.Items.Count());
Assert.AreEqual(3, pageResponse.Total);
Assert.AreEqual(0, pageResponse.Index);
Assert.AreEqual(3, pageResponse.Count);
Assert.AreEqual(3, pageResponse.Count);
}
[DataTestMethod]
[DataRow(0, 2, "Id", false, 2)]
[DataRow(1, 1, "Id", false, 1)]
[DataRow(0, 3, "Id", true, 3)]
public async Task Get_ReturnsCorrectPaginationAndOrdering(int index, int count, string orderingProperty,
bool descending, int expectedItemCount)
{
// Arrange
var request = new PageRequest
{
Index = index,
Count = count,
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<UserDto>));
var pageResponse = okResult.Value as PageResponse<UserDto>;
Assert.IsNotNull(pageResponse);
Assert.AreEqual(expectedItemCount, pageResponse.Items.Count());
}
[TestMethod]
public async Task Get_ReturnsInternalServerError_OnException()
{
_dataManagerMock.Setup(dm =>
dm.UserRepo.GetUsers(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<AthleteOrderCriteria>(),
It.IsAny<bool>()))
.ThrowsAsync(new Exception("Simulated database failure."));
var request = new PageRequest { Index = 0, Count = 3 };
var result = await _usersController.Get(request);
Assert.IsInstanceOfType(result.Result, typeof(ObjectResult));
var objectResult = result.Result as ObjectResult;
Assert.AreEqual(500, objectResult.StatusCode);
}
[TestMethod]
public async Task GetById_ReturnsUserDto_WhenRequestIsValid()
{
// Arrange
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_WhenRequestUserDoesNotExist()
{
// Arrange
var id = 0;
_dataManagerMock.Setup(dm => dm.UserRepo.GetItemById(id)).ReturnsAsync((User)null!);
// Act
var result = await _usersController.GetById(id) ;
// Assert
Assert.IsInstanceOfType(result.Result, typeof(NotFoundObjectResult));
}
[TestMethod]
public async Task GetById_Returns404_WhenIdIsInvalid()
{
// Arrange
var id = -2;
// Act
var result = await _usersController.GetById(id);
// Assert
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));
}
}

@ -10,7 +10,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0"/> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0"/>
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="MSTest.TestAdapter" Version="3.0.4"/> <PackageReference Include="MSTest.TestAdapter" Version="3.0.4"/>
<PackageReference Include="MSTest.TestFramework" Version="3.0.4"/> <PackageReference Include="MSTest.TestFramework" Version="3.0.4"/>
<PackageReference Include="coverlet.collector" Version="6.0.0"/> <PackageReference Include="coverlet.collector" Version="6.0.0"/>

@ -1,124 +0,0 @@
using Dto;
using HeartTrackAPI.Controllers;
using HeartTrackAPI.Request;
using HeartTrackAPI.Responce;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging.Abstractions;
using Model.Manager;
using Model.Repository;
using StubAPI;
namespace UnitTestApi;
[TestClass]
public class UserControllerTest
{
private readonly IDataManager StubDataManager;
private readonly UsersController _usersController;
public UserControllerTest()
{
StubDataManager = new StubData();
_usersController = new UsersController(new NullLogger<UsersController>(), StubDataManager);
}
[TestMethod]
public void Get_ReturnsPageResponse_WhenRequestIsValid()
{
// Arrange
var request = new PageRequest
{
Index = 0,
Count = 10,
OrderingPropertyName = "Id",
Descending = false
};
// Act
//var result = _usersController.Get(request).Result as OkObjectResult;
// Assert
// Assert.IsNotNull(result);
//Assert.IsInstanceOfType(result.Value, typeof(PageResponse<UserDto>));
}
/*
[TestMethod]
public void GetById_ReturnsUserDto_WhenRequestIsValid()
{
// Arrange
var id = 1;
// Act
var result = _usersController.GetById(id).Result as OkObjectResult;
// Assert
Assert.IsNotNull(result);
Assert.IsInstanceOfType(result.Value, typeof(UserDto));
}
[TestMethod]
public void GetById_Returns404_WhenIdIsInvalid()
{
// Arrange
var id = 0;
// Act
var result = _usersController.GetById(id).Result as NotFoundResult;
// Assert
Assert.IsNotNull(result);
}
[TestMethod]
public void GetById_Returns500_WheExceptionIsThrown()
{
// Arrange
var id = 0;
// Act
var result = _usersController.GetById(id).Result as StatusCodeResult;
// Assert
Assert.IsNotNull(result);
Assert.AreEqual(500, result.StatusCode);
}
[TestMethod]
public void Count_ReturnsInt_WhenRequestIsValid()
{
// Act
var result = _usersController.Count().Result as OkObjectResult;
// Assert
Assert.IsNotNull(result);
Assert.IsInstanceOfType(result.Value, typeof(int));
}
[TestMethod]
public void Count_Returns500_WheExceptionIsThrown()
{
// Act
var result = _usersController.Count().Result as StatusCodeResult;
// Assert
Assert.IsNotNull(result);
Assert.AreEqual(500, result.StatusCode);
}
[TestMethod]
public void Update_ReturnsUserDto_WhenRequestIsValid()
{
// Arrange
var id = 1;
var user = new UserDto
{
Id = 1,
FirstName = "John",
LastName = "Doe",
Email = "toto@eoeo.fr",
};
}*/
}

@ -0,0 +1,140 @@
namespace UnitTestsEntities;
using Xunit;
using System.Linq;
using Entities;
using Microsoft.EntityFrameworkCore;
public class ActivityEntityTests
{
[Fact]
public void Add_Activity_Success()
{
var activity = new ActivityEntity
{
Type = "Running",
Date = new DateOnly(2024, 3, 15),
StartTime = new TimeOnly(9, 0),
EndTime = new TimeOnly(10, 0),
EffortFelt = 7,
Variability = 0.5f,
Variance = 0.2f,
StandardDeviation = 0.3f,
Average = 0.4f,
Maximum = 200,
Minimum = 100,
AverageTemperature = 25.5f,
HasAutoPause = true,
DataSourceId = 1,
AthleteId = 1
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Activities.Add(activity);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedActivity = context.Activities.First(a => a.Type == "Running");
Assert.NotNull(savedActivity);
Assert.Equal("Running", savedActivity.Type );
}*/
}
[Fact]
public void Update_Activity_Success()
{
var activity = new ActivityEntity
{
Type = "Running",
Date = new DateOnly(2024, 3, 15),
StartTime = new TimeOnly(9, 0),
EndTime = new TimeOnly(10, 0),
EffortFelt = 7,
Variability = 0.5f,
Variance = 0.2f,
StandardDeviation = 0.3f,
Average = 0.4f,
Maximum = 200,
Minimum = 100,
AverageTemperature = 25.5f,
HasAutoPause = true,
DataSourceId = 1,
AthleteId = 1
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Activities.Add(activity);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedActivity = context.Activities.First(a => a.Type == "Running");
savedActivity.Type = "Walking";
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var updatedActivity = context.Activities.First(a => a.Type == "Walking");
Assert.NotNull(updatedActivity);
Assert.Equal("Walking", updatedActivity.Type );
Assert.Equal(7, updatedActivity.EffortFelt );
}*/
}
[Fact]
public void Delete_Activity_Success()
{
var activity = new ActivityEntity
{
Type = "Running",
Date = new DateOnly(2024, 3, 15),
StartTime = new TimeOnly(9, 0),
EndTime = new TimeOnly(10, 0),
EffortFelt = 7,
Variability = 0.5f,
Variance = 0.2f,
StandardDeviation = 0.3f,
Average = 0.4f,
Maximum = 200,
Minimum = 100,
AverageTemperature = 25.5f,
HasAutoPause = true,
DataSourceId = 1,
AthleteId = 1
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Activities.Add(activity);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedActivity = context.Activities.First(a => a.Type == "Running");
context.Activities.Remove(savedActivity);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var deletedActivity = context.Activities.FirstOrDefault(a => a.Type == "Running");
Assert.Null(deletedActivity);
}*/
}
}

@ -0,0 +1,122 @@
namespace UnitTestsEntities;
using Xunit;
using System.Linq;
using Entities;
using Microsoft.EntityFrameworkCore;
public class AthleteEntityTests
{
[Fact]
public void Add_Athlete_Success()
{
var athlete = new AthleteEntity
{
Username = "john_doe",
LastName = "Doe",
FirstName = "John",
Email = "john.doe@example.com",
Sexe = "M",
Length = 180.0,
Weight = 75.5f,
Password = "password",
DateOfBirth = new DateOnly(1990, 1, 1),
IsCoach = false
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Athletes.Add(athlete);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedAthlete = context.Athletes.First(a => a.Username == "john_doe");
Assert.NotNull(savedAthlete);
Assert.Equal("john_doe", savedAthlete.Username);
}*/
}
[Fact]
public void Update_Athlete_Success()
{
var athlete = new AthleteEntity
{
Username = "jane_smith",
LastName = "Smith",
FirstName = "Jane",
Email = "jane.smith@example.com",
Sexe = "F",
Length = 165.0,
Weight = 60.0f,
Password = "password123",
DateOfBirth = new DateOnly(1995, 5, 10),
IsCoach = false
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Athletes.Add(athlete);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedAthlete = context.Athletes.First(a => a.Username == "jane_smith");
savedAthlete.Username = "jane_doe";
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var updatedAthlete = context.Athletes.First(a => a.Username == "jane_doe");
Assert.NotNull(updatedAthlete);
Assert.Equal("jane_doe", updatedAthlete.Username);
Assert.Equal("Smith", updatedAthlete.LastName);
}*/
}
[Fact]
public void Delete_Athlete_Success()
{
var athlete = new AthleteEntity
{
Username = "test_user",
LastName = "Test",
FirstName = "User",
Email = "test.user@example.com",
Sexe = "M",
Length = 170.0,
Weight = 70.0f,
Password = "testpassword",
DateOfBirth = new DateOnly(1985, 10, 20),
IsCoach = false
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Athletes.Add(athlete);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedAthlete = context.Athletes.First(a => a.Username == "test_user");
context.Athletes.Remove(savedAthlete);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var deletedAthlete = context.Athletes.FirstOrDefault(a => a.Username == "test_user");
Assert.Null(deletedAthlete);
}*/
}
}

@ -0,0 +1,102 @@
namespace UnitTestsEntities;
using Xunit;
using System.Linq;
using Entities;
using Microsoft.EntityFrameworkCore;
public class DataSourceEntityTests
{
[Fact]
public void Add_DataSource_Success()
{
var dataSource = new DataSourceEntity
{
Type = "GPS",
Model = "Garmin Forerunner 945",
Precision = 0.1f
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.DataSources.Add(dataSource);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedDataSource = context.DataSources.First(d => d.Type == "GPS");
Assert.NotNull(savedDataSource);
Assert.Equal("Garmin Forerunner 945", savedDataSource.Model);
}*/
}
[Fact]
public void Update_DataSource_Success()
{
var dataSource = new DataSourceEntity
{
Type = "Heart Rate Monitor",
Model = "Polar H10",
Precision = 0.2f
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.DataSources.Add(dataSource);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedDataSource = context.DataSources.First(d => d.Type == "Heart Rate Monitor");
savedDataSource.Model = "Polar H9";
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var updatedDataSource = context.DataSources.First(d => d.Model == "Polar H9");
Assert.NotNull(updatedDataSource);
Assert.Equal("Heart Rate Monitor", updatedDataSource.Type);
Assert.Equal(0.2f, updatedDataSource.Precision);
}*/
}
[Fact]
public void Delete_DataSource_Success()
{
var dataSource = new DataSourceEntity
{
Type = "Smartwatch",
Model = "Apple Watch Series 6",
Precision = 0.05f
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.DataSources.Add(dataSource);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedDataSource = context.DataSources.First(d => d.Type == "Smartwatch");
context.DataSources.Remove(savedDataSource);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var deletedDataSource = context.DataSources.FirstOrDefault(d => d.Type == "Smartwatch");
Assert.Null(deletedDataSource);
}*/
}
}

@ -0,0 +1,206 @@
namespace UnitTestsEntities;
using Xunit;
using System.Linq;
using Entities;
using Microsoft.EntityFrameworkCore;
public class FriendshipEntityTests
{
[Fact]
public void Add_Friendship_Success()
{
var follower = new AthleteEntity
{
Username = "follower_user",
LastName = "Follower",
FirstName = "User",
Email = "follower.user@example.com",
Sexe = "M",
Length = 170.0,
Weight = 70.0f,
Password = "followerpassword",
DateOfBirth = new DateOnly(1990, 1, 1),
IsCoach = false
};
var following = new AthleteEntity
{
Username = "following_user",
LastName = "Following",
FirstName = "User",
Email = "following.user@example.com",
Sexe = "F",
Length = 165.0,
Weight = 60.0f,
Password = "followingpassword",
DateOfBirth = new DateOnly(1995, 5, 10),
IsCoach = false
};
var friendship = new FriendshipEntity
{
Follower = follower,
Following = following,
StartDate = DateTime.Now
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Athletes.Add(follower);
context.Athletes.Add(following);
context.Friendships.Add(friendship);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedFriendship = context.Friendships.FirstOrDefault();
Assert.NotNull(savedFriendship);
Assert.Equal(follower.IdAthlete, savedFriendship.FollowerId);
Assert.Equal(following.IdAthlete, savedFriendship.FollowingId);
}*/
}
[Fact]
public void Update_Friendship_Success()
{
var follower = new AthleteEntity
{
Username = "follower_user",
LastName = "Follower",
FirstName = "User",
Email = "follower.user@example.com",
Sexe = "M",
Length = 170.0,
Weight = 70.0f,
Password = "followerpassword",
DateOfBirth = new DateOnly(1990, 1, 1),
IsCoach = false
};
var following = new AthleteEntity
{
Username = "following_user",
LastName = "Following",
FirstName = "User",
Email = "following.user@example.com",
Sexe = "F",
Length = 165.0,
Weight = 60.0f,
Password = "followingpassword",
DateOfBirth = new DateOnly(1995, 5, 10),
IsCoach = false
};
var thirdAthlete = new AthleteEntity
{
Username = "third_user",
LastName = "Third",
FirstName = "User",
Email = "third.user@example.com",
Sexe = "M",
Length = 180.0,
Weight = 75.0f,
Password = "thirdpassword",
DateOfBirth = new DateOnly(1988, 3, 15),
IsCoach = false
};
var friendship = new FriendshipEntity
{
Follower = follower,
Following = following,
StartDate = DateTime.Now
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Athletes.Add(follower);
context.Athletes.Add(following);
context.Athletes.Add(thirdAthlete);
context.Friendships.Add(friendship);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedFriendship = context.Friendships.FirstOrDefault();
savedFriendship.Follower = thirdAthlete; // Update the follower
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var updatedFriendship = context.Friendships.FirstOrDefault();
Assert.NotNull(updatedFriendship);
Assert.Equal(thirdAthlete.IdAthlete, updatedFriendship.FollowerId);
}*/
}
[Fact]
public void Delete_Friendship_Success()
{
var follower = new AthleteEntity
{
Username = "follower_user",
LastName = "Follower",
FirstName = "User",
Email = "follower.user@example.com",
Sexe = "M",
Length = 170.0,
Weight = 70.0f,
Password = "followerpassword",
DateOfBirth = new DateOnly(1990, 1, 1),
IsCoach = false
};
var following = new AthleteEntity
{
Username = "following_user",
LastName = "Following",
FirstName = "User",
Email = "following.user@example.com",
Sexe = "F",
Length = 165.0,
Weight = 60.0f,
Password = "followingpassword",
DateOfBirth = new DateOnly(1995, 5, 10),
IsCoach = false
};
var friendship = new FriendshipEntity
{
Follower = follower,
Following = following,
StartDate = DateTime.Now
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Athletes.Add(follower);
context.Athletes.Add(following);
context.Friendships.Add(friendship);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedFriendship = context.Friendships.FirstOrDefault();
context.Friendships.Remove(savedFriendship);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var deletedFriendship = context.Friendships.FirstOrDefault();
Assert.Null(deletedFriendship);
}*/
}
}

@ -0,0 +1,172 @@
namespace UnitTestsEntities;
using Xunit;
using System.Linq;
using Entities;
using Microsoft.EntityFrameworkCore;
public class HeartRateEntityTests
{
[Fact]
public void Add_HeartRate_Success()
{
var activity = new ActivityEntity
{
Type = "Running",
Date = new DateOnly(2024, 3, 15),
StartTime = new TimeOnly(9, 0),
EndTime = new TimeOnly(10, 0),
EffortFelt = 7,
Variability = 0.5f,
Variance = 0.2f,
StandardDeviation = 0.3f,
Average = 0.4f,
Maximum = 200,
Minimum = 100,
AverageTemperature = 25.5f,
HasAutoPause = true,
DataSourceId = 1,
AthleteId = 1
};
var heartRateEntry = new HeartRateEntity
{
Altitude = 100.0,
Time = new TimeOnly(9, 30),
Temperature = 20.0f,
Bpm = 150,
Longitude = 45.12345f,
Latitude = 35.6789f,
Activity = activity
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Activities.Add(activity);
context.HeartRates.Add(heartRateEntry);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedHeartRate = context.HeartRates.First();
Assert.NotNull(savedHeartRate);
Assert.Equal(150, savedHeartRate.Bpm);
}*/
}
[Fact]
public void Update_HeartRate_Success()
{
var activity = new ActivityEntity
{
Type = "Running",
Date = new DateOnly(2024, 3, 15),
StartTime = new TimeOnly(9, 0),
EndTime = new TimeOnly(10, 0),
EffortFelt = 7,
Variability = 0.5f,
Variance = 0.2f,
StandardDeviation = 0.3f,
Average = 0.4f,
Maximum = 200,
Minimum = 100,
AverageTemperature = 25.5f,
HasAutoPause = true,
DataSourceId = 1,
AthleteId = 1
};
var heartRateEntry = new HeartRateEntity
{
Altitude = 100.0,
Time = new TimeOnly(9, 30),
Temperature = 20.0f,
Bpm = 150,
Longitude = 45.12345f,
Latitude = 35.6789f,
Activity = activity
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Activities.Add(activity);
context.HeartRates.Add(heartRateEntry);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedHeartRate = context.HeartRates.First();
savedHeartRate.Bpm = 160;
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var updatedHeartRate = context.HeartRates.First();
Assert.NotNull(updatedHeartRate);
Assert.Equal(160, updatedHeartRate.Bpm);
}*/
}
[Fact]
public void Delete_HeartRate_Success()
{
var activity = new ActivityEntity
{
Type = "Running",
Date = new DateOnly(2024, 3, 15),
StartTime = new TimeOnly(9, 0),
EndTime = new TimeOnly(10, 0),
EffortFelt = 7,
Variability = 0.5f,
Variance = 0.2f,
StandardDeviation = 0.3f,
Average = 0.4f,
Maximum = 200,
Minimum = 100,
AverageTemperature = 25.5f,
HasAutoPause = true,
DataSourceId = 1,
AthleteId = 1
};
var heartRateEntry = new HeartRateEntity
{
Altitude = 100.0,
Time = new TimeOnly(9, 30),
Temperature = 20.0f,
Bpm = 150,
Longitude = 45.12345f,
Latitude = 35.6789f,
Activity = activity
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Activities.Add(activity);
context.HeartRates.Add(heartRateEntry);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedHeartRate = context.HeartRates.First();
context.HeartRates.Remove(savedHeartRate);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var deletedHeartRate = context.HeartRates.FirstOrDefault();
Assert.Null(deletedHeartRate);
}*/
}
}

@ -0,0 +1,151 @@
namespace UnitTestsEntities;
using Xunit;
using System.Linq;
using Entities;
using Microsoft.EntityFrameworkCore;
public class NotificationEntityTests
{
[Fact]
public void Add_Notification_Success()
{
var sender = new AthleteEntity
{
Username = "sender_user",
LastName = "Sender",
FirstName = "User",
Email = "sender.user@example.com",
Sexe = "M",
Length = 170.0,
Weight = 70.0f,
Password = "senderpassword",
DateOfBirth = new DateOnly(1990, 1, 1),
IsCoach = false
};
var notification = new NotificationEntity
{
Message = "Test notification",
Date = DateTime.Now,
Statut = false,
Urgence = "High",
Sender = sender
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Athletes.Add(sender);
context.Notifications.Add(notification);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedNotification = context.Notifications.First();
Assert.NotNull(savedNotification);
Assert.Equal("Test notification", savedNotification.Message);
}*/
}
[Fact]
public void Update_Notification_Success()
{
var sender = new AthleteEntity
{
Username = "sender_user",
LastName = "Sender",
FirstName = "User",
Email = "sender.user@example.com",
Sexe = "M",
Length = 170.0,
Weight = 70.0f,
Password = "senderpassword",
DateOfBirth = new DateOnly(1990, 1, 1),
IsCoach = false
};
var notification = new NotificationEntity
{
Message = "Test notification",
Date = DateTime.Now,
Statut = false,
Urgence = "High",
Sender = sender
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Athletes.Add(sender);
context.Notifications.Add(notification);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedNotification = context.Notifications.First();
savedNotification.Message = "Updated message";
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var updatedNotification = context.Notifications.First();
Assert.NotNull(updatedNotification);
Assert.Equal("Updated message", updatedNotification.Message);
}*/
}
[Fact]
public void Delete_Notification_Success()
{
var sender = new AthleteEntity
{
Username = "sender_user",
LastName = "Sender",
FirstName = "User",
Email = "sender.user@example.com",
Sexe = "M",
Length = 170.0,
Weight = 70.0f,
Password = "senderpassword",
DateOfBirth = new DateOnly(1990, 1, 1),
IsCoach = false
};
var notification = new NotificationEntity
{
Message = "Test notification",
Date = DateTime.Now,
Statut = false,
Urgence = "High",
Sender = sender
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Athletes.Add(sender);
context.Notifications.Add(notification);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedNotification = context.Notifications.First();
context.Notifications.Remove(savedNotification);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var deletedNotification = context.Notifications.FirstOrDefault();
Assert.Null(deletedNotification);
}*/
}
}

@ -0,0 +1,155 @@
namespace UnitTestsEntities;
using Xunit;
using System.Linq;
using Entities;
using Microsoft.EntityFrameworkCore;
public class StatisticEntityTests
{
[Fact]
public void Add_Statistic_Success()
{
var athlete = new AthleteEntity
{
Username = "athlete_user",
LastName = "Athlete",
FirstName = "User",
Email = "athlete.user@example.com",
Sexe = "M",
Length = 170.0,
Weight = 70.0f,
Password = "athletepassword",
DateOfBirth = new DateOnly(1990, 1, 1),
IsCoach = false
};
var statistic = new StatisticEntity
{
Weight = 75.0f,
AverageHeartRate = 150.0,
MaximumHeartRate = 180.0,
AverageCaloriesBurned = 500.0,
Date = new DateOnly(2024, 3, 15),
Athlete = athlete
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Athletes.Add(athlete);
context.Statistics.Add(statistic);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedStatistic = context.Statistics.First();
Assert.NotNull(savedStatistic);
Assert.Equal(75.0f, savedStatistic.Weight);
}*/
}
[Fact]
public void Update_Statistic_Success()
{
var athlete = new AthleteEntity
{
Username = "athlete_user",
LastName = "Athlete",
FirstName = "User",
Email = "athlete.user@example.com",
Sexe = "M",
Length = 170.0,
Weight = 70.0f,
Password = "athletepassword",
DateOfBirth = new DateOnly(1990, 1, 1),
IsCoach = false
};
var statistic = new StatisticEntity
{
Weight = 75.0f,
AverageHeartRate = 150.0,
MaximumHeartRate = 180.0,
AverageCaloriesBurned = 500.0,
Date = new DateOnly(2024, 3, 15),
Athlete = athlete
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Athletes.Add(athlete);
context.Statistics.Add(statistic);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedStatistic = context.Statistics.First();
savedStatistic.Weight = 80.0f;
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var updatedStatistic = context.Statistics.First();
Assert.NotNull(updatedStatistic);
Assert.Equal(80.0f, updatedStatistic.Weight);
}*/
}
[Fact]
public void Delete_Statistic_Success()
{
var athlete = new AthleteEntity
{
Username = "athlete_user",
LastName = "Athlete",
FirstName = "User",
Email = "athlete.user@example.com",
Sexe = "M",
Length = 170.0,
Weight = 70.0f,
Password = "athletepassword",
DateOfBirth = new DateOnly(1990, 1, 1),
IsCoach = false
};
var statistic = new StatisticEntity
{
Weight = 75.0f,
AverageHeartRate = 150.0,
MaximumHeartRate = 180.0,
AverageCaloriesBurned = 500.0,
Date = new DateOnly(2024, 3, 15),
Athlete = athlete
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Athletes.Add(athlete);
context.Statistics.Add(statistic);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedStatistic = context.Statistics.First();
context.Statistics.Remove(savedStatistic);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var deletedStatistic = context.Statistics.FirstOrDefault();
Assert.Null(deletedStatistic);
}*/
}
}

@ -0,0 +1,202 @@
namespace UnitTestsEntities;
using Xunit;
using System.Linq;
using Entities;
using Microsoft.EntityFrameworkCore;
public class TrainingEntityTests
{
[Fact]
public void Add_Training_Success()
{
var coach = new AthleteEntity
{
Username = "coach_user",
LastName = "Coach",
FirstName = "User",
Email = "coach.user@example.com",
Sexe = "M",
Length = 180.0,
Weight = 75.0f,
Password = "coachpassword",
DateOfBirth = new DateOnly(1985, 5, 15),
IsCoach = true
};
var athlete = new AthleteEntity
{
Username = "athlete_user",
LastName = "Athlete",
FirstName = "User",
Email = "athlete.user@example.com",
Sexe = "F",
Length = 165.0,
Weight = 60.0f,
Password = "athletepassword",
DateOfBirth = new DateOnly(1990, 3, 20),
IsCoach = false
};
var training = new TrainingEntity
{
Date = new DateOnly(2024, 3, 15),
Description = "Training description",
Latitude = 40.12345f,
Longitude = -74.56789f,
FeedBack = "Training feedback",
Coach = coach,
Athletes = { athlete }
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Athletes.Add(coach);
context.Athletes.Add(athlete);
context.Trainings.Add(training);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedTraining = context.Trainings.First();
Assert.NotNull(savedTraining);
Assert.Equal("Training description", savedTraining.Description);
}*/
}
[Fact]
public void Update_Training_Success()
{
var coach = new AthleteEntity
{
Username = "coach_user",
LastName = "Coach",
FirstName = "User",
Email = "coach.user@example.com",
Sexe = "M",
Length = 180.0,
Weight = 75.0f,
Password = "coachpassword",
DateOfBirth = new DateOnly(1985, 5, 15),
IsCoach = true
};
var athlete = new AthleteEntity
{
Username = "athlete_user",
LastName = "Athlete",
FirstName = "User",
Email = "athlete.user@example.com",
Sexe = "F",
Length = 165.0,
Weight = 60.0f,
Password = "athletepassword",
DateOfBirth = new DateOnly(1990, 3, 20),
IsCoach = false
};
var training = new TrainingEntity
{
Date = new DateOnly(2024, 3, 15),
Description = "Training description",
Latitude = 40.12345f,
Longitude = -74.56789f,
FeedBack = "Training feedback",
Coach = coach,
Athletes = { athlete }
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Athletes.Add(coach);
context.Athletes.Add(athlete);
context.Trainings.Add(training);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedTraining = context.Trainings.First();
savedTraining.Description = "Updated training description";
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var updatedTraining = context.Trainings.First();
Assert.NotNull(updatedTraining);
Assert.Equal("Updated training description", updatedTraining.Description);
}*/
}
[Fact]
public void Delete_Training_Success()
{
var coach = new AthleteEntity
{
Username = "coach_user",
LastName = "Coach",
FirstName = "User",
Email = "coach.user@example.com",
Sexe = "M",
Length = 180.0,
Weight = 75.0f,
Password = "coachpassword",
DateOfBirth = new DateOnly(1985, 5, 15),
IsCoach = true
};
var athlete = new AthleteEntity
{
Username = "athlete_user",
LastName = "Athlete",
FirstName = "User",
Email = "athlete.user@example.com",
Sexe = "F",
Length = 165.0,
Weight = 60.0f,
Password = "athletepassword",
DateOfBirth = new DateOnly(1990, 3, 20),
IsCoach = false
};
var training = new TrainingEntity
{
Date = new DateOnly(2024, 3, 15),
Description = "Training description",
Latitude = 40.12345f,
Longitude = -74.56789f,
FeedBack = "Training feedback",
Coach = coach,
Athletes = { athlete }
};
/*
using (var context = new StubbedContext(options))
{
context.Database.EnsureCreated();
context.Athletes.Add(coach);
context.Athletes.Add(athlete);
context.Trainings.Add(training);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var savedTraining = context.Trainings.First();
context.Trainings.Remove(savedTraining);
context.SaveChanges();
}
using (var context = new StubbedContext(options))
{
var deletedTraining = context.Trainings.FirstOrDefault();
Assert.Null(deletedTraining);
}*/
}
}

@ -1,10 +0,0 @@
namespace UnitTestsEntities;
public class UnitTest1
{
[Fact]
public void Test1()
{
}
}

@ -10,6 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="xunit" Version="2.4.2" /> <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
@ -22,4 +23,8 @@
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Entities\Entities.csproj" />
</ItemGroup>
</Project> </Project>

@ -0,0 +1,11 @@
namespace UnitTestsEntities2
{
public class UnitTest1
{
[Fact]
public void Test1()
{
}
}
}

@ -10,16 +10,14 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" /> <PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="xunit" Version="2.4.2" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> <PackageReference Include="xunit" Version="2.5.3" />
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
<PrivateAssets>all</PrivateAssets> </ItemGroup>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.0"> <ItemGroup>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <Using Include="Xunit" />
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup> </ItemGroup>
</Project> </Project>
Loading…
Cancel
Save