using System.ComponentModel.DataAnnotations; using APIMappers; using Dto; using Dto.Tiny; using HeartTrackAPI.Request; using HeartTrackAPI.Responce; using HeartTrackAPI.Utils; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Model.Manager; 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]")] [Authorize] 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. Met None par defaut et/ou si le critère n'est pas correct /// 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.GetUsersTiny(request.Index, request.Count, Enum.TryParse(request.OrderingPropertyName, out AthleteOrderCriteria result) ? result : AthleteOrderCriteria.None, request.Descending ?? false); var pageResponse = new PageResponse(request.Index, request.Count, totalCount, athletes); return Ok(pageResponse); } catch (Exception e) { _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(ResponseUserDto), 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.GetUserById(id); if (athlete == null) { _logger.LogError("Athlete with id {id} not found", id); return NotFound($"Athlete with id {id} not found"); } return Ok(athlete); } 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}", nameof(Count)); 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(UserTinyDto), 200)] [ProducesResponseType(404)] [ProducesResponseType(500)] public async Task> Update(int id, [FromBody] UserTinyDto user) { try { _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(Update), user,id); var athlete = await _userService.GetUserTinyById(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.UpdateUser(id, user); if(updatedAthlete == null) { _logger.LogError("Error while updating athlete with id {id}", id); return Problem(); } return Ok(updatedAthlete); } 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.GetUserTinyById(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 totalCount = await _userService.GetNbFriends(id); if (request.Count * request.Index >= totalCount) { _logger.LogError("To many object is asked the max is {totalCount} but the request is superior of ", totalCount); return BadRequest("To many object is asked the max is : " + totalCount); } var friends = await _userService.GetFriends(id, request.Index, request.Count, Enum.TryParse(request.OrderingPropertyName, out AthleteOrderCriteria result) ? result : AthleteOrderCriteria.None, request.Descending ?? false); if (friends == null) return NotFound(); var pageResponse = new PageResponse(request.Index, request.Count, totalCount, friends); return Ok(pageResponse); } catch(ModelNotFoundException e) { _logger.LogError(e, "Error while adding a friend to an athlete"); return BadRequest(e.Message); } catch (Exception e) { _logger.LogError(e, "Error while getting the number of users"); 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 AddFollowing(int id, int friendId) { try { _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(AddFollowing), friendId,id); var isAdded = await _userService.AddFollowing(id, friendId); if(!isAdded) { _logger.LogError("Error while adding friend with id {friendId} to athlete with id {id}", friendId, id); return Problem(); } return Ok(); } catch(FriendShipException e) { _logger.LogError(e, "Error while adding a friend to an athlete"); return BadRequest(e.Message); } catch (Exception e) { _logger.LogError(e, "Error while attempting to follow a user"); 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 isRemoved = await _userService.RemoveFollowing(id, friendId); if(!isRemoved) { _logger.LogError("Error while removing friend with id {friendId} to athlete with id {id}", friendId, id); return Problem(); } return Ok(); } catch(FriendShipException e) { _logger.LogError(e, "Error while removing a friend to an athlete"); return BadRequest(e.Message); } catch (Exception e) { _logger.LogError(e, "Error while attempting to unfollow a user"); 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, Enum.TryParse(pageRequest.OrderingPropertyName, out ActivityOrderCriteria result) ? result : 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(); } }*/ }