using System.ComponentModel.DataAnnotations;
using APIMappers;
using Dto;
using HeartTrackAPI.Request;
using HeartTrackAPI.Responce;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Model.Manager;
using Model.Repository;
using Shared;
namespace HeartTrackAPI.Controllers;
///
/// 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.
///
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class UsersController : Controller
{
private readonly ILogger _logger;
private readonly IActivityRepository _activityService;
private readonly IUserRepository _userService;
public UsersController(ILogger logger, IDataManager dataManager)
{
_logger = logger;
_userService = dataManager.UserRepo;
_activityService = dataManager.ActivityRepo;
}
///
/// Récupère une page d'utilisateurs en fonction des critères de pagination et de tri fournis.
///
/// Les critères de pagination et de tri pour les utilisateurs.
/// Une page de données utilisateur selon les critères spécifiés.
/// Retourne la page demandée d'utilisateurs.
/// La demande de pagination est invalide.
/// Erreur interne du serveur.
[HttpGet]
[ProducesResponseType(typeof(PageResponse), 200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task>> Get([FromQuery] PageRequest request)
{
try
{
var totalCount = await _userService.GetNbItems();
if (request.Count * request.Index >= totalCount)
{
_logger.LogError("To many object is asked the max is {totalCount} but the request is superior of ", totalCount);
return BadRequest("To many object is asked the max is : " + totalCount);
}
_logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(Get), null);
var athletes = await _userService.GetUsers(request.Index, request.Count, Enum.TryParse(request.OrderingPropertyName, out AthleteOrderCriteria result) ? result : AthleteOrderCriteria.None, request.Descending ?? false);
var pageResponse = new PageResponse(request.Index, request.Count, totalCount, athletes!.Select(a => a.ToDto()));
return Ok(pageResponse);
}
catch (Exception e)
{
_logger.LogError(e, "Error while getting all athletes");
return Problem();
}
}
///
/// Récupère un utilisateur spécifique par son identifiant.
///
/// L'identifiant de l'utilisateur à récupérer.
/// L'utilisateur correspondant à l'identifiant spécifié.
/// Retourne l'utilisateur demandé.
/// Aucun utilisateur trouvé pour l'identifiant spécifié.
/// Erreur interne du serveur.
[HttpGet("{id}")]
[ProducesResponseType(typeof(UserDto), 200)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task> GetById([Range(0,int.MaxValue)]int id)
{
try
{
_logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetById), id);
var athlete = await _userService.GetItemById(id);
if (athlete == null)
{
_logger.LogError("Athlete with id {id} not found", id);
return NotFound($"Athlete with id {id} not found");
}
return Ok(athlete.ToDto());
}
catch (Exception e)
{
_logger.LogError(e, "Error while getting athlete by id {id}", id);
return Problem();
}
}
///
/// Obtient le nombre total d'utilisateurs.
///
/// Le nombre total d'utilisateurs.
/// Retourne le nombre total d'utilisateurs.
/// Erreur interne du serveur.
[HttpGet("count")]
[ProducesResponseType(typeof(int), 200)]
[ProducesResponseType(500)]
public async Task> Count()
{
try
{
_logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(Count), null);
var nbUsers = await _userService.GetNbItems();
return Ok(nbUsers);
}
catch (Exception e)
{
_logger.LogError(e, "Error while getting the number of users");
return Problem();
}
}
///
/// Met à jour les informations d'un utilisateur spécifique.
///
/// L'identifiant de l'utilisateur à mettre à jour.
/// Les données de l'utilisateur pour la mise à jour.
/// L'utilisateur mis à jour.
/// Retourne l'utilisateur mis à jour.
/// Utilisateur non trouvé.
/// Erreur interne du serveur.
[HttpPut("{id}")]
[ProducesResponseType(typeof(UserDto), 200)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task> Update(int id, [FromBody] UserDto user)
{
try
{
_logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(Update), user,id);
var athlete = await _userService.GetItemById(id);
if (athlete == null)
{
_logger.LogError("Athlete with id {id} not found", id);
return NotFound($"Athlete with id {id} not found");
}
var updatedAthlete = await _userService.UpdateItem(id, user.ToModel());
if(updatedAthlete == null)
{
_logger.LogError("Error while updating athlete with id {id}", id);
return Problem();
}
return Ok(updatedAthlete.ToDto());
}
catch (Exception e)
{
_logger.LogError(e, "Error while getting the number of users");
return Problem();
}
}
///
/// Supprime un utilisateur spécifique.
///
/// L'identifiant de l'utilisateur à supprimer.
/// Action result.
/// Utilisateur supprimé avec succès.
/// Utilisateur non trouvé.
/// Erreur interne du serveur.
[HttpDelete("{id}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task Delete(int id)
{
try
{
_logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(Delete), null,id);
var athlete = await _userService.GetItemById(id);
if (athlete == null)
{
_logger.LogError("Athlete with id {id} not found", id);
return NotFound($"Athlete with id {id} not found");
}
var isDeleted = await _userService.DeleteItem(id);
if(!isDeleted)
{
_logger.LogError("Error while deleting athlete with id {id}", id);
return Problem();
}
return Ok();
}
catch (Exception e)
{
_logger.LogError(e, "Error while getting the number of users");
return Problem();
}
}
///
/// Obtient la liste des amis d'un utilisateur spécifique.
///
/// L'identifiant de l'utilisateur.
/// Les critères de pagination et de tri.
/// La liste paginée des amis.
/// Retourne la liste paginée des amis de l'utilisateur.
/// Utilisateur non trouvé.
/// Erreur interne du serveur.
[HttpGet("{id}/friends")]
[ProducesResponseType(typeof(PageResponse), 200)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task>> GetFriends(int id, [FromQuery] PageRequest request)
{
try
{
_logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(GetFriends), null,id);
var athlete = await _userService.GetItemById(id);
if (athlete == null)
{
_logger.LogError("Athlete with id {id} not found", id);
return NotFound($"Athlete with id {id} not found");
}
var totalCount = await _userService.GetNbFriends(athlete);
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(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();
}
}
///
/// Ajoute un ami à un utilisateur spécifique.
///
/// L'identifiant de l'utilisateur.
/// L'identifiant de l'ami à ajouter.
/// Action result.
/// Ami ajouté avec succès.
/// Utilisateur ou ami non trouvé.
/// Erreur interne du serveur.
[HttpPost("{id}/friend/{friendId}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task 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();
}
}
///
/// Supprime un ami d'un utilisateur spécifique.
///
/// L'identifiant de l'utilisateur.
/// L'identifiant de l'ami à supprimer.
/// Action result.
/// Ami supprimé avec succès.
/// Utilisateur ou ami non trouvé.
/// Erreur interne du serveur.
[HttpDelete("{id}/friend/{friendId}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task 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();
}
catch (Exception e)
{
_logger.LogError(e, "Error while getting the number of users");
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
///
/// Obtient la liste des athlètes d'un coach spécifique.
///
/// L'identifiant du coach.
/// Les critères de pagination et de tri.
/// La liste paginée des athlètes.
/// Retourne la liste paginée des athlètes du coach.
/// Coach non trouvé.
/// Erreur interne du serveur.
[HttpGet("{coachId}/athletes")]
[ProducesResponseType(typeof(PageResponse), 200)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task>> GetAthletes(int coachId, [FromQuery] PageRequest request)
{
try
{
_logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(GetAthletes), null,coachId);
var coach = await _userService.GetItemById(coachId);
if (coach == null)
{
_logger.LogError("Athlete with id {id} not found", coachId);
return NotFound($"Athlete with id {coachId} not found");
}
var totalCount = await _userService.GetNbFriends(coach);
if (request.Count * request.Index >= totalCount)
{
_logger.LogError("To many object is asked the max is {totalCount} but the request is superior of ", totalCount);
return BadRequest("To many object is asked the max is : " + totalCount);
}
var athletes = await _userService.GetFriends(coach, request.Index, request.Count, Enum.TryParse(request.OrderingPropertyName, out AthleteOrderCriteria result) ? result : AthleteOrderCriteria.None, request.Descending ?? false);
if (athletes == null) return NotFound();
var pageResponse = new PageResponse(request.Index, request.Count, totalCount, athletes.Select(a => a.ToDto()));
return Ok(pageResponse);
}
catch (Exception e)
{
_logger.LogError(e, "Error while getting the number of users");
return Problem();
}
}
///
/// Obtient la liste des activités d'un utilisateur spécifique.
///
/// L'identifiant de l'utilisateur.
/// Les critères de pagination et de tri.
/// La liste paginée des activités de l'utilisateur.
/// Retourne la liste paginée des activités.
/// Aucune activité trouvée.
/// Erreur interne du serveur.
[HttpGet("{userId}/activities")]
// should be tiny DTOActivity returned with only the necessary information (will be used in the list of activities of a user)
public async Task>> GetActivitiesByUser(int userId, [FromQuery] PageRequest pageRequest)
{
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(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), 200)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task> GetTrainings(int userId, [FromQuery] PageRequest request)
*/
///
/// Déconnecte l'utilisateur actuel.
///
/// Le gestionnaire de connexion.
/// Paramètre vide utilisé pour s'assurer que la requête provient bien d'un client.
/// Action result.
/// Déconnexion réussie.
/// Déconnexion non autorisée.
/// Erreur interne du serveur.
[HttpPost("logout")]
[ProducesResponseType(200)]
[ProducesResponseType(401)]
[ProducesResponseType(500)]
public async Task Logout(SignInManager signInManager, [FromBody] object? empty)
{
if (empty == null) return Unauthorized();
await signInManager.SignOutAsync();
return Ok();
}
}