Compare commits
97 Commits
0650b3e057
...
271c4b18ed
@ -1,25 +0,0 @@
|
||||
using Entities;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace DbContextLib.Identity;
|
||||
|
||||
public class AuthDbContext: IdentityDbContext<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");
|
||||
}
|
||||
}*/
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Dto.Auth;
|
||||
|
||||
public class LoginRequestDto
|
||||
{
|
||||
[Required(ErrorMessage = "Username is required")]
|
||||
public string Username { get; set; }
|
||||
[Required(ErrorMessage = "Password is required")]
|
||||
public string Password { get; set; }
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
namespace Dto.Auth;
|
||||
|
||||
public class AuthResponseDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the access token issued by the OAuth provider.
|
||||
/// </summary>
|
||||
public string AccessToken { get; set; }
|
||||
|
||||
/// <summary>Gets or sets the token type.</summary>
|
||||
/// <remarks>Typically the string “bearer”.</remarks>
|
||||
public string? TokenType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a refresh token that applications can use to obtain another access token if tokens can expire.
|
||||
/// </summary>
|
||||
public string? RefreshToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the validatity lifetime of the token in seconds.
|
||||
/// </summary>
|
||||
public string? ExpiresIn { get; set; }
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dto.Auth;
|
||||
|
||||
public class RegisterRequestDto
|
||||
{
|
||||
|
||||
[MaxLength(100)]
|
||||
[Required(ErrorMessage = "Username is required")]
|
||||
public string Username { get; set; }
|
||||
[MaxLength(150)]
|
||||
[Required(ErrorMessage = "LastName is required")]
|
||||
public string LastName { get; set; }
|
||||
[MaxLength(100)]
|
||||
[Required(ErrorMessage = "FirstName is required")]
|
||||
public string FirstName { get; set; }
|
||||
[Required(ErrorMessage = "Email is required")]
|
||||
[EmailAddress]
|
||||
public string Email { get; set; }
|
||||
[Required(ErrorMessage = "Sexe is required")]
|
||||
public char Sexe { get; set; }
|
||||
[Required(ErrorMessage = "Size is required")]
|
||||
public float Size { get; set; }
|
||||
[Required(ErrorMessage = "Weight is required")]
|
||||
public float Weight { get; set; }
|
||||
[Required(ErrorMessage = "Password is required")]
|
||||
public string Password { get; set; }
|
||||
[Required(ErrorMessage = "DateOfBirth is required")]
|
||||
public DateTime DateOfBirth { get; set; }
|
||||
public string ProfilePicture { get; set; } = "https://davidalmeida.site/assets/me_avatar.f77af006.png";
|
||||
[Required(ErrorMessage = "Role is required")]
|
||||
public bool IsCoach { get; set; }
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
using Dto.Tiny;
|
||||
|
||||
namespace Dto;
|
||||
|
||||
public class NewActivityDto
|
||||
{
|
||||
public ActivityTinyDto Activity { get; set; }
|
||||
public HeartRateTinyDto[]? HeartRates { get; set; }
|
||||
public int? DataSourceId { get; set; }
|
||||
public int AthleteId { get; set; }
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
using Dto.Tiny;
|
||||
|
||||
namespace Dto;
|
||||
|
||||
public class ResponseActivityDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Type { get; set; } = "";
|
||||
public DateTime Date { get; set; }
|
||||
public DateTime StartTime { get; set; }
|
||||
public DateTime EndTime { get; set; }
|
||||
public int EffortFelt { get; set; }
|
||||
public float Variability { get; set; }
|
||||
public float Variance { get; set; }
|
||||
public float StandardDeviation { get; set; }
|
||||
public float Average { get; set; }
|
||||
public int Maximum { get; set; }
|
||||
public int Minimum { get; set; }
|
||||
public float AverageTemperature { get; set; }
|
||||
public bool HasAutoPause { get; set; }
|
||||
public HeartRateTinyDto[]? HeartRates { get; set; }
|
||||
public DataSourceTinyDto? DataSource { get; set; }
|
||||
public UserTinyDto? Athlete { get; set; }
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
using Dto.Tiny;
|
||||
|
||||
namespace Dto;
|
||||
|
||||
public class ResponseDataSourceDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Type { get; set; } = "Unknown";
|
||||
|
||||
public string Model { get; set; }
|
||||
|
||||
public float Precision { get; set; }
|
||||
|
||||
public ActivityTinyDto[]? Activities { get; set; }
|
||||
|
||||
public UserTinyDto[]? Users { get; set; }
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Dto.Tiny;
|
||||
|
||||
namespace Dto;
|
||||
|
||||
public class ResponseUserDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
[MaxLength(100)]
|
||||
public required string Username { get; set; }
|
||||
[MaxLength(150)]
|
||||
public required string LastName { get; set; }
|
||||
[MaxLength(100)]
|
||||
public required string FirstName { get; set; }
|
||||
public required string Email { get; set; }
|
||||
public required char Sexe { get; set; }
|
||||
public float Lenght { get; set; }
|
||||
public float Weight { get; set; }
|
||||
public string? Password { get; set; }
|
||||
public DateTime DateOfBirth { get; set; }
|
||||
public string ProfilePicture { get; set; } = "https://davidalmeida.site/assets/me_avatar.f77af006.png";
|
||||
public bool IsCoach { get; set; }
|
||||
public LargeImageDto? Image { get; set; }
|
||||
public ActivityTinyDto[] Activities { get; set; }
|
||||
public DataSourceTinyDto? DataSource { get; set; }
|
||||
public FriendshipDto?[] Followers { get; set; }
|
||||
public FriendshipDto?[] Followings { get; set; }
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
namespace Dto.Tiny;
|
||||
|
||||
public class ActivityTinyDto
|
||||
{
|
||||
public int? Id { get; set; }
|
||||
public string Type { get; set; } = "";
|
||||
public DateTime Date { get; set; }
|
||||
public DateTime StartTime { get; set; }
|
||||
public DateTime EndTime { get; set; }
|
||||
public int EffortFelt { get; set; }
|
||||
public float Variability { get; set; }
|
||||
public float Variance { get; set; }
|
||||
public float StandardDeviation { get; set; }
|
||||
public float Average { get; set; }
|
||||
public int Maximum { get; set; }
|
||||
public int Minimum { get; set; }
|
||||
public float AverageTemperature { get; set; }
|
||||
public bool HasAutoPause { get; set; }
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
namespace Dto.Tiny;
|
||||
|
||||
public class DataSourceTinyDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Type { get; set; } = "Unknown";
|
||||
|
||||
public string Model { get; set; }
|
||||
|
||||
public float Precision { get; set; }
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
namespace Dto.Tiny;
|
||||
|
||||
public class FriendshipDto
|
||||
{
|
||||
public int FollowedId { get; set; }
|
||||
public int FollowerId { get; set; }
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
namespace Dto.Tiny;
|
||||
|
||||
public class HeartRateTinyDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public DateTime Timestamp { get; set; }
|
||||
public double? Latitude { get; set; }
|
||||
public double? Longitude { get; set; }
|
||||
public double? Altitude { get; set; }
|
||||
public int HeartRate { get; set; }
|
||||
public int? Cadence { get; set; }
|
||||
public double? Distance { get; set; }
|
||||
public double? Speed { get; set; }
|
||||
public int? Power { get; set; }
|
||||
public double? Temperature { get; set; }
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dto.Tiny;
|
||||
|
||||
public class UserTinyDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
[MaxLength(100)]
|
||||
public required string Username { get; set; }
|
||||
[MaxLength(150)]
|
||||
public required string LastName { get; set; }
|
||||
[MaxLength(100)]
|
||||
public required string FirstName { get; set; }
|
||||
public required string Email { get; set; }
|
||||
public required char Sexe { get; set; }
|
||||
public float Length { get; set; }
|
||||
public float Weight { get; set; }
|
||||
public string? Password { get; set; }
|
||||
public DateTime DateOfBirth { get; set; }
|
||||
public string ProfilePicture { get; set; } = "https://davidalmeida.site/assets/me_avatar.f77af006.png";
|
||||
public bool IsCoach { get; set; }
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
using Dto;
|
||||
using Dto.Tiny;
|
||||
using Entities;
|
||||
using Shared;
|
||||
|
||||
namespace Entities2Dto;
|
||||
|
||||
public static class DataSourceMapper
|
||||
{
|
||||
private static GenericMapper<DataSourceTinyDto, DataSourceEntity> _mapper = new();
|
||||
|
||||
private static GenericMapper<ResponseDataSourceDto, DataSourceEntity> _mapperFull = new();
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
_mapper.Reset();
|
||||
_mapperFull.Reset();
|
||||
}
|
||||
|
||||
public static DataSourceTinyDto ToTinyDto(this DataSourceEntity entity)
|
||||
{
|
||||
Func<DataSourceEntity, DataSourceTinyDto> create = dataSourceEntity => new DataSourceTinyDto
|
||||
{
|
||||
Id = dataSourceEntity.IdSource,
|
||||
Type = dataSourceEntity.Type,
|
||||
Model = dataSourceEntity.Model,
|
||||
Precision = dataSourceEntity.Precision
|
||||
};
|
||||
return entity.ToT(_mapper, create, null,false);
|
||||
}
|
||||
|
||||
public static DataSourceEntity ToEntity(this DataSourceTinyDto dto)
|
||||
{
|
||||
Func<DataSourceTinyDto, DataSourceEntity> create = dataSource => new DataSourceEntity
|
||||
{
|
||||
IdSource = dataSource.Id,
|
||||
Type = dataSource.Type,
|
||||
Model = dataSource.Model,
|
||||
Precision = dataSource.Precision
|
||||
};
|
||||
return dto.ToU(_mapper, create);
|
||||
}
|
||||
|
||||
public static ResponseDataSourceDto ToResponseDto(this DataSourceEntity entity)
|
||||
{
|
||||
Func<DataSourceEntity, ResponseDataSourceDto> create = dataSourceEntity => new ResponseDataSourceDto
|
||||
{
|
||||
Id = dataSourceEntity.IdSource,
|
||||
Type = dataSourceEntity.Type,
|
||||
Model = dataSourceEntity.Model,
|
||||
Precision = dataSourceEntity.Precision,
|
||||
};
|
||||
|
||||
Action<DataSourceEntity, ResponseDataSourceDto> linker = (dataSourceEntity, dto) =>
|
||||
{
|
||||
dto.Activities = dataSourceEntity.Activities.ToTinyDtos().ToArray();
|
||||
dto.Users = dataSourceEntity.Athletes.ToTinyDtos().ToArray();
|
||||
};
|
||||
|
||||
return entity.ToT(_mapperFull, create, linker, false);
|
||||
}
|
||||
|
||||
public static IEnumerable<DataSourceTinyDto> ToTinyDtos(this IEnumerable<DataSourceEntity> entities)
|
||||
=> entities.Select(e => e.ToTinyDto());
|
||||
|
||||
public static IEnumerable<DataSourceEntity> ToEntities(this IEnumerable<DataSourceTinyDto> dtos)
|
||||
=> dtos.Select(d => d.ToEntity());
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
using Dto.Tiny;
|
||||
using Entities;
|
||||
using Shared;
|
||||
|
||||
namespace Entities2Dto;
|
||||
|
||||
public static class FriendshipMapper
|
||||
{
|
||||
private static GenericMapper<FriendshipDto, FriendshipEntity> _mapper = new();
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
_mapper.Reset();
|
||||
}
|
||||
|
||||
public static FriendshipDto ToTinyDto(this FriendshipEntity entity)
|
||||
{
|
||||
Func<FriendshipEntity, FriendshipDto> create = friendshipEntity => new FriendshipDto
|
||||
{
|
||||
FollowedId = friendshipEntity.FollowingId,
|
||||
FollowerId = friendshipEntity.FollowerId,
|
||||
};
|
||||
|
||||
return entity.ToT(_mapper, create, null, false);
|
||||
}
|
||||
|
||||
public static IEnumerable<FriendshipDto> ToTinyDtos(this IEnumerable<FriendshipEntity> entities)
|
||||
=> entities.Select(e => e.ToTinyDto());
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
using Dto.Tiny;
|
||||
using Entities;
|
||||
using Shared;
|
||||
|
||||
namespace Entities2Dto;
|
||||
|
||||
public static class HeartRateMapper
|
||||
{
|
||||
|
||||
private static GenericMapper<HeartRateTinyDto, HeartRateEntity> _mapper = new();
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
_mapper.Reset();
|
||||
}
|
||||
|
||||
public static HeartRateTinyDto ToTinyDto(this HeartRateEntity entity)
|
||||
{
|
||||
var activityTmp = new DateTime();
|
||||
Func<HeartRateEntity, HeartRateTinyDto> create = heartRateEntity => new HeartRateTinyDto
|
||||
{
|
||||
Id = heartRateEntity.IdHeartRate,
|
||||
HeartRate = heartRateEntity.Bpm,
|
||||
Timestamp = activityTmp,
|
||||
Latitude = heartRateEntity.Latitude,
|
||||
Longitude = heartRateEntity.Longitude,
|
||||
Altitude = heartRateEntity.Altitude,
|
||||
Cadence = heartRateEntity.Cadence,
|
||||
Distance = heartRateEntity.Distance,
|
||||
Speed = heartRateEntity.Speed,
|
||||
Power = heartRateEntity.Power,
|
||||
Temperature = heartRateEntity.Temperature
|
||||
};
|
||||
|
||||
return entity.ToT(_mapper, create, null, false);
|
||||
}
|
||||
|
||||
public static HeartRateEntity ToEntity(this HeartRateTinyDto dto)
|
||||
{
|
||||
Func<HeartRateTinyDto, HeartRateEntity> create = heartRate => new HeartRateEntity
|
||||
{
|
||||
IdHeartRate = heartRate.Id,
|
||||
Bpm = heartRate.HeartRate,
|
||||
Time = TimeOnly.FromDateTime(heartRate.Timestamp),
|
||||
Latitude = heartRate.Latitude,
|
||||
Longitude = heartRate.Longitude,
|
||||
Altitude = heartRate.Altitude,
|
||||
Cadence = heartRate.Cadence,
|
||||
Distance = heartRate.Distance,
|
||||
Speed = heartRate.Speed,
|
||||
Power = heartRate.Power,
|
||||
Temperature = heartRate.Temperature
|
||||
};
|
||||
return dto.ToU(_mapper, create);
|
||||
}
|
||||
|
||||
public static IEnumerable<HeartRateTinyDto> ToTinyDtos(this IEnumerable<HeartRateEntity> entities)
|
||||
=> entities.Select(e => e.ToTinyDto());
|
||||
|
||||
public static IEnumerable<HeartRateEntity> ToEntities(this IEnumerable<HeartRateTinyDto> dtos)
|
||||
=> dtos.Select(d => d.ToEntity());
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
using Dto;
|
||||
using Entities;
|
||||
using Shared;
|
||||
|
||||
namespace Entities2Dto;
|
||||
|
||||
public static class LargeImageMapper
|
||||
{
|
||||
private static GenericMapper<LargeImageDto, LargeImageEntity> _mapper = new();
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
_mapper.Reset();
|
||||
}
|
||||
|
||||
public static LargeImageDto ToDto(this LargeImageEntity entity)
|
||||
{
|
||||
Func<LargeImageEntity, LargeImageDto> create = largeImageEntity => new() { Base64 = largeImageEntity.Base64 };
|
||||
|
||||
return entity.ToT(_mapper, create, null, false);
|
||||
}
|
||||
|
||||
public static LargeImageEntity ToEntity(this LargeImageDto dto)
|
||||
{
|
||||
Func<LargeImageDto, LargeImageEntity> create = largeImage => new LargeImageEntity
|
||||
{
|
||||
Base64 = largeImage.Base64
|
||||
};
|
||||
|
||||
return dto.ToU(_mapper, create);
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
using Dto;
|
||||
using Dto.Tiny;
|
||||
using Entities;
|
||||
using Shared;
|
||||
|
||||
namespace Entities2Dto;
|
||||
|
||||
public static class UserMappeur
|
||||
{
|
||||
private static GenericMapper<UserTinyDto, AthleteEntity> _mapper = new();
|
||||
private static GenericMapper<ResponseUserDto, AthleteEntity> _mapperFull = new();
|
||||
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
_mapper.Reset();
|
||||
_mapperFull.Reset();
|
||||
}
|
||||
|
||||
public static UserTinyDto ToTinyDto(this AthleteEntity entity)
|
||||
{
|
||||
Func<AthleteEntity, UserTinyDto> create = athleteEntity => new UserTinyDto
|
||||
{
|
||||
Id = athleteEntity.Id,
|
||||
FirstName = athleteEntity.FirstName,
|
||||
LastName = athleteEntity.LastName,
|
||||
Email = athleteEntity.Email,
|
||||
Password = athleteEntity.PasswordHash,
|
||||
DateOfBirth = athleteEntity.DateOfBirth.ToDateTime(TimeOnly.MinValue),
|
||||
Sexe = athleteEntity.Sexe,
|
||||
Username = athleteEntity.UserName,
|
||||
Weight = athleteEntity.Weight,
|
||||
Length = (float)athleteEntity.Length,
|
||||
ProfilePicture = athleteEntity.ProfilPicture ?? "",
|
||||
IsCoach = athleteEntity.IsCoach
|
||||
};
|
||||
|
||||
return entity.ToT(_mapper, create, null, false);
|
||||
}
|
||||
|
||||
public static AthleteEntity ToEntity(this UserTinyDto model)
|
||||
{
|
||||
Func<UserTinyDto, AthleteEntity> create = user => new AthleteEntity
|
||||
{
|
||||
Id = user.Id,
|
||||
UserName = user.Username,
|
||||
Sexe = user.Sexe,
|
||||
FirstName = user.FirstName,
|
||||
LastName = user.LastName,
|
||||
Email = user.Email,
|
||||
PasswordHash = user.Password ?? "",
|
||||
DateOfBirth = DateOnly.FromDateTime(user.DateOfBirth),
|
||||
IsCoach = user.IsCoach,
|
||||
Weight = user.Weight,
|
||||
Length = user.Length,
|
||||
ProfilPicture = user.ProfilePicture
|
||||
};
|
||||
|
||||
return model.ToU(_mapper, create);
|
||||
}
|
||||
|
||||
public static ResponseUserDto ToResponseDto(this AthleteEntity entity)
|
||||
{
|
||||
Func<AthleteEntity, ResponseUserDto> creator = athleteEntity => new ResponseUserDto
|
||||
{
|
||||
Id = athleteEntity.Id,
|
||||
FirstName = athleteEntity.FirstName,
|
||||
LastName = athleteEntity.LastName,
|
||||
Email = athleteEntity.Email,
|
||||
Password = athleteEntity.PasswordHash,
|
||||
DateOfBirth = athleteEntity.DateOfBirth.ToDateTime(TimeOnly.MinValue),
|
||||
Sexe = athleteEntity.Sexe,
|
||||
Username = athleteEntity.UserName,
|
||||
Weight = athleteEntity.Weight,
|
||||
Lenght = (float)athleteEntity.Length,
|
||||
ProfilePicture = athleteEntity.ProfilPicture ?? "",
|
||||
IsCoach = athleteEntity.IsCoach,
|
||||
};
|
||||
|
||||
Action<AthleteEntity, ResponseUserDto> linker = (athleteEntity, userDto) =>
|
||||
{
|
||||
userDto.Activities = athleteEntity.Activities.ToTinyDtos().ToArray();
|
||||
userDto.Image = athleteEntity.Image?.ToDto();
|
||||
userDto.DataSource = athleteEntity.DataSource?.ToTinyDto();
|
||||
userDto.Followers = athleteEntity.Followers.ToTinyDtos().ToArray();
|
||||
userDto.Followings = athleteEntity.Followings.ToTinyDtos().ToArray();
|
||||
};
|
||||
|
||||
return entity.ToT(_mapperFull, creator, linker, false);
|
||||
}
|
||||
|
||||
public static IEnumerable<UserTinyDto> ToTinyDtos(this IEnumerable<AthleteEntity> entities)
|
||||
=> entities.Select(e => e.ToTinyDto());
|
||||
|
||||
public static IEnumerable<AthleteEntity> ToEntities(this IEnumerable<UserTinyDto> models)
|
||||
=> models.Select(m => m.ToEntity());
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
using Dto;
|
||||
using Dto.Tiny;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Model.Manager;
|
||||
using Model.Repository;
|
||||
using Model.utils;
|
||||
|
||||
namespace HeartTrackAPI.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[ApiVersion("1.0")]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
public class AnalysisController : Controller
|
||||
{
|
||||
|
||||
private readonly IActivityRepository _activityService;
|
||||
private readonly ILogger<AnalysisController> _logger;
|
||||
|
||||
|
||||
public AnalysisController(IDataManager dataManager, ILogger<AnalysisController> logger)
|
||||
{
|
||||
_activityService = dataManager.ActivityRepo;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
[HttpGet("activity/{activityId}")]
|
||||
public async Task<IActionResult> AnalyseByActivityId(int activityId)
|
||||
{
|
||||
var activity = await _activityService.GetActivityById(activityId);
|
||||
if (activity == null)
|
||||
{
|
||||
_logger.LogInformation($"Activity with ID {activityId} not found.");
|
||||
return NotFound($"Activity with ID {activityId} not found.");
|
||||
}
|
||||
// for the moment no need to get the user Entity [Dave]
|
||||
var user = activity.Athlete;
|
||||
if (user == null)
|
||||
{
|
||||
_logger.LogInformation($"User not found for activity ID {activityId}.");
|
||||
return NotFound($"User not found for activity ID {activityId}.");
|
||||
}
|
||||
|
||||
var analysis = ActivityAnalysis.FromActivityData(activity);
|
||||
return Ok(analysis);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
public class HeartRateZoneResult
|
||||
{
|
||||
public string Zone { get; set; }
|
||||
public TimeSpan TimeSpent { get; set; }
|
||||
}
|
||||
|
||||
private readonly List<HeartRateZone> _heartRateZones = new()
|
||||
{
|
||||
new() { Name = "Repos", MinHeartRate = 0, MaxHeartRate = 60 },
|
||||
new() { Name = "Aérobie légère", MinHeartRate = 61, MaxHeartRate = 90 },
|
||||
new() { Name = "Aérobie", MinHeartRate = 91, MaxHeartRate = 140 },
|
||||
new() { Name = "Anaérobie", MinHeartRate = 141, MaxHeartRate = 180 },
|
||||
new() { Name = "VO2 Max", MinHeartRate = 181, MaxHeartRate = 220 }
|
||||
};
|
||||
[HttpGet("heart-rate/zones/{activityId}")]
|
||||
public IActionResult GetActivityHeartRateZones(int activityId)
|
||||
{
|
||||
var heartRateTinyDtos = _activityService.GetActivityById(activityId).Result?.HeartRates;
|
||||
if (heartRateTinyDtos != null)
|
||||
{
|
||||
var heartRates = heartRateTinyDtos.ToList();
|
||||
var results = _heartRateZones.Select(zone => new HeartRateZoneResult
|
||||
{
|
||||
Zone = zone.Name,
|
||||
TimeSpent = CalculateTimeInZone(zone, heartRates)
|
||||
}).ToList();
|
||||
|
||||
return Ok(results);
|
||||
}
|
||||
|
||||
return NotFound("Not heart rates");
|
||||
|
||||
}
|
||||
private TimeSpan CalculateTimeInZone(HeartRateZone zone, List<HeartRateTinyDto> heartRates)
|
||||
{
|
||||
var secondsInZone =
|
||||
heartRates.Count(hr => hr.HeartRate >= zone.MinHeartRate && hr.HeartRate <= zone.MaxHeartRate);
|
||||
return TimeSpan.FromSeconds(secondsInZone);
|
||||
}* /
|
||||
|
||||
[HttpGet("getOptimizedPath")]
|
||||
public IActionResult GetOptimizedPath(int activityId)
|
||||
{
|
||||
var heartRateData = GetMockHeartRateData();
|
||||
|
||||
var sortedData = heartRateData.OrderBy(x => x.Timestamp).ToList();
|
||||
|
||||
var path = new GeoJsonPath();
|
||||
foreach (var item in sortedData)
|
||||
{
|
||||
if (item.Latitude.HasValue && item.Longitude.HasValue)
|
||||
{
|
||||
path.Coordinates.Add(new GeoJsonCoordinate(item.Longitude.Value, item.Latitude.Value));
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(path.ToGeoJson());
|
||||
}
|
||||
*/
|
@ -0,0 +1,154 @@
|
||||
using System.Globalization;
|
||||
using Dto.Auth;
|
||||
using Dto.Tiny;
|
||||
using Entities;
|
||||
using HeartTrackAPI.Request;
|
||||
using HeartTrackAPI.Services;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace HeartTrackAPI.Controllers;
|
||||
[ApiController]
|
||||
[ApiVersion("1.0")]
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
public class AuthController : Controller
|
||||
{
|
||||
|
||||
private readonly UserManager<AthleteEntity> _userManager;
|
||||
private readonly ITokenService _tokenService;
|
||||
private readonly SignInManager<AthleteEntity> _signinManager;
|
||||
|
||||
public AuthController(UserManager<AthleteEntity> userManager,ITokenService tokenService, SignInManager<AthleteEntity> signinManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_tokenService = tokenService;
|
||||
_signinManager = signinManager;
|
||||
}
|
||||
[HttpPost("login")]
|
||||
public async Task<IActionResult> Login(LoginRequestDto loginDto)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
return BadRequest(ModelState);
|
||||
|
||||
var user = await _userManager.Users.FirstOrDefaultAsync(x => x.UserName == loginDto.Username.ToLower());
|
||||
|
||||
if (user == null) return Unauthorized("Invalid username!");
|
||||
|
||||
var result = await _signinManager.CheckPasswordSignInAsync(user, loginDto.Password, false);
|
||||
|
||||
if (!result.Succeeded) return Unauthorized("Username not found and/or password incorrect");
|
||||
|
||||
return Ok(new AuthResponseDto
|
||||
{
|
||||
AccessToken = _tokenService.CreateToken(user),
|
||||
ExpiresIn = DateTime.Now.AddDays(7).ToString(CultureInfo.InvariantCulture),
|
||||
TokenType = "Bearer"
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
[HttpPost("register")]
|
||||
public async Task<IActionResult> Register([FromBody] RegisterRequestDto request)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
return BadRequest(ModelState);
|
||||
// just for testing
|
||||
// the good way is to use the repository and give him the userManager
|
||||
var user = new AthleteEntity
|
||||
{
|
||||
Email = request.Email,
|
||||
UserName = request.Username,
|
||||
LastName = request.LastName,
|
||||
FirstName = request.FirstName,
|
||||
Sexe = request.Sexe,
|
||||
Length = request.Size,
|
||||
Weight = request.Weight,
|
||||
DateOfBirth = DateOnly.FromDateTime(request.DateOfBirth),
|
||||
IsCoach = request.IsCoach
|
||||
};
|
||||
var createdUser = _userManager.CreateAsync(user, request.Password).Result;
|
||||
if (createdUser.Succeeded)
|
||||
{
|
||||
var roleResult = await _userManager.AddToRoleAsync(user, request.IsCoach ? "Coach" : "Athlete");
|
||||
if (roleResult.Succeeded)
|
||||
{
|
||||
return Ok(
|
||||
new AuthResponseDto
|
||||
{
|
||||
AccessToken = _tokenService.CreateToken(user),
|
||||
ExpiresIn = DateTime.Now.AddDays(7).ToString(),
|
||||
TokenType = "Bearer"
|
||||
}
|
||||
);
|
||||
}
|
||||
{
|
||||
return StatusCode(500, roleResult.Errors);
|
||||
}
|
||||
}
|
||||
{
|
||||
return StatusCode(500, createdUser.Errors);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
|
||||
|
||||
/* var user = _userRepository.GetByEmail(request.Email);
|
||||
if (user != null)
|
||||
{
|
||||
return BadRequest("User already exists");
|
||||
}
|
||||
var newUser = new User
|
||||
{
|
||||
Email = request.Email,
|
||||
PasswordHash = BCrypt.Net.BCrypt.HashPassword(request.PasswordHash),
|
||||
FirstName = request.FirstName,
|
||||
LastName = request.LastName
|
||||
};
|
||||
_userRepository.Add(newUser);
|
||||
return Ok();*/
|
||||
}
|
||||
/*
|
||||
[HttpPost("refresh")]
|
||||
public IActionResult Refresh([FromBody] RefreshRequest request)
|
||||
{
|
||||
var user = _userRepository.GetByEmail(request.Email);
|
||||
if (user == null)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
if (!BCrypt.Net.BCrypt.Verify(request.PasswordHash, user.PasswordHash))
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
var token = _jwtService.GenerateToken(user);
|
||||
return Ok(new { token });
|
||||
}
|
||||
*/
|
||||
[HttpPost("logout")]
|
||||
public IActionResult Logout()
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
/*
|
||||
|
||||
[HttpPost("forgot-password")]
|
||||
public IActionResult ForgotPassword([FromBody] ForgotPasswordRequest request)
|
||||
{
|
||||
var user = _userRepository.GetByEmail(request.Email);
|
||||
if (user == null)
|
||||
{
|
||||
return BadRequest("User not found");
|
||||
}
|
||||
var token = _jwtService.GenerateToken(user);
|
||||
// send email with token
|
||||
return Ok();
|
||||
}*/
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using Entities;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace HeartTrackAPI.Services;
|
||||
public interface ITokenService
|
||||
{
|
||||
string CreateToken(AthleteEntity user);
|
||||
}
|
||||
|
||||
public class TokenService : ITokenService
|
||||
{
|
||||
private readonly IConfiguration _config;
|
||||
private readonly SymmetricSecurityKey _key;
|
||||
|
||||
public TokenService(IConfiguration config)
|
||||
{
|
||||
_config = config;
|
||||
_key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["JWT:SigningKey"]));
|
||||
}
|
||||
public string CreateToken(AthleteEntity user)
|
||||
{
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new (JwtRegisteredClaimNames.Email, user.Email),
|
||||
new (JwtRegisteredClaimNames.NameId, user.Id.ToString()),
|
||||
new (JwtRegisteredClaimNames.GivenName, user.UserName)
|
||||
};
|
||||
|
||||
var creds = new SigningCredentials(_key, SecurityAlgorithms.HmacSha512Signature);
|
||||
|
||||
var tokenDescriptor = new SecurityTokenDescriptor
|
||||
{
|
||||
Subject = new ClaimsIdentity(claims),
|
||||
Expires = DateTime.Now.AddDays(7),
|
||||
SigningCredentials = creds,
|
||||
Issuer = _config["JWT:Issuer"],
|
||||
Audience = _config["JWT:Audience"]
|
||||
};
|
||||
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
|
||||
var token = tokenHandler.CreateToken(tokenDescriptor);
|
||||
|
||||
return tokenHandler.WriteToken(token);
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
namespace Model.Repository;
|
||||
|
||||
public interface IDataSourceRepository<T>
|
||||
{
|
||||
Task<T?> GetItemById(int id);
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
using Model.utils;
|
||||
|
||||
namespace Dto.Tiny;
|
||||
|
||||
public class ActivityAnalysis
|
||||
{
|
||||
public double AverageHeartRate { get; private set; }
|
||||
public string AverageHeartRateAdvice { get; private set; }
|
||||
public double Vo2Max { get; private set; }
|
||||
public string Vo2MaxAdvice { get; private set; }
|
||||
public double NormalBpm { get; private set; }
|
||||
public string NormalBpmAdvice { get; private set; }
|
||||
public double HeartRateVariability { get; private set; }
|
||||
public string HeartRateVariabilityAdvice { get; private set; }
|
||||
public string HeartRateZone { get; private set; }
|
||||
public string HeartRateZoneAdvice { get; private set; }
|
||||
public double Duration { get; private set; }
|
||||
public string DurationAdvice { get; private set; }
|
||||
public double Effort { get; private set; }
|
||||
public string EffortAdvice { get; private set; }
|
||||
public static ActivityAnalysis FromActivityData(ResponseActivityDto activity)
|
||||
{
|
||||
double dureeActivity = (activity.EndTime - activity.StartTime).TotalMinutes;
|
||||
var age = DateTime.Today.Year - activity.Athlete.DateOfBirth.Year;
|
||||
var gender = activity.Athlete.Sexe;
|
||||
var poids = activity.Athlete.Weight;
|
||||
var effortFelt = activity.EffortFelt;
|
||||
var averageHeartRate = activity.Average;
|
||||
var heartRateVariability = activity.Variability;
|
||||
|
||||
var heartRateZones = HeartRateAdvise.CalculateHeartRateZones(age);
|
||||
|
||||
var effortScore = HeartRateAdvise.EvaluateEffort(activity);
|
||||
|
||||
var (seuilBPM, vo2Max) = HeartRateAdvise.SeuilBPMavance(gender, age, poids, dureeActivity);
|
||||
string averageHeartRateAdvice = HeartRateAdvise.GenerateAverageHeartRateAdvice(averageHeartRate, seuilBPM);
|
||||
string vo2MaxAdvice = HeartRateAdvise.GenerateVo2MaxAdvice(vo2Max);
|
||||
string normalBpmAdvice = HeartRateAdvise.GenerateNormalBpmAdvice(seuilBPM, averageHeartRate);
|
||||
string hrvAdvice = HeartRateAdvise.GenerateHrvAdvice(heartRateVariability);
|
||||
HeartRateAdvise.HeartRateZone currentZone = heartRateZones.Find(zone => averageHeartRate >= zone.MinHeartRate && averageHeartRate <= zone.MaxHeartRate);
|
||||
string heartRateZoneAdvice = HeartRateAdvise.GenerateHeartRateZoneAdvice(currentZone?.Name);
|
||||
var effortAccuracy = HeartRateAdvise.CompareEffort(effortFelt, (int)effortScore);
|
||||
var analysis = new ActivityAnalysis
|
||||
{
|
||||
AverageHeartRate = averageHeartRate,
|
||||
AverageHeartRateAdvice = averageHeartRateAdvice,
|
||||
Vo2Max = vo2Max,
|
||||
Vo2MaxAdvice = vo2MaxAdvice,
|
||||
NormalBpm = seuilBPM,
|
||||
NormalBpmAdvice = normalBpmAdvice,
|
||||
HeartRateVariability = heartRateVariability,
|
||||
HeartRateVariabilityAdvice = hrvAdvice,
|
||||
HeartRateZone = currentZone != null ? currentZone.Name : "N/A",
|
||||
HeartRateZoneAdvice = heartRateZoneAdvice,
|
||||
Duration = dureeActivity,
|
||||
DurationAdvice =HeartRateAdvise.GenerateDurationAdvice(dureeActivity),
|
||||
Effort = effortScore,
|
||||
EffortAdvice = HeartRateAdvise.GenerateEffortAdvice(effortAccuracy)
|
||||
};
|
||||
|
||||
return analysis;
|
||||
}
|
||||
}
|
@ -0,0 +1,278 @@
|
||||
using Dto;
|
||||
|
||||
namespace Model.utils;
|
||||
|
||||
public class HeartRateAdvise
|
||||
{
|
||||
public class HeartRateZone
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int MinHeartRate { get; set; }
|
||||
public int MaxHeartRate { get; set; }
|
||||
}
|
||||
|
||||
public string getAdvise(Activity activity)
|
||||
{
|
||||
return "You should take a break";
|
||||
}
|
||||
public static List<HeartRateZone> CalculateHeartRateZones(int age)
|
||||
{
|
||||
int fcm = 220 - age; // Estimation de la FCM
|
||||
List<HeartRateZone> zones = new List<HeartRateZone>
|
||||
{
|
||||
new HeartRateZone { Name = "Très Légère", MinHeartRate = (int)(fcm * 0.50), MaxHeartRate = (int)(fcm * 0.60) },
|
||||
new HeartRateZone { Name = "Aérobie légère", MinHeartRate = (int)(fcm * 0.60), MaxHeartRate = (int)(fcm * 0.70) },
|
||||
new HeartRateZone { Name = "Aérobie", MinHeartRate = (int)(fcm * 0.70), MaxHeartRate = (int)(fcm * 0.80) },
|
||||
new HeartRateZone { Name = "Anaérobie", MinHeartRate = (int)(fcm * 0.80), MaxHeartRate = (int)(fcm * 0.90) },
|
||||
new HeartRateZone { Name = "Maximum", MinHeartRate = (int)(fcm * 0.90), MaxHeartRate = (int)(fcm * 1.00) }
|
||||
};
|
||||
|
||||
return zones;
|
||||
}
|
||||
public static double EvaluateEffort(ResponseActivityDto stats)
|
||||
{
|
||||
double score = 0;
|
||||
|
||||
score += stats.Average * 0.3; // Exemple de poids
|
||||
score += stats.HeartRates.Average(speed => speed.Speed ?? 0) * 0.25;
|
||||
score += stats.HeartRates.Sum(dist => dist.Distance ?? 0) * 0.15;
|
||||
score += stats.HeartRates.Average(hr => hr.Cadence ?? 0) * 0.1;
|
||||
score += stats.HeartRates.Average(hr => hr.Power ?? 0) * 0.15;
|
||||
score += stats.StandardDeviation * 0.05;
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
public static string CompareEffort(int perceivedEffort, int objectiveEffort)
|
||||
{
|
||||
if (perceivedEffort == objectiveEffort) return "Accurate";
|
||||
if (perceivedEffort > objectiveEffort) return "Overestimated";
|
||||
if (perceivedEffort < objectiveEffort) return "Underestimated";
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
|
||||
// Faible intensité : 50-60% de la FCM
|
||||
// Intensité modérée : 60-70% de la FCM
|
||||
// Haute intensité : 70-85% de la FCM
|
||||
public static double CalculerVo2Max(char sexe, int age, double poids)
|
||||
{
|
||||
if (sexe == 'M')
|
||||
{
|
||||
return (poids * 0.198) + (age * -0.193) + 24.489;
|
||||
}
|
||||
|
||||
// sexe == "F"
|
||||
{
|
||||
return (poids * 0.201) + (age * -0.217) + 20.453;
|
||||
}
|
||||
}
|
||||
|
||||
public static (double SeuilBPM, double Vo2Max) SeuilBPMavance(char sexe, int age, double poids, double dureeActivite)
|
||||
{
|
||||
double fcm = sexe == 'M' ? 207 - (0.7 * age) : 206 - (0.88 * age);
|
||||
double vo2Max = CalculerVo2Max(sexe, age, poids);
|
||||
|
||||
double zone = dureeActivite <= 30 ? 0.8 : dureeActivite <= 60 ? 0.7 : 0.6;
|
||||
double seuilBpm = fcm * zone;
|
||||
|
||||
return (seuilBpm, vo2Max);
|
||||
}
|
||||
|
||||
public static Dictionary<string, (double Value, string Advice)> GenerateAdvice(ResponseActivityDto activity)
|
||||
{
|
||||
int dureeActivity = (activity.EndTime - activity.StartTime).Minutes;
|
||||
var age = DateTime.Today.Year - activity.Athlete.DateOfBirth.Year;
|
||||
var gender = activity.Athlete.Sexe;
|
||||
var poids = activity.Athlete.Weight;
|
||||
var effortFelt = activity.EffortFelt;
|
||||
var averageHeartRate = activity.Average;
|
||||
var heartRateVariability = activity.Variability;
|
||||
var heartRateZones = CalculateHeartRateZones(age);
|
||||
var effortScore = EvaluateEffort(activity);
|
||||
|
||||
|
||||
var (seuilBPM, vo2Max) = SeuilBPMavance(gender, age, poids, dureeActivity);
|
||||
Dictionary<string, (double Value, string Advice)> healthMetrics = new Dictionary<string, (double Value, string Advice)>();
|
||||
|
||||
// Conseil pour AverageHeartRate
|
||||
string averageHeartRateAdvice = averageHeartRate > seuilBPM
|
||||
? "Votre rythme cardiaque moyen est supérieur au seuil recommandé. Envisagez de réduire l'intensité."
|
||||
: "Votre rythme cardiaque moyen est dans une bonne plage. Continuez à maintenir votre intensité actuelle.";
|
||||
|
||||
// Conseil pour Vo2Max
|
||||
string vo2MaxAdvice;
|
||||
if (vo2Max < 30)
|
||||
vo2MaxAdvice =
|
||||
"Votre Vo2 max est faible, envisagez d'augmenter progressivement l'intensité de vos entraînements.";
|
||||
else if (vo2Max < 40)
|
||||
vo2MaxAdvice = "Votre Vo2 max est dans la moyenne. Continuez de travailler sur votre endurance.";
|
||||
else vo2MaxAdvice = "Votre Vo2 max est excellente. Vous pourriez bénéficier d'entraînements à haute intensité.";
|
||||
|
||||
// Conseil basé sur la comparaison avec NormalBpm
|
||||
string normalBpmAdvice = seuilBPM > averageHeartRate
|
||||
? "Votre BPM normal est plus élevé que la moyenne, assurez-vous de surveiller votre intensité d'entraînement."
|
||||
: "Votre BPM normal est inférieur à la moyenne, ce qui peut indiquer un bon niveau de forme physique.";
|
||||
// Conseil pour HeartRateVariability
|
||||
string hrvAdvice = heartRateVariability < 40
|
||||
? "Votre HRV est basse, ce qui peut indiquer un stress élevé ou une récupération insuffisante. Envisagez d'améliorer votre récupération."
|
||||
: heartRateVariability < 60
|
||||
? "Votre HRV est dans une plage moyenne. Continuez de surveiller votre récupération et votre stress."
|
||||
: "Votre HRV est élevée, indiquant une bonne récupération et une gestion du stress. Continuez vos bonnes pratiques de gestion de la santé.";
|
||||
|
||||
HeartRateZone currentZone = heartRateZones.Find(zone =>
|
||||
averageHeartRate >= zone.MinHeartRate && averageHeartRate <= zone.MaxHeartRate);
|
||||
string heartRateZoneAdvice;
|
||||
if (currentZone != null)
|
||||
{
|
||||
heartRateZoneAdvice = $"Votre BPM moyen est dans la zone '{currentZone.Name}', qui est idéale pour ";
|
||||
switch (currentZone.Name)
|
||||
{
|
||||
case "Repos":
|
||||
heartRateZoneAdvice += "favoriser la récupération.";
|
||||
break;
|
||||
case "Endurance":
|
||||
heartRateZoneAdvice += "améliorer l'endurance cardiovasculaire et brûler des graisses.";
|
||||
break;
|
||||
case "Aérobie":
|
||||
heartRateZoneAdvice += "améliorer votre capacité aérobie.";
|
||||
break;
|
||||
case "Anaérobie":
|
||||
heartRateZoneAdvice += "améliorer la performance à haute intensité.";
|
||||
break;
|
||||
case "VO2 Max":
|
||||
heartRateZoneAdvice += "maximiser la performance et la capacité aérobie.";
|
||||
break;
|
||||
default:
|
||||
heartRateZoneAdvice =
|
||||
"Cette zone est spécifique et peut avoir différents objectifs en fonction de votre plan d'entraînement.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
heartRateZoneAdvice =
|
||||
"Vous n'êtes dans aucune zone spécifique. Assurez-vous que votre BPM moyen est correctement mesuré.";
|
||||
}
|
||||
|
||||
// Comparaison de l'effort objectif avec l'effort perçu
|
||||
var effortAccuracy = CompareEffort(effortFelt, (int)effortScore);
|
||||
|
||||
// Remplissage du dictionnaire
|
||||
healthMetrics.Add("AverageHeartRate", (averageHeartRate, averageHeartRateAdvice));
|
||||
healthMetrics.Add("Vo2Max", (vo2Max, vo2MaxAdvice));
|
||||
healthMetrics.Add("NormalBpm", (seuilBPM, normalBpmAdvice));
|
||||
healthMetrics.Add("HeartRateVariability", (heartRateVariability, hrvAdvice));
|
||||
healthMetrics.Add("HeartRateZone", (averageHeartRate, heartRateZoneAdvice));
|
||||
healthMetrics.Add("Duration",
|
||||
(dureeActivity,
|
||||
dureeActivity < 75
|
||||
? "Vous pourriez augmenter la durée de vos activités pour atteindre les recommandations."
|
||||
: "Votre durée d'activité est conforme aux recommandations."));
|
||||
healthMetrics.Add("Effort", (effortScore, GenerateEffortAdvice(effortAccuracy)));
|
||||
return healthMetrics;
|
||||
}
|
||||
public static string GenerateAverageHeartRateAdvice(float averageHeartRate, double seuilBPM)
|
||||
{
|
||||
return averageHeartRate > seuilBPM
|
||||
? "Votre rythme cardiaque moyen est supérieur au seuil recommandé. Envisagez de réduire l'intensité."
|
||||
: "Votre rythme cardiaque moyen est dans une bonne plage. Continuez à maintenir votre intensité actuelle.";
|
||||
}
|
||||
public static string GenerateVo2MaxAdvice(double vo2Max)
|
||||
{
|
||||
if (vo2Max < 30)
|
||||
return "Votre Vo2 max est faible, envisagez d'augmenter progressivement l'intensité de vos entraînements.";
|
||||
if (vo2Max < 40)
|
||||
return "Votre Vo2 max est dans la moyenne. Continuez de travailler sur votre endurance.";
|
||||
return "Votre Vo2 max est excellente. Vous pourriez bénéficier d'entraînements à haute intensité.";
|
||||
}
|
||||
public static string GenerateNormalBpmAdvice(double normalBpm,double averageHeartRate)
|
||||
{
|
||||
return normalBpm > averageHeartRate
|
||||
? "Votre BPM normal est plus élevé que la moyenne, ce qui peut indiquer un bon niveau de forme physique."
|
||||
: "Votre BPM normal est inférieur à la moyenne, assurez-vous de surveiller votre intensité d'entraînement.";
|
||||
}
|
||||
|
||||
public static string GenerateHrvAdvice(double heartRateVariability)
|
||||
{
|
||||
return heartRateVariability < 40
|
||||
? "Votre HRV est basse, ce qui peut indiquer un stress élevé ou une récupération insuffisante. Envisagez d'améliorer votre récupération."
|
||||
: heartRateVariability < 60
|
||||
? "Votre HRV est dans une plage moyenne. Continuez de surveiller votre récupération et votre stress."
|
||||
: "Votre HRV est élevée, indiquant une bonne récupération et une gestion du stress. Continuez vos bonnes pratiques de gestion de la santé.";
|
||||
}
|
||||
public static string GenerateHeartRateZoneAdvice(string? heartRateZone)
|
||||
{
|
||||
return heartRateZone switch
|
||||
{
|
||||
"Repos" => "Favoriser la récupération.",
|
||||
"Endurance" => "Améliorer l'endurance cardiovasculaire et brûler des graisses.",
|
||||
"Aérobie" => "Améliorer votre capacité aérobie.",
|
||||
"Anaérobie" => "Améliorer la performance à haute intensité.",
|
||||
"VO2 Max" => "Maximiser la performance et la capacité aérobie.",
|
||||
_ => "Cette zone est spécifique et peut avoir différents objectifs en fonction de votre plan d'entraînement."
|
||||
};
|
||||
}
|
||||
public static string GenerateDurationAdvice(double dureeActivity)
|
||||
{
|
||||
return dureeActivity < 75
|
||||
? "Vous pourriez augmenter la durée de vos activités pour atteindre les recommandations."
|
||||
: "Votre durée d'activité est conforme aux recommandations.";
|
||||
}
|
||||
|
||||
public static string GenerateEffortAdvice(string effortAccuracy)
|
||||
{
|
||||
return effortAccuracy switch
|
||||
{
|
||||
"Accurate" => "Votre perception de l'effort est précise. Continuez ainsi!",
|
||||
"Overestimated" => "Vous surestimez votre effort. Essayez de pousser un peu plus lors de vos prochaines activités.",
|
||||
"Underestimated" => "Vous sous-estimez votre effort. Vous pourriez être plus proche de vos limites que vous ne le pensez.",
|
||||
_ => "Continuez à surveiller et ajuster votre effort pour de meilleurs résultats."
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public class EffortAnalysisResult
|
||||
{
|
||||
public string EffortAccuracy { get; set; }
|
||||
public string Advice { get; set; }
|
||||
}
|
||||
|
||||
public EffortAnalysisResult AnalyzeActivityEffort(ResponseActivityDto activity)
|
||||
{
|
||||
|
||||
|
||||
var effortScore = EvaluateEffort(activity);
|
||||
|
||||
// Comparaison de l'effort objectif avec l'effort perçu
|
||||
var effortAccuracy = CompareEffort(activity.EffortFelt, (int)effortScore);
|
||||
var result = new EffortAnalysisResult
|
||||
{
|
||||
EffortAccuracy = effortAccuracy,
|
||||
Advice = GenerateEffortAdvice(effortAccuracy)
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
public List<HeartRateTinyDto> GetMockHeartRateData()
|
||||
{
|
||||
var random = new Random();
|
||||
return Enumerable.Range(1, 3600)
|
||||
.Select(_ => new HeartRateTinyDto
|
||||
{
|
||||
HeartRate = random.Next(60, 220),
|
||||
Timestamp = new DateTime(2021, 1, 1).AddSeconds(random.Next(3600)),
|
||||
Latitude = random.NextDouble() * 180 - 90,
|
||||
Longitude = random.NextDouble() * 360 - 180,
|
||||
Altitude = random.NextDouble() * 1000,
|
||||
Cadence = random.Next(60, 120),
|
||||
Distance = random.NextDouble() * 100,
|
||||
Speed = random.NextDouble() * 30,
|
||||
Power = random.Next(0, 500),
|
||||
Temperature = random.NextDouble() * 30
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
*/
|
||||
|
@ -0,0 +1,34 @@
|
||||
using Dto.Tiny;
|
||||
using Entities2Dto;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Model.Repository;
|
||||
|
||||
namespace Model2Entities;
|
||||
|
||||
public partial class DbDataManager
|
||||
{
|
||||
public class DataSourceRepository : IDataSourceRepository<DataSourceTinyDto>
|
||||
{
|
||||
private readonly DbDataManager _dataManager;
|
||||
private readonly ILogger<DbDataManager> _logger;
|
||||
|
||||
public DataSourceRepository(DbDataManager dbDataManager, ILogger<DbDataManager> logger)
|
||||
{
|
||||
_dataManager = dbDataManager;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
||||
public async Task<DataSourceTinyDto?> GetItemById(int id)
|
||||
{
|
||||
var dataSource = await _dataManager.DbContext.DataSourcesSet.FindAsync(id);
|
||||
if (dataSource == null)
|
||||
{
|
||||
_logger.LogInformation($"DataSource with ID {id} not found.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return dataSource.ToTinyDto();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
namespace Shared;
|
||||
|
||||
public class FriendShipException : ModelNotFoundException
|
||||
{
|
||||
public FriendShipException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class ModelNotFoundException : Exception
|
||||
{
|
||||
public ModelNotFoundException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
using Xunit;
|
||||
using Model2Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using DbContextLib;
|
||||
using StubbedContextLib;
|
||||
using System.Linq;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using System;
|
||||
using EFMappers;
|
||||
using Shared;
|
||||
using Model;
|
||||
using Moq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Entities;
|
||||
/*
|
||||
namespace UnitTestsEntities
|
||||
{
|
||||
public class ActivityRepositoryTests : IClassFixture<DatabaseFixture>
|
||||
{
|
||||
private readonly DatabaseFixture _fixture;
|
||||
|
||||
public ActivityRepositoryTests(DatabaseFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetActivities_ReturnsActivities()
|
||||
{
|
||||
var options = new DbContextOptionsBuilder<HeartTrackContext>()
|
||||
.UseSqlite(_fixture._connection)
|
||||
.Options;
|
||||
|
||||
using (var context = new HeartTrackContext(options))
|
||||
{
|
||||
context.Database.EnsureCreated();
|
||||
}
|
||||
|
||||
using (var context = new HeartTrackContext(options))
|
||||
{
|
||||
var repository = new DbDataManager.ActivityRepository(new DbDataManager(context), null);
|
||||
var activities = await repository.GetActivities(0, 10, ActivityOrderCriteria.None);
|
||||
|
||||
Assert.NotNull(activities);
|
||||
Assert.Equal(10, activities.Count());
|
||||
}
|
||||
}
|
||||
[Fact]
|
||||
public async Task GetActivityByIdAsync_ReturnsCorrectActivity_WhenIdExists()
|
||||
{
|
||||
// Arrange
|
||||
var activityId = 1;
|
||||
var expectedActivity = new Activity { Id = activityId, Type = "Running" };
|
||||
|
||||
var mockDataManager = new Mock<DbDataManager>();
|
||||
mockDataManager.Setup(dm => dm.DbContext.ActivitiesSet.SingleOrDefaultAsync(a => a.IdActivity == activityId))
|
||||
.ReturnsAsync(expectedActivity.ToEntity());
|
||||
|
||||
var loggerMock = new Mock<ILogger<DbDataManager>>();
|
||||
var activityRepository = new DbDataManager.ActivityRepository(mockDataManager.Object, loggerMock.Object);
|
||||
|
||||
// Act
|
||||
var result = await activityRepository.GetActivityByIdAsync(activityId);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(expectedActivity.Id, result.Id);
|
||||
Assert.Equal(expectedActivity.Type, result.Type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetActivityByIdAsync_ReturnsNull_WhenIdDoesNotExist()
|
||||
{
|
||||
// Arrange
|
||||
var activityId = 999;
|
||||
|
||||
var mockDataManager = new Mock<DbDataManager>();
|
||||
mockDataManager.Setup(dm => dm.DbContext.ActivitiesSet.SingleOrDefaultAsync(a => a.IdActivity == activityId))
|
||||
.ReturnsAsync((ActivityEntity)null);
|
||||
|
||||
var loggerMock = new Mock<ILogger<DbDataManager>>();
|
||||
var activityRepository = new DbDataManager.ActivityRepository(mockDataManager.Object, loggerMock.Object);
|
||||
|
||||
// Act
|
||||
var result = await activityRepository.GetActivityByIdAsync(activityId);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddActivity_SuccessfullyAddsNewActivity()
|
||||
{
|
||||
// Arrange
|
||||
var newActivity = new Activity { Type = "Walking" };
|
||||
|
||||
var mockDataManager = new Mock<DbDataManager>();
|
||||
mockDataManager.Setup(dm => dm.DbContext.AddItem(It.IsAny<ActivityEntity>()))
|
||||
.ReturnsAsync(newActivity.ToEntity());
|
||||
|
||||
var loggerMock = new Mock<ILogger<DbDataManager>>();
|
||||
var activityRepository = new DbDataManager.ActivityRepository(mockDataManager.Object, loggerMock.Object);
|
||||
|
||||
// Act
|
||||
var result = await activityRepository.AddActivity(newActivity);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(newActivity.Type, result.Type);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
@ -0,0 +1 @@
|
||||
global using Xunit;
|
@ -0,0 +1,31 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
|
||||
<PackageReference Include="Moq" Version="4.20.70" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Model2Entities\Model2Entities.csproj" />
|
||||
<ProjectReference Include="..\UnitTestsEntities\UnitTestsEntities.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,10 @@
|
||||
namespace RepositoriesUnitTest;
|
||||
|
||||
public class UnitTest1
|
||||
{
|
||||
[Fact]
|
||||
public void Test1()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
global using Microsoft.VisualStudio.TestTools.UnitTesting;
|
@ -1,26 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0"/>
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.0.4"/>
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.0.4"/>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\HeartTrackAPI\HeartTrackAPI.csproj" />
|
||||
<ProjectReference Include="..\..\Model\Model.csproj" />
|
||||
<ProjectReference Include="..\..\Shared\Shared.csproj" />
|
||||
<ProjectReference Include="..\..\StubAPI\StubAPI.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,12 +0,0 @@
|
||||
namespace ClientTests;
|
||||
|
||||
public class HttpClientManager
|
||||
{
|
||||
protected readonly HttpClient _httpClient;
|
||||
|
||||
public HttpClientManager(HttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_httpClient.BaseAddress = new Uri("https://localhost:7252");
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
/*/*!
|
||||
* \file BookDataServiceAPI.cs
|
||||
* \author HeartTeam
|
||||
* \brief Fichier contenant la classe BookDataServiceAPI.
|
||||
#1#
|
||||
|
||||
using System.Diagnostics;
|
||||
using Dto;
|
||||
using Model.Repository;
|
||||
using Shared;
|
||||
using APIMappers;
|
||||
using Dto.Tiny;
|
||||
using Model;
|
||||
|
||||
namespace WebAPIConsoleTests;
|
||||
|
||||
/*!
|
||||
* \brief Implémentation de l'interface IActivityRepository pour récupérer des activités via un service HTTP.
|
||||
#1#
|
||||
public class ActivityServiceAPI : IActivityRepository
|
||||
{
|
||||
private HttpRequest<ActivityDto> myRequest = new HttpRequest<ActivityDto>();
|
||||
|
||||
/*!
|
||||
* \brief Constructeur de la classe ActivityServiceAPI.
|
||||
* Initialise l'adresse de base du client HTTP.
|
||||
#1#
|
||||
public ActivityServiceAPI()
|
||||
{
|
||||
myRequest.HttpClient.BaseAddress = new Uri("http://localhost:5030/api/v1/Activity/");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Récupère toutes les Activités de manière asynchrone.
|
||||
* \return Une tâche représentant l'opération asynchrone qui retourne une liste d'Activity.
|
||||
#1#
|
||||
public async Task<IEnumerable<Model.Activity>?> GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending = false)
|
||||
{
|
||||
var activityDtos = await myRequest.GetAllAsync();
|
||||
return activityDtos?.ToModels();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Récupère les activités par index et compte de manière asynchrone.
|
||||
* \param index L'index de départ pour la pagination.
|
||||
* \param count Le nombre d'éléments à récupérer.
|
||||
* \return Une tâche représentant l'opération asynchrone qui retourne une liste d'Activity.
|
||||
#1#
|
||||
public async Task<List<Model.Activity>> GetBooksAsync(ActivityOrderCriteria criteria, bool descending, int index, int count)
|
||||
{
|
||||
var activityDtos = await myRequest.GetAsync(criteria, descending, index, count);
|
||||
return (List<Model.Activity>)activityDtos.ToModels();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Récupère une activité par son identifiant de manière asynchrone.
|
||||
* \param id L'identifiant du livre à récupérer.
|
||||
* \return Une tâche représentant l'opération asynchrone qui retourne une liste d'Activity.
|
||||
#1#
|
||||
async Task<IEnumerable<ActivityTinyDto>?> IActivityRepository.GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<Model.Activity?> GetActivityByIdAsync(int id)
|
||||
{
|
||||
var activityDtos = await myRequest.GetByIdAsync(id);
|
||||
return activityDtos.ToModel();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Ajoute une activité de manière asynchrone.
|
||||
* \param activity L'Activity à ajouter.
|
||||
* \return Une tâche représentant l'opération asynchrone qui retourne l'activité ajouté (Activity).
|
||||
#1#
|
||||
public async Task<Model.Activity?> AddActivity(Model.Activity activity)
|
||||
{
|
||||
return (await myRequest.PostAsync(activity.ToDto())).ToModel();
|
||||
}
|
||||
|
||||
public async Task<ResponseActivityDto?> AddActivity(NewActivityDto activity)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<ResponseActivityDto?> UpdateActivity(int id, ActivityTinyDto activity)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Met à jour une activité de manière asynchrone.
|
||||
* \param id L'identifiant de l'activité à mettre à jour.
|
||||
* \param activity Les nouvelles données de l'activité à mettre à jour.
|
||||
* \return Une tâche représentant l'opération asynchrone qui retourne l'activité mis à jour (Activity).
|
||||
#1#
|
||||
public async Task<Model.Activity?> UpdateActivity(int id, Model.Activity activity)
|
||||
{
|
||||
var activityDto = activity.ToDto();
|
||||
var updatedActivityDto = await myRequest.PutAsync(id, activityDto);
|
||||
return updatedActivityDto?.ToModel();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Supprime une activité de manière asynchrone.
|
||||
* \param id L'identifiant de l'activité à supprimer.
|
||||
* \return Une tâche représentant l'opération asynchrone.
|
||||
#1#
|
||||
public async Task<bool> DeleteActivity(int id)
|
||||
{
|
||||
await myRequest.DeleteAsync(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
public Task<int> GetNbItems()
|
||||
{
|
||||
return myRequest.GetNbItems();
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Model.Activity>?> GetActivitiesByUser(int userId, int index, int count, ActivityOrderCriteria orderCriteria, bool descending = false)
|
||||
{
|
||||
return (await myRequest.GetActivitiesByUser(userId, index, count, orderCriteria, descending)).ToModels();
|
||||
}
|
||||
|
||||
public Task<int> GetNbActivitiesByUser(int userId)
|
||||
{
|
||||
return myRequest.GetNbActivitiesByUser(userId);
|
||||
}
|
||||
}*/
|
@ -0,0 +1,101 @@
|
||||
/*!
|
||||
* \file HttpRequest.cs
|
||||
* \brief Fichier contenant la classe HttpRequest.
|
||||
*/
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Net.Http.Json;
|
||||
using Dto;
|
||||
using Shared;
|
||||
|
||||
namespace WebAPIConsoleTests;
|
||||
|
||||
/*!
|
||||
* \brief Classe représentant un client HTTP pour les requêtes vers un service de gestion de elément.
|
||||
*/
|
||||
public class HttpRequest<T> where T : class
|
||||
{
|
||||
private HttpClient _httpClient { get; } = new HttpClient();
|
||||
public HttpClient HttpClient => _httpClient;
|
||||
|
||||
/*!
|
||||
* \brief Récupère tous les activitée de manière asynchrone.
|
||||
* \return Une tâche représentant l'opération asynchrone qui retourne une liste de T.
|
||||
*/
|
||||
public async Task<List<T>> GetAllAsync()
|
||||
{
|
||||
return await _httpClient.GetFromJsonAsync<List<T>>("");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Récupère les élements par index et compte de manière asynchrone.
|
||||
* \param index L'index de départ pour la pagination.
|
||||
* \param count Le nombre d'éléments à récupérer.
|
||||
* \return Une tâche représentant l'opération asynchrone qui retourne une liste de T.
|
||||
*/
|
||||
// [TODO] enum
|
||||
public async Task<List<T>> GetAsync(Enum criteria, bool descending, int index, int count)
|
||||
{
|
||||
return await _httpClient.GetFromJsonAsync<List<T>>($"?OrderingPropertyName={criteria}&Descending={descending}&Index={index}&Count={count}");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Récupère un elément par son identifiant de manière asynchrone.
|
||||
* \param id L'identifiant du elément à récupérer.
|
||||
* \return Une tâche représentant l'opération asynchrone qui retourne une liste de T.
|
||||
*/
|
||||
public async Task<T?> GetByIdAsync(int id)
|
||||
{
|
||||
return await _httpClient.GetFromJsonAsync<T>($"{id}");
|
||||
}
|
||||
|
||||
public Task<int> GetNbItems()
|
||||
{
|
||||
return _httpClient.GetFromJsonAsync<int>("count");
|
||||
}
|
||||
|
||||
public Task<IEnumerable<T>?> GetActivitiesByUser(int userId, int index, int count, ActivityOrderCriteria orderCriteria, bool descending = false)
|
||||
{
|
||||
return _httpClient.GetFromJsonAsync<IEnumerable<T>?>($"?userId={userId}&index={index}&count={count}&orderCriteria={orderCriteria}&descending={descending}");
|
||||
}
|
||||
|
||||
public Task<int> GetNbActivitiesByUser(int userId)
|
||||
{
|
||||
return _httpClient.GetFromJsonAsync<int>($"count?userId={userId}");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Ajoute une activity de manière asynchrone.
|
||||
* \param book Le elément à ajouter.
|
||||
* \return Une tâche représentant l'opération asynchrone qui retourne le activity ajouté (T).
|
||||
*/
|
||||
public async Task<T> PostAsync(T activity)
|
||||
{
|
||||
var response = await _httpClient.PostAsJsonAsync("", activity);
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<T>();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Met à jour un elément de manière asynchrone.
|
||||
* \param id L'identifiant du elément à mettre à jour.
|
||||
* \param book Les nouvelles données du elément à mettre à jour.
|
||||
* \return Une tâche représentant l'opération asynchrone qui retourne le elément mis à jour (T).
|
||||
*/
|
||||
public async Task<T> PutAsync(int id, T activity)
|
||||
{
|
||||
var response = await _httpClient.PutAsJsonAsync($"{id}", activity);
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<T>();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Supprime un elément de manière asynchrone.
|
||||
* \param id L'identifiant du elément à supprimer.
|
||||
* \return Une tâche représentant l'opération asynchrone.
|
||||
*/
|
||||
public async Task DeleteAsync(int id)
|
||||
{
|
||||
await _httpClient.DeleteAsync($"{id}");
|
||||
}
|
||||
}
|
Loading…
Reference in new issue