Compare commits
331 Commits
WORK-WEB-A
...
master
@ -0,0 +1,188 @@
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: HeartTrack-API
|
||||
|
||||
#trigger:
|
||||
# branch:
|
||||
# - master
|
||||
# event:
|
||||
# - push
|
||||
steps:
|
||||
- name: build
|
||||
image: mcr.microsoft.com/dotnet/sdk:8.0
|
||||
commands:
|
||||
- cd src/
|
||||
- dotnet restore HeartTrack.sln
|
||||
- dotnet build HeartTrack.sln -c Release --no-restore
|
||||
- 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
|
||||
image: hub.codefirst.iut.uca.fr/marc.chevaldonne/codefirst-dronesonarplugin-dotnet8
|
||||
secrets: [ SECRET_SONAR_LOGIN ]
|
||||
settings:
|
||||
sonar_host: https://codefirst.iut.uca.fr/sonar/
|
||||
sonar_token:
|
||||
from_secret: SECRET_SONAR_LOGIN
|
||||
project_key: HeartTrack-API
|
||||
coverage_exclusions: Tests/**, StubbedContextLib/**, StubAPI/**
|
||||
duplication_exclusions: Tests/**, StubbedContextLib/**
|
||||
commands:
|
||||
- cd src/
|
||||
- dotnet restore HeartTrack.sln
|
||||
- dotnet sonarscanner begin /k:HeartTrack-API /d:sonar.host.url=$${PLUGIN_SONAR_HOST} /d:sonar.login=$${PLUGIN_SONAR_TOKEN} /d:sonar.coverage.exclusions="Tests/**, StubbedContextLib/**, StubAPI/**, HeartTrackAPI/Utils/**" /d:sonar.cpd.exclusions="Tests/**, StubbedContextLib/**, StubAPI/**" /d:sonar.coverageReportPaths="coveragereport/SonarQube.xml"
|
||||
- dotnet build HeartTrack.sln -c Release --no-restore
|
||||
- dotnet test HeartTrack.sln --logger trx --no-restore /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura --collect "XPlat Code Coverage"
|
||||
- reportgenerator -reports:"**/coverage.cobertura.xml" -reporttypes:SonarQube -targetdir:"coveragereport"
|
||||
- dotnet publish HeartTrack.sln -c Release --no-restore -o $CI_PROJECT_DIR/build/release
|
||||
- dotnet sonarscanner end /d:sonar.login=$${PLUGIN_SONAR_TOKEN}
|
||||
depends_on: [ tests ]
|
||||
|
||||
- name: swagger
|
||||
image: mcr.microsoft.com/dotnet/sdk:7.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 ]
|
||||
|
||||
volumes:
|
||||
- name: docs
|
||||
temp: {}
|
||||
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: HeartTrack-API-CD
|
||||
|
||||
trigger:
|
||||
event:
|
||||
- push
|
||||
steps:
|
||||
|
||||
- name: docker-build-and-push
|
||||
image: plugins/docker
|
||||
settings:
|
||||
dockerfile: src/HeartTrackAPI/Dockerfile
|
||||
context: src/
|
||||
registry: hub.codefirst.iut.uca.fr
|
||||
repo: hub.codefirst.iut.uca.fr/david.d_almeida/api
|
||||
username:
|
||||
from_secret: SECRET_REGISTRY_USERNAME
|
||||
password:
|
||||
from_secret: SECRET_REGISTRY_PASSWORD
|
||||
|
||||
# database container stub
|
||||
- name: deploy-container-stub
|
||||
image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dockerproxy-clientdrone:latest
|
||||
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,nicolasraymond,camillepetitalot
|
||||
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: true
|
||||
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,nicolasraymond,camillepetitalot
|
||||
|
||||
|
||||
# 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
|
||||
CONTAINERNAME: api
|
||||
CODEFIRST_CLIENTDRONE_ENV_PORT: 8080
|
||||
ADMINS: davidd_almeida,kevinmonteiro,antoineperederii,paullevrault,antoinepinagot,nicolasraymond
|
||||
COMMAND: create
|
||||
OVERWRITE: true
|
||||
depends_on: [deploy-container-mysql, docker-build-and-push, deploy-container-stub]
|
||||
|
||||
- name: deploy-container-phpmyadmin
|
||||
image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dockerproxy-clientdrone:latest
|
||||
environment:
|
||||
IMAGENAME: phpmyadmin/phpmyadmin
|
||||
CONTAINERNAME: phpmyadmin
|
||||
COMMAND: create
|
||||
OVERWRITE: true
|
||||
CODEFIRST_CLIENTDRONE_ENV_PMA_HOST: HeartDev-mysql
|
||||
CODEFIRST_CLIENTDRONE_ENV_PMA_PORT: 3306
|
||||
# CODEFIRST_CLIENTDRONE_ENV_PMA_ABSOLUTE_URI: /containers/HeartDev-phpmyadmin
|
||||
CODEFIRST_CLIENTDRONE_ENV_PMA_USER:
|
||||
from_secret: db_user
|
||||
CODEFIRST_CLIENTDRONE_ENV_PMA_PASSWORD:
|
||||
from_secret: db_password
|
||||
# CODEFIRST_CLIENTDRONE_ENV_PMA_ABSOLUTE_URI: /phpmyadmin
|
||||
ADMINS: davidd_almeida,kevinmonteiro,antoineperederii,paullevrault,antoinepinagot,nicolasraymond
|
||||
depends_on: [deploy-container-mysql]
|
@ -1,3 +1,167 @@
|
||||
# EF_WebAPI
|
||||
<div align = center>
|
||||
|
||||
This repository make a meeting of EF and WebAPI parts.
|
||||
<h1>HeartTrack</h1>
|
||||
<img src="docs/images/logo.png" />
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div align = center>
|
||||
|
||||
|
||||
|
||||
---
|
||||

|
||||

|
||||

|
||||
|
||||
</br>
|
||||
|
||||
[](https://codefirst.iut.uca.fr/HeartDev/API)
|
||||
[](https://codefirst.iut.uca.fr/sonar/dashboard?id=HeartTrack-API)
|
||||
[](https://codefirst.iut.uca.fr/sonar/dashboard?id=HeartTrack-API)
|
||||
[](https://codefirst.iut.uca.fr/sonar/dashboard?id=HeartTrack-API)
|
||||
[](https://codefirst.iut.uca.fr/sonar/dashboard?id=HeartTrack-API)
|
||||
[](https://codefirst.iut.uca.fr/sonar/dashboard?id=HeartTrack-API)
|
||||
[](https://codefirst.iut.uca.fr/sonar/dashboard?id=HeartTrack-API)
|
||||
[](https://codefirst.iut.uca.fr/sonar/dashboard?id=HeartTrack-API)
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
# Table des matières
|
||||
[Présentation](#présentation) | [Répartition du Git](#répartition-du-git) | [Documentation](#documentation) | [Prerequisites](#prerequisites) | [Getting Started](#getting-started) | [Features](#features) | [Ce que nous avons fait](#ce-que-nous-avons-fait) | [Fabriqué avec](#fabriqué-avec) | [Contributeurs](#contributeurs) | [Comment contribuer](#comment-contribuer) | [License](#license) | [Remerciements](#remerciements)
|
||||
|
||||
|
||||
|
||||
## Présentation
|
||||
|
||||
**Nom de l'application :** HeartTrack
|
||||
|
||||
### Contexte
|
||||
|
||||
HeartTrack est une application web PHP et mobile Android destinée aux sportifs et aux coachs afin de permettre l'analyse de courbes de fréquences cardiaques et le suivi d'équipe sportive. L'objectif principal de cette application est de récupérer les données de fréquence cardiaque à partir de fichiers .FIT, de les afficher sous forme de courbes, d'identifier des paternes, de fournir des statistiques et de réaliser des prédictions liées à l'effort physique, à la chaleur, à la récupération, etc.
|
||||
!! Fuseaux horaires de base
|
||||
|
||||
### Récapitulatif du Projet
|
||||
|
||||
Le projet HeartTrack, avec son application HeartTrack, vise à offrir une solution Open Source d'analyse des données de fréquence cardiaque, en mettant l'accent sur les besoins des sportifs et des coachs. L'application sera capable de traiter et d'interpréter les données de manière intelligente, fournissant ainsi des informations précieuses pour optimiser les performances sportives et la santé.
|
||||
|
||||
|
||||
## Répartition du Git
|
||||
|
||||
[**Sources**](Sources/) : **Code de l'application**
|
||||
|
||||
[**Documents**](docs/Diagramme/README_DIAGRAMMES.md) : **Documentation de l'application et diagrammes**
|
||||
|
||||
[**Wiki**](https://codefirst.iut.uca.fr/git/HeartDev/Web/wiki/PHP) : **Wiki de notre projet (attendus PHP)**
|
||||
|
||||
---
|
||||
|
||||
Le projet HeartTrack utilise un modèle de flux de travail Git (Gitflow) pour organiser le développement. Voici une brève explication des principales branches :
|
||||
|
||||
- **branche WORK-** : Cette branche est utilisée pour le développement de nouvelles fonctionnalités. Chaque fonctionnalité est développée dans une branche séparée. WORK-NOMDUDEV permet de savoir qui travaille sur quoi.
|
||||
|
||||
- **branche master** : Cette branch est la dernière version stable de l'application. Les modifications sur cette branche sont généralement destinées à des mises en production.
|
||||
|
||||
- **branche test** : Cette branche est utilisée pour tester les différentes fonctionnalités avant de les fusionner.
|
||||
|
||||
- **branche merge** : Cette branche est utilisée pour fusionner les différentes branches de fonctionnalités.
|
||||
|
||||
|
||||
## Documentation
|
||||
Documentation et informations à propos de `HearthTrack` disponible [ici](https://codefirst.iut.uca.fr/documentation/HeartDev/API/doxygen/)
|
||||
|
||||
### Prerequisites
|
||||
* [](https://dotnet.microsoft.com/download/dotnet/8.0)
|
||||
* [](https://docs.microsoft.com/fr-fr/ef/)
|
||||
* [](https://docs.microsoft.com/fr-fr/aspnet/core/web-api/?view=aspnetcore-8.0)
|
||||
* [](https://visualstudio.microsoft.com/fr/)
|
||||
* [](https://git-scm.com/)
|
||||
|
||||
## Getting Started
|
||||
|
||||
## Ce que nous avons fait
|
||||
### Entity Framework
|
||||
réalisé | niveau | description | coeff | jalon
|
||||
--- | --- | --- | --- | ---
|
||||
✅ | ☢️ | Le dépôt doit être accessible par l'enseignant | ☢️ | J1
|
||||
✅ | ☢️ | un .gitignore doit exister au premier push | ☢️ | J1
|
||||
✅ | 🎬 | les *projets* et les tests compilent | 1 | J1 & J2
|
||||
✅ | 🎬 | le projet et le tests s'exécutent sans bug (concernant la partie persistance) | 3 | J1 & J2
|
||||
✅ | 🟢 | Transcription du modèle : Modèle vers entités (et inversement) | 2 | J1
|
||||
✅ | 🟢 | Requêtes CRUD simples (sur une table) | 1 | J1
|
||||
✅ | 🟢 | Utilisation de LINQ to Entities | 2 | J1
|
||||
✅ | 🟡 | Injection / indépendance du fournisseur | 1 | J1
|
||||
✅ | 🟡 | Requêtes CRUD sur des données complexes (images par exemple) | 2 | J1
|
||||
✅ | 🟢 | Tests - Appli Console | 1 | J1
|
||||
✅ | 🟢 | Tests - Tests unitaires (avec SQLite in memory) | 2 | J1
|
||||
✅ | 🟢 | Tests - Données stubbées et/ou Moq | 1 | J1
|
||||
✅ | 🟡 | CI : build, tests, Sonar (doc?) | 1 | J1
|
||||
✅ | 🟡 | Utilisation de relations (One-to-One, One-to-Many, Many-to-Many) (+ mapping, TU, Requêtes) | 4 | J1
|
||||
✅ | 🟢 | Liens avec le web service | 2 | J1
|
||||
✅ | 🟡 | Utilisation d'un *Logger* | 1 | J1
|
||||
✅ | 🟡 | Déploiement | 4 | J2
|
||||
✅ | 🔴 | Unit of Work / Repository + extras (héritage, accès concurrents...) | 8 | J2
|
||||
✅ | 🟢 | Utilisation dans le projet | 2 | J2
|
||||
✅ | 🟢 | mon dépôt possède un readme qui apporte quelque chose... | 2 | J2
|
||||
|
||||
### API
|
||||
réalisé | niveau | description | coeff | jalon
|
||||
--- | --- | --- | --- | ---
|
||||
✅ | ☢️ | Le dépôt doit être accessible par l'enseignant | ☢️ | J1
|
||||
✅ | ☢️ | un .gitignore doit exister au premier push | ☢️ | J1
|
||||
✅ | 🎬 | les *projets* et les tests compilent | 1 | J1 & J2
|
||||
✅ | 🎬 | le projet et le tests s'exécutent sans bug (concernant la partie persistance) | 4 | J1 & J2
|
||||
✅ | 🟢 | Modèle <-> DTO | 1 | J1
|
||||
✅ | 🟢 | Entities <-> DTO | 1 | J1
|
||||
✅ | 🟡 | Authentification | 4 | J1
|
||||
✅ | 🟢 | Requêtes GET, PUT, POST, DELETE sur des données simples (1 seul type d'objet en retour, propriétés de types natifs) | 2 | J1
|
||||
✅ | 🟡 | Pagination & filtrage | 2 | J1
|
||||
✅ | 🟢 | Injection de service | 2 | J1
|
||||
✅ | 🟡 | Requêtes GET, PUT, POST, DELETE sur des données complexes (plusieurs données complexes en retour) | 4 | J1
|
||||
✅ | 🟢 | Tests - Appli Console (consommation des requêtes) | 4 | J1
|
||||
✅ | 🟢 | Tests - Tests unitaires (avec Stub et/ou Moq) | 2 | J1
|
||||
✅ | 🟡 | CI : build, tests, Sonar, Documentation (en particulier Swagger avec exemples...) | 1 | J1
|
||||
✅ | 🟢 | Liens avec la persistance en base de données | 4 | J1
|
||||
✅ | 🟡 | Utilisation d'un *Logger* | 1 | J1
|
||||
✅ | 🟡 | Déploiement | 4 | J2
|
||||
✅ | 🟡 | Utilisation dans le projet | 4 | J2
|
||||
✅ | 🎬 | mon dépôt possède un readme qui apporte quelque chose... | 1 | J2
|
||||
|
||||
## Fabriqué avec
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
|
||||
|
||||
## Contributeurs
|
||||
* [Antoine PEREDERII](https://codefirst.iut.uca.fr/git/antoine.perederii)
|
||||
* [Paul LEVRAULT](https://codefirst.iut.uca.fr/git/paul.levrault)
|
||||
* [Kevin MONTEIRO](https://codefirst.iut.uca.fr/git/kevin.monteiro)
|
||||
* [Antoine PINAGOT](https://codefirst.iut.uca.fr/git/antoine.pinagot)
|
||||
* [David D'HALMEIDA](https://codefirst.iut.uca.fr/git/david.d_almeida)
|
||||
|
||||
## Comment contribuer
|
||||
1. Forkez le projet (<https://codefirst.iut.uca.fr/git/HeartDev/API>)
|
||||
2. Créez votre branche (`git checkout -b feature/featureName`)
|
||||
3. commit vos changements (`git commit -am 'Add some feature'`)
|
||||
4. Push sur la branche (`git push origin feature/featureName`)
|
||||
5. Créez une nouvelle Pull Request
|
||||
|
||||
|
||||
## License
|
||||
Ce projet est sous licence ``MIT`` - voir le fichier [LICENSE.md](LICENSE.md) pour plus d'informations.
|
||||
|
||||
## Remerciements
|
||||
Ce projet a été réalisé dans le cadre de la SAÉ de l'IUT de Clermont-Ferrand.
|
@ -0,0 +1,113 @@
|
||||
@startuml
|
||||
skinparam classAttributeIconSize 0
|
||||
package MLD{
|
||||
entity "Athlète" as athlete {
|
||||
{static} idAthlete
|
||||
nom
|
||||
prénom
|
||||
email
|
||||
sexe
|
||||
taille
|
||||
poids
|
||||
motDePasse
|
||||
dateNaissance
|
||||
}
|
||||
|
||||
entity "Amitié" as friendship{
|
||||
{static}# idAthlete1
|
||||
{static}# idAthlete2
|
||||
début
|
||||
}
|
||||
|
||||
entity "Notification" as notif {
|
||||
{static} idNotif
|
||||
message
|
||||
date
|
||||
statut
|
||||
urgence
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "Coach" as coach {
|
||||
{static} idCoach
|
||||
// attributs spécifiques au coach
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "Statistique" as stats {
|
||||
{static} idStatistique
|
||||
poids
|
||||
fcMoyenne
|
||||
fcMax
|
||||
caloriesBrûléesMoy
|
||||
date
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "Entraînement" as training {
|
||||
{static} idEntrainement
|
||||
date
|
||||
description
|
||||
// Exercices
|
||||
latitude
|
||||
longitude
|
||||
feedback
|
||||
#coachId
|
||||
}
|
||||
|
||||
entity "Participe" as takepart {
|
||||
{static} #athleteId
|
||||
{static} #entrainementId
|
||||
}
|
||||
|
||||
|
||||
entity "SourceDonnée" as source {
|
||||
{static} idSource
|
||||
type
|
||||
modèle
|
||||
précision
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "Activité" as activity {
|
||||
{static} idActivité
|
||||
type
|
||||
date
|
||||
heureDeDébut
|
||||
heureDeFin
|
||||
effortRessent
|
||||
variabilité
|
||||
variance
|
||||
ecartType
|
||||
moyenne
|
||||
maximum
|
||||
minimum
|
||||
temperatureMoyenne
|
||||
#athleteId
|
||||
#sourceId
|
||||
}
|
||||
entity "FréquenceCardiaque" as fc {
|
||||
{static} idFc
|
||||
altitude
|
||||
temps : time
|
||||
température
|
||||
bpm
|
||||
longitude
|
||||
latitude
|
||||
#activitéId
|
||||
}
|
||||
|
||||
}
|
||||
activity --> athlete
|
||||
activity --> source
|
||||
activity <-- fc
|
||||
coach --> athlete
|
||||
athlete <-- source
|
||||
stats --> athlete
|
||||
takepart --> athlete
|
||||
takepart --> training
|
||||
friendship --> athlete
|
||||
notif --> athlete
|
||||
coach <-- training
|
||||
athlete <-- friendship
|
||||
@enduml
|
@ -0,0 +1,275 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# BDD
|
||||
|
||||
## Modèle Logique de Données (MLD)
|
||||
|
||||
Le MLD représente la structure de données de l'application, décrivant les entités et les relations entre elles. Voici un aperçu des principales entités du MLD :
|
||||
|
||||
### Athlète (Athlete)
|
||||
|
||||
L'entité principale représentant un athlète avec ces informations propre à lui telles que l'identifiant, le nom, le prénom, l'email, etc. Les athlètes peuvent être coach avec le boolean idCoach et être liés par des amitiés, ou par un coaching via la table `Amitie`.
|
||||
|
||||
### Amitié (Friendship)
|
||||
|
||||
Une entité qui modélise les relations d'amitié entre les athlètes et de coaching entre les athlètes et les coachs. Elle stocke les identifiants des deux utilisateurs impliqués.
|
||||
|
||||
### Notification (Notification)
|
||||
|
||||
L'entité qui stocke les notifications destinées aux athlètes, avec des détails tels que le message, la date, le statut, et le degré d'urgence.
|
||||
|
||||
### Envoi de Notification (SendNotification)
|
||||
|
||||
Une entité de liaison entre les athlètes et les notifications, indiquant quel athlète ou coach a envoyé quelle notification. Cela peut-être utile lors d'une notification d'ajout d'amie par exemple.
|
||||
|
||||
### Statistique (Statistic)
|
||||
|
||||
Les statistiques relatives à un athlètes, y compris le poids, la fréquence cardiaque moyenne, la fréquence cardiaque maximale, etc.
|
||||
|
||||
### Entraînement (Training)
|
||||
|
||||
Détails sur les sessions d'entraînement planifiés par un coach pour ses athlètes, comprenant la date, la description, la localisation, etc. Les athlètes peuvent participer à des entraînements et donner leur feedback sur l'entrainement donné.
|
||||
|
||||
### Participation (Participate)
|
||||
|
||||
Une entité de liaison entre les athlètes et les entraînements, indiquant quels athlètes participent à quels entraînements.
|
||||
|
||||
### Don (GiveParticipation)
|
||||
|
||||
Une entité de liaison entre les coachs et les entraînements, indiquant quels coachs ont attribué quels entraînements.
|
||||
|
||||
### Source de Données (DataSource)
|
||||
|
||||
L'entité représentant la source des données des enregistrements sportif, telle que le type, le modèle, la précision, etc., utilisée par les athlètes pour enregistrer une ou des activités.
|
||||
|
||||
### Activité (Activity)
|
||||
|
||||
Les détails des activités des athlètes, y compris le type, la date, les heures de début et de fin, l'effort ressenti, etc.
|
||||
|
||||
### Fréquence Cardiaque (HeartRate)
|
||||
|
||||
Les données de fréquence cardiaque enregistrées pendant les activités, avec des informations telles que l'altitude, la température, etc.
|
||||
|
||||
Ce MLD forme la base de données sous-jacente pour l'application, offrant une structure organisée pour stocker et récupérer les informations relatives aux athlètes et à leurs activités.
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
skinparam classAttributeIconSize 0
|
||||
package MLD{
|
||||
entity "Athlete" as athlete {
|
||||
{static} idAthlete
|
||||
username
|
||||
nom
|
||||
prenom
|
||||
email
|
||||
sexe
|
||||
taille
|
||||
poids
|
||||
motDePasse
|
||||
dateNaissance
|
||||
isCoach
|
||||
}
|
||||
|
||||
entity "Amitie" as friendship{
|
||||
{static}# idAthlete1
|
||||
{static}# idAthlete2
|
||||
début
|
||||
}
|
||||
|
||||
entity "Notification" as notif {
|
||||
{static} idNotif
|
||||
message
|
||||
date
|
||||
statut
|
||||
urgence
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "Envoi" as sendNotif{
|
||||
{static}# idAthlete
|
||||
{static}# idNotif
|
||||
}
|
||||
|
||||
entity "Statistique" as stats {
|
||||
{static} idStatistique
|
||||
poids
|
||||
fcMoyenne
|
||||
fcMax
|
||||
caloriesBruleesMoy
|
||||
date
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "Entrainement" as training {
|
||||
{static} idEntrainement
|
||||
date
|
||||
description
|
||||
latitude
|
||||
longitude
|
||||
feedback
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "Participe" as takepart {
|
||||
{static} #athleteId
|
||||
{static} #entrainementId
|
||||
}
|
||||
|
||||
entity "Donne" as givepart {
|
||||
{static} #coachId
|
||||
{static} #entrainementId
|
||||
}
|
||||
|
||||
|
||||
entity "SourceDonnee" as source {
|
||||
{static} idSource
|
||||
type
|
||||
modele
|
||||
precision
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "Activite" as activity {
|
||||
{static} idActivité
|
||||
type
|
||||
date
|
||||
heureDeDebut
|
||||
heureDeFin
|
||||
effortRessent
|
||||
variabilite
|
||||
variance
|
||||
ecartType
|
||||
moyenne
|
||||
maximum
|
||||
minimum
|
||||
temperatureMoyenne
|
||||
#athleteId
|
||||
#sourceId
|
||||
}
|
||||
entity "FréquenceCardiaque" as fc {
|
||||
{static} idFc
|
||||
altitude
|
||||
temps : time
|
||||
température
|
||||
bpm
|
||||
longitude
|
||||
latitude
|
||||
#activitéId
|
||||
}
|
||||
|
||||
}
|
||||
activity --> athlete
|
||||
activity --> source
|
||||
activity <-- fc
|
||||
athlete <-- source
|
||||
stats --> athlete
|
||||
takepart --> athlete
|
||||
takepart --> training
|
||||
givepart --> athlete
|
||||
givepart --> training
|
||||
sendNotif --> athlete
|
||||
sendNotif --> notif
|
||||
friendship --> athlete
|
||||
notif --> athlete
|
||||
athlete <-- friendship
|
||||
@enduml
|
||||
```
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
skinparam classAttributeIconSize 0
|
||||
package MCD{
|
||||
entity "Athlete" as athlete {
|
||||
{static} idAthlete
|
||||
username
|
||||
nom
|
||||
prenom
|
||||
email
|
||||
sexe
|
||||
taille
|
||||
poids
|
||||
motDePasse
|
||||
dateNaissance
|
||||
isCoach
|
||||
}
|
||||
|
||||
entity "Notification" as notif {
|
||||
{static} idNotif
|
||||
message
|
||||
date
|
||||
statut
|
||||
urgence
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "Statistique" as stats {
|
||||
{static} idStatistique
|
||||
poids
|
||||
fcMoyenne
|
||||
fcMax
|
||||
caloriesBruleesMoy
|
||||
date
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "Entrainement" as training {
|
||||
{static} idEntrainement
|
||||
date
|
||||
description
|
||||
latitude
|
||||
longitude
|
||||
feedback
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "SourceDonnee" as source {
|
||||
{static} idSource
|
||||
type
|
||||
modele
|
||||
precision
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "Activite" as activity {
|
||||
{static} idActivité
|
||||
type
|
||||
date
|
||||
heureDeDebut
|
||||
heureDeFin
|
||||
effortRessent
|
||||
variabilite
|
||||
variance
|
||||
ecartType
|
||||
moyenne
|
||||
maximum
|
||||
minimum
|
||||
temperatureMoyenne
|
||||
#athleteId
|
||||
#sourceId
|
||||
}
|
||||
|
||||
entity "FréquenceCardiaque" as fc {
|
||||
{static} idFc
|
||||
altitude
|
||||
temps : time
|
||||
température
|
||||
bpm
|
||||
longitude
|
||||
latitude
|
||||
#activitéId
|
||||
}
|
||||
|
||||
}
|
||||
activity "0..n" --- "1..1" athlete : réalise
|
||||
activity "1..n" --- "1..1" source : possede
|
||||
activity "1..1" --- "1..n" fc : enregistre
|
||||
athlete "1..n" --- "0..1" source : possede
|
||||
stats "0..n" --- "1..1" athlete : possede
|
||||
training "0..n" --- "1..n" athlete : participe
|
||||
training "0..n" --- "1..1" athlete : donne
|
||||
athlete "0..n" --- "1..n" athlete : est ami
|
||||
notif "0..n" --- "1..n" athlete : recoit
|
||||
notif "0..n" --- "1..1" athlete : envoie
|
||||
@enduml
|
||||
```
|
@ -0,0 +1,55 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# Introduction au Cas d'utilisation : Suivi d'une Équipe Sportive
|
||||
|
||||
Bienvenue dans le monde dynamique du suivi d'équipe sportive, où notre application offre une plateforme complète pour les entraîneurs soucieux d'optimiser les performances de leurs athlètes. Ce diagramme de cas d'utilisation vous plonge dans les fonctionnalités clés qui facilitent la gestion d'une équipe sportive avec efficacité.
|
||||
|
||||
**Acteurs Principaux :**
|
||||
|
||||
- **Coach :** Le protagoniste central, utilisant l'application pour gérer et superviser son équipe.
|
||||
|
||||
**Fonctionnalités Clés :**
|
||||
|
||||
- **Ajouter un Athlète :** Permet au coach d'ajouter de nouveaux membres à son équipe, avec des étapes incluant la validation par l'athlète et l'authentification.
|
||||
|
||||
- **Supprimer un Athlète :** Offre la possibilité de retirer des athlètes de l'équipe, avec une authentification préalable pour garantir la légitimité de l'action.
|
||||
|
||||
- **Afficher ses Athlètes :** Permet au coach de visualiser la liste complète de ses athlètes, nécessitant une authentification pour accéder à ces informations sensibles.
|
||||
|
||||
- **Afficher les Activités de Tous les Athlètes :** Donne au coach un aperçu global des activités de toute l'équipe, nécessitant une authentification pour garantir la confidentialité des données.
|
||||
|
||||
**Flux d'Interaction :**
|
||||
|
||||
- Le processus d'ajout d'un athlète inclut des étapes telles que la validation par l'athlète et l'authentification, garantissant une intégration fluide.
|
||||
|
||||
- Les actions de suppression, affichage des athlètes et affichage des activités nécessitent une authentification préalable pour assurer la sécurité des données.
|
||||
|
||||
- Des extensions telles que la visualisation des activités d'un athlète et l'analyse des performances offrent des fonctionnalités avancées pour un suivi détaillé.
|
||||
|
||||
Explorez ce diagramme pour comprendre l'étendue des fonctionnalités que notre application offre aux entraîneurs, les aidant à gérer leurs équipes de manière efficace et à maximiser le potentiel de chaque athlète.
|
||||
|
||||
```plantuml
|
||||
left to right direction
|
||||
:Coach: as a
|
||||
|
||||
a --> (Ajouter un athlète)
|
||||
a --> (Supprimer un athlète)
|
||||
a --> (Afficher ses athlètes )
|
||||
a --> (Afficher les activités de tous les athlètes)
|
||||
(Ajouter un athlète).>(Validation par l'athlète) : <<include>>
|
||||
(Ajouter un athlète)..>(S'authentifier) : <<include>>
|
||||
(Supprimer un athlète)..>(S'authentifier) : <<include>>
|
||||
(Afficher ses athlètes )..>(S'authentifier) : <<include>>
|
||||
(Afficher les activités de tous les athlètes)..>(S'authentifier) : <<include>>
|
||||
(S'authentifier)..>(S'inscrire) : <<extends>>
|
||||
(S'inscrire).>(Inscription Coach) : <<include>>
|
||||
(S'authentifier)..>(Se connecter) : <<include>>
|
||||
(Afficher ses athlètes )..>(Voir les activités d'un athlète) : <<extends>>
|
||||
(Afficher ses athlètes )..>(Voir les stats d'un athlète) : <<extends>>
|
||||
(Afficher les activités de tous les athlètes)..>(Sélectionner une activité) : <<include>>
|
||||
(Sélectionner une activité)..>(Voir l'analyse) : <<extends>>
|
||||
(Sélectionner une activité)..>(Exporter l'analyse) : <<extends>>
|
||||
(Voir les activités d'un athlète)..>(Voir l'analyse) : <<extends>>
|
||||
(Voir les activités d'un athlète)..>(Exporter l'analyse) : <<extends>>
|
||||
```
|
@ -0,0 +1,57 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# Introduction au Cas d'utilisation : Gestion d'Activités pour un Athlète
|
||||
|
||||
Bienvenue dans l'univers dédié à la gestion d'activités sportives personnalisées pour les athlètes ! Ce diagramme de cas d'utilisation explore les différentes fonctionnalités offertes aux utilisateurs, mettant en avant la flexibilité et la richesse d'interactions pour une expérience utilisateur optimale.
|
||||
|
||||
**Acteurs Principaux :**
|
||||
|
||||
- **Athlète :** Le protagoniste central, utilisant l'application pour importer, gérer et analyser ses activités sportives.
|
||||
|
||||
**Fonctionnalités Clés :**
|
||||
|
||||
- **Importer des Données :** Permet à l'athlète d'importer des données d'activités depuis différentes sources, avec la possibilité de spécifier la source pour une intégration transparente.
|
||||
|
||||
- **Exporter Mes Données :** Offre la possibilité d'exporter l'ensemble des activités, avec des extensions pour exporter une activité spécifique, le tout soumis à une authentification préalable.
|
||||
|
||||
- **Ajouter une Activité :** Permet à l'athlète d'ajouter de nouvelles activités, avec des étapes inclusives telles que la saisie du titre, du type d'activité, de la source, du matériel utilisé et de la visibilité, chacune accessible via l'authentification.
|
||||
|
||||
- **Voir une Activité :** Permet à l'athlète de visualiser en détail une activité particulière, avec la possibilité d'exporter une analyse et de gérer la visibilité, soumis à une authentification.
|
||||
|
||||
- **Supprimer une Activité :** Offre la possibilité de retirer une activité, requérant une authentification pour garantir la sécurité des données.
|
||||
|
||||
**Flux d'Interaction :**
|
||||
|
||||
- Les actions telles que l'importation, l'exportation, l'ajout et la visualisation d'activités impliquent une authentification préalable pour garantir la confidentialité des données personnelles.
|
||||
|
||||
- Des inclusions précises, telles que la saisie du titre, du type d'activité, de la source, du matériel utilisé et de la visibilité, sont incorporées dans le processus d'ajout d'une activité, offrant une expérience utilisateur détaillée et conviviale.
|
||||
|
||||
Explorez ce diagramme pour comprendre la manière dont notre application place la gestion d'activités entre les mains des athlètes, les encourageant à suivre, analyser et optimiser leurs performances sportives de manière personnalisée et efficace.
|
||||
|
||||
|
||||
```plantuml
|
||||
left to right direction
|
||||
:Athlete: as a
|
||||
|
||||
a --> (Importer des données)
|
||||
(Importer des données) .> (Saisir la source) : <<include>>
|
||||
a --> (Exporter mes données)
|
||||
(Exporter mes données) .>(Exporter toutes les activités): <<extends>>
|
||||
(Exporter mes données) ..>(Exporter une activité): <<include>>
|
||||
a --> (Ajouter une activité)
|
||||
(Ajouter une activité) ..>(Saisir un titre et une description): <<include>>
|
||||
(Ajouter une activité) ..>(Saisir le type d'activité): <<include>>
|
||||
(Ajouter une activité) .>(Saisir la source): <<include>>
|
||||
(Saisir la source) ..>(Saisir le matériel utilisé): <<include>>
|
||||
(Ajouter une activité) ..>(Saisir la visibilité): <<include>>
|
||||
a --> (Voir une activité)
|
||||
(Voir une activité) ..>(Exporter l'analyse): <<extends>>
|
||||
(Voir une activité) ..>(Saisir la visibilité): <<extends>>
|
||||
a --> (Supprimer une activité)
|
||||
(Supprimer une activité) ..>(S'authentifier): <<include>>
|
||||
(Importer des données) ...>(S'authentifier): <<include>>
|
||||
(Exporter mes données) ...>(S'authentifier): <<include>>
|
||||
(Ajouter une activité) ...>(S'authentifier): <<include>>
|
||||
(Voir une activité) ...>(S'authentifier): <<include>>
|
||||
```
|
@ -0,0 +1,55 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# Introduction au Cas d'utilisation : Gestion des Relations Sociales pour un Athlète
|
||||
|
||||
Bienvenue dans la sphère sociale de notre application dédiée aux athlètes ! Ce diagramme de cas d'utilisation explore les fonctionnalités sociales clés offertes aux utilisateurs, mettant en lumière la connectivité et l'interaction sociale au sein de notre communauté sportive.
|
||||
|
||||
**Acteurs Principaux :**
|
||||
|
||||
- **Athlète :** Le protagoniste central, utilisant l'application pour gérer ses relations sociales et explorer les profils de ses pairs.
|
||||
|
||||
**Fonctionnalités Clés :**
|
||||
|
||||
- **Ajouter un Ami :** Permet à l'athlète d'ajouter de nouveaux amis, nécessitant la saisie du nom de l'ami et soumis à une authentification préalable.
|
||||
|
||||
- **Supprimer un Ami :** Offre la possibilité de retirer un ami, exigeant une authentification pour garantir la sécurité des données.
|
||||
|
||||
- **Voir Mes Amis :** Permet à l'athlète de visualiser la liste de ses amis, avec la possibilité d'accéder à des fonctionnalités supplémentaires comme la visualisation des profils.
|
||||
|
||||
- **Modifier Mes Informations :** Offre à l'athlète la possibilité de mettre à jour ses informations personnelles et de connexion, avec des extensions pour des détails plus spécifiques.
|
||||
|
||||
**Flux d'Interaction :**
|
||||
|
||||
- Le processus d'ajout d'un ami inclut la saisie du nom de l'ami, tandis que la suppression d'un ami et la visualisation de la liste des amis sont soumises à une authentification préalable pour protéger la confidentialité.
|
||||
|
||||
- Les modifications d'informations englobent deux extensions : la mise à jour des informations personnelles et la mise à jour des informations de connexion, offrant une personnalisation approfondie du profil athlétique.
|
||||
|
||||
- La visualisation du profil d'un ami s'étend à des fonctionnalités telles que la consultation des activités et des statistiques de l'ami, ajoutant une dimension sociale à l'expérience de suivi sportif.
|
||||
|
||||
Explorez ce diagramme pour découvrir comment notre application encourage l'interaction sociale entre les athlètes, favorisant une communauté engagée et collaborative au sein de laquelle les utilisateurs peuvent partager, interagir et se soutenir mutuellement dans leur parcours sportif.
|
||||
|
||||
|
||||
```plantuml
|
||||
left to right direction
|
||||
:Athlete: as a
|
||||
|
||||
a --> (Ajouter un ami)
|
||||
a --> (Supprimer un ami)
|
||||
a --> (Voir mes amis)
|
||||
a --> (Modifier mes informations)
|
||||
(Ajouter un ami)->(Saisir le nom de l'ami)
|
||||
(Supprimer un ami)..>(S'authentifier) : <<include>>
|
||||
(Ajouter un ami)..>(S'authentifier) : <<include>>
|
||||
(Voir mes amis)..>(S'authentifier) : <<include>>
|
||||
(Voir mes amis)..>(Lister les amis) : <<include>>
|
||||
(Modifier mes informations)..>(Informations personnelles) : <<extends>>
|
||||
(Modifier mes informations)..>(Informations de connexion) : <<extends>>
|
||||
(Modifier mes informations)..>(S'authentifier) : <<include>>
|
||||
(Lister les amis)..>(Voir son profil) : <<include>>
|
||||
(Voir son profil)..>(Voir ses activités) : <<extends>>
|
||||
(Voir son profil)..>(Voir ses statistiques) : <<extends>>
|
||||
(S'authentifier)..>(S'inscrire) : <<extends>>
|
||||
(S'authentifier)..>(Se connecter) : <<include>>
|
||||
(S'inscrire)..>(Inscription Athlète) : <<include>>
|
||||
```
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,202 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# Introduction au Diagramme de Classes : Plateforme de Gestion d'Activités Sportives
|
||||
|
||||
Bienvenue dans l'écosystème dynamique de notre plateforme de gestion d'activités sportives ! Ce diagramme de classes offre une vision complète des entités et des relations qui façonnent l'expérience des utilisateurs au sein de notre système.
|
||||
|
||||
**Entités Principales :**
|
||||
|
||||
- **Utilisateur (User) :** Représente les individus inscrits sur notre plateforme, avec des détails personnels tels que le nom, le prénom, l'email, etc. Chaque utilisateur a un rôle spécifique (Athlete, Coach) qui détermine ses interactions au sein de l'application.
|
||||
|
||||
- **Rôle (Role) :** Classe abstraite qui définit les rôles spécifiques des utilisateurs (Athlete, Coach). Contient des méthodes pour gérer les amis, les entraînements, et les demandes.
|
||||
|
||||
- **Athlète (Athlete) :** Spécialisation de la classe Role, représentant les utilisateurs actifs qui enregistrent des activités sportives, des statistiques, et interagissent avec d'autres athlètes.
|
||||
|
||||
- **Activité (Activite) :** Contient des détails sur une activité sportive tels que le type, la date, la durée, la fréquence cardiaque, etc.
|
||||
|
||||
- **Notification (Notification) :** Messages pour informer les utilisateurs des actions importantes.
|
||||
|
||||
- **Entraînement (Entrainement) :** Sessions planifiées d'activités physiques avec des détails comme la date, la localisation, la description, et les retours.
|
||||
|
||||
- **Statistique (Statistique) :** Informations détaillées sur les performances sportives d'un athlète, comprenant la distance totale, le poids, le temps total, la fréquence cardiaque, etc.
|
||||
|
||||
- **Source de Données (SourceDonnees) :** Représente les sources utilisées pour collecter des données, telles que les montres connectées.
|
||||
|
||||
**Relations Clés :**
|
||||
|
||||
- Les Utilisateurs ont un rôle spécifique (Athlete, Coach) qui détermine leurs fonctionnalités.
|
||||
|
||||
- Un Athlète peut enregistrer plusieurs Activités, Statistiques, et interagir avec différentes Sources de Données.
|
||||
|
||||
- Les Entraînements sont liés aux Utilisateurs, permettant une planification efficace.
|
||||
|
||||
- Les Notifications informent les Utilisateurs des événements importants.
|
||||
|
||||
Explorez ce diagramme pour comprendre comment notre plateforme offre une expérience complète, de la gestion des utilisateurs à l'enregistrement des activités sportives et au suivi des performances.
|
||||
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
class User {
|
||||
- id: int
|
||||
- username: String
|
||||
- nom: string
|
||||
- prenom: string
|
||||
- email: string
|
||||
- motDePasse: string
|
||||
- sexe: string
|
||||
- taille: float
|
||||
- poids: float
|
||||
- dateNaissance: \DateTime
|
||||
+ getId(): int
|
||||
+ getUsername(): string
|
||||
+ setUsername(string $username): void
|
||||
+ setId(int $id): void
|
||||
+ getNom(): string
|
||||
+ setNom(string $nom): void
|
||||
+ getPrenom(): string
|
||||
+ setPrenom(string $prenom): void
|
||||
+ getEmail(): string
|
||||
+ setEmail(string $email): void
|
||||
+ getMotDePasse(): string
|
||||
+ setMotDePasse(string $motDePasse): void
|
||||
+ getSexe(): string
|
||||
+ setSexe(string $sexe): void
|
||||
+ getTaille(): float
|
||||
+ setTaille(float $taille): void
|
||||
+ getPoids(): float
|
||||
+ setPoids(float $poids): void
|
||||
+ getDateNaissance(): \DateTime
|
||||
+ setDateNaissance(\DateTime $dateNaissance): void
|
||||
+ getRole(): Role
|
||||
+ setRole(Role $role): void
|
||||
+ addNotification($notification): void
|
||||
+ deleteNotification($index): void
|
||||
+ isValidPassword(string $password): bool
|
||||
+ __toString(): string
|
||||
}
|
||||
abstract class Role {
|
||||
- id: int
|
||||
- usersRequests: array
|
||||
+ getUsersList(): array
|
||||
+ getUsersRequests(): array
|
||||
+ addUsersRequests(RelationshipRequest $request): void
|
||||
+ removeRequest(RelationshipRequest $req): bool
|
||||
+ CheckAdd(User $user): bool
|
||||
+ addUser(User $user): bool
|
||||
+ removeUser(User $user): bool
|
||||
+ addTraining(Training $training): bool
|
||||
+ getTrainingsList(): array
|
||||
}
|
||||
abstract class Coach extends Role {
|
||||
}
|
||||
class CoachAthlete extends Coach {
|
||||
+ CheckAdd(User $user): bool
|
||||
}
|
||||
class Athlete extends Role {
|
||||
+ getActivities(): array
|
||||
+ addActivity(Activity $myActivity): bool
|
||||
+ CheckAdd(User $user): bool
|
||||
}
|
||||
class Activite {
|
||||
- idActivity: int
|
||||
- type: String
|
||||
- date: \DateTime
|
||||
- heureDebut: \DateTime
|
||||
- heureFin: \DateTime
|
||||
- effortRessenti: int
|
||||
- variability: float
|
||||
- variance: float
|
||||
- standardDeviation: float
|
||||
- average: int
|
||||
- maximum: int
|
||||
- minimum: int
|
||||
- avrTemperature: float
|
||||
- hasAutoPause: bool
|
||||
+ getIdActivity(): int
|
||||
+ getType(): String
|
||||
+ getDate(): \DateTime
|
||||
+ getHeureDebut(): \DateTime
|
||||
+ getHeureFin(): \DateTime
|
||||
+ getEffortRessenti(): int
|
||||
+ getVariability(): float
|
||||
+ getVariance(): float
|
||||
+ getStandardDeviation(): float
|
||||
+ getAverage(): float
|
||||
+ getMaximum(): int
|
||||
+ getMinimum(): int
|
||||
+ getAvrTemperature(): float
|
||||
+ setType(String $type): void
|
||||
+ setEffortRessenti(int $effortRessenti): void
|
||||
+ __toString(): String
|
||||
}
|
||||
class Notification {
|
||||
- type: string
|
||||
- message: string
|
||||
- toUserId: int
|
||||
+ getType(): string
|
||||
+ setType(string $type): void
|
||||
+ getMessage(): string
|
||||
+ setMessage(string $message): void
|
||||
+ getToUserId(): int
|
||||
+ setToUserId(int $toUserId): void
|
||||
+ __construct(int $toUserId,string $type, string $message)
|
||||
+ __toString(): string
|
||||
}
|
||||
class Entrainement {
|
||||
- idTraining: int
|
||||
- date: \DateTime
|
||||
- latitude: float
|
||||
- longitude: float
|
||||
- description: String
|
||||
- feedback: String
|
||||
+ getId(): int
|
||||
+ getDate(): \DateTime
|
||||
+ getLocation(): String
|
||||
+ getDescription(): String
|
||||
+ getFeedback(): String
|
||||
+ __toString(): String
|
||||
}
|
||||
class Statistique {
|
||||
- idStat: int
|
||||
- distanceTotale: float
|
||||
- poids: float
|
||||
- tempsTotal: time
|
||||
- FCmoyenne: int
|
||||
- FCmin: int
|
||||
- FCmax: int
|
||||
- cloriesBrulees: int
|
||||
+ getIdStat(): int
|
||||
+ getDistanceTotale(): float
|
||||
+ getPoids(): float
|
||||
+ getTempsTotal(): time
|
||||
+ getFCmoyenne(): int
|
||||
+ getFCmin(): int
|
||||
+ getFCmax(): int
|
||||
+ getCloriesBrulees(): int
|
||||
+ __toString(): String
|
||||
}
|
||||
class SourceDonnees {
|
||||
- idSource: int
|
||||
- nom: String
|
||||
- type: String
|
||||
- precision: enum
|
||||
- dateDerniereUtilisation: \DateTime
|
||||
+ getIdSource(): int
|
||||
+ getNom(): String
|
||||
+ getType(): String
|
||||
+ getPrecision(): enum
|
||||
+ getDateDerniereUtilisation(): \DateTime
|
||||
+ __toString(): String
|
||||
}
|
||||
User -> Role : role
|
||||
Role -> User : usersList
|
||||
Athlete -> Statistique : statsList
|
||||
Athlete -> Activite : activityList
|
||||
Athlete -> SourceDonnees : sdList
|
||||
User -> Notification : notificationList
|
||||
User -> Entrainement : trainingsList
|
||||
Activite -> SourceDonnees : maSource
|
||||
@enduml
|
||||
```
|
@ -0,0 +1,90 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# Introduction au Diagramme de la Couche d'Accès aux Données
|
||||
|
||||
Bienvenue dans le cœur de notre système, où les données prennent vie à travers des ensembles de données (repositories) structurés et performants. Ce diagramme met en lumière la conception de la couche d'accès aux données de notre application, offrant un aperçu clair de la gestion des entités clées telles que les utilisateurs, les notifications, les demandes de relations et les entraînements.
|
||||
|
||||
**Principes Fondamentaux :**
|
||||
|
||||
- **IGenericRepository :** Une abstraction générique établissant les contrats essentiels pour l'accès aux données. Définissant des opérations standardisées telles que la récupération, la mise à jour, l'ajout et la suppression d'entités.
|
||||
|
||||
- **Interfaces Spécialisées :** Des interfaces telles que `IUserRepository`, `INotificationRepository`, `IRelationshipRequestRepository` et `ITrainingRepository` étendent les fonctionnalités génériques pour répondre aux besoins spécifiques de chaque entité.
|
||||
|
||||
**Repositories Concrets :**
|
||||
|
||||
- **UserRepository :** Gère les données relatives aux utilisateurs, permettant des opérations de récupération, de mise à jour et de suppression avec une efficacité optimale.
|
||||
|
||||
- **NotificationRepository :** Responsable de la gestion des notifications, assurant un accès structuré et une manipulation sécurisée de ces informations cruciales.
|
||||
|
||||
- **RelationshipRequestRepository :** Facilite la gestion des demandes de relations entre utilisateurs, garantissant une interaction claire et ordonnée.
|
||||
|
||||
- **TrainingRepository :** Permet l'accès et la manipulation des données liées aux entraînements, facilitant le suivi des performances athlétiques.
|
||||
|
||||
Explorez ce diagramme pour découvrir la robustesse de notre architecture de gestion des données, mettant en œuvre des pratiques de développement SOLID pour assurer une expérience utilisateur fiable et évolutive.
|
||||
|
||||
```plantuml
|
||||
@startuml couche_acces_aux_donnees
|
||||
abstract class IGenericRepository {
|
||||
+ getItemById(int id) : object
|
||||
+ getNbItems() : int
|
||||
+ getItems(int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ getItemsByName(string substring, int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ getItemByName(string substring, int index, int count, string orderingPropertyName, bool descending) : object
|
||||
+ updateItem(oldItem, newItem) : void
|
||||
+ addItem(item) : void
|
||||
+ deleteItem(item) : bool
|
||||
}
|
||||
interface IUserRepository extends IGenericRepository {
|
||||
}
|
||||
interface INotificationRepository extends IGenericRepository {
|
||||
}
|
||||
interface IRelationshipRequestRepository extends IGenericRepository {
|
||||
}
|
||||
interface ITrainingRepository extends IGenericRepository {
|
||||
}
|
||||
class NotificationRepository implements INotificationRepository {
|
||||
- notifications : array
|
||||
+ getItemById(int id) : object
|
||||
+ getNbItems() : int
|
||||
+ getItems(int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ getItemsByName(string substring, int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ getItemByName(string substring, int index, int count, string orderingPropertyName, bool descending) : object
|
||||
+ updateItem(oldItem, newItem) : void
|
||||
+ addItem(item) : void
|
||||
+ deleteItem(item) : bool
|
||||
}
|
||||
class RelationshipRequestRepository implements IRelationshipRequestRepository {
|
||||
- requests : array
|
||||
+ getItemById(int id) : object
|
||||
+ getNbItems() : int
|
||||
+ getItems(int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ getItemsByName(string substring, int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ getItemByName(string substring, int index, int count, string orderingPropertyName, bool descending) : object
|
||||
+ updateItem(oldItem, newItem) : void
|
||||
+ addItem(item) : void
|
||||
+ deleteItem(item) : bool
|
||||
}
|
||||
class TrainingRepository implements ITrainingRepository {
|
||||
- trainings : array
|
||||
+ getItemById(int id) : object
|
||||
+ getNbItems() : int
|
||||
+ getItems(int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ getItemsByDate(date, int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ updateItem(oldItem, newItem) : void
|
||||
+ addItem(item) : void
|
||||
+ deleteItem(item) : bool
|
||||
}
|
||||
class UserRepository implements IUserRepository {
|
||||
- users : array
|
||||
+ getItemById(int id) : object
|
||||
+ getNbItems() : int
|
||||
+ getItems(int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ getItemsByName(string substring, int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ getItemByName(string substring, int index, int count, string orderingPropertyName, bool descending) : object
|
||||
+ updateItem(oldItem, newItem) : void
|
||||
+ addItem(item) : void
|
||||
+ deleteItem(item) : bool
|
||||
}
|
||||
@enduml
|
||||
```
|
@ -0,0 +1,138 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# Introduction au Diagramme de Classes : Statistiques pour Coach
|
||||
|
||||
Bienvenue dans l'univers captivant de notre système de gestion d'activités sportives avec une mise au point spéciale sur les statistiques destinées aux coaches. Ce diagramme de classes offre une vue approfondie de la manière dont les utilisateurs, en particulier les athlètes et les coaches, interagissent avec les données de performance.
|
||||
|
||||
**Entités Principales :**
|
||||
|
||||
- **Utilisateur (User) :** Représente les individus inscrits sur notre plateforme, avec des détails personnels et un rôle spécifique dans l'écosystème sportif.
|
||||
|
||||
- **Athlète (Athlete) :** Un type spécialisé d'utilisateur qui peut enregistrer des statistiques liées à ses activités sportives.
|
||||
|
||||
- **Coach (Coach) :** Un rôle qui s'étend à partir de la classe abstraite Role, dédié à la gestion des athlètes et de leurs statistiques.
|
||||
|
||||
- **Statistique (Statistique) :** Contient des informations détaillées sur les performances sportives d'un athlète, telles que la distance totale, le poids, le temps total, la fréquence cardiaque moyenne, minimale et maximale, ainsi que les calories brûlées.
|
||||
|
||||
**Relations Clés :**
|
||||
|
||||
- Les Utilisateurs ont un rôle spécifique (Athlete, Coach) qui influence leurs interactions au sein de la plateforme.
|
||||
|
||||
- Un Coach peut gérer une liste d'athlètes et avoir accès à leurs statistiques.
|
||||
|
||||
- Un Athlète peut enregistrer plusieurs statistiques liées à ses activités.
|
||||
|
||||
**Objectif Principal :**
|
||||
|
||||
- Permettre aux coaches d'accéder et de surveiller les statistiques détaillées de leurs athlètes, offrant ainsi un aperçu complet de leurs performances sportives.
|
||||
|
||||
Explorez ce diagramme pour découvrir comment notre application crée une synergie entre les utilisateurs, les rôles, et les statistiques, contribuant ainsi à une expérience enrichissante dans le suivi des activités sportives.
|
||||
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
class Athlete {
|
||||
+ getAthlete(): Athlete
|
||||
+ getStatistic(): ?array
|
||||
+ getUsersList(): array
|
||||
+ getUserList(user: User): User
|
||||
+ CheckAdd(user: User): bool
|
||||
+ addUser(user: User): bool
|
||||
+ removeUser(user: User): bool
|
||||
}
|
||||
|
||||
abstract class Coach {
|
||||
+ abstract getUsersList(): ?array
|
||||
+ abstract getUserList(user: User): User
|
||||
}
|
||||
|
||||
class CoachAthlete {
|
||||
+ getUsersList(): ?array
|
||||
+ getUserList(user: User): User
|
||||
}
|
||||
|
||||
abstract class Role {
|
||||
- int id
|
||||
- array usersList
|
||||
- TrainingRepository trainingRepository
|
||||
+ abstract __construct(trainingRepository: ?TrainingRepository)
|
||||
+ abstract getUsersList(): ?array
|
||||
+ abstract getUserList(user: User): User
|
||||
+ abstract getTraining(): ?TrainingRepository
|
||||
+ abstract getTrainingsList(): ?array
|
||||
+ abstract getTrainingList(training: Training): ?Training
|
||||
+ abstract CheckAdd(user: User): bool
|
||||
+ abstract CheckAddTraining(training: Training): bool
|
||||
+ abstract addUser(user: User): bool
|
||||
+ abstract removeUser(user: User): bool
|
||||
+ abstract addTraining(training: Training): bool
|
||||
+ abstract removeTraining(training: Training): bool
|
||||
}
|
||||
|
||||
class User {
|
||||
- int id
|
||||
- String username
|
||||
- string nom
|
||||
- string prenom
|
||||
- string email
|
||||
- string motDePasse
|
||||
- string sexe
|
||||
- float taille
|
||||
- float poids
|
||||
- DateTime dateNaissance
|
||||
+ __construct(id: int, username: String, nom: string, prenom: string, email: string, motDePasse: string, sexe: string, taille: float, poids: float, dateNaissance: DateTime, role: Role)
|
||||
+ getId(): int
|
||||
+ setId(id: int): void
|
||||
+ getUsername(): String
|
||||
+ setUsername(username: int): void
|
||||
+ getNom(): string
|
||||
+ setNom(nom: string): void
|
||||
+ getPrenom(): string
|
||||
+ setPrenom(prenom: string): void
|
||||
+ getEmail(): string
|
||||
+ setEmail(email: string): void
|
||||
+ getMotDePasse(): string
|
||||
+ setMotDePasse(motDePasse: string): void
|
||||
+ getSexe(): string
|
||||
+ setSexe(sexe: string): void
|
||||
+ getTaille(): float
|
||||
+ setTaille(taille: float): void
|
||||
+ getPoids(): float
|
||||
+ setPoids(poids: float): void
|
||||
+ getDateNaissance(): DateTime
|
||||
+ setDateNaissance(dateNaissance: DateTime): void
|
||||
+ getRole(): Role
|
||||
+ setRole(role: Role): void
|
||||
+ isValidPassword(password: string): bool
|
||||
+ __toString(): String
|
||||
}
|
||||
|
||||
class Statistique {
|
||||
- idStat: int
|
||||
- distanceTotale: float
|
||||
- poids: float
|
||||
- tempsTotal: time
|
||||
- FCmoyenne: int
|
||||
- FCmin: int
|
||||
- FCmax: int
|
||||
- cloriesBrulees: int
|
||||
+ getIdStat(): int
|
||||
+ getDistanceTotale(): float
|
||||
+ getPoids(): float
|
||||
+ getTempsTotal(): time
|
||||
+ getFCmoyenne(): int
|
||||
+ getFCmin(): int
|
||||
+ getFCmax(): int
|
||||
+ getCloriesBrulees(): int
|
||||
+ __toString(): String
|
||||
}
|
||||
|
||||
CoachAthlete --|> Coach
|
||||
Coach --|> Role
|
||||
Athlete --|> Role
|
||||
User -> Role : role
|
||||
Role -> User : usersList
|
||||
Athlete -> Statistique : statsList
|
||||
@enduml
|
||||
````
|
After Width: | Height: | Size: 35 KiB |
@ -0,0 +1,49 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# Introduction au Diagramme de Séquence : Gestion des Demandes d'Amis
|
||||
|
||||
Bienvenue dans le processus dynamique de gestion des demandes d'amis au sein de notre application ! Ce diagramme de séquence met en évidence les étapes clés impliquées dans la gestion des demandes d'amis entre utilisateurs.
|
||||
|
||||
**Acteurs Principaux :**
|
||||
|
||||
- **Utilisateur (u) :** L'individu interagissant avec l'application, recevant et répondant aux demandes d'amis.
|
||||
|
||||
**Flux d'Interaction :**
|
||||
|
||||
1. **Réception d'une Demande d'Ami :** Lorsqu'un utilisateur reçoit une demande d'ami, le modèle (Model) notifie le contrôleur (Controller) de la nouvelle demande, spécifiant l'identifiant de l'utilisateur émetteur.
|
||||
|
||||
2. **Affichage de la Demande d'Ami :** Le contrôleur transmet l'information à la vue (View), qui affiche la demande d'ami à l'utilisateur.
|
||||
|
||||
3. **Affichage de la Page des Demandes d'Amis :** L'utilisateur visualise la page des demandes d'amis dans l'interface utilisateur.
|
||||
|
||||
4. **Réponse à la Demande d'Ami :** L'utilisateur prend une décision quant à la demande d'ami, en répondant par un choix binaire (accepter ou refuser).
|
||||
|
||||
5. **Enregistrement de la Réponse :** La vue (View) transmet la réponse de l'utilisateur au contrôleur, qui enregistre cette réponse.
|
||||
|
||||
6. **Envoi de la Réponse :** Le contrôleur communique avec le modèle pour envoyer la réponse, indiquant si la demande a été acceptée (true) ou refusée (false).
|
||||
|
||||
À travers ce diagramme de séquence, découvrez comment notre application gère efficacement le processus de gestion des demandes d'amis, offrant aux utilisateurs une expérience transparente et réactive lors de l'établissement de connexions sociales au sein de la plateforme.
|
||||
|
||||
````plantuml
|
||||
@startuml
|
||||
actor User as u
|
||||
boundary View as v
|
||||
control Controller as c
|
||||
entity Model as m
|
||||
|
||||
m-->c: pendingRequests: Request[]
|
||||
|
||||
c-->v: DisplayPendingRequests(pendingRequests)
|
||||
v-->u: Show Friend Requests
|
||||
|
||||
u->v: RespondToRequest(requestId, response)
|
||||
v-->c: RecordResponse(requestId, response)
|
||||
|
||||
c->m: UpdateRequestStatus(requestId, response)
|
||||
m-->c: updateStatus: success/failure
|
||||
c-->v: NotifyUpdateResult(updateStatus)
|
||||
v-->u: Show Response Result
|
||||
|
||||
@enduml
|
||||
``````
|
@ -0,0 +1,30 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# Introduction au Diagramme de Séquence : Recherche d'Amis
|
||||
|
||||
Bienvenue dans le processus dynamique de recherche d'amis au sein de notre application ! Ce diagramme de séquence met en lumière les étapes clés impliquées lorsque les utilisateurs recherchent des amis en utilisant un pseudo spécifique.
|
||||
|
||||
**Acteurs Principaux :**
|
||||
|
||||
- **Utilisateur (u) :** L'individu interagissant avec l'application, initié à la recherche d'amis.
|
||||
|
||||
**Flux d'Interaction :**
|
||||
|
||||
1. **Accès à la Fonctionnalité de Recherche :** L'utilisateur déclenche la fonctionnalité de recherche d'amis depuis son interface utilisateur.
|
||||
|
||||
2. **Saisie du Pseudo :** L'utilisateur entre le pseudo de l'ami qu'il souhaite rechercher.
|
||||
|
||||
3. **Requête de Recherche :** La vue (View) transmet la demande de recherche au contrôleur (Controller), qui déclenche une requête GET au serveur pour récupérer la liste des amis correspondant au pseudo saisi.
|
||||
|
||||
4. **Traitement de la Requête :** Le modèle (Model) récupère la liste d'amis correspondante en utilisant l'identifiant de l'utilisateur et notifie le contrôleur du résultat.
|
||||
|
||||
5. **Notification des Utilisateurs :** Le modèle informe également les utilisateurs concernés (émetteur et destinataire) de l'action de recherche effectuée.
|
||||
|
||||
6. **Rendu de la Vue :** Le contrôleur reçoit la liste d'amis du modèle et rend cette liste à la vue.
|
||||
|
||||
7. **Affichage des Résultats :** La vue affiche les résultats de la recherche à l'utilisateur, montrant les amis qui correspondent au pseudo saisi.
|
||||
|
||||
À travers ce diagramme de séquence, découvrez comment notre application facilite le processus de recherche d'amis, fournissant aux utilisateurs une interface conviviale et réactive pour élargir leur réseau social au sein de la plateforme.
|
||||
|
||||
<img src="AjouterAmis.png" alt="Diagramme de Séquence : Recherche d'Amis" width="1000"/>
|
@ -0,0 +1,63 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# Introduction au Diagramme de Séquence : Gestion des Amis
|
||||
|
||||
Bienvenue dans le processus dynamique de gestion des amis au sein de notre application ! Ce diagramme de séquence met en lumière les interactions entre l'utilisateur et l'application, ainsi que le flux d'informations entre les différentes composantes du système.
|
||||
|
||||
**Acteurs Principaux :**
|
||||
|
||||
- **Utilisateur (u) :** L'individu interagissant avec l'application, souhaitant consulter et gérer sa liste d'amis.
|
||||
|
||||
**Flux d'Interaction :**
|
||||
|
||||
1. **Demande de la Page d'Amis :** L'utilisateur déclenche la demande de la page d'amis, amorçant le processus d'affichage de sa liste d'amis.
|
||||
|
||||
2. **Récupération des Amis :** Le contrôleur (Controller) reçoit la demande et interagit avec le modèle (Model) pour récupérer la liste d'amis associée à l'identifiant de l'utilisateur.
|
||||
|
||||
- *Cas de Récupération Réussi :* Si la récupération est réussie, le modèle transmet la liste d'amis au contrôleur.
|
||||
|
||||
- *Cas d'Échec de Récupération :* En cas d'échec, une notification d'erreur est renvoyée.
|
||||
|
||||
3. **Affichage de la Liste d'Amis :** Le contrôleur rend la vue (View) en utilisant la liste d'amis récupérée, qui est ensuite affichée à l'utilisateur.
|
||||
|
||||
4. **Suppression d'un Ami :** L'utilisateur décide de supprimer un ami spécifique en cliquant sur l'option correspondante.
|
||||
|
||||
5. **Traitement de la Suppression :** Le contrôleur, en réponse à la demande de suppression, envoie une requête au modèle pour effectuer la suppression de l'ami identifié par son identifiant utilisateur (idUser).
|
||||
|
||||
- *Cas de Suppression Réussie :* Si la suppression est réussie, le modèle renvoie la liste d'amis mise à jour.
|
||||
|
||||
- *Cas d'Échec de Suppression :* En cas d'échec, une notification d'erreur est renvoyée.
|
||||
|
||||
6. **Affichage de la Liste d'Amis Mise à Jour :** La vue est mise à jour avec la nouvelle liste d'amis, qui est ensuite affichée à l'utilisateur.
|
||||
|
||||
À travers ce diagramme de séquence, découvrez comment notre application gère de manière fluide et réactive les interactions de l'utilisateur avec sa liste d'amis, garantissant une expérience utilisateur cohérente et sans heurts.
|
||||
|
||||
```plantuml
|
||||
actor User as u
|
||||
boundary View as v
|
||||
control Controller as c
|
||||
entity Model as m
|
||||
|
||||
u->v: Request Friends Page
|
||||
v->c: Get /Friends
|
||||
c->m: getFriends(userId)
|
||||
alt successful retrieval
|
||||
m-->c: friendsList: User[]
|
||||
else retrieval failed
|
||||
m-->c: error
|
||||
end
|
||||
c-->v: renderView(friendsList)
|
||||
v-->u: Display Friends
|
||||
|
||||
u->v: clickDeleteFriend(idUser)
|
||||
v->c: Post: deleteFriend(idUser)
|
||||
c->m: deleteFriend(idUser)
|
||||
alt successful deletion
|
||||
m-->c: updatedFriendsList: User[]
|
||||
else deletion failed
|
||||
m-->c: error
|
||||
end
|
||||
c-->v: renderView(updatedFriendsList)
|
||||
v-->u: Display Updated Friends
|
||||
```
|
@ -0,0 +1,21 @@
|
||||
[retour au README.md](../../README.md)
|
||||
|
||||
# Diagrammes nécéssaires à notre projet
|
||||
|
||||
## Diagrammes de classes
|
||||
- [issue016 - Statistiques coach ](DiagrammeDeClasses/README_issue016.md)
|
||||
- [couche d'accès aux données](DiagrammeDeClasses/README_accesDonnees.md)
|
||||
- [Diagramme général](DiagrammeDeClasses/README_DIAGRAMME.md)
|
||||
|
||||
## Diagrammes de séquence
|
||||
- [Envoi de demande d'ami](DiagrammeDeSequence/README_demandeAmi.md)
|
||||
- [Accepter une demande d'ami](DiagrammeDeSequence/README_accepterAmi.md)
|
||||
- [Supprimer un ami](DiagrammeDeSequence/README_suppressionAmi.md)
|
||||
- [issue021 - Authentification ](DiagrammeDeSequence/README_issue021.md)
|
||||
|
||||
## Diagrammes de cas d'utilisation
|
||||
- [Cas d'utilisation pour la gestion du compte et des amitiés](CasUtilisations/README_gestionCompteAmitie.md)
|
||||
- [Cas d'utilisation pour la gestion des activités et données](CasUtilisations/README_gestionActivites.md)
|
||||
|
||||
## Base de données
|
||||
- [MCD - MLD](BDD/README_BDD.md)
|
@ -0,0 +1,429 @@
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = "HeartTrackAPI"
|
||||
PROJECT_NUMBER = 1.0.0
|
||||
PROJECT_BRIEF = "This is the HeartTrack API documentation."
|
||||
PROJECT_LOGO = /docs/images/logo.png
|
||||
OUTPUT_DIRECTORY = /docs/doxygen
|
||||
CREATE_SUBDIRS = NO
|
||||
ALLOW_UNICODE_NAMES = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF = "The $name class" \
|
||||
"The $name widget" \
|
||||
"The $name file" \
|
||||
is \
|
||||
provides \
|
||||
specifies \
|
||||
contains \
|
||||
represents \
|
||||
a \
|
||||
an \
|
||||
the
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = YES
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
JAVADOC_BANNER = NO
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
PYTHON_DOCSTRING = YES
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 4
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = NO
|
||||
# Well... the one for Java looks so similar to the one for C#...
|
||||
OPTIMIZE_OUTPUT_JAVA = YES
|
||||
OPTIMIZE_FOR_FORTRAN = NO
|
||||
OPTIMIZE_OUTPUT_VHDL = NO
|
||||
OPTIMIZE_OUTPUT_SLICE = NO
|
||||
EXTENSION_MAPPING =
|
||||
MARKDOWN_SUPPORT = YES
|
||||
TOC_INCLUDE_HEADINGS = 5
|
||||
AUTOLINK_SUPPORT = YES
|
||||
BUILTIN_STL_SUPPORT = NO
|
||||
CPP_CLI_SUPPORT = NO
|
||||
SIP_SUPPORT = NO
|
||||
IDL_PROPERTY_SUPPORT = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
GROUP_NESTED_COMPOUNDS = NO
|
||||
SUBGROUPING = YES
|
||||
INLINE_GROUPED_CLASSES = NO
|
||||
INLINE_SIMPLE_STRUCTS = NO
|
||||
TYPEDEF_HIDES_STRUCT = NO
|
||||
LOOKUP_CACHE_SIZE = 0
|
||||
NUM_PROC_THREADS = 1
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
EXTRACT_ALL = YES
|
||||
# I do not like other members to see my private members... but you can set it to YES if you prefer.
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_PRIV_VIRTUAL = NO
|
||||
EXTRACT_PACKAGE = NO
|
||||
EXTRACT_STATIC = YES
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
EXTRACT_ANON_NSPACES = NO
|
||||
RESOLVE_UNNAMED_PARAMS = YES
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = NO
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
HIDE_COMPOUND_REFERENCE= NO
|
||||
SHOW_HEADERFILE = YES
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
SHOW_GROUPED_MEMB_INC = NO
|
||||
FORCE_LOCAL_INCLUDES = NO
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = NO
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_MEMBERS_CTORS_1ST = NO
|
||||
SORT_GROUP_NAMES = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
STRICT_PROTO_MATCHING = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_FILES = YES
|
||||
SHOW_NAMESPACES = YES
|
||||
FILE_VERSION_FILTER =
|
||||
LAYOUT_FILE =
|
||||
CITE_BIB_FILES =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_IF_INCOMPLETE_DOC = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_AS_ERROR = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
INPUT = src/
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS = *.c \
|
||||
*.cc \
|
||||
*.cxx \
|
||||
*.cpp \
|
||||
*.c++ \
|
||||
*.java \
|
||||
*.ii \
|
||||
*.ixx \
|
||||
*.ipp \
|
||||
*.i++ \
|
||||
*.inl \
|
||||
*.idl \
|
||||
*.ddl \
|
||||
*.odl \
|
||||
*.h \
|
||||
*.hh \
|
||||
*.hxx \
|
||||
*.hpp \
|
||||
*.h++ \
|
||||
*.l \
|
||||
*.cs \
|
||||
*.d \
|
||||
*.php \
|
||||
*.php4 \
|
||||
*.php5 \
|
||||
*.phtml \
|
||||
*.inc \
|
||||
*.m \
|
||||
*.markdown \
|
||||
*.md \
|
||||
*.mm \
|
||||
*.dox \
|
||||
*.py \
|
||||
*.pyw \
|
||||
*.f90 \
|
||||
*.f95 \
|
||||
*.f03 \
|
||||
*.f08 \
|
||||
*.f18 \
|
||||
*.f \
|
||||
*.for \
|
||||
*.vhd \
|
||||
*.vhdl \
|
||||
*.ucf \
|
||||
*.qsf \
|
||||
*.ice
|
||||
RECURSIVE = YES
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS = */Tests/*
|
||||
EXCLUDE_PATTERNS += */bin/*
|
||||
EXCLUDE_PATTERNS += */obj/*
|
||||
EXCLUDE_SYMBOLS =
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
FILTER_SOURCE_PATTERNS =
|
||||
USE_MDFILE_AS_MAINPAGE =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
SOURCE_BROWSER = NO
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = NO
|
||||
REFERENCES_RELATION = NO
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
SOURCE_TOOLTIPS = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = YES
|
||||
CLANG_ASSISTED_PARSING = NO
|
||||
CLANG_ADD_INC_PATHS = YES
|
||||
CLANG_OPTIONS =
|
||||
CLANG_DATABASE_PATH =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
ALPHABETICAL_INDEX = YES
|
||||
IGNORE_PREFIX =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_EXTRA_STYLESHEET =
|
||||
HTML_EXTRA_FILES = images/CodeFirst.png images/clubinfo.png
|
||||
HTML_COLORSTYLE_HUE = 215
|
||||
HTML_COLORSTYLE_SAT = 45
|
||||
HTML_COLORSTYLE_GAMMA = 240
|
||||
HTML_TIMESTAMP = NO
|
||||
HTML_DYNAMIC_MENUS = YES
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
HTML_INDEX_NUM_ENTRIES = 100
|
||||
GENERATE_DOCSET = NO
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
DOCSET_FEEDURL =
|
||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
|
||||
DOCSET_PUBLISHER_NAME = Publisher
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
CHM_INDEX_ENCODING =
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
GENERATE_QHP = NO
|
||||
QCH_FILE =
|
||||
QHP_NAMESPACE = org.doxygen.Project
|
||||
QHP_VIRTUAL_FOLDER = doc
|
||||
QHP_CUST_FILTER_NAME =
|
||||
QHP_CUST_FILTER_ATTRS =
|
||||
QHP_SECT_FILTER_ATTRS =
|
||||
QHG_LOCATION =
|
||||
GENERATE_ECLIPSEHELP = NO
|
||||
ECLIPSE_DOC_ID = org.doxygen.Project
|
||||
DISABLE_INDEX = NO
|
||||
GENERATE_TREEVIEW = NO
|
||||
FULL_SIDEBAR = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
TREEVIEW_WIDTH = 250
|
||||
EXT_LINKS_IN_WINDOW = NO
|
||||
OBFUSCATE_EMAILS = YES
|
||||
HTML_FORMULA_FORMAT = png
|
||||
FORMULA_FONTSIZE = 10
|
||||
FORMULA_TRANSPARENT = YES
|
||||
FORMULA_MACROFILE =
|
||||
USE_MATHJAX = NO
|
||||
MATHJAX_VERSION = MathJax_2
|
||||
MATHJAX_FORMAT = HTML-CSS
|
||||
MATHJAX_RELPATH =
|
||||
MATHJAX_EXTENSIONS =
|
||||
MATHJAX_CODEFILE =
|
||||
SEARCHENGINE = YES
|
||||
SERVER_BASED_SEARCH = NO
|
||||
EXTERNAL_SEARCH = NO
|
||||
SEARCHENGINE_URL =
|
||||
SEARCHDATA_FILE = searchdata.xml
|
||||
EXTERNAL_SEARCH_ID =
|
||||
EXTRA_SEARCH_MAPPINGS =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME =
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
LATEX_MAKEINDEX_CMD = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
LATEX_FOOTER =
|
||||
LATEX_EXTRA_STYLESHEET =
|
||||
LATEX_EXTRA_FILES =
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = YES
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
LATEX_BIB_STYLE = plain
|
||||
LATEX_TIMESTAMP = NO
|
||||
LATEX_EMOJI_DIRECTORY =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_SUBDIR =
|
||||
MAN_LINKS = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_PROGRAMLISTING = YES
|
||||
XML_NS_MEMB_FILE_SCOPE = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the DOCBOOK output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
GENERATE_DOCBOOK = NO
|
||||
DOCBOOK_OUTPUT = docbook
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to Sqlite3 output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED =
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
EXTERNAL_PAGES = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
DIA_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = NO
|
||||
DOT_NUM_THREADS = 0
|
||||
DOT_FONTNAME = Helvetica
|
||||
DOT_FONTSIZE = 10
|
||||
DOT_FONTPATH =
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = NO
|
||||
UML_LIMIT_NUM_FIELDS = 10
|
||||
DOT_UML_DETAILS = NO
|
||||
DOT_WRAP_THRESHOLD = 17
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
CALLER_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = YES
|
||||
DIR_GRAPH_MAX_DEPTH = 1
|
||||
DOT_IMAGE_FORMAT = png
|
||||
INTERACTIVE_SVG = NO
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MSCFILE_DIRS =
|
||||
DIAFILE_DIRS =
|
||||
PLANTUML_JAR_PATH =
|
||||
PLANTUML_CFG_FILE =
|
||||
PLANTUML_INCLUDE_PATH =
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
After Width: | Height: | Size: 27 KiB |
@ -0,0 +1,109 @@
|
||||
using Dto;
|
||||
using Dto.Tiny;
|
||||
using Entities;
|
||||
using Model;
|
||||
using Shared;
|
||||
|
||||
namespace APIMappers;
|
||||
|
||||
public static class ActivityMapper
|
||||
{
|
||||
private static GenericMapper<Activity, ActivityDto> _mapper = new();
|
||||
private static GenericMapper<ActivityTinyDto, ActivityEntity> _mapperTiny = new ();
|
||||
|
||||
public static Activity ToModel(this ActivityDto activityDto, User user)
|
||||
{
|
||||
Func<ActivityDto, Activity> create = activity => new Activity
|
||||
{
|
||||
Id = activity.Id,
|
||||
Type = activity.Type,
|
||||
Date = activity.Date,
|
||||
StartTime = activity.StartTime,
|
||||
EndTime = activity.EndTime,
|
||||
Effort = activity.EffortFelt,
|
||||
Variability = activity.Variability,
|
||||
Variance = activity.Variance,
|
||||
StandardDeviation = activity.StandardDeviation,
|
||||
Average = activity.Average,
|
||||
Maximum = activity.Maximum,
|
||||
Minimum = activity.Minimum,
|
||||
AverageTemperature = activity.AverageTemperature,
|
||||
HasAutoPause = activity.HasAutoPause
|
||||
};
|
||||
|
||||
Action<ActivityDto, Activity> link = (activity, model) =>
|
||||
{
|
||||
if (activity.DataSource != null)
|
||||
model.DataSource = user.DataSources.FirstOrDefault(ds => ds.Id == activity.DataSource.Id);
|
||||
model.Athlete = user;
|
||||
};
|
||||
|
||||
var act = activityDto.ToT(_mapper, create, link);
|
||||
act.HeartRates.AddRange(activityDto.HeartRates.ToModels(act).ToList());
|
||||
|
||||
return act;
|
||||
}
|
||||
|
||||
public static ActivityDto ToDto(this Activity model)
|
||||
{
|
||||
Func<Activity, ActivityDto> create = activity => 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,
|
||||
AthleteId = activity.Athlete.Id
|
||||
};
|
||||
|
||||
Action<Activity, ActivityDto> link = (activity, dto) =>
|
||||
{
|
||||
dto.HeartRates = activity.HeartRates.ToDtos().ToArray();
|
||||
dto.DataSource = activity.DataSource.ToDto();
|
||||
dto.Athlete = activity.Athlete.ToDto();
|
||||
};
|
||||
|
||||
return model.ToU(_mapper, create, link);
|
||||
}
|
||||
|
||||
public static ActivityEntity ToEntity(this ActivityTinyDto tinyDto)
|
||||
{
|
||||
Func<ActivityTinyDto, ActivityEntity> create = dto => new ActivityEntity
|
||||
{
|
||||
Type = dto.Type,
|
||||
Date = DateOnly.FromDateTime(dto.Date),
|
||||
StartTime = TimeOnly.FromDateTime(dto.StartTime),
|
||||
EndTime = TimeOnly.FromDateTime(dto.EndTime),
|
||||
EffortFelt = dto.EffortFelt,
|
||||
Variability = dto.Variability,
|
||||
Variance = dto.Variance,
|
||||
StandardDeviation = dto.StandardDeviation,
|
||||
Average = dto.Average,
|
||||
Maximum = dto.Maximum,
|
||||
Minimum = dto.Minimum,
|
||||
AverageTemperature = dto.AverageTemperature,
|
||||
HasAutoPause = dto.HasAutoPause
|
||||
};
|
||||
|
||||
return tinyDto.ToU(_mapperTiny, create);
|
||||
}
|
||||
|
||||
public static IEnumerable<Activity> ToModels(this IEnumerable<ActivityDto> dtos, User user)
|
||||
=> dtos.Select(dto => dto.ToModel(user));
|
||||
|
||||
public static IEnumerable<ActivityDto> ToDtos(this IEnumerable<Activity> models)
|
||||
=> models.Select(model => model.ToDto());
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
using Dto;
|
||||
using Model;
|
||||
using Shared;
|
||||
|
||||
namespace APIMappers;
|
||||
|
||||
public static class DataSourceMapper
|
||||
{
|
||||
|
||||
private static GenericMapper<DataSource, DataSourceDto> _mapper = new ();
|
||||
|
||||
public static DataSource ToModel(this DataSourceDto dto, User user)
|
||||
{
|
||||
Func<DataSourceDto, DataSource> create = dataSourceDto =>
|
||||
new DataSource(dataSourceDto.Id, dataSourceDto.Type, dataSourceDto.Model, dataSourceDto.Precision,
|
||||
new List<User> { user }, user.Activities.Where(a => a.DataSource.Id == dataSourceDto.Id).ToList());
|
||||
/*
|
||||
Action<DataSourceDto, DataSource> link = (dataSourceDto, model) =>
|
||||
{
|
||||
model.Activities.AddRange(dataSourceDto.Activities.ToModels());
|
||||
model.Athletes.AddRange(dataSourceDto.Athletes.ToModels());
|
||||
};*/
|
||||
|
||||
return dto.ToT(_mapper, create);
|
||||
}
|
||||
|
||||
public static DataSourceDto ToDto(this DataSource model)
|
||||
{
|
||||
Func<DataSource, DataSourceDto> create = dataSource =>
|
||||
new DataSourceDto
|
||||
{
|
||||
Id = dataSource.Id,
|
||||
Type = dataSource.Type,
|
||||
Model = dataSource.Model,
|
||||
Precision = dataSource.Precision,
|
||||
};
|
||||
Action<DataSource, DataSourceDto> link = (dataSource, dto) =>
|
||||
{
|
||||
dto.Activities = dataSource.Activities.ToDtos().ToArray();
|
||||
dto.Athletes = dataSource.Athletes.ToDtos().ToArray();
|
||||
};
|
||||
return model.ToU(_mapper, create, link);
|
||||
}
|
||||
|
||||
public static IEnumerable<DataSource> ToModels(this IEnumerable<DataSourceDto> dtos, User user)
|
||||
=> dtos.Select(d => d.ToModel(user));
|
||||
|
||||
public static IEnumerable<DataSourceDto> ToDtos(this IEnumerable<DataSource> models)
|
||||
=> models.Select(m => m.ToDto());
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
using Dto;
|
||||
using Model;
|
||||
using Shared;
|
||||
|
||||
namespace APIMappers;
|
||||
|
||||
public static class HeartRateMapper
|
||||
{
|
||||
private static GenericMapper<HeartRate, HeartRateDto> _mapper = new();
|
||||
|
||||
public static HeartRate ToModel(this HeartRateDto dto,Activity activityDto)
|
||||
{
|
||||
Func<HeartRateDto, HeartRate> create = heartRateDto =>
|
||||
new HeartRate(heartRateDto.HeartRate, TimeOnly.FromDateTime(heartRateDto.Timestamp), activityDto, heartRateDto.Latitude, heartRateDto.Longitude, heartRateDto.Altitude, heartRateDto.Cadence, heartRateDto.Distance, heartRateDto.Speed, heartRateDto.Power, heartRateDto.Temperature);
|
||||
|
||||
return dto.ToT(_mapper, create);
|
||||
}
|
||||
|
||||
public static HeartRateDto ToDto(this HeartRate model)//Activity activity
|
||||
{
|
||||
var activity = new DateTime();
|
||||
Func<HeartRate, HeartRateDto> create = heartRate =>
|
||||
new HeartRateDto
|
||||
{
|
||||
Timestamp = new DateTime(activity.Date.Year, activity.Date.Month, activity.Date.Day, heartRate.Timestamp.Hour, heartRate.Timestamp.Minute, heartRate.Timestamp.Second),
|
||||
Latitude = heartRate.Latitude,
|
||||
Longitude = heartRate.Longitude,
|
||||
Altitude = heartRate.Altitude,
|
||||
HeartRate = heartRate.Bpm,
|
||||
Cadence = heartRate.Cadence,
|
||||
Distance = heartRate.Distance,
|
||||
Speed = heartRate.Speed,
|
||||
Power = heartRate.Power,
|
||||
Temperature = heartRate.Temperature
|
||||
};
|
||||
return model.ToU(_mapper, create);
|
||||
}
|
||||
|
||||
public static IEnumerable<HeartRate> ToModels(this IEnumerable<HeartRateDto> dtos, Activity activityDto)
|
||||
=> dtos.Select(d => d.ToModel(activityDto));
|
||||
|
||||
public static IEnumerable<HeartRateDto> ToDtos(this IEnumerable<HeartRate> models)
|
||||
=> models.Select(m => m.ToDto());
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
using Dto;
|
||||
using Model;
|
||||
|
||||
namespace APIMappers;
|
||||
|
||||
public static class LargeImageMapper
|
||||
{
|
||||
public static LargeImageDto ToDto(this LargeImage largeImage)
|
||||
=> new() { Base64 = largeImage.Base64 };
|
||||
|
||||
public static LargeImage ToModel(this LargeImageDto largeImageDto) => new(largeImageDto.Base64);
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dto;
|
||||
|
||||
public class ActivityDto
|
||||
{
|
||||
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; }
|
||||
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
public DataSourceDto? DataSource { get; set; }
|
||||
|
||||
[JsonProperty("DataSourceId")]
|
||||
public int? DataSourceId { get; set; }
|
||||
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
public UserDto? Athlete { get; set; }
|
||||
|
||||
[JsonProperty("AthleteId")]
|
||||
public int AthleteId { get; set; }
|
||||
|
||||
// public int? TrainingId { get; set; }
|
||||
public IEnumerable<HeartRateDto> HeartRates { get; set; }
|
||||
}
|
@ -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,20 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Dto;
|
||||
|
||||
public class DataSourceDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string? Type { get; set; }
|
||||
|
||||
public string Model { get; set; }
|
||||
|
||||
public float Precision { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public IEnumerable<UserDto>? Athletes { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public IEnumerable<ActivityDto>? Activities { get; set; }
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
namespace Dto;
|
||||
|
||||
public class HeartRateDto
|
||||
{
|
||||
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,6 @@
|
||||
namespace Dto;
|
||||
|
||||
public class LargeImageDto
|
||||
{
|
||||
public string Base64 { 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 @@
|
||||
namespace Dto;
|
@ -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 @@
|
||||
namespace Dto;
|
@ -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 @@
|
||||
namespace Dto;
|
@ -0,0 +1,78 @@
|
||||
using Entities;
|
||||
using Model;
|
||||
using Shared;
|
||||
|
||||
namespace EFMappers;
|
||||
|
||||
public static class ActivityMapper
|
||||
{
|
||||
private static GenericMapper<Activity, ActivityEntity> _mapper = new ();
|
||||
public static void Reset()
|
||||
{
|
||||
_mapper.Reset();
|
||||
}
|
||||
|
||||
public static Activity ToModel(this ActivityEntity entity)
|
||||
{
|
||||
Func<ActivityEntity, Activity> create = activityEntity => new Activity
|
||||
{
|
||||
Id = activityEntity.IdActivity,
|
||||
Type = activityEntity.Type,
|
||||
Date = activityEntity.Date.ToDateTime(TimeOnly.MinValue),
|
||||
StartTime = activityEntity.Date.ToDateTime(activityEntity.StartTime),
|
||||
EndTime = activityEntity.Date.ToDateTime(activityEntity.EndTime),
|
||||
Effort = activityEntity.EffortFelt,
|
||||
Variability = activityEntity.Variability,
|
||||
Variance = activityEntity.Variance,
|
||||
StandardDeviation = activityEntity.StandardDeviation,
|
||||
Average = activityEntity.Average,
|
||||
Maximum = activityEntity.Maximum,
|
||||
Minimum = activityEntity.Minimum,
|
||||
AverageTemperature = activityEntity.AverageTemperature,
|
||||
HasAutoPause = activityEntity.HasAutoPause
|
||||
};
|
||||
|
||||
Action<ActivityEntity, Activity> link = (activityEntity, model) =>
|
||||
{
|
||||
model.HeartRates.AddRange(activityEntity.HeartRates?.ToModels());
|
||||
model.DataSource = activityEntity.DataSource.ToModel();
|
||||
model.Athlete = activityEntity.Athlete.ToModel();
|
||||
};
|
||||
return entity.ToT(_mapper, create, link);
|
||||
}
|
||||
|
||||
|
||||
public static ActivityEntity ToEntity(this Activity model)
|
||||
{
|
||||
Func<Activity, ActivityEntity> create = activity => new ActivityEntity
|
||||
{
|
||||
IdActivity = activity.Id,
|
||||
Type = activity.Type,
|
||||
Date = DateOnly.FromDateTime(activity.Date),
|
||||
StartTime = TimeOnly.FromDateTime(activity.StartTime),
|
||||
EndTime = TimeOnly.FromDateTime(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
|
||||
};
|
||||
Action<Activity, ActivityEntity> link = (activity, entity) =>
|
||||
{
|
||||
entity.HeartRates = activity.HeartRates.ToEntities().ToList();
|
||||
entity.DataSource = activity.DataSource != null ? activity.DataSource.ToEntity() : null;
|
||||
entity.Athlete = activity.Athlete.ToEntity();
|
||||
};
|
||||
return model.ToU(_mapper, create, link);
|
||||
}
|
||||
|
||||
public static IEnumerable<Activity> ToModels(this IEnumerable<ActivityEntity> entities)
|
||||
=> entities.Select(a => a.ToModel());
|
||||
|
||||
public static IEnumerable<ActivityEntity> ToEntities(this IEnumerable<Activity> models)
|
||||
=> models.Select(a => a.ToEntity());
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
using Entities;
|
||||
using Model;
|
||||
using Shared;
|
||||
|
||||
namespace EFMappers;
|
||||
|
||||
public static class DataSourceMapper
|
||||
{
|
||||
|
||||
private static GenericMapper<DataSource, DataSourceEntity> _mapper = new ();
|
||||
|
||||
public static DataSource ToModel(this DataSourceEntity entity)
|
||||
{
|
||||
Func<DataSourceEntity, DataSource> create = dataSourceEntity =>
|
||||
new DataSource( dataSourceEntity.IdSource, dataSourceEntity.Type, dataSourceEntity.Model, dataSourceEntity.Precision, dataSourceEntity.Athletes.ToModels().ToList(), dataSourceEntity.Activities.ToModels().ToList());
|
||||
/*
|
||||
Action<DataSourceEntity, DataSource> link = (dataSourceEntity, model) =>
|
||||
{
|
||||
model.Activities.AddRange(dataSourceEntity.Activities.ToModels());
|
||||
model.Athletes.AddRange(dataSourceEntity.Athletes.ToModels());
|
||||
};*/
|
||||
|
||||
return entity.ToT(_mapper, create);
|
||||
}
|
||||
|
||||
public static DataSourceEntity ToEntity(this DataSource model)
|
||||
{
|
||||
Func<DataSource, DataSourceEntity> create = dataSource =>
|
||||
new DataSourceEntity
|
||||
{
|
||||
IdSource = dataSource.Id,
|
||||
Type = dataSource.Type,
|
||||
Model = dataSource.Model,
|
||||
Precision = dataSource.Precision
|
||||
};
|
||||
|
||||
Action<DataSource, DataSourceEntity> link = (dataSource, entity) =>
|
||||
{
|
||||
entity.Activities = dataSource.Activities.ToEntities().ToList();
|
||||
entity.Athletes = dataSource.Athletes.ToEntities().ToList();
|
||||
};
|
||||
|
||||
return model.ToU(_mapper, create, link);
|
||||
}
|
||||
|
||||
public static IEnumerable<DataSource> ToModels(this IEnumerable<DataSourceEntity> entities)
|
||||
=> entities.Select(e => e.ToModel());
|
||||
|
||||
public static IEnumerable<DataSourceEntity> ToEntities(this IEnumerable<DataSource> models)
|
||||
=> models.Select(m => m.ToEntity());
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
using Entities;
|
||||
using Model;
|
||||
using Shared;
|
||||
|
||||
namespace EFMappers;
|
||||
|
||||
public static class HeartRateMapper
|
||||
{
|
||||
private static GenericMapper<HeartRate, HeartRateEntity> _mapper = new ();
|
||||
|
||||
public static HeartRate ToModel(this HeartRateEntity entity)
|
||||
{
|
||||
Func<HeartRateEntity,HeartRate> create = heartRateEntity =>
|
||||
new HeartRate(heartRateEntity.IdHeartRate, heartRateEntity.Bpm, heartRateEntity.Time, heartRateEntity.Activity.ToModel(),heartRateEntity.Latitude, heartRateEntity.Longitude, heartRateEntity.Altitude, heartRateEntity.Cadence, heartRateEntity.Distance, heartRateEntity.Speed, heartRateEntity.Power, heartRateEntity.Temperature);
|
||||
|
||||
Action<HeartRateEntity, HeartRate> link = (heartRateEntity, model) =>
|
||||
{
|
||||
model.Activity = heartRateEntity.Activity.ToModel();
|
||||
};
|
||||
|
||||
return entity.ToT(_mapper, create, link);
|
||||
}
|
||||
|
||||
public static HeartRateEntity ToEntity(this HeartRate model)
|
||||
{
|
||||
Func<HeartRate, HeartRateEntity> create = heartRate =>
|
||||
new HeartRateEntity
|
||||
{
|
||||
IdHeartRate = heartRate.Id,
|
||||
Bpm = heartRate.Bpm,
|
||||
Time = heartRate.Timestamp,
|
||||
Latitude = heartRate.Latitude,
|
||||
Longitude = heartRate.Longitude,
|
||||
Altitude = heartRate.Altitude,
|
||||
Cadence = heartRate.Cadence??0,
|
||||
Distance = heartRate.Distance,
|
||||
Speed = heartRate.Speed,
|
||||
Power = heartRate.Power,
|
||||
Temperature = heartRate.Temperature
|
||||
};
|
||||
|
||||
Action<HeartRate, HeartRateEntity> link = (heartRate, entity) =>
|
||||
{
|
||||
entity.Activity = heartRate.Activity.ToEntity();
|
||||
};
|
||||
|
||||
return model.ToU(_mapper, create, link);
|
||||
}
|
||||
|
||||
public static IEnumerable<HeartRate> ToModels(this IEnumerable<HeartRateEntity> entities)
|
||||
=> entities.Select(h => h.ToModel());
|
||||
|
||||
public static IEnumerable<HeartRateEntity> ToEntities(this IEnumerable<HeartRate> models)
|
||||
=> models.Select(h => h.ToEntity());
|
||||
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
using Entities;
|
||||
using Model;
|
||||
|
||||
namespace EFMappers;
|
||||
|
||||
public static class LargeImageMapper
|
||||
{
|
||||
public static LargeImage ToModel(this LargeImageEntity largeImage) => new(largeImage.Base64);
|
||||
|
||||
public static LargeImageEntity ToEntity(this LargeImage largeImage) => new() { Base64 = largeImage.Base64 };
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Entities;
|
||||
|
||||
public class LargeImageEntity
|
||||
{
|
||||
[Key]
|
||||
public Guid Id { get; set; }
|
||||
public string Base64 { 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,202 @@
|
||||
using APIMappers;
|
||||
using Dto;
|
||||
using Dto.Tiny;
|
||||
using HeartTrackAPI.Request;
|
||||
using HeartTrackAPI.Responce;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Shared;
|
||||
using Model.Manager;
|
||||
using Model.Repository;
|
||||
|
||||
namespace HeartTrackAPI.Controllers;
|
||||
[ApiController]
|
||||
[ApiVersion("1.0")]
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[Authorize]
|
||||
|
||||
public class ActivityController : Controller
|
||||
{
|
||||
private readonly IActivityRepository _activityService;
|
||||
private readonly ILogger<ActivityController> _logger;
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly IDataSourceRepository<DataSourceTinyDto> _dataSourceRepository;
|
||||
|
||||
|
||||
public ActivityController(IDataManager dataManager, ILogger<ActivityController> logger)
|
||||
{
|
||||
_activityService = dataManager.ActivityRepo;
|
||||
_userRepository = dataManager.UserRepo;
|
||||
_dataSourceRepository = dataManager.DataSourceRepo;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ProducesResponseType(typeof(PageResponse<ActivityTinyDto>), 200)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(500)]
|
||||
public async Task<ActionResult<PageResponse<ActivityTinyDto>>> GetActivities([FromQuery] PageRequest pageRequest)
|
||||
{
|
||||
try
|
||||
{
|
||||
var totalCount = await _activityService.GetNbItems();
|
||||
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(GetActivities), pageRequest);
|
||||
var activities = await _activityService.GetActivities(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<ActivityTinyDto>(pageRequest.Index, pageRequest.Count, totalCount, activities);
|
||||
return Ok(pageResponse);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Error while getting all activities");
|
||||
return StatusCode(500);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> PostActivity(NewActivityDto activityDto)
|
||||
{
|
||||
_logger.LogInformation("Executing {Action} with parameters: {Parameters}, {add}", nameof(PostActivity), activityDto.Activity.Average, activityDto.HeartRates[0].Timestamp);
|
||||
var user = await _userRepository.GetUserTinyById(activityDto.AthleteId);
|
||||
if (user == null)
|
||||
{
|
||||
_logger.LogError("Athlete with id {id} not found", activityDto.AthleteId);
|
||||
return NotFound($"Athlete with id {activityDto.AthleteId} not found");
|
||||
}
|
||||
if (activityDto.DataSourceId != null)
|
||||
{
|
||||
var dataSource = await _dataSourceRepository.GetItemById(activityDto.DataSourceId.Value);
|
||||
|
||||
if (dataSource == null)
|
||||
{
|
||||
_logger.LogError("DataSource with id {id} not found", activityDto.DataSourceId);
|
||||
return NotFound($"DataSource with id {activityDto.DataSourceId} not found");
|
||||
}
|
||||
}
|
||||
|
||||
var result = await _activityService.AddActivity(activityDto);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
_logger.LogInformation("Activity added with id {id}", result.Id);
|
||||
|
||||
return CreatedAtAction(nameof(GetActivity), new { id = result.Id }, result);
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
public async Task<ActionResult<ResponseActivityDto>> GetActivity(int id)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetActivity), id);
|
||||
|
||||
var activity = await _activityService.GetActivityById(id);
|
||||
if (activity == null)
|
||||
{
|
||||
_logger.LogError("Activity with id {id} not found", id);
|
||||
|
||||
return NotFound($"Activity with id {id} not found");
|
||||
}
|
||||
return Ok(activity);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Error while getting activity by id {id}", id);
|
||||
return Problem();
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPut("{id}")]
|
||||
public async Task<IActionResult> PutActivity(int id, ActivityTinyDto activityDto)
|
||||
{
|
||||
var result = await _activityService.UpdateActivity(id, activityDto);
|
||||
if (result == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supprime une activity spécifique.
|
||||
/// </summary>
|
||||
/// <param name="id">L'identifiant de l'activity à supprimer.</param>
|
||||
/// <returns>Action result.</returns>
|
||||
/// <response code="200">Activity supprimé avec succès.</response>
|
||||
/// <response code="404">Activity non trouvé.</response>
|
||||
/// <response code="500">Erreur interne du serveur.</response>
|
||||
[HttpDelete("{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
[ProducesResponseType(500)]
|
||||
public async Task<IActionResult> DeleteActivity(int id)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(DeleteActivity), null,id);
|
||||
|
||||
|
||||
var activity = await _activityService.GetActivityByIdAsync(id);
|
||||
if (activity == null)
|
||||
{
|
||||
_logger.LogError("Activity with id {id} not found", id);
|
||||
return NotFound($"Activity with id {id} not found");
|
||||
}
|
||||
var isDeleted = await _activityService.DeleteActivity(id);
|
||||
if(!isDeleted)
|
||||
{
|
||||
_logger.LogError("Error while deleting activity with id {id}", id);
|
||||
return Problem("Error while deleting activity");
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Error while deleting activity");
|
||||
return Problem();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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
|
||||
};
|
||||
}*/
|
||||
}
|
@ -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());
|
||||
}
|
||||
*/
|
@ -1,26 +0,0 @@
|
||||
using Dto;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Shared;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/athletes")]
|
||||
public class AthletesController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<AthletesController> _logger;
|
||||
IAthleteService _stubbedDto;
|
||||
private const int DEFAULT_INDEX = 0, DEFAULT_COUNT = 5;
|
||||
|
||||
public AthletesController(ILogger<AthletesController> logger, IAthleteService athletesService)
|
||||
{
|
||||
_logger = logger;
|
||||
_stubbedDto = athletesService;
|
||||
}
|
||||
|
||||
[HttpGet("all")]
|
||||
[ProducesResponseType(typeof(IEnumerable<AthleteDto>), 200)]
|
||||
public async Task<IActionResult> GetAllAthletesAsync()
|
||||
{
|
||||
var athletes = await _stubbedDto.GetAllAthletesAsync();
|
||||
return Ok(athletes);
|
||||
}
|
||||
}
|
@ -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,366 @@
|
||||
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;
|
||||
/// <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]
|
||||
[ApiVersion("1.0")]
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[Authorize]
|
||||
public class UsersController : Controller
|
||||
{
|
||||
private readonly ILogger<UsersController> _logger;
|
||||
private readonly IActivityRepository _activityService;
|
||||
private readonly IUserRepository _userService;
|
||||
public UsersController(ILogger<UsersController> logger, IDataManager dataManager)
|
||||
{
|
||||
_logger = logger;
|
||||
_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. Met None par defaut et/ou si le critère n'est pas correct</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]
|
||||
[ProducesResponseType(typeof(PageResponse<UserTinyDto>), 200)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(500)]
|
||||
public async Task<ActionResult<PageResponse<UserTinyDto>>> 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<UserTinyDto>(request.Index, request.Count, totalCount, athletes);
|
||||
return Ok(pageResponse);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Error while getting all athletes");
|
||||
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}")]
|
||||
[ProducesResponseType(typeof(ResponseUserDto), 200)]
|
||||
[ProducesResponseType(404)]
|
||||
[ProducesResponseType(500)]
|
||||
public async Task<ActionResult<ResponseUserDto>> 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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <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")]
|
||||
[ProducesResponseType(typeof(int), 200)]
|
||||
[ProducesResponseType(500)]
|
||||
public async Task<ActionResult<int>> 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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <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}")]
|
||||
[ProducesResponseType(typeof(UserTinyDto), 200)]
|
||||
[ProducesResponseType(404)]
|
||||
[ProducesResponseType(500)]
|
||||
public async Task<ActionResult<UserTinyDto>> 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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <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}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
[ProducesResponseType(500)]
|
||||
public async Task<IActionResult> 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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <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<UserTinyDto>), 200)]
|
||||
[ProducesResponseType(404)]
|
||||
[ProducesResponseType(500)]
|
||||
public async Task<ActionResult<PageResponse<UserTinyDto>>> 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<UserTinyDto>(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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <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> 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <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 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();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/// <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<ActivityTinyDto>>> 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<ActivityTinyDto>(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();
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
|
||||
WORKDIR /src/HeartTrackAPI
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
RUN dotnet publish "HeartTrackAPI.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||
USER $APP_UID
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=build /app/publish .
|
||||
|
||||
EXPOSE 8080
|
||||
EXPOSE 8081
|
||||
|
||||
ENTRYPOINT ["dotnet", "HeartTrackAPI.dll"]
|
@ -1,6 +0,0 @@
|
||||
@HeartTrackAPI_HostAddress = http://localhost:5030
|
||||
|
||||
GET {{HeartTrackAPI_HostAddress}}/weatherforecast/
|
||||
Accept: application/json
|
||||
|
||||
###
|
@ -0,0 +1,12 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
namespace HeartTrackAPI.Request;
|
||||
|
||||
public class PageRequest
|
||||
{
|
||||
public string? OrderingPropertyName { get; set; } = null;
|
||||
public bool? Descending { get; set; } = false;
|
||||
public int Index { get; set; } = 0;
|
||||
public int Count { get; set; } = 1;
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
namespace HeartTrackAPI.Responce;
|
||||
|
||||
public class PageResponse<T>
|
||||
{
|
||||
// The index of the first item
|
||||
public int Index { get; set; } = 1;
|
||||
// The number of items
|
||||
public int Count { get; set; } = 1;
|
||||
// The total number of items
|
||||
public int Total { get; set; } = 1;
|
||||
// The items
|
||||
public IEnumerable<T> Items { get; set; }
|
||||
|
||||
public PageResponse(int index, int count, int total, IEnumerable<T> items)
|
||||
{
|
||||
Index = index;
|
||||
Count = count;
|
||||
Total = total;
|
||||
Items = items;
|
||||
}
|
||||
|
||||
}
|
@ -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,271 @@
|
||||
using System.Reflection;
|
||||
using DbContextLib;
|
||||
using Entities;
|
||||
using HeartTrackAPI.Services;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc.Versioning;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Model.Manager;
|
||||
using Model2Entities;
|
||||
using StubAPI;
|
||||
using StubbedContextLib;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
namespace HeartTrackAPI.Utils;
|
||||
|
||||
public class AppBootstrap(IConfiguration configuration)
|
||||
{
|
||||
private IConfiguration Configuration { get; } = configuration;
|
||||
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddControllers();
|
||||
|
||||
services.AddEndpointsApiExplorer();
|
||||
AddSwagger(services);
|
||||
AddHeartTrackContextServices(services);
|
||||
AddModelService(services);
|
||||
AddIdentityServices(services, configuration);
|
||||
AddApiVersioning(services);
|
||||
services.AddHealthChecks();
|
||||
}
|
||||
|
||||
private void AddHeartTrackContextServices(IServiceCollection services)
|
||||
{
|
||||
string? connectionString;
|
||||
|
||||
switch (Environment.GetEnvironmentVariable("TYPE"))
|
||||
{
|
||||
case "BDD":
|
||||
var host = Environment.GetEnvironmentVariable("HOST");
|
||||
var port = Environment.GetEnvironmentVariable("PORTDB");
|
||||
var database = Environment.GetEnvironmentVariable("DATABASE");
|
||||
var username = Environment.GetEnvironmentVariable("USERNAME");
|
||||
var password = Environment.GetEnvironmentVariable("PASSWORD");
|
||||
|
||||
connectionString = $"Server={host};port={port};database={database};user={username};password={password}";
|
||||
Console.WriteLine("========RUNNING USING THE MYSQL SERVER==============");
|
||||
Console.WriteLine(connectionString);
|
||||
Console.WriteLine("====================================================");
|
||||
services.AddDbContext<HeartTrackContext>(options =>
|
||||
options.UseMySql($"{connectionString}", new MySqlServerVersion(new Version(10, 11, 1)))
|
||||
, ServiceLifetime.Singleton);
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine("====== RUNNING USING THE IN SQLITE DATABASE ======");
|
||||
connectionString = Configuration.GetConnectionString("HeartTrackAuthConnection");
|
||||
Console.WriteLine(connectionString);
|
||||
if (!string.IsNullOrWhiteSpace(connectionString))
|
||||
{
|
||||
services.AddDbContext<TrainingStubbedContext>(options =>
|
||||
options.UseSqlite(connectionString), ServiceLifetime.Singleton);
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddDbContext<TrainingStubbedContext>();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void AddModelService(IServiceCollection services)
|
||||
{
|
||||
switch (Environment.GetEnvironmentVariable("TYPE"))
|
||||
{
|
||||
case "BDD":
|
||||
services.AddSingleton<IDataManager>(provider =>
|
||||
new DbDataManager(provider.GetRequiredService<HeartTrackContext>()));
|
||||
break;
|
||||
case "STUB-MODEL":
|
||||
services.AddSingleton<IDataManager, StubData>();
|
||||
break;
|
||||
default:
|
||||
services.AddSingleton<IDataManager>(provider =>
|
||||
{
|
||||
provider.GetRequiredService<TrainingStubbedContext>().Database.EnsureCreated();
|
||||
return new DbDataManager(provider.GetRequiredService<TrainingStubbedContext>());
|
||||
});
|
||||
|
||||
// services.AddSingleton<IDataManager>(provider => new DbDataManager(provider.GetRequiredService<TrainingStubbedContext>()));
|
||||
break;
|
||||
}
|
||||
// Auth
|
||||
|
||||
services.AddScoped<ITokenService, TokenService>();
|
||||
}
|
||||
|
||||
private void AddIdentityServices(IServiceCollection services, IConfiguration config)
|
||||
{
|
||||
/*services.AddAuthorization();
|
||||
services.AddIdentityApiEndpoints<AthleteEntity>()
|
||||
.AddEntityFrameworkStores<TrainingStubbedContext>();*/
|
||||
|
||||
var identityBuilder = services.AddIdentity<AthleteEntity, IdentityRole<int>>(options =>
|
||||
{
|
||||
options.Password.RequireDigit = true;
|
||||
options.Password.RequireLowercase = true;
|
||||
options.Password.RequireUppercase = true;
|
||||
options.Password.RequireNonAlphanumeric = true;
|
||||
options.Password.RequiredLength = 8;
|
||||
});
|
||||
|
||||
if (Environment.GetEnvironmentVariable("TYPE") == "BDD")
|
||||
{
|
||||
identityBuilder.AddEntityFrameworkStores<HeartTrackContext>();
|
||||
}
|
||||
else
|
||||
{
|
||||
identityBuilder.AddEntityFrameworkStores<TrainingStubbedContext>();
|
||||
}
|
||||
|
||||
services.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultAuthenticateScheme =
|
||||
options.DefaultChallengeScheme =
|
||||
options.DefaultForbidScheme =
|
||||
options.DefaultScheme =
|
||||
options.DefaultSignInScheme =
|
||||
options.DefaultSignOutScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
}).AddJwtBearer(options =>
|
||||
{
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = true,
|
||||
ValidIssuer =config["JWT:Issuer"],
|
||||
ValidateAudience = true,
|
||||
ValidAudience = config["JWT:Audience"],
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(
|
||||
System.Text.Encoding.UTF8.GetBytes(config["JWT:SigningKey"])
|
||||
)
|
||||
};
|
||||
});
|
||||
|
||||
/*
|
||||
app.UseCors(x => x
|
||||
.AllowAnyMethod()
|
||||
.AllowAnyHeader()
|
||||
.AllowCredentials()
|
||||
//.WithOrigins("https://localhost:44351))
|
||||
.SetIsOriginAllowed(origin => true));*/
|
||||
|
||||
// services.AddTransient<IEmailSender<AthleteEntity>, EmailSender>();
|
||||
// services.AddAuthorization();
|
||||
|
||||
// services.AddIdentityApiEndpoints<AthleteEntity>()
|
||||
// .AddEntityFrameworkStores<HeartTrackContext>();
|
||||
// .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);
|
||||
opt.ApiVersionReader = ApiVersionReader.Combine(new UrlSegmentApiVersionReader(),
|
||||
new HeaderApiVersionReader("x-api-version"),
|
||||
new MediaTypeApiVersionReader("x-api-version"));
|
||||
});
|
||||
}
|
||||
|
||||
private void AddSwagger(IServiceCollection services)
|
||||
{
|
||||
services.AddSwaggerGen(options =>
|
||||
{
|
||||
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.Http,
|
||||
Scheme = "Bearer",
|
||||
BearerFormat = "JWT"
|
||||
});
|
||||
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);
|
||||
options.OperationFilter<SwaggerDefaultValues>();
|
||||
});
|
||||
services.AddTransient<IConfigureOptions<SwaggerGenOptions>, SwaggerOptions>();
|
||||
|
||||
services.AddVersionedApiExplorer(setup =>
|
||||
{
|
||||
setup.GroupNameFormat = "'v'VVV";
|
||||
setup.SubstituteApiVersionInUrl = true;
|
||||
});
|
||||
}
|
||||
|
||||
public void Configure(WebApplication app, IWebHostEnvironment env)
|
||||
{
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
// app.MapIdentityApi<AthleteEntity>();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.MapHealthChecks("/health");
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (true)
|
||||
{
|
||||
app.UseSwagger(options =>
|
||||
{
|
||||
options.PreSerializeFilters.Add((swagger, httpReq) =>
|
||||
{
|
||||
if (httpReq.Headers.ContainsKey("X-Forwarded-Host"))
|
||||
{
|
||||
string basePath;
|
||||
switch (Environment.GetEnvironmentVariable("TYPE")) // httpReq.Host.Value
|
||||
{
|
||||
case "STUB":
|
||||
basePath = "containers/HeartDev-heart_stub";
|
||||
break;
|
||||
case "BDD":
|
||||
basePath = "containers/HeartDev-api";
|
||||
break;
|
||||
default:
|
||||
basePath = httpReq.Host.Value;
|
||||
break;
|
||||
}
|
||||
|
||||
var serverUrl = $"https://{httpReq.Headers["X-Forwarded-Host"]}/{basePath}";
|
||||
swagger.Servers = new List<OpenApiServer> { new() { Url = serverUrl } };
|
||||
}
|
||||
});
|
||||
});
|
||||
app.UseSwaggerUI();
|
||||
app.MapSwagger();
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Model;
|
||||
public class Activity
|
||||
{
|
||||
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; }
|
||||
|
||||
private int _effort;
|
||||
|
||||
[Range(0, 5)]
|
||||
public int Effort
|
||||
{
|
||||
get => _effort;
|
||||
set
|
||||
{
|
||||
if (value < 0 || value > 5)
|
||||
{
|
||||
throw new ArgumentException("Effort must be between 0 and 5.");
|
||||
}
|
||||
_effort = value;
|
||||
}
|
||||
}
|
||||
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 User Athlete { get; set; }
|
||||
public DataSource? DataSource { get; set; }
|
||||
public List<HeartRate> HeartRates { get; set; } = new List<HeartRate>();
|
||||
|
||||
public Activity(int id, string type, DateTime date, DateTime startTime, DateTime endTime, int effort, float variability, float variance, float standardDeviation, float average, int maximum, int minimum, float averageTemperature, bool hasAutoPause, User user, DataSource dataSource, List<HeartRate> heartRates)
|
||||
{
|
||||
Id = id;
|
||||
Type = type;
|
||||
Date = date;
|
||||
StartTime = startTime;
|
||||
EndTime = endTime;
|
||||
Effort = effort;
|
||||
Variability = variability;
|
||||
Variance = variance;
|
||||
StandardDeviation = standardDeviation;
|
||||
Average = average;
|
||||
Maximum = maximum;
|
||||
Minimum = minimum;
|
||||
AverageTemperature = averageTemperature;
|
||||
HasAutoPause = hasAutoPause;
|
||||
Athlete = user;
|
||||
DataSource = dataSource;
|
||||
HeartRates = heartRates;
|
||||
}
|
||||
public Activity(int id, string type, DateTime date, DateTime startTime, DateTime endTime, int effort, float variability, float variance, float standardDeviation, float average, int maximum, int minimum, float averageTemperature, bool hasAutoPause, User user){
|
||||
Id = id;
|
||||
Type = type;
|
||||
Date = date;
|
||||
StartTime = startTime;
|
||||
EndTime = endTime;
|
||||
Effort = effort;
|
||||
Variability = variability;
|
||||
Variance = variance;
|
||||
StandardDeviation = standardDeviation;
|
||||
Average = average;
|
||||
Maximum = maximum;
|
||||
Minimum = minimum;
|
||||
AverageTemperature = averageTemperature;
|
||||
HasAutoPause = hasAutoPause;
|
||||
Athlete = user;
|
||||
}
|
||||
public Activity(){}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Activity #{Id}: {Type} on {Date:d/M/yyyy} from {StartTime:HH:mm:ss} to {EndTime:HH:mm:ss}" +
|
||||
$" with an effort of {Effort}/5 and an average temperature of {AverageTemperature}°C" +
|
||||
$" and a heart rate variability of {Variability} bpm" +
|
||||
$" and a variance of {Variance} bpm" +
|
||||
$" and a standard deviation of {StandardDeviation} bpm" +
|
||||
$" and an average of {Average} bpm" +
|
||||
$" and a maximum of {Maximum} bpm" +
|
||||
$" and a minimum of {Minimum} bpm" +
|
||||
$" and auto pause is {(HasAutoPause ? "enabled" : "disabled")}.";
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
namespace Model;
|
||||
|
||||
public class Coach : Role
|
||||
{
|
||||
public override bool CheckAdd(User user)
|
||||
{
|
||||
return user.Role is Athlete;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "CoachAthlete";
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
namespace Model;
|
||||
|
||||
public class DataSource
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Type { get; set; }
|
||||
public string Model { get; set; }
|
||||
public float Precision { get; set; }
|
||||
public ICollection<Activity> Activities { get; set; } = new List<Activity>();
|
||||
public ICollection<User> Athletes { get; set; }
|
||||
|
||||
public DataSource(int id, string type, string model, float precision, ICollection<User> athletes, ICollection<Activity>? activities)
|
||||
{
|
||||
Id = id;
|
||||
Type = type;
|
||||
Model = model;
|
||||
Precision = precision;
|
||||
Athletes = athletes;
|
||||
Activities = activities;
|
||||
}
|
||||
public DataSource(string type, string model, float precision, ICollection<User> athletes, ICollection<Activity>? activities)
|
||||
: this(0, type, model, precision, athletes, activities)
|
||||
{}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"DataSource #{Id}: {Type} {Model} with a precision of {Precision}";
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
using Model.Repository;
|
||||
|
||||
namespace Model;
|
||||
|
||||
public static class EnumMappeur
|
||||
{
|
||||
public static Shared.AthleteOrderCriteria ToEnum(this IUserRepository repository, string? value)
|
||||
{
|
||||
return value switch
|
||||
{
|
||||
"None" => Shared.AthleteOrderCriteria.None,
|
||||
"ById" => Shared.AthleteOrderCriteria.ById,
|
||||
"ByUsername" => Shared.AthleteOrderCriteria.ByUsername,
|
||||
"ByFirstName" => Shared.AthleteOrderCriteria.ByFirstName,
|
||||
"ByLastName" => Shared.AthleteOrderCriteria.ByLastName,
|
||||
"BySexe" => Shared.AthleteOrderCriteria.BySexe,
|
||||
"ByLenght" => Shared.AthleteOrderCriteria.ByLenght,
|
||||
"ByWeight" => Shared.AthleteOrderCriteria.ByWeight,
|
||||
"ByDateOfBirth" => Shared.AthleteOrderCriteria.ByDateOfBirth,
|
||||
"ByEmail" => Shared.AthleteOrderCriteria.ByEmail,
|
||||
"ByRole" => Shared.AthleteOrderCriteria.ByRole,
|
||||
_ => Shared.AthleteOrderCriteria.None
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
namespace Model;
|
||||
|
||||
public class HeartRate
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int Bpm { get; set; }
|
||||
public TimeOnly Timestamp { get; set; }
|
||||
public Activity Activity { get; set; }
|
||||
public double? Latitude { get; set; }
|
||||
public double? Longitude { get; set; }
|
||||
public double? Altitude { 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; }
|
||||
|
||||
public HeartRate(int id, int bpm, TimeOnly timestamp, Activity activity, double? latitude, double? longitude, double? altitude, int? cadence, double? distance, double? speed, int? power, double? temperature)
|
||||
{
|
||||
Id = id;
|
||||
Bpm = bpm;
|
||||
Timestamp = timestamp;
|
||||
Activity = activity;
|
||||
Latitude = latitude;
|
||||
Longitude = longitude;
|
||||
Altitude = altitude;
|
||||
Cadence = cadence;
|
||||
Distance = distance;
|
||||
Speed = speed;
|
||||
Power = power;
|
||||
Temperature = temperature;
|
||||
}
|
||||
|
||||
|
||||
public HeartRate(int bpm, TimeOnly timestamp, Activity activity, double? latitude, double? longitude, double? altitude, int? cadence, double? distance, double? speed, int? power, double? temperature)
|
||||
: this(0, bpm, timestamp, activity, latitude, longitude, altitude, cadence, distance, speed, power, temperature)
|
||||
{}
|
||||
|
||||
public HeartRate(int bpm, TimeOnly timestamp, int activity, double? latitude, double? longitude, double? altitude, int? cadence, double? distance, double? speed, int? power, double? temperature)
|
||||
: this(0, bpm, timestamp, null, latitude, longitude, altitude, cadence, distance, speed, power, temperature)
|
||||
{}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"HeartRate #{Id}: {Bpm} bpm at {Timestamp:HH:mm:ss} with a temperature of {Temperature}°C" +
|
||||
$" and an altitude of {Altitude}m at {Longitude}°E and {Latitude}°N";
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
namespace Model;
|
||||
|
||||
public class LargeImage : IEquatable<LargeImage>
|
||||
{
|
||||
public string Base64 { get; set; }
|
||||
|
||||
public LargeImage(string base64)
|
||||
{
|
||||
Base64 = base64;
|
||||
}
|
||||
|
||||
public bool Equals(LargeImage? other)
|
||||
=> other != null && other.Base64.Equals(Base64);
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if(ReferenceEquals(obj, null)) return false;
|
||||
if(ReferenceEquals(obj!, this)) return true;
|
||||
if(GetType() != obj!.GetType()) return false;
|
||||
return Equals(obj! as LargeImage);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
=> Base64.Substring(0, 10).GetHashCode();
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
using Dto.Tiny;
|
||||
using Model.Repository;
|
||||
|
||||
namespace Model.Manager;
|
||||
|
||||
public interface IDataManager
|
||||
{
|
||||
IUserRepository UserRepo { get; }
|
||||
IActivityRepository ActivityRepo { get; }
|
||||
|
||||
IDataSourceRepository<DataSourceTinyDto> DataSourceRepo { get; }
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
namespace Model;
|
||||
|
||||
public class Notification
|
||||
{
|
||||
|
||||
public int IdNotif { get; private set; }
|
||||
public string Message { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
public bool Statut { get; set; }
|
||||
public string Urgence { get; set; }
|
||||
public int ToUserId { get; set; }
|
||||
|
||||
public Notification(int id,string message, DateTime date, bool statut, string urgence, int toUserId)
|
||||
{
|
||||
this.IdNotif = id;
|
||||
this.Message = message;
|
||||
this.Date = date;
|
||||
this.Statut = statut;
|
||||
this.Urgence = urgence;
|
||||
this.ToUserId = toUserId;
|
||||
}
|
||||
|
||||
public Notification(){}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue