diff --git a/.drone.yml b/.drone.yml index 1a6f708..5fa128c 100644 --- a/.drone.yml +++ b/.drone.yml @@ -10,31 +10,64 @@ trigger: steps: - name: build - image: hub.codefirst.iut.uca.fr/marc.chevaldonne/codefirst-dotnet8:latest + 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: - # accessible en ligne de commande par ${PLUGIN_SONAR_HOST} sonar_host: https://codefirst.iut.uca.fr/sonar/ - # accessible en ligne de commande par ${SONAR_TOKEN} 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" /d:sonar.host.url=$${PLUGIN_SONAR_HOST} /d:sonar.login=$${SONAR_TOKEN} + - 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.csproj -c Release --no-restore -o $CI_PROJECT_DIR/build/release -f:net8 - - dotnet sonarscanner end /d:sonar.login=$${SONAR_TOKEN} - + - 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:8.0 + failure: ignore + volumes: + - name: docs + path: /docs + environment: + CODEFIRST_CLIENTDRONE_ENV_DOTNET_ROLL_FORWARD: LatestMajor + CODEFIRST_CLIENTDRONE_ENV_DOTNET_ROLL_FORWARD_TO_PRERELEASE: 1 + commands: + - cd src/ + - dotnet restore HeartTrack.sln + - cd HeartTrackAPI + - dotnet new tool-manifest + - dotnet tool install -g --version 6.5.0 Swashbuckle.AspNetCore.Cli + - cd ../ + - dotnet build HeartTrack.sln -c Release --no-restore + - dotnet publish HeartTrack.sln -c Release --no-restore -o CI_PROJECT_DIR/build/release + - export PATH="$PATH:/root/.dotnet/tools" + - swagger tofile --output /docs/swagger.json HeartTrackAPI/bin/Release/net8.0/HeartTrackAPI.dll v1 + depends_on: [build,tests] + - name: generate-and-deploy-docs image: hub.codefirst.iut.uca.fr/maxime.batista/codefirst-docdeployer failure: ignore @@ -42,4 +75,100 @@ steps: - /entrypoint.sh -l docs/doxygen -t doxygen when: event: - - push \ No newline at end of file + - 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: false + CODEFIRST_CLIENTDRONE_ENV_MARIADB_ROOT_PASSWORD: + from_secret: db_root_password + CODEFIRST_CLIENTDRONE_ENV_MARIADB_DATABASE: + from_secret: db_database + CODEFIRST_CLIENTDRONE_ENV_MARIADB_USER: + from_secret: db_user + CODEFIRST_CLIENTDRONE_ENV_MARIADB_PASSWORD: + from_secret: db_password + ADMINS: davidd_almeida,kevinmonteiro,antoineperederii,paullevrault,antoinepinagot,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,camillepetitalot + COMMAND: create + OVERWRITE: true + depends_on: [deploy-container-mysql, docker-build-and-push, deploy-container-stub] \ No newline at end of file diff --git a/.gitignore b/.gitignore index 6d8621c..284650c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ ## files generated by popular Visual Studio add-ons. ## ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore - # User-specific files *.rsuser *.suo @@ -498,7 +497,8 @@ fabric.properties .LSOverride # Icon must end with two \r -Icon +Icon + # Thumbnails ._* @@ -548,3 +548,24 @@ xcuserdata/ *.xcscmblueprint *.xccheckout + +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/.idea.HeartTrack.iml +/modules.xml +/projectSettingsUpdater.xml +/contentModel.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +.ideaMigration/ +Migration/ +Migrations/ + +*.db +*.db-shm +*.db-wal \ No newline at end of file diff --git a/README.md b/README.md index e00e2f0..2db5c57 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,167 @@ -# EF_WebAPI +
-This repository make a meeting of EF and WebAPI parts. \ No newline at end of file +

HeartTrack

+ + +
+ + + +
+ + + +--- +  ![C#](https://img.shields.io/badge/C%23-000?style=for-the-badge&logo=c-sharp&logoColor=white&color=purple) +  ![Entity Framework](https://img.shields.io/badge/Entity_Framework-000?style=for-the-badge&logo=.net&logoColor=white&color=blue) +  ![API](https://img.shields.io/badge/API-000?style=for-the-badge&logo=api&logoColor=white&color=orange) + +
+ +[![Build Status](https://codefirst.iut.uca.fr/api/badges/HeartDev/API/status.svg)](https://codefirst.iut.uca.fr/HeartDev/API) +[![Bugs](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=HeartTrack-API&metric=bugs&token=c3e0444eb978e1d346ed0041c552b24870316a03)](https://codefirst.iut.uca.fr/sonar/dashboard?id=HeartTrack-API) +[![Coverage](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=HeartTrack-API&metric=coverage&token=c3e0444eb978e1d346ed0041c552b24870316a03)](https://codefirst.iut.uca.fr/sonar/dashboard?id=HeartTrack-API) +[![Duplicated Lines (%)](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=HeartTrack-API&metric=duplicated_lines_density&token=c3e0444eb978e1d346ed0041c552b24870316a03)](https://codefirst.iut.uca.fr/sonar/dashboard?id=HeartTrack-API) +[![Maintainability Rating](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=HeartTrack-API&metric=sqale_rating&token=c3e0444eb978e1d346ed0041c552b24870316a03)](https://codefirst.iut.uca.fr/sonar/dashboard?id=HeartTrack-API) +[![Reliability Rating](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=HeartTrack-API&metric=reliability_rating&token=c3e0444eb978e1d346ed0041c552b24870316a03)](https://codefirst.iut.uca.fr/sonar/dashboard?id=HeartTrack-API) +[![Security Rating](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=HeartTrack-API&metric=security_rating&token=c3e0444eb978e1d346ed0041c552b24870316a03)](https://codefirst.iut.uca.fr/sonar/dashboard?id=HeartTrack-API) +[![Vulnerabilities](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=HeartTrack-API&metric=vulnerabilities&token=c3e0444eb978e1d346ed0041c552b24870316a03)](https://codefirst.iut.uca.fr/sonar/dashboard?id=HeartTrack-API) + + +
+ +# 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. + +### 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 +* [![.NET 8.0](https://img.shields.io/badge/Langage-.NET-000?style=for-the-badge&logo=.net&logoColor=white&color=blue)](https://dotnet.microsoft.com/download/dotnet/8.0) +* [![Entity Framework](https://img.shields.io/badge/ORM-Entity_Framework-000?style=for-the-badge&logo=.net&logoColor=white&color=blue)](https://docs.microsoft.com/fr-fr/ef/) +* [![API](https://img.shields.io/badge/API-000?style=for-the-badge&logo=api&logoColor=white&color=orange)](https://docs.microsoft.com/fr-fr/aspnet/core/web-api/?view=aspnetcore-8.0) +* [![Visual Studio](https://img.shields.io/badge/IDE-Visual_Studio-000?style=for-the-badge&logo=visual-studio&logoColor=white&color=purple)](https://visualstudio.microsoft.com/fr/) +* [![Git](https://img.shields.io/badge/Versioning-Git-000?style=for-the-badge&logo=git&logoColor=white&color=red)](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 +![.NET](https://img.shields.io/badge/Langage-.NET-000?style=for-the-badge&logo=.net&logoColor=white&color=blue) +![Entity Framework](https://img.shields.io/badge/ORM-Entity_Framework-000?style=for-the-badge&logo=.net&logoColor=white&color=blue) +![API](https://img.shields.io/badge/API-000?style=for-the-badge&logo=api&logoColor=white&color=orange) +![ASP.NET](https://img.shields.io/badge/ASP.NET-000?style=for-the-badge&logo=asp.net&logoColor=white&color=blue) +![Visual Studio](https://img.shields.io/badge/IDE-Visual_Studio-000?style=for-the-badge&logo=visual-studio&logoColor=white&color=purple) +![JetBrains Rider](https://img.shields.io/badge/IDE-JetBrains_Rider-000?style=for-the-badge&logo=rider&logoColor=white&color=purple) +![Git](https://img.shields.io/badge/Versioning-Git-000?style=for-the-badge&logo=git&logoColor=white&color=red) +![SonarQube](https://img.shields.io/badge/Qualit%C3%A9-SonarQube-000?style=for-the-badge&logo=sonarqube&logoColor=white&color=red) +![Drone](https://img.shields.io/badge/CI-Drone-000?style=for-the-badge&logo=drone&logoColor=white&color=orange) +![Docker](https://img.shields.io/badge/Container-Docker-000?style=for-the-badge&logo=docker&logoColor=white&color=blue) +![C#](https://img.shields.io/badge/Langage-C%23-000?style=for-the-badge&logo=c-sharp&logoColor=white&color=purple) +![Doxygen](https://img.shields.io/badge/Documentation-Doxygen-000?style=for-the-badge&logo=doxygen&logoColor=white&color=blue) + + + +## 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 () +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. \ No newline at end of file diff --git a/docs/Diagramme/BDD/MLD.plantuml b/docs/Diagramme/BDD/MLD.plantuml new file mode 100755 index 0000000..cdf6bec --- /dev/null +++ b/docs/Diagramme/BDD/MLD.plantuml @@ -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 \ No newline at end of file diff --git a/docs/Diagramme/BDD/README_BDD.md b/docs/Diagramme/BDD/README_BDD.md new file mode 100644 index 0000000..63d6db6 --- /dev/null +++ b/docs/Diagramme/BDD/README_BDD.md @@ -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 +``` \ No newline at end of file diff --git a/docs/Diagramme/CasUtilisations/README_coachSuiviSportif.md b/docs/Diagramme/CasUtilisations/README_coachSuiviSportif.md new file mode 100644 index 0000000..9ca737e --- /dev/null +++ b/docs/Diagramme/CasUtilisations/README_coachSuiviSportif.md @@ -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) : <> +(Ajouter un athlète)..>(S'authentifier) : <> +(Supprimer un athlète)..>(S'authentifier) : <> +(Afficher ses athlètes )..>(S'authentifier) : <> +(Afficher les activités de tous les athlètes)..>(S'authentifier) : <> +(S'authentifier)..>(S'inscrire) : <> +(S'inscrire).>(Inscription Coach) : <> +(S'authentifier)..>(Se connecter) : <> +(Afficher ses athlètes )..>(Voir les activités d'un athlète) : <> +(Afficher ses athlètes )..>(Voir les stats d'un athlète) : <> +(Afficher les activités de tous les athlètes)..>(Sélectionner une activité) : <> +(Sélectionner une activité)..>(Voir l'analyse) : <> +(Sélectionner une activité)..>(Exporter l'analyse) : <> +(Voir les activités d'un athlète)..>(Voir l'analyse) : <> +(Voir les activités d'un athlète)..>(Exporter l'analyse) : <> +``` \ No newline at end of file diff --git a/docs/Diagramme/CasUtilisations/README_gestionActivites.md b/docs/Diagramme/CasUtilisations/README_gestionActivites.md new file mode 100644 index 0000000..3cf26db --- /dev/null +++ b/docs/Diagramme/CasUtilisations/README_gestionActivites.md @@ -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) : <> +a --> (Exporter mes données) +(Exporter mes données) .>(Exporter toutes les activités): <> +(Exporter mes données) ..>(Exporter une activité): <> +a --> (Ajouter une activité) +(Ajouter une activité) ..>(Saisir un titre et une description): <> +(Ajouter une activité) ..>(Saisir le type d'activité): <> +(Ajouter une activité) .>(Saisir la source): <> +(Saisir la source) ..>(Saisir le matériel utilisé): <> +(Ajouter une activité) ..>(Saisir la visibilité): <> +a --> (Voir une activité) +(Voir une activité) ..>(Exporter l'analyse): <> +(Voir une activité) ..>(Saisir la visibilité): <> +a --> (Supprimer une activité) +(Supprimer une activité) ..>(S'authentifier): <> +(Importer des données) ...>(S'authentifier): <> +(Exporter mes données) ...>(S'authentifier): <> +(Ajouter une activité) ...>(S'authentifier): <> +(Voir une activité) ...>(S'authentifier): <> +``` \ No newline at end of file diff --git a/docs/Diagramme/CasUtilisations/README_gestionCompteAmitie.md b/docs/Diagramme/CasUtilisations/README_gestionCompteAmitie.md new file mode 100644 index 0000000..495c918 --- /dev/null +++ b/docs/Diagramme/CasUtilisations/README_gestionCompteAmitie.md @@ -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) : <> +(Ajouter un ami)..>(S'authentifier) : <> +(Voir mes amis)..>(S'authentifier) : <> +(Voir mes amis)..>(Lister les amis) : <> +(Modifier mes informations)..>(Informations personnelles) : <> +(Modifier mes informations)..>(Informations de connexion) : <> +(Modifier mes informations)..>(S'authentifier) : <> +(Lister les amis)..>(Voir son profil) : <> +(Voir son profil)..>(Voir ses activités) : <> +(Voir son profil)..>(Voir ses statistiques) : <> +(S'authentifier)..>(S'inscrire) : <> +(S'authentifier)..>(Se connecter) : <> +(S'inscrire)..>(Inscription Athlète) : <> +``` \ No newline at end of file diff --git a/docs/Diagramme/DiagrammeDeClasses/DiagrammeClasses.mdj b/docs/Diagramme/DiagrammeDeClasses/DiagrammeClasses.mdj new file mode 100644 index 0000000..c543891 --- /dev/null +++ b/docs/Diagramme/DiagrammeDeClasses/DiagrammeClasses.mdj @@ -0,0 +1,16708 @@ +{ + "_type": "Project", + "_id": "AAAAAAFF+h6SjaM2Hec=", + "name": "Untitled", + "ownedElements": [ + { + "_type": "UMLModel", + "_id": "AAAAAAFF+qBWK6M3Z8Y=", + "_parent": { + "$ref": "AAAAAAFF+h6SjaM2Hec=" + }, + "name": "Model", + "ownedElements": [ + { + "_type": "UMLClassDiagram", + "_id": "AAAAAAFF+qBtyKM79qY=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Main", + "defaultDiagram": true, + "ownedViews": [ + { + "_type": "UMLClassView", + "_id": "AAAAAAGL3Bpk6Nh7nd8=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL3Bpk6Nh8Lq8=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6Nh7nd8=" + }, + "model": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL3Bpk6Nh9hPU=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6Nh8Lq8=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 7438, + "top": 4026, + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3Bpk6Nh+Fwc=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6Nh8Lq8=" + }, + "font": "Arial;13;1", + "left": 3933, + "top": 1975, + "width": 134.05615234375, + "height": 13, + "text": "Utilisateur" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3Bpk6Nh/isA=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6Nh8Lq8=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 7438, + "top": 4026, + "width": 83.560546875, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3Bpk6NiAZ5I=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6Nh8Lq8=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 7438, + "top": 4026, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 3928, + "top": 1968, + "width": 144.05615234375, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGL3Bpk6Nh9hPU=" + }, + "nameLabel": { + "$ref": "AAAAAAGL3Bpk6Nh+Fwc=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL3Bpk6Nh/isA=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3Bpk6NiAZ5I=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL3Bpk6NiBNB8=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6Nh7nd8=" + }, + "model": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL+9pbIrmYC30=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6NiBNB8=" + }, + "model": { + "$ref": "AAAAAAGL+9pa8rlijfg=" + }, + "font": "Arial;13;0", + "left": 3933, + "top": 1998, + "width": 134.05615234375, + "height": 13, + "text": "-id: int", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL4p5p1eRDPvQ=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6NiBNB8=" + }, + "model": { + "$ref": "AAAAAAGL4p5pjeQNzxA=" + }, + "font": "Arial;13;0", + "left": 3933, + "top": 2013, + "width": 134.05615234375, + "height": 13, + "text": "-username: String", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3Bpk6NiCaQg=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6NiBNB8=" + }, + "model": { + "$ref": "AAAAAAGLpAD5vx0yijE=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 7915, + "top": 4408, + "width": 63.2353515625, + "height": 13, + "text": "+id", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3Bpk6NiDSjc=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6NiBNB8=" + }, + "model": { + "$ref": "AAAAAAGLpAHrOB1Dmpw=" + }, + "font": "Arial;13;0", + "left": 3933, + "top": 2028, + "width": 134.05615234375, + "height": 13, + "text": "-nom: String", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3Bpk6NiEgW4=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6NiBNB8=" + }, + "model": { + "$ref": "AAAAAAGLpAHubx1JTgc=" + }, + "font": "Arial;13;0", + "left": 3933, + "top": 2043, + "width": 134.05615234375, + "height": 13, + "text": "-prenom: String", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3Bpk6NiFn9A=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6NiBNB8=" + }, + "model": { + "$ref": "AAAAAAGLpAHxSR1PUSs=" + }, + "font": "Arial;13;0", + "left": 3933, + "top": 2058, + "width": 134.05615234375, + "height": 13, + "text": "-email: String", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3Bpk6NiGtyQ=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6NiBNB8=" + }, + "model": { + "$ref": "AAAAAAGLpAH0SB1VgF8=" + }, + "font": "Arial;13;0", + "left": 3933, + "top": 2073, + "width": 134.05615234375, + "height": 13, + "text": "-sexe: String", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3Bpk6NiHvyA=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6NiBNB8=" + }, + "model": { + "$ref": "AAAAAAGLpAH2wh1b3Gg=" + }, + "font": "Arial;13;0", + "left": 3933, + "top": 2088, + "width": 134.05615234375, + "height": 13, + "text": "-taille: Float", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3Bpk6NiIsq0=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6NiBNB8=" + }, + "model": { + "$ref": "AAAAAAGLpAH5dB1h8j4=" + }, + "font": "Arial;13;0", + "left": 3933, + "top": 2103, + "width": 134.05615234375, + "height": 13, + "text": "-poids: float", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3Bpk6NiJqPU=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6NiBNB8=" + }, + "model": { + "$ref": "AAAAAAGLpAH8Jx1ngTU=" + }, + "font": "Arial;13;0", + "left": 3933, + "top": 2118, + "width": 134.05615234375, + "height": 13, + "text": "-motDePasse: String", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3Bpk6NiKgHM=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6NiBNB8=" + }, + "model": { + "$ref": "AAAAAAGLpAH+3B1t8HQ=" + }, + "font": "Arial;13;0", + "left": 3933, + "top": 2133, + "width": 134.05615234375, + "height": 13, + "text": "-dateNaissance: Date", + "horizontalAlignment": 0 + } + ], + "font": "Arial;13;0", + "left": 3928, + "top": 1993, + "width": 144.05615234375, + "height": 158 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL3Bpk6NiLdbA=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6Nh7nd8=" + }, + "model": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "font": "Arial;13;0", + "left": 3928, + "top": 2151, + "width": 144.05615234375, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL3Bpk6NiMKQ0=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6Nh7nd8=" + }, + "model": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3456, + "top": 1616, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL3Bpk6NiNkKc=", + "_parent": { + "$ref": "AAAAAAGL3Bpk6Nh7nd8=" + }, + "model": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3456, + "top": 1616, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 3928, + "top": 1968, + "width": 144.05615234375, + "height": 193, + "nameCompartment": { + "$ref": "AAAAAAGL3Bpk6Nh8Lq8=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL3Bpk6NiBNB8=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL3Bpk6NiLdbA=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL3Bpk6NiMKQ0=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL3Bpk6NiNkKc=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL3BqoCyTo5V4=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL3BqoCyTpW4g=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTo5V4=" + }, + "model": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL3BqoCyTqEq4=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTpW4g=" + }, + "font": "Arial;13;0", + "left": 3941, + "top": 2237, + "width": 459.21484375, + "height": 13, + "text": "«abstract»" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3BqoCyTr0yo=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTpW4g=" + }, + "font": "Arial;13;1", + "left": 3941, + "top": 2252, + "width": 459.21484375, + "height": 13, + "text": "Role" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3BqoCyTsjzM=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTpW4g=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 5049, + "top": 2094, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3BqoCyTt63k=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTpW4g=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 5049, + "top": 2094, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 3936, + "top": 2232, + "width": 469.21484375, + "height": 38, + "stereotypeLabel": { + "$ref": "AAAAAAGL3BqoCyTqEq4=" + }, + "nameLabel": { + "$ref": "AAAAAAGL3BqoCyTr0yo=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL3BqoCyTsjzM=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3BqoCyTt63k=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL3BqoCyTuNbk=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTo5V4=" + }, + "model": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3EO8K52/YfM=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTuNbk=" + }, + "model": { + "$ref": "AAAAAAGL3EO77J2JFbo=" + }, + "font": "Arial;13;0", + "left": 3941, + "top": 2275, + "width": 459.21484375, + "height": 13, + "text": "#id: int", + "horizontalAlignment": 0 + } + ], + "font": "Arial;13;0", + "left": 3936, + "top": 2270, + "width": 469.21484375, + "height": 23 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL3BqoCyTvFJU=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTo5V4=" + }, + "model": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL8lDIXnknspM=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTvFJU=" + }, + "model": { + "$ref": "AAAAAAGL8lDIQHjxa7g=" + }, + "font": "Arial;13;0", + "left": 3941, + "top": 2298, + "width": 459.21484375, + "height": 13, + "text": "+getUsersList(): ?array", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL+91tPmZKyM8=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTvFJU=" + }, + "model": { + "$ref": "AAAAAAGL+91tC2YUaHo=" + }, + "font": "Arial;13;0", + "left": 3941, + "top": 2313, + "width": 459.21484375, + "height": 13, + "text": "+getUserList(user: User): ?User", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL+93wGZ1DB2g=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTvFJU=" + }, + "model": { + "$ref": "AAAAAAGL+93v8Z0NH0E=" + }, + "font": "Arial;13;0", + "left": 3941, + "top": 2328, + "width": 459.21484375, + "height": 13, + "text": "+getEntrainement(): ?EntrainementRepository", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL+90Kslfv1ko=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTvFJU=" + }, + "model": { + "$ref": "AAAAAAGL+90Kble5JDw=" + }, + "font": "Arial;13;0", + "left": 3941, + "top": 2343, + "width": 459.21484375, + "height": 13, + "text": "+getEntrainementsList(): ?array", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL+95cBqY03KQ=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTvFJU=" + }, + "model": { + "$ref": "AAAAAAGL+95b8qX+sig=" + }, + "font": "Arial;13;0", + "left": 3941, + "top": 2358, + "width": 459.21484375, + "height": 13, + "text": "+getEntrainementList(entrainement: Entrainement): ?EntrainementSportif", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL8lQnvRSBOMg=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTvFJU=" + }, + "model": { + "$ref": "AAAAAAGL8lQnmhRLfho=" + }, + "font": "Arial;13;0", + "left": 3941, + "top": 2373, + "width": 459.21484375, + "height": 13, + "text": "+checkAdd(user: User): bool", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL8lRO7h1yezo=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTvFJU=" + }, + "model": { + "$ref": "AAAAAAGL8lROwx08WBA=" + }, + "font": "Arial;13;0", + "left": 3941, + "top": 2388, + "width": 459.21484375, + "height": 13, + "text": "+chackAddEntrainement(entrainement: Entrainement): bool", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL3B61kj4t0Y8=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTvFJU=" + }, + "model": { + "$ref": "AAAAAAGL3B61dD33CBk=" + }, + "font": "Arial;13;0", + "left": 3941, + "top": 2403, + "width": 459.21484375, + "height": 13, + "text": "+addUser(user: User): bool", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL58RPQfS6YrU=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTvFJU=" + }, + "model": { + "$ref": "AAAAAAGL58RPF/SE7Hs=" + }, + "font": "Arial;13;0", + "left": 3941, + "top": 2418, + "width": 459.21484375, + "height": 13, + "text": "+removeUser(user: User): bool", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL8lBBRXGB2H8=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTvFJU=" + }, + "model": { + "$ref": "AAAAAAGL8lBBHXFLScI=" + }, + "font": "Arial;13;0", + "left": 3941, + "top": 2433, + "width": 459.21484375, + "height": 13, + "text": "+addEntrainement(entr: Entrainement): bool", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL++FfCiqny8U=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTvFJU=" + }, + "model": { + "$ref": "AAAAAAGL++Fe3CpxsSg=" + }, + "font": "Arial;13;0", + "left": 3941, + "top": 2448, + "width": 459.21484375, + "height": 13, + "text": "+removeEntrainement(entr: Entrainement): bool", + "horizontalAlignment": 0 + } + ], + "font": "Arial;13;0", + "left": 3936, + "top": 2293, + "width": 469.21484375, + "height": 173 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL3BqoCyTwnlw=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTo5V4=" + }, + "model": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2240, + "top": 536, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL3BqoCyTxlpY=", + "_parent": { + "$ref": "AAAAAAGL3BqoCyTo5V4=" + }, + "model": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2240, + "top": 536, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 3936, + "top": 2232, + "width": 469.21484375, + "height": 264, + "nameCompartment": { + "$ref": "AAAAAAGL3BqoCyTpW4g=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL3BqoCyTuNbk=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL3BqoCyTvFJU=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL3BqoCyTwnlw=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL3BqoCyTxlpY=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAGL3BrkEXIgRp8=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL3BrkDnIc/Ag=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3BrkEnIhgag=", + "_parent": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + }, + "model": { + "$ref": "AAAAAAGL3BrkDnIc/Ag=" + }, + "font": "Arial;13;0", + "left": 4111, + "top": 2234, + "width": 29.26904296875, + "height": 13, + "alpha": 0.3204269313614675, + "distance": 68.41052550594829, + "hostEdge": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + }, + "edgePosition": 1, + "text": "+role" + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3BrkEnIiuII=", + "_parent": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + }, + "model": { + "$ref": "AAAAAAGL3BrkDnIc/Ag=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 4099, + "top": 2174, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3BrkEnIj/vY=", + "_parent": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + }, + "model": { + "$ref": "AAAAAAGL3BrkDnIc/Ag=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4061, + "top": 2197, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3BrkEnIk2Ck=", + "_parent": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + }, + "model": { + "$ref": "AAAAAAGL3BrkD3IdNgc=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4080, + "top": 2169, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3BrkEnIlv/8=", + "_parent": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + }, + "model": { + "$ref": "AAAAAAGL3BrkD3IdNgc=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4092, + "top": 2165, + "height": 13, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3BrkEnImsmA=", + "_parent": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + }, + "model": { + "$ref": "AAAAAAGL3BrkD3IdNgc=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4054, + "top": 2179, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3BrkEnInNc8=", + "_parent": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + }, + "model": { + "$ref": "AAAAAAGL3BrkD3IeED0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4094, + "top": 2195, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3BrkEnIofzw=", + "_parent": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + }, + "model": { + "$ref": "AAAAAAGL3BrkD3IeED0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4105, + "top": 2186, + "height": 13, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3BrkEnIpNCY=", + "_parent": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + }, + "model": { + "$ref": "AAAAAAGL3BrkD3IeED0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4073, + "top": 2212, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + } + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL3BrkE3IqKYk=", + "_parent": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + }, + "model": { + "$ref": "AAAAAAGL3BrkD3IdNgc=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 664, + "top": 560, + "width": 10, + "height": 10 + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL3BrkE3IrgMo=", + "_parent": { + "$ref": "AAAAAAGL3BrkEXIgRp8=" + }, + "model": { + "$ref": "AAAAAAGL3BrkD3IeED0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 664, + "top": 560, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL3BqoCyTo5V4=" + }, + "tail": { + "$ref": "AAAAAAGL3Bpk6Nh7nd8=" + }, + "lineStyle": 1, + "points": "4054:2161;4095:2231", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL3BrkEnIhgag=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL3BrkEnIiuII=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3BrkEnIj/vY=" + }, + "showEndOrder": "hide", + "tailRoleNameLabel": { + "$ref": "AAAAAAGL3BrkEnIk2Ck=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAGL3BrkEnIlv/8=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAGL3BrkEnImsmA=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAGL3BrkEnInNc8=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAGL3BrkEnIofzw=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAGL3BrkEnIpNCY=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAGL3BrkE3IqKYk=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAGL3BrkE3IrgMo=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL3BsTqaEI6W8=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL3BsTqaEJsn8=", + "_parent": { + "$ref": "AAAAAAGL3BsTqaEI6W8=" + }, + "model": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL3BsTqaEKhxM=", + "_parent": { + "$ref": "AAAAAAGL3BsTqaEJsn8=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 8083, + "top": 4718, + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3BsTqaELxcM=", + "_parent": { + "$ref": "AAAAAAGL3BsTqaEJsn8=" + }, + "font": "Arial;13;1", + "left": 4189, + "top": 2551, + "width": 171.62158203125, + "height": 13, + "text": "Athlete" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3BsTqaEMDwE=", + "_parent": { + "$ref": "AAAAAAGL3BsTqaEJsn8=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 8083, + "top": 4718, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3BsTqaENG6Q=", + "_parent": { + "$ref": "AAAAAAGL3BsTqaEJsn8=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 8083, + "top": 4718, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 4184, + "top": 2544, + "width": 181.62158203125, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGL3BsTqaEKhxM=" + }, + "nameLabel": { + "$ref": "AAAAAAGL3BsTqaELxcM=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL3BsTqaEMDwE=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3BsTqaENG6Q=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL3BsTqaEO6QI=", + "_parent": { + "$ref": "AAAAAAGL3BsTqaEI6W8=" + }, + "model": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "font": "Arial;13;0", + "left": 4184, + "top": 2569, + "width": 181.62158203125, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL3BsTqaEQWyw=", + "_parent": { + "$ref": "AAAAAAGL3BsTqaEI6W8=" + }, + "model": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL3Cav/l7YrXw=", + "_parent": { + "$ref": "AAAAAAGL3BsTqaEQWyw=" + }, + "model": { + "$ref": "AAAAAAGL3Cav216fXX4=" + }, + "font": "Arial;13;0", + "left": 4189, + "top": 2584, + "width": 171.62158203125, + "height": 13, + "text": "+getAthlete(): Athlete", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL3CcA8mU47Ao=", + "_parent": { + "$ref": "AAAAAAGL3BsTqaEQWyw=" + }, + "model": { + "$ref": "AAAAAAGL3CcA1GT//kE=" + }, + "font": "Arial;13;0", + "left": 4189, + "top": 2599, + "width": 171.62158203125, + "height": 13, + "text": "+getActivite(): lesActivite", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL3DDNi5ul+XY=", + "_parent": { + "$ref": "AAAAAAGL3BsTqaEQWyw=" + }, + "model": { + "$ref": "AAAAAAGL3DDNcZtsRlI=" + }, + "font": "Arial;13;0", + "left": 4189, + "top": 2614, + "width": 171.62158203125, + "height": 13, + "text": "+getStatistiques(): lesStats", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL3EaR8i1ibdU=", + "_parent": { + "$ref": "AAAAAAGL3BsTqaEQWyw=" + }, + "model": { + "$ref": "AAAAAAGL3EaRsi0pEF4=" + }, + "font": "Arial;13;0", + "left": 4189, + "top": 2629, + "width": 171.62158203125, + "height": 13, + "text": "+getSourceDonnees(): lesSD", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL3DEwIp45CMc=", + "_parent": { + "$ref": "AAAAAAGL3BsTqaEQWyw=" + }, + "model": { + "$ref": "AAAAAAGL3DEwGp4As4s=" + }, + "font": "Arial;13;0", + "left": 4189, + "top": 2644, + "width": 171.62158203125, + "height": 13, + "text": "+__toString(): String", + "horizontalAlignment": 0 + } + ], + "font": "Arial;13;0", + "left": 4184, + "top": 2579, + "width": 181.62158203125, + "height": 83 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL3BsTqaERJ/c=", + "_parent": { + "$ref": "AAAAAAGL3BsTqaEI6W8=" + }, + "model": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3672, + "top": 1728, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL3BsTqaESBEk=", + "_parent": { + "$ref": "AAAAAAGL3BsTqaEI6W8=" + }, + "model": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3672, + "top": 1728, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 4184, + "top": 2544, + "width": 181.62158203125, + "height": 193, + "nameCompartment": { + "$ref": "AAAAAAGL3BsTqaEJsn8=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL3BsTqaEO6QI=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL3BsTqaEQWyw=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL3BsTqaERJ/c=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL3BsTqaESBEk=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL3BtJt/VYyF0=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL3BtJt/VZIHE=", + "_parent": { + "$ref": "AAAAAAGL3BtJt/VYyF0=" + }, + "model": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL3BtJt/Va6uM=", + "_parent": { + "$ref": "AAAAAAGL3BtJt/VZIHE=" + }, + "font": "Arial;13;0", + "left": 3757, + "top": 2549, + "width": 145.58984375, + "height": 13, + "text": "«abstract»" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3BtJt/Vb5Cg=", + "_parent": { + "$ref": "AAAAAAGL3BtJt/VZIHE=" + }, + "font": "Arial;13;1", + "left": 3757, + "top": 2564, + "width": 145.58984375, + "height": 13, + "text": "Coach" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3BtJt/VcVGI=", + "_parent": { + "$ref": "AAAAAAGL3BtJt/VZIHE=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 6001, + "top": 5422, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3BtJt/VdTcw=", + "_parent": { + "$ref": "AAAAAAGL3BtJt/VZIHE=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 6001, + "top": 5422, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 3752, + "top": 2544, + "width": 155.58984375, + "height": 38, + "stereotypeLabel": { + "$ref": "AAAAAAGL3BtJt/Va6uM=" + }, + "nameLabel": { + "$ref": "AAAAAAGL3BtJt/Vb5Cg=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL3BtJt/VcVGI=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3BtJt/VdTcw=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL3BtJt/VeAHE=", + "_parent": { + "$ref": "AAAAAAGL3BtJt/VYyF0=" + }, + "model": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + }, + "font": "Arial;13;0", + "left": 3752, + "top": 2582, + "width": 155.58984375, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL3BtJt/VgHOE=", + "_parent": { + "$ref": "AAAAAAGL3BtJt/VYyF0=" + }, + "model": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + }, + "font": "Arial;13;0", + "left": 3752, + "top": 2592, + "width": 155.58984375, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL3BtJt/Vh00A=", + "_parent": { + "$ref": "AAAAAAGL3BtJt/VYyF0=" + }, + "model": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2880, + "top": 2080, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL3BtJt/ViK6I=", + "_parent": { + "$ref": "AAAAAAGL3BtJt/VYyF0=" + }, + "model": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2880, + "top": 2080, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 3752, + "top": 2544, + "width": 155.58984375, + "height": 65, + "nameCompartment": { + "$ref": "AAAAAAGL3BtJt/VZIHE=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL3BtJt/VeAHE=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL3BtJt/VgHOE=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL3BtJt/Vh00A=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL3BtJt/ViK6I=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAGL3B0Tspu8D9c=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL3B0TsZu6iEw=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3B0Ts5u9bfM=", + "_parent": { + "$ref": "AAAAAAGL3B0Tspu8D9c=" + }, + "model": { + "$ref": "AAAAAAGL3B0TsZu6iEw=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3988, + "top": 2560, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3B0Tspu8D9c=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3B0Ts5u+QVY=", + "_parent": { + "$ref": "AAAAAAGL3B0Tspu8D9c=" + }, + "model": { + "$ref": "AAAAAAGL3B0TsZu6iEw=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 3976, + "top": 2551, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3B0Tspu8D9c=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3B0Ts5u/JUw=", + "_parent": { + "$ref": "AAAAAAGL3B0Tspu8D9c=" + }, + "model": { + "$ref": "AAAAAAGL3B0TsZu6iEw=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4011, + "top": 2579, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3B0Tspu8D9c=" + }, + "edgePosition": 1 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL3BqoCyTo5V4=" + }, + "tail": { + "$ref": "AAAAAAGL3BsTqaEI6W8=" + }, + "lineStyle": 1, + "points": "4183:2619;4000:2576;4064:2496", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL3B0Ts5u9bfM=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL3B0Ts5u+QVY=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3B0Ts5u/JUw=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAGL3B0hqKVLIeI=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL3B0hp6VJcj4=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3B0hqaVMQzU=", + "_parent": { + "$ref": "AAAAAAGL3B0hqKVLIeI=" + }, + "model": { + "$ref": "AAAAAAGL3B0hp6VJcj4=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3988, + "top": 2560, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3B0hqKVLIeI=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3B0hqaVNgVQ=", + "_parent": { + "$ref": "AAAAAAGL3B0hqKVLIeI=" + }, + "model": { + "$ref": "AAAAAAGL3B0hp6VJcj4=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 3976, + "top": 2551, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3B0hqKVLIeI=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3B0hqaVO884=", + "_parent": { + "$ref": "AAAAAAGL3B0hqKVLIeI=" + }, + "model": { + "$ref": "AAAAAAGL3B0hp6VJcj4=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4011, + "top": 2579, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3B0hqKVLIeI=" + }, + "edgePosition": 1 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL3BqoCyTo5V4=" + }, + "tail": { + "$ref": "AAAAAAGL3BtJt/VYyF0=" + }, + "lineStyle": 1, + "points": "3908:2576;4000:2576;4064:2496", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL3B0hqaVMQzU=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL3B0hqaVNgVQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3B0hqaVO884=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAGL3B3/zPI/wtk=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL3B3/yvI7wq4=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3B3/zPJAevY=", + "_parent": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + }, + "model": { + "$ref": "AAAAAAGL3B3/yvI7wq4=" + }, + "font": "Arial;13;0", + "left": 3838, + "top": 2031, + "width": 76.24169921875, + "height": 13, + "alpha": -0.6874078923357949, + "distance": 209.60200380721554, + "hostEdge": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + }, + "edgePosition": 1, + "text": "#*lesUsers" + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3B3/zPJBn8k=", + "_parent": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + }, + "model": { + "$ref": "AAAAAAGL3B3/yvI7wq4=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 3714, + "top": 2193, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3B3/zPJC3Oo=", + "_parent": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + }, + "model": { + "$ref": "AAAAAAGL3B3/yvI7wq4=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3759, + "top": 2194, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3B3/zPJDWvc=", + "_parent": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + }, + "model": { + "$ref": "AAAAAAGL3B3/yvI8/hQ=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3908, + "top": 2360, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3B3/zPJEM5A=", + "_parent": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + }, + "model": { + "$ref": "AAAAAAGL3B3/yvI8/hQ=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3905, + "top": 2373, + "height": 13, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3B3/zPJFcmY=", + "_parent": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + }, + "model": { + "$ref": "AAAAAAGL3B3/yvI8/hQ=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3913, + "top": 2333, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3B3/zPJGtMk=", + "_parent": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + }, + "model": { + "$ref": "AAAAAAGL3B3/yvI9HQU=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3901, + "top": 2040, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3B3/zfJH08c=", + "_parent": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + }, + "model": { + "$ref": "AAAAAAGL3B3/yvI9HQU=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3899, + "top": 2026, + "height": 13, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3B3/zfJI3Gs=", + "_parent": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + }, + "model": { + "$ref": "AAAAAAGL3B3/yvI9HQU=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3904, + "top": 2067, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + } + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL3B3/zfJJbDQ=", + "_parent": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + }, + "model": { + "$ref": "AAAAAAGL3B3/yvI8/hQ=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 664, + "top": 560, + "width": 10, + "height": 10 + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL3B3/zfJKKCk=", + "_parent": { + "$ref": "AAAAAAGL3B3/zPI/wtk=" + }, + "model": { + "$ref": "AAAAAAGL3B3/yvI9HQU=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 664, + "top": 560, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL3Bpk6Nh7nd8=" + }, + "tail": { + "$ref": "AAAAAAGL3BqoCyTo5V4=" + }, + "lineStyle": 1, + "points": "3935:2353;3744:2344;3744:2056;3927:2062", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL3B3/zPJAevY=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL3B3/zPJBn8k=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3B3/zPJC3Oo=" + }, + "showEndOrder": "hide", + "tailRoleNameLabel": { + "$ref": "AAAAAAGL3B3/zPJDWvc=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAGL3B3/zPJEM5A=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAGL3B3/zPJFcmY=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAGL3B3/zPJGtMk=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAGL3B3/zfJH08c=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAGL3B3/zfJI3Gs=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAGL3B3/zfJJbDQ=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAGL3B3/zfJKKCk=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL3CMxnUgw9Qc=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL3CMxnEguLCQ=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL3CMxnUgxJhM=", + "_parent": { + "$ref": "AAAAAAGL3CMxnUgw9Qc=" + }, + "model": { + "$ref": "AAAAAAGL3CMxnEguLCQ=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL3CMxnUgy8AA=", + "_parent": { + "$ref": "AAAAAAGL3CMxnUgxJhM=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 1328, + "top": 1120, + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3CMxnUgztGY=", + "_parent": { + "$ref": "AAAAAAGL3CMxnUgxJhM=" + }, + "font": "Arial;13;1", + "left": 3469, + "top": 2575, + "width": 135.47802734375, + "height": 13, + "text": "CoachAthlete" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3CMxnkg0N2A=", + "_parent": { + "$ref": "AAAAAAGL3CMxnUgxJhM=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 1328, + "top": 1120, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3CMxnkg1xaw=", + "_parent": { + "$ref": "AAAAAAGL3CMxnUgxJhM=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 1328, + "top": 1120, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 3464, + "top": 2568, + "width": 145.47802734375, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGL3CMxnUgy8AA=" + }, + "nameLabel": { + "$ref": "AAAAAAGL3CMxnUgztGY=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL3CMxnkg0N2A=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3CMxnkg1xaw=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL3CMxnkg25RI=", + "_parent": { + "$ref": "AAAAAAGL3CMxnUgw9Qc=" + }, + "model": { + "$ref": "AAAAAAGL3CMxnEguLCQ=" + }, + "font": "Arial;13;0", + "left": 3464, + "top": 2593, + "width": 145.47802734375, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL3CMxnkg3D5k=", + "_parent": { + "$ref": "AAAAAAGL3CMxnUgw9Qc=" + }, + "model": { + "$ref": "AAAAAAGL3CMxnEguLCQ=" + }, + "font": "Arial;13;0", + "left": 3464, + "top": 2603, + "width": 145.47802734375, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL3CMxnkg4o/Y=", + "_parent": { + "$ref": "AAAAAAGL3CMxnUgw9Qc=" + }, + "model": { + "$ref": "AAAAAAGL3CMxnEguLCQ=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 664, + "top": 560, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL3CMxnkg5gG4=", + "_parent": { + "$ref": "AAAAAAGL3CMxnUgw9Qc=" + }, + "model": { + "$ref": "AAAAAAGL3CMxnEguLCQ=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 664, + "top": 560, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 3464, + "top": 2568, + "width": 145.47802734375, + "height": 58, + "nameCompartment": { + "$ref": "AAAAAAGL3CMxnUgxJhM=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL3CMxnkg25RI=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL3CMxnkg3D5k=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL3CMxnkg4o/Y=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL3CMxnkg5gG4=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAGL3CS00llKDD4=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL3CS00FlI+OY=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3CS001lLo9U=", + "_parent": { + "$ref": "AAAAAAGL3CS00llKDD4=" + }, + "model": { + "$ref": "AAAAAAGL3CS00FlI+OY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3678, + "top": 2565, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3CS00llKDD4=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3CS01FlMCgk=", + "_parent": { + "$ref": "AAAAAAGL3CS00llKDD4=" + }, + "model": { + "$ref": "AAAAAAGL3CS00FlI+OY=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 3677, + "top": 2550, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3CS00llKDD4=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3CS01FlNYLY=", + "_parent": { + "$ref": "AAAAAAGL3CS00llKDD4=" + }, + "model": { + "$ref": "AAAAAAGL3CS00FlI+OY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3681, + "top": 2594, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3CS00llKDD4=" + }, + "edgePosition": 1 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL3BtJt/VYyF0=" + }, + "tail": { + "$ref": "AAAAAAGL3CMxnUgw9Qc=" + }, + "lineStyle": 1, + "points": "3609:2591;3751:2581", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL3CS001lLo9U=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL3CS01FlMCgk=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3CS01FlNYLY=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL3DH0VM3eelw=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL3DH0VM3fysc=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3eelw=" + }, + "model": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL3DH0VM3gY5o=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3fysc=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 7526, + "top": 5046, + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3DH0VM3hGX8=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3fysc=" + }, + "font": "Arial;13;1", + "left": 4253, + "top": 2983, + "width": 185.3388671875, + "height": 13, + "text": "Activite" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3DH0VM3iMEw=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3fysc=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 7526, + "top": 5046, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3DH0VM3j6No=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3fysc=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 7526, + "top": 5046, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 4248, + "top": 2976, + "width": 195.3388671875, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGL3DH0VM3gY5o=" + }, + "nameLabel": { + "$ref": "AAAAAAGL3DH0VM3hGX8=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL3DH0VM3iMEw=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3DH0VM3j6No=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL3DH0VM3kbjc=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3eelw=" + }, + "model": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DH0VM3lc5Y=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3kbjc=" + }, + "model": { + "$ref": "AAAAAAGLpCXSK/WOLkA=" + }, + "font": "Arial;13;0", + "left": 4253, + "top": 3006, + "width": 185.3388671875, + "height": 13, + "text": "-idActivite: int", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DH0VM3mS/0=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3kbjc=" + }, + "model": { + "$ref": "AAAAAAGLrxCVfeebjRQ=" + }, + "font": "Arial;13;0", + "left": 4253, + "top": 3021, + "width": 185.3388671875, + "height": 13, + "text": "-type: string", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DH0VM3n7eQ=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3kbjc=" + }, + "model": { + "$ref": "AAAAAAGLrxCvKejL/fw=" + }, + "font": "Arial;13;0", + "left": 4253, + "top": 3036, + "width": 185.3388671875, + "height": 13, + "text": "-date: Date", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DH0VM3oMXE=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3kbjc=" + }, + "model": { + "$ref": "AAAAAAGLrxDHu+n7GHc=" + }, + "font": "Arial;13;0", + "left": 4253, + "top": 3051, + "width": 185.3388671875, + "height": 13, + "text": "-heureDebut: time", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DH0VM3pTPo=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3kbjc=" + }, + "model": { + "$ref": "AAAAAAGLrxDu8esr6vo=" + }, + "font": "Arial;13;0", + "left": 4253, + "top": 3066, + "width": 185.3388671875, + "height": 13, + "text": "-heureFin: time", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DH0VM3q4W0=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3kbjc=" + }, + "model": { + "$ref": "AAAAAAGLrxEIwOxboHI=" + }, + "font": "Arial;13;0", + "left": 4253, + "top": 3081, + "width": 185.3388671875, + "height": 13, + "text": "-effortRessenti: int", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DH0VM3rtcU=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3kbjc=" + }, + "model": { + "$ref": "AAAAAAGLrxJXpe2Lor0=" + }, + "font": "Arial;13;0", + "left": 4253, + "top": 3096, + "width": 185.3388671875, + "height": 13, + "text": "-variabilite: float", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DH0VM3s3TU=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3kbjc=" + }, + "model": { + "$ref": "AAAAAAGLrxKISe67v6E=" + }, + "font": "Arial;13;0", + "left": 4253, + "top": 3111, + "width": 185.3388671875, + "height": 13, + "text": "-variance: float", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DH0VM3tB54=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3kbjc=" + }, + "model": { + "$ref": "AAAAAAGLrxKpzu/rHo4=" + }, + "font": "Arial;13;0", + "left": 4253, + "top": 3126, + "width": 185.3388671875, + "height": 13, + "text": "-ecartType: float", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DH0VM3uR/M=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3kbjc=" + }, + "model": { + "$ref": "AAAAAAGLrxLaO/Ebr8k=" + }, + "font": "Arial;13;0", + "left": 4253, + "top": 3141, + "width": 185.3388671875, + "height": 13, + "text": "-moyenne: float", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DH0VM3v9vo=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3kbjc=" + }, + "model": { + "$ref": "AAAAAAGLrxL5PfJLk04=" + }, + "font": "Arial;13;0", + "left": 4253, + "top": 3156, + "width": 185.3388671875, + "height": 13, + "text": "-maximum: int", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DH0VM3wYUA=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3kbjc=" + }, + "model": { + "$ref": "AAAAAAGLrxM0SfWY9pQ=" + }, + "font": "Arial;13;0", + "left": 4253, + "top": 3171, + "width": 185.3388671875, + "height": 13, + "text": "-minimum: int", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DH0VM3xJcc=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3kbjc=" + }, + "model": { + "$ref": "AAAAAAGLrxNQCvbIr2U=" + }, + "font": "Arial;13;0", + "left": 4253, + "top": 3186, + "width": 185.3388671875, + "height": 13, + "text": "-TemperatureMoyenne: float", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGMBkKgGyoAcM4=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3kbjc=" + }, + "model": { + "$ref": "AAAAAAGMBkKf7yn3AyI=" + }, + "font": "Arial;13;0", + "left": 4253, + "top": 3201, + "width": 185.3388671875, + "height": 13, + "text": "-pause: bool", + "horizontalAlignment": 0 + } + ], + "font": "Arial;13;0", + "left": 4248, + "top": 3001, + "width": 195.3388671875, + "height": 218 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL3DH0VM3yGA4=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3eelw=" + }, + "model": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL3DQ2l6ufcOo=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3yGA4=" + }, + "model": { + "$ref": "AAAAAAGL3DQ2catj1/Q=" + }, + "font": "Arial;13;0", + "left": 4253, + "top": 3224, + "width": 185.3388671875, + "height": 13, + "text": "+getActivite(): Activite", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL3DTgR8iexiI=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3yGA4=" + }, + "model": { + "$ref": "AAAAAAGL3DTgKchiipU=" + }, + "font": "Arial;13;0", + "left": 4253, + "top": 3239, + "width": 185.3388671875, + "height": 13, + "text": "+getAnalyse(a1: Activite): String", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL3DXeXM52u3o=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3yGA4=" + }, + "model": { + "$ref": "AAAAAAGL3DXeGc46SeI=" + }, + "font": "Arial;13;0", + "left": 4253, + "top": 3254, + "width": 185.3388671875, + "height": 13, + "text": "+toString(Activite): String", + "horizontalAlignment": 0 + } + ], + "font": "Arial;13;0", + "left": 4248, + "top": 3219, + "width": 195.3388671875, + "height": 53 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL3DH0VM3zpCE=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3eelw=" + }, + "model": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3504, + "top": 1728, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL3DH0VM30Qm4=", + "_parent": { + "$ref": "AAAAAAGL3DH0VM3eelw=" + }, + "model": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3504, + "top": 1728, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 4248, + "top": 2976, + "width": 195.3388671875, + "height": 296, + "nameCompartment": { + "$ref": "AAAAAAGL3DH0VM3fysc=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL3DH0VM3kbjc=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL3DH0VM3yGA4=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL3DH0VM3zpCE=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL3DH0VM30Qm4=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL3DJHyBCPzHA=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL3DJHyBCQzFI=", + "_parent": { + "$ref": "AAAAAAGL3DJHyBCPzHA=" + }, + "model": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL3DJHyRCRIbE=", + "_parent": { + "$ref": "AAAAAAGL3DJHyBCQzFI=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 7468, + "top": 3944, + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3DJHyRCSG8Y=", + "_parent": { + "$ref": "AAAAAAGL3DJHyBCQzFI=" + }, + "font": "Arial;13;1", + "left": 4581, + "top": 2471, + "width": 177.39794921875, + "height": 13, + "text": "Statistique" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3DJHyRCTKdI=", + "_parent": { + "$ref": "AAAAAAGL3DJHyBCQzFI=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 7468, + "top": 3944, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3DJHyRCUC6A=", + "_parent": { + "$ref": "AAAAAAGL3DJHyBCQzFI=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 7468, + "top": 3944, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 4576, + "top": 2464, + "width": 187.39794921875, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGL3DJHyRCRIbE=" + }, + "nameLabel": { + "$ref": "AAAAAAGL3DJHyRCSG8Y=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL3DJHyRCTKdI=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3DJHyRCUC6A=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL3DJHyRCVwdU=", + "_parent": { + "$ref": "AAAAAAGL3DJHyBCPzHA=" + }, + "model": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DJHyRCWvV0=", + "_parent": { + "$ref": "AAAAAAGL3DJHyRCVwdU=" + }, + "model": { + "$ref": "AAAAAAGLrwixuGGJpE4=" + }, + "font": "Arial;13;0", + "left": 4581, + "top": 2494, + "width": 177.39794921875, + "height": 13, + "text": "-idStatistique: int", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DJHyRCXojk=", + "_parent": { + "$ref": "AAAAAAGL3DJHyRCVwdU=" + }, + "model": { + "$ref": "AAAAAAGLrwlhdmOIz0E=" + }, + "font": "Arial;13;0", + "left": 4581, + "top": 2509, + "width": 177.39794921875, + "height": 13, + "text": "-distanceTotale: float", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DJHyRCYR9w=", + "_parent": { + "$ref": "AAAAAAGL3DJHyRCVwdU=" + }, + "model": { + "$ref": "AAAAAAGLrwmwgWUPuog=" + }, + "font": "Arial;13;0", + "left": 4581, + "top": 2524, + "width": 177.39794921875, + "height": 13, + "text": "-poids: float", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DJHyRCZ9DA=", + "_parent": { + "$ref": "AAAAAAGL3DJHyRCVwdU=" + }, + "model": { + "$ref": "AAAAAAGLrwnYLWYeNa4=" + }, + "font": "Arial;13;0", + "left": 4581, + "top": 2539, + "width": 177.39794921875, + "height": 13, + "text": "-tempsTotal: time", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DJHyRCavHw=", + "_parent": { + "$ref": "AAAAAAGL3DJHyRCVwdU=" + }, + "model": { + "$ref": "AAAAAAGLrwoPTGct0ws=" + }, + "font": "Arial;13;0", + "left": 4581, + "top": 2554, + "width": 177.39794921875, + "height": 13, + "text": "-FCmoyenne: int", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DJHyRCbZAA=", + "_parent": { + "$ref": "AAAAAAGL3DJHyRCVwdU=" + }, + "model": { + "$ref": "AAAAAAGLrwps72g8dI8=" + }, + "font": "Arial;13;0", + "left": 4581, + "top": 2569, + "width": 177.39794921875, + "height": 13, + "text": "-FCmin: int", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DJHyRCc4c8=", + "_parent": { + "$ref": "AAAAAAGL3DJHyRCVwdU=" + }, + "model": { + "$ref": "AAAAAAGLrwqb7mlLpYw=" + }, + "font": "Arial;13;0", + "left": 4581, + "top": 2584, + "width": 177.39794921875, + "height": 13, + "text": "-FCmax: int", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DJHyRCd7DA=", + "_parent": { + "$ref": "AAAAAAGL3DJHyRCVwdU=" + }, + "model": { + "$ref": "AAAAAAGLrwq/JGpaMCs=" + }, + "font": "Arial;13;0", + "left": 4581, + "top": 2599, + "width": 177.39794921875, + "height": 13, + "text": "-caloriesBrulées: int", + "horizontalAlignment": 0 + } + ], + "font": "Arial;13;0", + "left": 4576, + "top": 2489, + "width": 187.39794921875, + "height": 128 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL3DJHyRCealo=", + "_parent": { + "$ref": "AAAAAAGL3DJHyBCPzHA=" + }, + "model": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL3EVASgrSjt4=", + "_parent": { + "$ref": "AAAAAAGL3DJHyRCealo=" + }, + "model": { + "$ref": "AAAAAAGL3EVAEQqWm2c=" + }, + "font": "Arial;13;0", + "left": 4581, + "top": 2622, + "width": 177.39794921875, + "height": 13, + "text": "+getStatistique(): Statistique", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL3EWyfxByyz4=", + "_parent": { + "$ref": "AAAAAAGL3DJHyRCealo=" + }, + "model": { + "$ref": "AAAAAAGL3EWydxA200E=" + }, + "font": "Arial;13;0", + "left": 4581, + "top": 2637, + "width": 177.39794921875, + "height": 13, + "text": "+__toString(Statistique): String", + "horizontalAlignment": 0 + } + ], + "font": "Arial;13;0", + "left": 4576, + "top": 2617, + "width": 187.39794921875, + "height": 38 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL3DJHyRCfEJM=", + "_parent": { + "$ref": "AAAAAAGL3DJHyBCPzHA=" + }, + "model": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3488, + "top": 1456, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL3DJHyRCggVc=", + "_parent": { + "$ref": "AAAAAAGL3DJHyBCPzHA=" + }, + "model": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3488, + "top": 1456, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 4576, + "top": 2464, + "width": 187.39794921875, + "height": 191, + "nameCompartment": { + "$ref": "AAAAAAGL3DJHyBCQzFI=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL3DJHyRCVwdU=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL3DJHyRCealo=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL3DJHyRCfEJM=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL3DJHyRCggVc=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL3DLQlyYtiTQ=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGLpCqsVQhTM54=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL3DLQlyYubF0=", + "_parent": { + "$ref": "AAAAAAGL3DLQlyYtiTQ=" + }, + "model": { + "$ref": "AAAAAAGLpCqsVQhTM54=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL3DLQlyYvw2U=", + "_parent": { + "$ref": "AAAAAAGL3DLQlyYubF0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 6878, + "top": 3818, + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3DLQmCYwFXU=", + "_parent": { + "$ref": "AAAAAAGL3DLQlyYubF0=" + }, + "font": "Arial;13;1", + "left": 3997, + "top": 2807, + "width": 196.193359375, + "height": 13, + "text": "SourceDonnee" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3DLQmCYxQMk=", + "_parent": { + "$ref": "AAAAAAGL3DLQlyYubF0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 6878, + "top": 3818, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3DLQmCYyi5c=", + "_parent": { + "$ref": "AAAAAAGL3DLQlyYubF0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 6878, + "top": 3818, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 3992, + "top": 2800, + "width": 206.193359375, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGL3DLQlyYvw2U=" + }, + "nameLabel": { + "$ref": "AAAAAAGL3DLQmCYwFXU=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL3DLQmCYxQMk=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3DLQmCYyi5c=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL3DLQmCYzLJk=", + "_parent": { + "$ref": "AAAAAAGL3DLQlyYtiTQ=" + }, + "model": { + "$ref": "AAAAAAGLpCqsVQhTM54=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DLQmCY0y+0=", + "_parent": { + "$ref": "AAAAAAGL3DLQmCYzLJk=" + }, + "model": { + "$ref": "AAAAAAGLrxTIICbUAdU=" + }, + "font": "Arial;13;0", + "left": 3997, + "top": 2830, + "width": 196.193359375, + "height": 13, + "text": "-idSource: int", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DLQmCY1DTA=", + "_parent": { + "$ref": "AAAAAAGL3DLQmCYzLJk=" + }, + "model": { + "$ref": "AAAAAAGLrxTswiiLUpA=" + }, + "font": "Arial;13;0", + "left": 3997, + "top": 2845, + "width": 196.193359375, + "height": 13, + "text": "-Type: enum", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DLQmCY2rE8=", + "_parent": { + "$ref": "AAAAAAGL3DLQmCYzLJk=" + }, + "model": { + "$ref": "AAAAAAGLrxVKVSm7bms=" + }, + "font": "Arial;13;0", + "left": 3997, + "top": 2860, + "width": 196.193359375, + "height": 13, + "text": "-modele: string", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DLQmCY31Ao=", + "_parent": { + "$ref": "AAAAAAGL3DLQmCYzLJk=" + }, + "model": { + "$ref": "AAAAAAGLrxV3+SrrCr8=" + }, + "font": "Arial;13;0", + "left": 3997, + "top": 2875, + "width": 196.193359375, + "height": 13, + "text": "-precision: enum", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DLQmCY46yk=", + "_parent": { + "$ref": "AAAAAAGL3DLQmCYzLJk=" + }, + "model": { + "$ref": "AAAAAAGLrxWfnSwbQ58=" + }, + "font": "Arial;13;0", + "left": 3997, + "top": 2890, + "width": 196.193359375, + "height": 13, + "text": "-dateDerniereUtilisation: Date", + "horizontalAlignment": 0 + } + ], + "font": "Arial;13;0", + "left": 3992, + "top": 2825, + "width": 206.193359375, + "height": 83 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL3DLQmCY54P8=", + "_parent": { + "$ref": "AAAAAAGL3DLQlyYtiTQ=" + }, + "model": { + "$ref": "AAAAAAGLpCqsVQhTM54=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL3EcVKzvuuFk=", + "_parent": { + "$ref": "AAAAAAGL3DLQmCY54P8=" + }, + "model": { + "$ref": "AAAAAAGL3EcVFjuykz0=" + }, + "font": "Arial;13;0", + "left": 3997, + "top": 2913, + "width": 196.193359375, + "height": 13, + "text": "+getSD(SourceDonnee): String", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL3Eee900OLuk=", + "_parent": { + "$ref": "AAAAAAGL3DLQmCY54P8=" + }, + "model": { + "$ref": "AAAAAAGL3EeezUzS6YA=" + }, + "font": "Arial;13;0", + "left": 3997, + "top": 2928, + "width": 196.193359375, + "height": 13, + "text": "+to_String(SourceDonnee): String", + "horizontalAlignment": 0 + } + ], + "font": "Arial;13;0", + "left": 3992, + "top": 2908, + "width": 206.193359375, + "height": 38 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL3DLQmCY6OQc=", + "_parent": { + "$ref": "AAAAAAGL3DLQlyYtiTQ=" + }, + "model": { + "$ref": "AAAAAAGLpCqsVQhTM54=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3280, + "top": 1352, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL3DLQmCY7Ngc=", + "_parent": { + "$ref": "AAAAAAGL3DLQlyYtiTQ=" + }, + "model": { + "$ref": "AAAAAAGLpCqsVQhTM54=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3280, + "top": 1352, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 3992, + "top": 2800, + "width": 206.193359375, + "height": 146, + "nameCompartment": { + "$ref": "AAAAAAGL3DLQlyYubF0=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL3DLQmCYzLJk=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL3DLQmCY54P8=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL3DLQmCY6OQc=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL3DLQmCY7Ngc=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL3DMzZkmwpP8=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL3DMzZkmx2TA=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkmwpP8=" + }, + "model": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL3DMzZkmyRDk=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkmx2TA=" + }, + "font": "Arial;13;0", + "left": 3357, + "top": 2885, + "width": 165.115234375, + "height": 13, + "text": "«abstract»" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3DMzZkmzoys=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkmx2TA=" + }, + "font": "Arial;13;1", + "left": 3357, + "top": 2900, + "width": 165.115234375, + "height": 13, + "text": "Entrainement" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3DMzZkm0anw=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkmx2TA=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4809, + "top": 2930, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3DMzZkm1g4k=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkmx2TA=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4809, + "top": 2930, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 3352, + "top": 2880, + "width": 175.115234375, + "height": 38, + "stereotypeLabel": { + "$ref": "AAAAAAGL3DMzZkmyRDk=" + }, + "nameLabel": { + "$ref": "AAAAAAGL3DMzZkmzoys=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL3DMzZkm0anw=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3DMzZkm1g4k=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL3DMzZkm2VYs=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkmwpP8=" + }, + "model": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DMzZkm3yLU=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkm2VYs=" + }, + "model": { + "$ref": "AAAAAAGLrxcxm0yu9ck=" + }, + "font": "Arial;13;0", + "left": 3357, + "top": 2923, + "width": 165.115234375, + "height": 13, + "text": "+idEntrainement: int", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DMzZkm45Gk=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkm2VYs=" + }, + "model": { + "$ref": "AAAAAAGLrxdjg05lkd0=" + }, + "font": "Arial;13;0", + "left": 3357, + "top": 2938, + "width": 165.115234375, + "height": 13, + "text": "+date: Date", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL7QbRQNBhx7c=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkm2VYs=" + }, + "model": { + "$ref": "AAAAAAGL7QbRBNAl41g=" + }, + "font": "Arial;13;0", + "left": 3357, + "top": 2953, + "width": 165.115234375, + "height": 13, + "text": "+latitude: float", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DMzZkm59RQ=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkm2VYs=" + }, + "model": { + "$ref": "AAAAAAGLrxeDFU+VhpI=" + }, + "font": "Arial;13;0", + "left": 3357, + "top": 2968, + "width": 165.115234375, + "height": 13, + "text": "+longitude: float", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DMzZkm6JIs=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkm2VYs=" + }, + "model": { + "$ref": "AAAAAAGLrxezwlDFkh4=" + }, + "font": "Arial;13;0", + "left": 3357, + "top": 2983, + "width": 165.115234375, + "height": 13, + "text": "+description: text", + "horizontalAlignment": 0 + }, + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL3DMzZkm7L1c=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkm2VYs=" + }, + "model": { + "$ref": "AAAAAAGLrxfiTFH1ArI=" + }, + "font": "Arial;13;0", + "left": 3357, + "top": 2998, + "width": 165.115234375, + "height": 13, + "text": "+feedback: text", + "horizontalAlignment": 0 + } + ], + "font": "Arial;13;0", + "left": 3352, + "top": 2918, + "width": 175.115234375, + "height": 98 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL3DMzZkm8ngY=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkmwpP8=" + }, + "model": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL3D2GBgECc9M=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkm8ngY=" + }, + "model": { + "$ref": "AAAAAAGL3D2F3gDGuRs=" + }, + "font": "Arial;13;0", + "left": 3357, + "top": 3021, + "width": 165.115234375, + "height": 13, + "text": "+getId(): int", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL++UQVUMgtH4=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkm8ngY=" + }, + "model": { + "$ref": "AAAAAAGL++UQDELkhBM=" + }, + "font": "Arial;13;0", + "left": 3357, + "top": 3036, + "width": 165.115234375, + "height": 13, + "text": "+getDate(): DateTime", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL++U2mUfQLgw=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkm8ngY=" + }, + "model": { + "$ref": "AAAAAAGL++U2j0eU938=" + }, + "font": "Arial;13;0", + "left": 3357, + "top": 3051, + "width": 165.115234375, + "height": 13, + "text": "+getLocation(): String", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL++Vh8UyAceA=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkm8ngY=" + }, + "model": { + "$ref": "AAAAAAGL++Vh50xEGPg=" + }, + "font": "Arial;13;0", + "left": 3357, + "top": 3066, + "width": 165.115234375, + "height": 13, + "text": "+getDescription(): Text", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL++WjXFEwtks=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkm8ngY=" + }, + "model": { + "$ref": "AAAAAAGL++WjUVD03ak=" + }, + "font": "Arial;13;0", + "left": 3357, + "top": 3081, + "width": 165.115234375, + "height": 13, + "text": "+getFeedBack(): String", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL++XHPVXggdY=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkm8ngY=" + }, + "model": { + "$ref": "AAAAAAGL++XHM1Wk8GA=" + }, + "font": "Arial;13;0", + "left": 3357, + "top": 3096, + "width": 165.115234375, + "height": 13, + "text": "+__toString(): String", + "horizontalAlignment": 0 + } + ], + "font": "Arial;13;0", + "left": 3352, + "top": 3016, + "width": 175.115234375, + "height": 98 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL3DMzZkm9E/c=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkmwpP8=" + }, + "model": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2472, + "top": 1024, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL3DMzZkm+Ato=", + "_parent": { + "$ref": "AAAAAAGL3DMzZkmwpP8=" + }, + "model": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2472, + "top": 1024, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 3352, + "top": 2880, + "width": 175.115234375, + "height": 234, + "nameCompartment": { + "$ref": "AAAAAAGL3DMzZkmx2TA=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL3DMzZkm2VYs=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL3DMzZkm8ngY=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL3DMzZkm9E/c=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL3DMzZkm+Ato=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAGL3DO5DGG3okQ=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL3DO5CWGzYdk=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DO5DWG4Vxk=", + "_parent": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + }, + "model": { + "$ref": "AAAAAAGL3DO5CWGzYdk=" + }, + "font": "Arial;13;0", + "left": 4326, + "top": 2927, + "width": 77.669921875, + "height": 13, + "alpha": 0.4974685789155705, + "distance": 97.8008179924892, + "hostEdge": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + }, + "edgePosition": 1, + "text": "-*activiteList" + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DO5DWG5mQE=", + "_parent": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + }, + "model": { + "$ref": "AAAAAAGL3DO5CWGzYdk=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 4334, + "top": 2845, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DO5DWG6kmk=", + "_parent": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + }, + "model": { + "$ref": "AAAAAAGL3DO5CWGzYdk=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4290, + "top": 2852, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DO5DWG7U68=", + "_parent": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + }, + "model": { + "$ref": "AAAAAAGL3DO5CWG0ZOw=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4306, + "top": 2754, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DO5DWG8UHU=", + "_parent": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + }, + "model": { + "$ref": "AAAAAAGL3DO5CWG0ZOw=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4320, + "top": 2754, + "height": 13, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DO5DWG9eyk=", + "_parent": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + }, + "model": { + "$ref": "AAAAAAGL3DO5CWG0ZOw=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4278, + "top": 2754, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DO5DWG+1dY=", + "_parent": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + }, + "model": { + "$ref": "AAAAAAGL3DO5CmG1yFk=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4334, + "top": 2941, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DO5DWG/mG8=", + "_parent": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + }, + "model": { + "$ref": "AAAAAAGL3DO5CmG1yFk=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4346, + "top": 2936, + "height": 13, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DO5DWHAtAE=", + "_parent": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + }, + "model": { + "$ref": "AAAAAAGL3DO5CmG1yFk=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4307, + "top": 2949, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + } + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL3DO5DWHBZf0=", + "_parent": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + }, + "model": { + "$ref": "AAAAAAGL3DO5CWG0ZOw=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 664, + "top": 560, + "width": 10, + "height": 10 + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL3DO5DWHC8CY=", + "_parent": { + "$ref": "AAAAAAGL3DO5DGG3okQ=" + }, + "model": { + "$ref": "AAAAAAGL3DO5CmG1yFk=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 664, + "top": 560, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL3DH0VM3eelw=" + }, + "tail": { + "$ref": "AAAAAAGL3BsTqaEI6W8=" + }, + "lineStyle": 1, + "points": "4288:2737;4323:2975", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL3DO5DWG4Vxk=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL3DO5DWG5mQE=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3DO5DWG6kmk=" + }, + "showEndOrder": "hide", + "tailRoleNameLabel": { + "$ref": "AAAAAAGL3DO5DWG7U68=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAGL3DO5DWG8UHU=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAGL3DO5DWG9eyk=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAGL3DO5DWG+1dY=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAGL3DO5DWG/mG8=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAGL3DO5DWHAtAE=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAGL3DO5DWHBZf0=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAGL3DO5DWHC8CY=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAGL3DdoAArKtwk=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL3Ddn/grGOiw=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DdoAArLq4o=", + "_parent": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + }, + "model": { + "$ref": "AAAAAAGL3Ddn/grGOiw=" + }, + "font": "Arial;13;0", + "left": 4162, + "top": 2788, + "width": 47.328125, + "height": 13, + "alpha": 1.0433323237988876, + "distance": 28.653097563788805, + "hostEdge": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + }, + "edgePosition": 1, + "text": "-*sdList" + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DdoAArM1RQ=", + "_parent": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + }, + "model": { + "$ref": "AAAAAAGL3Ddn/grGOiw=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 4198, + "top": 2780, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DdoAArN2G8=", + "_parent": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + }, + "model": { + "$ref": "AAAAAAGL3Ddn/grGOiw=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4163, + "top": 2752, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DdoAArOnkE=", + "_parent": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + }, + "model": { + "$ref": "AAAAAAGL3Ddn/grHlaI=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4194, + "top": 2760, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DdoAArPOz4=", + "_parent": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + }, + "model": { + "$ref": "AAAAAAGL3Ddn/grHlaI=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4204, + "top": 2770, + "height": 13, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DdoAArQnj0=", + "_parent": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + }, + "model": { + "$ref": "AAAAAAGL3Ddn/grHlaI=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4175, + "top": 2740, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DdoAArRcIQ=", + "_parent": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + }, + "model": { + "$ref": "AAAAAAGL3Ddn/grIS6Y=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4178, + "top": 2781, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DdoAArS3XI=", + "_parent": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + }, + "model": { + "$ref": "AAAAAAGL3Ddn/grIS6Y=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4190, + "top": 2787, + "height": 13, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DdoAArT1Uk=", + "_parent": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + }, + "model": { + "$ref": "AAAAAAGL3Ddn/grIS6Y=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4154, + "top": 2768, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + } + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL3DdoAArU9sw=", + "_parent": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + }, + "model": { + "$ref": "AAAAAAGL3Ddn/grHlaI=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 664, + "top": 560, + "width": 10, + "height": 10 + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL3DdoAArVCNA=", + "_parent": { + "$ref": "AAAAAAGL3DdoAArKtwk=" + }, + "model": { + "$ref": "AAAAAAGL3Ddn/grIS6Y=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 664, + "top": 560, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL3DLQlyYtiTQ=" + }, + "tail": { + "$ref": "AAAAAAGL3BsTqaEI6W8=" + }, + "lineStyle": 1, + "points": "4199:2737;4151:2799", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL3DdoAArLq4o=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL3DdoAArM1RQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3DdoAArN2G8=" + }, + "showEndOrder": "hide", + "tailRoleNameLabel": { + "$ref": "AAAAAAGL3DdoAArOnkE=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAGL3DdoAArPOz4=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAGL3DdoAArQnj0=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAGL3DdoAArRcIQ=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAGL3DdoAArS3XI=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAGL3DdoAArT1Uk=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAGL3DdoAArU9sw=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAGL3DdoAArVCNA=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAGL3DewVyCoB1Q=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL3DewVSCksyY=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DewWCCp9IE=", + "_parent": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + }, + "model": { + "$ref": "AAAAAAGL3DewVSCksyY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4196, + "top": 2989, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DewWCCqFY4=", + "_parent": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + }, + "model": { + "$ref": "AAAAAAGL3DewVSCksyY=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 4185, + "top": 3000, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DewWCCrus4=", + "_parent": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + }, + "model": { + "$ref": "AAAAAAGL3DewVSCksyY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4217, + "top": 2968, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DewWCCsgRA=", + "_parent": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + }, + "model": { + "$ref": "AAAAAAGL3DewViClTrY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4218, + "top": 3011, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DewWCCttCE=", + "_parent": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + }, + "model": { + "$ref": "AAAAAAGL3DewViClTrY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4207, + "top": 3019, + "height": 13, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DewWCCuzq0=", + "_parent": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + }, + "model": { + "$ref": "AAAAAAGL3DewViClTrY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4240, + "top": 2994, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DewWCCv920=", + "_parent": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + }, + "model": { + "$ref": "AAAAAAGL3DewViCmmWs=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4175, + "top": 2968, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DewWCCwtKA=", + "_parent": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + }, + "model": { + "$ref": "AAAAAAGL3DewViCmmWs=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4168, + "top": 2980, + "height": 13, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DewWCCxEwU=", + "_parent": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + }, + "model": { + "$ref": "AAAAAAGL3DewViCmmWs=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4192, + "top": 2946, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + } + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL3DewWCCy+4I=", + "_parent": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + }, + "model": { + "$ref": "AAAAAAGL3DewViClTrY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 664, + "top": 560, + "width": 10, + "height": 10 + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL3DewWCCzXsQ=", + "_parent": { + "$ref": "AAAAAAGL3DewVyCoB1Q=" + }, + "model": { + "$ref": "AAAAAAGL3DewViCmmWs=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 664, + "top": 560, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL3DLQlyYtiTQ=" + }, + "tail": { + "$ref": "AAAAAAGL3DH0VM3eelw=" + }, + "lineStyle": 1, + "points": "4247:3025;4168:2946", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL3DewWCCp9IE=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL3DewWCCqFY4=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3DewWCCrus4=" + }, + "showEndOrder": "hide", + "tailRoleNameLabel": { + "$ref": "AAAAAAGL3DewWCCsgRA=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAGL3DewWCCttCE=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAGL3DewWCCuzq0=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAGL3DewWCCv920=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAGL3DewWCCwtKA=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAGL3DewWCCxEwU=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAGL3DewWCCy+4I=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAGL3DewWCCzXsQ=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAGL3DgOnTog8NI=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL3DgOmzocF5c=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DgOnjohHis=", + "_parent": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + }, + "model": { + "$ref": "AAAAAAGL3DgOmzocF5c=" + }, + "font": "Arial;13;0", + "left": 4509, + "top": 2559, + "width": 60.33447265625, + "height": 13, + "alpha": 0.2589997153205553, + "distance": 76.96752561957543, + "hostEdge": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + }, + "edgePosition": 1, + "text": "-*statsList" + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DgOnjoiojs=", + "_parent": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + }, + "model": { + "$ref": "AAAAAAGL3DgOmzocF5c=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 4464, + "top": 2563, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DgOnjojT9Y=", + "_parent": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + }, + "model": { + "$ref": "AAAAAAGL3DgOmzocF5c=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4472, + "top": 2607, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DgOnjokvV8=", + "_parent": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + }, + "model": { + "$ref": "AAAAAAGL3DgOnDodXGk=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4388, + "top": 2595, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DgOnjolI+M=", + "_parent": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + }, + "model": { + "$ref": "AAAAAAGL3DgOnDodXGk=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4388, + "top": 2581, + "height": 13, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DgOnjom8EQ=", + "_parent": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + }, + "model": { + "$ref": "AAAAAAGL3DgOnDodXGk=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4389, + "top": 2622, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DgOnjonKzk=", + "_parent": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + }, + "model": { + "$ref": "AAAAAAGL3DgOnDoedKI=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4546, + "top": 2562, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DgOnjoobA8=", + "_parent": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + }, + "model": { + "$ref": "AAAAAAGL3DgOnDoedKI=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4541, + "top": 2549, + "height": 13, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3DgOnjopwyY=", + "_parent": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + }, + "model": { + "$ref": "AAAAAAGL3DgOnDoedKI=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4556, + "top": 2588, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + } + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL3DgOnjoqPJw=", + "_parent": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + }, + "model": { + "$ref": "AAAAAAGL3DgOnDodXGk=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 664, + "top": 560, + "width": 10, + "height": 10 + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL3DgOnjora1c=", + "_parent": { + "$ref": "AAAAAAGL3DgOnTog8NI=" + }, + "model": { + "$ref": "AAAAAAGL3DgOnDoedKI=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 664, + "top": 560, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL3DJHyBCPzHA=" + }, + "tail": { + "$ref": "AAAAAAGL3BsTqaEI6W8=" + }, + "lineStyle": 1, + "points": "4366:2621;4575:2578", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL3DgOnjohHis=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL3DgOnjoiojs=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3DgOnjojT9Y=" + }, + "showEndOrder": "hide", + "tailRoleNameLabel": { + "$ref": "AAAAAAGL3DgOnjokvV8=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAGL3DgOnjolI+M=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAGL3DgOnjom8EQ=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAGL3DgOnjonKzk=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAGL3DgOnjoobA8=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAGL3DgOnjopwyY=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAGL3DgOnjoqPJw=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAGL3DgOnjora1c=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL3EA5py45w5E=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL3EA5py46RZs=", + "_parent": { + "$ref": "AAAAAAGL3EA5py45w5E=" + }, + "model": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL3EA5py47qQ4=", + "_parent": { + "$ref": "AAAAAAGL3EA5py46RZs=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2784, + "top": 48, + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3EA5py48ztA=", + "_parent": { + "$ref": "AAAAAAGL3EA5py46RZs=" + }, + "font": "Arial;13;1", + "left": 4221, + "top": 1175, + "width": 93.18994140625, + "height": 13, + "text": "CoachManager" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3EA5qC499bk=", + "_parent": { + "$ref": "AAAAAAGL3EA5py46RZs=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2784, + "top": 48, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3EA5qC4+erY=", + "_parent": { + "$ref": "AAAAAAGL3EA5py46RZs=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2784, + "top": 48, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 4216, + "top": 1168, + "width": 103.18994140625, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGL3EA5py47qQ4=" + }, + "nameLabel": { + "$ref": "AAAAAAGL3EA5py48ztA=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL3EA5qC499bk=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3EA5qC4+erY=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL3EA5qC4/sY4=", + "_parent": { + "$ref": "AAAAAAGL3EA5py45w5E=" + }, + "model": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + }, + "font": "Arial;13;0", + "left": 4216, + "top": 1193, + "width": 103.18994140625, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL3EA5qC5AD5k=", + "_parent": { + "$ref": "AAAAAAGL3EA5py45w5E=" + }, + "model": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + }, + "font": "Arial;13;0", + "left": 4216, + "top": 1203, + "width": 103.18994140625, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL3EA5qC5B3KQ=", + "_parent": { + "$ref": "AAAAAAGL3EA5py45w5E=" + }, + "model": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 1392, + "top": 24, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL3EA5qC5CL3c=", + "_parent": { + "$ref": "AAAAAAGL3EA5py45w5E=" + }, + "model": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 1392, + "top": 24, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 4216, + "top": 1168, + "width": 103.18994140625, + "height": 45, + "nameCompartment": { + "$ref": "AAAAAAGL3EA5py46RZs=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL3EA5qC4/sY4=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL3EA5qC5AD5k=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL3EA5qC5B3KQ=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL3EA5qC5CL3c=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL3EC6NugSKAY=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGLw7nD48sOfVM=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL3EC6NugTD+k=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugSKAY=" + }, + "model": { + "$ref": "AAAAAAGLw7nD48sOfVM=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL3EC6NugUf44=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugTD+k=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2881, + "top": -777, + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3EC6NugVIHM=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugTD+k=" + }, + "font": "Arial;13;1", + "left": 2878, + "top": 822, + "width": 61.38818359375, + "height": 13, + "text": "index.php" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3EC6NugW6ig=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugTD+k=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2881, + "top": -777, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3EC6NugXQtk=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugTD+k=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2881, + "top": -777, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 2873, + "top": 815, + "width": 71.38818359375, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGL3EC6NugUf44=" + }, + "nameLabel": { + "$ref": "AAAAAAGL3EC6NugVIHM=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL3EC6NugW6ig=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3EC6NugXQtk=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL3EC6NugYR90=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugSKAY=" + }, + "model": { + "$ref": "AAAAAAGLw7nD48sOfVM=" + }, + "font": "Arial;13;0", + "left": 2873, + "top": 840, + "width": 71.38818359375, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL3EC6NugZZ5k=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugSKAY=" + }, + "model": { + "$ref": "AAAAAAGLw7nD48sOfVM=" + }, + "font": "Arial;13;0", + "left": 2873, + "top": 850, + "width": 71.38818359375, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL3EC6Nugaz2E=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugSKAY=" + }, + "model": { + "$ref": "AAAAAAGLw7nD48sOfVM=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2209, + "top": -49, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL3EC6NugbE8o=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugSKAY=" + }, + "model": { + "$ref": "AAAAAAGLw7nD48sOfVM=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2209, + "top": -49, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 2873, + "top": 815, + "width": 71.38818359375, + "height": 45, + "nameCompartment": { + "$ref": "AAAAAAGL3EC6NugTD+k=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL3EC6NugYR90=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL3EC6NugZZ5k=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL3EC6Nugaz2E=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL3EC6NugbE8o=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL3EC6NugccSE=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGLw7oXg9WQpWI=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL3EC6NugdYDM=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugccSE=" + }, + "model": { + "$ref": "AAAAAAGLw7oXg9WQpWI=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL3EC6NugedV8=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugdYDM=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3553, + "top": -889, + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3EC6Nugfy9g=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugdYDM=" + }, + "font": "Arial;13;1", + "left": 3286, + "top": 838, + "width": 78.71728515625, + "height": 13, + "text": "Console.php" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3EC6Nugg3/Q=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugdYDM=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3553, + "top": -889, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3EC6NughFjQ=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugdYDM=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3553, + "top": -889, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 3281, + "top": 831, + "width": 88.71728515625, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGL3EC6NugedV8=" + }, + "nameLabel": { + "$ref": "AAAAAAGL3EC6Nugfy9g=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL3EC6Nugg3/Q=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3EC6NughFjQ=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL3EC6NugilgA=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugccSE=" + }, + "model": { + "$ref": "AAAAAAGLw7oXg9WQpWI=" + }, + "font": "Arial;13;0", + "left": 3281, + "top": 856, + "width": 88.71728515625, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL3EC6NugjjkY=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugccSE=" + }, + "model": { + "$ref": "AAAAAAGLw7oXg9WQpWI=" + }, + "font": "Arial;13;0", + "left": 3281, + "top": 866, + "width": 88.71728515625, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL3EC6NugkPS4=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugccSE=" + }, + "model": { + "$ref": "AAAAAAGLw7oXg9WQpWI=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2545, + "top": -105, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL3EC6NuglsZk=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugccSE=" + }, + "model": { + "$ref": "AAAAAAGLw7oXg9WQpWI=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2545, + "top": -105, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 3281, + "top": 831, + "width": 88.71728515625, + "height": 45, + "nameCompartment": { + "$ref": "AAAAAAGL3EC6NugdYDM=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL3EC6NugilgA=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL3EC6NugjjkY=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL3EC6NugkPS4=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL3EC6NuglsZk=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAGL3EC6Nugm4CE=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGLw7pt1PGAP1c=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3EC6Nugnevw=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + }, + "model": { + "$ref": "AAAAAAGLw7pt1PGAP1c=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3112, + "top": 823, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3EC6NugoFWs=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + }, + "model": { + "$ref": "AAAAAAGLw7pt1PGAP1c=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 3113, + "top": 808, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3EC6NugpkNw=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + }, + "model": { + "$ref": "AAAAAAGLw7pt1PGAP1c=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3111, + "top": 852, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3EC6NugqVoQ=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + }, + "model": { + "$ref": "AAAAAAGLw7pt1PGB1i0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2970, + "top": 818, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3EC6Nugr4Fs=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + }, + "model": { + "$ref": "AAAAAAGLw7pt1PGB1i0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2973, + "top": 804, + "height": 13, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3EC6NugscZs=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + }, + "model": { + "$ref": "AAAAAAGLw7pt1PGB1i0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2965, + "top": 845, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3EC6NugtRDc=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + }, + "model": { + "$ref": "AAAAAAGLw7pt1PGCpVw=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3254, + "top": 829, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3EC6NuguAY0=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + }, + "model": { + "$ref": "AAAAAAGLw7pt1PGCpVw=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3252, + "top": 815, + "height": 13, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3EC6Nugv3Bs=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + }, + "model": { + "$ref": "AAAAAAGLw7pt1PGCpVw=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3257, + "top": 856, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + } + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL3EC6NugwZMg=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + }, + "model": { + "$ref": "AAAAAAGLw7pt1PGB1i0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2649, + "top": 111, + "width": 10, + "height": 10 + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL3EC6Nugxzvc=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nugm4CE=" + }, + "model": { + "$ref": "AAAAAAGLw7pt1PGCpVw=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2649, + "top": 111, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL3EC6NugccSE=" + }, + "tail": { + "$ref": "AAAAAAGL3EC6NugSKAY=" + }, + "lineStyle": 1, + "points": "2944:838;3280:851", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL3EC6Nugnevw=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL3EC6NugoFWs=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3EC6NugpkNw=" + }, + "showEndOrder": "hide", + "tailRoleNameLabel": { + "$ref": "AAAAAAGL3EC6NugqVoQ=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAGL3EC6Nugr4Fs=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAGL3EC6NugscZs=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAGL3EC6NugtRDc=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAGL3EC6NuguAY0=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAGL3EC6Nugv3Bs=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAGL3EC6NugwZMg=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAGL3EC6Nugxzvc=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL3EC6NugywOI=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGLw7v65PPlleU=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL3EC6Nugz9NQ=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugywOI=" + }, + "model": { + "$ref": "AAAAAAGLw7v65PPlleU=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL3EC6Nug0I+c=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nugz9NQ=" + }, + "font": "Arial;13;0", + "left": 3590, + "top": 844, + "width": 81.63720703125, + "height": 13, + "text": "«abstract»" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3EC6Nug1sZU=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nugz9NQ=" + }, + "font": "Arial;13;1", + "left": 3590, + "top": 859, + "width": 81.63720703125, + "height": 13, + "text": "DataManager" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3EC6Nug2Jf8=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nugz9NQ=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3041, + "top": -585, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3EC6Nug3TP0=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nugz9NQ=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3041, + "top": -585, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 3585, + "top": 839, + "width": 91.63720703125, + "height": 38, + "stereotypeLabel": { + "$ref": "AAAAAAGL3EC6Nug0I+c=" + }, + "nameLabel": { + "$ref": "AAAAAAGL3EC6Nug1sZU=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL3EC6Nug2Jf8=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3EC6Nug3TP0=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL3EC6Nug47Vw=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugywOI=" + }, + "model": { + "$ref": "AAAAAAGLw7v65PPlleU=" + }, + "font": "Arial;13;0", + "left": 3585, + "top": 877, + "width": 91.63720703125, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL3EC6Nug5yqc=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugywOI=" + }, + "model": { + "$ref": "AAAAAAGLw7v65PPlleU=" + }, + "font": "Arial;13;0", + "left": 3585, + "top": 887, + "width": 91.63720703125, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL3EC6Nug6/JU=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugywOI=" + }, + "model": { + "$ref": "AAAAAAGLw7v65PPlleU=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2289, + "top": 47, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL3EC6Nug7Jso=", + "_parent": { + "$ref": "AAAAAAGL3EC6NugywOI=" + }, + "model": { + "$ref": "AAAAAAGLw7v65PPlleU=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2289, + "top": 47, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 3585, + "top": 839, + "width": 91.63720703125, + "height": 58, + "nameCompartment": { + "$ref": "AAAAAAGL3EC6Nugz9NQ=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL3EC6Nug47Vw=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL3EC6Nug5yqc=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL3EC6Nug6/JU=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL3EC6Nug7Jso=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL3EC6Nug8Ro0=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL3EC6Nug9ngw=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nug8Ro0=" + }, + "model": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL3EC6Nug+fE0=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nug9ngw=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3679, + "top": -695, + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3EC6Nug/ut4=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nug9ngw=" + }, + "font": "Arial;13;1", + "left": 3565, + "top": 991, + "width": 41.919921875, + "height": 13, + "text": "Stub" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3EC6NuhA9+g=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nug9ngw=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3679, + "top": -695, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL3EC6NuhBHQ0=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nug9ngw=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3679, + "top": -695, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 3560, + "top": 984, + "width": 51.919921875, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGL3EC6Nug+fE0=" + }, + "nameLabel": { + "$ref": "AAAAAAGL3EC6Nug/ut4=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL3EC6NuhA9+g=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3EC6NuhBHQ0=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL3EC6NuhC6ng=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nug8Ro0=" + }, + "model": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + }, + "font": "Arial;13;0", + "left": 3560, + "top": 1009, + "width": 51.919921875, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL3EC6NuhDUz0=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nug8Ro0=" + }, + "model": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + }, + "font": "Arial;13;0", + "left": 3560, + "top": 1019, + "width": 51.919921875, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL3EC6NuhEj+Y=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nug8Ro0=" + }, + "model": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2608, + "top": -8, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL3EC6NuhFxZI=", + "_parent": { + "$ref": "AAAAAAGL3EC6Nug8Ro0=" + }, + "model": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 2608, + "top": -8, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 3560, + "top": 984, + "width": 51.919921875, + "height": 45, + "nameCompartment": { + "$ref": "AAAAAAGL3EC6Nug9ngw=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL3EC6NuhC6ng=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL3EC6NuhDUz0=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL3EC6NuhEj+Y=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL3EC6NuhFxZI=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAGL3EC6NuhGMoE=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGLw7xJLQpG+ik=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3EC6NuhHoNM=", + "_parent": { + "$ref": "AAAAAAGL3EC6NuhGMoE=" + }, + "model": { + "$ref": "AAAAAAGLw7xJLQpG+ik=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3591, + "top": 929, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3EC6NuhGMoE=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3EC6NuhI1H0=", + "_parent": { + "$ref": "AAAAAAGL3EC6NuhGMoE=" + }, + "model": { + "$ref": "AAAAAAGLw7xJLQpG+ik=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 3577, + "top": 924, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3EC6NuhGMoE=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3EC6NuhJlKQ=", + "_parent": { + "$ref": "AAAAAAGL3EC6NuhGMoE=" + }, + "model": { + "$ref": "AAAAAAGLw7xJLQpG+ik=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3620, + "top": 938, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3EC6NuhGMoE=" + }, + "edgePosition": 1 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL3EC6NugywOI=" + }, + "tail": { + "$ref": "AAAAAAGL3EC6Nug8Ro0=" + }, + "lineStyle": 1, + "points": "3592:983;3620:897", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL3EC6NuhHoNM=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL3EC6NuhI1H0=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3EC6NuhJlKQ=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAGL3EC6NuhKhx0=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGLw8OfyokBM5A=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3EC6NuhLBMA=", + "_parent": { + "$ref": "AAAAAAGL3EC6NuhKhx0=" + }, + "model": { + "$ref": "AAAAAAGLw8OfyokBM5A=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3477, + "top": 839, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3EC6NuhKhx0=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3EC6NuhMeaQ=", + "_parent": { + "$ref": "AAAAAAGL3EC6NuhKhx0=" + }, + "model": { + "$ref": "AAAAAAGLw8OfyokBM5A=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 3478, + "top": 824, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3EC6NuhKhx0=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3EC6NuhN5ak=", + "_parent": { + "$ref": "AAAAAAGL3EC6NuhKhx0=" + }, + "model": { + "$ref": "AAAAAAGLw8OfyokBM5A=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3476, + "top": 868, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3EC6NuhKhx0=" + }, + "edgePosition": 1 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL3EC6NugywOI=" + }, + "tail": { + "$ref": "AAAAAAGL3EC6NugccSE=" + }, + "lineStyle": 1, + "points": "3370:855;3584:865", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL3EC6NuhLBMA=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL3EC6NuhMeaQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3EC6NuhN5ak=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAGL3EhnLQk/wU8=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL3EhnKwk9Pw0=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3EhnLQlAeLk=", + "_parent": { + "$ref": "AAAAAAGL3EhnLQk/wU8=" + }, + "model": { + "$ref": "AAAAAAGL3EhnKwk9Pw0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3773, + "top": 2707, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3EhnLQk/wU8=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3EhnLglBTew=", + "_parent": { + "$ref": "AAAAAAGL3EhnLQk/wU8=" + }, + "model": { + "$ref": "AAAAAAGL3EhnKwk9Pw0=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 3770, + "top": 2692, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL3EhnLQk/wU8=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL3EhnLglC42U=", + "_parent": { + "$ref": "AAAAAAGL3EhnLQk/wU8=" + }, + "model": { + "$ref": "AAAAAAGL3EhnKwk9Pw0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3778, + "top": 2736, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL3EhnLQk/wU8=" + }, + "edgePosition": 1 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL3BsTqaEI6W8=" + }, + "tail": { + "$ref": "AAAAAAGL3CMxnUgw9Qc=" + }, + "lineStyle": 1, + "points": "3591:2626;3776:2728;4183:2656", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL3EhnLQlAeLk=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL3EhnLglBTew=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL3EhnLglC42U=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL8e8PL0VmSkQ=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL8e8PLkVkOWg=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL8e8PMEVnGz8=", + "_parent": { + "$ref": "AAAAAAGL8e8PL0VmSkQ=" + }, + "model": { + "$ref": "AAAAAAGL8e8PLkVkOWg=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL8e8PMEVoIWg=", + "_parent": { + "$ref": "AAAAAAGL8e8PMEVnGz8=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 1408, + "top": 992, + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL8e8PMUVpAU4=", + "_parent": { + "$ref": "AAAAAAGL8e8PMEVnGz8=" + }, + "font": "Arial;13;1", + "left": 3965, + "top": 1799, + "width": 96.80810546875, + "height": 13, + "text": "UserRepository" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL8e8PMUVqQ5g=", + "_parent": { + "$ref": "AAAAAAGL8e8PMEVnGz8=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 1408, + "top": 992, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL8e8PMUVrcd4=", + "_parent": { + "$ref": "AAAAAAGL8e8PMEVnGz8=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 1408, + "top": 992, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 3960, + "top": 1792, + "width": 106.80810546875, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGL8e8PMEVoIWg=" + }, + "nameLabel": { + "$ref": "AAAAAAGL8e8PMUVpAU4=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL8e8PMUVqQ5g=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL8e8PMUVrcd4=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL8e8PMUVsK2E=", + "_parent": { + "$ref": "AAAAAAGL8e8PL0VmSkQ=" + }, + "model": { + "$ref": "AAAAAAGL8e8PLkVkOWg=" + }, + "subViews": [ + { + "_type": "UMLAttributeView", + "_id": "AAAAAAGL+8w3rCz3EQg=", + "_parent": { + "$ref": "AAAAAAGL8e8PMUVsK2E=" + }, + "model": { + "$ref": "AAAAAAGL+8w3liysleM=" + }, + "font": "Arial;13;0", + "left": 3965, + "top": 1822, + "width": 96.80810546875, + "height": 13, + "text": "-users: array", + "horizontalAlignment": 0 + } + ], + "font": "Arial;13;0", + "left": 3960, + "top": 1817, + "width": 106.80810546875, + "height": 23 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL8e8PMUVtEH0=", + "_parent": { + "$ref": "AAAAAAGL8e8PL0VmSkQ=" + }, + "model": { + "$ref": "AAAAAAGL8e8PLkVkOWg=" + }, + "font": "Arial;13;0", + "left": 3960, + "top": 1840, + "width": 106.80810546875, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL8e8PMUVurv4=", + "_parent": { + "$ref": "AAAAAAGL8e8PL0VmSkQ=" + }, + "model": { + "$ref": "AAAAAAGL8e8PLkVkOWg=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 704, + "top": 496, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL8e8PMUVvyqI=", + "_parent": { + "$ref": "AAAAAAGL8e8PL0VmSkQ=" + }, + "model": { + "$ref": "AAAAAAGL8e8PLkVkOWg=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 704, + "top": 496, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 3960, + "top": 1792, + "width": 106.80810546875, + "height": 71, + "nameCompartment": { + "$ref": "AAAAAAGL8e8PMEVnGz8=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL8e8PMUVsK2E=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL8e8PMUVtEH0=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL8e8PMUVurv4=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL8e8PMUVvyqI=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL8e9J0ldJrjo=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL8e9J0FdHmso=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL8e9J01dKxDk=", + "_parent": { + "$ref": "AAAAAAGL8e9J0ldJrjo=" + }, + "model": { + "$ref": "AAAAAAGL8e9J0FdHmso=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL8e9J01dLMhE=", + "_parent": { + "$ref": "AAAAAAGL8e9J01dKxDk=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 1952, + "top": -704, + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL8e9J01dMxu0=", + "_parent": { + "$ref": "AAAAAAGL8e9J01dKxDk=" + }, + "font": "Arial;13;1", + "left": 4061, + "top": 959, + "width": 75.86083984375, + "height": 13, + "text": "AuthService" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL8e9J01dN/AA=", + "_parent": { + "$ref": "AAAAAAGL8e9J01dKxDk=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 1952, + "top": -704, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL8e9J01dOzTw=", + "_parent": { + "$ref": "AAAAAAGL8e9J01dKxDk=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 1952, + "top": -704, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 4056, + "top": 952, + "width": 85.86083984375, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGL8e9J01dLMhE=" + }, + "nameLabel": { + "$ref": "AAAAAAGL8e9J01dMxu0=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL8e9J01dN/AA=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL8e9J01dOzTw=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL8e9J01dPxyE=", + "_parent": { + "$ref": "AAAAAAGL8e9J0ldJrjo=" + }, + "model": { + "$ref": "AAAAAAGL8e9J0FdHmso=" + }, + "font": "Arial;13;0", + "left": 4056, + "top": 977, + "width": 85.86083984375, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL8e9J01dQhvI=", + "_parent": { + "$ref": "AAAAAAGL8e9J0ldJrjo=" + }, + "model": { + "$ref": "AAAAAAGL8e9J0FdHmso=" + }, + "font": "Arial;13;0", + "left": 4056, + "top": 987, + "width": 85.86083984375, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL8e9J01dRnSs=", + "_parent": { + "$ref": "AAAAAAGL8e9J0ldJrjo=" + }, + "model": { + "$ref": "AAAAAAGL8e9J0FdHmso=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 976, + "top": -352, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL8e9J01dSt+8=", + "_parent": { + "$ref": "AAAAAAGL8e9J0ldJrjo=" + }, + "model": { + "$ref": "AAAAAAGL8e9J0FdHmso=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 976, + "top": -352, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 4056, + "top": 952, + "width": 85.86083984375, + "height": 45, + "nameCompartment": { + "$ref": "AAAAAAGL8e9J01dKxDk=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL8e9J01dPxyE=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL8e9J01dQhvI=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL8e9J01dRnSs=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL8e9J01dSt+8=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL8fAHTpcfcxQ=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL8fAHTJcd2Kc=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL8fAHTpcgm1k=", + "_parent": { + "$ref": "AAAAAAGL8fAHTpcfcxQ=" + }, + "model": { + "$ref": "AAAAAAGL8fAHTJcd2Kc=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL8fAHT5chwjE=", + "_parent": { + "$ref": "AAAAAAGL8fAHTpcgm1k=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 1248, + "top": -416, + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL8fAHT5ciXp0=", + "_parent": { + "$ref": "AAAAAAGL8fAHTpcgm1k=" + }, + "font": "Arial;13;1", + "left": 3685, + "top": 1175, + "width": 82.3671875, + "height": 13, + "text": "UserManager" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL8fAHT5cjZF4=", + "_parent": { + "$ref": "AAAAAAGL8fAHTpcgm1k=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 1248, + "top": -416, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL8fAHT5cki6A=", + "_parent": { + "$ref": "AAAAAAGL8fAHTpcgm1k=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 1248, + "top": -416, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 3680, + "top": 1168, + "width": 92.3671875, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGL8fAHT5chwjE=" + }, + "nameLabel": { + "$ref": "AAAAAAGL8fAHT5ciXp0=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL8fAHT5cjZF4=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL8fAHT5cki6A=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL8fAHT5clCB0=", + "_parent": { + "$ref": "AAAAAAGL8fAHTpcfcxQ=" + }, + "model": { + "$ref": "AAAAAAGL8fAHTJcd2Kc=" + }, + "font": "Arial;13;0", + "left": 3680, + "top": 1193, + "width": 92.3671875, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL8fAHT5cmKsU=", + "_parent": { + "$ref": "AAAAAAGL8fAHTpcfcxQ=" + }, + "model": { + "$ref": "AAAAAAGL8fAHTJcd2Kc=" + }, + "font": "Arial;13;0", + "left": 3680, + "top": 1203, + "width": 92.3671875, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL8fAHT5cnzVg=", + "_parent": { + "$ref": "AAAAAAGL8fAHTpcfcxQ=" + }, + "model": { + "$ref": "AAAAAAGL8fAHTJcd2Kc=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 624, + "top": -208, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL8fAHT5cobGg=", + "_parent": { + "$ref": "AAAAAAGL8fAHTpcfcxQ=" + }, + "model": { + "$ref": "AAAAAAGL8fAHTJcd2Kc=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 624, + "top": -208, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 3680, + "top": 1168, + "width": 92.3671875, + "height": 45, + "nameCompartment": { + "$ref": "AAAAAAGL8fAHTpcgm1k=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL8fAHT5clCB0=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL8fAHT5cmKsU=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL8fAHT5cnzVg=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL8fAHT5cobGg=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL8kwWNOvs/ko=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL8kwWNevt7h4=", + "_parent": { + "$ref": "AAAAAAGL8kwWNOvs/ko=" + }, + "model": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL8kwWNevuGgw=", + "_parent": { + "$ref": "AAAAAAGL8kwWNevt7h4=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -544, + "top": 432, + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL8kwWNevv/0Y=", + "_parent": { + "$ref": "AAAAAAGL8kwWNevt7h4=" + }, + "font": "Arial;13;1", + "left": 3189, + "top": 2743, + "width": 150.97265625, + "height": 13, + "text": "EntrainementRepository" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL8kwWNevwRpI=", + "_parent": { + "$ref": "AAAAAAGL8kwWNevt7h4=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -544, + "top": 432, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL8kwWNevx3X0=", + "_parent": { + "$ref": "AAAAAAGL8kwWNevt7h4=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -544, + "top": 432, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 3184, + "top": 2736, + "width": 160.97265625, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGL8kwWNevuGgw=" + }, + "nameLabel": { + "$ref": "AAAAAAGL8kwWNevv/0Y=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL8kwWNevwRpI=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL8kwWNevx3X0=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL8kwWNevy7vE=", + "_parent": { + "$ref": "AAAAAAGL8kwWNOvs/ko=" + }, + "model": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + }, + "font": "Arial;13;0", + "left": 3184, + "top": 2761, + "width": 160.97265625, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL8kwWNevzRQQ=", + "_parent": { + "$ref": "AAAAAAGL8kwWNOvs/ko=" + }, + "model": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + }, + "font": "Arial;13;0", + "left": 3184, + "top": 2771, + "width": 160.97265625, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL8kwWNev0nPo=", + "_parent": { + "$ref": "AAAAAAGL8kwWNOvs/ko=" + }, + "model": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -272, + "top": 216, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL8kwWNev1L3w=", + "_parent": { + "$ref": "AAAAAAGL8kwWNOvs/ko=" + }, + "model": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -272, + "top": 216, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 3184, + "top": 2736, + "width": 160.97265625, + "height": 45, + "nameCompartment": { + "$ref": "AAAAAAGL8kwWNevt7h4=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL8kwWNevy7vE=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL8kwWNevzRQQ=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL8kwWNev0nPo=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL8kwWNev1L3w=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAGL8lO7+WPDWLU=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL8lO7+GO/UQE=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL8lO7+mPEK6o=", + "_parent": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + }, + "model": { + "$ref": "AAAAAAGL8lO7+GO/UQE=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4021, + "top": 1909, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL8lO7+mPF070=", + "_parent": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + }, + "model": { + "$ref": "AAAAAAGL8lO7+GO/UQE=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 4036, + "top": 1910, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL8lO7+mPGdnA=", + "_parent": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + }, + "model": { + "$ref": "AAAAAAGL8lO7+GO/UQE=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3992, + "top": 1908, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL8lO7+mPHYXo=", + "_parent": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + }, + "model": { + "$ref": "AAAAAAGL8lO7+GPAblU=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4023, + "top": 1883, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL8lO7+mPIjKE=", + "_parent": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + }, + "model": { + "$ref": "AAAAAAGL8lO7+GPAblU=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4036, + "top": 1886, + "height": 13, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL8lO7+mPJ378=", + "_parent": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + }, + "model": { + "$ref": "AAAAAAGL8lO7+GPAblU=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3996, + "top": 1877, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL8lO7+mPK26w=", + "_parent": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + }, + "model": { + "$ref": "AAAAAAGL8lO7+GPBs+g=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4020, + "top": 1935, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL8lO7+mPLcXE=", + "_parent": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + }, + "model": { + "$ref": "AAAAAAGL8lO7+GPBs+g=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4033, + "top": 1934, + "height": 13, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL8lO7+mPMY/Y=", + "_parent": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + }, + "model": { + "$ref": "AAAAAAGL8lO7+GPBs+g=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3992, + "top": 1938, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + } + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL8lO7+mPN9/A=", + "_parent": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + }, + "model": { + "$ref": "AAAAAAGL8lO7+GPAblU=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL8lO7+mPOJ04=", + "_parent": { + "$ref": "AAAAAAGL8lO7+WPDWLU=" + }, + "model": { + "$ref": "AAAAAAGL8lO7+GPBs+g=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL3Bpk6Nh7nd8=" + }, + "tail": { + "$ref": "AAAAAAGL8e8PL0VmSkQ=" + }, + "lineStyle": 1, + "points": "4010:1863;4004:1967", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL8lO7+mPEK6o=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL8lO7+mPF070=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL8lO7+mPGdnA=" + }, + "showEndOrder": "hide", + "tailRoleNameLabel": { + "$ref": "AAAAAAGL8lO7+mPHYXo=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAGL8lO7+mPIjKE=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAGL8lO7+mPJ378=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAGL8lO7+mPK26w=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAGL8lO7+mPLcXE=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAGL8lO7+mPMY/Y=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAGL8lO7+mPN9/A=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAGL8lO7+mPOJ04=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAGL8lXBS67DYgg=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL8lXBSa6/2w4=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL8lXBS67EK3I=", + "_parent": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + }, + "model": { + "$ref": "AAAAAAGL8lXBSa6/2w4=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3869, + "top": 900, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL8lXBS67F6AQ=", + "_parent": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + }, + "model": { + "$ref": "AAAAAAGL8lXBSa6/2w4=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 3872, + "top": 885, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL8lXBS67Gc4s=", + "_parent": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + }, + "model": { + "$ref": "AAAAAAGL8lXBSa6/2w4=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3862, + "top": 929, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL8lXBTK7HYIA=", + "_parent": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + }, + "model": { + "$ref": "AAAAAAGL8lXBSa7AoxY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3705, + "top": 863, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL8lXBTK7Ivfo=", + "_parent": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + }, + "model": { + "$ref": "AAAAAAGL8lXBSa7AoxY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3710, + "top": 850, + "height": 13, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL8lXBTK7JxMA=", + "_parent": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + }, + "model": { + "$ref": "AAAAAAGL8lXBSa7AoxY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3695, + "top": 888, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL8lXBTK7KBwQ=", + "_parent": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + }, + "model": { + "$ref": "AAAAAAGL8lXBSa7B00o=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4032, + "top": 937, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL8lXBTK7LPto=", + "_parent": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + }, + "model": { + "$ref": "AAAAAAGL8lXBSa7B00o=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4033, + "top": 924, + "height": 13, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL8lXBTK7MGZo=", + "_parent": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + }, + "model": { + "$ref": "AAAAAAGL8lXBSa7B00o=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4031, + "top": 965, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + } + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL8lXBTK7NaZA=", + "_parent": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + }, + "model": { + "$ref": "AAAAAAGL8lXBSa7AoxY=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL8lXBTK7OIvI=", + "_parent": { + "$ref": "AAAAAAGL8lXBS67DYgg=" + }, + "model": { + "$ref": "AAAAAAGL8lXBSa7B00o=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL8e9J0ldJrjo=" + }, + "tail": { + "$ref": "AAAAAAGL3EC6NugywOI=" + }, + "lineStyle": 1, + "points": "3677:878;4055:964", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL8lXBS67EK3I=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL8lXBS67F6AQ=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL8lXBS67Gc4s=" + }, + "showEndOrder": "hide", + "tailRoleNameLabel": { + "$ref": "AAAAAAGL8lXBTK7HYIA=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAGL8lXBTK7Ivfo=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAGL8lXBTK7JxMA=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAGL8lXBTK7KBwQ=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAGL8lXBTK7LPto=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAGL8lXBTK7MGZo=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAGL8lXBTK7NaZA=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAGL8lXBTK7OIvI=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAGL+8rOIEknLJI=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL+8rOHkkjQa8=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+8rOIUko0e8=", + "_parent": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + }, + "model": { + "$ref": "AAAAAAGL+8rOHkkjQa8=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4170, + "top": 1085, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+8rOIUkpnxA=", + "_parent": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + }, + "model": { + "$ref": "AAAAAAGL+8rOHkkjQa8=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 4158, + "top": 1094, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+8rOIUkqzew=", + "_parent": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + }, + "model": { + "$ref": "AAAAAAGL+8rOHkkjQa8=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4193, + "top": 1066, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+8rOIUkrcbw=", + "_parent": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + }, + "model": { + "$ref": "AAAAAAGL+8rOH0kk5Us=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4221, + "top": 1149, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+8rOIUks864=", + "_parent": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + }, + "model": { + "$ref": "AAAAAAGL+8rOH0kk5Us=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4209, + "top": 1156, + "height": 13, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+8rOIUktsAY=", + "_parent": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + }, + "model": { + "$ref": "AAAAAAGL+8rOH0kk5Us=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4245, + "top": 1136, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+8rOIUkuZk8=", + "_parent": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + }, + "model": { + "$ref": "AAAAAAGL+8rOH0kl1Ag=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4120, + "top": 1020, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+8rOIUkv5a8=", + "_parent": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + }, + "model": { + "$ref": "AAAAAAGL+8rOH0kl1Ag=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4111, + "top": 1030, + "height": 13, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+8rOIUkwAc4=", + "_parent": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + }, + "model": { + "$ref": "AAAAAAGL+8rOH0kl1Ag=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4139, + "top": 1000, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + } + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL+8rOIUkx/wo=", + "_parent": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + }, + "model": { + "$ref": "AAAAAAGL+8rOH0kk5Us=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL+8rOIUkyAUc=", + "_parent": { + "$ref": "AAAAAAGL+8rOIEknLJI=" + }, + "model": { + "$ref": "AAAAAAGL+8rOH0kl1Ag=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL8e9J0ldJrjo=" + }, + "tail": { + "$ref": "AAAAAAGL3EA5py45w5E=" + }, + "lineStyle": 1, + "points": "4249:1167;4116:997", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL+8rOIUko0e8=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL+8rOIUkpnxA=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL+8rOIUkqzew=" + }, + "showEndOrder": "hide", + "tailRoleNameLabel": { + "$ref": "AAAAAAGL+8rOIUkrcbw=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAGL+8rOIUks864=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAGL+8rOIUktsAY=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAGL+8rOIUkuZk8=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAGL+8rOIUkv5a8=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAGL+8rOIUkwAc4=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAGL+8rOIUkx/wo=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAGL+8rOIUkyAUc=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAGL+8tZ+K7c/nM=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL+8tZ967YT0Q=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+8tZ+a7digU=", + "_parent": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + }, + "model": { + "$ref": "AAAAAAGL+8tZ967YT0Q=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4369, + "top": 1116, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+8tZ+a7eLHc=", + "_parent": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + }, + "model": { + "$ref": "AAAAAAGL+8tZ967YT0Q=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 4354, + "top": 1119, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+8tZ+a7fiuQ=", + "_parent": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + }, + "model": { + "$ref": "AAAAAAGL+8tZ967YT0Q=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4398, + "top": 1111, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+8tZ+a7gF+o=", + "_parent": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + }, + "model": { + "$ref": "AAAAAAGL+8tZ967ZQD0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3799, + "top": 1176, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+8tZ+a7hbVM=", + "_parent": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + }, + "model": { + "$ref": "AAAAAAGL+8tZ967ZQD0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3802, + "top": 1163, + "height": 13, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+8tZ+a7iO2M=", + "_parent": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + }, + "model": { + "$ref": "AAAAAAGL+8tZ967ZQD0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3792, + "top": 1203, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+8tZ+a7j0rE=", + "_parent": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + }, + "model": { + "$ref": "AAAAAAGL+8tZ967azMY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4167, + "top": 985, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+8tZ+a7kGIo=", + "_parent": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + }, + "model": { + "$ref": "AAAAAAGL+8tZ967azMY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4169, + "top": 999, + "height": 13, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+8tZ+a7lIZQ=", + "_parent": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + }, + "model": { + "$ref": "AAAAAAGL+8tZ967azMY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4164, + "top": 958, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + } + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL+8tZ+a7mZBU=", + "_parent": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + }, + "model": { + "$ref": "AAAAAAGL+8tZ967ZQD0=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL+8tZ+a7nWnA=", + "_parent": { + "$ref": "AAAAAAGL+8tZ+K7c/nM=" + }, + "model": { + "$ref": "AAAAAAGL+8tZ967azMY=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL8e9J0ldJrjo=" + }, + "tail": { + "$ref": "AAAAAAGL8fAHTpcfcxQ=" + }, + "lineStyle": 1, + "points": "3772:1195;4408:1256;4360:984;4142:976", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL+8tZ+a7digU=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL+8tZ+a7eLHc=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL+8tZ+a7fiuQ=" + }, + "showEndOrder": "hide", + "tailRoleNameLabel": { + "$ref": "AAAAAAGL+8tZ+a7gF+o=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAGL+8tZ+a7hbVM=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAGL+8tZ+a7iO2M=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAGL+8tZ+a7j0rE=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAGL+8tZ+a7kGIo=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAGL+8tZ+a7lIZQ=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAGL+8tZ+a7mZBU=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAGL+8tZ+a7nWnA=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL+82j3FEcyoc=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL+82j2lEaUGY=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL+82j3FEdnM8=", + "_parent": { + "$ref": "AAAAAAGL+82j3FEcyoc=" + }, + "model": { + "$ref": "AAAAAAGL+82j2lEaUGY=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL+82j3VEef7E=", + "_parent": { + "$ref": "AAAAAAGL+82j3FEdnM8=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -64, + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL+82j3VEfYy0=", + "_parent": { + "$ref": "AAAAAAGL+82j3FEdnM8=" + }, + "font": "Arial;13;1", + "left": 3605, + "top": 1295, + "width": 665.8564453125, + "height": 13, + "text": "IGenericRepository" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL+82j3VEgwrw=", + "_parent": { + "$ref": "AAAAAAGL+82j3FEdnM8=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -64, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL+82j3VEha1o=", + "_parent": { + "$ref": "AAAAAAGL+82j3FEdnM8=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -64, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 3600, + "top": 1288, + "width": 675.8564453125, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGL+82j3VEef7E=" + }, + "nameLabel": { + "$ref": "AAAAAAGL+82j3VEfYy0=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL+82j3VEgwrw=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL+82j3VEha1o=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL+82j3VEiTxc=", + "_parent": { + "$ref": "AAAAAAGL+82j3FEcyoc=" + }, + "model": { + "$ref": "AAAAAAGL+82j2lEaUGY=" + }, + "font": "Arial;13;0", + "left": 3600, + "top": 1313, + "width": 675.8564453125, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL+82j3VEjiyg=", + "_parent": { + "$ref": "AAAAAAGL+82j3FEcyoc=" + }, + "model": { + "$ref": "AAAAAAGL+82j2lEaUGY=" + }, + "subViews": [ + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL+84t2m6K78I=", + "_parent": { + "$ref": "AAAAAAGL+82j3VEjiyg=" + }, + "model": { + "$ref": "AAAAAAGL+84tpm4nUBQ=" + }, + "font": "Arial;13;0", + "left": 3605, + "top": 1328, + "width": 665.8564453125, + "height": 13, + "text": "+getItemById(id: int)", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL+86cfHnTO3k=", + "_parent": { + "$ref": "AAAAAAGL+82j3VEjiyg=" + }, + "model": { + "$ref": "AAAAAAGL+86cPHlwc+E=" + }, + "font": "Arial;13;0", + "left": 3605, + "top": 1343, + "width": 665.8564453125, + "height": 13, + "text": "+getNbItems(): int", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL+86fd305Cww=", + "_parent": { + "$ref": "AAAAAAGL+82j3VEjiyg=" + }, + "model": { + "$ref": "AAAAAAGL+86fO3zWI0s=" + }, + "font": "Arial;13;0", + "left": 3605, + "top": 1358, + "width": 665.8564453125, + "height": 13, + "text": "+getItems(index: int, count: int, orderingPropertyName: ?String, descending: bool): array", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL+86ns4CfwV0=", + "_parent": { + "$ref": "AAAAAAGL+82j3VEjiyg=" + }, + "model": { + "$ref": "AAAAAAGL+86ncIA8/pY=" + }, + "font": "Arial;13;0", + "left": 3605, + "top": 1373, + "width": 665.8564453125, + "height": 13, + "text": "+getItemsByName(substring: String, index: int, count: int, orderingPropertyName: ?String, descending: bool): ?array", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL+86qHYQFmS4=", + "_parent": { + "$ref": "AAAAAAGL+82j3VEjiyg=" + }, + "model": { + "$ref": "AAAAAAGL+86p3oOiaNc=" + }, + "font": "Arial;13;0", + "left": 3605, + "top": 1388, + "width": 665.8564453125, + "height": 13, + "text": "+getItemsByName(substring: String, index: int, count: int, orderingPropertyName: ?String, descending: bool)", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL+86sjYdrzkU=", + "_parent": { + "$ref": "AAAAAAGL+82j3VEjiyg=" + }, + "model": { + "$ref": "AAAAAAGL+86sTYcItmQ=" + }, + "font": "Arial;13;0", + "left": 3605, + "top": 1403, + "width": 665.8564453125, + "height": 13, + "text": "+updateItem(oldItem, newItem): void", + "horizontalAlignment": 0 + }, + { + "_type": "UMLOperationView", + "_id": "AAAAAAGL+86uxIrRU/g=", + "_parent": { + "$ref": "AAAAAAGL+82j3VEjiyg=" + }, + "model": { + "$ref": "AAAAAAGL+86ui4puvnk=" + }, + "font": "Arial;13;0", + "left": 3605, + "top": 1418, + "width": 665.8564453125, + "height": 13, + "text": "+deleteItem(item): bool", + "horizontalAlignment": 0 + } + ], + "font": "Arial;13;0", + "left": 3600, + "top": 1323, + "width": 675.8564453125, + "height": 113 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL+82j3VEkf/0=", + "_parent": { + "$ref": "AAAAAAGL+82j3FEcyoc=" + }, + "model": { + "$ref": "AAAAAAGL+82j2lEaUGY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -32, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL+82j3VEleEk=", + "_parent": { + "$ref": "AAAAAAGL+82j3FEcyoc=" + }, + "model": { + "$ref": "AAAAAAGL+82j2lEaUGY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -32, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 3600, + "top": 1288, + "width": 675.8564453125, + "height": 148, + "nameCompartment": { + "$ref": "AAAAAAGL+82j3FEdnM8=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL+82j3VEiTxc=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL+82j3VEjiyg=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL+82j3VEkf/0=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL+82j3VEleEk=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL+9O3Fr8A9kM=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL+9O3E77+iB4=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL+9O3F78BOMg=", + "_parent": { + "$ref": "AAAAAAGL+9O3Fr8A9kM=" + }, + "model": { + "$ref": "AAAAAAGL+9O3E77+iB4=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL+9O3F78CrIE=", + "_parent": { + "$ref": "AAAAAAGL+9O3F78BOMg=" + }, + "visible": false, + "font": "Arial;13;0", + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL+9O3F78DySM=", + "_parent": { + "$ref": "AAAAAAGL+9O3F78BOMg=" + }, + "font": "Arial;13;1", + "left": 3709, + "top": 1519, + "width": 122.07177734375, + "height": 13, + "text": "ITrainingRepository" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL+9O3F78EMdg=", + "_parent": { + "$ref": "AAAAAAGL+9O3F78BOMg=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL+9O3F78FN9A=", + "_parent": { + "$ref": "AAAAAAGL+9O3F78BOMg=" + }, + "visible": false, + "font": "Arial;13;0", + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 3704, + "top": 1512, + "width": 132.07177734375, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGL+9O3F78CrIE=" + }, + "nameLabel": { + "$ref": "AAAAAAGL+9O3F78DySM=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL+9O3F78EMdg=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL+9O3F78FN9A=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL+9O3F78GjZg=", + "_parent": { + "$ref": "AAAAAAGL+9O3Fr8A9kM=" + }, + "model": { + "$ref": "AAAAAAGL+9O3E77+iB4=" + }, + "font": "Arial;13;0", + "left": 3704, + "top": 1537, + "width": 132.07177734375, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL+9O3F78H6KE=", + "_parent": { + "$ref": "AAAAAAGL+9O3Fr8A9kM=" + }, + "model": { + "$ref": "AAAAAAGL+9O3E77+iB4=" + }, + "font": "Arial;13;0", + "left": 3704, + "top": 1547, + "width": 132.07177734375, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL+9O3F78IiiI=", + "_parent": { + "$ref": "AAAAAAGL+9O3Fr8A9kM=" + }, + "model": { + "$ref": "AAAAAAGL+9O3E77+iB4=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL+9O3GL8J2/s=", + "_parent": { + "$ref": "AAAAAAGL+9O3Fr8A9kM=" + }, + "model": { + "$ref": "AAAAAAGL+9O3E77+iB4=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 3704, + "top": 1512, + "width": 132.07177734375, + "height": 45, + "nameCompartment": { + "$ref": "AAAAAAGL+9O3F78BOMg=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL+9O3F78GjZg=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL+9O3F78H6KE=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL+9O3F78IiiI=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL+9O3GL8J2/s=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL+9PoNNQIuXw=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL+9PoMtQG54g=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL+9PoNdQJC5U=", + "_parent": { + "$ref": "AAAAAAGL+9PoNNQIuXw=" + }, + "model": { + "$ref": "AAAAAAGL+9PoMtQG54g=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL+9PoNdQKlXY=", + "_parent": { + "$ref": "AAAAAAGL+9PoNdQJC5U=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 848, + "top": 48, + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL+9PoNdQLUfI=", + "_parent": { + "$ref": "AAAAAAGL+9PoNdQJC5U=" + }, + "font": "Arial;13;1", + "left": 4085, + "top": 1527, + "width": 100.419921875, + "height": 13, + "text": "IUserRepository" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL+9PoNdQM5Ew=", + "_parent": { + "$ref": "AAAAAAGL+9PoNdQJC5U=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 848, + "top": 48, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL+9PoNdQN2fA=", + "_parent": { + "$ref": "AAAAAAGL+9PoNdQJC5U=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 848, + "top": 48, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 4080, + "top": 1520, + "width": 110.419921875, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGL+9PoNdQKlXY=" + }, + "nameLabel": { + "$ref": "AAAAAAGL+9PoNdQLUfI=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL+9PoNdQM5Ew=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL+9PoNdQN2fA=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL+9PoNdQOmYg=", + "_parent": { + "$ref": "AAAAAAGL+9PoNNQIuXw=" + }, + "model": { + "$ref": "AAAAAAGL+9PoMtQG54g=" + }, + "font": "Arial;13;0", + "left": 4080, + "top": 1545, + "width": 110.419921875, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL+9PoNdQPg/M=", + "_parent": { + "$ref": "AAAAAAGL+9PoNNQIuXw=" + }, + "model": { + "$ref": "AAAAAAGL+9PoMtQG54g=" + }, + "font": "Arial;13;0", + "left": 4080, + "top": 1555, + "width": 110.419921875, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL+9PoNdQQOeE=", + "_parent": { + "$ref": "AAAAAAGL+9PoNNQIuXw=" + }, + "model": { + "$ref": "AAAAAAGL+9PoMtQG54g=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 424, + "top": 24, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL+9PoNdQRN8A=", + "_parent": { + "$ref": "AAAAAAGL+9PoNNQIuXw=" + }, + "model": { + "$ref": "AAAAAAGL+9PoMtQG54g=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 424, + "top": 24, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 4080, + "top": 1520, + "width": 110.419921875, + "height": 45, + "nameCompartment": { + "$ref": "AAAAAAGL+9PoNdQJC5U=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL+9PoNdQOmYg=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL+9PoNdQPg/M=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL+9PoNdQQOeE=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL+9PoNdQRN8A=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAGL+9RSGxB+nHc=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL+9RSGRB8+vM=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9RSGxB/KpY=", + "_parent": { + "$ref": "AAAAAAGL+9RSGxB+nHc=" + }, + "model": { + "$ref": "AAAAAAGL+9RSGRB8+vM=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3816, + "top": 1456, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+9RSGxB+nHc=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9RSGxCAPdg=", + "_parent": { + "$ref": "AAAAAAGL+9RSGxB+nHc=" + }, + "model": { + "$ref": "AAAAAAGL+9RSGRB8+vM=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 3805, + "top": 1445, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+9RSGxB+nHc=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9RSGxCBVsg=", + "_parent": { + "$ref": "AAAAAAGL+9RSGxB+nHc=" + }, + "model": { + "$ref": "AAAAAAGL+9RSGRB8+vM=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3837, + "top": 1477, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+9RSGxB+nHc=" + }, + "edgePosition": 1 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL+82j3FEcyoc=" + }, + "tail": { + "$ref": "AAAAAAGL+9O3Fr8A9kM=" + }, + "lineStyle": 1, + "points": "3791:1511;3864:1436", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL+9RSGxB/KpY=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL+9RSGxCAPdg=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL+9RSGxCBVsg=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAGL+9RdJRsYynw=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL+9RdJBsWH7s=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9RdJRsZl4s=", + "_parent": { + "$ref": "AAAAAAGL+9RdJRsYynw=" + }, + "model": { + "$ref": "AAAAAAGL+9RdJBsWH7s=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4053, + "top": 1482, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+9RdJRsYynw=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9RdJhsaMvs=", + "_parent": { + "$ref": "AAAAAAGL+9RdJRsYynw=" + }, + "model": { + "$ref": "AAAAAAGL+9RdJBsWH7s=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 4043, + "top": 1493, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+9RdJRsYynw=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9RdJhsbpBU=", + "_parent": { + "$ref": "AAAAAAGL+9RdJRsYynw=" + }, + "model": { + "$ref": "AAAAAAGL+9RdJBsWH7s=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4074, + "top": 1459, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+9RdJRsYynw=" + }, + "edgePosition": 1 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL+82j3FEcyoc=" + }, + "tail": { + "$ref": "AAAAAAGL+9PoNNQIuXw=" + }, + "lineStyle": 1, + "points": "4109:1519;4019:1436", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL+9RdJRsZl4s=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL+9RdJhsaMvs=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL+9RdJhsbpBU=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAGL+9Ru2jbFEaA=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL+9Ru2TbDJ+A=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9Ru2zbGfmg=", + "_parent": { + "$ref": "AAAAAAGL+9Ru2jbFEaA=" + }, + "model": { + "$ref": "AAAAAAGL+9Ru2TbDJ+A=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4061, + "top": 1666, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+9Ru2jbFEaA=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9Ru2zbHIig=", + "_parent": { + "$ref": "AAAAAAGL+9Ru2jbFEaA=" + }, + "model": { + "$ref": "AAAAAAGL+9Ru2TbDJ+A=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 4047, + "top": 1660, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+9Ru2jbFEaA=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9Ru2zbIGgw=", + "_parent": { + "$ref": "AAAAAAGL+9Ru2jbFEaA=" + }, + "model": { + "$ref": "AAAAAAGL+9Ru2TbDJ+A=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4088, + "top": 1677, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+9Ru2jbFEaA=" + }, + "edgePosition": 1 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL+9PoNNQIuXw=" + }, + "tail": { + "$ref": "AAAAAAGL8e8PL0VmSkQ=" + }, + "lineStyle": 1, + "points": "4027:1791;4124:1565", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL+9Ru2zbGfmg=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL+9Ru2zbHIig=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL+9Ru2zbIGgw=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAGL+9Se8smboVw=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL+9Se8MmZLdo=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9Se8smclxw=", + "_parent": { + "$ref": "AAAAAAGL+9Se8smboVw=" + }, + "model": { + "$ref": "AAAAAAGL+9Se8MmZLdo=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3357, + "top": 1895, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+9Se8smboVw=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9Se8smdmXM=", + "_parent": { + "$ref": "AAAAAAGL+9Se8smboVw=" + }, + "model": { + "$ref": "AAAAAAGL+9Se8MmZLdo=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 3347, + "top": 1884, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+9Se8smboVw=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9Se8smeaGk=", + "_parent": { + "$ref": "AAAAAAGL+9Se8smboVw=" + }, + "model": { + "$ref": "AAAAAAGL+9Se8MmZLdo=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3378, + "top": 1916, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+9Se8smboVw=" + }, + "edgePosition": 1 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL+9O3Fr8A9kM=" + }, + "tail": { + "$ref": "AAAAAAGL8kwWNOvs/ko=" + }, + "lineStyle": 1, + "points": "3266:2735;3368:1912;3745:1557", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL+9Se8smclxw=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL+9Se8smdmXM=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL+9Se8smeaGk=" + } + }, + { + "_type": "UMLDependencyView", + "_id": "AAAAAAGL+9V6x0TV/+Y=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL+9V6xkTTcHA=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9V6yETWAtw=", + "_parent": { + "$ref": "AAAAAAGL+9V6x0TV/+Y=" + }, + "model": { + "$ref": "AAAAAAGL+9V6xkTTcHA=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3526, + "top": 1588, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+9V6x0TV/+Y=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9V6yETXVbY=", + "_parent": { + "$ref": "AAAAAAGL+9V6x0TV/+Y=" + }, + "model": { + "$ref": "AAAAAAGL+9V6xkTTcHA=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 3532, + "top": 1574, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+9V6x0TV/+Y=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9V6yETYeeg=", + "_parent": { + "$ref": "AAAAAAGL+9V6x0TV/+Y=" + }, + "model": { + "$ref": "AAAAAAGL+9V6xkTTcHA=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3513, + "top": 1615, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+9V6x0TV/+Y=" + }, + "edgePosition": 1 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL8e8PL0VmSkQ=" + }, + "tail": { + "$ref": "AAAAAAGL3EC6Nug8Ro0=" + }, + "lineStyle": 1, + "points": "3583:1029;3520:1608;3959:1803", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL+9V6yETWAtw=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL+9V6yETXVbY=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL+9V6yETYeeg=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAGL+9YU3awXKn8=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL+9YU26wTNo0=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9YU3qwY2s8=", + "_parent": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + }, + "model": { + "$ref": "AAAAAAGL+9YU26wTNo0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4041, + "top": 1141, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9YU3qwZHX0=", + "_parent": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + }, + "model": { + "$ref": "AAAAAAGL+9YU26wTNo0=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 4055, + "top": 1147, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9YU3qwaaAc=", + "_parent": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + }, + "model": { + "$ref": "AAAAAAGL+9YU26wTNo0=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4014, + "top": 1130, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9YU3qwbL8I=", + "_parent": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + }, + "model": { + "$ref": "AAAAAAGL+9YU26wUZOY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4091, + "top": 1020, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9YU3qwcWnI=", + "_parent": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + }, + "model": { + "$ref": "AAAAAAGL+9YU26wUZOY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4103, + "top": 1027, + "height": 13, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9YU3qwd9bg=", + "_parent": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + }, + "model": { + "$ref": "AAAAAAGL+9YU26wUZOY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4068, + "top": 1006, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9YU3qwe/3E=", + "_parent": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + }, + "model": { + "$ref": "AAAAAAGL+9YU26wVXhc=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3991, + "top": 1262, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9YU3qwfUbg=", + "_parent": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + }, + "model": { + "$ref": "AAAAAAGL+9YU26wVXhc=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4004, + "top": 1265, + "height": 13, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9YU3qwgFmc=", + "_parent": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + }, + "model": { + "$ref": "AAAAAAGL+9YU26wVXhc=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3964, + "top": 1256, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + } + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL+9YU3qwhe/Y=", + "_parent": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + }, + "model": { + "$ref": "AAAAAAGL+9YU26wUZOY=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL+9YU3qwiTuU=", + "_parent": { + "$ref": "AAAAAAGL+9YU3awXKn8=" + }, + "model": { + "$ref": "AAAAAAGL+9YU26wVXhc=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL+82j3FEcyoc=" + }, + "tail": { + "$ref": "AAAAAAGL8e9J0ldJrjo=" + }, + "lineStyle": 1, + "points": "4088:997;3968:1287", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL+9YU3qwY2s8=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL+9YU3qwZHX0=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL+9YU3qwaaAc=" + }, + "showEndOrder": "hide", + "tailRoleNameLabel": { + "$ref": "AAAAAAGL+9YU3qwbL8I=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAGL+9YU3qwcWnI=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAGL+9YU3qwd9bg=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAGL+9YU3qwe/3E=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAGL+9YU3qwfUbg=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAGL+9YU3qwgFmc=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAGL+9YU3qwhe/Y=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAGL+9YU3qwiTuU=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAGL+9lB22JQZ5E=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL+9lB2GJMfIE=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9lB22JRtlE=", + "_parent": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + }, + "model": { + "$ref": "AAAAAAGL+9lB2GJMfIE=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3666, + "top": 1082, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9lB22JSZXA=", + "_parent": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + }, + "model": { + "$ref": "AAAAAAGL+9lB2GJMfIE=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 3678, + "top": 1073, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9lB22JT9HQ=", + "_parent": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + }, + "model": { + "$ref": "AAAAAAGL+9lB2GJMfIE=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3643, + "top": 1101, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9lB22JUfvg=", + "_parent": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + }, + "model": { + "$ref": "AAAAAAGL+9lB2WJNfVI=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3630, + "top": 1034, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9lB22JV6mA=", + "_parent": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + }, + "model": { + "$ref": "AAAAAAGL+9lB2WJNfVI=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3642, + "top": 1028, + "height": 13, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9lB22JWWlA=", + "_parent": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + }, + "model": { + "$ref": "AAAAAAGL+9lB2WJNfVI=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3606, + "top": 1047, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9lB22JX5gk=", + "_parent": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + }, + "model": { + "$ref": "AAAAAAGL+9lB2WJO1RQ=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3704, + "top": 1131, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9lB22JYWWM=", + "_parent": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + }, + "model": { + "$ref": "AAAAAAGL+9lB2WJO1RQ=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3713, + "top": 1121, + "height": 13, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9lB22JZ4j0=", + "_parent": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + }, + "model": { + "$ref": "AAAAAAGL+9lB2WJO1RQ=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3684, + "top": 1151, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + } + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL+9lB22JagX4=", + "_parent": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + }, + "model": { + "$ref": "AAAAAAGL+9lB2WJNfVI=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL+9lB3GJbP0E=", + "_parent": { + "$ref": "AAAAAAGL+9lB22JQZ5E=" + }, + "model": { + "$ref": "AAAAAAGL+9lB2WJO1RQ=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL8fAHTpcfcxQ=" + }, + "tail": { + "$ref": "AAAAAAGL3EC6Nug8Ro0=" + }, + "lineStyle": 1, + "points": "3603:1029;3708:1167", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL+9lB22JRtlE=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL+9lB22JSZXA=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL+9lB22JT9HQ=" + }, + "showEndOrder": "hide", + "tailRoleNameLabel": { + "$ref": "AAAAAAGL+9lB22JUfvg=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAGL+9lB22JV6mA=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAGL+9lB22JWWlA=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAGL+9lB22JX5gk=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAGL+9lB22JYWWM=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAGL+9lB22JZ4j0=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAGL+9lB22JagX4=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAGL+9lB3GJbP0E=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAGL+9lQ0XokzqM=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL+9lQz3og1pg=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9lQ0XolXG4=", + "_parent": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + }, + "model": { + "$ref": "AAAAAAGL+9lQz3og1pg=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3916, + "top": 1073, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9lQ0Xomv/A=", + "_parent": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + }, + "model": { + "$ref": "AAAAAAGL+9lQz3og1pg=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 3920, + "top": 1059, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9lQ0XoniIU=", + "_parent": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + }, + "model": { + "$ref": "AAAAAAGL+9lQz3og1pg=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3909, + "top": 1102, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9lQ0XoorW0=", + "_parent": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + }, + "model": { + "$ref": "AAAAAAGL+9lQz3ohaCY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3640, + "top": 999, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9lQ0Xop+7o=", + "_parent": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + }, + "model": { + "$ref": "AAAAAAGL+9lQz3ohaCY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3646, + "top": 987, + "height": 13, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9lQ0noqobQ=", + "_parent": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + }, + "model": { + "$ref": "AAAAAAGL+9lQz3ohaCY=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3629, + "top": 1024, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9lQ0norYrs=", + "_parent": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + }, + "model": { + "$ref": "AAAAAAGL+9lQz3oiCYc=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4193, + "top": 1148, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9lQ0nosRNA=", + "_parent": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + }, + "model": { + "$ref": "AAAAAAGL+9lQz3oiCYc=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4195, + "top": 1135, + "height": 13, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL+9lQ0notl+k=", + "_parent": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + }, + "model": { + "$ref": "AAAAAAGL+9lQz3oiCYc=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4190, + "top": 1176, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + } + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL+9lQ0nou4Os=", + "_parent": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + }, + "model": { + "$ref": "AAAAAAGL+9lQz3ohaCY=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL+9lQ0nov3ao=", + "_parent": { + "$ref": "AAAAAAGL+9lQ0XokzqM=" + }, + "model": { + "$ref": "AAAAAAGL+9lQz3oiCYc=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL3EA5py45w5E=" + }, + "tail": { + "$ref": "AAAAAAGL3EC6Nug8Ro0=" + }, + "lineStyle": 1, + "points": "3612:1013;4215:1176", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL+9lQ0XolXG4=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL+9lQ0Xomv/A=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL+9lQ0XoniIU=" + }, + "showEndOrder": "hide", + "tailRoleNameLabel": { + "$ref": "AAAAAAGL+9lQ0XoorW0=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAGL+9lQ0Xop+7o=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAGL+9lQ0noqobQ=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAGL+9lQ0norYrs=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAGL+9lQ0nosRNA=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAGL+9lQ0notl+k=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAGL+9lQ0nou4Os=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAGL+9lQ0nov3ao=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAGL++Z1Ierpd8M=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL++Z1IOrl2bA=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++Z1Iurq+hE=", + "_parent": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + }, + "model": { + "$ref": "AAAAAAGL++Z1IOrl2bA=" + }, + "font": "Arial;13;0", + "left": 3351, + "top": 2848, + "width": 121.03076171875, + "height": 13, + "alpha": 0.6921845475682045, + "distance": 98.95453501482385, + "hostEdge": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + }, + "edgePosition": 1, + "text": "-entrainementList" + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++Z1Iurrux4=", + "_parent": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + }, + "model": { + "$ref": "AAAAAAGL++Z1IOrl2bA=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 3340, + "top": 2806, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++Z1IursKqY=", + "_parent": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + }, + "model": { + "$ref": "AAAAAAGL++Z1IOrl2bA=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3303, + "top": 2832, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++Z1IurtNUc=", + "_parent": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + }, + "model": { + "$ref": "AAAAAAGL++Z1IOrmj24=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3307, + "top": 2787, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++Z1IuruW3k=", + "_parent": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + }, + "model": { + "$ref": "AAAAAAGL++Z1IOrmj24=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3319, + "top": 2781, + "height": 13, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++Z1Iurv9ho=", + "_parent": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + }, + "model": { + "$ref": "AAAAAAGL++Z1IOrmj24=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3282, + "top": 2799, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++Z1Iurw9sk=", + "_parent": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + }, + "model": { + "$ref": "AAAAAAGL++Z1IOrnew4=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3348, + "top": 2843, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++Z1Iurx+J8=", + "_parent": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + }, + "model": { + "$ref": "AAAAAAGL++Z1IOrnew4=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3358, + "top": 2833, + "height": 13, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++Z1IuryFxs=", + "_parent": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + }, + "model": { + "$ref": "AAAAAAGL++Z1IOrnew4=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3329, + "top": 2862, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + } + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL++Z1Iurz82s=", + "_parent": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + }, + "model": { + "$ref": "AAAAAAGL++Z1IOrmj24=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL++Z1Iur0tvc=", + "_parent": { + "$ref": "AAAAAAGL++Z1Ierpd8M=" + }, + "model": { + "$ref": "AAAAAAGL++Z1IOrnew4=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL3DMzZkmwpP8=" + }, + "tail": { + "$ref": "AAAAAAGL8kwWNOvs/ko=" + }, + "lineStyle": 1, + "points": "3280:2781;3352:2879", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL++Z1Iurq+hE=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL++Z1Iurrux4=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL++Z1IursKqY=" + }, + "showEndOrder": "hide", + "tailRoleNameLabel": { + "$ref": "AAAAAAGL++Z1IurtNUc=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAGL++Z1IuruW3k=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAGL++Z1Iurv9ho=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAGL++Z1Iurw9sk=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAGL++Z1Iurx+J8=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAGL++Z1IuryFxs=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAGL++Z1Iurz82s=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAGL++Z1Iur0tvc=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGL++aCHApuNNY=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL++aCGgpsPN4=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGL++aCHApv9g0=", + "_parent": { + "$ref": "AAAAAAGL++aCHApuNNY=" + }, + "model": { + "$ref": "AAAAAAGL++aCGgpsPN4=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGL++aCHApwYGY=", + "_parent": { + "$ref": "AAAAAAGL++aCHApv9g0=" + }, + "visible": false, + "font": "Arial;13;0", + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL++aCHApxh8E=", + "_parent": { + "$ref": "AAAAAAGL++aCHApv9g0=" + }, + "font": "Arial;13;1", + "left": 3397, + "top": 3215, + "width": 124.95361328125, + "height": 13, + "text": "EntrainementSportif" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL++aCHApytmc=", + "_parent": { + "$ref": "AAAAAAGL++aCHApv9g0=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGL++aCHApzgMU=", + "_parent": { + "$ref": "AAAAAAGL++aCHApv9g0=" + }, + "visible": false, + "font": "Arial;13;0", + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 3392, + "top": 3208, + "width": 134.95361328125, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGL++aCHApwYGY=" + }, + "nameLabel": { + "$ref": "AAAAAAGL++aCHApxh8E=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGL++aCHApytmc=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL++aCHApzgMU=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGL++aCHAp0YNk=", + "_parent": { + "$ref": "AAAAAAGL++aCHApuNNY=" + }, + "model": { + "$ref": "AAAAAAGL++aCGgpsPN4=" + }, + "font": "Arial;13;0", + "left": 3392, + "top": 3233, + "width": 134.95361328125, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGL++aCHQp1bng=", + "_parent": { + "$ref": "AAAAAAGL++aCHApuNNY=" + }, + "model": { + "$ref": "AAAAAAGL++aCGgpsPN4=" + }, + "font": "Arial;13;0", + "left": 3392, + "top": 3243, + "width": 134.95361328125, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGL++aCHQp2hLc=", + "_parent": { + "$ref": "AAAAAAGL++aCHApuNNY=" + }, + "model": { + "$ref": "AAAAAAGL++aCGgpsPN4=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGL++aCHQp3KP0=", + "_parent": { + "$ref": "AAAAAAGL++aCHApuNNY=" + }, + "model": { + "$ref": "AAAAAAGL++aCGgpsPN4=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 3392, + "top": 3208, + "width": 134.95361328125, + "height": 45, + "nameCompartment": { + "$ref": "AAAAAAGL++aCHApv9g0=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGL++aCHAp0YNk=" + }, + "operationCompartment": { + "$ref": "AAAAAAGL++aCHQp1bng=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGL++aCHQp2hLc=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGL++aCHQp3KP0=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAGL++arOhiEW1s=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL++arORiCGus=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++arOxiFTMI=", + "_parent": { + "$ref": "AAAAAAGL++arOhiEW1s=" + }, + "model": { + "$ref": "AAAAAAGL++arORiCGus=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3437, + "top": 3154, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL++arOhiEW1s=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++arOxiGkAc=", + "_parent": { + "$ref": "AAAAAAGL++arOhiEW1s=" + }, + "model": { + "$ref": "AAAAAAGL++arORiCGus=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 3422, + "top": 3155, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL++arOhiEW1s=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++arOxiHKFc=", + "_parent": { + "$ref": "AAAAAAGL++arOhiEW1s=" + }, + "model": { + "$ref": "AAAAAAGL++arORiCGus=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3466, + "top": 3153, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL++arOhiEW1s=" + }, + "edgePosition": 1 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL3DMzZkmwpP8=" + }, + "tail": { + "$ref": "AAAAAAGL++aCHApuNNY=" + }, + "lineStyle": 1, + "points": "3456:3207;3449:3114", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL++arOxiFTMI=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL++arOxiGkAc=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL++arOxiHKFc=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAGL++iBH/dTm1o=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGL++iBHvdP07A=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++iBH/dUZHc=", + "_parent": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + }, + "model": { + "$ref": "AAAAAAGL++iBHvdP07A=" + }, + "font": "Arial;13;0", + "left": 3352, + "top": 2440, + "width": 145.60888671875, + "height": 13, + "alpha": 3.678431948894711, + "distance": 42, + "hostEdge": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + }, + "edgePosition": 1, + "text": "#entrainementRepository" + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++iBIPdVuVs=", + "_parent": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + }, + "model": { + "$ref": "AAAAAAGL++iBHvdP07A=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 3449, + "top": 2497, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++iBIPdW3Xk=", + "_parent": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + }, + "model": { + "$ref": "AAAAAAGL++iBHvdP07A=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3411, + "top": 2474, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++iBIPdXmHU=", + "_parent": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + }, + "model": { + "$ref": "AAAAAAGL++iBHvdQzLE=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3911, + "top": 2415, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++iBIPdY5+E=", + "_parent": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + }, + "model": { + "$ref": "AAAAAAGL++iBHvdQzLE=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3911, + "top": 2428, + "height": 13, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++iBIPdZNqU=", + "_parent": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + }, + "model": { + "$ref": "AAAAAAGL++iBHvdQzLE=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3911, + "top": 2387, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++iBIPdaKH4=", + "_parent": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + }, + "model": { + "$ref": "AAAAAAGL++iBHvdR3xE=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3303, + "top": 2714, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++iBIPdblc8=", + "_parent": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + }, + "model": { + "$ref": "AAAAAAGL++iBHvdR3xE=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3315, + "top": 2719, + "height": 13, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGL++iBIPdcVS0=", + "_parent": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + }, + "model": { + "$ref": "AAAAAAGL++iBHvdR3xE=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 3277, + "top": 2704, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + } + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL++iBIPddals=", + "_parent": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + }, + "model": { + "$ref": "AAAAAAGL++iBHvdQzLE=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGL++iBIPdem5g=", + "_parent": { + "$ref": "AAAAAAGL++iBH/dTm1o=" + }, + "model": { + "$ref": "AAAAAAGL++iBHvdR3xE=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGL8kwWNOvs/ko=" + }, + "tail": { + "$ref": "AAAAAAGL3BqoCyTo5V4=" + }, + "lineStyle": 1, + "points": "3935:2402;3424:2488;3277:2735", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGL++iBH/dUZHc=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGL++iBIPdVuVs=" + }, + "propertyLabel": { + "$ref": "AAAAAAGL++iBIPdW3Xk=" + }, + "showEndOrder": "hide", + "tailRoleNameLabel": { + "$ref": "AAAAAAGL++iBIPdXmHU=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAGL++iBIPdY5+E=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAGL++iBIPdZNqU=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAGL++iBIPdaKH4=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAGL++iBIPdblc8=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAGL++iBIPdcVS0=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAGL++iBIPddals=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAGL++iBIPdem5g=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGMBpdAZwuU9Ko=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGMBpdAZQuSkhA=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGMBpdAaAuVC8E=", + "_parent": { + "$ref": "AAAAAAGMBpdAZwuU9Ko=" + }, + "model": { + "$ref": "AAAAAAGMBpdAZQuSkhA=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGMBpdAaAuWiv8=", + "_parent": { + "$ref": "AAAAAAGMBpdAaAuVC8E=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -16, + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGMBpdAaAuXB5Q=", + "_parent": { + "$ref": "AAAAAAGMBpdAaAuVC8E=" + }, + "font": "Arial;13;1", + "left": 4613, + "top": 815, + "width": 70.08447265625, + "height": 13, + "text": "IFileReader" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGMBpdAaAuY0IM=", + "_parent": { + "$ref": "AAAAAAGMBpdAaAuVC8E=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -16, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGMBpdAaAuZ2rI=", + "_parent": { + "$ref": "AAAAAAGMBpdAaAuVC8E=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -16, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 4608, + "top": 808, + "width": 80.08447265625, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGMBpdAaAuWiv8=" + }, + "nameLabel": { + "$ref": "AAAAAAGMBpdAaAuXB5Q=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGMBpdAaAuY0IM=" + }, + "propertyLabel": { + "$ref": "AAAAAAGMBpdAaAuZ2rI=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGMBpdAaQuaSkI=", + "_parent": { + "$ref": "AAAAAAGMBpdAZwuU9Ko=" + }, + "model": { + "$ref": "AAAAAAGMBpdAZQuSkhA=" + }, + "font": "Arial;13;0", + "left": 4608, + "top": 833, + "width": 80.08447265625, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGMBpdAaQubhRA=", + "_parent": { + "$ref": "AAAAAAGMBpdAZwuU9Ko=" + }, + "model": { + "$ref": "AAAAAAGMBpdAZQuSkhA=" + }, + "font": "Arial;13;0", + "left": 4608, + "top": 843, + "width": 80.08447265625, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGMBpdAaQucVWQ=", + "_parent": { + "$ref": "AAAAAAGMBpdAZwuU9Ko=" + }, + "model": { + "$ref": "AAAAAAGMBpdAZQuSkhA=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -8, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGMBpdAaQudKxk=", + "_parent": { + "$ref": "AAAAAAGMBpdAZwuU9Ko=" + }, + "model": { + "$ref": "AAAAAAGMBpdAZQuSkhA=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -8, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 4608, + "top": 808, + "width": 80.08447265625, + "height": 45, + "nameCompartment": { + "$ref": "AAAAAAGMBpdAaAuVC8E=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGMBpdAaQuaSkI=" + }, + "operationCompartment": { + "$ref": "AAAAAAGMBpdAaQubhRA=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGMBpdAaQucVWQ=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGMBpdAaQudKxk=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGMBpd9jA67nyk=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGMBpd9ig65uB8=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGMBpd9jA68eic=", + "_parent": { + "$ref": "AAAAAAGMBpd9jA67nyk=" + }, + "model": { + "$ref": "AAAAAAGMBpd9ig65uB8=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGMBpd9jA69DEg=", + "_parent": { + "$ref": "AAAAAAGMBpd9jA68eic=" + }, + "visible": false, + "font": "Arial;13;0", + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGMBpd9jA6++N4=", + "_parent": { + "$ref": "AAAAAAGMBpd9jA68eic=" + }, + "font": "Arial;13;1", + "left": 4573, + "top": 1175, + "width": 75.1181640625, + "height": 13, + "text": "AthlketeMgr" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGMBpd9jA6/8qY=", + "_parent": { + "$ref": "AAAAAAGMBpd9jA68eic=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGMBpd9jA7AJO0=", + "_parent": { + "$ref": "AAAAAAGMBpd9jA68eic=" + }, + "visible": false, + "font": "Arial;13;0", + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 4568, + "top": 1168, + "width": 85.1181640625, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGMBpd9jA69DEg=" + }, + "nameLabel": { + "$ref": "AAAAAAGMBpd9jA6++N4=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGMBpd9jA6/8qY=" + }, + "propertyLabel": { + "$ref": "AAAAAAGMBpd9jA7AJO0=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGMBpd9jA7B6Ps=", + "_parent": { + "$ref": "AAAAAAGMBpd9jA67nyk=" + }, + "model": { + "$ref": "AAAAAAGMBpd9ig65uB8=" + }, + "font": "Arial;13;0", + "left": 4568, + "top": 1193, + "width": 85.1181640625, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGMBpd9jQ7CylI=", + "_parent": { + "$ref": "AAAAAAGMBpd9jA67nyk=" + }, + "model": { + "$ref": "AAAAAAGMBpd9ig65uB8=" + }, + "font": "Arial;13;0", + "left": 4568, + "top": 1203, + "width": 85.1181640625, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGMBpd9jQ7DFus=", + "_parent": { + "$ref": "AAAAAAGMBpd9jA67nyk=" + }, + "model": { + "$ref": "AAAAAAGMBpd9ig65uB8=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGMBpd9jQ7EUI0=", + "_parent": { + "$ref": "AAAAAAGMBpd9jA67nyk=" + }, + "model": { + "$ref": "AAAAAAGMBpd9ig65uB8=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 4568, + "top": 1168, + "width": 85.1181640625, + "height": 45, + "nameCompartment": { + "$ref": "AAAAAAGMBpd9jA68eic=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGMBpd9jA7B6Ps=" + }, + "operationCompartment": { + "$ref": "AAAAAAGMBpd9jQ7CylI=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGMBpd9jQ7DFus=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGMBpd9jQ7EUI0=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAGMBperHCDV/Mc=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGMBperGiDRgno=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBperHCDWjP4=", + "_parent": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + }, + "model": { + "$ref": "AAAAAAGMBperGiDRgno=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4613, + "top": 1002, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBperHCDXrqs=", + "_parent": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + }, + "model": { + "$ref": "AAAAAAGMBperGiDRgno=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 4598, + "top": 1000, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBperHCDYm6E=", + "_parent": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + }, + "model": { + "$ref": "AAAAAAGMBperGiDRgno=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4642, + "top": 1005, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBperHCDZ0hM=", + "_parent": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + }, + "model": { + "$ref": "AAAAAAGMBperGiDSkv4=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4599, + "top": 1133, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBperHCDa9C0=", + "_parent": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + }, + "model": { + "$ref": "AAAAAAGMBperGiDSkv4=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4586, + "top": 1129, + "height": 13, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBperHCDbV2Q=", + "_parent": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + }, + "model": { + "$ref": "AAAAAAGMBperGiDSkv4=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4626, + "top": 1140, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBperHSDcI7U=", + "_parent": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + }, + "model": { + "$ref": "AAAAAAGMBperGiDT2kA=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4627, + "top": 871, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBperHSDdRYk=", + "_parent": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + }, + "model": { + "$ref": "AAAAAAGMBperGiDT2kA=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4613, + "top": 872, + "height": 13, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBperHSDee18=", + "_parent": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + }, + "model": { + "$ref": "AAAAAAGMBperGiDT2kA=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4655, + "top": 869, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + } + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGMBperHSDfwBk=", + "_parent": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + }, + "model": { + "$ref": "AAAAAAGMBperGiDSkv4=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGMBperHSDgy0c=", + "_parent": { + "$ref": "AAAAAAGMBperHCDV/Mc=" + }, + "model": { + "$ref": "AAAAAAGMBperGiDT2kA=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGMBpdAZwuU9Ko=" + }, + "tail": { + "$ref": "AAAAAAGMBpd9jA67nyk=" + }, + "lineStyle": 1, + "points": "4612:1167;4645:853", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGMBperHCDWjP4=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGMBperHCDXrqs=" + }, + "propertyLabel": { + "$ref": "AAAAAAGMBperHCDYm6E=" + }, + "showEndOrder": "hide", + "tailRoleNameLabel": { + "$ref": "AAAAAAGMBperHCDZ0hM=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAGMBperHCDa9C0=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAGMBperHCDbV2Q=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAGMBperHSDcI7U=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAGMBperHSDdRYk=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAGMBperHSDee18=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAGMBperHSDfwBk=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAGMBperHSDgy0c=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGMBpe7/iSd2yE=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGMBpe7/CSbj9A=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGMBpe7/iSeTew=", + "_parent": { + "$ref": "AAAAAAGMBpe7/iSd2yE=" + }, + "model": { + "$ref": "AAAAAAGMBpe7/CSbj9A=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGMBpe7/iSfpKY=", + "_parent": { + "$ref": "AAAAAAGMBpe7/iSeTew=" + }, + "visible": false, + "font": "Arial;13;0", + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGMBpe7/iSg9/o=", + "_parent": { + "$ref": "AAAAAAGMBpe7/iSeTew=" + }, + "font": "Arial;13;1", + "left": 4845, + "top": 999, + "width": 41.919921875, + "height": 13, + "text": "Fit" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGMBpe7/iShO0o=", + "_parent": { + "$ref": "AAAAAAGMBpe7/iSeTew=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGMBpe7/iSizgA=", + "_parent": { + "$ref": "AAAAAAGMBpe7/iSeTew=" + }, + "visible": false, + "font": "Arial;13;0", + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 4840, + "top": 992, + "width": 51.919921875, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGMBpe7/iSfpKY=" + }, + "nameLabel": { + "$ref": "AAAAAAGMBpe7/iSg9/o=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGMBpe7/iShO0o=" + }, + "propertyLabel": { + "$ref": "AAAAAAGMBpe7/iSizgA=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGMBpe7/iSjG28=", + "_parent": { + "$ref": "AAAAAAGMBpe7/iSd2yE=" + }, + "model": { + "$ref": "AAAAAAGMBpe7/CSbj9A=" + }, + "font": "Arial;13;0", + "left": 4840, + "top": 1017, + "width": 51.919921875, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGMBpe7/iSkAzo=", + "_parent": { + "$ref": "AAAAAAGMBpe7/iSd2yE=" + }, + "model": { + "$ref": "AAAAAAGMBpe7/CSbj9A=" + }, + "font": "Arial;13;0", + "left": 4840, + "top": 1027, + "width": 51.919921875, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGMBpe7/ySlufY=", + "_parent": { + "$ref": "AAAAAAGMBpe7/iSd2yE=" + }, + "model": { + "$ref": "AAAAAAGMBpe7/CSbj9A=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGMBpe7/ySmCFQ=", + "_parent": { + "$ref": "AAAAAAGMBpe7/iSd2yE=" + }, + "model": { + "$ref": "AAAAAAGMBpe7/CSbj9A=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 4840, + "top": 992, + "width": 51.919921875, + "height": 45, + "nameCompartment": { + "$ref": "AAAAAAGMBpe7/iSeTew=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGMBpe7/iSjG28=" + }, + "operationCompartment": { + "$ref": "AAAAAAGMBpe7/iSkAzo=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGMBpe7/ySlufY=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGMBpe7/ySmCFQ=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAGMBpfYWy3ZgGs=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGMBpfYWi3Xomc=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBpfYXC3aIX8=", + "_parent": { + "$ref": "AAAAAAGMBpfYWy3ZgGs=" + }, + "model": { + "$ref": "AAAAAAGMBpfYWi3Xomc=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4746, + "top": 927, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGMBpfYWy3ZgGs=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBpfYXC3btwY=", + "_parent": { + "$ref": "AAAAAAGMBpfYWy3ZgGs=" + }, + "model": { + "$ref": "AAAAAAGMBpfYWi3Xomc=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 4736, + "top": 938, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGMBpfYWy3ZgGs=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBpfYXC3c538=", + "_parent": { + "$ref": "AAAAAAGMBpfYWy3ZgGs=" + }, + "model": { + "$ref": "AAAAAAGMBpfYWi3Xomc=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4765, + "top": 904, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGMBpfYWy3ZgGs=" + }, + "edgePosition": 1 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGMBpdAZwuU9Ko=" + }, + "tail": { + "$ref": "AAAAAAGMBpe7/iSd2yE=" + }, + "lineStyle": 1, + "points": "4839:992;4674:853", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGMBpfYXC3aIX8=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGMBpfYXC3btwY=" + }, + "propertyLabel": { + "$ref": "AAAAAAGMBpfYXC3c538=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGMBpo0VtxckhI=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGMBpo0VdxaKM0=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGMBpo0V9xdlNU=", + "_parent": { + "$ref": "AAAAAAGMBpo0VtxckhI=" + }, + "model": { + "$ref": "AAAAAAGMBpo0VdxaKM0=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGMBpo0V9xe4j4=", + "_parent": { + "$ref": "AAAAAAGMBpo0V9xdlNU=" + }, + "visible": false, + "font": "Arial;13;0", + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGMBpo0V9xfU9w=", + "_parent": { + "$ref": "AAAAAAGMBpo0V9xdlNU=" + }, + "font": "Arial;13;1", + "left": 4805, + "top": 3055, + "width": 66.47265625, + "height": 13, + "text": "IAnalyseur" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGMBpo0V9xgOy8=", + "_parent": { + "$ref": "AAAAAAGMBpo0V9xdlNU=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGMBpo0V9xhYak=", + "_parent": { + "$ref": "AAAAAAGMBpo0V9xdlNU=" + }, + "visible": false, + "font": "Arial;13;0", + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 4800, + "top": 3048, + "width": 76.47265625, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGMBpo0V9xe4j4=" + }, + "nameLabel": { + "$ref": "AAAAAAGMBpo0V9xfU9w=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGMBpo0V9xgOy8=" + }, + "propertyLabel": { + "$ref": "AAAAAAGMBpo0V9xhYak=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGMBpo0V9xinDc=", + "_parent": { + "$ref": "AAAAAAGMBpo0VtxckhI=" + }, + "model": { + "$ref": "AAAAAAGMBpo0VdxaKM0=" + }, + "font": "Arial;13;0", + "left": 4800, + "top": 3073, + "width": 76.47265625, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGMBpo0V9xjdcE=", + "_parent": { + "$ref": "AAAAAAGMBpo0VtxckhI=" + }, + "model": { + "$ref": "AAAAAAGMBpo0VdxaKM0=" + }, + "font": "Arial;13;0", + "left": 4800, + "top": 3083, + "width": 76.47265625, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGMBpo0V9xk5v8=", + "_parent": { + "$ref": "AAAAAAGMBpo0VtxckhI=" + }, + "model": { + "$ref": "AAAAAAGMBpo0VdxaKM0=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGMBpo0V9xl6vk=", + "_parent": { + "$ref": "AAAAAAGMBpo0VtxckhI=" + }, + "model": { + "$ref": "AAAAAAGMBpo0VdxaKM0=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 4800, + "top": 3048, + "width": 76.47265625, + "height": 45, + "nameCompartment": { + "$ref": "AAAAAAGMBpo0V9xdlNU=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGMBpo0V9xinDc=" + }, + "operationCompartment": { + "$ref": "AAAAAAGMBpo0V9xjdcE=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGMBpo0V9xk5v8=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGMBpo0V9xl6vk=" + } + }, + { + "_type": "UMLAssociationView", + "_id": "AAAAAAGMBppPXOnSowQ=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGMBppPWenO/AQ=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBppPXenT8H4=", + "_parent": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + }, + "model": { + "$ref": "AAAAAAGMBppPWenO/AQ=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4619, + "top": 3072, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBppPXenUjNw=", + "_parent": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + }, + "model": { + "$ref": "AAAAAAGMBppPWenO/AQ=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 4617, + "top": 3057, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBppPXenVYiY=", + "_parent": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + }, + "model": { + "$ref": "AAAAAAGMBppPWenO/AQ=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4622, + "top": 3101, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBppPXenWrjU=", + "_parent": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + }, + "model": { + "$ref": "AAAAAAGMBppPWunPg3A=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4467, + "top": 3088, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBppPXenXSC0=", + "_parent": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + }, + "model": { + "$ref": "AAAAAAGMBppPWunPg3A=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4468, + "top": 3074, + "height": 13, + "alpha": 0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBppPXenY2s0=", + "_parent": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + }, + "model": { + "$ref": "AAAAAAGMBppPWunPg3A=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4465, + "top": 3116, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + }, + "edgePosition": 2 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBppPXenZWUM=", + "_parent": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + }, + "model": { + "$ref": "AAAAAAGMBppPWunQr5E=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4771, + "top": 3055, + "height": 13, + "alpha": -0.5235987755982988, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBppPXenavXk=", + "_parent": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + }, + "model": { + "$ref": "AAAAAAGMBppPWunQr5E=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4767, + "top": 3042, + "height": 13, + "alpha": -0.7853981633974483, + "distance": 40, + "hostEdge": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + } + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBppPXenbBMk=", + "_parent": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + }, + "model": { + "$ref": "AAAAAAGMBppPWunQr5E=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4778, + "top": 3082, + "height": 13, + "alpha": 0.5235987755982988, + "distance": 25, + "hostEdge": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + } + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGMBppPXunclvs=", + "_parent": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + }, + "model": { + "$ref": "AAAAAAGMBppPWunPg3A=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + }, + { + "_type": "UMLQualifierCompartmentView", + "_id": "AAAAAAGMBppPXundICc=", + "_parent": { + "$ref": "AAAAAAGMBppPXOnSowQ=" + }, + "model": { + "$ref": "AAAAAAGMBppPWunQr5E=" + }, + "visible": false, + "font": "Arial;13;0", + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGMBpo0VtxckhI=" + }, + "tail": { + "$ref": "AAAAAAGL3DH0VM3eelw=" + }, + "lineStyle": 1, + "points": "4443:3112;4799:3074", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGMBppPXenT8H4=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGMBppPXenUjNw=" + }, + "propertyLabel": { + "$ref": "AAAAAAGMBppPXenVYiY=" + }, + "showEndOrder": "hide", + "tailRoleNameLabel": { + "$ref": "AAAAAAGMBppPXenWrjU=" + }, + "tailPropertyLabel": { + "$ref": "AAAAAAGMBppPXenXSC0=" + }, + "tailMultiplicityLabel": { + "$ref": "AAAAAAGMBppPXenY2s0=" + }, + "headRoleNameLabel": { + "$ref": "AAAAAAGMBppPXenZWUM=" + }, + "headPropertyLabel": { + "$ref": "AAAAAAGMBppPXenavXk=" + }, + "headMultiplicityLabel": { + "$ref": "AAAAAAGMBppPXenbBMk=" + }, + "tailQualifiersCompartment": { + "$ref": "AAAAAAGMBppPXunclvs=" + }, + "headQualifiersCompartment": { + "$ref": "AAAAAAGMBppPXundICc=" + } + }, + { + "_type": "UMLClassView", + "_id": "AAAAAAGMBqILMi7wY5A=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGMBqILMC7uP0g=" + }, + "subViews": [ + { + "_type": "UMLNameCompartmentView", + "_id": "AAAAAAGMBqILMi7xX9g=", + "_parent": { + "$ref": "AAAAAAGMBqILMi7wY5A=" + }, + "model": { + "$ref": "AAAAAAGMBqILMC7uP0g=" + }, + "subViews": [ + { + "_type": "LabelView", + "_id": "AAAAAAGMBqILMi7yY/E=", + "_parent": { + "$ref": "AAAAAAGMBqILMi7xX9g=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -496, + "top": 224, + "height": 13 + }, + { + "_type": "LabelView", + "_id": "AAAAAAGMBqILMi7zRDg=", + "_parent": { + "$ref": "AAAAAAGMBqILMi7xX9g=" + }, + "font": "Arial;13;1", + "left": 4805, + "top": 3191, + "width": 62.86083984375, + "height": 13, + "text": "Analyseur" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGMBqILMi70pg8=", + "_parent": { + "$ref": "AAAAAAGMBqILMi7xX9g=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -496, + "top": 224, + "width": 73.67724609375, + "height": 13, + "text": "(from Model)" + }, + { + "_type": "LabelView", + "_id": "AAAAAAGMBqILMi71Nx4=", + "_parent": { + "$ref": "AAAAAAGMBqILMi7xX9g=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -496, + "top": 224, + "height": 13, + "horizontalAlignment": 1 + } + ], + "font": "Arial;13;0", + "left": 4800, + "top": 3184, + "width": 72.86083984375, + "height": 25, + "stereotypeLabel": { + "$ref": "AAAAAAGMBqILMi7yY/E=" + }, + "nameLabel": { + "$ref": "AAAAAAGMBqILMi7zRDg=" + }, + "namespaceLabel": { + "$ref": "AAAAAAGMBqILMi70pg8=" + }, + "propertyLabel": { + "$ref": "AAAAAAGMBqILMi71Nx4=" + } + }, + { + "_type": "UMLAttributeCompartmentView", + "_id": "AAAAAAGMBqILMi72bC0=", + "_parent": { + "$ref": "AAAAAAGMBqILMi7wY5A=" + }, + "model": { + "$ref": "AAAAAAGMBqILMC7uP0g=" + }, + "font": "Arial;13;0", + "left": 4800, + "top": 3209, + "width": 72.86083984375, + "height": 10 + }, + { + "_type": "UMLOperationCompartmentView", + "_id": "AAAAAAGMBqILMy73IbQ=", + "_parent": { + "$ref": "AAAAAAGMBqILMi7wY5A=" + }, + "model": { + "$ref": "AAAAAAGMBqILMC7uP0g=" + }, + "font": "Arial;13;0", + "left": 4800, + "top": 3219, + "width": 72.86083984375, + "height": 10 + }, + { + "_type": "UMLReceptionCompartmentView", + "_id": "AAAAAAGMBqILMy74L7c=", + "_parent": { + "$ref": "AAAAAAGMBqILMi7wY5A=" + }, + "model": { + "$ref": "AAAAAAGMBqILMC7uP0g=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -248, + "top": 112, + "width": 10, + "height": 10 + }, + { + "_type": "UMLTemplateParameterCompartmentView", + "_id": "AAAAAAGMBqILMy75p6M=", + "_parent": { + "$ref": "AAAAAAGMBqILMi7wY5A=" + }, + "model": { + "$ref": "AAAAAAGMBqILMC7uP0g=" + }, + "visible": false, + "font": "Arial;13;0", + "left": -248, + "top": 112, + "width": 10, + "height": 10 + } + ], + "font": "Arial;13;0", + "containerChangeable": true, + "left": 4800, + "top": 3184, + "width": 72.86083984375, + "height": 45, + "nameCompartment": { + "$ref": "AAAAAAGMBqILMi7xX9g=" + }, + "attributeCompartment": { + "$ref": "AAAAAAGMBqILMi72bC0=" + }, + "operationCompartment": { + "$ref": "AAAAAAGMBqILMy73IbQ=" + }, + "receptionCompartment": { + "$ref": "AAAAAAGMBqILMy74L7c=" + }, + "templateParameterCompartment": { + "$ref": "AAAAAAGMBqILMy75p6M=" + } + }, + { + "_type": "UMLGeneralizationView", + "_id": "AAAAAAGMBsEyOiaLjws=", + "_parent": { + "$ref": "AAAAAAFF+qBtyKM79qY=" + }, + "model": { + "$ref": "AAAAAAGMBsEyOCaJKLw=" + }, + "subViews": [ + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBsEyOiaMm/Q=", + "_parent": { + "$ref": "AAAAAAGMBsEyOiaLjws=" + }, + "model": { + "$ref": "AAAAAAGMBsEyOCaJKLw=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4821, + "top": 3131, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGMBsEyOiaLjws=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBsEyOiaNpAg=", + "_parent": { + "$ref": "AAAAAAGMBsEyOiaLjws=" + }, + "model": { + "$ref": "AAAAAAGMBsEyOCaJKLw=" + }, + "visible": null, + "font": "Arial;13;0", + "left": 4806, + "top": 3131, + "height": 13, + "alpha": 1.5707963267948966, + "distance": 30, + "hostEdge": { + "$ref": "AAAAAAGMBsEyOiaLjws=" + }, + "edgePosition": 1 + }, + { + "_type": "EdgeLabelView", + "_id": "AAAAAAGMBsEyOiaOgTs=", + "_parent": { + "$ref": "AAAAAAGMBsEyOiaLjws=" + }, + "model": { + "$ref": "AAAAAAGMBsEyOCaJKLw=" + }, + "visible": false, + "font": "Arial;13;0", + "left": 4850, + "top": 3132, + "height": 13, + "alpha": -1.5707963267948966, + "distance": 15, + "hostEdge": { + "$ref": "AAAAAAGMBsEyOiaLjws=" + }, + "edgePosition": 1 + } + ], + "font": "Arial;13;0", + "head": { + "$ref": "AAAAAAGMBpo0VtxckhI=" + }, + "tail": { + "$ref": "AAAAAAGMBqILMi7wY5A=" + }, + "lineStyle": 1, + "points": "4835:3183;4837:3093", + "showVisibility": true, + "nameLabel": { + "$ref": "AAAAAAGMBsEyOiaMm/Q=" + }, + "stereotypeLabel": { + "$ref": "AAAAAAGMBsEyOiaNpAg=" + }, + "propertyLabel": { + "$ref": "AAAAAAGMBsEyOiaOgTs=" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLo/fkFXnWSO0=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Utilisateur", + "ownedElements": [ + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGLpAecPh2uaoQ=", + "_parent": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "source": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "target": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + } + }, + { + "_type": "UMLConstraint", + "_id": "AAAAAAGLpAxpgR4ZI4c=", + "_parent": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "name": "Constraint1" + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLw8Girlz2pU0=", + "_parent": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw8Girlz3DrY=", + "_parent": { + "$ref": "AAAAAAGLw8Girlz2pU0=" + }, + "reference": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw8Girlz43FQ=", + "_parent": { + "$ref": "AAAAAAGLw8Girlz2pU0=" + }, + "reference": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL3BrkDnIc/Ag=", + "_parent": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "name": "role", + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3BrkD3IdNgc=", + "_parent": { + "$ref": "AAAAAAGL3BrkDnIc/Ag=" + }, + "reference": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3BrkD3IeED0=", + "_parent": { + "$ref": "AAAAAAGL3BrkDnIc/Ag=" + }, + "reference": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "navigable": "navigable" + } + } + ], + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAGL+9pa8rlijfg=", + "_parent": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "name": "id", + "visibility": "private", + "type": "int" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGL4p5pjeQNzxA=", + "_parent": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "name": "username", + "visibility": "private", + "type": "String" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLpAD5vx0yijE=", + "_parent": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "name": "id", + "type": "" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLpAHrOB1Dmpw=", + "_parent": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "name": "nom", + "visibility": "private", + "type": "String" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLpAHubx1JTgc=", + "_parent": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "name": "prenom", + "visibility": "private", + "type": "String" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLpAHxSR1PUSs=", + "_parent": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "name": "email", + "visibility": "private", + "type": "String" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLpAH0SB1VgF8=", + "_parent": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "name": "sexe", + "visibility": "private", + "type": "String" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLpAH2wh1b3Gg=", + "_parent": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "name": "taille", + "visibility": "private", + "type": "Float" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLpAH5dB1h8j4=", + "_parent": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "name": "poids", + "visibility": "private", + "type": "float" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLpAH8Jx1ngTU=", + "_parent": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "name": "motDePasse", + "visibility": "private", + "type": "String" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLpAH+3B1t8HQ=", + "_parent": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "name": "dateNaissance", + "visibility": "private", + "type": "Date" + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLpAZHmx2CSnc=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Coach", + "ownedElements": [ + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGLpAzL8h4kabg=", + "_parent": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + }, + "source": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + }, + "target": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLpCliuwcCjzg=", + "_parent": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLpCliuwcDUVw=", + "_parent": { + "$ref": "AAAAAAGLpCliuwcCjzg=" + }, + "reference": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLpCliuwcEgfY=", + "_parent": { + "$ref": "AAAAAAGLpCliuwcCjzg=" + }, + "reference": { + "$ref": "AAAAAAGLpCIKk+d152w=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLrxtF+5qFc8A=", + "_parent": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLrxtF+5qGyTw=", + "_parent": { + "$ref": "AAAAAAGLrxtF+5qFc8A=" + }, + "reference": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLrxtF+5qHrhY=", + "_parent": { + "$ref": "AAAAAAGLrxtF+5qFc8A=" + }, + "reference": { + "$ref": "AAAAAAGLrxlW1I2zOyU=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLDependency", + "_id": "AAAAAAGLrxumQrU4vyI=", + "_parent": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + }, + "source": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + }, + "target": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + } + }, + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGLw8G3EmoOXHk=", + "_parent": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + }, + "source": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + }, + "target": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL3BvCOTlsc2M=", + "_parent": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + }, + "name": "*lesAthletes", + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3BvCOjltmkU=", + "_parent": { + "$ref": "AAAAAAGL3BvCOTlsc2M=" + }, + "reference": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3BvCOjluKwE=", + "_parent": { + "$ref": "AAAAAAGL3BvCOTlsc2M=" + }, + "reference": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGL3B0hp6VJcj4=", + "_parent": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + }, + "source": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + }, + "target": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + } + } + ], + "stereotype": "abstract" + }, + { + "_type": "UMLInterface", + "_id": "AAAAAAGLpAwf8B3QX1g=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Interface1" + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLpAzboB41ECQ=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Athlete", + "ownedElements": [ + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGLpAz8rx5frvk=", + "_parent": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "source": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "target": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLpCNbyef3xVM=", + "_parent": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLpCNbyuf4TUk=", + "_parent": { + "$ref": "AAAAAAGLpCNbyef3xVM=" + }, + "reference": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLpCNbyuf5Owk=", + "_parent": { + "$ref": "AAAAAAGLpCNbyef3xVM=" + }, + "reference": { + "$ref": "AAAAAAGLpCMdQOfM2Wo=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLDependency", + "_id": "AAAAAAGLpCUhQfKy6BM=", + "_parent": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "source": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "target": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLrw2ZlZxbXCg=", + "_parent": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLrw2ZlZxcFvQ=", + "_parent": { + "$ref": "AAAAAAGLrw2ZlZxbXCg=" + }, + "reference": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLrw2ZlZxdZjo=", + "_parent": { + "$ref": "AAAAAAGLrw2ZlZxbXCg=" + }, + "reference": { + "$ref": "AAAAAAGLpCqsVQhTM54=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLrxtvS62Q1yw=", + "_parent": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLrxtvS62RQtA=", + "_parent": { + "$ref": "AAAAAAGLrxtvS62Q1yw=" + }, + "reference": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLrxtvTK2SVQE=", + "_parent": { + "$ref": "AAAAAAGLrxtvS62Q1yw=" + }, + "reference": { + "$ref": "AAAAAAGLrxlW1I2zOyU=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLDependency", + "_id": "AAAAAAGLrx7/fTi27wg=", + "_parent": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "source": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "target": { + "$ref": "AAAAAAGLpCMdQOfM2Wo=" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLrx/5OVEi78k=", + "_parent": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLrx/5OVEjXTE=", + "_parent": { + "$ref": "AAAAAAGLrx/5OVEi78k=" + }, + "reference": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLrx/5OVEkE+s=", + "_parent": { + "$ref": "AAAAAAGLrx/5OVEi78k=" + }, + "reference": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLDependency", + "_id": "AAAAAAGLryAmY1g6f3w=", + "_parent": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "source": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "target": { + "$ref": "AAAAAAGLpC6+3hxaFwM=" + } + }, + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGLw8HHMXjjv4w=", + "_parent": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "source": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "target": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + } + }, + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGL3B0TsZu6iEw=", + "_parent": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "source": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "target": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL3DO5CWGzYdk=", + "_parent": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "name": "*activiteList", + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3DO5CWG0ZOw=", + "_parent": { + "$ref": "AAAAAAGL3DO5CWGzYdk=" + }, + "reference": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3DO5CmG1yFk=", + "_parent": { + "$ref": "AAAAAAGL3DO5CWGzYdk=" + }, + "reference": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "navigable": "navigable" + }, + "visibility": "private" + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL3Ddn/grGOiw=", + "_parent": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "name": "*sdList", + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3Ddn/grHlaI=", + "_parent": { + "$ref": "AAAAAAGL3Ddn/grGOiw=" + }, + "reference": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3Ddn/grIS6Y=", + "_parent": { + "$ref": "AAAAAAGL3Ddn/grGOiw=" + }, + "reference": { + "$ref": "AAAAAAGLpCqsVQhTM54=" + }, + "navigable": "navigable" + }, + "visibility": "private" + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL3DgOmzocF5c=", + "_parent": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "name": "*statsList", + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3DgOnDodXGk=", + "_parent": { + "$ref": "AAAAAAGL3DgOmzocF5c=" + }, + "reference": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3DgOnDoedKI=", + "_parent": { + "$ref": "AAAAAAGL3DgOmzocF5c=" + }, + "reference": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "navigable": "navigable" + }, + "visibility": "private" + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL3D32NRysQcE=", + "_parent": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3D32NRytcgc=", + "_parent": { + "$ref": "AAAAAAGL3D32NRysQcE=" + }, + "reference": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3D32NRyuVZo=", + "_parent": { + "$ref": "AAAAAAGL3D32NRysQcE=" + }, + "name": "ent", + "reference": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + }, + "navigable": "navigable" + } + } + ], + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAGL3Cav216fXX4=", + "_parent": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "name": "getAthlete", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3CbrLmGdRT8=", + "_parent": { + "$ref": "AAAAAAGL3Cav216fXX4=" + }, + "type": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL3CcA1GT//kE=", + "_parent": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "name": "getActivite", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3Cg0I2bvypE=", + "_parent": { + "$ref": "AAAAAAGL3CcA1GT//kE=" + }, + "type": "lesActivite", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL3DDNcZtsRlI=", + "_parent": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "name": "getStatistiques", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3DEvup1chzs=", + "_parent": { + "$ref": "AAAAAAGL3DDNcZtsRlI=" + }, + "type": "lesStats", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL3EaRsi0pEF4=", + "_parent": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "name": "getSourceDonnees", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3EbayDAnCWI=", + "_parent": { + "$ref": "AAAAAAGL3EaRsi0pEF4=" + }, + "type": "lesSD", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL3DEwGp4As4s=", + "_parent": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "name": "__toString", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3DGxWJ/xM/c=", + "_parent": { + "$ref": "AAAAAAGL3DEwGp4As4s=" + }, + "type": "String", + "direction": "return" + } + ] + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLpCIKk+d152w=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Analyse", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLpDFQTUb/JFU=", + "_parent": { + "$ref": "AAAAAAGLpCIKk+d152w=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLpDFQTUcAb8I=", + "_parent": { + "$ref": "AAAAAAGLpDFQTUb/JFU=" + }, + "reference": { + "$ref": "AAAAAAGLpCIKk+d152w=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLpDFQTUcBF6U=", + "_parent": { + "$ref": "AAAAAAGLpDFQTUb/JFU=" + }, + "reference": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "navigable": "navigable" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLpCJOKOeiXS4=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Activite", + "ownedElements": [ + { + "_type": "UMLDependency", + "_id": "AAAAAAGLpCQyD+pd5dY=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "source": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "target": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLpCkkyQISTtc=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLpCkkyQIT3V8=", + "_parent": { + "$ref": "AAAAAAGLpCkkyQISTtc=" + }, + "reference": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLpCkkyQIUk7c=", + "_parent": { + "$ref": "AAAAAAGLpCkkyQISTtc=" + }, + "reference": { + "$ref": "AAAAAAGLpCIKk+d152w=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLpCrtIwt6IIM=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLpCrtJAt7teE=", + "_parent": { + "$ref": "AAAAAAGLpCrtIwt6IIM=" + }, + "reference": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLpCrtJAt8tqE=", + "_parent": { + "$ref": "AAAAAAGLpCrtIwt6IIM=" + }, + "reference": { + "$ref": "AAAAAAGLpCqsVQhTM54=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL3DewVSCksyY=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3DewViClTrY=", + "_parent": { + "$ref": "AAAAAAGL3DewVSCksyY=" + }, + "reference": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3DewViCmmWs=", + "_parent": { + "$ref": "AAAAAAGL3DewVSCksyY=" + }, + "reference": { + "$ref": "AAAAAAGLpCqsVQhTM54=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGMBppPWenO/AQ=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGMBppPWunPg3A=", + "_parent": { + "$ref": "AAAAAAGMBppPWenO/AQ=" + }, + "reference": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGMBppPWunQr5E=", + "_parent": { + "$ref": "AAAAAAGMBppPWenO/AQ=" + }, + "reference": { + "$ref": "AAAAAAGMBpo0VdxaKM0=" + }, + "navigable": "navigable" + } + } + ], + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLpCXSK/WOLkA=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "name": "idActivite", + "visibility": "private", + "type": "int" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxCVfeebjRQ=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "name": "type", + "visibility": "private", + "type": "string" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxCvKejL/fw=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "name": "date", + "visibility": "private", + "type": "Date" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxDHu+n7GHc=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "name": "heureDebut", + "visibility": "private", + "type": "time" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxDu8esr6vo=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "name": "heureFin", + "visibility": "private", + "type": "time" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxEIwOxboHI=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "name": "effortRessenti", + "visibility": "private", + "type": "int" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxJXpe2Lor0=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "name": "variabilite", + "visibility": "private", + "type": "float" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxKISe67v6E=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "name": "variance", + "visibility": "private", + "type": "float" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxKpzu/rHo4=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "name": "ecartType", + "visibility": "private", + "type": "float" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxLaO/Ebr8k=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "name": "moyenne", + "visibility": "private", + "type": "float" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxL5PfJLk04=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "name": "maximum", + "visibility": "private", + "type": "int" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxM0SfWY9pQ=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "name": "minimum", + "visibility": "private", + "type": "int" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxNQCvbIr2U=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "name": "TemperatureMoyenne", + "visibility": "private", + "type": "float" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGMBkKf7yn3AyI=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "name": "pause", + "visibility": "private", + "type": "bool" + } + ], + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAGL3DQ2catj1/Q=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "name": "getActivite", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3DSrMq6LST8=", + "_parent": { + "$ref": "AAAAAAGL3DQ2catj1/Q=" + }, + "type": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL3DTgKchiipU=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "name": "getAnalyse", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3DXHucptwRw=", + "_parent": { + "$ref": "AAAAAAGL3DTgKchiipU=" + }, + "name": "a1", + "type": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + } + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3DXHuspuz9Q=", + "_parent": { + "$ref": "AAAAAAGL3DTgKchiipU=" + }, + "type": "String", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL3DXeGc46SeI=", + "_parent": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "name": "toString", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3DYdBdBF0T4=", + "_parent": { + "$ref": "AAAAAAGL3DXeGc46SeI=" + }, + "name": "Activite", + "type": "" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3DYdBtBGMg8=", + "_parent": { + "$ref": "AAAAAAGL3DXeGc46SeI=" + }, + "type": "String", + "direction": "return" + } + ] + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLpCMdQOfM2Wo=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Activitheque", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLpCN16+h8aQ0=", + "_parent": { + "$ref": "AAAAAAGLpCMdQOfM2Wo=" + }, + "name": "lesActivites", + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLpCN17+h9pms=", + "_parent": { + "$ref": "AAAAAAGLpCN16+h8aQ0=" + }, + "reference": { + "$ref": "AAAAAAGLpCMdQOfM2Wo=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLpCN17+h+bfw=", + "_parent": { + "$ref": "AAAAAAGLpCN16+h8aQ0=" + }, + "reference": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "navigable": "navigable" + }, + "visibility": "private" + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLpCTkfe4C0zU=", + "_parent": { + "$ref": "AAAAAAGLpCMdQOfM2Wo=" + }, + "name": "*lesActivites", + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLpCTkfu4DUbA=", + "_parent": { + "$ref": "AAAAAAGLpCTkfe4C0zU=" + }, + "reference": { + "$ref": "AAAAAAGLpCMdQOfM2Wo=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLpCTkfu4EADw=", + "_parent": { + "$ref": "AAAAAAGLpCTkfe4C0zU=" + }, + "reference": { + "$ref": "AAAAAAGLpCJOKOeiXS4=" + }, + "navigable": "navigable" + } + } + ], + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAGLpCVoW/TUDTs=", + "_parent": { + "$ref": "AAAAAAGLpCMdQOfM2Wo=" + }, + "name": "Operation1" + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLpCqsVQhTM54=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "SourceDonnee", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxTIICbUAdU=", + "_parent": { + "$ref": "AAAAAAGLpCqsVQhTM54=" + }, + "name": "idSource", + "visibility": "private", + "type": "int" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxTswiiLUpA=", + "_parent": { + "$ref": "AAAAAAGLpCqsVQhTM54=" + }, + "name": "Type", + "visibility": "private", + "type": "enum" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxVKVSm7bms=", + "_parent": { + "$ref": "AAAAAAGLpCqsVQhTM54=" + }, + "name": "modele", + "visibility": "private", + "type": "string" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxV3+SrrCr8=", + "_parent": { + "$ref": "AAAAAAGLpCqsVQhTM54=" + }, + "name": "precision", + "visibility": "private", + "type": "enum" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxWfnSwbQ58=", + "_parent": { + "$ref": "AAAAAAGLpCqsVQhTM54=" + }, + "name": "dateDerniereUtilisation", + "visibility": "private", + "type": "Date" + } + ], + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAGL3EcVFjuykz0=", + "_parent": { + "$ref": "AAAAAAGLpCqsVQhTM54=" + }, + "name": "getSD", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3Ed/tEBUogw=", + "_parent": { + "$ref": "AAAAAAGL3EcVFjuykz0=" + }, + "name": "SourceDonnee", + "type": "" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3Ed/tUBVIpo=", + "_parent": { + "$ref": "AAAAAAGL3EcVFjuykz0=" + }, + "type": "String", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL3EeezUzS6YA=", + "_parent": { + "$ref": "AAAAAAGLpCqsVQhTM54=" + }, + "name": "to_String", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3EfxCE/QIC8=", + "_parent": { + "$ref": "AAAAAAGL3EeezUzS6YA=" + }, + "name": "SourceDonnee", + "type": "" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3EfxCk/RWz4=", + "_parent": { + "$ref": "AAAAAAGL3EeezUzS6YA=" + }, + "type": "String", + "direction": "return" + } + ] + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLpC6+3hxaFwM=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Notification", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLpC8ityhF+Rs=", + "_parent": { + "$ref": "AAAAAAGLpC6+3hxaFwM=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLpC8iuChGpgc=", + "_parent": { + "$ref": "AAAAAAGLpC8ityhF+Rs=" + }, + "reference": { + "$ref": "AAAAAAGLpC6+3hxaFwM=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLpC8iuChHuYc=", + "_parent": { + "$ref": "AAAAAAGLpC8ityhF+Rs=" + }, + "reference": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "navigable": "navigable" + } + } + ], + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrwTQNkoBs18=", + "_parent": { + "$ref": "AAAAAAGLpC6+3hxaFwM=" + }, + "name": "idNotification", + "visibility": "private", + "type": "int" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrwWAclJrDg4=", + "_parent": { + "$ref": "AAAAAAGLpC6+3hxaFwM=" + }, + "name": "message", + "visibility": "private", + "type": "text" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrwXMTFPyfWM=", + "_parent": { + "$ref": "AAAAAAGLpC6+3hxaFwM=" + }, + "name": "date", + "visibility": "private", + "type": "Date" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrwXq6FUBKfs=", + "_parent": { + "$ref": "AAAAAAGLpC6+3hxaFwM=" + }, + "name": "statut", + "visibility": "private", + "type": "boolean" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrwhVcFox6nk=", + "_parent": { + "$ref": "AAAAAAGLpC6+3hxaFwM=" + }, + "name": "Urgence", + "visibility": "private", + "type": "enum" + } + ], + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAGLrwVqf1F1q2A=", + "_parent": { + "$ref": "AAAAAAGLpC6+3hxaFwM=" + }, + "name": "Operation1" + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLpDCydyvBWA4=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Statistique", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLpDDf2zNOiFs=", + "_parent": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLpDDf2zNP3wA=", + "_parent": { + "$ref": "AAAAAAGLpDDf2zNOiFs=" + }, + "reference": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLpDDf2zNQzDU=", + "_parent": { + "$ref": "AAAAAAGLpDDf2zNOiFs=" + }, + "reference": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "navigable": "navigable" + } + } + ], + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrwixuGGJpE4=", + "_parent": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "name": "idStatistique", + "visibility": "private", + "type": "int" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrwlhdmOIz0E=", + "_parent": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "name": "distanceTotale", + "visibility": "private", + "type": "float" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrwmwgWUPuog=", + "_parent": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "name": "poids", + "visibility": "private", + "type": "float" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrwnYLWYeNa4=", + "_parent": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "name": "tempsTotal", + "visibility": "private", + "type": "time" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrwoPTGct0ws=", + "_parent": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "name": "FCmoyenne", + "visibility": "private", + "type": "int" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrwps72g8dI8=", + "_parent": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "name": "FCmin", + "visibility": "private", + "type": "int" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrwqb7mlLpYw=", + "_parent": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "name": "FCmax", + "visibility": "private", + "type": "int" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrwq/JGpaMCs=", + "_parent": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "name": "caloriesBrulées", + "visibility": "private", + "type": "int" + } + ], + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAGL3EVAEQqWm2c=", + "_parent": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "name": "getStatistique", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3EWyFw84O9s=", + "_parent": { + "$ref": "AAAAAAGL3EVAEQqWm2c=" + }, + "type": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL3EWydxA200E=", + "_parent": { + "$ref": "AAAAAAGLpDCydyvBWA4=" + }, + "name": "__toString", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3EX7bBOIgbw=", + "_parent": { + "$ref": "AAAAAAGL3EWydxA200E=" + }, + "name": "Statistique", + "type": "" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3EX7bROJu3A=", + "_parent": { + "$ref": "AAAAAAGL3EWydxA200E=" + }, + "type": "String", + "direction": "return" + } + ] + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLpDGNPV37CeU=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Main", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAGLpDG1k1/VDfE=", + "_parent": { + "$ref": "AAAAAAGLpDGNPV37CeU=" + }, + "name": "Operation1" + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLpDN9jGOcNzo=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Afficheur" + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLpDOU2mUWdIY=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Saissiseur" + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLpDO85Wao3Xs=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Suppresseur" + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLrxb6dUqeBKo=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Entrainement", + "ownedElements": [ + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGL++OFOjnitkY=", + "_parent": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "source": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "target": { + "$ref": "AAAAAAGL8lJC3yKeddk=" + } + } + ], + "stereotype": "abstract", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxcxm0yu9ck=", + "_parent": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "name": "idEntrainement", + "type": "int" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxdjg05lkd0=", + "_parent": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "name": "date", + "type": "Date" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGL7QbRBNAl41g=", + "_parent": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "name": "latitude", + "type": "float" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxeDFU+VhpI=", + "_parent": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "name": "longitude", + "type": "float" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxezwlDFkh4=", + "_parent": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "name": "description", + "type": "text" + }, + { + "_type": "UMLAttribute", + "_id": "AAAAAAGLrxfiTFH1ArI=", + "_parent": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "name": "feedback", + "type": "text" + } + ], + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAGL3D2F3gDGuRs=", + "_parent": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "name": "getId", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3D3LVQdJ3C4=", + "_parent": { + "$ref": "AAAAAAGL3D2F3gDGuRs=" + }, + "type": "int", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL++UQDELkhBM=", + "_parent": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "name": "getDate", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL++U2OEZpVpc=", + "_parent": { + "$ref": "AAAAAAGL++UQDELkhBM=" + }, + "type": "DateTime", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL++U2j0eU938=", + "_parent": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "name": "getLocation", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL++VhlEsZBcw=", + "_parent": { + "$ref": "AAAAAAGL++U2j0eU938=" + }, + "type": "String", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL++Vh50xEGPg=", + "_parent": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "name": "getDescription", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL++Wi6k/JzIU=", + "_parent": { + "$ref": "AAAAAAGL++Vh50xEGPg=" + }, + "type": "Text", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL++WjUVD03ak=", + "_parent": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "name": "getFeedBack", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL++XGtVR5vT8=", + "_parent": { + "$ref": "AAAAAAGL++WjUVD03ak=" + }, + "type": "String", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL++XHM1Wk8GA=", + "_parent": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "name": "__toString", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL++XvGlkp8eA=", + "_parent": { + "$ref": "AAAAAAGL++XHM1Wk8GA=" + }, + "type": "String", + "direction": "return" + } + ] + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLrxlW1I2zOyU=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Groupe", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLrxtgF6RW9mw=", + "_parent": { + "$ref": "AAAAAAGLrxlW1I2zOyU=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLrxtgF6RXHhs=", + "_parent": { + "$ref": "AAAAAAGLrxtgF6RW9mw=" + }, + "reference": { + "$ref": "AAAAAAGLrxlW1I2zOyU=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLrxtgF6RY8Ic=", + "_parent": { + "$ref": "AAAAAAGLrxtgF6RW9mw=" + }, + "reference": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLrxxzThcUhGA=", + "_parent": { + "$ref": "AAAAAAGLrxlW1I2zOyU=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLrxxzThcVL6o=", + "_parent": { + "$ref": "AAAAAAGLrxxzThcUhGA=" + }, + "reference": { + "$ref": "AAAAAAGLrxlW1I2zOyU=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLrxxzThcWPZ8=", + "_parent": { + "$ref": "AAAAAAGLrxxzThcUhGA=" + }, + "reference": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + }, + "navigable": "navigable" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLw7nD48sOfVM=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "index.php", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLw7pt1PGAP1c=", + "_parent": { + "$ref": "AAAAAAGLw7nD48sOfVM=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw7pt1PGB1i0=", + "_parent": { + "$ref": "AAAAAAGLw7pt1PGAP1c=" + }, + "reference": { + "$ref": "AAAAAAGLw7nD48sOfVM=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw7pt1PGCpVw=", + "_parent": { + "$ref": "AAAAAAGLw7pt1PGAP1c=" + }, + "reference": { + "$ref": "AAAAAAGLw7oXg9WQpWI=" + }, + "navigable": "navigable" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLw7oXg9WQpWI=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Console.php", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLw7x8nxMcncI=", + "_parent": { + "$ref": "AAAAAAGLw7oXg9WQpWI=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw7x8nxMdRU0=", + "_parent": { + "$ref": "AAAAAAGLw7x8nxMcncI=" + }, + "reference": { + "$ref": "AAAAAAGLw7oXg9WQpWI=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw7x8nxMeKxY=", + "_parent": { + "$ref": "AAAAAAGLw7x8nxMcncI=" + }, + "reference": { + "$ref": "AAAAAAGLw7v65PPlleU=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLDependency", + "_id": "AAAAAAGLw8OfyokBM5A=", + "_parent": { + "$ref": "AAAAAAGLw7oXg9WQpWI=" + }, + "source": { + "$ref": "AAAAAAGLw7oXg9WQpWI=" + }, + "target": { + "$ref": "AAAAAAGLw7v65PPlleU=" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLw7v65PPlleU=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "DataManager", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLw739qDtrDhg=", + "_parent": { + "$ref": "AAAAAAGLw7v65PPlleU=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw739qDtsLsw=", + "_parent": { + "$ref": "AAAAAAGLw739qDtrDhg=" + }, + "reference": { + "$ref": "AAAAAAGLw7v65PPlleU=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw739qDtt8oQ=", + "_parent": { + "$ref": "AAAAAAGLw739qDtrDhg=" + }, + "reference": { + "$ref": "AAAAAAGLw722NTGx6eY=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL3EEppBTCx28=", + "_parent": { + "$ref": "AAAAAAGLw7v65PPlleU=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3EEppBTDPCs=", + "_parent": { + "$ref": "AAAAAAGL3EEppBTCx28=" + }, + "reference": { + "$ref": "AAAAAAGLw7v65PPlleU=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3EEppBTE3EY=", + "_parent": { + "$ref": "AAAAAAGL3EEppBTCx28=" + }, + "reference": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL8lXBSa6/2w4=", + "_parent": { + "$ref": "AAAAAAGLw7v65PPlleU=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lXBSa7AoxY=", + "_parent": { + "$ref": "AAAAAAGL8lXBSa6/2w4=" + }, + "reference": { + "$ref": "AAAAAAGLw7v65PPlleU=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lXBSa7B00o=", + "_parent": { + "$ref": "AAAAAAGL8lXBSa6/2w4=" + }, + "reference": { + "$ref": "AAAAAAGL8e9J0FdHmso=" + }, + "navigable": "navigable" + } + } + ], + "stereotype": "abstract" + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLw7wcvPtpS0g=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Stub", + "ownedElements": [ + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGLw7xJLQpG+ik=", + "_parent": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + }, + "source": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + }, + "target": { + "$ref": "AAAAAAGLw7v65PPlleU=" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLw79ywHVPvfw=", + "_parent": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw79ywHVQcT8=", + "_parent": { + "$ref": "AAAAAAGLw79ywHVPvfw=" + }, + "reference": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw79ywHVRW1U=", + "_parent": { + "$ref": "AAAAAAGLw79ywHVPvfw=" + }, + "reference": { + "$ref": "AAAAAAGLw722NTGx6eY=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLDependency", + "_id": "AAAAAAGLw8O3vpcZDOs=", + "_parent": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + }, + "source": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + }, + "target": { + "$ref": "AAAAAAGLw722NTGx6eY=" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL8e3m2zur3i0=", + "_parent": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8e3m3DusHLI=", + "_parent": { + "$ref": "AAAAAAGL8e3m2zur3i0=" + }, + "reference": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8e3m3Dut15M=", + "_parent": { + "$ref": "AAAAAAGL8e3m2zur3i0=" + }, + "reference": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL8lNA6tzH31s=", + "_parent": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lNA6tzIag0=", + "_parent": { + "$ref": "AAAAAAGL8lNA6tzH31s=" + }, + "reference": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lNA6tzJ0wg=", + "_parent": { + "$ref": "AAAAAAGL8lNA6tzH31s=" + }, + "reference": { + "$ref": "AAAAAAGL8e9J0FdHmso=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL+8owjNKG+JM=", + "_parent": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL+8owjNKHXMk=", + "_parent": { + "$ref": "AAAAAAGL+8owjNKG+JM=" + }, + "reference": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL+8owjNKIBW4=", + "_parent": { + "$ref": "AAAAAAGL+8owjNKG+JM=" + }, + "reference": { + "$ref": "AAAAAAGL+8nHIFKZGGE=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLDependency", + "_id": "AAAAAAGL+9V6xkTTcHA=", + "_parent": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + }, + "source": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + }, + "target": { + "$ref": "AAAAAAGL8e8PLkVkOWg=" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL+9lB2GJMfIE=", + "_parent": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL+9lB2WJNfVI=", + "_parent": { + "$ref": "AAAAAAGL+9lB2GJMfIE=" + }, + "reference": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL+9lB2WJO1RQ=", + "_parent": { + "$ref": "AAAAAAGL+9lB2GJMfIE=" + }, + "reference": { + "$ref": "AAAAAAGL8fAHTJcd2Kc=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL+9lQz3og1pg=", + "_parent": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL+9lQz3ohaCY=", + "_parent": { + "$ref": "AAAAAAGL+9lQz3og1pg=" + }, + "reference": { + "$ref": "AAAAAAGLw7wcvPtpS0g=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL+9lQz3oiCYc=", + "_parent": { + "$ref": "AAAAAAGL+9lQz3og1pg=" + }, + "reference": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + }, + "navigable": "navigable" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLw722NTGx6eY=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "IUserManager", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLw77Um1toR1M=", + "_parent": { + "$ref": "AAAAAAGLw722NTGx6eY=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw77Um1tpvS8=", + "_parent": { + "$ref": "AAAAAAGLw77Um1toR1M=" + }, + "reference": { + "$ref": "AAAAAAGLw722NTGx6eY=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw77Um1tqTz8=", + "_parent": { + "$ref": "AAAAAAGLw77Um1toR1M=" + }, + "reference": { + "$ref": "AAAAAAGLw75/NVNSG5E=" + }, + "navigable": "navigable" + } + } + ], + "stereotype": "sbtract" + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLw74acUM+FsM=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "UserManager", + "ownedElements": [ + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGLw75J1lDRG8o=", + "_parent": { + "$ref": "AAAAAAGLw74acUM+FsM=" + }, + "source": { + "$ref": "AAAAAAGLw74acUM+FsM=" + }, + "target": { + "$ref": "AAAAAAGLw722NTGx6eY=" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLw7+J/n3/B1Y=", + "_parent": { + "$ref": "AAAAAAGLw74acUM+FsM=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw7+J/n4AoQo=", + "_parent": { + "$ref": "AAAAAAGLw7+J/n3/B1Y=" + }, + "reference": { + "$ref": "AAAAAAGLw74acUM+FsM=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw7+J/n4BrBk=", + "_parent": { + "$ref": "AAAAAAGLw7+J/n3/B1Y=" + }, + "reference": { + "$ref": "AAAAAAGLw75/NVNSG5E=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLDependency", + "_id": "AAAAAAGLw8PRbqZ11JM=", + "_parent": { + "$ref": "AAAAAAGLw74acUM+FsM=" + }, + "source": { + "$ref": "AAAAAAGLw74acUM+FsM=" + }, + "target": { + "$ref": "AAAAAAGLw75/NVNSG5E=" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLw75/NVNSG5E=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "IAuthService", + "stereotype": "abstract" + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLw77mx15mj/c=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "AuthService", + "ownedElements": [ + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGLw78az2rf0JI=", + "_parent": { + "$ref": "AAAAAAGLw77mx15mj/c=" + }, + "source": { + "$ref": "AAAAAAGLw77mx15mj/c=" + }, + "target": { + "$ref": "AAAAAAGLw75/NVNSG5E=" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLw8AdI58up9U=", + "_parent": { + "$ref": "AAAAAAGLw77mx15mj/c=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw8AdI58v8mI=", + "_parent": { + "$ref": "AAAAAAGLw8AdI58up9U=" + }, + "reference": { + "$ref": "AAAAAAGLw77mx15mj/c=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw8AdI58w4bI=", + "_parent": { + "$ref": "AAAAAAGLw8AdI58up9U=" + }, + "reference": { + "$ref": "AAAAAAGLw7+uCZK14Kw=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLw8DsaAT3Z3E=", + "_parent": { + "$ref": "AAAAAAGLw77mx15mj/c=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw8DsaQT4sn8=", + "_parent": { + "$ref": "AAAAAAGLw8DsaAT3Z3E=" + }, + "reference": { + "$ref": "AAAAAAGLw77mx15mj/c=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw8DsaQT5+dg=", + "_parent": { + "$ref": "AAAAAAGLw8DsaAT3Z3E=" + }, + "reference": { + "$ref": "AAAAAAGLw8CsTvtt06M=" + }, + "navigable": "navigable" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLw7+uCZK14Kw=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "IHashPasswd", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLw8CDXMoYIRA=", + "_parent": { + "$ref": "AAAAAAGLw7+uCZK14Kw=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw8CDXMoZH4o=", + "_parent": { + "$ref": "AAAAAAGLw8CDXMoYIRA=" + }, + "reference": { + "$ref": "AAAAAAGLw7+uCZK14Kw=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw8CDXMoaWgc=", + "_parent": { + "$ref": "AAAAAAGLw8CDXMoYIRA=" + }, + "reference": { + "$ref": "AAAAAAGLw8A1cbelFNg=" + }, + "navigable": "navigable" + } + } + ], + "stereotype": "abstract" + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLw8A1cbelFNg=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "HashPasswd", + "ownedElements": [ + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGLw8P2P7Eq0Zg=", + "_parent": { + "$ref": "AAAAAAGLw8A1cbelFNg=" + }, + "source": { + "$ref": "AAAAAAGLw8A1cbelFNg=" + }, + "target": { + "$ref": "AAAAAAGLw7+uCZK14Kw=" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLw8CsTvtt06M=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "IUserRepository", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLw8E4dyjMplk=", + "_parent": { + "$ref": "AAAAAAGLw8CsTvtt06M=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw8E4dyjNt00=", + "_parent": { + "$ref": "AAAAAAGLw8E4dyjMplk=" + }, + "reference": { + "$ref": "AAAAAAGLw8CsTvtt06M=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw8E4dyjOpGg=", + "_parent": { + "$ref": "AAAAAAGLw8E4dyjMplk=" + }, + "reference": { + "$ref": "AAAAAAGLw8ERdB3gYJY=" + }, + "navigable": "navigable" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLw8ERdB3gYJY=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "UserRepository", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGLw8FINzNWfKU=", + "_parent": { + "$ref": "AAAAAAGLw8ERdB3gYJY=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw8FINzNXfFM=", + "_parent": { + "$ref": "AAAAAAGLw8FINzNWfKU=" + }, + "reference": { + "$ref": "AAAAAAGLw8ERdB3gYJY=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGLw8FINzNYczE=", + "_parent": { + "$ref": "AAAAAAGLw8FINzNWfKU=" + }, + "reference": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "navigable": "navigable" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGLw8GJdFMAfwk=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Role", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL3B3/yvI7wq4=", + "_parent": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "name": "*lesUsers", + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3B3/yvI8/hQ=", + "_parent": { + "$ref": "AAAAAAGL3B3/yvI7wq4=" + }, + "reference": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3B3/yvI9HQU=", + "_parent": { + "$ref": "AAAAAAGL3B3/yvI7wq4=" + }, + "reference": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "navigable": "navigable" + }, + "visibility": "protected" + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL8lAAXUGgrrQ=", + "_parent": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lAAXUGh/wI=", + "_parent": { + "$ref": "AAAAAAGL8lAAXUGgrrQ=" + }, + "reference": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lAAXUGi4/c=", + "_parent": { + "$ref": "AAAAAAGL8lAAXUGgrrQ=" + }, + "reference": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL8lKzBWBVyb4=", + "_parent": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lKzBWBWoKM=", + "_parent": { + "$ref": "AAAAAAGL8lKzBWBVyb4=" + }, + "reference": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lKzBWBXFpY=", + "_parent": { + "$ref": "AAAAAAGL8lKzBWBVyb4=" + }, + "reference": { + "$ref": "AAAAAAGL8lJC3yKeddk=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL++ZRWq9wC2Q=", + "_parent": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL++ZRWq9xmHA=", + "_parent": { + "$ref": "AAAAAAGL++ZRWq9wC2Q=" + }, + "reference": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL++ZRWq9yVyo=", + "_parent": { + "$ref": "AAAAAAGL++ZRWq9wC2Q=" + }, + "reference": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL++iBHvdP07A=", + "_parent": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "name": "entrainementRepository", + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL++iBHvdQzLE=", + "_parent": { + "$ref": "AAAAAAGL++iBHvdP07A=" + }, + "reference": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL++iBHvdR3xE=", + "_parent": { + "$ref": "AAAAAAGL++iBHvdP07A=" + }, + "reference": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + }, + "navigable": "navigable" + }, + "visibility": "protected" + } + ], + "stereotype": "abstract", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAGL3EO77J2JFbo=", + "_parent": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "name": "id", + "visibility": "protected", + "type": "int" + } + ], + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAGL8lDIQHjxa7g=", + "_parent": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "name": "getUsersList", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9z2Wk7Rkl0=", + "_parent": { + "$ref": "AAAAAAGL8lDIQHjxa7g=" + }, + "type": "?array", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL+91tC2YUaHo=", + "_parent": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "name": "getUserList", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+93WVmslMmk=", + "_parent": { + "$ref": "AAAAAAGL+91tC2YUaHo=" + }, + "name": "user", + "type": "User" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+93WWGsme7k=", + "_parent": { + "$ref": "AAAAAAGL+91tC2YUaHo=" + }, + "type": "?User", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL+93v8Z0NH0E=", + "_parent": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "name": "getEntrainement", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+95FxaCSyVw=", + "_parent": { + "$ref": "AAAAAAGL+93v8Z0NH0E=" + }, + "type": "?EntrainementRepository", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL+90Kble5JDw=", + "_parent": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "name": "getEntrainementsList", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+91Bwls+tYg=", + "_parent": { + "$ref": "AAAAAAGL+90Kble5JDw=" + }, + "type": "?array", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL+95b8qX+sig=", + "_parent": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "name": "getEntrainementList", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+97c6amDCSE=", + "_parent": { + "$ref": "AAAAAAGL+95b8qX+sig=" + }, + "name": "entrainement", + "type": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + } + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+97c66mEPPE=", + "_parent": { + "$ref": "AAAAAAGL+95b8qX+sig=" + }, + "type": "?EntrainementSportif", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL8lQnmhRLfho=", + "_parent": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "name": "checkAdd", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL8lRFEBfQcoA=", + "_parent": { + "$ref": "AAAAAAGL8lQnmhRLfho=" + }, + "type": "bool", + "direction": "return" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL8lTMXSaTy7k=", + "_parent": { + "$ref": "AAAAAAGL8lQnmhRLfho=" + }, + "name": "user", + "type": "User" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL8lROwx08WBA=", + "_parent": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "name": "chackAddEntrainement", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL8lSScCDBz5M=", + "_parent": { + "$ref": "AAAAAAGL8lROwx08WBA=" + }, + "name": "entrainement", + "type": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + } + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL8lSSciDCofo=", + "_parent": { + "$ref": "AAAAAAGL8lROwx08WBA=" + }, + "type": "bool", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL3B61dD33CBk=", + "_parent": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "name": "addUser", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3CF8BUD1MaE=", + "_parent": { + "$ref": "AAAAAAGL3B61dD33CBk=" + }, + "name": "user", + "type": "User" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL3CF8BkD2uFE=", + "_parent": { + "$ref": "AAAAAAGL3B61dD33CBk=" + }, + "type": "bool", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL58RPF/SE7Hs=", + "_parent": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "name": "removeUser", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL58SDNfeCYS0=", + "_parent": { + "$ref": "AAAAAAGL58RPF/SE7Hs=" + }, + "name": "user", + "type": "User" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL58SDN/eDi6M=", + "_parent": { + "$ref": "AAAAAAGL58RPF/SE7Hs=" + }, + "type": "bool", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL8lBBHXFLScI=", + "_parent": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "name": "addEntrainement", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL8lCF13QufIw=", + "_parent": { + "$ref": "AAAAAAGL8lBBHXFLScI=" + }, + "name": "entr", + "type": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + } + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL8lCF2HQvGso=", + "_parent": { + "$ref": "AAAAAAGL8lBBHXFLScI=" + }, + "type": "bool", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL++Fe3CpxsSg=", + "_parent": { + "$ref": "AAAAAAGLw8GJdFMAfwk=" + }, + "name": "removeEntrainement", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL++GDKi32bTY=", + "_parent": { + "$ref": "AAAAAAGL++Fe3CpxsSg=" + }, + "name": "entr", + "type": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + } + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL++GDKy3305U=", + "_parent": { + "$ref": "AAAAAAGL++Fe3CpxsSg=" + }, + "type": "bool", + "direction": "return" + } + ] + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGL3CMxnEguLCQ=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "CoachAthlete", + "ownedElements": [ + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGL3CS00FlI+OY=", + "_parent": { + "$ref": "AAAAAAGL3CMxnEguLCQ=" + }, + "source": { + "$ref": "AAAAAAGL3CMxnEguLCQ=" + }, + "target": { + "$ref": "AAAAAAGLpAZHmx2CSnc=" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL3DzrydAwEjA=", + "_parent": { + "$ref": "AAAAAAGL3CMxnEguLCQ=" + }, + "name": "ent", + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3DzrydAx3B4=", + "_parent": { + "$ref": "AAAAAAGL3DzrydAwEjA=" + }, + "reference": { + "$ref": "AAAAAAGL3CMxnEguLCQ=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3DzrydAyGD8=", + "_parent": { + "$ref": "AAAAAAGL3DzrydAwEjA=" + }, + "reference": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLDependency", + "_id": "AAAAAAGL3EhnKwk9Pw0=", + "_parent": { + "$ref": "AAAAAAGL3CMxnEguLCQ=" + }, + "source": { + "$ref": "AAAAAAGL3CMxnEguLCQ=" + }, + "target": { + "$ref": "AAAAAAGLpAzboB41ECQ=" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL++fe3kQi84s=", + "_parent": { + "$ref": "AAAAAAGL3CMxnEguLCQ=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL++fe3kQjPRk=", + "_parent": { + "$ref": "AAAAAAGL++fe3kQi84s=" + }, + "reference": { + "$ref": "AAAAAAGL3CMxnEguLCQ=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL++fe3kQkqMw=", + "_parent": { + "$ref": "AAAAAAGL++fe3kQi84s=" + }, + "reference": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL++hbOMaLLhI=", + "_parent": { + "$ref": "AAAAAAGL3CMxnEguLCQ=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL++hbOMaMnnU=", + "_parent": { + "$ref": "AAAAAAGL++hbOMaLLhI=" + }, + "reference": { + "$ref": "AAAAAAGL3CMxnEguLCQ=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL++hbOMaN3HA=", + "_parent": { + "$ref": "AAAAAAGL++hbOMaLLhI=" + }, + "reference": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + }, + "navigable": "navigable" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGL3EA5pS43tRY=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "CoachManager", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL3EE9vyQmH2s=", + "_parent": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3EE9wCQnjEA=", + "_parent": { + "$ref": "AAAAAAGL3EE9vyQmH2s=" + }, + "reference": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL3EE9wCQorTo=", + "_parent": { + "$ref": "AAAAAAGL3EE9vyQmH2s=" + }, + "reference": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL8lOXnTwD+Jk=", + "_parent": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lOXnTwEKpY=", + "_parent": { + "$ref": "AAAAAAGL8lOXnTwD+Jk=" + }, + "reference": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lOXnTwFBh4=", + "_parent": { + "$ref": "AAAAAAGL8lOXnTwD+Jk=" + }, + "reference": { + "$ref": "AAAAAAGL8e8PLkVkOWg=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGL+8nwg3agVXE=", + "_parent": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + }, + "source": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + }, + "target": { + "$ref": "AAAAAAGL+8nHIFKZGGE=" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL+8rOHkkjQa8=", + "_parent": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL+8rOH0kk5Us=", + "_parent": { + "$ref": "AAAAAAGL+8rOHkkjQa8=" + }, + "reference": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL+8rOH0kl1Ag=", + "_parent": { + "$ref": "AAAAAAGL+8rOHkkjQa8=" + }, + "reference": { + "$ref": "AAAAAAGL8e9J0FdHmso=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGL+9dNnjZFrD0=", + "_parent": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + }, + "source": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + }, + "target": { + "$ref": "AAAAAAGLw7v65PPlleU=" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGL8e8PLkVkOWg=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "UserRepository", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL8lO7+GO/UQE=", + "_parent": { + "$ref": "AAAAAAGL8e8PLkVkOWg=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lO7+GPAblU=", + "_parent": { + "$ref": "AAAAAAGL8lO7+GO/UQE=" + }, + "reference": { + "$ref": "AAAAAAGL8e8PLkVkOWg=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lO7+GPBs+g=", + "_parent": { + "$ref": "AAAAAAGL8lO7+GO/UQE=" + }, + "reference": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGL+9Ru2TbDJ+A=", + "_parent": { + "$ref": "AAAAAAGL8e8PLkVkOWg=" + }, + "source": { + "$ref": "AAAAAAGL8e8PLkVkOWg=" + }, + "target": { + "$ref": "AAAAAAGL+9PoMtQG54g=" + } + } + ], + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAGL+8w3liysleM=", + "_parent": { + "$ref": "AAAAAAGL8e8PLkVkOWg=" + }, + "name": "users", + "visibility": "private", + "type": "array" + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGL8e9J0FdHmso=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "AuthService", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL8lNUk/Ru41c=", + "_parent": { + "$ref": "AAAAAAGL8e9J0FdHmso=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lNUk/RvtFM=", + "_parent": { + "$ref": "AAAAAAGL8lNUk/Ru41c=" + }, + "reference": { + "$ref": "AAAAAAGL8e9J0FdHmso=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lNUk/RwcBM=", + "_parent": { + "$ref": "AAAAAAGL8lNUk/Ru41c=" + }, + "reference": { + "$ref": "AAAAAAGL3EA5pS43tRY=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL8lNl2wXc834=", + "_parent": { + "$ref": "AAAAAAGL8e9J0FdHmso=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lNl2wXdgpY=", + "_parent": { + "$ref": "AAAAAAGL8lNl2wXc834=" + }, + "reference": { + "$ref": "AAAAAAGL8e9J0FdHmso=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lNl2wXekOo=", + "_parent": { + "$ref": "AAAAAAGL8lNl2wXc834=" + }, + "reference": { + "$ref": "AAAAAAGL8fAHTJcd2Kc=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL+8pYQv2ZiyI=", + "_parent": { + "$ref": "AAAAAAGL8e9J0FdHmso=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL+8pYQv2aok8=", + "_parent": { + "$ref": "AAAAAAGL+8pYQv2ZiyI=" + }, + "reference": { + "$ref": "AAAAAAGL8e9J0FdHmso=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL+8pYQv2bihk=", + "_parent": { + "$ref": "AAAAAAGL+8pYQv2ZiyI=" + }, + "reference": { + "$ref": "AAAAAAGL8e8PLkVkOWg=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL+9YU26wTNo0=", + "_parent": { + "$ref": "AAAAAAGL8e9J0FdHmso=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL+9YU26wUZOY=", + "_parent": { + "$ref": "AAAAAAGL+9YU26wTNo0=" + }, + "reference": { + "$ref": "AAAAAAGL8e9J0FdHmso=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL+9YU26wVXhc=", + "_parent": { + "$ref": "AAAAAAGL+9YU26wTNo0=" + }, + "reference": { + "$ref": "AAAAAAGL+82j2lEaUGY=" + }, + "navigable": "navigable" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGL8fAHTJcd2Kc=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "UserManager", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL8lNzphcjVzA=", + "_parent": { + "$ref": "AAAAAAGL8fAHTJcd2Kc=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lNzphckA0Q=", + "_parent": { + "$ref": "AAAAAAGL8lNzphcjVzA=" + }, + "reference": { + "$ref": "AAAAAAGL8fAHTJcd2Kc=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lNzphcloeU=", + "_parent": { + "$ref": "AAAAAAGL8lNzphcjVzA=" + }, + "reference": { + "$ref": "AAAAAAGLo/fkFXnWSO0=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL8lOuHlPLHnQ=", + "_parent": { + "$ref": "AAAAAAGL8fAHTJcd2Kc=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lOuHlPMMOQ=", + "_parent": { + "$ref": "AAAAAAGL8lOuHlPLHnQ=" + }, + "reference": { + "$ref": "AAAAAAGL8fAHTJcd2Kc=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lOuHlPNza4=", + "_parent": { + "$ref": "AAAAAAGL8lOuHlPLHnQ=" + }, + "reference": { + "$ref": "AAAAAAGL8e8PLkVkOWg=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGL+8oAEIaDan4=", + "_parent": { + "$ref": "AAAAAAGL8fAHTJcd2Kc=" + }, + "source": { + "$ref": "AAAAAAGL8fAHTJcd2Kc=" + }, + "target": { + "$ref": "AAAAAAGL+8nHIFKZGGE=" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL+8tZ967YT0Q=", + "_parent": { + "$ref": "AAAAAAGL8fAHTJcd2Kc=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL+8tZ967ZQD0=", + "_parent": { + "$ref": "AAAAAAGL+8tZ967YT0Q=" + }, + "reference": { + "$ref": "AAAAAAGL8fAHTJcd2Kc=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL+8tZ967azMY=", + "_parent": { + "$ref": "AAAAAAGL+8tZ967YT0Q=" + }, + "reference": { + "$ref": "AAAAAAGL8e9J0FdHmso=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGL+9c7CRuveJk=", + "_parent": { + "$ref": "AAAAAAGL8fAHTJcd2Kc=" + }, + "source": { + "$ref": "AAAAAAGL8fAHTJcd2Kc=" + }, + "target": { + "$ref": "AAAAAAGLw7v65PPlleU=" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGL8kwWMOvqRNg=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "EntrainementRepository", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL8kz1eGm5YVc=", + "_parent": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + }, + "name": "*lesEntrainements", + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8kz1eGm6iIc=", + "_parent": { + "$ref": "AAAAAAGL8kz1eGm5YVc=" + }, + "reference": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8kz1eWm7nGc=", + "_parent": { + "$ref": "AAAAAAGL8kz1eGm5YVc=" + }, + "reference": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGL+9Se8MmZLdo=", + "_parent": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + }, + "source": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + }, + "target": { + "$ref": "AAAAAAGL+9O3E77+iB4=" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL++NtKh6cvUs=", + "_parent": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL++NtKh6dcW8=", + "_parent": { + "$ref": "AAAAAAGL++NtKh6cvUs=" + }, + "reference": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL++NtKh6eGOg=", + "_parent": { + "$ref": "AAAAAAGL++NtKh6cvUs=" + }, + "reference": { + "$ref": "AAAAAAGL8lJC3yKeddk=" + }, + "navigable": "navigable" + } + }, + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL++Z1IOrl2bA=", + "_parent": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + }, + "name": "entrainementList", + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL++Z1IOrmj24=", + "_parent": { + "$ref": "AAAAAAGL++Z1IOrl2bA=" + }, + "reference": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL++Z1IOrnew4=", + "_parent": { + "$ref": "AAAAAAGL++Z1IOrl2bA=" + }, + "reference": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + }, + "navigable": "navigable" + }, + "visibility": "private" + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGL8lJC3yKeddk=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Entrainement", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGL8lLYKYP6eHU=", + "_parent": { + "$ref": "AAAAAAGL8lJC3yKeddk=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lLYKYP7ejM=", + "_parent": { + "$ref": "AAAAAAGL8lLYKYP6eHU=" + }, + "reference": { + "$ref": "AAAAAAGL8lJC3yKeddk=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGL8lLYKYP8bHc=", + "_parent": { + "$ref": "AAAAAAGL8lLYKYP6eHU=" + }, + "reference": { + "$ref": "AAAAAAGL8kwWMOvqRNg=" + }, + "navigable": "navigable" + } + } + ], + "stereotype": "interfaces", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAGL++Q3gS35XNs=", + "_parent": { + "$ref": "AAAAAAGL8lJC3yKeddk=" + }, + "name": "Attribute1", + "type": "" + } + ] + }, + { + "_type": "UMLModel", + "_id": "AAAAAAGL8oOYXQr/AQc=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Models" + }, + { + "_type": "UMLPackage", + "_id": "AAAAAAGL8oPx1E8rJeI=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Package1" + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGL8qWWJj6joa0=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Responsabilité", + "attributes": [ + { + "_type": "UMLAttribute", + "_id": "AAAAAAGL8qXHfUcNtPA=", + "_parent": { + "$ref": "AAAAAAGL8qWWJj6joa0=" + }, + "name": "But principale de la classe", + "type": "" + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGL+8nHIFKZGGE=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "DataManager" + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGL+82j2lEaUGY=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "IGenericRepository", + "operations": [ + { + "_type": "UMLOperation", + "_id": "AAAAAAGL+84tpm4nUBQ=", + "_parent": { + "$ref": "AAAAAAGL+82j2lEaUGY=" + }, + "name": "getItemById", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+86GNHNuQcE=", + "_parent": { + "$ref": "AAAAAAGL+84tpm4nUBQ=" + }, + "name": "id", + "type": "int" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL+86cPHlwc+E=", + "_parent": { + "$ref": "AAAAAAGL+82j2lEaUGY=" + }, + "name": "getNbItems", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+88J8ZbWW34=", + "_parent": { + "$ref": "AAAAAAGL+86cPHlwc+E=" + }, + "type": "int", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL+86fO3zWI0s=", + "_parent": { + "$ref": "AAAAAAGL+82j2lEaUGY=" + }, + "name": "getItems", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9DcKZwZz84=", + "_parent": { + "$ref": "AAAAAAGL+86fO3zWI0s=" + }, + "name": "index", + "type": "int" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9DcLJwaaCk=", + "_parent": { + "$ref": "AAAAAAGL+86fO3zWI0s=" + }, + "name": "count", + "type": "int" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9DcLJwbnOI=", + "_parent": { + "$ref": "AAAAAAGL+86fO3zWI0s=" + }, + "name": "orderingPropertyName", + "type": "?String" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9DcLZwcFiA=", + "_parent": { + "$ref": "AAAAAAGL+86fO3zWI0s=" + }, + "name": "descending", + "type": "bool" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9DcLZwdTV8=", + "_parent": { + "$ref": "AAAAAAGL+86fO3zWI0s=" + }, + "type": "array", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL+86ncIA8/pY=", + "_parent": { + "$ref": "AAAAAAGL+82j2lEaUGY=" + }, + "name": "getItemsByName", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9H4NaLkbQE=", + "_parent": { + "$ref": "AAAAAAGL+86ncIA8/pY=" + }, + "name": "substring", + "type": "String" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9H4N6Llqjg=", + "_parent": { + "$ref": "AAAAAAGL+86ncIA8/pY=" + }, + "name": "index", + "type": "int" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9H4N6LmObw=", + "_parent": { + "$ref": "AAAAAAGL+86ncIA8/pY=" + }, + "name": "count", + "type": "int" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9H4N6LnQEw=", + "_parent": { + "$ref": "AAAAAAGL+86ncIA8/pY=" + }, + "name": "orderingPropertyName", + "type": "?String" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9H4OKLo8r8=", + "_parent": { + "$ref": "AAAAAAGL+86ncIA8/pY=" + }, + "name": "descending", + "type": "bool" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9H4OKLph44=", + "_parent": { + "$ref": "AAAAAAGL+86ncIA8/pY=" + }, + "type": "?array", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL+86p3oOiaNc=", + "_parent": { + "$ref": "AAAAAAGL+82j2lEaUGY=" + }, + "name": "getItemsByName", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9JcOrExLOI=", + "_parent": { + "$ref": "AAAAAAGL+86p3oOiaNc=" + }, + "name": "substring", + "type": "String" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9JcPLEybNk=", + "_parent": { + "$ref": "AAAAAAGL+86p3oOiaNc=" + }, + "name": "index", + "type": "int" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9JcPbEz+zo=", + "_parent": { + "$ref": "AAAAAAGL+86p3oOiaNc=" + }, + "name": "count", + "type": "int" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9JcPbE0XQI=", + "_parent": { + "$ref": "AAAAAAGL+86p3oOiaNc=" + }, + "name": "orderingPropertyName", + "type": "?String" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9JcPbE1q0s=", + "_parent": { + "$ref": "AAAAAAGL+86p3oOiaNc=" + }, + "name": "descending", + "type": "bool" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL+86sTYcItmQ=", + "_parent": { + "$ref": "AAAAAAGL+82j2lEaUGY=" + }, + "name": "updateItem", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9LXLLf8t0A=", + "_parent": { + "$ref": "AAAAAAGL+86sTYcItmQ=" + }, + "name": "oldItem", + "type": "" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9LXLrf9C5A=", + "_parent": { + "$ref": "AAAAAAGL+86sTYcItmQ=" + }, + "name": "newItem", + "type": "" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9LXLrf+Tzg=", + "_parent": { + "$ref": "AAAAAAGL+86sTYcItmQ=" + }, + "type": "void", + "direction": "return" + } + ] + }, + { + "_type": "UMLOperation", + "_id": "AAAAAAGL+86ui4puvnk=", + "_parent": { + "$ref": "AAAAAAGL+82j2lEaUGY=" + }, + "name": "deleteItem", + "parameters": [ + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9MCVL4Dc40=", + "_parent": { + "$ref": "AAAAAAGL+86ui4puvnk=" + }, + "name": "item", + "type": "" + }, + { + "_type": "UMLParameter", + "_id": "AAAAAAGL+9MCVb4E2Hk=", + "_parent": { + "$ref": "AAAAAAGL+86ui4puvnk=" + }, + "type": "bool", + "direction": "return" + } + ] + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGL+9O3E77+iB4=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "ITrainingRepository", + "ownedElements": [ + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGL+9RSGRB8+vM=", + "_parent": { + "$ref": "AAAAAAGL+9O3E77+iB4=" + }, + "source": { + "$ref": "AAAAAAGL+9O3E77+iB4=" + }, + "target": { + "$ref": "AAAAAAGL+82j2lEaUGY=" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGL+9PlDtA7iBo=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Class1" + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGL+9PoMtQG54g=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "IUserRepository", + "ownedElements": [ + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGL+9RdJBsWH7s=", + "_parent": { + "$ref": "AAAAAAGL+9PoMtQG54g=" + }, + "source": { + "$ref": "AAAAAAGL+9PoMtQG54g=" + }, + "target": { + "$ref": "AAAAAAGL+82j2lEaUGY=" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGL+9Qa4uFEN74=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Class2" + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGL++aCGgpsPN4=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "EntrainementSportif", + "ownedElements": [ + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGL++arORiCGus=", + "_parent": { + "$ref": "AAAAAAGL++aCGgpsPN4=" + }, + "source": { + "$ref": "AAAAAAGL++aCGgpsPN4=" + }, + "target": { + "$ref": "AAAAAAGLrxb6dUqeBKo=" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGMBpdAZQuSkhA=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "IFileReader" + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGMBpd9ig65uB8=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "AthlketeMgr", + "ownedElements": [ + { + "_type": "UMLAssociation", + "_id": "AAAAAAGMBperGiDRgno=", + "_parent": { + "$ref": "AAAAAAGMBpd9ig65uB8=" + }, + "end1": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGMBperGiDSkv4=", + "_parent": { + "$ref": "AAAAAAGMBperGiDRgno=" + }, + "reference": { + "$ref": "AAAAAAGMBpd9ig65uB8=" + } + }, + "end2": { + "_type": "UMLAssociationEnd", + "_id": "AAAAAAGMBperGiDT2kA=", + "_parent": { + "$ref": "AAAAAAGMBperGiDRgno=" + }, + "reference": { + "$ref": "AAAAAAGMBpdAZQuSkhA=" + }, + "navigable": "navigable" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGMBpe7/CSbj9A=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Fit", + "ownedElements": [ + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGMBpfYWi3Xomc=", + "_parent": { + "$ref": "AAAAAAGMBpe7/CSbj9A=" + }, + "source": { + "$ref": "AAAAAAGMBpe7/CSbj9A=" + }, + "target": { + "$ref": "AAAAAAGMBpdAZQuSkhA=" + } + } + ] + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGMBpo0VdxaKM0=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "IAnalyseur" + }, + { + "_type": "UMLClass", + "_id": "AAAAAAGMBqILMC7uP0g=", + "_parent": { + "$ref": "AAAAAAFF+qBWK6M3Z8Y=" + }, + "name": "Analyseur", + "ownedElements": [ + { + "_type": "UMLGeneralization", + "_id": "AAAAAAGMBsEyOCaJKLw=", + "_parent": { + "$ref": "AAAAAAGMBqILMC7uP0g=" + }, + "source": { + "$ref": "AAAAAAGMBqILMC7uP0g=" + }, + "target": { + "$ref": "AAAAAAGMBpo0VdxaKM0=" + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/docs/Diagramme/DiagrammeDeClasses/README_DIAGRAMME.md b/docs/Diagramme/DiagrammeDeClasses/README_DIAGRAMME.md new file mode 100644 index 0000000..3002217 --- /dev/null +++ b/docs/Diagramme/DiagrammeDeClasses/README_DIAGRAMME.md @@ -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 +``` \ No newline at end of file diff --git a/docs/Diagramme/DiagrammeDeClasses/README_accesDonnees.md b/docs/Diagramme/DiagrammeDeClasses/README_accesDonnees.md new file mode 100644 index 0000000..19c5794 --- /dev/null +++ b/docs/Diagramme/DiagrammeDeClasses/README_accesDonnees.md @@ -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 +``` \ No newline at end of file diff --git a/docs/Diagramme/DiagrammeDeClasses/README_issue016.md b/docs/Diagramme/DiagrammeDeClasses/README_issue016.md new file mode 100644 index 0000000..9d0dac9 --- /dev/null +++ b/docs/Diagramme/DiagrammeDeClasses/README_issue016.md @@ -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 +```` diff --git a/docs/Diagramme/DiagrammeDeClasses/README_issue022.md b/docs/Diagramme/DiagrammeDeClasses/README_issue022.md new file mode 100644 index 0000000..37c0ac4 --- /dev/null +++ b/docs/Diagramme/DiagrammeDeClasses/README_issue022.md @@ -0,0 +1,91 @@ +[retour au README.md](../../../README.md) +[Retour au diagramme de classes](../README_DIAGRAMMES.md) + +# Diagramme de Classes : Gestion des Utilisateurs et Notifications + +Bienvenue dans le cœur de notre système, où la gestion des utilisateurs et des notifications prend vie à travers ce diagramme de classes. Explorez les relations et les fonctionnalités essentielles qui orchestrent l'interaction entre les utilisateurs, les demandes d'amis, et les notifications. + +**Entités Principales :** + +- **Utilisateur (User) :** Représente les individus inscrits sur notre plateforme, caractérisés par leur nom et établissant des liens d'amitié avec d'autres utilisateurs. + +- **Notification (Notification) :** Contient le texte informatif des notifications qui peuvent être émises par le système. + +- **Demande d'Ami (Ask) :** Modélise une demande d'amitié émise par un utilisateur en direction d'un autre. + +**Interfaces et Classes Abstraites :** + +- **INotifier :** Interface définissant la méthode `notify()`, implémentée par des classes concrètes pour gérer la notification aux observateurs. + +- **Observer :** Interface définissant la méthode `update()`, implémentée par les classes qui souhaitent être informées des changements dans un sujet observé. + +- **UserManager :** Classe abstraite gérant la logique métier liée aux utilisateurs, tels que l'ajout ou la suppression d'amis, la réponse aux demandes d'amis, et la récupération de la liste d'amis. + +- **IUserRepository :** Interface définissant les méthodes pour la recherche d'utilisateurs et l'ajout d'un nouvel utilisateur. + +**Relations Clés :** + +- Les utilisateurs peuvent avoir plusieurs amis et plusieurs notifications. + +- La classe UserManager est connectée à IUserRepository pour gérer les opérations liées aux utilisateurs. + +- Observer et Subject sont des composants du modèle de conception "Observer", permettant la notification efficace des changements dans le système. + +Plongez-vous dans ce diagramme pour découvrir comment notre application crée un écosystème social dynamique, permettant aux utilisateurs d'interagir, de rester informés et de développer des liens significatifs au sein de la communauté. + + +```plantuml +class User { + + name : string +} + +User "1" --> "*" User: friends +User "1" --> "*" Notification: notifications +User "1" --> "*" Ask: friendRequests +class Notification { + - text : string +} + +interface INotifier { + + notify() : void +} + +INotifier --|> Observer + +abstract class UserManager { + - currentUser : User + + deleteFriend(userId : int) : void + + addFriend(userId : int) : void + + respondToFriendRequest(requestId : int, choice : bool) : void + + getFriends(userId : int) : User[] +} + +class Ask { + - fromUser : int + - toUser : int +} + +Ask --|> Subject + +abstract class Subject { + + attach(o : Observer) : void + + detach(o : Observer) : void + + notify() : void +} + +Subject "1" --> "*" Observer +interface Observer { + + update() : void +} + +UserManager ..> User +UserManager o-- IUserRepository +UserManager o-- INotifier + +interface IUserRepository { + + findByUsername(username : string) : User + + addUser(user : User) : bool +} + +IUserRepository ..> User +``` \ No newline at end of file diff --git a/docs/Diagramme/DiagrammeDeClasses/README_issue023.md b/docs/Diagramme/DiagrammeDeClasses/README_issue023.md new file mode 100644 index 0000000..3763288 --- /dev/null +++ b/docs/Diagramme/DiagrammeDeClasses/README_issue023.md @@ -0,0 +1,200 @@ +[retour au README.md](../../../README.md) +[Retour au diagramme de classes](../README_DIAGRAMMES.md) + +# Introduction au Modèle de Données de l'Application + +L'architecture de données de notre application de suivi d'activités sportives repose sur un modèle robuste, avec des entités clés pour représenter les activités, les athlètes et les coachs. Découvrez les composants principaux de notre modèle de données : + +## Activité +L'entité Activité représente une session d'activité sportive avec des détails variés tels que le type d'activité, la date, la durée, l'effort ressenti, etc. Le `ActiviteEntity` encapsule ces données, tandis que le `ActiviteGateway` gère la communication avec la base de données pour les activités. + +## Athlète +L'entité Athlète représente un utilisateur de l'application qui participe à des activités sportives. Le `AthleteEntity` stocke les détails de l'athlète, et le `AtheletGateway` facilite l'accès et la gestion des données des athlètes. + +## Coach +L'entité Coach représente un utilisateur qui peut superviser et coacher d'autres athlètes. Le `CoachEntity` stocke les détails du coach, tandis que le `CoachGateway` gère les interactions avec la base de données. + +## Mapper +Les mappers, tels que `ActiviteMapper`, `AthleteMapper`, et `CoachMapper`, facilitent la conversion entre les entités et les modèles utilisés dans l'application. + +## Connexion à la Base de Données +La classe `Connection` étend de `PDO` et assure la connexion à la base de données. Chaque Gateway utilise cette connexion pour interagir avec la base de données. + + +```plantuml +@startuml +class ActiviteEntity { + - idActivite: int + - type: string + - date: string + - heureDebut: string + - heureFin: string + - effortRessenti: int + - variabilite: int + - variance: int + - ecartType: int + - moyenne: int + - maximum: int + - minimum: int + - temperatureMoyenne: int + + getIdActivite(): int + + getType(): string + + getDate(): string + + getHeureDebut(): string + + getHeureFin(): string + + getEffortRessenti(): int + + getVariabilite(): int + + getVariance(): int + + getEcartType(): int + + getMoyenne(): int + + getMaximum(): int + + getMinimum(): int + + getTemperatureMoyenne(): int + + setIdActivite(idActivite: int): void + + setType(type: string): void + + setDate(date: string): void + + setHeureDebut(heureDebut: string): void + + setHeureFin(heureFin: string): void + + setEffortRessenti(effortRessenti: int): void + + setVariabilite(variabilite: int): void + + setVariance(variance: int): void + + setEcartType(ecartType: int): void + + setMoyenne(moyenne: int): void + + setMaximum(maximum: int): void + + setMinimum(minimum: int): void + + setTemperatureMoyenne(temperatureMoyenne: int): void +} +class ActiviteGateway { + + __construct(connection: Connection) + + getActivite(): ?array + + getActiviteById(activiteId: int): ?array + + getActiviteByType(type: string): ?array + + getActiviteByDate(date: string): ?array + + getActiviteByTimeRange(startTime: string, endTime: string): ?array + + getActiviteByEffort(effortRessenti: int): ?array + + getActiviteByVariability(variabilite: int): ?array + + getActiviteByTemperature(temperatureMoyenne: int): ?array + + addActivite(activite: ActiviteEntity): bool + + updateActivite(oldActivite: ActiviteEntity, newActivite: ActiviteEntity): bool + + deleteActivite(idActivite: int): bool +} +class ActiviteMapper { + + map(data: array): ActiviteEntity + + ActiviteEntityToModel(activiteEntity: ActiviteEntity): Activite +} +class AthleteEntity { + - idAthlete: int + - nom: string + - prenom: string + - email: string + - sexe: string + - taille: float + - poids: float + - motDePasse: string + - dateNaissance: string + + getIdAthlete(): int + + getNom(): string + + getPrenom(): string + + getEmail(): string + + getSexe(): string + + getTaille(): float + + getPoids(): float + + getMotDePasse(): string + + getDateNaissance(): string + + setIdAthlete(idAthlete: int): void + + setNom(nom: string): void + + setPrenom(prenom: string): void + + setEmail(email: string): void + + setSexe(sexe: string): void + + setTaille(taille: float): void + + setPoids(poids: float): void + + setMotDePasse(motDePasse: string): void + + setDateNaissance(dateNaissance: string): void +} +class AtheletGateway { + + __construct(connection: Connection) + + getAthlete(): ?array + + getAthleteById(userId: int): ?array + + getAthleteByName(name: string): ?array + + getAthleteByFirstName(firstName: string): ?array + + getAthleteByEmail(email: string): ?array + + getAthleteByGender(gender: string): ?array + + getAthleteByHeight(height: int): ?array + + getAthleteByWeight(weight: int): ?array + + getAthleteByBirthDate(birthdate: string): ?array + + addAthlete(athlete: AthleteEntity): bool + + updateAthlete(oldAthlete: AthleteEntity, newAthlete: AthleteEntity): bool + + deleteAthlete(idAthlete: int): bool +} +class AthleteMapper { + + fromSqlToEntity(data: array): array + + athleteEntityToModel(athleteEntity: AthleteEntity): User + + athleteToEntity(user: User): AthleteEntity +} +class CoachEntity { + - idCoach: int + - nom: string + - prenom: string + - email: string + - sexe: string + - taille: float + - poids: float + - motDePasse: string + - dateNaissance: string + + getIdCoach(): int + + getNom(): string + + getPrenom(): string + + getEmail(): string + + getSexe(): string + + getTaille(): float + + getPoids(): float + + getMotDePasse(): string + + getDateNaissance(): string + + setIdCoach(idCoach: int): void + + setNom(nom: string): void + + setPrenom(prenom: string): void + + setEmail(email: string): void + + setSexe(sexe: string): void + + setTaille(taille: float): void + + setPoids(poids: float): void + + setMotDePasse(motDePasse: string): void + + setDateNaissance(dateNaissance: string): void +} +class CoachGateway { + + __construct(connection: Connection) + + getCoach(): ?array + + getCoachById(userId: int): ?array + + getCoachByName(name: string): ?array + + getCoachByFirstName(firstName: string): ?array + + getCoachByEmail(email: string): ?array + + getCoachByGender(gender : string): ?array + + getCoachByHeight(height: int): ?array + + getCoachByBirthDate(birthdate: string): ?array + + addCoach(coach: CoachEntity): bool + + updateCoach(oldCoach: CoachEntity, newCoach: CoachEntity): bool + + deleteCoach(idCoach: int): bool +} +class CoachMapper { + + map(data: array): CoachEntity + + CoachEntityToModel(coachEntity: CoachEntity): User + + CoachToEntity(user: User): CoachEntity +} +class Connection extends PDO { + - stmt + + __construct(dsn: string, username: string, password: string) + + executeQuery(query: string, parameters: array): bool + + executeWithErrorHandling(query: string, params: array): array + + getResults(): array +} + +Connection <- ActiviteGateway : connection +Connection <- AtheletGateway : connection +Connection <- CoachGateway : connection +AthleteMapper -> AthleteEntity +CoachMapper -> CoachEntity +ActiviteMapper -> ActiviteEntity +ActiviteMapper -> ActiviteGateway +CoachMapper -> CoachGateway +AthleteMapper -> AtheletGateway +@enduml +``` \ No newline at end of file diff --git a/docs/Diagramme/DiagrammeDeClasses/README_issue028.md b/docs/Diagramme/DiagrammeDeClasses/README_issue028.md new file mode 100644 index 0000000..e1d0cf7 --- /dev/null +++ b/docs/Diagramme/DiagrammeDeClasses/README_issue028.md @@ -0,0 +1,136 @@ +[retour au README.md](../../../README.md) +[Retour au diagramme de classes](../README_DIAGRAMMES.md) + +# Diagramme de classes pour l'importation de fichiers .fit + +Bienvenue dans le monde de la gestion d'activités sportives avec notre application innovante ! Cette user story se concentre sur une fonctionnalité essentielle qui améliorera l'expérience des utilisateurs : l'importation de fichiers .fit. Nous avons conçu un diagramme de classes pour vous offrir une vision claire et structurée de la manière dont cette fonctionnalité est implémentée au sein de notre application. + +**Acteurs Principaux :** + +- Utilisateur (User) : Représente un individu inscrit sur notre plateforme, avec la capacité d'importer des fichiers .fit. +- Athlète (Athlete) : Un type spécialisé d'utilisateur, bénéficiant de fonctionnalités supplémentaires liées à la gestion d'activités sportives. + +**Entités Clés :** + +- Activité (Activity) : Représente une session d'activité physique, avec des détails tels que le type, la date, la durée, et plus encore. +- Gestionnaires (Managers) : Gérant différentes facettes de l'application, notamment les utilisateurs, les activités et les fichiers. + +**Fonctionnalité Clé :** + +- Importation de fichiers .fit : Permet aux utilisateurs de charger des données provenant de fichiers .fit, générés par des dispositifs de suivi d'activité. Ces fichiers contiennent des informations précieuses telles que la fréquence cardiaque, la distance parcourue et d'autres métriques essentielles. + +**Architecture :** + +- AuthService (Service d'Authentification) : Gère l'authentification des utilisateurs, garantissant un accès sécurisé à la fonction d'importation. +- UserManager (Gestionnaire d'Utilisateurs) : Gère les opérations liées aux utilisateurs, y compris l'importation de fichiers .fit. +ActivityManager (Gestionnaire d'Activités) : Responsable du stockage et de la gestion des activités importées. + +**Objectif :** + +Offrir aux utilisateurs, en particulier aux athlètes, la possibilité d'enrichir leur profil et de suivre leur performance en important des données détaillées à partir de fichiers .fit. + + +```plantuml +@startuml issue028_DiagrammeDeClasses +class Activite { + -idActivite:int + -type:String + -date:Date + -heureDebut:Date + -heureFin:Date + -effortRessenti:int + -variability:float + -variance:float + -standardDeviation:float + -average:float + -maximum:int + -minimum:int + -avrTemperature:float + -hasAutoPause:boolean + +getIdActivite():int + +getType():String + +getDate():Date + +getHeureDebut():Date + +getHeureFin():Date + +getEffortRessenti():int + +getVariability():float + +getVariance():float + +getStandardDeviation():float + +getAverage():float + +getMaximum():int + +getMinimum():int + +getAvrTemperature():float + +setType(type:String):void + +setEffortRessenti(effortRessenti:int):void + +__toString():String +} +class Role { + -id:int +} +class Athlete { + +getActivities():array + +addActivity(myActivity:Activity):boolean +} +class User { + -id:int + -username:String + -nom:String + -prenom:String + -email:String + -motDePasse:String + -sexe:String + -taille:float + -poids:float + -dateNaissance:Date + +getId():int + +setId(id:int):void + +getUsername():String + +setUsername(username:String):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():Date + +setDateNaissance(dateNaissance:Date):void + +getRole():Role + +setRole(role:Role):void + +isValidPassword(password:String):boolean + +__toString():String +} +class AthleteManager { + +getActivities():array +} +class ActivityManager { + +saveFitFileToJSON(monFichierFit:object):boolean + +uploadFile(type:string, effortRessenti:int, file_path_or_data:string|resource, options:array):boolean +} +class DataManager { +} +class UserManager { + +login(loginUser:string, passwordUser:string):boolean + +register(loginUser:string, passwordUser:string, data:array):boolean + +deconnecter():boolean +} + +User -> Role: role +Athlete -|> Role +DataManager -> UserManager: -userMgr +DataManager -> AthleteManager: -athleteMgr +DataManager -> ActivityManager: -activityMgr +UserManager -> AuthService: -authService +UserManager -> User: -currentUser +ActivityManager -> AuthService: -authService +Athlete -> Activite: listActivite +AthleteManager -> AuthService: -authService +@enduml +``` \ No newline at end of file diff --git a/docs/Diagramme/DiagrammeDeSequence/AjouterAmis.png b/docs/Diagramme/DiagrammeDeSequence/AjouterAmis.png new file mode 100644 index 0000000..1d66820 Binary files /dev/null and b/docs/Diagramme/DiagrammeDeSequence/AjouterAmis.png differ diff --git a/docs/Diagramme/DiagrammeDeSequence/README_accepterAmi.md b/docs/Diagramme/DiagrammeDeSequence/README_accepterAmi.md new file mode 100644 index 0000000..6ae4a47 --- /dev/null +++ b/docs/Diagramme/DiagrammeDeSequence/README_accepterAmi.md @@ -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 +`````` \ No newline at end of file diff --git a/docs/Diagramme/DiagrammeDeSequence/README_demandeAmi.md b/docs/Diagramme/DiagrammeDeSequence/README_demandeAmi.md new file mode 100644 index 0000000..a4e4bfa --- /dev/null +++ b/docs/Diagramme/DiagrammeDeSequence/README_demandeAmi.md @@ -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. + +Diagramme de Séquence : Recherche d'Amis \ No newline at end of file diff --git a/docs/Diagramme/DiagrammeDeSequence/README_issue021.md b/docs/Diagramme/DiagrammeDeSequence/README_issue021.md new file mode 100644 index 0000000..1cd6631 --- /dev/null +++ b/docs/Diagramme/DiagrammeDeSequence/README_issue021.md @@ -0,0 +1,40 @@ +[retour au README.md](../../../README.md) +[Retour au diagramme de classes](../README_DIAGRAMMES.md) + +# Introduction au Processus de Connexion sur la Plateforme + +Bienvenue sur notre plateforme de gestion d'activités sportives ! Pour offrir une expérience fluide et sécurisée, nous avons mis en place un processus de connexion intuitif. Découvrez comment accéder à votre compte ou créer un nouveau compte en quelques étapes simples. + +**Étapes du Processus :** + +1. **Demande de Page de Connexion :** L'utilisateur démarre en exprimant le désir de se connecter à la plateforme. + +2. **Vérification de la Connexion Préexistante :** Le système vérifie si l'utilisateur est déjà connecté. En cas de connexion active, l'utilisateur est redirigé directement vers sa page de compte. + +3. **Page de Connexion :** Si l'utilisateur n'est pas encore connecté, il est dirigé vers la page de connexion, où il peut saisir ses informations d'identification. + +4. **Choix pour les Utilisateurs Possédant un Compte :** Si l'utilisateur a déjà un compte, il peut fournir ses informations de connexion existantes. + +5. **Création de Compte pour les Nouveaux Utilisateurs :** Pour ceux qui n'ont pas encore de compte, l'option de création de compte est disponible. L'utilisateur peut fournir les détails nécessaires pour créer son compte. + +6. **Page de Création de Compte :** Une page dédiée guide l'utilisateur tout au long du processus de création de compte, lui permettant de saisir les informations nécessaires. + +7. **Validation et Connexion :** Une fois que les informations de connexion ou de création de compte sont fournies, le système procède à la vérification et connecte l'utilisateur à son compte. + + +```plantuml +actor User as u +u->Systeme : demandePageConnexion() +alt User déjà connecté + Systeme-->u : redirectionPageCompte() +end +Systeme-->u : PageConnexion() +alt User possède déjà un compte + u->Systeme:InfosConnexion() +else + u->Systeme:CreerCompte() + Systeme-->u :PageCreationCompte() + u->Systeme:InfosCreationCompte() +end +Systeme-->u :Connecter() +``` \ No newline at end of file diff --git a/docs/Diagramme/DiagrammeDeSequence/README_suppressionAmi.md b/docs/Diagramme/DiagrammeDeSequence/README_suppressionAmi.md new file mode 100644 index 0000000..afec35a --- /dev/null +++ b/docs/Diagramme/DiagrammeDeSequence/README_suppressionAmi.md @@ -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 +``` \ No newline at end of file diff --git a/docs/Diagramme/README_DIAGRAMMES.md b/docs/Diagramme/README_DIAGRAMMES.md new file mode 100644 index 0000000..cc22a4c --- /dev/null +++ b/docs/Diagramme/README_DIAGRAMMES.md @@ -0,0 +1,25 @@ +[retour au README.md](../../README.md) + +# Diagrammes nécéssaires à notre projet + +## Diagrammes de classes +- [issue016 - Statistiques coach ](DiagrammeDeClasses/README_issue016.md) +- [issue022 - Ajout des amis ](DiagrammeDeClasses/README_issue022.md) +- [issue023 - User Gateway ](DiagrammeDeClasses/README_issue023.md) +- [issue028 - Importation de fichiers .fit](DiagrammeDeClasses/README_issue028.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) +- [Cas d'utilisation pour la suivi d'une équipe sportive](CasUtilisations/README_coachSuiviSportif.md) + +## Base de données +- [MCD - MLD](BDD/README_BDD.md) \ No newline at end of file diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile new file mode 100644 index 0000000..12f9ffe --- /dev/null +++ b/docs/doxygen/Doxyfile @@ -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 \ No newline at end of file diff --git a/docs/images/logo.png b/docs/images/logo.png new file mode 100755 index 0000000..5294913 Binary files /dev/null and b/docs/images/logo.png differ diff --git a/src/APIMappers/APIMappers.csproj b/src/APIMappers/APIMappers.csproj new file mode 100644 index 0000000..3bb04a5 --- /dev/null +++ b/src/APIMappers/APIMappers.csproj @@ -0,0 +1,14 @@ + + + + net8.0 + enable + enable + + + + + + + + diff --git a/src/APIMappers/ActivityMapper.cs b/src/APIMappers/ActivityMapper.cs new file mode 100644 index 0000000..2442a40 --- /dev/null +++ b/src/APIMappers/ActivityMapper.cs @@ -0,0 +1,84 @@ +using Dto; +using Model; +using Shared; + +namespace APIMappers; + +public static class ActivityMapper +{ + private static GenericMapper _mapper = new(); + + public static Activity ToModel(this ActivityDto activityDto, User user) + { + Func 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 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 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 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 IEnumerable ToModels(this IEnumerable dtos, User user) + => dtos.Select(dto => dto.ToModel(user)); + + public static IEnumerable ToDtos(this IEnumerable models) + => models.Select(model => model.ToDto()); + + + + +} \ No newline at end of file diff --git a/src/APIMappers/DataSourceMapper.cs b/src/APIMappers/DataSourceMapper.cs new file mode 100644 index 0000000..221fccb --- /dev/null +++ b/src/APIMappers/DataSourceMapper.cs @@ -0,0 +1,52 @@ +using Dto; +using Model; +using Shared; + +namespace APIMappers; + +public static class DataSourceMapper +{ + + private static GenericMapper _mapper = new (); + + public static DataSource ToModel(this DataSourceDto dto, User user) + { + Func create = dataSourceDto => + new DataSource(dataSourceDto.Id, dataSourceDto.Type, dataSourceDto.Model, dataSourceDto.Precision, + new List { user }, user.Activities.Where(a => a.DataSource.Id == dataSourceDto.Id).ToList()); + /* + Action 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 create = dataSource => + new DataSourceDto + { + Id = dataSource.Id, + Type = dataSource.Type, + Model = dataSource.Model, + Precision = dataSource.Precision, + }; + Action link = (dataSource, dto) => + { + dto.Activities = dataSource.Activities.ToDtos().ToArray(); + dto.Athletes = dataSource.Athletes.ToDtos().ToArray(); + }; + return model.ToU(_mapper, create, link); + } + + public static IEnumerable ToModels(this IEnumerable dtos, User user) + => dtos.Select(d => d.ToModel(user)); + + public static IEnumerable ToDtos(this IEnumerable models) + => models.Select(m => m.ToDto()); + + +} \ No newline at end of file diff --git a/src/APIMappers/HeartRateMapper.cs b/src/APIMappers/HeartRateMapper.cs new file mode 100644 index 0000000..c5f81a6 --- /dev/null +++ b/src/APIMappers/HeartRateMapper.cs @@ -0,0 +1,47 @@ +using Dto; +using Model; +using Shared; + +namespace APIMappers; + +public static class HeartRateMapper +{ + private static GenericMapper _mapper = new(); + + public static HeartRate ToModel(this HeartRateDto dto,Activity activityDto) + { + Func 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 + { + // [TODO] [Dave] fix this should be activity but it boucle indefinitly + var activity = new DateTime(); + Func 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 ToModels(this IEnumerable dtos, Activity activityDto) + => dtos.Select(d => d.ToModel(activityDto)); + + public static IEnumerable ToDtos(this IEnumerable models) + => models.Select(m => m.ToDto()); + + +} \ No newline at end of file diff --git a/src/APIMappers/LargeImageMapper.cs b/src/APIMappers/LargeImageMapper.cs new file mode 100644 index 0000000..f198415 --- /dev/null +++ b/src/APIMappers/LargeImageMapper.cs @@ -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); +} \ No newline at end of file diff --git a/src/APIMappers/UserMappeur.cs b/src/APIMappers/UserMappeur.cs new file mode 100644 index 0000000..6dbd1fc --- /dev/null +++ b/src/APIMappers/UserMappeur.cs @@ -0,0 +1,57 @@ +using Dto; +using Model; +using Shared; + +namespace APIMappers; + +public static class UserMappeur +{ + private static GenericMapper _mapper = new GenericMapper(); + + public static UserDto ToDto(this User user) + { + return user.ToU(_mapper, userDto => new UserDto + { + Id = user.Id, + Username = user.Username, + ProfilePicture = user.ProfilePicture, + LastName = user.LastName, + FirstName = user.FirstName, + Email = user.Email, + Password = user.MotDePasse, + Sexe = user.Sexe, + Lenght = user.Lenght, + Weight = user.Weight, + DateOfBirth = user.DateOfBirth, + IsCoach = user.Role is Coach + }); + + } + + + public static User ToModel(this UserDto userDto) + { + return userDto.ToT(_mapper, user => new User + { + Username = userDto.Username, + ProfilePicture = userDto.ProfilePicture, + LastName = userDto.LastName, + FirstName = userDto.FirstName, + Email = userDto.Email, + MotDePasse = userDto.Password, + Sexe = userDto.Sexe, + Lenght = userDto.Lenght, + Weight = userDto.Weight, + DateOfBirth = userDto.DateOfBirth, + Role = userDto.IsCoach ? new Coach() : new Athlete() + + }); + } + + public static IEnumerable ToModels(this IEnumerable dtos) + => dtos.Select(dto => dto.ToModel()); + + public static IEnumerable ToDtos(this IEnumerable models) + => models.Select(model => model.ToDto()); + +} \ No newline at end of file diff --git a/src/DbContextLib/DbContextLib.csproj b/src/DbContextLib/DbContextLib.csproj index 928ae7a..cd47dbc 100644 --- a/src/DbContextLib/DbContextLib.csproj +++ b/src/DbContextLib/DbContextLib.csproj @@ -6,13 +6,15 @@ enable - - - + + + + + - - + + diff --git a/src/DbContextLib/HeartTrackContext.cs b/src/DbContextLib/HeartTrackContext.cs new file mode 100644 index 0000000..3e94ae9 --- /dev/null +++ b/src/DbContextLib/HeartTrackContext.cs @@ -0,0 +1,248 @@ +//----------------------------------------------------------------------- +// FILENAME: HeartTrackContextLibraryContext.cs +// PROJECT: DbContextLib +// SOLUTION: FitnessApp +// DATE CREATED: 22/02/2024 +// AUTHOR: Antoine PEREDERII +//----------------------------------------------------------------------- + +using Entities; +using Microsoft.EntityFrameworkCore; + +namespace DbContextLib +{ + /// + /// Represents the database context for the FitnessApp. + /// + public class HeartTrackContext : DbContext + { + /// + /// Gets or sets the set of athletes. + /// + public DbSet AthletesSet { get; set; } + + /// + /// Gets or sets the set of activities. + /// + public DbSet ActivitiesSet { get; set; } + + /// + /// Gets or sets the set of data sources. + /// + public DbSet DataSourcesSet { get; set; } + + /// + /// Gets or sets the set of heart rates. + /// + public DbSet HeartRatesSet { get; set; } + + /// + /// Gets or sets the set of notifications. + /// + public DbSet NotificationsSet { get; set; } + + /// + /// Gets or sets the set of statistics. + /// + public DbSet StatisticsSet { get; set; } + + /// + /// Gets or sets the set of trainings. + /// + public DbSet TrainingsSet { get; set; } + + /// + /// Gets or sets the set of large images. + /// + public DbSet LargeImages { get; set; } + + + /// + /// Initializes a new instance of the class. + /// + public HeartTrackContext() : base() + { } + + /// + /// Initializes a new instance of the class with the specified options. + /// + /// The options for the context. + public HeartTrackContext(DbContextOptions options) : base(options) + { } + + public HeartTrackContext(string dbPlatformPath) + : this(InitPlaformDb(dbPlatformPath)) + { + } + + private static DbContextOptions InitPlaformDb(string dbPlatformPath) + { + var options = new DbContextOptionsBuilder() + .UseMySql($"{dbPlatformPath}", new MySqlServerVersion(new Version(10, 11, 1))) + .Options; + return options; + } + + + + + /// + /// Configures the database options if they are not already configured. + /// + /// The options builder instance. + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (!optionsBuilder.IsConfigured) + { + Console.WriteLine("!IsConfigured..."); + optionsBuilder.UseSqlite($"Data Source=uca_HeartTrack.db"); + } + } + + /// + /// Configures the model for the library context. + /// + /// The model builder instance. + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity() + .HasKey(a => a.IdActivity); + //generation mode (at insertion) + modelBuilder.Entity() + .Property(a => a.IdActivity) + .ValueGeneratedOnAdd(); + + //primary key of HeartRateEntity + modelBuilder.Entity() + .HasKey(h => h.IdHeartRate); + //generation mode (at insertion) + modelBuilder.Entity() + .Property(h => h.IdHeartRate) + .ValueGeneratedOnAdd(); + + //primary key of DataSourceEntity + modelBuilder.Entity() + .HasKey(d => d.IdSource); + //generation mode (at insertion) + modelBuilder.Entity() + .Property(d => d.IdSource) + .ValueGeneratedOnAdd(); + + //primary key of AthleteEntity + modelBuilder.Entity() + .HasKey(at => at.IdAthlete); + //generation mode (at insertion) + modelBuilder.Entity() + .Property(at => at.IdAthlete) + .ValueGeneratedOnAdd(); + // add image column type + // modelBuilder.Entity() + // .Property(at => at.ProfilPicture) + // .HasColumnType("image"); + + + //primary key of StatisticEntity + modelBuilder.Entity() + .HasKey(s => s.IdStatistic); + //generation mode (at insertion) + modelBuilder.Entity() + .Property(s => s.IdStatistic) + .ValueGeneratedOnAdd(); + + //primary key of TrainingEntity + modelBuilder.Entity() + .HasKey(t => t.IdTraining); + //generation mode (at insertion) + modelBuilder.Entity() + .Property(t => t.IdTraining) + .ValueGeneratedOnAdd(); + + //primary key of NotificationEntity + modelBuilder.Entity() + .HasKey(n => n.IdNotif); + //generation mode (at insertion) + modelBuilder.Entity() + .Property(n => n.IdNotif) + .ValueGeneratedOnAdd(); + + modelBuilder.Entity() + .HasKey(f => new { f.FollowingId, f.FollowerId }); + + modelBuilder.Entity() + .HasOne(fing => fing.Following) + .WithMany(fings => fings.Followings) + .HasForeignKey(fing => fing.FollowingId); + + modelBuilder.Entity() + .HasOne(fer => fer.Follower) + .WithMany(fers => fers.Followers) + .HasForeignKey(fing => fing.FollowerId); + + // ! + // ? Plusieurs questions sur les required ou non, différence difficile à comprendre + + modelBuilder.Entity() + .HasMany(at => at.TrainingsCoach) + .WithOne(tc => tc.Coach) + .HasForeignKey(tc => tc.CoachId); + + modelBuilder.Entity() + .HasMany(at => at.TrainingsAthlete) + .WithMany(ta => ta.Athletes); + + modelBuilder.Entity() + .HasMany(at => at.NotificationsReceived) + .WithMany(nr => nr.Receivers); + + modelBuilder.Entity() + .HasMany(at => at.NotificationsSent) + .WithOne(ns => ns.Sender) + .HasForeignKey(ns => ns.SenderId); + // required car on veut toujours savoir le receveur et l'envoyeur de la notification meme admin ou systeme + + modelBuilder.Entity() + .HasMany(at => at.Statistics) + .WithOne(s => s.Athlete) + .HasForeignKey(s => s.AthleteId) + .IsRequired(false) + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(at => at.Activities) + .WithOne(a => a.Athlete) + .HasForeignKey(a => a.AthleteId) + .IsRequired(false) + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(a => a.HeartRates) + .WithOne(h => h.Activity) + .HasForeignKey(h => h.ActivityId) + .IsRequired() + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(d => d.Activities) + .WithOne(a => a.DataSource) + .HasForeignKey(a => a.DataSourceId) + .IsRequired(false); + + modelBuilder.Entity() + .HasMany(ds => ds.Athletes) + .WithOne(at => at.DataSource) + .HasForeignKey(at => at.DataSourceId) + .IsRequired(); + + // modelBuilder.Entity() + // .HasMany(fer => fer.Followers) + // .WithMany(fing => fing.Followings) + // .UsingEntity( + // l => l.HasOne().WithMany().HasForeignKey(fer => fer.FollowerId), + // r => r.HasOne().WithMany().HasForeignKey(fing => fing.FollowingId), + // j => j.Property(f => f.StartDate).HasDefaultValueSql("CURRENT_TIMESTAMP") + // ); + } + } +} \ No newline at end of file diff --git a/src/DbContextLib/Identity/AuthDbContext.cs b/src/DbContextLib/Identity/AuthDbContext.cs new file mode 100644 index 0000000..89924a7 --- /dev/null +++ b/src/DbContextLib/Identity/AuthDbContext.cs @@ -0,0 +1,25 @@ +using Entities; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; + +namespace DbContextLib.Identity; + +public class AuthDbContext: IdentityDbContext +{ + + public AuthDbContext(DbContextOptions options) : base(options) { } + public AuthDbContext() { } + /* + /// + /// Configures the database options if they are not already configured. + /// + /// The options builder instance. + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (!optionsBuilder.IsConfigured) + { + optionsBuilder.UseSqlite($"Data Source=uca.HeartTrack.db"); + } + }*/ +} \ No newline at end of file diff --git a/src/DbContextLib/LibraryContext.cs b/src/DbContextLib/LibraryContext.cs deleted file mode 100644 index 008bbc9..0000000 --- a/src/DbContextLib/LibraryContext.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Entities; -using Microsoft.EntityFrameworkCore; - -namespace DbContextLib; - -public class LibraryContext : DbContext -{ - public DbSet AthletesSet { get; set; } - - public LibraryContext() - :base() - { } - - public LibraryContext(DbContextOptions options) - :base(options) - { } - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - if(!optionsBuilder.IsConfigured) - { - optionsBuilder.UseSqlite($"Data Source=uca.HeartTrack.db"); - } - } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - } -} diff --git a/src/Dto/ActivityDto.cs b/src/Dto/ActivityDto.cs new file mode 100644 index 0000000..6411837 --- /dev/null +++ b/src/Dto/ActivityDto.cs @@ -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 HeartRates { get; set; } +} \ No newline at end of file diff --git a/src/Dto/AthleteDto.cs b/src/Dto/AthleteDto.cs new file mode 100644 index 0000000..d5c94c0 --- /dev/null +++ b/src/Dto/AthleteDto.cs @@ -0,0 +1,23 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dto; + +public class UserDto +{ + 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 string 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 LargeImageDto? Image { get; set; } + public bool IsCoach { get; set; } +} diff --git a/src/Dto/DataSourceDto.cs b/src/Dto/DataSourceDto.cs new file mode 100644 index 0000000..74705a1 --- /dev/null +++ b/src/Dto/DataSourceDto.cs @@ -0,0 +1,22 @@ +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; } + + // [TODO] [Dave] Add a property to store the athletes and the activities so maybe adapt to have a tiny DTO + [JsonIgnore] + public IEnumerable? Athletes { get; set; } + + // [TODO] [Dave] Add a property to store the athletes and the activities so maybe adapt to have a tiny DTO + [JsonIgnore] + public IEnumerable? Activities { get; set; } +} \ No newline at end of file diff --git a/src/Dto/Dto.csproj b/src/Dto/Dto.csproj new file mode 100644 index 0000000..3123d8b --- /dev/null +++ b/src/Dto/Dto.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/src/Dto/HeartRateDto.cs b/src/Dto/HeartRateDto.cs new file mode 100644 index 0000000..a0d3a40 --- /dev/null +++ b/src/Dto/HeartRateDto.cs @@ -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; } +} \ No newline at end of file diff --git a/src/Dto/LargeImageDto.cs b/src/Dto/LargeImageDto.cs new file mode 100644 index 0000000..a7e6783 --- /dev/null +++ b/src/Dto/LargeImageDto.cs @@ -0,0 +1,6 @@ +namespace Dto; + +public class LargeImageDto +{ + public string Base64 { get; set; } +} \ No newline at end of file diff --git a/src/Dto/NotificationDto.cs b/src/Dto/NotificationDto.cs new file mode 100644 index 0000000..25a4442 --- /dev/null +++ b/src/Dto/NotificationDto.cs @@ -0,0 +1 @@ +namespace Dto; \ No newline at end of file diff --git a/src/Dto/StatisticDto.cs b/src/Dto/StatisticDto.cs new file mode 100644 index 0000000..25a4442 --- /dev/null +++ b/src/Dto/StatisticDto.cs @@ -0,0 +1 @@ +namespace Dto; \ No newline at end of file diff --git a/src/Dto/TrainingDto.cs b/src/Dto/TrainingDto.cs new file mode 100644 index 0000000..25a4442 --- /dev/null +++ b/src/Dto/TrainingDto.cs @@ -0,0 +1 @@ +namespace Dto; \ No newline at end of file diff --git a/src/EFMappers/ActivityMapper.cs b/src/EFMappers/ActivityMapper.cs new file mode 100644 index 0000000..1c58a3d --- /dev/null +++ b/src/EFMappers/ActivityMapper.cs @@ -0,0 +1,78 @@ +using Entities; +using Model; +using Shared; + +namespace EFMappers; + +public static class ActivityMapper +{ + private static GenericMapper _mapper = new (); + public static void Reset() + { + _mapper.Reset(); + } + + public static Activity ToModel(this ActivityEntity entity) + { + Func 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 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 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 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 ToModels(this IEnumerable entities) + => entities.Select(a => a.ToModel()); + + public static IEnumerable ToEntities(this IEnumerable models) + => models.Select(a => a.ToEntity()); +} \ No newline at end of file diff --git a/src/EFMappers/AthleteMappeur.cs b/src/EFMappers/AthleteMappeur.cs new file mode 100644 index 0000000..ef779f1 --- /dev/null +++ b/src/EFMappers/AthleteMappeur.cs @@ -0,0 +1,86 @@ +using System.Buffers; +using Dto; +using Entities; +using Model; +using Shared; + +namespace EFMappers; +public static class UserMappeur +{ + private static GenericMapper _mapper = new (); + + public static User ToModel(this AthleteEntity entity) + { + Func create = athleteEntity => new User + { + Id = athleteEntity.IdAthlete, + FirstName = athleteEntity.FirstName, + LastName = athleteEntity.LastName, + Email = athleteEntity.Email, + MotDePasse = athleteEntity.Password, + DateOfBirth = athleteEntity.DateOfBirth.ToDateTime(TimeOnly.MinValue), + Sexe = athleteEntity.Sexe, + Username = athleteEntity.Username, + Weight = athleteEntity.Weight, + Lenght = (float)athleteEntity.Length, + ProfilePicture = athleteEntity.ProfilPicture, + // Role = athleteEntity.IsCoach ? new Coach() : new Athlete(), + }; + + Action link = (athleteEntity, model) => + { + model.Role = athleteEntity.IsCoach ? new Coach() : new Athlete(); + if (athleteEntity.DataSource != null) model.DataSources.Add(athleteEntity.DataSource.ToModel()); + if (athleteEntity.Activities != null) model.Activities.AddRange(athleteEntity.Activities.ToModels()); + //model.Image = athleteEntity.Image.ToModel(); + }; + + return entity.ToT(_mapper, create, link); + } + + public static AthleteEntity ToEntity(this User model) + { + Func create = user => new AthleteEntity + { + IdAthlete = user.Id, + Username = user.Username, + Sexe = user.Sexe, + FirstName = user.FirstName, + LastName = user.LastName, + Email = user.Email, + Password = user.MotDePasse, + DateOfBirth = DateOnly.FromDateTime(user.DateOfBirth), + IsCoach = user.Role is Coach, + Weight = user.Weight, + Length = user.Lenght, + ProfilPicture = user.ProfilePicture, + }; + + Action link = (user, entity) => + { + entity.DataSource = user.DataSources.ToEntities().First(); + entity.Activities = user.Activities.ToEntities().ToList(); + entity.IsCoach = user.Role is Coach; + entity.Image = user.Image.ToEntity(); + /*if (user.Role is Coach) + entity.TrainingsCoach = user.Traning.ToEntities().ToList(); + else + entity.TrainingsAthlete = user.Traning.ToEntities().ToList(); + */ + // entity.NotificationsReceived = user.Notifications.ToEntities().ToList(); + + // entity.DataSource = user.DataSources.ToEntities().ToList(); + + // [TODO] [DAVE] : Add the link to the friendship + + }; + + return model.ToU(_mapper, create, link); + } + + public static IEnumerable ToModels(this IEnumerable entities) + => entities.Select(e => e.ToModel()); + + public static IEnumerable ToEntities(this IEnumerable models) + => models.Select(m => m.ToEntity()); +} \ No newline at end of file diff --git a/src/EFMappers/DataSourceMapper.cs b/src/EFMappers/DataSourceMapper.cs new file mode 100644 index 0000000..2295d1a --- /dev/null +++ b/src/EFMappers/DataSourceMapper.cs @@ -0,0 +1,51 @@ +using Entities; +using Model; +using Shared; + +namespace EFMappers; + +public static class DataSourceMapper +{ + + private static GenericMapper _mapper = new (); + + public static DataSource ToModel(this DataSourceEntity entity) + { + Func create = dataSourceEntity => + new DataSource( dataSourceEntity.IdSource, dataSourceEntity.Type, dataSourceEntity.Model, dataSourceEntity.Precision, dataSourceEntity.Athletes.ToModels().ToList(), dataSourceEntity.Activities.ToModels().ToList()); + /* + Action 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 create = dataSource => + new DataSourceEntity + { + IdSource = dataSource.Id, + Type = dataSource.Type, + Model = dataSource.Model, + Precision = dataSource.Precision + }; + + Action link = (dataSource, entity) => + { + entity.Activities = dataSource.Activities.ToEntities().ToList(); + entity.Athletes = dataSource.Athletes.ToEntities().ToList(); + }; + + return model.ToU(_mapper, create, link); + } + + public static IEnumerable ToModels(this IEnumerable entities) + => entities.Select(e => e.ToModel()); + + public static IEnumerable ToEntities(this IEnumerable models) + => models.Select(m => m.ToEntity()); +} \ No newline at end of file diff --git a/src/EFMappers/EFMappers.csproj b/src/EFMappers/EFMappers.csproj new file mode 100644 index 0000000..916706d --- /dev/null +++ b/src/EFMappers/EFMappers.csproj @@ -0,0 +1,14 @@ + + + + net8.0 + enable + enable + + + + + + + + diff --git a/src/EFMappers/HeartRateMapper.cs b/src/EFMappers/HeartRateMapper.cs new file mode 100644 index 0000000..0f30d36 --- /dev/null +++ b/src/EFMappers/HeartRateMapper.cs @@ -0,0 +1,56 @@ +using Entities; +using Model; +using Shared; + +namespace EFMappers; + +public static class HeartRateMapper +{ + private static GenericMapper _mapper = new (); + + public static HeartRate ToModel(this HeartRateEntity entity) + { + Func 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 link = (heartRateEntity, model) => + { + model.Activity = heartRateEntity.Activity.ToModel(); + }; + + return entity.ToT(_mapper, create, link); + } + + public static HeartRateEntity ToEntity(this HeartRate model) + { + Func 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 link = (heartRate, entity) => + { + entity.Activity = heartRate.Activity.ToEntity(); + }; + + return model.ToU(_mapper, create, link); + } + + public static IEnumerable ToModels(this IEnumerable entities) + => entities.Select(h => h.ToModel()); + + public static IEnumerable ToEntities(this IEnumerable models) + => models.Select(h => h.ToEntity()); + +} \ No newline at end of file diff --git a/src/EFMappers/LargeImageMapper.cs b/src/EFMappers/LargeImageMapper.cs new file mode 100644 index 0000000..644351b --- /dev/null +++ b/src/EFMappers/LargeImageMapper.cs @@ -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 }; + +} \ No newline at end of file diff --git a/src/Entities/ActivityEntity.cs b/src/Entities/ActivityEntity.cs index 62b0870..d1af116 100644 --- a/src/Entities/ActivityEntity.cs +++ b/src/Entities/ActivityEntity.cs @@ -1,26 +1,110 @@ +//----------------------------------------------------------------------- +// FILENAME: ActivityEntity.cs +// PROJECT: Entities +// SOLUTION: HeartTrack +// DATE CREATED: 22/02/2024 +// AUTHOR: HeartTeam +//----------------------------------------------------------------------- + using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -namespace Entities; +namespace Entities +{ + /// + /// Represents an activity entity in the database. + /// + [Table("Activity")] + public class ActivityEntity + { + /// + /// Gets or sets the unique identifier of the activity. + /// + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int IdActivity { get; set; } + /// + /// Gets or sets the type of the activity. + /// + [Required] + [MaxLength(100)] + public string? Type { get; set; } = null!; -[Table("Activity")] -public class ActivityEntity -{ - [Key] - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int IdActivity { get; set; } - public required 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; } + /// + /// Gets or sets the date of the activity. + /// + [Required(ErrorMessage = "Activity Date is required")] + [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)] + public DateOnly Date { get; set; } + + /// + /// Gets or sets the start time of the activity. + /// + [Required(ErrorMessage = "Start Activity Hour is required")] + [DisplayFormat(DataFormatString = "{0:HH:mm;ss}", ApplyFormatInEditMode = true)] + public TimeOnly StartTime { get; set; } + + /// + /// Gets or sets the end time of the activity. + /// + [Required(ErrorMessage = "End Activity Hour is required")] + [DisplayFormat(DataFormatString = "{0:HH:mm;ss}", ApplyFormatInEditMode = true)] + public TimeOnly EndTime { get; set; } + + /// + /// Gets or sets the perceived effort of the activity. + /// + public int EffortFelt { get; set; } + + /// + /// Gets or sets the variability of the activity. + /// + public float Variability { get; set; } + + /// + /// Gets or sets the variance of the activity. + /// + public float Variance { get; set; } + + /// + /// Gets or sets the standard deviation of the activity. + /// + public float StandardDeviation { get; set; } + + /// + /// Gets or sets the average of the activity. + /// + public float Average { get; set; } + + /// + /// Gets or sets the maximum value of the activity. + /// + public int Maximum { get; set; } + + /// + /// Gets or sets the minimum value of the activity. + /// + public int Minimum { get; set; } + + /// + /// Gets or sets the average temperature during the activity. + /// + public float AverageTemperature { get; set; } + + /// + /// Gets or sets whether the activity has an automatic pause feature. + /// + public bool HasAutoPause { get; set; } + + public ICollection? HeartRates { get; set; } = new List(); + + public int? DataSourceId { get; set; } + + public DataSourceEntity? DataSource { get; set; } = null!; + + public int AthleteId { get; set; } + + public AthleteEntity Athlete { get; set; } = null!; + } } \ No newline at end of file diff --git a/src/Entities/AthleteEntity.cs b/src/Entities/AthleteEntity.cs index a9fff57..199d635 100644 --- a/src/Entities/AthleteEntity.cs +++ b/src/Entities/AthleteEntity.cs @@ -1,27 +1,114 @@ +//----------------------------------------------------------------------- +// FILENAME: AthleteEntity.cs +// PROJECT: Entities +// SOLUTION: HeartTrack +// DATE CREATED: 22/02/2024 +// AUTHOR: HeartTeam +//----------------------------------------------------------------------- + using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -namespace Entities; - -[Table("Athlete")] -public class AthleteEntity +namespace Entities { - // ! donner plus de contraintes !! - [Key] - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int IdAthlete { get; set; } - [Required] - [MaxLength(100)] - public required string Username { get; set; } - [MaxLength(100)] - public required string LastName { get; set; } - [MaxLength(150)] - public required string FirstName { get; set; } - public required string Email { get; set; } - public required string Sexe { get; set; } - public float Lenght { get; set; } - public float Weight { get; set; } - public required string Password { get; set; } - public DateTime DateOfBirth { get; set; } - public bool IsCoach { get; set; } + /// + /// Represents an athlete entity in the database. + /// + [Table("Athlete")] + public class AthleteEntity + { + /// + /// Gets or sets the unique identifier of the athlete. + /// + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int IdAthlete { get; set; } + + /// + /// Gets or sets the username of the athlete. + /// + [MaxLength(100)] + [Required(ErrorMessage = "Athlete Username is ")] + public required string Username { get; set; } + + /// + /// Gets or sets the last name of the athlete. + /// + [MaxLength(100)] + [Required(ErrorMessage = "Athlete Last Name is ")] + public required string LastName { get; set; } + + /// + /// Gets or sets the first name of the athlete. + /// + [MaxLength(150)] + [Required(ErrorMessage = "Athlete First Name is ")] + public required string FirstName { get; set; } + + /// + /// Gets or sets the email of the athlete. + /// + [MaxLength(100)] + [Required(ErrorMessage = "Athlete Email is ")] + public required string Email { get; set; } + + /// + /// Gets or sets the gender of the athlete. + /// + [MaxLength(1)] + [Required(ErrorMessage = "Athlete Sexe is ")] + public required string Sexe { get; set; } + + /// + /// Gets or sets the height of the athlete. + /// + public double Length { get; set; } + + /// + /// Gets or sets the weight of the athlete. + /// + public float Weight { get; set; } + + /// + /// Gets or sets the password of the athlete. + /// + [Required(ErrorMessage = "Athlete Password is ")] + public required string Password { get; set; } + + /// + /// Gets or sets the date of birth of the athlete. + /// + [Required(ErrorMessage = "Athlete Date of Birth is ")] + [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)] + public DateOnly DateOfBirth { get; set; } + + /// + /// Gets or sets whether the athlete is a coach. + /// + public bool IsCoach { get; set; } + + // [TODO] [DAVE] Check Image + public string? ProfilPicture { get; set; } + + public LargeImageEntity? Image { get; set; } + + [ForeignKey("Image")] + public Guid? ImageId { get; set; } + + public ICollection Activities { get; set; } = new List(); + + public ICollection Statistics { get; set; } = new List(); + + public ICollection TrainingsAthlete { get; set; } = new List(); + public ICollection TrainingsCoach { get; set; } = new List(); + + public ICollection NotificationsReceived { get; set; } = new List(); + public ICollection NotificationsSent { get; set; } = new List(); + + public int? DataSourceId { get; set; } + public DataSourceEntity? DataSource { get; set; } + + public ICollection Followers { get; set; } = []; + public ICollection Followings { get; set; } = []; + } } \ No newline at end of file diff --git a/src/Entities/DataSourceEntity.cs b/src/Entities/DataSourceEntity.cs index 8bed224..9a1eb1e 100644 --- a/src/Entities/DataSourceEntity.cs +++ b/src/Entities/DataSourceEntity.cs @@ -1,15 +1,50 @@ +//----------------------------------------------------------------------- +// FILENAME: DataSourceEntity.cs +// PROJECT: Entities +// SOLUTION: HeartTrack +// DATE CREATED: 22/02/2024 +// AUTHOR: HeartTeam +//----------------------------------------------------------------------- + using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -namespace Entities; - -[Table("DataSource")] -public class DataSourceEntity +namespace Entities { - [Key] - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int IdSource { get; set; } - public required string Type { get; set; } - public required string Modele { get; set; } - public float Precision { get; set; } + /// + /// Represents a data source entity in the database. + /// + [Table("DataSource")] + public class DataSourceEntity + { + /// + /// Gets or sets the unique identifier of the data source. + /// + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int IdSource { get; set; } + + /// + /// Gets or sets the type of the data source. + /// + [MaxLength(100)] + [Required] + public required string Type { get; set; } + + /// + /// Gets or sets the model of the data source. + /// + [MaxLength(100)] + [Required] + public required string Model { get; set; } + + /// + /// Gets or sets the precision of the data source. + /// + public float Precision { get; set; } + + public ICollection Activities { get; set; } = new List(); + + public ICollection Athletes { get; set; } = new List(); + } } \ No newline at end of file diff --git a/src/Entities/Entities.csproj b/src/Entities/Entities.csproj index bb23fb7..b007a4d 100644 --- a/src/Entities/Entities.csproj +++ b/src/Entities/Entities.csproj @@ -5,5 +5,4 @@ enable enable - diff --git a/src/Entities/FriendshipEntity.cs b/src/Entities/FriendshipEntity.cs new file mode 100644 index 0000000..6fadb15 --- /dev/null +++ b/src/Entities/FriendshipEntity.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace Entities; + +public class FriendshipEntity +{ + [ForeignKey("FollowingId")] + public int FollowingId { get; set; } + public AthleteEntity Following { get; set; } = null!; + [ForeignKey("FollowerId")] + public int FollowerId { get; set; } + public AthleteEntity Follower { get; set; } = null!; + public DateTime StartDate { get; set; } +} \ No newline at end of file diff --git a/src/Entities/HeartRateEntity.cs b/src/Entities/HeartRateEntity.cs index 0806219..bd3486d 100644 --- a/src/Entities/HeartRateEntity.cs +++ b/src/Entities/HeartRateEntity.cs @@ -1,18 +1,83 @@ +//----------------------------------------------------------------------- +// FILENAME: HeartRateEntity.cs +// PROJECT: Entities +// SOLUTION: HeartTrack +// DATE CREATED: 22/02/2024 +// AUTHOR: HeartTeam +//----------------------------------------------------------------------- + using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -namespace Entities; - -[Table("HeartRate")] -public class HeartRateEntity +namespace Entities { - [Key] - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int IdHeartRate { get; set; } - public double Altitude { get; set; } - public DateTime Time { get; set; } - public float Temperature { get; set; } - public int Bpm { get; set; } - public float Longitude { get; set; } - public float Latitude { get; set; } + /// + /// Represents a heart rate entity in the database. + /// + [Table("HeartRate")] + public class HeartRateEntity + { + /// + /// Gets or sets the unique identifier of the heart rate entry. + /// + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int IdHeartRate { get; set; } + + /// + /// Gets or sets the altitude. + /// + public double? Altitude { get; set; } + + /// + /// Gets or sets the time of the heart rate measurement. + /// + [Required(ErrorMessage = "HeartRate Time is required")] + [DisplayFormat(DataFormatString = "{0:HH:mm;ss}", ApplyFormatInEditMode = true)] + public TimeOnly Time { get; set; } + + /// + /// Gets or sets the temperature. + /// + public double? Temperature { get; set; } + + /// + /// Gets or sets the heart rate in beats per minute (bpm). + /// + public int Bpm { get; set; } + + /// + /// Gets or sets the longitude. + /// + public double? Longitude { get; set; } + + /// + /// Gets or sets the latitude. + /// + public double? Latitude { get; set; } + + /// + /// Gets or sets the cadence. + /// + public int? Cadence { get; set; } + + /// + /// Gets or sets the distance. + /// + public double? Distance { get; set; } + + /// + /// Gets or sets the speed. + /// + public double? Speed { get; set; } + + /// + /// Gets or sets the power. + /// + public int? Power { get; set; } + + public int ActivityId { get; set; } + + public ActivityEntity Activity { get; set; } = null!; + } } \ No newline at end of file diff --git a/src/Entities/LargeImageEntity.cs b/src/Entities/LargeImageEntity.cs new file mode 100644 index 0000000..dfe917e --- /dev/null +++ b/src/Entities/LargeImageEntity.cs @@ -0,0 +1,11 @@ +using System.ComponentModel.DataAnnotations; + +namespace Entities; + +public class LargeImageEntity +{ + [Key] + public Guid Id { get; set; } + public string Base64 { get; set; } + +} \ No newline at end of file diff --git a/src/Entities/NotificationEntity.cs b/src/Entities/NotificationEntity.cs index 53d12cc..c08204d 100644 --- a/src/Entities/NotificationEntity.cs +++ b/src/Entities/NotificationEntity.cs @@ -1,16 +1,57 @@ +//----------------------------------------------------------------------- +// FILENAME: NotificationEntity.cs +// PROJECT: Entities +// SOLUTION: HeartTrack +// DATE CREATED: 22/02/2024 +// AUTHOR: HeartTeam +//----------------------------------------------------------------------- + using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -namespace Entities; - -[Table("Notification")] -public class NotificationEntity +namespace Entities { - [Key] - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int IdNotif { get; set; } - public required string Message { get; set; } - public DateTime Date { get; set; } - public required bool Statut { get; set; } - public required string Urgence { get; set; } + /// + /// Represents a notification entity in the database. + /// + [Table("Notification")] + public class NotificationEntity + { + /// + /// Gets or sets the unique identifier of the notification. + /// + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int IdNotif { get; set; } + + /// + /// Gets or sets the message of the notification. + /// + [MaxLength(100)] + [Required(ErrorMessage = "Message is required")] + public string Message { get; set; } = null!; + + /// + /// Gets or sets the date of the notification. + /// + [Required(ErrorMessage = "Notification Date is required")] + [DisplayFormat(DataFormatString = "{0:HH.mm.ss - HH.mm.ss}", ApplyFormatInEditMode = true)] + public DateTime Date { get; set; } + + /// + /// Gets or sets the status of the notification. + /// + public bool Statut { get; set; } + + /// + /// Gets or sets the urgency of the notification. + /// + [MaxLength(100)] + public string Urgence { get; set; } = null!; + + public int SenderId { get; set; } + + public AthleteEntity Sender { get; set; } = null!; + public ICollection Receivers { get; set; } = new List(); + } } \ No newline at end of file diff --git a/src/Entities/StatisticEntity.cs b/src/Entities/StatisticEntity.cs index ed01553..27e58ca 100644 --- a/src/Entities/StatisticEntity.cs +++ b/src/Entities/StatisticEntity.cs @@ -1,17 +1,58 @@ +//----------------------------------------------------------------------- +// FILENAME: StatisticEntity.cs +// PROJECT: Entities +// SOLUTION: HeartTrack +// DATE CREATED: 22/02/2024 +// AUTHOR: HeartTeam +//----------------------------------------------------------------------- + using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -namespace Entities; - -[Table("Statistic")] -public class StatisticEntity +namespace Entities { - [Key] - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int IdStatistic { get; set; } - public float Weight { get; set; } - public double AverageHeartRate { get; set; } - public double MaximumHeartRate { get; set; } - public double AverageCaloriesBurned { get; set; } - public DateTime Date { get; set; } + /// + /// Represents a statistic entity in the database. + /// + [Table("Statistic")] + public class StatisticEntity + { + /// + /// Gets or sets the unique identifier of the statistic. + /// + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int IdStatistic { get; set; } + + /// + /// Gets or sets the weight recorded in the statistic. + /// + public float Weight { get; set; } + + /// + /// Gets or sets the average heart rate recorded in the statistic. + /// + public double AverageHeartRate { get; set; } + + /// + /// Gets or sets the maximum heart rate recorded in the statistic. + /// + public double MaximumHeartRate { get; set; } + + /// + /// Gets or sets the average calories burned recorded in the statistic. + /// + public double AverageCaloriesBurned { get; set; } + + /// + /// Gets or sets the date of the statistic. + /// + [Required(ErrorMessage = "Statistic Date is required")] + [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)] + public DateOnly Date { get; set; } + + public int AthleteId { get; set; } + + public AthleteEntity Athlete { get; set; } = null!; + } } \ No newline at end of file diff --git a/src/Entities/TrainingEntity.cs b/src/Entities/TrainingEntity.cs index 5bf7949..f801790 100644 --- a/src/Entities/TrainingEntity.cs +++ b/src/Entities/TrainingEntity.cs @@ -1,20 +1,61 @@ +//----------------------------------------------------------------------- +// FILENAME: TrainingEntity.cs +// PROJECT: Entities +// SOLUTION: HeartTrack +// DATE CREATED: 22/02/2024 +// AUTHOR: HeartTeam +//----------------------------------------------------------------------- + using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -namespace Entities; - -[Table("Training")] -public class TrainingEntity +namespace Entities { - // ! donner plus de contraintes !! - [Key] - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int IdTraining { get; set; } - public DateTime Date { get; set; } - [MaxLength(300)] - public string? Description { get; set; } - public float Latitude { get; set; } - public float Longitude { get; set; } - [MaxLength(300)] - public string? FeedBack { get; set; } + /// + /// Represents a training entity in the database. + /// + [Table("Training")] + public class TrainingEntity + { + /// + /// Gets or sets the unique identifier of the training. + /// + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int IdTraining { get; set; } + + /// + /// Gets or sets the date of the training. + /// + [Required(ErrorMessage = "Training Date is required")] + [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)] + public DateOnly Date { get; set; } + + /// + /// Gets or sets the description of the training. + /// + [MaxLength(300)] + public string? Description { get; set; } + + /// + /// Gets or sets the latitude of the training location. + /// + public float Latitude { get; set; } + + /// + /// Gets or sets the longitude of the training location. + /// + public float Longitude { get; set; } + + /// + /// Gets or sets the feedback for the training. + /// + [MaxLength(300)] + public string? FeedBack { get; set; } + + public int CoachId { get; set; } + + public AthleteEntity Coach { get; set; } = null!; + public ICollection Athletes { get; set; } = new List(); + } } \ No newline at end of file diff --git a/src/HeartTrack.sln b/src/HeartTrack.sln index 6ecaf7b..8bd8954 100644 --- a/src/HeartTrack.sln +++ b/src/HeartTrack.sln @@ -3,26 +3,51 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DbContextLib", "DbContextLib\DbContextLib.csproj", "{330A5DA0-0B4E-48D4-9AF3-6DCB39EE9622}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DbContextLib", "DbContextLib\DbContextLib.csproj", "{330A5DA0-0B4E-48D4-9AF3-6DCB39EE9622}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entities", "Entities\Entities.csproj", "{A07F86B3-555B-4B35-8BB1-25E844825A38}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Entities", "Entities\Entities.csproj", "{A07F86B3-555B-4B35-8BB1-25E844825A38}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StubbedContextLib", "StubbedContextLib\StubbedContextLib.csproj", "{2F44DE6E-EFFC-42FE-AFF6-79CDC762E6D8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StubbedContextLib", "StubbedContextLib\StubbedContextLib.csproj", "{2F44DE6E-EFFC-42FE-AFF6-79CDC762E6D8}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{2B227C67-3BEC-4A83-BDA0-F3918FBC0D18}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleTestEntities", "Tests\ConsoleTestEntities\ConsoleTestEntities.csproj", "{477D2129-A6C9-4FF8-8BE9-5E9E8E5282F8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleTestEntities", "Tests\ConsoleTestEntities\ConsoleTestEntities.csproj", "{477D2129-A6C9-4FF8-8BE9-5E9E8E5282F8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleTestRelationships", "Tests\ConsoleTestRelationships\ConsoleTestRelationships.csproj", "{2D166FAD-4934-474B-96A8-6C0635156EC2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleTestRelationships", "Tests\ConsoleTestRelationships\ConsoleTestRelationships.csproj", "{2D166FAD-4934-474B-96A8-6C0635156EC2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dto", "Dto\Dto.csproj", "{562019BC-0F61-41B0-9BAE-259B92C6BFBA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HeartTrackAPI", "HeartTrackAPI\HeartTrackAPI.csproj", "{C1C2EAC3-3347-466B-BFB6-2A9F11A3AE12}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "Shared\Shared.csproj", "{F80C60E1-1E06-46C2-96DE-42B1C7DE65BC}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestsAPI", "TestsAPI", "{30FC2BE9-7397-445A-84AD-043CE70F4281}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClientTests", "Tests\TestsAPI\ClientTests\ClientTests.csproj", "{9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model", "Model\Model.csproj", "{30AB7FAA-6072-40B6-A15E-9188B59144F9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTestApi", "Tests\TestsAPI\UnitTestApi\UnitTestApi.csproj", "{E515C8B6-6282-4D8B-8523-7B3A13E4AF58}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTestsEntities", "Tests\UnitTestsEntities\UnitTestsEntities.csproj", "{31FA8E5E-D642-4C43-A2B2-02B9832B2CEC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model2Entities", "Model2Entities\Model2Entities.csproj", "{FA329DEF-4756-4A8B-84E9-5A625FF94CBF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StubAPI", "StubAPI\StubAPI.csproj", "{C9BD0310-DC18-4356-B8A7-2B6959AF7813}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleTestEFMapper", "Tests\ConsoleTestEFMapper\ConsoleTestEFMapper.csproj", "{73EA27F2-9F0C-443F-A5EE-2960C983A422}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EFMappers", "EFMappers\EFMappers.csproj", "{9397795D-F482-44C4-8443-A20AC26671AA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APIMappers", "APIMappers\APIMappers.csproj", "{41D18203-1688-43BD-A3AC-FD0C2BD81909}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestsModel", "Tests\UnitTestsModel\UnitTestsModel.csproj", "{508D380F-145C-437E-A7DF-7A17C526B2F3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {330A5DA0-0B4E-48D4-9AF3-6DCB39EE9622}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {330A5DA0-0B4E-48D4-9AF3-6DCB39EE9622}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -44,9 +69,73 @@ Global {2D166FAD-4934-474B-96A8-6C0635156EC2}.Debug|Any CPU.Build.0 = Debug|Any CPU {2D166FAD-4934-474B-96A8-6C0635156EC2}.Release|Any CPU.ActiveCfg = Release|Any CPU {2D166FAD-4934-474B-96A8-6C0635156EC2}.Release|Any CPU.Build.0 = Release|Any CPU + {562019BC-0F61-41B0-9BAE-259B92C6BFBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {562019BC-0F61-41B0-9BAE-259B92C6BFBA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {562019BC-0F61-41B0-9BAE-259B92C6BFBA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {562019BC-0F61-41B0-9BAE-259B92C6BFBA}.Release|Any CPU.Build.0 = Release|Any CPU + {C1C2EAC3-3347-466B-BFB6-2A9F11A3AE12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C1C2EAC3-3347-466B-BFB6-2A9F11A3AE12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C1C2EAC3-3347-466B-BFB6-2A9F11A3AE12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C1C2EAC3-3347-466B-BFB6-2A9F11A3AE12}.Release|Any CPU.Build.0 = Release|Any CPU + {F80C60E1-1E06-46C2-96DE-42B1C7DE65BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F80C60E1-1E06-46C2-96DE-42B1C7DE65BC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F80C60E1-1E06-46C2-96DE-42B1C7DE65BC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F80C60E1-1E06-46C2-96DE-42B1C7DE65BC}.Release|Any CPU.Build.0 = Release|Any CPU + {9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9E4D3AC5-E6CA-4753-BD96-BF5EE793931A}.Release|Any CPU.Build.0 = Release|Any CPU + {30AB7FAA-6072-40B6-A15E-9188B59144F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {30AB7FAA-6072-40B6-A15E-9188B59144F9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {30AB7FAA-6072-40B6-A15E-9188B59144F9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {30AB7FAA-6072-40B6-A15E-9188B59144F9}.Release|Any CPU.Build.0 = Release|Any CPU + {E515C8B6-6282-4D8B-8523-7B3A13E4AF58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E515C8B6-6282-4D8B-8523-7B3A13E4AF58}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E515C8B6-6282-4D8B-8523-7B3A13E4AF58}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E515C8B6-6282-4D8B-8523-7B3A13E4AF58}.Release|Any CPU.Build.0 = Release|Any CPU + {31FA8E5E-D642-4C43-A2B2-02B9832B2CEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {31FA8E5E-D642-4C43-A2B2-02B9832B2CEC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {31FA8E5E-D642-4C43-A2B2-02B9832B2CEC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {31FA8E5E-D642-4C43-A2B2-02B9832B2CEC}.Release|Any CPU.Build.0 = Release|Any CPU + {FA329DEF-4756-4A8B-84E9-5A625FF94CBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FA329DEF-4756-4A8B-84E9-5A625FF94CBF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FA329DEF-4756-4A8B-84E9-5A625FF94CBF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FA329DEF-4756-4A8B-84E9-5A625FF94CBF}.Release|Any CPU.Build.0 = Release|Any CPU + {C9BD0310-DC18-4356-B8A7-2B6959AF7813}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C9BD0310-DC18-4356-B8A7-2B6959AF7813}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C9BD0310-DC18-4356-B8A7-2B6959AF7813}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C9BD0310-DC18-4356-B8A7-2B6959AF7813}.Release|Any CPU.Build.0 = Release|Any CPU + {73EA27F2-9F0C-443F-A5EE-2960C983A422}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {73EA27F2-9F0C-443F-A5EE-2960C983A422}.Debug|Any CPU.Build.0 = Debug|Any CPU + {73EA27F2-9F0C-443F-A5EE-2960C983A422}.Release|Any CPU.ActiveCfg = Release|Any CPU + {73EA27F2-9F0C-443F-A5EE-2960C983A422}.Release|Any CPU.Build.0 = Release|Any CPU + {9397795D-F482-44C4-8443-A20AC26671AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9397795D-F482-44C4-8443-A20AC26671AA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9397795D-F482-44C4-8443-A20AC26671AA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9397795D-F482-44C4-8443-A20AC26671AA}.Release|Any CPU.Build.0 = Release|Any CPU + {41D18203-1688-43BD-A3AC-FD0C2BD81909}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {41D18203-1688-43BD-A3AC-FD0C2BD81909}.Debug|Any CPU.Build.0 = Debug|Any CPU + {41D18203-1688-43BD-A3AC-FD0C2BD81909}.Release|Any CPU.ActiveCfg = Release|Any CPU + {41D18203-1688-43BD-A3AC-FD0C2BD81909}.Release|Any CPU.Build.0 = Release|Any CPU + {508D380F-145C-437E-A7DF-7A17C526B2F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {508D380F-145C-437E-A7DF-7A17C526B2F3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {508D380F-145C-437E-A7DF-7A17C526B2F3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {508D380F-145C-437E-A7DF-7A17C526B2F3}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {477D2129-A6C9-4FF8-8BE9-5E9E8E5282F8} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} {2D166FAD-4934-474B-96A8-6C0635156EC2} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} + {30FC2BE9-7397-445A-84AD-043CE70F4281} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} + {9E4D3AC5-E6CA-4753-BD96-BF5EE793931A} = {30FC2BE9-7397-445A-84AD-043CE70F4281} + {E515C8B6-6282-4D8B-8523-7B3A13E4AF58} = {30FC2BE9-7397-445A-84AD-043CE70F4281} + {31FA8E5E-D642-4C43-A2B2-02B9832B2CEC} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} + {73EA27F2-9F0C-443F-A5EE-2960C983A422} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} + {508D380F-145C-437E-A7DF-7A17C526B2F3} = {2B227C67-3BEC-4A83-BDA0-F3918FBC0D18} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0F3487F4-66CA-4034-AC66-1BC899C9B523} EndGlobalSection EndGlobal diff --git a/src/HeartTrackAPI/Controllers/ActivityController.cs b/src/HeartTrackAPI/Controllers/ActivityController.cs new file mode 100644 index 0000000..b6e160b --- /dev/null +++ b/src/HeartTrackAPI/Controllers/ActivityController.cs @@ -0,0 +1,251 @@ +using APIMappers; +using Dto; +using HeartTrackAPI.Request; +using HeartTrackAPI.Responce; +using Microsoft.AspNetCore.Mvc; +using Model; +using Shared; +using Model.Manager; +using Model.Repository; + +namespace HeartTrackAPI.Controllers; +[ApiController] +[ApiVersion("1.0")] +[Route("api/v{version:apiVersion}/[controller]")] +public class ActivityController : Controller +{ + private readonly IActivityRepository _activityService; + private readonly ILogger _logger; + private readonly IUserRepository _userRepository; + + + public ActivityController(IDataManager dataManager, ILogger logger) + { + _activityService = dataManager.ActivityRepo; + _userRepository = dataManager.UserRepo; + _logger = logger; + } + + [HttpGet] + [ProducesResponseType(typeof(PageResponse), 200)] + [ProducesResponseType(400)] + [ProducesResponseType(500)] + public async Task>> 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(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 StatusCode(500); + } + } + + [HttpPost] + public async Task PostActivity(ActivityDto activityDto) + { + var user = await _userRepository.GetItemById(activityDto.AthleteId); + if (user == null) + { + _logger.LogError("Athlete with id {id} not found", activityDto.AthleteId); + return NotFound($"Athlete with id {activityDto.AthleteId} not found"); + } + var tmp = user.DataSources.FirstOrDefault(ds => ds.Id == activityDto.DataSourceId); + if (tmp == null) + { + _logger.LogError("DataSource with id {id} not found", activityDto.DataSourceId); + return NotFound($"DataSource with id {activityDto.DataSourceId} not found"); + } + + var activity = activityDto.ToModel(user); + var result = await _activityService.AddActivity(activity); + if (result == null) + { + return BadRequest(); + } + return CreatedAtAction(nameof(GetActivity), new { id = result.Id }, result.ToDto()); + } + + /* + public async Task PostFitFile( Stream file, string contentType) // [FromForm] + { + if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) + { + ModelState.AddModelError("File", + $"The request couldn't be processed (Error 1)."); + // Log error + + return BadRequest(ModelState); + } + if (file == null) + { + return BadRequest("No file was provided"); + } + //var fileUploadSummary = await _fileService.UploadFileAsync(HttpContext.Request.Body, Request.ContentType); +// var activity = await _activityManager.AddActivityFromFitFile(file); + var activity = new Activity + { + Id = 1, + Type = "Running", + Date = new DateTime(2021, 10, 10), + StartTime = new DateTime(2021, 10, 10, 10, 0, 0), + EndTime = new DateTime(2021, 10, 10, 11, 0, 0), + Effort = 3, + Variability = 0.5f, + Variance = 0.5f, + StandardDeviation = 0.5f, + Average = 5.0f, + Maximum = 10, + Minimum = 0, + AverageTemperature = 20.0f, + HasAutoPause = false, + Users = + { + new User + { + Id = 3, Username = "Athlete3", + ProfilePicture = + "https://plus.unsplash.com/premium_photo-1705091981693-6006f8a20479?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + FirstName = "First3", LastName = "Last3", + Sexe = "M", Lenght = 190, Weight = 80, DateOfBirth = new DateTime(1994, 3, 3), Email = "ath@ex.fr", + Role = new Athlete() + } + } + }; + if (activity == null) + { + return BadRequest("The file provided is not a valid fit file"); + } + return CreatedAtAction(nameof(GetActivity), new { id = activity.Id }, activity.ToDto()); + }*/ + + [HttpGet("{id}")] + public async Task> GetActivity(int id) + { + try + { + _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetActivity), 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"); + } + return Ok(activity.ToDto()); + } + catch (Exception e) + { + _logger.LogError(e, "Error while getting activity by id {id}", id); + return Problem(); + } + } + + [HttpPut("{id}")] + public async Task PutActivity(int id, ActivityDto activityDto) + { + if (id != activityDto.Id) + { + return BadRequest(); + } + var user = await _userRepository.GetItemById(activityDto.AthleteId); + if (user == null) + { + _logger.LogError("Athlete with id {id} not found", activityDto.AthleteId); + return NotFound($"Athlete with id {activityDto.AthleteId} not found"); + } + var activity = activityDto.ToModel(user); + var result = await _activityService.UpdateActivity(id, activity); + if (result == null) + { + return NotFound(); + } + return NoContent(); + } + + /// + /// Supprime une activity spécifique. + /// + /// L'identifiant de l'activity à supprimer. + /// Action result. + /// Activity supprimé avec succès. + /// Activity non trouvé. + /// Erreur interne du serveur. + [HttpDelete("{id}")] + [ProducesResponseType(200)] + [ProducesResponseType(404)] + [ProducesResponseType(500)] + public async Task 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 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(); + var notUploadedFiles = new List(); + + 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 + }; + }*/ +} \ No newline at end of file diff --git a/src/HeartTrackAPI/Controllers/UsersController.cs b/src/HeartTrackAPI/Controllers/UsersController.cs new file mode 100644 index 0000000..cd9f0b6 --- /dev/null +++ b/src/HeartTrackAPI/Controllers/UsersController.cs @@ -0,0 +1,436 @@ +using System.ComponentModel.DataAnnotations; +using APIMappers; +using Dto; +using HeartTrackAPI.Request; +using HeartTrackAPI.Responce; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Model.Manager; +using Model.Repository; +using Shared; + +namespace HeartTrackAPI.Controllers; +/// +/// Contrôle les actions liées aux utilisateurs dans l'application HeartTrack. +/// Gère les opérations CRUD sur les utilisateurs, leurs amis, et leurs activités. +/// +[ApiController] +[ApiVersion("1.0")] +[Route("api/v{version:apiVersion}/[controller]")] +public class UsersController : Controller +{ + private readonly ILogger _logger; + private readonly IActivityRepository _activityService; + private readonly IUserRepository _userService; + public UsersController(ILogger logger, IDataManager dataManager) + { + _logger = logger; + _userService = dataManager.UserRepo; + _activityService = dataManager.ActivityRepo; + } + + /// + /// Récupère une page d'utilisateurs en fonction des critères de pagination et de tri fournis. + /// + /// Les critères de pagination et de tri pour les utilisateurs. Met None par defaut et/ou si le critère n'est pas correct + /// Une page de données utilisateur selon les critères spécifiés. + /// Retourne la page demandée d'utilisateurs. + /// La demande de pagination est invalide. + /// Erreur interne du serveur. + [HttpGet] + [ProducesResponseType(typeof(PageResponse), 200)] + [ProducesResponseType(400)] + [ProducesResponseType(500)] + public async Task>> Get([FromQuery] PageRequest request) + { + try + { + var totalCount = await _userService.GetNbItems(); + if (request.Count * request.Index >= totalCount) + { + _logger.LogError("To many object is asked the max is {totalCount} but the request is superior of ", totalCount); + return BadRequest("To many object is asked the max is : " + totalCount); + } + + _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(Get), null); + + var athletes = await _userService.GetUsers(request.Index, request.Count, Enum.TryParse(request.OrderingPropertyName, out AthleteOrderCriteria result) ? result : AthleteOrderCriteria.None, request.Descending ?? false); + var pageResponse = new PageResponse(request.Index, request.Count, totalCount, athletes!.Select(a => a.ToDto())); + return Ok(pageResponse); + } + catch (Exception e) + { + _logger.LogError(e, "Error while getting all athletes"); + return Problem(); + } + } + + /// + /// Récupère un utilisateur spécifique par son identifiant. + /// + /// L'identifiant de l'utilisateur à récupérer. + /// L'utilisateur correspondant à l'identifiant spécifié. + /// Retourne l'utilisateur demandé. + /// Aucun utilisateur trouvé pour l'identifiant spécifié. + /// Erreur interne du serveur. + [HttpGet("{id}")] + [ProducesResponseType(typeof(UserDto), 200)] + [ProducesResponseType(404)] + [ProducesResponseType(500)] + public async Task> GetById([Range(0,int.MaxValue)]int id) + { + try + { + _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetById), id); + var athlete = await _userService.GetItemById(id); + if (athlete == null) + { + _logger.LogError("Athlete with id {id} not found", id); + return NotFound($"Athlete with id {id} not found"); + } + return Ok(athlete.ToDto()); + } + catch (Exception e) + { + _logger.LogError(e, "Error while getting athlete by id {id}", id); + return Problem(); + } + } + + /// + /// Obtient le nombre total d'utilisateurs. + /// + /// Le nombre total d'utilisateurs. + /// Retourne le nombre total d'utilisateurs. + /// Erreur interne du serveur. + [HttpGet("count")] + [ProducesResponseType(typeof(int), 200)] + [ProducesResponseType(500)] + public async Task> Count() + { + try + { + _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(Count), null); + var nbUsers = await _userService.GetNbItems(); + return Ok(nbUsers); + } + catch (Exception e) + { + _logger.LogError(e, "Error while getting the number of users"); + return Problem(); + } + } + + /// + /// Met à jour les informations d'un utilisateur spécifique. + /// + /// L'identifiant de l'utilisateur à mettre à jour. + /// Les données de l'utilisateur pour la mise à jour. + /// L'utilisateur mis à jour. + /// Retourne l'utilisateur mis à jour. + /// Utilisateur non trouvé. + /// Erreur interne du serveur. + [HttpPut("{id}")] + [ProducesResponseType(typeof(UserDto), 200)] + [ProducesResponseType(404)] + [ProducesResponseType(500)] + public async Task> Update(int id, [FromBody] UserDto user) + { + try + { + _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(Update), user,id); + var athlete = await _userService.GetItemById(id); + if (athlete == null) + { + _logger.LogError("Athlete with id {id} not found", id); + return NotFound($"Athlete with id {id} not found"); + } + var updatedAthlete = await _userService.UpdateItem(id, user.ToModel()); + if(updatedAthlete == null) + { + _logger.LogError("Error while updating athlete with id {id}", id); + return Problem(); + } + return Ok(updatedAthlete.ToDto()); + + } + catch (Exception e) + { + _logger.LogError(e, "Error while getting the number of users"); + return Problem(); + } + } + + /// + /// Supprime un utilisateur spécifique. + /// + /// L'identifiant de l'utilisateur à supprimer. + /// Action result. + /// Utilisateur supprimé avec succès. + /// Utilisateur non trouvé. + /// Erreur interne du serveur. + [HttpDelete("{id}")] + [ProducesResponseType(200)] + [ProducesResponseType(404)] + [ProducesResponseType(500)] + public async Task Delete(int id) + { + try + { + _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(Delete), null,id); + + + var athlete = await _userService.GetItemById(id); + if (athlete == null) + { + _logger.LogError("Athlete with id {id} not found", id); + return NotFound($"Athlete with id {id} not found"); + } + var isDeleted = await _userService.DeleteItem(id); + if(!isDeleted) + { + _logger.LogError("Error while deleting athlete with id {id}", id); + return Problem(); + } + return Ok(); + } + catch (Exception e) + { + _logger.LogError(e, "Error while getting the number of users"); + return Problem(); + } + } + + /// + /// Obtient la liste des amis d'un utilisateur spécifique. + /// + /// L'identifiant de l'utilisateur. + /// Les critères de pagination et de tri. + /// La liste paginée des amis. + /// Retourne la liste paginée des amis de l'utilisateur. + /// Utilisateur non trouvé. + /// Erreur interne du serveur. + [HttpGet("{id}/friends")] + [ProducesResponseType(typeof(PageResponse), 200)] + [ProducesResponseType(404)] + [ProducesResponseType(500)] + public async Task>> GetFriends(int id, [FromQuery] PageRequest request) + { + try + { + _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(GetFriends), null,id); + var athlete = await _userService.GetItemById(id); + if (athlete == null) + { + _logger.LogError("Athlete with id {id} not found", id); + return NotFound($"Athlete with id {id} not found"); + } + var totalCount = await _userService.GetNbFriends(athlete); + if (request.Count * request.Index >= totalCount) + { + _logger.LogError("To many object is asked the max is {totalCount} but the request is superior of ", totalCount); + return BadRequest("To many object is asked the max is : " + totalCount); + } + var friends = await _userService.GetFriends(athlete, request.Index, request.Count, Enum.TryParse(request.OrderingPropertyName, out AthleteOrderCriteria result) ? result : AthleteOrderCriteria.None, request.Descending ?? false); + if (friends == null) return NotFound(); + var pageResponse = new PageResponse(request.Index, request.Count, totalCount, friends.Select(a => a.ToDto())); + return Ok(pageResponse); + } + catch (Exception e) + { + _logger.LogError(e, "Error while getting the number of users"); + return Problem(); + } + } + + /// + /// Ajoute un ami à un utilisateur spécifique. + /// + /// L'identifiant de l'utilisateur. + /// L'identifiant de l'ami à ajouter. + /// Action result. + /// Ami ajouté avec succès. + /// Utilisateur ou ami non trouvé. + /// Erreur interne du serveur. + [HttpPost("{id}/friend/{friendId}")] + [ProducesResponseType(200)] + [ProducesResponseType(404)] + [ProducesResponseType(500)] + public async Task AddFriend(int id, int friendId) + { + try + { + _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(AddFriend), friendId,id); + var athlete = await _userService.GetItemById(id); + if (athlete == null) + { + _logger.LogError("Athlete with id {id} not found", id); + return NotFound($"Athlete with id {id} not found"); + } + var friend = await _userService.GetItemById(friendId); + if (friend == null) + { + _logger.LogError("Athlete with id {id} not found", friendId); + return NotFound($"Athlete with id {friendId} not found"); + } + var isAdded = await _userService.AddFriend(athlete, friend); + if(!isAdded) + { + _logger.LogError("Error while adding friend with id {friendId} to athlete with id {id}", friendId, id); + return Problem(); + } + return Ok(); + } + catch (Exception e) + { + _logger.LogError(e, "Error while getting the number of users"); + return Problem(); + } + } + + + /// + /// Supprime un ami d'un utilisateur spécifique. + /// + /// L'identifiant de l'utilisateur. + /// L'identifiant de l'ami à supprimer. + /// Action result. + /// Ami supprimé avec succès. + /// Utilisateur ou ami non trouvé. + /// Erreur interne du serveur. + [HttpDelete("{id}/friend/{friendId}")] + [ProducesResponseType(200)] + [ProducesResponseType(404)] + [ProducesResponseType(500)] + public async Task RemoveFriend(int id, int friendId) + { + try + { + _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(RemoveFriend), friendId,id); + var athlete = await _userService.GetItemById(id); + if (athlete == null) + { + _logger.LogError("Athlete with id {id} not found", id); + return NotFound($"Athlete with id {id} not found"); + } + var friend = await _userService.GetItemById(friendId); + if (friend == null) + { + _logger.LogError("Athlete with id {id} not found", friendId); + return NotFound($"Athlete with id {friendId} not found"); + } + var isRemoved = await _userService.RemoveFriend(athlete, friend); + if(!isRemoved) + { + _logger.LogError("Error while removing friend with id {friendId} to athlete with id {id}", friendId, id); + return Problem(); + } + return Ok(); + } + catch (Exception e) + { + _logger.LogError(e, "Error while getting the number of users"); + return Problem(); + } + } + + /// + /// Obtient la liste des athlètes d'un coach spécifique. + /// + /// L'identifiant du coach. + /// Les critères de pagination et de tri. + /// La liste paginée des athlètes. + /// Retourne la liste paginée des athlètes du coach. + /// Coach non trouvé. + /// Erreur interne du serveur. + [HttpGet("{coachId}/athletes")] + [ProducesResponseType(typeof(PageResponse), 200)] + [ProducesResponseType(404)] + [ProducesResponseType(500)] + public async Task>> GetAthletes(int coachId, [FromQuery] PageRequest request) + { + try + { + _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(GetAthletes), null,coachId); + var coach = await _userService.GetItemById(coachId); + if (coach == null) + { + _logger.LogError("Athlete with id {id} not found", coachId); + return NotFound($"Athlete with id {coachId} not found"); + } + var totalCount = await _userService.GetNbFriends(coach); + if (request.Count * request.Index >= totalCount) + { + _logger.LogError("To many object is asked the max is {totalCount} but the request is superior of ", totalCount); + return BadRequest("To many object is asked the max is : " + totalCount); + } + var athletes = await _userService.GetFriends(coach, request.Index, request.Count, Enum.TryParse(request.OrderingPropertyName, out AthleteOrderCriteria result) ? result : AthleteOrderCriteria.None, request.Descending ?? false); + if (athletes == null) return NotFound(); + var pageResponse = new PageResponse(request.Index, request.Count, totalCount, athletes.Select(a => a.ToDto())); + return Ok(pageResponse); + } + catch (Exception e) + { + _logger.LogError(e, "Error while getting the number of users"); + return Problem(); + } + } + + /// + /// Obtient la liste des activités d'un utilisateur spécifique. + /// + /// L'identifiant de l'utilisateur. + /// Les critères de pagination et de tri. + /// La liste paginée des activités de l'utilisateur. + /// Retourne la liste paginée des activités. + /// Aucune activité trouvée. + /// Erreur interne du serveur. + [HttpGet("{userId}/activities")] + // should be tiny DTOActivity returned with only the necessary information (will be used in the list of activities of a user) + public async Task>> GetActivitiesByUser(int userId, [FromQuery] PageRequest pageRequest) + { + try + { + var totalCount = await _activityService.GetNbActivitiesByUser(userId); + if (pageRequest.Count * pageRequest.Index >= totalCount) + { + _logger.LogError("To many object is asked the max is {totalCount} but the request is superior of ", totalCount); + return BadRequest("To many object is asked the max is : " + totalCount); + } + _logger.LogInformation("Executing {Action} with parameters: {Parameters}", nameof(GetActivitiesByUser), pageRequest); + var activities = await _activityService.GetActivitiesByUser(userId, pageRequest.Index, pageRequest.Count, Enum.TryParse(pageRequest.OrderingPropertyName, out ActivityOrderCriteria result) ? result : ActivityOrderCriteria.None, pageRequest.Descending ?? false); + if(activities == null) + { + return NotFound("No activities found"); + } + var pageResponse = new PageResponse(pageRequest.Index, pageRequest.Count, totalCount, activities.Select(a => a.ToDto())); + return Ok(pageResponse); + } + catch (Exception e) + { + _logger.LogError(e, "Error while getting all activities"); + return Problem(); + } + } + + /// + /// Déconnecte l'utilisateur actuel. + /// + /// Le gestionnaire de connexion. + /// Paramètre vide utilisé pour s'assurer que la requête provient bien d'un client. + /// Action result. + /// Déconnexion réussie. + /// Déconnexion non autorisée. + /// Erreur interne du serveur. + [HttpPost("logout")] + [ProducesResponseType(200)] + [ProducesResponseType(401)] + [ProducesResponseType(500)] + public async Task Logout(SignInManager signInManager, [FromBody] object? empty) + { + if (empty == null) return Unauthorized(); + await signInManager.SignOutAsync(); + return Ok(); + } + +} \ No newline at end of file diff --git a/src/HeartTrackAPI/Dockerfile b/src/HeartTrackAPI/Dockerfile new file mode 100644 index 0000000..64bcd55 --- /dev/null +++ b/src/HeartTrackAPI/Dockerfile @@ -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"] \ No newline at end of file diff --git a/src/HeartTrackAPI/HeartTrackAPI.csproj b/src/HeartTrackAPI/HeartTrackAPI.csproj new file mode 100644 index 0000000..e815c27 --- /dev/null +++ b/src/HeartTrackAPI/HeartTrackAPI.csproj @@ -0,0 +1,31 @@ + + + + net8.0 + enable + enable + true + true + $(NoWarn);1591 + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/HeartTrackAPI/Program.cs b/src/HeartTrackAPI/Program.cs new file mode 100644 index 0000000..b0010a6 --- /dev/null +++ b/src/HeartTrackAPI/Program.cs @@ -0,0 +1,19 @@ +using HeartTrackAPI.Utils; + +var builder = WebApplication.CreateBuilder(args); + +builder.Logging.AddConsole(); +builder.WebHost.ConfigureKestrel(serverOptions => +{ + serverOptions.Limits.MaxRequestBodySize = long.MaxValue; +}); + +var init = new AppBootstrap(builder.Configuration); + +init.ConfigureServices(builder.Services); + +var app = builder.Build(); + +init.Configure(app, app.Environment); + +app.Run(); \ No newline at end of file diff --git a/src/HeartTrackAPI/Properties/launchSettings.json b/src/HeartTrackAPI/Properties/launchSettings.json new file mode 100644 index 0000000..7156f3d --- /dev/null +++ b/src/HeartTrackAPI/Properties/launchSettings.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:13881", + "sslPort": 44333 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5030", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7233;http://localhost:5030", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/HeartTrackAPI/Request/PageRequest.cs b/src/HeartTrackAPI/Request/PageRequest.cs new file mode 100644 index 0000000..a4399f4 --- /dev/null +++ b/src/HeartTrackAPI/Request/PageRequest.cs @@ -0,0 +1,16 @@ +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; + +// [Range(0, int.MaxValue, ErrorMessage = "Count must be greater than 0")] + public int Index { get; set; } = 0; + +// [Range(0, int.MaxValue, ErrorMessage = "Count must be greater than 0")] + public int Count { get; set; } = 1; +} diff --git a/src/HeartTrackAPI/Responce/PageResponse.cs b/src/HeartTrackAPI/Responce/PageResponse.cs new file mode 100644 index 0000000..93b4cfe --- /dev/null +++ b/src/HeartTrackAPI/Responce/PageResponse.cs @@ -0,0 +1,22 @@ +namespace HeartTrackAPI.Responce; + +public class PageResponse +{ + // 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 Items { get; set; } + + public PageResponse(int index, int count, int total, IEnumerable items) + { + Index = index; + Count = count; + Total = total; + Items = items; + } + +} \ No newline at end of file diff --git a/src/HeartTrackAPI/Utils/AppBootstrap.cs b/src/HeartTrackAPI/Utils/AppBootstrap.cs new file mode 100644 index 0000000..c629f5e --- /dev/null +++ b/src/HeartTrackAPI/Utils/AppBootstrap.cs @@ -0,0 +1,205 @@ +using System.Reflection; +using DbContextLib; +using DbContextLib.Identity; +using HeartTrackAPI.Utils; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.AspNetCore.Mvc.Versioning; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; +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); + 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(connectionString); + Console.WriteLine("======================"); + services.AddDbContext(options => options.UseInMemoryDatabase("AuthDb")); + services.AddDbContext(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"); + if (!string.IsNullOrWhiteSpace(connectionString)) + { + services.AddDbContext(options => options.UseInMemoryDatabase("AuthDb")); + services.AddDbContext(options => + options.UseSqlite(connectionString), ServiceLifetime.Singleton); + } + else + { + services.AddDbContext(options => options.UseInMemoryDatabase("AuthDb")); + services.AddDbContext(); + } + break; + + } + } + + private void AddModelService(IServiceCollection services) + { + switch (Environment.GetEnvironmentVariable("TYPE")) + { + case "BDD": + services.AddSingleton(provider => new DbDataManager(provider.GetRequiredService())); + break; + case "STUB": + services.AddSingleton(); + break; + default: + services.AddSingleton(provider => + { + provider.GetRequiredService().Database.EnsureCreated(); + return new DbDataManager(provider.GetRequiredService()); + }); + break; + } + + //services.AddTransient(); + } + + private void AddIdentityServices(IServiceCollection services) + { +// services.AddTransient, EmailSender>(); + services.AddAuthorization(); + + services.AddIdentityApiEndpoints() + .AddEntityFrameworkStores(); + // .AddEntityFrameworkStores().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 => + { + options.OperationFilter(); + + var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; + var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); + options.IncludeXmlComments(xmlPath); + + options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme + { + Description = + "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", + Name = "Authorization", + In = ParameterLocation.Header, + Type = SecuritySchemeType.ApiKey + }); + var scheme = new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "Bearer" + }, + Scheme = "oauth2", + Name = "Bearer", + In = ParameterLocation.Header, + }, + new List() + } + }; + options.AddSecurityRequirement(scheme); + }); + services.AddTransient, SwaggerOptions>(); + services.AddSwaggerGen(options => + { + options.OperationFilter(); + }); + + services.AddVersionedApiExplorer(setup => + { + setup.GroupNameFormat = "'v'VVV"; + setup.SubstituteApiVersionInUrl = true; + }); + + } + + public void Configure(WebApplication app, IWebHostEnvironment env) + { + app.UseHttpsRedirection(); + app.MapIdentityApi(); + + app.MapControllers(); + app.UseAuthorization(); + + app.MapHealthChecks("/health"); + + // Configure the HTTP request pipeline. + if (true) + { + var apiVersionDescriptionProvider = app.Services.GetRequiredService(); + app.UseSwagger(); + app.UseSwaggerUI(); + app.MapSwagger(); + app.UseSwaggerUI(options => + { + foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions) + { + options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", + description.GroupName.ToUpperInvariant()); + } + }); + + } + + + } +} diff --git a/src/HeartTrackAPI/Utils/SwaggerDefaultValues.cs b/src/HeartTrackAPI/Utils/SwaggerDefaultValues.cs new file mode 100644 index 0000000..dd8671c --- /dev/null +++ b/src/HeartTrackAPI/Utils/SwaggerDefaultValues.cs @@ -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; + } + } +} \ No newline at end of file diff --git a/src/HeartTrackAPI/Utils/SwaggerOptions.cs b/src/HeartTrackAPI/Utils/SwaggerOptions.cs new file mode 100644 index 0000000..02c92d8 --- /dev/null +++ b/src/HeartTrackAPI/Utils/SwaggerOptions.cs @@ -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 + + { + private readonly IApiVersionDescriptionProvider _provider; + + public SwaggerOptions( + IApiVersionDescriptionProvider provider) + { + _provider = provider; + } + + /// + /// Configure each API discovered for Swagger Documentation + /// + /// + 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)); + } + } + + /// + /// Configure Swagger Options. Inherited from the Interface + /// + /// + /// + public void Configure(string? name, SwaggerGenOptions options) + { + Configure(options); + } + + /// + /// Create information about the version of the API + /// + /// + /// Information about the API + 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; + } + } diff --git a/src/HeartTrackAPI/appsettings.Development.json b/src/HeartTrackAPI/appsettings.Development.json new file mode 100644 index 0000000..5a8cc87 --- /dev/null +++ b/src/HeartTrackAPI/appsettings.Development.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "ConnectionStrings": { + "HeartTrackAuthConnection": "Data Source=uca_HeartTrack.db" + } +} diff --git a/src/HeartTrackAPI/appsettings.json b/src/HeartTrackAPI/appsettings.json new file mode 100644 index 0000000..5fb6b3c --- /dev/null +++ b/src/HeartTrackAPI/appsettings.json @@ -0,0 +1,12 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "ConnectionStrings": { + "HeartTrackAuthConnection": "Data Source=uca_HeartTrack.db" + } +} diff --git a/src/Model/Activity.cs b/src/Model/Activity.cs new file mode 100644 index 0000000..bdb3e79 --- /dev/null +++ b/src/Model/Activity.cs @@ -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 HeartRates { get; set; } = new List(); + + 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 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")}."; + } + } \ No newline at end of file diff --git a/src/Model/Athlete.cs b/src/Model/Athlete.cs new file mode 100644 index 0000000..fa04950 --- /dev/null +++ b/src/Model/Athlete.cs @@ -0,0 +1,9 @@ +namespace Model; + +public class Athlete : Role +{ + public override bool CheckAdd(User user) + { + return user.Role is Athlete; + } +} \ No newline at end of file diff --git a/src/Model/Coach.cs b/src/Model/Coach.cs new file mode 100644 index 0000000..1bd22bb --- /dev/null +++ b/src/Model/Coach.cs @@ -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"; + } +} \ No newline at end of file diff --git a/src/Model/DataSource.cs b/src/Model/DataSource.cs new file mode 100644 index 0000000..e073dba --- /dev/null +++ b/src/Model/DataSource.cs @@ -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 Activities { get; set; } = new List(); + public ICollection Athletes { get; set; } + + public DataSource(int id, string type, string model, float precision, ICollection athletes, ICollection? activities) + { + Id = id; + Type = type; + Model = model; + Precision = precision; + Athletes = athletes; + Activities = activities; + } + public DataSource(string type, string model, float precision, ICollection athletes, ICollection? activities) + : this(0, type, model, precision, athletes, activities) + {} + + public override string ToString() + { + return $"DataSource #{Id}: {Type} {Model} with a precision of {Precision}"; + } +} \ No newline at end of file diff --git a/src/Model/EnumMappeur.cs b/src/Model/EnumMappeur.cs new file mode 100644 index 0000000..b939ee9 --- /dev/null +++ b/src/Model/EnumMappeur.cs @@ -0,0 +1,24 @@ +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, + "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, + "ByIsCoach" => Shared.AthleteOrderCriteria.ByIsCoach, + _ => Shared.AthleteOrderCriteria.None + }; + } +} \ No newline at end of file diff --git a/src/Model/HeartRate.cs b/src/Model/HeartRate.cs new file mode 100644 index 0000000..ebf7cd7 --- /dev/null +++ b/src/Model/HeartRate.cs @@ -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"; + } +} \ No newline at end of file diff --git a/src/Model/LargeImage.cs b/src/Model/LargeImage.cs new file mode 100644 index 0000000..9f28c59 --- /dev/null +++ b/src/Model/LargeImage.cs @@ -0,0 +1,25 @@ +namespace Model; + +public class LargeImage : IEquatable +{ + 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(); +} diff --git a/src/Model/Manager/IDataManager.cs b/src/Model/Manager/IDataManager.cs new file mode 100644 index 0000000..6fc8532 --- /dev/null +++ b/src/Model/Manager/IDataManager.cs @@ -0,0 +1,9 @@ +using Model.Repository; + +namespace Model.Manager; + +public interface IDataManager +{ + IUserRepository UserRepo { get; } + IActivityRepository ActivityRepo { get; } +} diff --git a/src/Model/Model.csproj b/src/Model/Model.csproj new file mode 100644 index 0000000..ead9f5a --- /dev/null +++ b/src/Model/Model.csproj @@ -0,0 +1,18 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + diff --git a/src/Model/Notification.cs b/src/Model/Notification.cs new file mode 100644 index 0000000..fae442e --- /dev/null +++ b/src/Model/Notification.cs @@ -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(){} + +} \ No newline at end of file diff --git a/src/Model/RelationshipRequest.cs b/src/Model/RelationshipRequest.cs new file mode 100644 index 0000000..0889092 --- /dev/null +++ b/src/Model/RelationshipRequest.cs @@ -0,0 +1,9 @@ +namespace Model; + +public class RelationshipRequest // : Observable +{ + public int Id { get ; set ; } + public int FromUser { get ; set; } + public int ToUser { get; set ; } + public required string Status { get ; set; } +} \ No newline at end of file diff --git a/src/Model/Repository/IActivityRepository.cs b/src/Model/Repository/IActivityRepository.cs new file mode 100644 index 0000000..eab97da --- /dev/null +++ b/src/Model/Repository/IActivityRepository.cs @@ -0,0 +1,15 @@ +using Shared; + +namespace Model.Repository; + +public interface IActivityRepository +{ + public Task?> GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending = false); + public Task GetActivityByIdAsync(int id); + public Task AddActivity(Activity activity); + public Task UpdateActivity(int id, Activity activity); + public Task DeleteActivity(int id); + public Task GetNbItems(); + public Task?> GetActivitiesByUser(int userId, int index, int count, ActivityOrderCriteria orderCriteria, bool descending= false); + public Task GetNbActivitiesByUser(int userId); +} \ No newline at end of file diff --git a/src/Model/Repository/IUserRepository.cs b/src/Model/Repository/IUserRepository.cs new file mode 100644 index 0000000..dddc19d --- /dev/null +++ b/src/Model/Repository/IUserRepository.cs @@ -0,0 +1,15 @@ +using Shared; + +namespace Model.Repository; + +public interface IUserRepository : IGenericRepository +{ + public Task?> GetUsers(int index, int count, AthleteOrderCriteria? criteria , bool descending = false); + public Task AddFriend(User user, User friend); + public Task RemoveFriend(User user, User friend); + public Task?> GetFriends(User user, int index, int count, AthleteOrderCriteria? criteria, bool descending = false); + public Task GetNbFriends(User user); + public Task?> GetAllAthletes(int index, int count, AthleteOrderCriteria? criteria, bool descending = false); + public Task?> GetAllCoaches(int index, int count, AthleteOrderCriteria? criteria, bool descending = false); + +} \ No newline at end of file diff --git a/src/Model/Role.cs b/src/Model/Role.cs new file mode 100644 index 0000000..5353ea7 --- /dev/null +++ b/src/Model/Role.cs @@ -0,0 +1,42 @@ +namespace Model; + +public abstract class Role +{ + protected List UsersList { get; set; } = []; + protected List UsersRequests { get; set; } = []; + protected List TrainingList { get; set; } = []; + public abstract bool CheckAdd(User user); + + public bool AddUser(User user) + { + if (!CheckAdd(user)) return false; + UsersList.Add(user); + return true; + } + + public bool RemoveUser(User user) + { + return UsersList.Remove(user); + } + + public void AddTraining(Training training) + { + TrainingList.Add(training); + } + + public bool RemoveTraining(Training training) + { + return TrainingList.Remove(training); + } + + public void AddUserRequest(RelationshipRequest request) + { + UsersRequests.Add(request); + } + + public bool RemoveUserRequest(RelationshipRequest request) + { + return UsersRequests.Remove(request); + + } +} \ No newline at end of file diff --git a/src/Model/Training.cs b/src/Model/Training.cs new file mode 100644 index 0000000..53573af --- /dev/null +++ b/src/Model/Training.cs @@ -0,0 +1,7 @@ +namespace Model; + +public class Training +{ + + +} \ No newline at end of file diff --git a/src/Model/User.cs b/src/Model/User.cs new file mode 100644 index 0000000..3a8acd6 --- /dev/null +++ b/src/Model/User.cs @@ -0,0 +1,42 @@ +namespace Model; + +public class User +{ + public int Id { get; set; } + public string Username { get; set; } + public string ProfilePicture { get; set; } = ""; + public string LastName { get; set; } + public string FirstName { get; set; } + public string Email { get; set; } + public string? MotDePasse { get; set; } + public string Sexe { get; set; } + public float Lenght { get; set; } + public float Weight { get; set; } + public DateTime DateOfBirth { get; set; } + public Role Role { get; set; } + + public LargeImage Image { get; set; } = new LargeImage(""); + + public List Notifications { get; set; } = new List(); + public List Activities { get; set; } = new List(); + public List Users { get; set; } = new List(); + public List DataSources { get; set; } = new List(); + + public User( string username, string profilePicture, string nom, string prenom, string email, string motDePasse, string sexe, float taille, float poids, DateTime dateNaissance, Role role) + { + Username = username; + ProfilePicture = profilePicture; + LastName = nom; + FirstName = prenom; + Email = email; + MotDePasse = motDePasse; + Sexe = sexe; + Lenght = taille; + Weight = poids; + DateOfBirth = dateNaissance; + Role = role; + } + + public User(){} + +} \ No newline at end of file diff --git a/src/Model2Entities/ActivityRepository.cs b/src/Model2Entities/ActivityRepository.cs new file mode 100644 index 0000000..d3ba2da --- /dev/null +++ b/src/Model2Entities/ActivityRepository.cs @@ -0,0 +1,175 @@ +using Model; +using Model.Repository; +using Shared; +using Model.Manager; +using Microsoft.Extensions.Logging; +using Entities; +using EFMappers; +using Microsoft.EntityFrameworkCore; + +namespace Model2Entities; + +public partial class DbDataManager : IDataManager +{ + public class ActivityRepository : IActivityRepository + { + private readonly DbDataManager _dataManager; + private readonly ILogger _logger; + public ActivityRepository(DbDataManager dbDataManager, ILogger logger) + { + this._dataManager = dbDataManager; + this._logger = logger; + } + + public async Task> GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending = false) + { + _logger.LogInformation($"GetActivities with index {index} and count {count}", index, count); + _logger.LogInformation($"GetActivities with criteria {criteria} and descending {descending}", criteria, descending); + + var activities = _dataManager.DbContext.ActivitiesSet + .IncludeStandardProperties().GetItemsWithFilterAndOrdering(b => true, index, count, criteria, descending).ToModels(); + + _logger.LogInformation($"Retrieved {activities.Count()} activities"); + return await Task.FromResult(activities); + } + + public async Task GetActivityByIdAsync(int id) + { + _logger.LogInformation($"GetActivityByIdAsync with id {id}", id); + + var activityEntity = await _dataManager.DbContext.ActivitiesSet.IncludeStandardProperties().SingleOrDefaultAsync(a => a.IdActivity == id); + var activity = activityEntity != null ? activityEntity.ToModel() : null; + + if (activity != null) + _logger.LogInformation($"Retrieved activity with ID {id}"); + else + _logger.LogWarning($"No activity found with ID {id}"); + + return await Task.FromResult(activity); + } + + public async Task AddActivity(Activity activity) + { + try + { + _logger.LogInformation("Adding new activity"); + var addedActivity = (await _dataManager.DbContext.AddItem(activity.ToEntity()))?.ToModel(); + if (addedActivity != null) + _logger.LogInformation($"Added activity with ID {addedActivity.Id}"); + else + _logger.LogError("Failed to add activity"); + return await Task.FromResult(addedActivity); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occurred while adding activity"); + throw; + } + } + + public async Task UpdateActivity(int id, Activity activity) + { + try + { + _logger.LogInformation($"Updating activity with ID {id}"); + var updatedActivity = await _dataManager.DbContext.UpdateItem(id, activity, (activity, entity) => + { + entity.Type = activity.Type; + entity.Date = DateOnly.FromDateTime(activity.Date); + entity.StartTime = TimeOnly.FromDateTime(activity.StartTime); + entity.EndTime = TimeOnly.FromDateTime(activity.EndTime); + entity.EffortFelt = activity.Effort; + entity.Variability = activity.Variability; + entity.Variance = activity.Variance; + entity.StandardDeviation = activity.StandardDeviation; + entity.Average = activity.Average; + entity.Maximum = activity.Maximum; + entity.Minimum = activity.Minimum; + entity.AverageTemperature = activity.AverageTemperature; + entity.HasAutoPause = activity.HasAutoPause; + }); + if (updatedActivity != null) + { + _logger.LogInformation($"Updated activity with ID {id}"); + return await Task.FromResult(updatedActivity.ToModel()); + } + else + { + _logger.LogError($"Failed to update activity with ID {id}"); + return await Task.FromResult(null); + } + } + catch (Exception ex) + { + _logger.LogError(ex, $"Error occurred while updating activity with ID {id}"); + throw; + } + } + + public async Task DeleteActivity(int id) + { + try + { + _logger.LogInformation($"Deleting activity with ID {id}"); + var isDeleted = await _dataManager.DbContext.DeleteItem(id); + if (isDeleted) + _logger.LogInformation($"Deleted activity with ID {id}"); + else + _logger.LogWarning($"No activity found with ID {id}"); + return await Task.FromResult(isDeleted); + } + catch (Exception ex) + { + _logger.LogError(ex, $"Error occurred while deleting activity with ID {id}"); + throw; + } + } + + public async Task GetNbItems() + { + try + { + _logger.LogInformation("Getting the total number of activities"); + var count = await _dataManager.DbContext.ActivitiesSet.CountAsync(); + _logger.LogInformation($"Total number of activities: {count}"); + return await Task.FromResult(count); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occurred while getting the total number of activities"); + throw; + } + } + + public Task> GetActivitiesByUser(int userId, int index, int count, ActivityOrderCriteria criteria, bool descending = false) + { + try { + _logger.LogInformation($"Getting activities for user with ID {userId}"); + var activities = _dataManager.DbContext.ActivitiesSet + .IncludeStandardProperties().GetItemsWithFilterAndOrdering(b => b.AthleteId == userId, index, count, criteria, descending).ToModels(); + _logger.LogInformation($"Retrieved {activities.Count()} activities for user with ID {userId}"); + return Task.FromResult(activities); + } + catch (Exception ex) + { + _logger.LogError(ex, $"Error occurred while getting activities for user with ID {userId}"); + throw; + } + } + + public Task GetNbActivitiesByUser(int userId) + { + try { + _logger.LogInformation($"Getting the total number of activities for user with ID {userId}"); + var count = _dataManager.DbContext.ActivitiesSet.Count(b => b.AthleteId == userId); + _logger.LogInformation($"Total number of activities for user with ID {userId}: {count}"); + return Task.FromResult(count); + } + catch (Exception ex) + { + _logger.LogError(ex, $"Error occurred while getting the total number of activities for user with ID {userId}"); + throw; + } + } + } +} \ No newline at end of file diff --git a/src/Model2Entities/DbDataManager.cs b/src/Model2Entities/DbDataManager.cs new file mode 100644 index 0000000..bf1e4fd --- /dev/null +++ b/src/Model2Entities/DbDataManager.cs @@ -0,0 +1,38 @@ +using DbContextLib; +using EFMappers; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Model.Manager; +using Model.Repository; + +namespace Model2Entities; + +public partial class DbDataManager: IDataManager +{ + public IActivityRepository ActivityRepo { get; } + public IUserRepository UserRepo { get; } + protected HeartTrackContext DbContext { get; } + + protected readonly ILogger _logger = new Logger(new LoggerFactory()); + + // mettre si pb lors d'une requete si rollback ou pas + public DbDataManager(HeartTrackContext dbContext) + { + DbContext = dbContext; + ActivityRepo = new ActivityRepository(this, _logger); + UserRepo = new UserRepository(this, _logger); + ActivityMapper.Reset(); + // Faire pour les autres reset() des autres mappers + } + + public DbDataManager(string dbPlatformPath) + : this(new HeartTrackContext(dbPlatformPath)) + {} + + public DbDataManager() + { + DbContext = new HeartTrackContext(); + ActivityRepo = new ActivityRepository(this, _logger); + UserRepo= new UserRepository(this, _logger); + } +} diff --git a/src/Model2Entities/Extension.cs b/src/Model2Entities/Extension.cs new file mode 100644 index 0000000..d7341ec --- /dev/null +++ b/src/Model2Entities/Extension.cs @@ -0,0 +1,213 @@ +using DbContextLib; +using Entities; +using Microsoft.EntityFrameworkCore; +using Model; + +namespace Model2Entities; + + +public static class Extensions +{ + internal static async Task AddItem(this HeartTrackContext context, T? item) where T :class + { + if(item == null || context.Set().Contains(item)) + { + return await Task.FromResult(null); + } + var entry = context.Set().Add(item); + try { + await context.SaveChangesAsync(); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message, ex.InnerException, ex.StackTrace); + } + + return await Task.FromResult(entry.Entity); + } + + internal static async Task DeleteItem(this HeartTrackContext context, int? id) where T:class + { + var item = await context.Set().FindAsync(id); + if(item == null) return await Task.FromResult(false); + context.Set().Remove(item); + await context.SaveChangesAsync(); + return await Task.FromResult(true); + } + + public static async Task UpdateItem(this HeartTrackContext context, int? id, T? newItem, Action updateAction) where T : class where U: class + { + var existingT = await context.Set().FindAsync(id); + if (existingT != null && newItem != null) + { + // Appliquer les mises à jour sur l'objet existant en utilisant l'action passée en paramètre + updateAction(newItem, existingT); + + // Marquer l'objet comme modifié dans le contexte + context.Update(existingT); + + // Enregistrer les modifications dans la base de données + await context.SaveChangesAsync(); + return existingT; + } + return Task.FromResult(null).Result; + + } + + + public static IEnumerable GetItemsWithFilterAndOrdering(this IEnumerable list, Func filter, int index, int count, Enum? orderCriterium, bool descending = false ) where T : class + { + var filteredList = list.Where(filter); + + if(orderCriterium != null && orderCriterium.ToString() != "None") + { + filteredList = filteredList.OrderByCriteria(orderCriterium, descending); + } + + return filteredList + .Skip(index * count) + .Take(count); + } + + public static IOrderedEnumerable OrderByCriteria(this IEnumerable list, Enum orderCriterium, bool descending = false ) where T : class + { + var orderCriteriumString = orderCriterium.ToString(); + if (orderCriteriumString.StartsWith("By")) + { + orderCriteriumString = orderCriteriumString.Substring(2); + } + var propertyInfo = typeof(T).GetProperty(orderCriteriumString); + if (propertyInfo == null) + { + throw new ArgumentException($"No property {orderCriterium} in type {typeof(T)}"); + } + + return descending ? list.OrderByDescending(x => propertyInfo.GetValue(x)) : list.OrderBy(x => propertyInfo.GetValue(x)); + } + public static IQueryable IncludeAll(this HeartTrackContext dbContext, IQueryable query) where TEntity : class + { + var entityType = dbContext.Model.FindEntityType(typeof(TEntity)); + foreach (var navigation in entityType.GetNavigations()) + { + query = query.Include(navigation.Name); + } + return query; + } + public static IQueryable IncludeStandardProperties(this IQueryable query) + { + return query.Include(a => a.HeartRates) + .Include(a => a.Athlete) + .Include(a => a.DataSource); + } + public static IQueryable IncludeStandardProperties(this IQueryable query) + { + return query.Include(a => a.DataSource) + .Include(a => a.Activities).ThenInclude(ac => ac.HeartRates).Include(ac => ac.Activities).ThenInclude(ac => ac.DataSource) + .Include(a => a.Image); + } + // public static Activity ToModel(this ActivityEntity entity) + // { + // return new Activity ( + // entity.IdActivity, + // entity.Type, + // new DateTime(entity.Date.Year, entity.Date.Month, entity.Date.Day), + // new DateTime().Add(entity.StartTime.ToTimeSpan()), // Utilisation de ToTimeSpan() pour obtenir la composante temps sans la date + // new DateTime().Add(entity.EndTime.ToTimeSpan()), + // entity.EffortFelt, + // entity.Variability, + // entity.Variance, + // entity.StandardDeviation, + // entity.Average, + // entity.Maximum, + // entity.Minimum, + // entity.AverageTemperature, + // entity.HasAutoPause + // ); + // } + + // public static ActivityEntity ToEntity(this Activity model) + // { + // return new ActivityEntity + // { + // IdActivity = model.Id, + // Type = model.Type, + // Date = DateOnly.FromDateTime(model.Date), + // StartTime = TimeOnly.FromDateTime(model.StartTime), + // EndTime = TimeOnly.FromDateTime(model.EndTime), + // EffortFelt = model.Effort, + // Variability = model.Variability, + // Variance = model.Variance, + // StandardDeviation = model.StandardDeviation, + // Average = model.Average, + // Maximum = model.Maximum, + // Minimum = model.Minimum, + // AverageTemperature = model.AverageTemperature, + // HasAutoPause = model.HasAutoPause + // }; + // } + + // public static IEnumerable ToModels(this IEnumerable entities) + // => entities.Select(a => a.ToModel()); + + // public static IEnumerable ToEntities(this IEnumerable models) + // => models.Select(a => a.ToEntity()); +} + +// using System; +// using Entities; +// using Models; +// using System.Collections.Generic; // Add missing namespace + +// namespace Model2Entities +// { +// public static class Extension +// { + + +// public static TEntity ToEntity(this T model) +// where TEntity : new() +// { +// return new TEntity +// { +// Id = model.Id, +// Title = model.Title, +// Author = model.Author, +// Isbn = model.Isbn +// }; +// } + +// public static IEnumerable ToEntities(this IEnumerable models) // Add missing type parameter +// where TEntity : new() // Add constraint for TEntity +// { +// return models.Select(m => m.ToEntity()); +// } + +// public static T ToModel(this TEntity myTEntity) // Add missing type parameter +// where T : new() // Add constraint for T +// { +// return new T(myTEntity.Id, myTEntity.Title, myTEntity.Author, myTEntity.Isbn); +// } + +// public static IEnumerable ToModels(this IEnumerable TsEntities) +// => TsEntities.Select(e => e.ToModel()); +// } +// { +// public static T ToEntity(this T model) +// => new TEntity +// { +// Id = model.Id, +// Title = model.Title, +// Author = model.Author, +// Isbn = model.Isbn +// }; + +// public static IEnumerable ToEntities(this IEnumerable models) +// => models.Select(m => m.ToEntity()); + +// public static T ToModel(this T myTEntity) +// => new T(myTEntity.Id, myTEntity.Title, myTEntity.Author, myTEntity.Isbn); + +// public static IEnumerable ToModels(this IEnumerable TsEntities) +// => TsEntities.Select(e => e.ToModel()); +// } +// } \ No newline at end of file diff --git a/src/Model2Entities/Model2Entities.csproj b/src/Model2Entities/Model2Entities.csproj new file mode 100644 index 0000000..d1f7751 --- /dev/null +++ b/src/Model2Entities/Model2Entities.csproj @@ -0,0 +1,16 @@ + + + + net8.0 + enable + enable + + + + + + + + + + diff --git a/src/Model2Entities/UserRepository.cs b/src/Model2Entities/UserRepository.cs new file mode 100644 index 0000000..09d2cf2 --- /dev/null +++ b/src/Model2Entities/UserRepository.cs @@ -0,0 +1,226 @@ +using Microsoft.Extensions.Logging; +using Model; +using Model.Repository; +using Shared; +using EFMappers; +using Entities; +using Microsoft.EntityFrameworkCore; + +namespace Model2Entities; + +public partial class DbDataManager +{ + public class UserRepository : IUserRepository + { + private readonly DbDataManager _dataManager; + private readonly ILogger _logger; + + public UserRepository(DbDataManager dbDataManager, ILogger logger) + { + _dataManager = dbDataManager; + _logger = logger; + } + + public async Task> GetItems(int index, int count, string? orderingProperty = null, + bool descending = false) + => await GetUsers(index, count, this.ToEnum(orderingProperty), descending); + + public async Task> GetUsers(int index, int count, + AthleteOrderCriteria? orderingProperty = null, bool descending = false) + { + + _logger.LogInformation($"GetItems with index {index} and count {count}", index, count); + _logger.LogInformation($"GetItems with orderingProperty {orderingProperty} and descending {descending}", + orderingProperty, descending); + var users = _dataManager.DbContext.AthletesSet.IncludeStandardProperties().GetItemsWithFilterAndOrdering(b => true, index, count, + orderingProperty != AthleteOrderCriteria.None ? orderingProperty : null, descending).ToModels(); + _logger.LogInformation($"Retrieved {users.Count()} users"); + return await Task.FromResult(users); + + } + + public async Task GetItemById(int id) + { + + _logger.LogInformation($"GetItemById with id {id}", id); + var userEntity = await _dataManager.DbContext.AthletesSet.IncludeStandardProperties() + .SingleOrDefaultAsync(a => a.IdAthlete == id); + var user = userEntity != null ? userEntity.ToModel() : null; + if (user != null) + _logger.LogInformation($"Retrieved user with ID {id}"); + else + _logger.LogWarning($"No user found with ID {id}"); + return await Task.FromResult(user); + + } + + public async Task UpdateItem(int oldItem, User newItem) + { + _logger.LogInformation($"UpdateItem with id {oldItem}", oldItem); + + var originalEntity = _dataManager.DbContext.AthletesSet.Find(oldItem); + if (originalEntity == null) + { + _logger.LogWarning($"No user found with ID {oldItem}"); + return await Task.FromResult(null); + } + var originalEntry = _dataManager.DbContext.Entry(originalEntity); + var values = typeof(AthleteEntity).GetProperties().Where(ppty => ppty.Name != "IdAthlete") + .ToDictionary(ppty => ppty.Name, ppty => ppty.GetValue(newItem.ToEntity())); + originalEntry.CurrentValues.SetValues(values); + _dataManager.DbContext.AthletesSet.Attach(originalEntity); + _dataManager.DbContext.Entry(originalEntity).State = EntityState.Modified; + _dataManager.DbContext.SaveChanges(); + var updatedUser = originalEntity.ToModel(); + if (updatedUser != null) + _logger.LogInformation($"Updated user with ID {oldItem}"); + else + _logger.LogWarning($"No user found with ID {oldItem}"); + return await Task.FromResult(updatedUser); + } + + public async Task AddItem(User item) + { + + _logger.LogInformation("Adding new user"); + var addedUser = (await _dataManager.DbContext.AddItem(item.ToEntity()))?.ToModel(); + if (addedUser != null) + _logger.LogInformation($"Added user with ID {addedUser.Id}"); + else + _logger.LogError("Failed to add user"); + return await Task.FromResult(addedUser); + + } + + public async Task DeleteItem(int item) + { + + _logger.LogInformation($"DeleteItem with id {item}", item); + var deleted = await _dataManager.DbContext.DeleteItem(item); + if (deleted) + _logger.LogInformation($"Deleted user with ID {item}"); + else + _logger.LogWarning($"No user found with ID {item}"); + return await Task.FromResult(deleted); + + } + + public async Task GetNbItems() + { + + _logger.LogInformation("GetNbItems"); + var nbItems = await _dataManager.DbContext.AthletesSet.CountAsync(); + _logger.LogInformation($"Retrieved {nbItems} users"); + return await Task.FromResult(nbItems); + } + + public async Task> GetAllAthletes(int index, int count, AthleteOrderCriteria? criteria, + bool descending = false) + { + + _logger.LogInformation($"GetAllAthletes with index {index} and count {count}", index, count); + _logger.LogInformation($"GetAllAthletes with criteria {criteria} and descending {descending}", criteria, + descending); + var athletes = _dataManager.DbContext.AthletesSet.IncludeStandardProperties() + .GetItemsWithFilterAndOrdering(a => a.IsCoach == false, index, count, + criteria != AthleteOrderCriteria.None ? criteria : null, descending).ToModels(); + _logger.LogInformation($"Retrieved {athletes.Count()} athletes"); + return await Task.FromResult(athletes); + } + + public async Task> GetAllCoaches(int index, int count, AthleteOrderCriteria? criteria, + bool descending = false) + { + + _logger.LogInformation($"GetAllCoaches with index {index} and count {count}", index, count); + _logger.LogInformation($"GetAllCoaches with criteria {criteria} and descending {descending}", criteria, + descending); + var coaches = _dataManager.DbContext.AthletesSet.IncludeStandardProperties() + .GetItemsWithFilterAndOrdering(a => a.IsCoach, index, count, + criteria != AthleteOrderCriteria.None ? criteria : null, descending).ToModels(); + _logger.LogInformation($"Retrieved {coaches.Count()} coaches"); + return await Task.FromResult(coaches); + + } + + public async Task AddFriend(User user, User friend) + { + _logger.LogInformation($"Attempting to add friend: User {user.Id} adding Friend {friend.Id}"); + var userEntity = _dataManager.DbContext.AthletesSet.IncludeStandardProperties().FirstOrDefault(a => a.IdAthlete == user.Id); + var friendEntity = _dataManager.DbContext.AthletesSet.IncludeStandardProperties().FirstOrDefault(a => a.IdAthlete == friend.Id); + if (userEntity == null || friendEntity == null) + { + _logger.LogWarning($"User or friend not found: User {user.Id}, Friend {friend.Id}"); + return false; + } + + if (userEntity.Followings.All(f => f.FollowingId != friend.Id)) + { + userEntity.Followings.Add(new FriendshipEntity + { FollowingId = friend.Id, FollowerId = user.Id, StartDate = DateTime.Now }); + await _dataManager.DbContext.SaveChangesAsync(); + _logger.LogInformation($"Successfully added friend: User {user.Id} added Friend {friend.Id}"); + return true; + } + + _logger.LogInformation($"Friendship already exists: User {user.Id} and Friend {friend.Id}"); + return false; + } + + public async Task RemoveFriend(User user, User friend) + { + _logger.LogInformation($"Attempting to remove friend: User {user.Id} removing Friend {friend.Id}"); + var userEntity = _dataManager.DbContext.AthletesSet.IncludeStandardProperties().FirstOrDefault(a => a.IdAthlete == user.Id); + var friendEntity = _dataManager.DbContext.AthletesSet.IncludeStandardProperties().FirstOrDefault(a => a.IdAthlete == friend.Id); + if (userEntity == null || friendEntity == null) + { + _logger.LogWarning($"User or friend not found: User {user.Id}, Friend {friend.Id}"); + return false; + } + + var friendship = userEntity.Followings.FirstOrDefault(f => f.FollowingId == friend.Id); + if (friendship != null) + { + userEntity.Followings.Remove(friendship); + await _dataManager.DbContext.SaveChangesAsync(); + _logger.LogInformation($"Successfully removed friend: User {user.Id} removed Friend {friend.Id}"); + return true; + } + + _logger.LogInformation($"Friendship does not exist: User {user.Id} and Friend {friend.Id}"); + return false; + } + + public Task> GetFriends(User user, int index, int count, AthleteOrderCriteria? criteria, + bool descending = false) + { + try + { + _logger.LogInformation($"GetFriends with index {index} and count {count}", index, count); + _logger.LogInformation($"GetFriends with criteria {criteria} and descending {descending}", criteria, + descending); + var friends = _dataManager.DbContext.AthletesSet.IncludeStandardProperties().Include(a => a.Followers).Include(a => a.Followings) + .GetItemsWithFilterAndOrdering(a => a.Followers.Any(f => f.FollowingId == user.Id), index, count, + criteria, descending).ToModels(); + _logger.LogInformation($"Retrieved {friends.Count()} friends"); + return Task.FromResult(friends); + } + catch (Exception ex) + { + _logger.LogError(ex.Message, ex.InnerException, ex.StackTrace); + return Task.FromResult>(new List()); + } + } + + public Task GetNbFriends(User user) + { + + _logger.LogInformation($"GetNbFriends with user {user}", user); + var nbFriends = _dataManager.DbContext.AthletesSet + .GetItemsWithFilterAndOrdering(a => a.IdAthlete == user.Id, 0, int.MaxValue, + AthleteOrderCriteria.None, false).First().Followings.Count(); + _logger.LogInformation($"Retrieved {nbFriends} friends"); + return Task.FromResult(nbFriends); + } + } +} \ No newline at end of file diff --git a/src/Shared/ActivityOrderCriteria.cs b/src/Shared/ActivityOrderCriteria.cs new file mode 100644 index 0000000..3a5fc31 --- /dev/null +++ b/src/Shared/ActivityOrderCriteria.cs @@ -0,0 +1,22 @@ +namespace Shared; + +public enum ActivityOrderCriteria +{ + None, + ByIdActivity, + ByType, + ByDate, + ByStartTime, + ByEndTime, + ByEffortFelt, + ByVariability, + ByVariance, + ByStandardDeviation, + ByAverage, + ByMaximum, + ByMinimum, + ByAverageTemperature, + ByHasAutoPause, + ByDataSourceId, + ByAthleteId +} \ No newline at end of file diff --git a/src/Shared/AthleteOrderCriteria.cs b/src/Shared/AthleteOrderCriteria.cs new file mode 100644 index 0000000..4bc54f0 --- /dev/null +++ b/src/Shared/AthleteOrderCriteria.cs @@ -0,0 +1,45 @@ +namespace Shared +{ + public enum AthleteOrderCriteria + { + None, + ByUsername, + ByFirstName, + ByLastName, + BySexe, + ByLenght, + ByWeight, + ByDateOfBirth, + ByEmail, + ByIsCoach + } + +} + + +/*public AthleteOrderCriteria MapToAthleteOrderCriteria(string orderingPropertyName) + { + switch (orderingPropertyName) + { + case nameof(User.Username): + return AthleteOrderCriteria.ByUsername; + case nameof(User.FirstName): + return AthleteOrderCriteria.ByFirstName; + case nameof(User.LastName): + return AthleteOrderCriteria.ByLastName; + case nameof(User.Sexe): + return AthleteOrderCriteria.BySexe; + case nameof(User.Length): + return AthleteOrderCriteria.ByLength; + case nameof(User.Weight): + return AthleteOrderCriteria.ByWeight; + case nameof(User.DateOfBirth): + return AthleteOrderCriteria.ByDateOfBirth; + case nameof(User.Email): + return AthleteOrderCriteria.ByEmail; + case nameof(User.IsCoach): + return AthleteOrderCriteria.ByIsCoach; + default: + return AthleteOrderCriteria.None; + } + }*/ \ No newline at end of file diff --git a/src/Shared/DataSourceOrderCriteria.cs b/src/Shared/DataSourceOrderCriteria.cs new file mode 100644 index 0000000..9e78721 --- /dev/null +++ b/src/Shared/DataSourceOrderCriteria.cs @@ -0,0 +1,10 @@ +namespace Shared; + +public enum DataSourceOrderCriteria +{ + None, + ByName, + ByDate, + ByType, + ByContent +} \ No newline at end of file diff --git a/src/Shared/Extension.cs b/src/Shared/Extension.cs new file mode 100644 index 0000000..d86ba4d --- /dev/null +++ b/src/Shared/Extension.cs @@ -0,0 +1,36 @@ +namespace Shared; + +public static class Extensions +{ + public static U ToU(this T t, GenericMapper mapper, Func func,Action? action = null) where U :class where T :class + { + var res = mapper.GetU(t); + if (res != null) return res; + + U u = func(t); + mapper.Add(t, u); + if(action != null) action(t, u); + return u; + } +// , Action action + public static T ToT(this U u, GenericMapper mapper, Func func,Action? action = null) where U :class where T :class + { + var result = mapper.GetT(u); + + if(result != null) return result; + + T t = func(u); + mapper.Add(t, u); + if(action != null) action(u, t); + + return t; + } + + public static void AddRange(this ICollection set, IEnumerable ts) + { + foreach(var t in ts) + { + set.Add(t); + } + } +} \ No newline at end of file diff --git a/src/Shared/GenericMappers.cs b/src/Shared/GenericMappers.cs new file mode 100644 index 0000000..aef882d --- /dev/null +++ b/src/Shared/GenericMappers.cs @@ -0,0 +1,34 @@ +namespace Shared; + +public class GenericMapper where T : class where U : class +{ + private HashSet> mapper = new HashSet>(); + public T? GetT(U u) + { + var found = mapper.Where(t => ReferenceEquals(t.Item2, u)); + if (found.Count() != 1) + { + return null; + } + return found.First().Item1; + } + public U? GetU(T t) + { + var found = mapper.Where(u => ReferenceEquals(u.Item1, t)); + if (found.Count() != 1) + { + return null; + } + return found.First().Item2; + } + public void Add(T model, U entity) + { + var tuple = new Tuple(model, entity); + mapper.Add(tuple); + } + + public void Reset() + { + mapper.Clear(); + } +} \ No newline at end of file diff --git a/src/Shared/HeartRateOrderCriteria.cs b/src/Shared/HeartRateOrderCriteria.cs new file mode 100644 index 0000000..0f21f04 --- /dev/null +++ b/src/Shared/HeartRateOrderCriteria.cs @@ -0,0 +1,10 @@ +namespace Shared; + +public enum HeartRateOrderCriteria +{ + None, + ByDate, + ByValue, + ByActivity, + ByUser +} \ No newline at end of file diff --git a/src/Shared/IGenericRepository.cs b/src/Shared/IGenericRepository.cs new file mode 100644 index 0000000..372d79b --- /dev/null +++ b/src/Shared/IGenericRepository.cs @@ -0,0 +1,12 @@ +namespace Shared; + +public interface IGenericRepository +{ + Task> GetItems(int index, int count, string? orderingProperty = null, bool descending = false); + Task GetItemById(int id); + Task UpdateItem(int oldItem, T newItem); + Task AddItem(T item); + Task DeleteItem(int item); + Task GetNbItems(); + +} \ No newline at end of file diff --git a/src/Shared/NotificationOrderCriteria.cs b/src/Shared/NotificationOrderCriteria.cs new file mode 100644 index 0000000..3315691 --- /dev/null +++ b/src/Shared/NotificationOrderCriteria.cs @@ -0,0 +1,11 @@ +namespace Shared; + +public enum NotificationOrderCriteria +{ + None, + ByDate, + ByType, + BySender, + ByReceiver, + ByContent +} \ No newline at end of file diff --git a/src/Shared/Shared.csproj b/src/Shared/Shared.csproj new file mode 100644 index 0000000..34786a9 --- /dev/null +++ b/src/Shared/Shared.csproj @@ -0,0 +1,13 @@ + + + + + + + + net8.0 + enable + enable + + + diff --git a/src/Shared/StatisticOrderCriteria.cs b/src/Shared/StatisticOrderCriteria.cs new file mode 100644 index 0000000..3968c7e --- /dev/null +++ b/src/Shared/StatisticOrderCriteria.cs @@ -0,0 +1,10 @@ +namespace Shared; + +public enum StatisticOrderCriteria +{ + None, + ByDate, + ByType, + ByValue, + ByUser +} \ No newline at end of file diff --git a/src/Shared/TrainingOrderCriteria.cs b/src/Shared/TrainingOrderCriteria.cs new file mode 100644 index 0000000..4f17bca --- /dev/null +++ b/src/Shared/TrainingOrderCriteria.cs @@ -0,0 +1,12 @@ +namespace Shared; + +public enum TrainingOrderCriteria +{ + None, + ByDate, + ByType, + ByDuration, + ByDistance, + ByCalories, + ByUser +} \ No newline at end of file diff --git a/src/StubAPI/ActivityService.cs b/src/StubAPI/ActivityService.cs new file mode 100644 index 0000000..fe08608 --- /dev/null +++ b/src/StubAPI/ActivityService.cs @@ -0,0 +1,78 @@ +using Model; +using Model.Repository; +using Shared; + +namespace StubAPI; + +public class ActivityService: IActivityRepository +{ + private List _activities = new List( + new Activity[] + { + new Activity + { + Id = 1, + Type = "Running", + Date = new DateTime(2021, 10, 10), + StartTime = new DateTime(2021, 10, 10, 10, 0, 0), + EndTime = new DateTime(2021, 10, 10, 11, 0, 0), + Effort = 3, + Variability = 0.5f, + Variance = 0.5f, + StandardDeviation = 0.5f, + Average = 5.0f, + Maximum = 10, + Minimum = 0, + AverageTemperature = 20.0f, + HasAutoPause = false, + Athlete = new User + { + Id = 3, Username = "Athlete3", ProfilePicture = "https://plus.unsplash.com/premium_photo-1705091981693-6006f8a20479?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", FirstName = "First3", LastName = "Last3", + Sexe = "M", Lenght = 190, Weight = 80, DateOfBirth = new DateTime(1994, 3, 3), Email = "ath@ex.fr", + Role = new Athlete() + } + }, + } + ); + + public async Task?> GetActivities(int index, int count, ActivityOrderCriteria criteria, bool descending = false) + => await Task.FromResult(_activities.GetItemsWithFilterAndOrdering(c=>true,index, count,criteria != ActivityOrderCriteria.None ? criteria: null , descending)); + + public Task GetActivityByIdAsync(int id) + { + return Task.FromResult(_activities.FirstOrDefault(s => s.Id == id)); + } + + public Task AddActivity(Activity activity) + => _activities.AddItem(activity); + + + public async Task UpdateActivity(int id, Activity activity) + { + var oldActivity = _activities.FirstOrDefault(s => s.Id == id); + if (oldActivity == null) return null; + return await _activities.UpdateItem(oldActivity, activity); + } + + public Task DeleteActivity(int id) + { + var activity = _activities.FirstOrDefault(s => s.Id == id); + if (activity == null) return Task.FromResult(false); + return _activities.DeleteItem(activity); + } + + public Task GetNbItems() + => Task.FromResult(_activities.Count); + + public async Task?> GetActivitiesByUser(int userId, int index, int count, ActivityOrderCriteria criteria, bool descending = false) + { + var activities = _activities.GetItemsWithFilterAndOrdering(a => a.Athlete.Id == userId, index, count, + criteria != ActivityOrderCriteria.None ? criteria : null, descending); + return await Task.FromResult(activities); + } + + public Task GetNbActivitiesByUser(int userId) + { + return Task.FromResult(_activities.Count(a => a.Athlete.Id == userId)); + } +} \ No newline at end of file diff --git a/src/StubAPI/AthleteService.cs b/src/StubAPI/AthleteService.cs new file mode 100644 index 0000000..4d8bf29 --- /dev/null +++ b/src/StubAPI/AthleteService.cs @@ -0,0 +1,121 @@ +using Model; +using Model.Repository; +using Shared; + +namespace StubAPI; + +public class UserService : IUserRepository +{ + private List athletes = + [ + new User + { + Id = 1, Username = "DoeDoe", ProfilePicture = "https://images.unsplash.com/photo-1682687982134-2ac563b2228b?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", FirstName = "John", LastName = "Doe", + Sexe = "M", Lenght = 180, Weight = 70, DateOfBirth = new DateTime(1990, 1, 1), + Email = "john.doe@example.com", Role = new Athlete() + }, + + new User + { + Id = 2, Username = "SmithSmith", ProfilePicture = "https://images.unsplash.com/photo-1709507779917-242b560288be?q=80&w=2080&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", FirstName = "Jane", LastName = "Smith", + Sexe = "F", Lenght = 170, Weight = 60, DateOfBirth = new DateTime(1992, 2, 2), + Email = "athlete2@example.com", Role = new Coach() + }, + + new User + { + Id = 3, Username = "Athlete3", ProfilePicture = "https://plus.unsplash.com/premium_photo-1705091981693-6006f8a20479?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", FirstName = "First3", LastName = "Last3", + Sexe = "M", Lenght = 190, Weight = 80, DateOfBirth = new DateTime(1994, 3, 3), Email = "ath@ex.fr", + Role = new Athlete() + } + + ]; + + public async Task> GetUsers(int index, int count, AthleteOrderCriteria? orderingProperty = null, bool descending = false) + => athletes.GetItemsWithFilterAndOrdering(c=>true,index, count,orderingProperty != AthleteOrderCriteria.None ? orderingProperty: null , descending); + + public async Task AddFriend(User user, User friend) + { + if (user == null || friend == null) + { + return false; + } + + if (user.Users.Contains(friend)) + { + return false; + } + + user.Users.Add(friend); + + return true; + } + + public async Task RemoveFriend(User user, User friend) + { + if (user == null || friend == null) + { + return false; + } + + if (!user.Users.Contains(friend)) + { + return false; + } + + user.Users.Remove(friend); + + return true; + } + + public async Task?>? GetFriends(User user, int index, int count, AthleteOrderCriteria? criteria, bool descending = false) + =>await Task.FromResult(athletes.FirstOrDefault(s => s.Id == user.Id)?.Users.GetItemsWithFilterAndOrdering(c=>true,index, count,criteria, descending)); + + public Task GetNbFriends(User user) + { + return Task.FromResult(athletes.FirstOrDefault(s => s.Id == user.Id)?.Users.Count ?? 0); + } + + public async Task> GetItems(int index, int count, string? orderingProperty = null, + bool descending = false) + =>await GetUsers(index, count, this.ToEnum(orderingProperty), descending); + + + public async Task GetItemById(int id) + =>await Task.FromResult(athletes.FirstOrDefault(s => s.Id == id)); + + + public async Task AddItem(User user) + { + return await athletes.AddItem(user); + } + + public async Task UpdateItem(int id, User user) + { + var oldUser = athletes.FirstOrDefault(s => s.Id == id); + if (oldUser == null) return null; + return await athletes.UpdateItem(oldUser, user); + } + + public async Task DeleteItem(int id) + { + var user = athletes.FirstOrDefault(s => s.Id == id); + if (user == null) return false; + return await athletes.DeleteItem(user); + } + + public async Task GetNbItems() + { + return await Task.FromResult(athletes.Count); + } + + public async Task> GetAllAthletes(int index, int count, AthleteOrderCriteria? criteria, bool descending = false) + { + return await Task.FromResult(athletes.GetItemsWithFilterAndOrdering(c=>c.Role is Athlete,index, count,criteria, descending)); + } + + public async Task> GetAllCoaches(int index, int count, AthleteOrderCriteria? criteria, bool descending = false) + { + return await Task.FromResult(athletes.GetItemsWithFilterAndOrdering(c=>c.Role is Coach,index, count,criteria, descending)); + } +} \ No newline at end of file diff --git a/src/StubAPI/Extensions.cs b/src/StubAPI/Extensions.cs new file mode 100644 index 0000000..af6f004 --- /dev/null +++ b/src/StubAPI/Extensions.cs @@ -0,0 +1,72 @@ +namespace StubAPI; + + +public static class Extensions +{ + internal static Task AddItem(this IList collection, T? item) + { + if(item == null || collection.Contains(item)) + { + return Task.FromResult(default(T)); + } + collection.Add(item); + return Task.FromResult(item); + } + + internal static Task DeleteItem(this IList collection, T? item) + { + if(item == null) + { + return Task.FromResult(false); + } + bool result = collection.Remove(item!); + return Task.FromResult(result); + } + + internal static Task UpdateItem(this IList collection, T? oldItem, T? newItem) + { + if(oldItem == null || newItem == null) return Task.FromResult(default(T)); + + if(!collection.Contains(oldItem)) + { + return Task.FromResult(default(T)); + } + + collection.Remove(oldItem!); + collection.Add(newItem!); + return Task.FromResult(newItem); + } + + public static IEnumerable GetItemsWithFilterAndOrdering(this IEnumerable list, Func filter, int index, int count, Enum? orderCriterium, bool descending = false ) where T : class + { + IEnumerable query = list; + + query = query.Where(filter); + + if(orderCriterium != null) + { + query = query.OrderByCriteria(orderCriterium, descending); + } + return query + .Skip(index * count) + .Take(count); + } + + public static IOrderedEnumerable OrderByCriteria(this IEnumerable list, Enum orderCriterium, bool descending = false ) where T : class + { + var orderCriteriumString = orderCriterium.ToString(); + if (orderCriteriumString.StartsWith("By")) + { + orderCriteriumString = orderCriteriumString.Substring(2); + } + var propertyInfo = typeof(T).GetProperty(orderCriteriumString); + if (propertyInfo == null) + { + throw new ArgumentException($"No property {orderCriterium} in type {typeof(T)}"); + } + + return descending ? list.OrderByDescending(x => propertyInfo.GetValue(x)) : list.OrderBy(x => propertyInfo.GetValue(x)); + } + + +} \ No newline at end of file diff --git a/src/StubAPI/StubAPI.csproj b/src/StubAPI/StubAPI.csproj new file mode 100644 index 0000000..eea9fb7 --- /dev/null +++ b/src/StubAPI/StubAPI.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + \ No newline at end of file diff --git a/src/StubAPI/StubData.cs b/src/StubAPI/StubData.cs new file mode 100644 index 0000000..bceb496 --- /dev/null +++ b/src/StubAPI/StubData.cs @@ -0,0 +1,16 @@ +using Model.Manager; +using Model.Repository; + +namespace StubAPI; + +public class StubData : IDataManager +{ + public IUserRepository UserRepo { get; } + public IActivityRepository ActivityRepo { get; } + + public StubData() + { + UserRepo = new UserService(); + ActivityRepo = new ActivityService(); + } +} \ No newline at end of file diff --git a/src/StubApi/AthleteStubDto.cs b/src/StubApi/AthleteStubDto.cs new file mode 100644 index 0000000..5725d31 --- /dev/null +++ b/src/StubApi/AthleteStubDto.cs @@ -0,0 +1,4 @@ +// using Shared; + +// namespace + diff --git a/src/StubbedContextLib/ActivityStubbedContext.cs b/src/StubbedContextLib/ActivityStubbedContext.cs index 11f8457..7506778 100644 --- a/src/StubbedContextLib/ActivityStubbedContext.cs +++ b/src/StubbedContextLib/ActivityStubbedContext.cs @@ -1,31 +1,51 @@ +//----------------------------------------------------------------------- +// FILENAME: ActivityStubbedContext.cs +// PROJECT: StubbedContextLib +// SOLUTION: HeartTrack +// DATE CREATED: 22/02/2024 +// AUTHOR: Antoine PEREDERII +//----------------------------------------------------------------------- + using DbContextLib; using Entities; using Microsoft.EntityFrameworkCore; -namespace StubbedContextLib; - -public class ActivityStubbedContext : LibraryContext +namespace StubbedContextLib { - public ActivityStubbedContext() - :base() - { } + /// + /// Represents a stubbed context for activities. + /// + public class ActivityStubbedContext : HeartTrackContext + { + /// + /// Initializes a new instance of the class. + /// + public ActivityStubbedContext() : base() { } - public ActivityStubbedContext(DbContextOptions options) - :base(options) - { } + /// + /// Initializes a new instance of the class with the specified options. + /// + /// The options for the context. + public ActivityStubbedContext(DbContextOptions options) : base(options) { } - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - - modelBuilder.Entity().HasData( - new ActivityEntity { IdActivity = 1, Type = "Running", Date = new DateTime(), StartTime = new DateTime(), EndTime = new DateTime(), EffortFelt = 5, Variability = 0.5f, Variance = 0.5f, StandardDeviation = 0.5f, Average = 0.5f, Maximum = 0, Minimum = 0, AverageTemperature = 20.0f, HasAutoPause = false }, - new ActivityEntity { IdActivity = 2, Type = "Cycling", Date = new DateTime(), StartTime = new DateTime(), EndTime = new DateTime(), EffortFelt = 5, Variability = 0.5f, Variance = 0.5f, StandardDeviation = 0.5f, Average = 0.5f, Maximum = 0, Minimum = 0, AverageTemperature = 20.0f, HasAutoPause = false }, - new ActivityEntity { IdActivity = 3, Type = "Swimming", Date = new DateTime(), StartTime = new DateTime(), EndTime = new DateTime(), EffortFelt = 5, Variability = 0.5f, Variance = 0.5f, StandardDeviation = 0.5f, Average = 0.5f, Maximum = 0, Minimum = 0, AverageTemperature = 20.0f, HasAutoPause = false }, - new ActivityEntity { IdActivity = 4, Type = "Walking", Date = new DateTime(), StartTime = new DateTime(), EndTime = new DateTime(), EffortFelt = 5, Variability = 0.5f, Variance = 0.5f, StandardDeviation = 0.5f, Average = 0.5f, Maximum = 0, Minimum = 0, AverageTemperature = 20.0f, HasAutoPause = false }, - new ActivityEntity { IdActivity = 5, Type = "Hiking", Date = new DateTime(), StartTime = new DateTime(), EndTime = new DateTime(), EffortFelt = 5, Variability = 0.5f, Variance = 0.5f, StandardDeviation = 0.5f, Average = 0.5f, Maximum = 0, Minimum = 0, AverageTemperature = 20.0f, HasAutoPause = false }, - new ActivityEntity { IdActivity = 6, Type = "Climbing", Date = new DateTime(), StartTime = new DateTime(), EndTime = new DateTime(), EffortFelt = 5, Variability = 0.5f, Variance = 0.5f, StandardDeviation = 0.5f, Average = 0.5f, Maximum = 0, Minimum = 0, AverageTemperature = 20.0f, HasAutoPause = false }, - new ActivityEntity { IdActivity = 7, Type = "Yoga", Date = new DateTime(), StartTime = new DateTime(), EndTime = new DateTime(), EffortFelt = 5, Variability = 0.5f, Variance = 0.5f, StandardDeviation = 0.5f, Average = 0.5f, Maximum = 0, Minimum = 0, AverageTemperature = 20.0f, HasAutoPause = false } - ); + /// + /// Configures the model for the activity context. + /// + /// The model builder instance. + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + // Seed data for activities + modelBuilder.Entity().HasData( + new ActivityEntity { IdActivity = 1, Type = "Running", Date = new DateOnly(2023, 01, 10), StartTime = new TimeOnly(13, 00, 34), EndTime = new TimeOnly(14, 00, 22), EffortFelt = 5, Variability = 0.5f, Variance = 0.5f, StandardDeviation = 0.5f, Average = 0.5f, Maximum = 0, Minimum = 0, AverageTemperature = 20.0f, HasAutoPause = false, DataSourceId = 1, AthleteId = 1 }, + new ActivityEntity { IdActivity = 2, Type = "Cycling", Date = new DateOnly(2023, 01, 25), StartTime = new TimeOnly(13, 04, 34), EndTime = new TimeOnly(14, 00, 22), EffortFelt = 5, Variability = 0.5f, Variance = 0.5f, StandardDeviation = 0.5f, Average = 0.5f, Maximum = 0, Minimum = 0, AverageTemperature = 20.0f, HasAutoPause = false, DataSourceId = 2, AthleteId = 2 }, + new ActivityEntity { IdActivity = 3, Type = "Swimming", Date = new DateOnly(2023, 12, 10), StartTime = new TimeOnly(13, 30, 34), EndTime = new TimeOnly(15, 02, 22), EffortFelt = 5, Variability = 0.5f, Variance = 0.5f, StandardDeviation = 0.5f, Average = 0.5f, Maximum = 0, Minimum = 0, AverageTemperature = 20.0f, HasAutoPause = false, DataSourceId = 1, AthleteId = 1 }, + new ActivityEntity { IdActivity = 4, Type = "Walking", Date = new DateOnly(2024, 01, 02), StartTime = new TimeOnly(15, 00, 00), EndTime = new TimeOnly(16, 01, 55), EffortFelt = 5, Variability = 0.5f, Variance = 0.5f, StandardDeviation = 0.5f, Average = 0.5f, Maximum = 0, Minimum = 0, AverageTemperature = 20.0f, HasAutoPause = false, DataSourceId = 3, AthleteId = 5 }, + new ActivityEntity { IdActivity = 5, Type = "Hiking", Date = new DateOnly(2024, 01, 12), StartTime = new TimeOnly(07, 45, 34), EndTime = new TimeOnly(09, 00, 22), EffortFelt = 5, Variability = 0.5f, Variance = 0.5f, StandardDeviation = 0.5f, Average = 0.5f, Maximum = 0, Minimum = 0, AverageTemperature = 20.0f, HasAutoPause = false, DataSourceId = 4, AthleteId = 4 }, + new ActivityEntity { IdActivity = 6, Type = "Climbing", Date = new DateOnly(2024, 01, 27), StartTime = new TimeOnly(13, 30, 01), EndTime = new TimeOnly(14, 00, 22), EffortFelt = 5, Variability = 0.5f, Variance = 0.5f, StandardDeviation = 0.5f, Average = 0.5f, Maximum = 0, Minimum = 0, AverageTemperature = 20.0f, HasAutoPause = false, DataSourceId = 4, AthleteId = 4 }, + new ActivityEntity { IdActivity = 7, Type = "Yoga", Date = new DateOnly(2024, 02, 22), StartTime = new TimeOnly(22, 00, 34), EndTime = new TimeOnly(23, 50, 58), EffortFelt = 5, Variability = 0.5f, Variance = 0.5f, StandardDeviation = 0.5f, Average = 0.5f, Maximum = 0, Minimum = 0, AverageTemperature = 20.0f, HasAutoPause = false, DataSourceId = 5, AthleteId = 3 } + ); + } } } \ No newline at end of file diff --git a/src/StubbedContextLib/AthleteStubbedContext.cs b/src/StubbedContextLib/AthleteStubbedContext.cs index c4a238b..f45140f 100644 --- a/src/StubbedContextLib/AthleteStubbedContext.cs +++ b/src/StubbedContextLib/AthleteStubbedContext.cs @@ -1,29 +1,53 @@ -using DbContextLib; +//----------------------------------------------------------------------- +// FILENAME: AthleteStubbedContext.cs +// PROJECT: StubbedContextLib +// SOLUTION: HeartTrack +// DATE CREATED: 22/02/2024 +// AUTHOR: Antoine PEREDERII +//----------------------------------------------------------------------- + +using DbContextLib; using Entities; using Microsoft.EntityFrameworkCore; -namespace StubbedContextLib; - -public class AthleteStubbedContext : LibraryContext +namespace StubbedContextLib { - public AthleteStubbedContext() - :base() - { } + /// + /// Represents the stubbed context for athletes. + /// + public class AthleteStubbedContext : ActivityStubbedContext + { + /// + /// Initializes a new instance of the class. + /// + public AthleteStubbedContext() : base() { } - public AthleteStubbedContext(DbContextOptions options) - :base(options) - { } + /// + /// Initializes a new instance of the class with the specified options. + /// + /// The options for the context. + public AthleteStubbedContext(DbContextOptions options) : base(options) { } - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - - modelBuilder.Entity().HasData( - new AthleteEntity { IdAthlete = 1, Username = "Doe", LastName = "Doe", FirstName = "John", Email = "john.doe@example.com", Password = "password123", Sexe = "M", Lenght = 1.80, Weight = 75, DateOfBirth = new DateTime(), IsCoach = true }, - new AthleteEntity { IdAthlete = 2, Username = "Smith", LastName = "Smith", FirstName = "Jane", Email = "jane.smith@example.com", Password = "secure456", Sexe = "F", Lenght = 1.65, Weight = 60, DateOfBirth = new DateTime(), IsCoach = false }, - new AthleteEntity { IdAthlete = 3, Username = "Martin", LastName = "Martin", FirstName = "Paul", Email = "paul.martin@example.com", Password = "super789", Sexe = "M", Lenght = 1.75, Weight = 68, DateOfBirth = new DateTime(), IsCoach = true }, - new AthleteEntity { IdAthlete = 4, Username = "Brown", LastName = "Brown", FirstName = "Anna", Email = "anna.brown@example.com", Password = "test000", Sexe = "F", Lenght = 1.70, Weight = 58, DateOfBirth = new DateTime(), IsCoach = false }, - new AthleteEntity { IdAthlete = 5, Username = "Lee", LastName = "Lee", FirstName ="Bruce", Email = "bruce.lee@example.com", Password = "hello321", Sexe = "M", Lenght = 2.0, Weight = 90, DateOfBirth = new DateTime(), IsCoach = false } - ); + /// + /// Configures the model for the athlete stubbed context. + /// + /// The model builder instance. + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + var picture2 = + "https://davidalmeida.site/assets/me_avatar.f77af006.png"; + LargeImageEntity picture = new LargeImageEntity { Id = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}"), Base64 = "UklGRtwDAABXRUJQVlA4INADAAAwEACdASoqACoAAMASJZgCdMoSCz655ndU4XXAP2yXIge5neM/Qd6WCfO8evoj2S0A/p7+f0An85cBxlLDgPC8jO/0nsl/13/O8vvzj7Af8s/p3/H4FU6td4MCwq23z1H2uzoKIXaqJniPI/bRMf8qzv0Zp+HE1RCBw5WQ1j/JovdM1FS52+QcaAAA/v/+NxU4DpPk3+xQPW7tcmURSo9vC4qc+XMxNVBzEM5E8actDz98gmwTXgD62e9EmG/ervdd2ovFFSuxYppWl/wtaX3rkn0xrt8qOql/5I2jfLOnCU0kALLcW4F/wTjU10qsxZXW9fxauC6OPVRF28sc94V9ocmoSWy+sf6jW3vYkVOh+gE/RE0L6b2d3oFyHmkRJnfYwG8o3p6fv9pivNF5aopIBzFnjzwb/VqSq3/b+MWKFmjr8T1qe4/fITo2vBWEqDyogV3ZVGnDVi2DbiEFVSUr2eXTNZQ9V/D9QC/+vCR5TGyX9QOVBgtAYtm/ZTIwzPEYB9NrV1NeO1/sAz78u0tW59r0I+SO5Jgm3B9i1toRurzHv9EZJ9yZL8nafb/T1FaoPDkuJfM+iPs0j8xnS7TaU/gEK0wCxeDYRYtJx9j4hUQq7pAu/T2yWy0vjcUHki952ZNbXnXxB8m8pV5x9E1sfLj5MZEgpU2XV8RHrVvWniCjsf6vgxmR7+KtwIbMjahitUGtHet1WdL+8MmdL29iQJC37pDXirir1NibxKKhFYRuJ3xW9O0r9+Vnh8diqbBuXqDbYR/MSoHvscOCm2t95dN5WBdRUoD7YCG/ZHWc7Ypv/x/al4fkB2lZlYhVWHxjaoeF9jEPI0gAN5XsvUI6hbzEzWMsNW/1orkNOnlskalgmpI4B2rm4Gc7LNui+MuMBrpnBvLkbYX9exe9g8tu7wLt7ScOjDcL99oOyR89Mh9L8rd4+43+JQyR6tsIfcPJo6T6FxHf11d/MGayJi+SWct/uhvvua0oOh+zXNIaUzgoBmu1XULjkpuA0Ghzctf30jbY1AOM49qbMZRYS9A+0S1HrHPnwRvpQY/Sj4xKPn0gdpv/+iTbKJb8zkPC4/9af0Jvesa+GDG0/iw3TswenMhqlh7BM9MW5txpeblsByx4WnJ/oHv6cc0dmM7tsV36lYkCTUXEf/0eKlnfivnN0g1g+j/Lk9et/uoa6TFCW0HgwFOIVFumEYdT675PfuTrYO5o8ZrWEIHtv2Ctlrv9J3TrslD/iKEwtipGHtn0Vak8B9wLL+kz+CIQ/VG4KJpXjx88CeCC4XaGitEdjAAA" }; + + modelBuilder.Entity().HasData(picture); + + modelBuilder.Entity().HasData( + new AthleteEntity { IdAthlete = 1, Username = "Doe",ProfilPicture = picture2, ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}") ,LastName = "Doe", FirstName = "John", Email = "john.doe@example.com", Password = "password123", Sexe = "M", Length = 1.80, Weight = 75, DateOfBirth = new DateOnly(1990, 01, 01), IsCoach = true , DataSourceId = 1}, + new AthleteEntity { IdAthlete = 2, Username = "Smith",ProfilPicture = picture2,ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}") ,LastName = "Smith", FirstName = "Jane", Email = "jane.smith@exemple.com", Password = "secure456", Sexe = "F", Length = 1.65, Weight = 60, DateOfBirth = new DateOnly(1995, 01, 01), IsCoach = false, DataSourceId = 1 }, + new AthleteEntity { IdAthlete = 3, Username = "Martin",ProfilPicture = picture2,ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}") ,LastName = "Martin", FirstName = "Paul", Email = "paul.martin@example.com", Password = "super789", Sexe = "M", Length = 1.75, Weight = 68, DateOfBirth = new DateOnly(1992, 01, 01), IsCoach = true, DataSourceId = 1}, + new AthleteEntity { IdAthlete = 4, Username = "Brown",ProfilPicture = picture2, ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}"),LastName = "Brown", FirstName = "Anna", Email = "anna.brown@example.com", Password = "test000", Sexe = "F", Length = 1.70, Weight = 58, DateOfBirth = new DateOnly(1993, 01, 01), IsCoach = false, DataSourceId = 2 }, + new AthleteEntity { IdAthlete = 5, Username = "Lee", ProfilPicture = picture2, ImageId = Guid.Parse("{8d121cdc-6787-4738-8edd-9e026ac16b65}"),LastName = "Lee", FirstName = "Bruce", Email = "bruce.lee@example.com", Password = "hello321", Sexe = "M", Length = 2.0, Weight = 90, DateOfBirth = new DateOnly(1991, 01, 01), IsCoach = false, DataSourceId = 3 } + ); + } } } \ No newline at end of file diff --git a/src/StubbedContextLib/DataSourceStubbedContext.cs b/src/StubbedContextLib/DataSourceStubbedContext.cs index f1b8b2b..734cc5b 100644 --- a/src/StubbedContextLib/DataSourceStubbedContext.cs +++ b/src/StubbedContextLib/DataSourceStubbedContext.cs @@ -1,29 +1,48 @@ +//----------------------------------------------------------------------- +// FILENAME: DataSourceStubbedContext.cs +// PROJECT: StubbedContextLib +// SOLUTION: HeartTrack +// DATE CREATED: 22/02/2024 +// AUTHOR: Antoine PEREDERII +//----------------------------------------------------------------------- + using DbContextLib; using Entities; using Microsoft.EntityFrameworkCore; -namespace StubbedContextLib; - -public class DataSourceStubbedContext : LibraryContext +namespace StubbedContextLib { - public DataSourceStubbedContext() - :base() - { } + /// + /// Represents the stubbed context for data sources. + /// + public class DataSourceStubbedContext : AthleteStubbedContext + { + /// + /// Initializes a new instance of the class. + /// + public DataSourceStubbedContext() : base() { } - public DataSourceStubbedContext(DbContextOptions options) - :base(options) - { } + /// + /// Initializes a new instance of the class with the specified options. + /// + /// The options for the context. + public DataSourceStubbedContext(DbContextOptions options) : base(options) { } - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - - modelBuilder.Entity().HasData( - new DataSourceEntity { IdSource = 1, Type = "Smartwatch", Modele = "Garmin", Precision = 0.5f }, - new DataSourceEntity { IdSource = 2, Type = "Smartwatch", Modele = "Polar", Precision = 0.5f }, - new DataSourceEntity { IdSource = 3, Type = "Smartwatch", Modele = "Suunto", Precision = 0.5f }, - new DataSourceEntity { IdSource = 4, Type = "Smartwatch", Modele = "Fitbit", Precision = 0.5f }, - new DataSourceEntity { IdSource = 5, Type = "Smartwatch", Modele = "Apple Watch", Precision = 0.5f } - ); + /// + /// Configures the model for the data source stubbed context. + /// + /// The model builder instance. + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity().HasData( + new DataSourceEntity { IdSource = 1, Type = "Smartwatch", Model = "Garmin", Precision = 0.5f }, + new DataSourceEntity { IdSource = 2, Type = "Smartwatch", Model = "Polar", Precision = 0.5f }, + new DataSourceEntity { IdSource = 3, Type = "Smartwatch", Model = "Suunto", Precision = 0.5f }, + new DataSourceEntity { IdSource = 4, Type = "Smartwatch", Model = "Fitbit", Precision = 0.5f }, + new DataSourceEntity { IdSource = 5, Type = "Smartwatch", Model = "Apple Watch", Precision = 0.5f } + ); + } } } \ No newline at end of file diff --git a/src/StubbedContextLib/FriendshipStubbedContext.cs b/src/StubbedContextLib/FriendshipStubbedContext.cs new file mode 100644 index 0000000..70eb76f --- /dev/null +++ b/src/StubbedContextLib/FriendshipStubbedContext.cs @@ -0,0 +1,49 @@ +//----------------------------------------------------------------------- +// FILENAME: FriendshipStubbedContext.cs +// PROJECT: StubbedContextLib +// SOLUTION: HeartTrack +// DATE CREATED: 22/02/2024 +// AUTHOR: Antoine PEREDERII +//----------------------------------------------------------------------- + +using DbContextLib; +using Entities; +using Microsoft.EntityFrameworkCore; + +namespace StubbedContextLib +{ + /// + /// Represents the stubbed context for friendship entities. + /// + public class FriendshipStubbedContext : DataSourceStubbedContext + { + /// + /// Initializes a new instance of the class. + /// + public FriendshipStubbedContext() : base() { } + + /// + /// Initializes a new instance of the class with the specified options. + /// + /// The options for the context. + public FriendshipStubbedContext(DbContextOptions options) : base(options) { } + + /// + /// Configures the model for the heart rate stubbed context. + /// + /// The model builder instance. + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity().HasData( + new FriendshipEntity { FollowerId = 1, FollowingId = 2 }, + new FriendshipEntity { FollowerId = 1, FollowingId = 3 }, + new FriendshipEntity { FollowerId = 1, FollowingId = 4 }, + new FriendshipEntity { FollowerId = 1, FollowingId = 5 }, + new FriendshipEntity { FollowerId = 2, FollowingId = 1 }, + new FriendshipEntity { FollowerId = 2, FollowingId = 3 } + ); + } + } +} \ No newline at end of file diff --git a/src/StubbedContextLib/HeartRateStubbedContext.cs b/src/StubbedContextLib/HeartRateStubbedContext.cs index f22659a..a80ca57 100644 --- a/src/StubbedContextLib/HeartRateStubbedContext.cs +++ b/src/StubbedContextLib/HeartRateStubbedContext.cs @@ -1,29 +1,48 @@ +//----------------------------------------------------------------------- +// FILENAME: HeartRateStubbedContext.cs +// PROJECT: StubbedContextLib +// SOLUTION: HeartTrack +// DATE CREATED: 22/02/2024 +// AUTHOR: Antoine PEREDERII +//----------------------------------------------------------------------- + using DbContextLib; using Entities; using Microsoft.EntityFrameworkCore; -namespace StubbedContextLib; - -public class HeartRateStubbedContext : LibraryContext +namespace StubbedContextLib { - public HeartRateStubbedContext() - :base() - { } + /// + /// Represents the stubbed context for heart rate entities. + /// + public class HeartRateStubbedContext : FriendshipStubbedContext + { + /// + /// Initializes a new instance of the class. + /// + public HeartRateStubbedContext() : base() { } - public HeartRateStubbedContext(DbContextOptions options) - :base(options) - { } + /// + /// Initializes a new instance of the class with the specified options. + /// + /// The options for the context. + public HeartRateStubbedContext(DbContextOptions options) : base(options) { } - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - - modelBuilder.Entity().HasData( - new HeartRateEntity { IdHeartRate = 1, Altitude = 0.0, Time = new DateTime(), Temperature = 20.0f, Bpm = 60, Longitude = 35f, Latitude = 66f }, - new HeartRateEntity { IdHeartRate = 2, Altitude = 10, Time = new DateTime(), Temperature = 20.5f, Bpm = 65, Longitude = 35f, Latitude = 67f }, - new HeartRateEntity { IdHeartRate = 3, Altitude = 11, Time = new DateTime(), Temperature = 20.0f, Bpm = 71, Longitude = 36f, Latitude = 66f }, - new HeartRateEntity { IdHeartRate = 4, Altitude = 12, Time = new DateTime(), Temperature = 20.5f, Bpm = 75, Longitude = 36f, Latitude = 67f }, - new HeartRateEntity { IdHeartRate = 5, Altitude = 13, Time = new DateTime(), Temperature = 20.0f, Bpm = 80, Longitude = 37f, Latitude = 66f } - ); + /// + /// Configures the model for the heart rate stubbed context. + /// + /// The model builder instance. + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity().HasData( + new HeartRateEntity { IdHeartRate = 1, Altitude = 0.0, Time = new TimeOnly(13, 00, 30), Temperature = 20.0f, Bpm = 60, Longitude = 35f, Latitude = 66f, ActivityId = 1 }, + new HeartRateEntity { IdHeartRate = 2, Altitude = 10, Time = new TimeOnly(13, 00, 31), Temperature = 20.5f, Bpm = 65, Longitude = 35f, Latitude = 67f, ActivityId = 2 }, + new HeartRateEntity { IdHeartRate = 3, Altitude = 11, Time = new TimeOnly(13, 00, 32), Temperature = 20.0f, Bpm = 71, Longitude = 36f, Latitude = 66f, ActivityId = 1 }, + new HeartRateEntity { IdHeartRate = 4, Altitude = 12, Time = new TimeOnly(13, 00, 33), Temperature = 20.5f, Bpm = 75, Longitude = 36f, Latitude = 67f, ActivityId = 2 }, + new HeartRateEntity { IdHeartRate = 5, Altitude = 13, Time = new TimeOnly(13, 00, 34), Temperature = 20.0f, Bpm = 80, Longitude = 37f, Latitude = 66f, ActivityId = 4 } + ); + } } } \ No newline at end of file diff --git a/src/StubbedContextLib/Migrations/20240216134447_MyMirgations.Designer.cs b/src/StubbedContextLib/Migrations/20240216134447_MyMirgations.Designer.cs deleted file mode 100644 index 4232a95..0000000 --- a/src/StubbedContextLib/Migrations/20240216134447_MyMirgations.Designer.cs +++ /dev/null @@ -1,147 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using StubbedContextLib; - -#nullable disable - -namespace StubbedContextLib.Migrations -{ - [DbContext(typeof(AthleteStubbedContext))] - [Migration("20240216134447_MyMirgations")] - partial class MyMirgations - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "8.0.2"); - - modelBuilder.Entity("Entities.AthleteEntity", b => - { - b.Property("IdAthlete") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateOfBirth") - .HasColumnType("TEXT"); - - b.Property("Email") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("FirstName") - .IsRequired() - .HasMaxLength(150) - .HasColumnType("TEXT"); - - b.Property("IsCoach") - .HasColumnType("INTEGER"); - - b.Property("LastName") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("TEXT"); - - b.Property("Lenght") - .HasColumnType("REAL"); - - b.Property("Password") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Sexe") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("TEXT"); - - b.Property("Weight") - .HasColumnType("REAL"); - - b.HasKey("IdAthlete"); - - b.ToTable("Athlete"); - - b.HasData( - new - { - IdAthlete = 1, - DateOfBirth = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), - Email = "john.doe@example.com", - FirstName = "John", - IsCoach = true, - LastName = "Doe", - Lenght = 1.8, - Password = "password123", - Sexe = "M", - Username = "Doe", - Weight = 75f - }, - new - { - IdAthlete = 2, - DateOfBirth = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), - Email = "jane.smith@example.com", - FirstName = "Jane", - IsCoach = false, - LastName = "Smith", - Lenght = 1.6499999999999999, - Password = "secure456", - Sexe = "F", - Username = "Smith", - Weight = 60f - }, - new - { - IdAthlete = 3, - DateOfBirth = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), - Email = "paul.martin@example.com", - FirstName = "Paul", - IsCoach = true, - LastName = "Martin", - Lenght = 1.75, - Password = "super789", - Sexe = "M", - Username = "Martin", - Weight = 68f - }, - new - { - IdAthlete = 4, - DateOfBirth = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), - Email = "anna.brown@example.com", - FirstName = "Anna", - IsCoach = false, - LastName = "Brown", - Lenght = 1.7, - Password = "test000", - Sexe = "F", - Username = "Brown", - Weight = 58f - }, - new - { - IdAthlete = 5, - DateOfBirth = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), - Email = "bruce.lee@example.com", - FirstName = "Bruce", - IsCoach = false, - LastName = "Lee", - Lenght = 2.0, - Password = "hello321", - Sexe = "M", - Username = "Lee", - Weight = 90f - }); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/StubbedContextLib/Migrations/20240216134447_MyMirgations.cs b/src/StubbedContextLib/Migrations/20240216134447_MyMirgations.cs deleted file mode 100644 index 3f410d6..0000000 --- a/src/StubbedContextLib/Migrations/20240216134447_MyMirgations.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional - -namespace StubbedContextLib.Migrations -{ - /// - public partial class MyMirgations : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Athlete", - columns: table => new - { - IdAthlete = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Username = table.Column(type: "TEXT", maxLength: 100, nullable: false), - LastName = table.Column(type: "TEXT", maxLength: 100, nullable: false), - FirstName = table.Column(type: "TEXT", maxLength: 150, nullable: false), - Email = table.Column(type: "TEXT", nullable: false), - Sexe = table.Column(type: "TEXT", nullable: false), - Lenght = table.Column(type: "REAL", nullable: false), - Weight = table.Column(type: "REAL", nullable: false), - Password = table.Column(type: "TEXT", nullable: false), - DateOfBirth = table.Column(type: "TEXT", nullable: false), - IsCoach = table.Column(type: "INTEGER", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Athlete", x => x.IdAthlete); - }); - - migrationBuilder.InsertData( - table: "Athlete", - columns: new[] { "IdAthlete", "DateOfBirth", "Email", "FirstName", "IsCoach", "LastName", "Lenght", "Password", "Sexe", "Username", "Weight" }, - values: new object[,] - { - { 1, new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), "john.doe@example.com", "John", true, "Doe", 1.8, "password123", "M", "Doe", 75f }, - { 2, new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), "jane.smith@example.com", "Jane", false, "Smith", 1.6499999999999999, "secure456", "F", "Smith", 60f }, - { 3, new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), "paul.martin@example.com", "Paul", true, "Martin", 1.75, "super789", "M", "Martin", 68f }, - { 4, new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), "anna.brown@example.com", "Anna", false, "Brown", 1.7, "test000", "F", "Brown", 58f }, - { 5, new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), "bruce.lee@example.com", "Bruce", false, "Lee", 2.0, "hello321", "M", "Lee", 90f } - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "Athlete"); - } - } -} diff --git a/src/StubbedContextLib/Migrations/AthleteStubbedContextModelSnapshot.cs b/src/StubbedContextLib/Migrations/AthleteStubbedContextModelSnapshot.cs deleted file mode 100644 index 1556ab4..0000000 --- a/src/StubbedContextLib/Migrations/AthleteStubbedContextModelSnapshot.cs +++ /dev/null @@ -1,144 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using StubbedContextLib; - -#nullable disable - -namespace StubbedContextLib.Migrations -{ - [DbContext(typeof(AthleteStubbedContext))] - partial class AthleteStubbedContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "8.0.2"); - - modelBuilder.Entity("Entities.AthleteEntity", b => - { - b.Property("IdAthlete") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateOfBirth") - .HasColumnType("TEXT"); - - b.Property("Email") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("FirstName") - .IsRequired() - .HasMaxLength(150) - .HasColumnType("TEXT"); - - b.Property("IsCoach") - .HasColumnType("INTEGER"); - - b.Property("LastName") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("TEXT"); - - b.Property("Lenght") - .HasColumnType("REAL"); - - b.Property("Password") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Sexe") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("TEXT"); - - b.Property("Weight") - .HasColumnType("REAL"); - - b.HasKey("IdAthlete"); - - b.ToTable("Athlete"); - - b.HasData( - new - { - IdAthlete = 1, - DateOfBirth = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), - Email = "john.doe@example.com", - FirstName = "John", - IsCoach = true, - LastName = "Doe", - Lenght = 1.8, - Password = "password123", - Sexe = "M", - Username = "Doe", - Weight = 75f - }, - new - { - IdAthlete = 2, - DateOfBirth = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), - Email = "jane.smith@example.com", - FirstName = "Jane", - IsCoach = false, - LastName = "Smith", - Lenght = 1.6499999999999999, - Password = "secure456", - Sexe = "F", - Username = "Smith", - Weight = 60f - }, - new - { - IdAthlete = 3, - DateOfBirth = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), - Email = "paul.martin@example.com", - FirstName = "Paul", - IsCoach = true, - LastName = "Martin", - Lenght = 1.75, - Password = "super789", - Sexe = "M", - Username = "Martin", - Weight = 68f - }, - new - { - IdAthlete = 4, - DateOfBirth = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), - Email = "anna.brown@example.com", - FirstName = "Anna", - IsCoach = false, - LastName = "Brown", - Lenght = 1.7, - Password = "test000", - Sexe = "F", - Username = "Brown", - Weight = 58f - }, - new - { - IdAthlete = 5, - DateOfBirth = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), - Email = "bruce.lee@example.com", - FirstName = "Bruce", - IsCoach = false, - LastName = "Lee", - Lenght = 2.0, - Password = "hello321", - Sexe = "M", - Username = "Lee", - Weight = 90f - }); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/StubbedContextLib/NotificationStubbedContext.cs b/src/StubbedContextLib/NotificationStubbedContext.cs index e2b287a..2c5e0d2 100644 --- a/src/StubbedContextLib/NotificationStubbedContext.cs +++ b/src/StubbedContextLib/NotificationStubbedContext.cs @@ -1,29 +1,48 @@ +//----------------------------------------------------------------------- +// FILENAME: NotificationStubbedContext.cs +// PROJECT: StubbedContextLib +// SOLUTION: HeartTrack +// DATE CREATED: 22/02/2024 +// AUTHOR: Antoine PEREDERII +//----------------------------------------------------------------------- + using DbContextLib; using Entities; using Microsoft.EntityFrameworkCore; -namespace StubbedContextLib; - -public class NotificationStubbedContext : LibraryContext +namespace StubbedContextLib { - public NotificationStubbedContext() - :base() - { } + /// + /// Represents the stubbed context for notification entities. + /// + public class NotificationStubbedContext : HeartRateStubbedContext + { + /// + /// Initializes a new instance of the class. + /// + public NotificationStubbedContext() : base() { } - public NotificationStubbedContext(DbContextOptions options) - :base(options) - { } + /// + /// Initializes a new instance of the class with the specified options. + /// + /// The options for the context. + public NotificationStubbedContext(DbContextOptions options) : base(options) { } - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - - modelBuilder.Entity().HasData( - new NotificationEntity { IdNotif = 1, Message = "You have a new activity to check", Date = new DateTime(), Statut = true, Urgence = "A" }, - new NotificationEntity { IdNotif = 2, Message = "You have a new athlete to check", Date = new DateTime(), Statut = false, Urgence = "3" }, - new NotificationEntity { IdNotif = 3, Message = "You have a new heart rate to check", Date = new DateTime(), Statut = true, Urgence = "2" }, - new NotificationEntity { IdNotif = 4, Message = "You have a new data source to check", Date = new DateTime(), Statut = false, Urgence = "1" }, - new NotificationEntity { IdNotif = 5, Message = "You have a new notification to check", Date = new DateTime(), Statut = true, Urgence = "3" } - ); + /// + /// Configures the model for the notification stubbed context. + /// + /// The model builder instance. + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity().HasData( + new NotificationEntity { IdNotif = 1, Message = "You have a new activity to check", Date = new DateTime(2023, 12, 25, 13, 00, 40), Statut = true, Urgence = "A", SenderId = 1 }, + new NotificationEntity { IdNotif = 2, Message = "You have a new athlete to check", Date = new DateTime(2023, 12, 26, 13, 10, 40), Statut = false, Urgence = "3", SenderId = 2 }, + new NotificationEntity { IdNotif = 3, Message = "You have a new heart rate to check", Date = new DateTime(2023, 12, 26, 16, 10, 04), Statut = true, Urgence = "2", SenderId = 3 }, + new NotificationEntity { IdNotif = 4, Message = "You have a new data source to check", Date = new DateTime(2024, 01, 12, 09, 30, 50), Statut = false, Urgence = "1", SenderId = 4 }, + new NotificationEntity { IdNotif = 5, Message = "You have a new notification to check", Date = new DateTime(2024, 02, 22, 12, 10, 00), Statut = true, Urgence = "3", SenderId = 5 } + ); + } } } \ No newline at end of file diff --git a/src/StubbedContextLib/StatisticStubbedContext.cs b/src/StubbedContextLib/StatisticStubbedContext.cs index e69de29..1b72aff 100644 --- a/src/StubbedContextLib/StatisticStubbedContext.cs +++ b/src/StubbedContextLib/StatisticStubbedContext.cs @@ -0,0 +1,48 @@ +//----------------------------------------------------------------------- +// FILENAME: StatisticStubbedContext.cs +// PROJECT: StubbedContextLib +// SOLUTION: HeartTrack +// DATE CREATED: 22/02/2024 +// AUTHOR: Antoine PEREDERII +//----------------------------------------------------------------------- + +using DbContextLib; +using Entities; +using Microsoft.EntityFrameworkCore; + +namespace StubbedContextLib +{ + /// + /// Represents the stubbed context for statistic entities. + /// + public class StatisticStubbedContext : NotificationStubbedContext + { + /// + /// Initializes a new instance of the class. + /// + public StatisticStubbedContext() : base() { } + + /// + /// Initializes a new instance of the class with the specified options. + /// + /// The options for the context. + public StatisticStubbedContext(DbContextOptions options) : base(options) { } + + /// + /// Configures the model for the statistic stubbed context. + /// + /// The model builder instance. + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity().HasData( + new StatisticEntity { IdStatistic = 1, Weight = 75, AverageHeartRate = 120, MaximumHeartRate = 180, AverageCaloriesBurned = 500, Date = new DateOnly(2021, 12, 12), AthleteId = 1 }, + new StatisticEntity { IdStatistic = 2, Weight = 60, AverageHeartRate = 130, MaximumHeartRate = 190, AverageCaloriesBurned = 600, Date = new DateOnly(2021, 01, 11), AthleteId = 2 }, + new StatisticEntity { IdStatistic = 3, Weight = 68, AverageHeartRate = 125, MaximumHeartRate = 185, AverageCaloriesBurned = 550, Date = new DateOnly(2022, 12, 30), AthleteId = 1 }, + new StatisticEntity { IdStatistic = 4, Weight = 58, AverageHeartRate = 135, MaximumHeartRate = 195, AverageCaloriesBurned = 650, Date = new DateOnly(2023, 02, 20), AthleteId = 3 }, + new StatisticEntity { IdStatistic = 5, Weight = 90, AverageHeartRate = 110, MaximumHeartRate = 170, AverageCaloriesBurned = 450, Date = new DateOnly(2024, 01, 10), AthleteId = 4 } + ); + } + } +} \ No newline at end of file diff --git a/src/StubbedContextLib/StubbedContextLib.csproj b/src/StubbedContextLib/StubbedContextLib.csproj index ecea2c4..bdd147f 100644 --- a/src/StubbedContextLib/StubbedContextLib.csproj +++ b/src/StubbedContextLib/StubbedContextLib.csproj @@ -1,16 +1,16 @@  - - - + + + - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + diff --git a/src/StubbedContextLib/TrainingStubbedContext.cs b/src/StubbedContextLib/TrainingStubbedContext.cs index e69de29..0916024 100644 --- a/src/StubbedContextLib/TrainingStubbedContext.cs +++ b/src/StubbedContextLib/TrainingStubbedContext.cs @@ -0,0 +1,48 @@ +//----------------------------------------------------------------------- +// FILENAME: TrainingStubbedContext.cs +// PROJECT: StubbedContextLib +// SOLUTION: HeartTrack +// DATE CREATED: 22/02/2024 +// AUTHOR: Antoine PEREDERII +//----------------------------------------------------------------------- + +using DbContextLib; +using Entities; +using Microsoft.EntityFrameworkCore; + +namespace StubbedContextLib +{ + /// + /// Represents the stubbed context for training entities. + /// + public class TrainingStubbedContext : StatisticStubbedContext + { + /// + /// Initializes a new instance of the class. + /// + public TrainingStubbedContext() : base() { } + + /// + /// Initializes a new instance of the class with the specified options. + /// + /// The options for the context. + public TrainingStubbedContext(DbContextOptions options) : base(options) { } + + /// + /// Configures the model for the training stubbed context. + /// + /// The model builder instance. + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity().HasData( + new TrainingEntity { IdTraining = 1, Date = new DateOnly(2024, 01, 19), Description = "Running", Latitude = 48.8566f, Longitude = 2.3522f, FeedBack = "Good", CoachId = 1 }, + new TrainingEntity { IdTraining = 2, Date = new DateOnly(2024, 02, 20), Description = "Cycling", Latitude = 48.8566f, Longitude = 2.3522f, CoachId = 5 }, + new TrainingEntity { IdTraining = 3, Date = new DateOnly(2024, 02, 21), Latitude = 48.8566f, Longitude = 2.3522f, FeedBack = "Good", CoachId = 4 }, + new TrainingEntity { IdTraining = 4, Date = new DateOnly(2024, 02, 22), Description = "Running", Latitude = 48.8566f, Longitude = 2.3522f, FeedBack = "Good", CoachId = 3 }, + new TrainingEntity { IdTraining = 5, Date = new DateOnly(2024, 02, 23), Description = "Cycling", Latitude = 48.8566f, Longitude = 2.3522f, CoachId = 1 } + ); + } + } +} \ No newline at end of file diff --git a/src/Tests/ConsoleTestEFMapper/ConsoleTestEFMapper.csproj b/src/Tests/ConsoleTestEFMapper/ConsoleTestEFMapper.csproj new file mode 100644 index 0000000..1832a20 --- /dev/null +++ b/src/Tests/ConsoleTestEFMapper/ConsoleTestEFMapper.csproj @@ -0,0 +1,23 @@ + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + Exe + net8.0 + enable + enable + + + diff --git a/src/Tests/ConsoleTestEFMapper/Program.cs b/src/Tests/ConsoleTestEFMapper/Program.cs new file mode 100644 index 0000000..bc71893 --- /dev/null +++ b/src/Tests/ConsoleTestEFMapper/Program.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Model; +using Shared; +using StubbedContextLib; +using static Model2Entities.DbDataManager; + +namespace Model2Entities +{ + static class Program + { + static async Task Main(string[] args) + { + // Instanciation de DbDataManager et ActivityRepository + var dataManager = new DbDataManager(new TrainingStubbedContext()); + var logger = new Logger(new LoggerFactory()); + + // Test de la méthode GetActivities + await ActivitiesTestAsync(dataManager, logger); + + } + static async Task ActivitiesTestAsync(DbDataManager dataManager, ILogger logger) + { + var activityRepository = new ActivityRepository(dataManager, logger); + + // Test de la méthode GetActivities + Console.WriteLine("Testing GetActivities method..."); + var activities = await activityRepository.GetActivities(0, 10, ActivityOrderCriteria.ByType, true); + foreach (var activity in activities) + { + Console.WriteLine($"Activity ID: {activity.Id}, Name: {activity.Type}, Date: {activity.Date}, Start Time: {activity.StartTime}, End Time: {activity.EndTime}"); + } + Console.WriteLine(); + + // Test de la méthode GetActivityByIdAsync + Console.WriteLine("Testing GetActivityByIdAsync method..."); + var activityById = await activityRepository.GetActivityByIdAsync(2); + if (activityById != null) + { + Console.WriteLine($"Activity found: ID: {activityById.Id}, Name: {activityById.Type}, Date: {activityById.Date}, Start Time: {activityById.StartTime}, End Time: {activityById.EndTime}"); + } + else + { + Console.WriteLine("No activity found with the specified ID."); + } + Console.WriteLine(); + + // // Test de la méthode AddActivity + Console.WriteLine("Testing AddActivity method..."); + var user = new User + { + Id = 1, Username = "DoeDoe", + ProfilePicture = + "https://images.unsplash.com/photo-1682687982134-2ac563b2228b?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + FirstName = "John", LastName = "Doe", + Sexe = "M", Lenght = 180, Weight = 70, DateOfBirth = new DateTime(1990, 1, 1), + Email = "john.doe@example.com", Role = new Athlete() + }; + var dataSource = new DataSource(1, "Polar", "Vantage V2", 0.5f, new List {user}, new List()); + + var newActivity = new Activity(10, "New Activity", new DateTime(2021, 10, 10), + new DateTime(10, 10, 10, 10, 10, 10), new DateTime(10, 10, 10, 12, 12, 12), 5, 5, 5, 5, 5, 5, 5, 5, + false, user) + { + DataSource = dataSource + }; + var HeartRates = new List + { + new HeartRate(1, 60, new TimeOnly(10, 10, 10), newActivity, 5, 5, 5, 5, 5, 5, 5, 5), + }; + newActivity.HeartRates = HeartRates; + var addedActivity = await activityRepository.AddActivity(newActivity); + if (addedActivity != null) + { + Console.WriteLine($"New activity added successfully: ID: {addedActivity.Id}, Name: {addedActivity.Type}, Date: {addedActivity.Date}, Start Time: {addedActivity.StartTime}, End Time: {addedActivity.EndTime}"); + } + else + { + Console.WriteLine("Failed to add new activity."); + } + Console.WriteLine(); + + // Test de la méthode UpdateActivity + Console.WriteLine("Testing UpdateActivity method..."); + var updatedActivity = await activityRepository.UpdateActivity(6, new Activity { Id = 6, Type = "Updated Activity", Date = new DateTime(2021, 10, 11), StartTime = new DateTime(10, 10, 10, 10, 10, 10), EndTime = new DateTime(10, 10, 10, 12, 12, 12) }); + if (updatedActivity != null) + { + Console.WriteLine($"Activity updated successfully: ID: {updatedActivity.Id}, Name: {updatedActivity.Type}, Date: {updatedActivity.Date}, Start Time: {updatedActivity.StartTime}, End Time: {updatedActivity.EndTime}"); + } + else + { + Console.WriteLine("Failed to update activity."); + } + Console.WriteLine(); + + // Test de la méthode DeleteActivity + Console.WriteLine("Testing DeleteActivity method..."); + var isDeleted = await activityRepository.DeleteActivity(1); + if (isDeleted) + { + Console.WriteLine("Activity deleted successfully."); + } else + { + Console.WriteLine("Failed to delete activity."); + } + + // Test de la méthode GetNbItems + Console.WriteLine("Testing GetNbItems method..."); + var itemCount = await activityRepository.GetNbItems(); + Console.WriteLine($"Total number of activities: {itemCount}"); + } + static void UsersTest() + {} + } +} \ No newline at end of file diff --git a/src/Tests/ConsoleTestEntities/Program.cs b/src/Tests/ConsoleTestEntities/Program.cs index 80154f8..826f345 100644 --- a/src/Tests/ConsoleTestEntities/Program.cs +++ b/src/Tests/ConsoleTestEntities/Program.cs @@ -1,7 +1,7 @@ using DbContextLib; using StubbedContextLib; -using Microsoft.EntityFrameworkCore; - +using Entities; +namespace ConsoleTestEntities; class Program { @@ -9,15 +9,35 @@ class Program { try { - using (LibraryContext db = new AthleteStubbedContext()) + using (HeartTrackContext db = new TrainingStubbedContext()) { AthletesTests(db); - // // Test d'ajout, de modification et de suppression - // AddUpdateDeleteOperations(db); + ActivityTests(db); + + DataSourceTests(db); + + HeartRateTests(db); + + NotificationTests(db); + + StatisticTests(db); + + TrainingTests(db); + + AddUpdateDeleteAthlete(db); + + AddUpdateDeleteActivity(db); - // // Test d'emprunt et de retour de livre - // BorrowAndReturnBook(db); + AddUpdateDeleteDataSource(db); + + AddUpdateDeleteHeartRate(db); + + AddUpdateDeleteNotification(db); + + AddUpdateDeleteStatistic(db); + + AddUpdateDeleteTraining(db); } } catch (Exception ex) @@ -26,18 +46,17 @@ class Program } } - - static void AthletesTests(LibraryContext db) + static void AthletesTests(HeartTrackContext db) { Console.WriteLine("Accès à tous les athletes :"); - // Affichage des livres + // Affichage des athletes Console.WriteLine("Athletes :"); Console.WriteLine("---------------------------------"); foreach (var athlete in db.AthletesSet) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Lenght}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); @@ -46,7 +65,7 @@ class Program Console.WriteLine("---------------------------------"); foreach (var athlete in db.AthletesSet.Where(a => a.IdAthlete == 2)) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Lenght}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); @@ -55,7 +74,7 @@ class Program Console.WriteLine("---------------------------------"); foreach (var athlete in db.AthletesSet.Where(a => a.Username == "Doe")) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Lenght}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); @@ -64,7 +83,7 @@ class Program Console.WriteLine("---------------------------------"); foreach (var athlete in db.AthletesSet.Where(a => a.Sexe == "F")) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Lenght}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); @@ -73,7 +92,7 @@ class Program Console.WriteLine("---------------------------------"); foreach (var athlete in db.AthletesSet.Where(a => a.Email == "bruce.lee@example.com")) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Lenght}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); @@ -82,26 +101,25 @@ class Program Console.WriteLine("---------------------------------"); foreach (var athlete in db.AthletesSet.Where(a => a.Weight == 90)) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Lenght}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); Console.WriteLine("Accès à l'athlete de taille '1.80' :"); Console.WriteLine("---------------------------------"); - foreach (var athlete in db.AthletesSet.Where(a => a.Lenght == 1.80)) + foreach (var athlete in db.AthletesSet.Where(a => a.Length == 1.80)) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Lenght}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); - // ! A revoir !! - Console.WriteLine("Accès à l'athlete de date de naissance '01/01/2000' :"); + Console.WriteLine("Accès à l'athlete de date de naissance '01/01/1990' :"); Console.WriteLine("---------------------------------"); - foreach (var athlete in db.AthletesSet.Where(a => a.DateOfBirth == new DateTime())) + foreach (var athlete in db.AthletesSet.Where(a => a.DateOfBirth == new DateOnly(1990, 01, 01))) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Lenght}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); @@ -110,7 +128,7 @@ class Program Console.WriteLine("---------------------------------"); foreach (var athlete in db.AthletesSet.Where(a => a.LastName == "Martin")) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Lenght}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); @@ -119,7 +137,7 @@ class Program Console.WriteLine("---------------------------------"); foreach (var athlete in db.AthletesSet.Where(a => a.FirstName == "Anna")) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Lenght}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); @@ -128,7 +146,7 @@ class Program Console.WriteLine("---------------------------------"); foreach (var athlete in db.AthletesSet.Where(a => a.LastName == "Brown" && a.FirstName == "Anna")) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Lenght}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); } Console.WriteLine("---------------------------------\n"); @@ -137,93 +155,836 @@ class Program Console.WriteLine("---------------------------------"); foreach (var athlete in db.AthletesSet.Where(a => a.IsCoach == true)) { - Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Lenght}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + } + + Console.WriteLine("---------------------------------\n"); + } + + static void ActivityTests(HeartTrackContext db) + { + Console.WriteLine("Accès à toutes les activités :"); + + Console.WriteLine("Activités :"); + Console.WriteLine("---------------------------------"); + + foreach (var activity in db.ActivitiesSet) + { + Console.WriteLine($"\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'activité d'id '2' :"); + Console.WriteLine("---------------------------------"); + + foreach (var activity in db.ActivitiesSet.Where(a => a.IdActivity == 2)) + { + Console.WriteLine($"\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'activité de type 'Running' :"); + Console.WriteLine("---------------------------------"); + + foreach (var activity in db.ActivitiesSet.Where(a => a.Type == "Running")) + { + Console.WriteLine($"\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'activité de date '10/01/2023' :"); + Console.WriteLine("---------------------------------"); + + foreach (var activity in db.ActivitiesSet.Where(a => a.Date == new DateOnly(2023, 01, 10))) + { + Console.WriteLine($"\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'activité de temps '13:00:34' :"); + Console.WriteLine("---------------------------------"); + + foreach (var activity in db.ActivitiesSet.Where(a => a.StartTime == new TimeOnly(13, 00, 34))) + { + Console.WriteLine($"\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'activité de temps '13:00:34' et de type 'Running' :"); + Console.WriteLine("---------------------------------"); + + foreach (var activity in db.ActivitiesSet.Where(a => a.StartTime == new TimeOnly(13, 00, 34) && a.Type == "Running")) + { + Console.WriteLine($"\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'activité de temps '13:00:34' et de type 'Running' et de date '10/01/2023' :"); + Console.WriteLine("---------------------------------"); + + foreach (var activity in db.ActivitiesSet.Where(a => a.StartTime == new TimeOnly(13, 00, 34) && a.Type == "Running" && a.Date == new DateOnly(2023, 01, 10))) + { + Console.WriteLine($"\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'activité de temps '13:00:34' et de type 'Running' et de date '10/01/2023' et de temps de fin '14:00:22' :"); + Console.WriteLine("---------------------------------"); + + foreach (var activity in db.ActivitiesSet.Where(a => a.StartTime == new TimeOnly(13, 00, 34) && a.Type == "Running" && a.Date == new DateOnly(2023, 01, 10) && a.EndTime == new TimeOnly(14, 00, 22))) + { + Console.WriteLine($"\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'activité de temps '13:00:34' et de type 'Running' et de date '10/01/2023' et de temps de fin '14:00:22' et de ressenti d'effort '5' :"); + Console.WriteLine("---------------------------------"); + + foreach (var activity in db.ActivitiesSet.Where(a => a.StartTime == new TimeOnly(13, 00, 34) && a.Type == "Running" && a.Date == new DateOnly(2023, 01, 10) && a.EndTime == new TimeOnly(14, 00, 22) && a.EffortFelt == 5)) + { + Console.WriteLine($"\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'activité de temps '13:00:34' et de type 'Running' et de date '10/01/2023' et de temps de fin '14:00:22' et de ressenti d'effort '5' et de variabilité '0.5' :"); + Console.WriteLine("---------------------------------"); + + foreach (var activity in db.ActivitiesSet.Where(a => a.StartTime == new TimeOnly(13, 00, 34) && a.Type == "Running" && a.Date == new DateOnly(2023, 01, 10) && a.EndTime == new TimeOnly(14, 00, 22) && a.EffortFelt == 5 && a.Variability == 0.5F)) + { + Console.WriteLine($"\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'activité de temps '13:00:34' et de type 'Running' et de date '10/01/2023' et de temps de fin '14:00:22' et de ressenti d'effort '5' et de variabilité '0.5' et de variance '0.5' :"); + Console.WriteLine("---------------------------------"); + + foreach (var activity in db.ActivitiesSet.Where(a => a.StartTime == new TimeOnly(13, 00, 34) && a.Type == "Running" && a.Date == new DateOnly(2023, 01, 10) && a.EndTime == new TimeOnly(14, 00, 22) && a.EffortFelt == 5 && a.Variability == 0.5F && a.Variance == 0.5F)) + { + Console.WriteLine($"\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + Console.WriteLine("---------------------------------\n"); + } + + static void DataSourceTests(HeartTrackContext db) + { + Console.WriteLine("Accès à toutes les sources de données :"); + + Console.WriteLine("Sources de données :"); + Console.WriteLine("---------------------------------"); + + foreach (var dataSource in db.DataSourcesSet) + { + Console.WriteLine($"\t{dataSource.IdSource} - {dataSource.Type}, {dataSource.Model}, {dataSource.Precision}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la source de données d'id '2' :"); + Console.WriteLine("---------------------------------"); + + foreach (var dataSource in db.DataSourcesSet.Where(d => d.IdSource == 2)) + { + Console.WriteLine($"\t{dataSource.IdSource} - {dataSource.Type}, {dataSource.Model}, {dataSource.Precision}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la source de données de type 'Smartwatch' :"); + Console.WriteLine("---------------------------------"); + + foreach (var dataSource in db.DataSourcesSet.Where(d => d.Type == "Smartwatch")) + { + Console.WriteLine($"\t{dataSource.IdSource} - {dataSource.Type}, {dataSource.Model}, {dataSource.Precision}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la source de données de modèle 'Garmin' :"); + Console.WriteLine("---------------------------------"); + + foreach (var dataSource in db.DataSourcesSet.Where(d => d.Model == "Garmin")) + { + Console.WriteLine($"\t{dataSource.IdSource} - {dataSource.Type}, {dataSource.Model}, {dataSource.Precision}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la source de données de précision '0.5' :"); + Console.WriteLine("---------------------------------"); + + foreach (var dataSource in db.DataSourcesSet.Where(d => d.Precision == 0.5f)) + { + Console.WriteLine($"\t{dataSource.IdSource} - {dataSource.Type}, {dataSource.Model}, {dataSource.Precision}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la source de données de type 'Smartwatch' et de modèle 'Garmin' :"); + Console.WriteLine("---------------------------------"); + + foreach (var dataSource in db.DataSourcesSet.Where(d => d.Type == "Smartwatch" && d.Model == "Garmin")) + { + Console.WriteLine($"\t{dataSource.IdSource} - {dataSource.Type}, {dataSource.Model}, {dataSource.Precision}"); + } + + Console.WriteLine("---------------------------------\n"); + } + + static void HeartRateTests(HeartTrackContext db) + { + Console.WriteLine("Accès à toutes les fréquences cardiaques :"); + + Console.WriteLine("Fréquences cardiaques :"); + Console.WriteLine("---------------------------------"); + + foreach (var heartRate in db.HeartRatesSet) + { + Console.WriteLine($"\t{heartRate.IdHeartRate} - {heartRate.Altitude}, {heartRate.Time}, {heartRate.Temperature}, {heartRate.Bpm}, {heartRate.Longitude}, {heartRate.Latitude}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la fréquence cardiaque d'id '2' :"); + Console.WriteLine("---------------------------------"); + + foreach (var heartRate in db.HeartRatesSet.Where(h => h.IdHeartRate == 2)) + { + Console.WriteLine($"\t{heartRate.IdHeartRate} - {heartRate.Altitude}, {heartRate.Time}, {heartRate.Temperature}, {heartRate.Bpm}, {heartRate.Longitude}, {heartRate.Latitude}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la fréquence cardiaque d'altitude '10' :"); + Console.WriteLine("---------------------------------"); + + foreach (var heartRate in db.HeartRatesSet.Where(h => h.Altitude == 10)) + { + Console.WriteLine($"\t{heartRate.IdHeartRate} - {heartRate.Altitude}, {heartRate.Time}, {heartRate.Temperature}, {heartRate.Bpm}, {heartRate.Longitude}, {heartRate.Latitude}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la fréquence cardiaque de température '20.5' :"); + Console.WriteLine("---------------------------------"); + + foreach (var heartRate in db.HeartRatesSet.Where(h => h.Temperature == 20.5f)) + { + Console.WriteLine($"\t{heartRate.IdHeartRate} - {heartRate.Altitude}, {heartRate.Time}, {heartRate.Temperature}, {heartRate.Bpm}, {heartRate.Longitude}, {heartRate.Latitude}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la fréquence cardiaque de bpm '65' :"); + Console.WriteLine("---------------------------------"); + + foreach (var heartRate in db.HeartRatesSet.Where(h => h.Bpm == 65)) + { + Console.WriteLine($"\t{heartRate.IdHeartRate} - {heartRate.Altitude}, {heartRate.Time}, {heartRate.Temperature}, {heartRate.Bpm}, {heartRate.Longitude}, {heartRate.Latitude}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la fréquence cardiaque de longitude '35' :"); + Console.WriteLine("---------------------------------"); + + foreach (var heartRate in db.HeartRatesSet.Where(h => h.Longitude == 35)) + { + Console.WriteLine($"\t{heartRate.IdHeartRate} - {heartRate.Altitude}, {heartRate.Time}, {heartRate.Temperature}, {heartRate.Bpm}, {heartRate.Longitude}, {heartRate.Latitude}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la fréquence cardiaque de latitude '66' :"); + Console.WriteLine("---------------------------------"); + + foreach (var heartRate in db.HeartRatesSet.Where(h => h.Latitude == 66)) + { + Console.WriteLine($"\t{heartRate.IdHeartRate} - {heartRate.Altitude}, {heartRate.Time}, {heartRate.Temperature}, {heartRate.Bpm}, {heartRate.Longitude}, {heartRate.Latitude}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la fréquence cardiaque d'altitude '10' et de température '20.5' :"); + Console.WriteLine("---------------------------------"); + + foreach (var heartRate in db.HeartRatesSet.Where(h => h.Altitude == 10 && h.Temperature == 20.5f)) + { + Console.WriteLine($"\t{heartRate.IdHeartRate} - {heartRate.Altitude}, {heartRate.Time}, {heartRate.Temperature}, {heartRate.Bpm}, {heartRate.Longitude}, {heartRate.Latitude}"); + } + + Console.WriteLine("---------------------------------\n"); + } + + static void NotificationTests(HeartTrackContext db) + { + Console.WriteLine("Accès à toutes les notifications :"); + + Console.WriteLine("Notifications :"); + Console.WriteLine("---------------------------------"); + + foreach (var notification in db.NotificationsSet) + { + Console.WriteLine($"\t{notification.IdNotif} - {notification.Message}, {notification.Date}, {notification.Statut}, {notification.Urgence}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la notification d'id '2' :"); + Console.WriteLine("---------------------------------"); + + foreach (var notification in db.NotificationsSet.Where(n => n.IdNotif == 2)) + { + Console.WriteLine($"\t{notification.IdNotif} - {notification.Message}, {notification.Date}, {notification.Statut}, {notification.Urgence}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la notification de message 'You have a new activity to check' :"); + Console.WriteLine("---------------------------------"); + + foreach (var notification in db.NotificationsSet.Where(n => n.Message == "You have a new activity to check")) + { + Console.WriteLine($"\t{notification.IdNotif} - {notification.Message}, {notification.Date}, {notification.Statut}, {notification.Urgence}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la notification de date '25/12/2023' :"); + Console.WriteLine("---------------------------------"); + + foreach (var notification in db.NotificationsSet.Where(n => n.Date == new DateTime(2023, 12, 25, 13, 00, 40))) + { + Console.WriteLine($"\t{notification.IdNotif} - {notification.Message}, {notification.Date}, {notification.Statut}, {notification.Urgence}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la notification de statut 'true' :"); + Console.WriteLine("---------------------------------"); + + foreach (var notification in db.NotificationsSet.Where(n => n.Statut == true)) + { + Console.WriteLine($"\t{notification.IdNotif} - {notification.Message}, {notification.Date}, {notification.Statut}, {notification.Urgence}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la notification d'urgence 'A' :"); + Console.WriteLine("---------------------------------"); + + foreach (var notification in db.NotificationsSet.Where(n => n.Urgence == "A")) + { + Console.WriteLine($"\t{notification.IdNotif} - {notification.Message}, {notification.Date}, {notification.Statut}, {notification.Urgence}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la notification de message 'You have a new activity to check' et de date '25/12/2023' :"); + Console.WriteLine("---------------------------------"); + + foreach (var notification in db.NotificationsSet.Where(n => n.Message == "You have a new activity to check" && n.Date == new DateTime(2023, 12, 25, 13, 00, 40))) + { + Console.WriteLine($"\t{notification.IdNotif} - {notification.Message}, {notification.Date}, {notification.Statut}, {notification.Urgence}"); } Console.WriteLine("---------------------------------\n"); } -// /// -// /// Test d'ajout, de modification et de suppression de livres. -// /// -// /// Contexte de la base de données. -// static void AddUpdateDeleteOperations(LibraryContext db) -// { -// Console.WriteLine("Test d'ajout, de modification et de suppression :"); - -// // Ajout d'un nouveau livre -// var newBook = new BookEntity { Title = "Comment bien réussir son stage", Author = "Abdelfettah HASBANI", Isbn = "TheBest" }; -// // par defaut, l'Id en long est égale à zero et se mettre par la BDD -// db.BooksSet.Add(newBook); -// db.SaveChanges(); - -// // Affichage des livres après ajout -// Console.WriteLine("Livres après ajout :"); -// // .Include pour importer les personnes, ne pas le mettre si pas besoins de personnes -// foreach (var book in db.BooksSet.Include(b => b.Person)) -// { -// Console.WriteLine($"\t{book.Id}, {book.Title}, {book.Author}, {book.Isbn}, {book.Person?.FirstName} {book.Person?.LastName}"); -// } - -// // Modification du titre du nouveau livre -// newBook.Title = "Mes nouvelles dates de stage"; -// db.SaveChanges(); - -// // Affichage des livres après modification -// Console.WriteLine("Livres après modification :"); -// foreach (var book in db.BooksSet.Include(b => b.Person)) -// { -// Console.WriteLine($"\t{book.Id}, {book.Title}, {book.Author}, {book.Isbn}, {book.Person?.FirstName} {book.Person?.LastName}"); -// } - -// // Suppression du nouveau livre -// db.BooksSet.Remove(newBook); -// db.SaveChanges(); - -// // Affichage des livres après suppression -// Console.WriteLine("Livres après suppression :"); -// foreach (var book in db.BooksSet.Include(b => b.Person)) -// { -// Console.WriteLine($"\t{book.Id}, {book.Title}, {book.Author}, {book.Isbn}, {book.Person?.FirstName} {book.Person?.LastName}"); -// } -// } - -// /// -// /// Test d'emprunt et de retour de livre. -// /// -// /// Contexte de la base de données. -// static void BorrowAndReturnBook(LibraryContext db) -// { -// Console.WriteLine("Test d'emprunt et de retour de livre :"); -// var person = db.PersonsSet.FirstOrDefault(); -// var bookToBorrow = db.BooksSet.FirstOrDefault(); - -// // Retour du livre 1 -// if (bookToBorrow != null) -// { -// bookToBorrow.Person = null; -// db.SaveChanges(); -// } - -// // Affichage des livres après retour -// Console.WriteLine("Livres après retour :"); -// foreach (var book in db.BooksSet.Include(b => b.Person)) -// { -// Console.WriteLine($"\t{book.Id}, {book.Title}, {book.Author}, {book.Isbn}, {book.Person?.FirstName} {book.Person?.LastName}"); -// } - -// // Emprunt d'un livre par une personne existante -// if (person != null && bookToBorrow != null) -// { -// bookToBorrow.Person = person; -// db.SaveChanges(); -// } - -// // Affichage des livres après emprunt -// Console.WriteLine("Livres après emprunt :"); -// foreach (var book in db.BooksSet.Include(b => b.Person)) -// { -// Console.WriteLine($"\t{book.Id}, {book.Title}, {book.Author}, {book.Isbn}, {book.Person?.FirstName} {book.Person?.LastName}"); -// } -// } + static void StatisticTests(HeartTrackContext db) + { + Console.WriteLine("Accès à toutes les statistiques :"); + + Console.WriteLine("Statistiques :"); + Console.WriteLine("---------------------------------"); + + foreach (var statistic in db.StatisticsSet) + { + Console.WriteLine($"\t{statistic.IdStatistic} - {statistic.Weight}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}, {statistic.AverageCaloriesBurned}, {statistic.Date}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la statistique d'id '2' :"); + Console.WriteLine("---------------------------------"); + + foreach (var statistic in db.StatisticsSet.Where(s => s.IdStatistic == 2)) + { + Console.WriteLine($"\t{statistic.IdStatistic} - {statistic.Weight}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}, {statistic.AverageCaloriesBurned}, {statistic.Date}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la statistique de poids '60' :"); + Console.WriteLine("---------------------------------"); + + foreach (var statistic in db.StatisticsSet.Where(s => s.Weight == 60)) + { + Console.WriteLine($"\t{statistic.IdStatistic} - {statistic.Weight}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}, {statistic.AverageCaloriesBurned}, {statistic.Date}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la statistique de fréquence cardiaque moyenne '130' :"); + Console.WriteLine("---------------------------------"); + + foreach (var statistic in db.StatisticsSet.Where(s => s.AverageHeartRate == 130)) + { + Console.WriteLine($"\t{statistic.IdStatistic} - {statistic.Weight}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}, {statistic.AverageCaloriesBurned}, {statistic.Date}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la statistique de fréquence cardiaque maximale '190' :"); + Console.WriteLine("---------------------------------"); + + foreach (var statistic in db.StatisticsSet.Where(s => s.MaximumHeartRate == 190)) + { + Console.WriteLine($"\t{statistic.IdStatistic} - {statistic.Weight}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}, {statistic.AverageCaloriesBurned}, {statistic.Date}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la statistique de calories brûlées en moyenne '550' :"); + Console.WriteLine("---------------------------------"); + + foreach (var statistic in db.StatisticsSet.Where(s => s.AverageCaloriesBurned == 550)) + { + Console.WriteLine($"\t{statistic.IdStatistic} - {statistic.Weight}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}, {statistic.AverageCaloriesBurned}, {statistic.Date}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la statistique de date '30/12/2022' :"); + Console.WriteLine("---------------------------------"); + + foreach (var statistic in db.StatisticsSet.Where(s => s.Date == new DateOnly(2022, 12, 30))) + { + Console.WriteLine($"\t{statistic.IdStatistic} - {statistic.Weight}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}, {statistic.AverageCaloriesBurned}, {statistic.Date}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la statistique de poids '60' et de fréquence cardiaque moyenne '130' :"); + Console.WriteLine("---------------------------------"); + + foreach (var statistic in db.StatisticsSet.Where(s => s.Weight == 60 && s.AverageHeartRate == 130)) + { + Console.WriteLine($"\t{statistic.IdStatistic} - {statistic.Weight}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}, {statistic.AverageCaloriesBurned}, {statistic.Date}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la statistique de poids '60' et de fréquence cardiaque moyenne '130' et de fréquence cardiaque maximale '190' :"); + Console.WriteLine("---------------------------------"); + + foreach (var statistic in db.StatisticsSet.Where(s => s.Weight == 60 && s.AverageHeartRate == 130 && s.MaximumHeartRate == 190)) + { + Console.WriteLine($"\t{statistic.IdStatistic} - {statistic.Weight}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}, {statistic.AverageCaloriesBurned}, {statistic.Date}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la statistique de poids '60' et de fréquence cardiaque moyenne '130' et de fréquence cardiaque maximale '190' et de calories brûlées en moyenne '600' :"); + Console.WriteLine("---------------------------------"); + + foreach (var statistic in db.StatisticsSet.Where(s => s.Weight == 60 && s.AverageHeartRate == 130 && s.MaximumHeartRate == 190 && s.AverageCaloriesBurned == 600)) + { + Console.WriteLine($"\t{statistic.IdStatistic} - {statistic.Weight}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}, {statistic.AverageCaloriesBurned}, {statistic.Date}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la statistique de poids '60' et de fréquence cardiaque moyenne '130' et de fréquence cardiaque maximale '190' et de calories brûlées en moyenne '600' et de date '11/01/2021' :"); + Console.WriteLine("---------------------------------"); + + foreach (var statistic in db.StatisticsSet.Where(s => s.Weight == 60 && s.AverageHeartRate == 130 && s.MaximumHeartRate == 190 && s.AverageCaloriesBurned == 600 && s.Date == new DateOnly(2021, 01, 11))) + { + Console.WriteLine($"\t{statistic.IdStatistic} - {statistic.Weight}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}, {statistic.AverageCaloriesBurned}, {statistic.Date}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la statistique de poids '60' et de fréquence cardiaque moyenne '130' et de fréquence cardiaque maximale '190' et de calories brûlées en moyenne '600' et de date '11/01/2021' :"); + Console.WriteLine("---------------------------------"); + + foreach (var statistic in db.StatisticsSet.Where(s => s.Weight == 60 && s.AverageHeartRate == 130 && s.MaximumHeartRate == 190 && s.AverageCaloriesBurned == 600 && s.Date == new DateOnly(2021, 01, 11))) + { + Console.WriteLine($"\t{statistic.IdStatistic} - {statistic.Weight}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}, {statistic.AverageCaloriesBurned}, {statistic.Date}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la statistique de poids '60' et de fréquence cardiaque moyenne '130' et de fréquence cardiaque maximale '190' et de calories brûlées en moyenne '600' et de date '11/01/2021' :"); + Console.WriteLine("---------------------------------"); + + foreach (var statistic in db.StatisticsSet.Where(s => s.Weight == 60 && s.AverageHeartRate == 130 && s.MaximumHeartRate == 190 && s.AverageCaloriesBurned == 600 && s.Date == new DateOnly(2021, 01, 11))) + { + Console.WriteLine($"\t{statistic.IdStatistic} - {statistic.Weight}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}, {statistic.AverageCaloriesBurned}, {statistic.Date}"); + } + + Console.WriteLine("---------------------------------\n"); + } + static void TrainingTests(HeartTrackContext db) + { + Console.WriteLine("Accès à tout les entrainements :"); + + Console.WriteLine("Entrainements :"); + Console.WriteLine("---------------------------------"); + + foreach (var training in db.TrainingsSet) + { + Console.WriteLine($"\t{training.IdTraining} - {training.Date}, {training.Description}, {training.Latitude}, {training.Longitude}, {training.FeedBack}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'entrainement d'id '2' :"); + Console.WriteLine("---------------------------------"); + + foreach (var training in db.TrainingsSet.Where(t => t.IdTraining == 2)) + { + Console.WriteLine($"\t{training.IdTraining} - {training.Date}, {training.Description}, {training.Latitude}, {training.Longitude}, {training.FeedBack}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'entrainement de date '21/02/2024' :"); + Console.WriteLine("---------------------------------"); + + foreach (var training in db.TrainingsSet.Where(t => t.Date == new DateOnly(2024, 02, 21))) + { + Console.WriteLine($"\t{training.IdTraining} - {training.Date}, {training.Description}, {training.Latitude}, {training.Longitude}, {training.FeedBack}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'entrainement de description 'Running' :"); + Console.WriteLine("---------------------------------"); + + foreach (var training in db.TrainingsSet.Where(t => t.Description == "Running")) + { + Console.WriteLine($"\t{training.IdTraining} - {training.Date}, {training.Description}, {training.Latitude}, {training.Longitude}, {training.FeedBack}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'entrainement de latitude '48.8566f' :"); + Console.WriteLine("---------------------------------"); + + foreach (var training in db.TrainingsSet.Where(t => t.Latitude == 48.8566f)) + { + Console.WriteLine($"\t{training.IdTraining} - {training.Date}, {training.Description}, {training.Latitude}, {training.Longitude}, {training.FeedBack}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'entrainement de longitude '2.3522f' :"); + Console.WriteLine("---------------------------------"); + + foreach (var training in db.TrainingsSet.Where(t => t.Longitude == 2.3522f)) + { + Console.WriteLine($"\t{training.IdTraining} - {training.Date}, {training.Description}, {training.Latitude}, {training.Longitude}, {training.FeedBack}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'entrainement de feedback 'Good' :"); + Console.WriteLine("---------------------------------"); + + foreach (var training in db.TrainingsSet.Where(t => t.FeedBack == "Good")) + { + Console.WriteLine($"\t{training.IdTraining} - {training.Date}, {training.Description}, {training.Latitude}, {training.Longitude}, {training.FeedBack}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'entrainement de date '20/02/2024' et de description 'Cycling' :"); + Console.WriteLine("---------------------------------"); + + foreach (var training in db.TrainingsSet.Where(t => t.Date == new DateOnly(2024, 02, 20) && t.Description == "Cycling")) + { + Console.WriteLine($"\t{training.IdTraining} - {training.Date}, {training.Description}, {training.Latitude}, {training.Longitude}, {training.FeedBack}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'entrainement de date '22/02/2024' et de description 'Running' et de latitude '48.8566f' :"); + Console.WriteLine("---------------------------------"); + + foreach (var training in db.TrainingsSet.Where(t => t.Date == new DateOnly(2024, 02, 22) && t.Description == "Running" && t.Latitude == 48.8566f)) + { + Console.WriteLine($"\t{training.IdTraining} - {training.Date}, {training.Description}, {training.Latitude}, {training.Longitude}, {training.FeedBack}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'entrainement de date '23/02/2024' et de description 'Cycling' et de latitude '48.8566f' et de longitude '2.3522f' :"); + Console.WriteLine("---------------------------------"); + + foreach (var training in db.TrainingsSet.Where(t => t.Date == new DateOnly(2024, 02, 23) && t.Description == "Cycling" && t.Latitude == 48.8566f && t.Longitude == 2.3522f)) + { + Console.WriteLine($"\t{training.IdTraining} - {training.Date}, {training.Description}, {training.Latitude}, {training.Longitude}, {training.FeedBack}"); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'entrainement de date '19/01/2024' et de description 'Running' et de latitude '48.8566f' et de longitude '2.3522f' et de feedback 'Good' :"); + Console.WriteLine("---------------------------------"); + + foreach (var training in db.TrainingsSet.Where(t => t.Date == new DateOnly(2024, 01, 19) && t.Description == "Running" && t.Latitude == 48.8566f && t.Longitude == 2.3522f && t.FeedBack == "Good")) + { + Console.WriteLine($"\t{training.IdTraining} - {training.Date}, {training.Description}, {training.Latitude}, {training.Longitude}, {training.FeedBack}"); + } + + Console.WriteLine("---------------------------------\n"); + } + + static void AddUpdateDeleteAthlete(HeartTrackContext db) + { + Console.WriteLine("Test d'ajout, de modification et de suppression des athletes :"); + var picture = "https://davidalmeida.site/assets/me_avatar.f77af006.png"; + // Ajout d'un nouveau livre + var newAthlete = new AthleteEntity { Username = "Doe", LastName = "Doe",ProfilPicture = picture,FirstName = "John", Email = "essaie.example.com", Password = "TheNewPassword", Sexe = "M", Length = 1.80, Weight = 90, DateOfBirth = new DateOnly(2024, 02, 22), IsCoach = false }; + db.AthletesSet.Add(newAthlete); + db.SaveChanges(); + + // Affichage des livres après ajout + Console.WriteLine("Athlete après ajout :"); + foreach (var athlete in db.AthletesSet) + { + Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + } + + // Modification du titre du nouveau livre + newAthlete.Email = "email.example@exemple.com"; + db.SaveChanges(); + + // Affichage des livres après modification + Console.WriteLine("Livres après modification :"); + foreach (var athlete in db.AthletesSet) + { + Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + } + + // Suppression du nouveau livre + db.AthletesSet.Remove(newAthlete); + db.SaveChanges(); + + // Affichage des livres après suppression + Console.WriteLine("Livres après suppression :"); + foreach (var athlete in db.AthletesSet) + { + Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.Username}, {athlete.LastName}, {athlete.FirstName}, {athlete.Email}, {athlete.Sexe}, {athlete.Length}, {athlete.Weight}, {athlete.DateOfBirth}, {athlete.IsCoach}"); + } + } + + static void AddUpdateDeleteActivity(HeartTrackContext db) + { + Console.WriteLine("Test d'ajout, de modification et de suppression des activités :"); + + var newActivity = new ActivityEntity { Type = "Running", Date = new DateOnly(2022, 02, 22), StartTime = new TimeOnly(12, 01, 38), EndTime = new TimeOnly(13, 45, 58), EffortFelt = 5, Variability = 10, Variance = 20, StandardDeviation = 30, Average = 40, Maximum = 50, Minimum = 60, AverageTemperature = 70, HasAutoPause = false }; + db.ActivitiesSet.Add(newActivity); + db.SaveChanges(); + + Console.WriteLine("Activité après ajout :"); + foreach (var activity in db.ActivitiesSet) + { + Console.WriteLine($"\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + newActivity.Type = "Cycling"; + db.SaveChanges(); + + Console.WriteLine("Activité après modification :"); + foreach (var activity in db.ActivitiesSet) + { + Console.WriteLine($"\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + db.ActivitiesSet.Remove(newActivity); + db.SaveChanges(); + + Console.WriteLine("Activité après suppression :"); + foreach (var activity in db.ActivitiesSet) + { + Console.WriteLine($"\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + } + + static void AddUpdateDeleteDataSource(HeartTrackContext db) + { + Console.WriteLine("Test d'ajout, de modification et de suppression des sources de données :"); + + var newDataSource = new DataSourceEntity { Type = "Polar", Model = "Polar Vantage V2", Precision = 0.5F }; + db.DataSourcesSet.Add(newDataSource); + db.SaveChanges(); + + Console.WriteLine("Source de données après ajout :"); + foreach (var dataSource in db.DataSourcesSet) + { + Console.WriteLine($"\t{dataSource.IdSource} - {dataSource.Type}, {dataSource.Model}, {dataSource.Precision}"); + } + + newDataSource.Type = "Garmin"; + db.SaveChanges(); + + Console.WriteLine("Source de données après modification :"); + foreach (var dataSource in db.DataSourcesSet) + { + Console.WriteLine($"\t{dataSource.IdSource} - {dataSource.Type}, {dataSource.Model}, {dataSource.Precision}"); + } + + db.DataSourcesSet.Remove(newDataSource); + db.SaveChanges(); + + Console.WriteLine("Source de données après suppression :"); + foreach (var dataSource in db.DataSourcesSet) + { + Console.WriteLine($"\t{dataSource.IdSource} - {dataSource.Type}, {dataSource.Model}, {dataSource.Precision}"); + } + } + + static void AddUpdateDeleteHeartRate(HeartTrackContext db) + { + Console.WriteLine("Test d'ajout, de modification et de suppression des fréquences cardiaques :"); + + var newHeartRate = new HeartRateEntity { Altitude = 100, Time = new TimeOnly(12, 00, 00), Temperature = 20, Bpm = 150, Longitude = 0, Latitude = 0 }; + db.HeartRatesSet.Add(newHeartRate); + db.SaveChanges(); + + Console.WriteLine("Fréquence cardiaque après ajout :"); + foreach (var heartRate in db.HeartRatesSet) + { + Console.WriteLine($"\t{heartRate.IdHeartRate} - {heartRate.Altitude}, {heartRate.Time}, {heartRate.Temperature}, {heartRate.Bpm}, {heartRate.Longitude}, {heartRate.Latitude}"); + } + + newHeartRate.Altitude = 200; + db.SaveChanges(); + + Console.WriteLine("Fréquence cardiaque après modification :"); + foreach (var heartRate in db.HeartRatesSet) + { + Console.WriteLine($"\t{heartRate.IdHeartRate} - {heartRate.Altitude}, {heartRate.Time}, {heartRate.Temperature}, {heartRate.Bpm}, {heartRate.Longitude}, {heartRate.Latitude}"); + } + + db.HeartRatesSet.Remove(newHeartRate); + db.SaveChanges(); + + Console.WriteLine("Fréquence cardiaque après suppression :"); + foreach (var heartRate in db.HeartRatesSet) + { + Console.WriteLine($"\t{heartRate.IdHeartRate} - {heartRate.Altitude}, {heartRate.Time}, {heartRate.Temperature}, {heartRate.Bpm}, {heartRate.Longitude}, {heartRate.Latitude}"); + } + } + + static void AddUpdateDeleteNotification(HeartTrackContext db) + { + Console.WriteLine("Test d'ajout, de modification et de suppression des notifications :"); + + var newNotification = new NotificationEntity { Message = "Message de test", Date = new DateTime(2022, 01, 01), Statut = false, Urgence = "Urgent" }; + db.NotificationsSet.Add(newNotification); + db.SaveChanges(); + + Console.WriteLine("Notification après ajout :"); + foreach (var notification in db.NotificationsSet) + { + Console.WriteLine($"\t{notification.IdNotif} - {notification.Message}, {notification.Date}, {notification.Statut}, {notification.Urgence}"); + } + + newNotification.Message = "Nouveau message de test"; + db.SaveChanges(); + + Console.WriteLine("Notification après modification :"); + foreach (var notification in db.NotificationsSet) + { + Console.WriteLine($"\t{notification.IdNotif} - {notification.Message}, {notification.Date}, {notification.Statut}, {notification.Urgence}"); + } + + db.NotificationsSet.Remove(newNotification); + db.SaveChanges(); + + Console.WriteLine("Notification après suppression :"); + foreach (var notification in db.NotificationsSet) + { + Console.WriteLine($"\t{notification.IdNotif} - {notification.Message}, {notification.Date}, {notification.Statut}, {notification.Urgence}"); + } + } + + static void AddUpdateDeleteStatistic(HeartTrackContext db) + { + Console.WriteLine("Test d'ajout, de modification et de suppression des statistiques :"); + + var newStatistic = new StatisticEntity { Weight = 80, AverageHeartRate = 150, MaximumHeartRate = 180, AverageCaloriesBurned = 500, Date = new DateOnly(2022, 01, 01) }; + db.StatisticsSet.Add(newStatistic); + db.SaveChanges(); + + Console.WriteLine("Statistique après ajout :"); + foreach (var statistic in db.StatisticsSet) + { + Console.WriteLine($"\t{statistic.IdStatistic} - {statistic.Weight}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}, {statistic.AverageCaloriesBurned}, {statistic.Date}"); + } + + newStatistic.Weight = 90; + db.SaveChanges(); + + Console.WriteLine("Statistique après modification :"); + foreach (var statistic in db.StatisticsSet) + { + Console.WriteLine($"\t{statistic.IdStatistic} - {statistic.Weight}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}, {statistic.AverageCaloriesBurned}, {statistic.Date}"); + } + + db.StatisticsSet.Remove(newStatistic); + db.SaveChanges(); + + Console.WriteLine("Statistique après suppression :"); + foreach (var statistic in db.StatisticsSet) + { + Console.WriteLine($"\t{statistic.IdStatistic} - {statistic.Weight}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}, {statistic.AverageCaloriesBurned}, {statistic.Date}"); + } + } + + static void AddUpdateDeleteTraining(HeartTrackContext db) + { + Console.WriteLine("Test d'ajout, de modification et de suppression des entrainements :"); + + var newTraining = new TrainingEntity { Date = new DateOnly(2022, 01, 01), Description = "Entrainement de test", Latitude = 0, Longitude = 0, FeedBack = "Bon entrainement" }; + db.TrainingsSet.Add(newTraining); + db.SaveChanges(); + + Console.WriteLine("Entrainement après ajout :"); + foreach (var training in db.TrainingsSet) + { + Console.WriteLine($"\t{training.IdTraining} - {training.Date}, {training.Description}, {training.Latitude}, {training.Longitude}, {training.FeedBack}"); + } + + newTraining.Description = "Nouvel entrainement de test"; + db.SaveChanges(); + + Console.WriteLine("Entrainement après modification :"); + foreach (var training in db.TrainingsSet) + { + Console.WriteLine($"\t{training.IdTraining} - {training.Date}, {training.Description}, {training.Latitude}, {training.Longitude}, {training.FeedBack}"); + } + + db.TrainingsSet.Remove(newTraining); + db.SaveChanges(); + + Console.WriteLine("Entrainement après suppression :"); + foreach (var training in db.TrainingsSet) + { + Console.WriteLine($"\t{training.IdTraining} - {training.Date}, {training.Description}, {training.Latitude}, {training.Longitude}, {training.FeedBack}"); + } + } } \ No newline at end of file diff --git a/src/Tests/ConsoleTestEntities/uca.HeartTrack.db b/src/Tests/ConsoleTestEntities/uca.HeartTrack.db deleted file mode 100644 index 1895d72..0000000 Binary files a/src/Tests/ConsoleTestEntities/uca.HeartTrack.db and /dev/null differ diff --git a/src/Tests/ConsoleTestRelationships/ConsoleTestRelationships.csproj b/src/Tests/ConsoleTestRelationships/ConsoleTestRelationships.csproj index 206b89a..10252ee 100644 --- a/src/Tests/ConsoleTestRelationships/ConsoleTestRelationships.csproj +++ b/src/Tests/ConsoleTestRelationships/ConsoleTestRelationships.csproj @@ -1,5 +1,10 @@  + + + + + Exe net8.0 diff --git a/src/Tests/ConsoleTestRelationships/Program.cs b/src/Tests/ConsoleTestRelationships/Program.cs index 83fa4f4..fa9797e 100644 --- a/src/Tests/ConsoleTestRelationships/Program.cs +++ b/src/Tests/ConsoleTestRelationships/Program.cs @@ -1,2 +1,280 @@ -// See https://aka.ms/new-console-template for more information -Console.WriteLine("Hello, World!"); + +using DbContextLib; +using Entities; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; +using StubbedContextLib; +namespace ConsoleTestRelationships; +class Program +{ + static void Main(string[] args) + { + + try { + var options = new DbContextOptionsBuilder() + .UseSqlite("Data Source=uca.HeartTrack.db") + .Options; + + using (HeartTrackContext db = new TrainingStubbedContext(options)) + { + db.Database.EnsureCreated(); + ActivityTests(db); + + DataSourceTests(db); + + AthleteTests(db); + + FriendshipTests(db); + } + } + catch (Exception ex) + { + Console.WriteLine($"Une erreur s'est produite : {ex.Message}"); + } + } + static void ActivityTests(HeartTrackContext db) + { + Console.WriteLine("Accès à toutes les activités avec leurs fréquences cardiaques :"); + + Console.WriteLine("Activités :"); + Console.WriteLine("---------------------------------"); + + foreach (var activity in db.ActivitiesSet.Include(a => a.HeartRates)) + { + Console.WriteLine($"\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + + Console.WriteLine("\t\tFréquences cardiaques :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var heartRate in activity.HeartRates) + { + Console.WriteLine($"\t\t\t{heartRate.IdHeartRate} - {heartRate.Altitude}, {heartRate.Time}, {heartRate.Temperature}, {heartRate.Bpm}, {heartRate.Longitude}, {heartRate.Latitude}"); + } + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'activité d'id '2' :"); + Console.WriteLine("---------------------------------"); + + foreach (var activity in db.ActivitiesSet.Where(a => a.IdActivity == 2).Include(a => a.HeartRates)) + { + Console.WriteLine($"\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + + Console.WriteLine("\t\tFréquences cardiaques :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var heartRate in activity.HeartRates) + { + Console.WriteLine($"\t\t\t{heartRate.IdHeartRate} - {heartRate.Altitude}, {heartRate.Time}, {heartRate.Temperature}, {heartRate.Bpm}, {heartRate.Longitude}, {heartRate.Latitude}"); + } + } + } + + static void DataSourceTests(HeartTrackContext db) + { + Console.WriteLine("Accès à toutes les sources de données avec leurs activités :"); + + Console.WriteLine("Sources de données :"); + Console.WriteLine("---------------------------------"); + + foreach (var dataSource in db.DataSourcesSet.Include(ds => ds.Activities).Include(ds => ds.Athletes)) + { + Console.WriteLine($"\t{dataSource.IdSource} - {dataSource.Model}"); + + Console.WriteLine("\t\tActivités :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var activity in dataSource.Activities) + { + Console.WriteLine($"\t\t\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + Console.WriteLine("\t\tAthletes :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var athlete in dataSource.Athletes) + { + Console.WriteLine($"\t\t\t{athlete.IdAthlete} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); + } + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à la source de données d'id '2' :"); + Console.WriteLine("---------------------------------"); + + foreach (var dataSource in db.DataSourcesSet.Where(ds => ds.IdSource == 2).Include(ds => ds.Activities).Include(ds => ds.Athletes)) + { + Console.WriteLine($"\t{dataSource.IdSource} - {dataSource.Model}"); + + Console.WriteLine("\t\tActivités :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var activity in dataSource.Activities) + { + Console.WriteLine($"\t\t\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + Console.WriteLine("\t\tAthletes :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var athlete in dataSource.Athletes) + { + Console.WriteLine($"\t\t\t{athlete.IdAthlete} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); + } + } + + Console.WriteLine("---------------------------------\n"); + } + + static void AthleteTests(HeartTrackContext db) + { + Console.WriteLine("Accès à tous les athlètes avec leurs statistiques :"); + + Console.WriteLine("Athlètes :"); + Console.WriteLine("---------------------------------"); + + foreach (var athlete in db.AthletesSet.Include(a => a.Statistics).Include(a => a.Activities).Include(a => a.TrainingsAthlete).Include(a => a.NotificationsSent).Include(a => a.DataSource).Include(a => a.TrainingsCoach).Include(a => a.NotificationsReceived)) + { + Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); + + Console.WriteLine("\t\tStatistiques :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var statistic in athlete.Statistics) + { + Console.WriteLine($"\t\t\t{statistic.IdStatistic} - {statistic.Date}, {statistic.AverageCaloriesBurned}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}"); + } + + Console.WriteLine("\t\tActivités :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var activity in athlete.Activities) + { + Console.WriteLine($"\t\t\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + Console.WriteLine("\t\tEntraînements :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var training in athlete.TrainingsAthlete) + { + Console.WriteLine($"\t\t\t{training.IdTraining} - {training.Date}, {training.Latitude}, {training.Longitude}, {training.Description}, {training.FeedBack}"); + } + + Console.WriteLine("\t\tEntrainements données :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var training in athlete.TrainingsCoach) + { + Console.WriteLine($"\t\t\t{training.IdTraining} - {training.Date}, {training.Latitude}, {training.Longitude}, {training.Description}, {training.FeedBack}"); + } + + Console.WriteLine("\t\tNotifications reçus :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var notification in athlete.NotificationsReceived) + { + Console.WriteLine($"\t\t\t{notification.IdNotif} - {notification.Date}, {notification.Statut}, {notification.Message}"); + } + + Console.WriteLine("\t\tNotifications données :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var notification in athlete.NotificationsSent) + { + Console.WriteLine($"\t\t\t{notification.IdNotif} - {notification.Date}, {notification.Statut}, {notification.Message}"); + } + + Console.WriteLine("\t\tSources de données :"); + Console.WriteLine("\t\t---------------------------------"); + + Console.WriteLine("\t\t\t" + (athlete.DataSource?.Model ?? "Aucune source de données")); + } + + Console.WriteLine("---------------------------------\n"); + + Console.WriteLine("Accès à l'athlète d'id '2' :"); + Console.WriteLine("---------------------------------"); + + foreach (var athlete in db.AthletesSet.Where(a => a.IdAthlete == 2).Include(a => a.Statistics).Include(a => a.Activities).Include(a => a.TrainingsAthlete).Include(a => a.NotificationsSent).Include(a => a.DataSource).Include(a => a.TrainingsCoach).Include(a => a.NotificationsReceived)) + { + Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); + + Console.WriteLine("\t\tStatistiques :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var statistic in athlete.Statistics) + { + Console.WriteLine($"\t\t\t{statistic.IdStatistic} - {statistic.Date}, {statistic.AverageCaloriesBurned}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}"); + } + + Console.WriteLine("\t\tActivités :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var activity in athlete.Activities) + { + Console.WriteLine($"\t\t\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + Console.WriteLine("\t\tEntraînements :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var training in athlete.TrainingsAthlete) + { + Console.WriteLine($"\t\t\t{training.IdTraining} - {training.Date}, {training.Latitude}, {training.Longitude}, {training.Description}, {training.FeedBack}"); + } + + Console.WriteLine("\t\tEntrainements données :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var training in athlete.TrainingsCoach) + { + Console.WriteLine($"\t\t\t{training.IdTraining} - {training.Date}, {training.Latitude}, {training.Longitude}, {training.Description}, {training.FeedBack}"); + } + + Console.WriteLine("\t\tNotifications reçus :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var notification in athlete.NotificationsReceived) + { + Console.WriteLine($"\t\t\t{notification.IdNotif} - {notification.Date}, {notification.Statut}, {notification.Message}"); + } + + Console.WriteLine("\t\tNotifications données :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var notification in athlete.NotificationsSent) + { + Console.WriteLine($"\t\t\t{notification.IdNotif} - {notification.Date}, {notification.Statut}, {notification.Message}"); + } + + Console.WriteLine("\t\tSources de données :"); + Console.WriteLine("\t\t---------------------------------"); + + Console.WriteLine("\t\t\t" + (athlete.DataSource?.Model ?? "Aucune source de données")); + } + + Console.WriteLine("---------------------------------\n"); + } + + static void FriendshipTests(HeartTrackContext db) + { + Console.WriteLine("Accès à toutes les amitiés :"); + + Console.WriteLine("Amitiés :"); + Console.WriteLine("---------------------------------"); + + foreach (var athlete in db.AthletesSet.Include(f => f.Followers).Include(f => f.Followings)) + { + Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); + + Console.WriteLine($""); + Console.WriteLine($""); + + Console.WriteLine($"\t\t{athlete.Followers.Aggregate("", (seed, kvp) => $"{seed} [{kvp.FollowerId} ; {kvp.FollowingId} ; {kvp.StartDate.ToString("dd/MM/yyyy hh:mm:ss")}]")}"); + } + } +} \ No newline at end of file diff --git a/src/Tests/TestApi/GlobalUsings.cs b/src/Tests/TestApi/GlobalUsings.cs new file mode 100644 index 0000000..ab67c7e --- /dev/null +++ b/src/Tests/TestApi/GlobalUsings.cs @@ -0,0 +1 @@ +global using Microsoft.VisualStudio.TestTools.UnitTesting; \ No newline at end of file diff --git a/src/Tests/TestApi/TestApi.csproj b/src/Tests/TestApi/TestApi.csproj new file mode 100644 index 0000000..719074b --- /dev/null +++ b/src/Tests/TestApi/TestApi.csproj @@ -0,0 +1,26 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + diff --git a/src/Tests/TestApi/UserControllerTest.cs b/src/Tests/TestApi/UserControllerTest.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/Tests/TestConsoleApi/Class1.cs b/src/Tests/TestConsoleApi/Class1.cs new file mode 100644 index 0000000..0b0d5dc --- /dev/null +++ b/src/Tests/TestConsoleApi/Class1.cs @@ -0,0 +1,5 @@ +namespace TestConsoleApi; + +public class Class1 +{ +} \ No newline at end of file diff --git a/src/Tests/TestConsoleApi/TestConsoleApi.csproj b/src/Tests/TestConsoleApi/TestConsoleApi.csproj new file mode 100644 index 0000000..3a63532 --- /dev/null +++ b/src/Tests/TestConsoleApi/TestConsoleApi.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/src/Tests/TestsAPI/ClientTests/ClientTests.csproj b/src/Tests/TestsAPI/ClientTests/ClientTests.csproj new file mode 100644 index 0000000..206b89a --- /dev/null +++ b/src/Tests/TestsAPI/ClientTests/ClientTests.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/src/Tests/TestsAPI/ClientTests/HttpClientManager.cs b/src/Tests/TestsAPI/ClientTests/HttpClientManager.cs new file mode 100644 index 0000000..2e8e593 --- /dev/null +++ b/src/Tests/TestsAPI/ClientTests/HttpClientManager.cs @@ -0,0 +1,12 @@ +namespace ClientTests; + +public class HttpClientManager +{ + protected readonly HttpClient _httpClient; + + public HttpClientManager(HttpClient httpClient) + { + _httpClient = httpClient; + _httpClient.BaseAddress = new Uri("https://localhost:7252"); + } +} diff --git a/src/Tests/TestsAPI/ClientTests/Program.cs b/src/Tests/TestsAPI/ClientTests/Program.cs new file mode 100644 index 0000000..83fa4f4 --- /dev/null +++ b/src/Tests/TestsAPI/ClientTests/Program.cs @@ -0,0 +1,2 @@ +// See https://aka.ms/new-console-template for more information +Console.WriteLine("Hello, World!"); diff --git a/src/Tests/TestsAPI/UnitTestApi/Controllers/UsersControllerTest.cs b/src/Tests/TestsAPI/UnitTestApi/Controllers/UsersControllerTest.cs new file mode 100644 index 0000000..0a5eb52 --- /dev/null +++ b/src/Tests/TestsAPI/UnitTestApi/Controllers/UsersControllerTest.cs @@ -0,0 +1,225 @@ +using APIMappers; +using Dto; +using HeartTrackAPI.Controllers; +using HeartTrackAPI.Request; +using HeartTrackAPI.Responce; +using JetBrains.Annotations; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging.Abstractions; +using Model; +using Model.Manager; +using Model.Repository; +using Moq; +using Shared; +using StubAPI; + +namespace UnitTestApi.Controllers; + +[TestClass] +[TestSubject(typeof(UsersController))] +public class UsersControllerTest +{ + private Mock _dataManagerMock; + private IDataManager _dataManager; + private UsersController _usersController; + + private readonly List _users = + [ + new User + { + Id = 1, Username = "DoeDoe", + ProfilePicture = + "https://images.unsplash.com/photo-1682687982134-2ac563b2228b?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + FirstName = "John", LastName = "Doe", + Sexe = "M", Lenght = 180, Weight = 70, DateOfBirth = new DateTime(1990, 1, 1), + Email = "john.doe@example.com", Role = new Athlete() + }, + + new User + { + Id = 2, Username = "SmithSmith", + ProfilePicture = + "https://images.unsplash.com/photo-1709507779917-242b560288be?q=80&w=2080&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + FirstName = "Jane", LastName = "Smith", + Sexe = "F", Lenght = 170, Weight = 60, DateOfBirth = new DateTime(1992, 2, 2), + Email = "athlete2@example.com", Role = new Coach() + }, + + new User + { + Id = 3, Username = "Athlete3", + ProfilePicture = + "https://plus.unsplash.com/premium_photo-1705091981693-6006f8a20479?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + FirstName = "First3", LastName = "Last3", + Sexe = "M", Lenght = 190, Weight = 80, DateOfBirth = new DateTime(1994, 3, 3), Email = "ath@ex.fr", + Role = new Athlete() + } + ]; + + [TestInitialize] + public void SetUp() + { + _dataManagerMock = new Mock(); + + _dataManagerMock.Setup(dm => dm.UserRepo.GetNbItems()).ReturnsAsync(_users.Count); + _dataManagerMock.Setup(dm => + dm.UserRepo.GetUsers(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny())).ReturnsAsync( + (int index, int count, AthleteOrderCriteria criteria, bool descending) => + _users.GetItemsWithFilterAndOrdering(c => true, index, count, + criteria != AthleteOrderCriteria.None ? criteria : null, descending) + ); + + + + _usersController = new UsersController(new NullLogger(), _dataManagerMock.Object); + } +/* + [TestInitialize] + public void SetUp() + { + _dataManager = new StubData(); + _usersController = new UsersController(new NullLogger(), _dataManager); + }*/ + + + [TestMethod] + public async Task Get_ReturnsPageResponse_WhenRequestIsValid() + { + + var request = new PageRequest + { + Index = 0, + Count = 3, + OrderingPropertyName = "Id", + Descending = false + }; + + // Act + var result = await _usersController.Get(request); + Assert.IsInstanceOfType(result.Result, typeof(OkObjectResult)); + var okResult = result.Result as OkObjectResult; + // Assert + Assert.IsNotNull(okResult); + Assert.IsInstanceOfType(okResult.Value, typeof(PageResponse)); + var pageResponse = okResult.Value as PageResponse; + Assert.IsNotNull(pageResponse); + Assert.AreEqual(3, pageResponse.Items.Count()); + Assert.AreEqual(3, pageResponse.Total); + Assert.AreEqual(0, pageResponse.Index); + Assert.AreEqual(3, pageResponse.Count); + Assert.AreEqual(3, pageResponse.Count); + } + + [DataTestMethod] + [DataRow(0, 2, "Id", false, 2)] + [DataRow(1, 1, "Id", false, 1)] + [DataRow(0, 3, "Id", true, 3)] + public async Task Get_ReturnsCorrectPaginationAndOrdering(int index, int count, string orderingProperty, + bool descending, int expectedItemCount) + { + + var request = new PageRequest + { + Index = index, + Count = count, + OrderingPropertyName = orderingProperty, + Descending = descending + }; + // Act + var result = await _usersController.Get(request); + Assert.IsInstanceOfType(result.Result, typeof(OkObjectResult)); + var okResult = result.Result as OkObjectResult; + // Assert + Assert.IsNotNull(okResult); + Assert.IsInstanceOfType(okResult.Value, typeof(PageResponse)); + var pageResponse = okResult.Value as PageResponse; + Assert.IsNotNull(pageResponse); + Assert.AreEqual(expectedItemCount, pageResponse.Items.Count()); + } + + [TestMethod] + public async Task Get_ReturnsInternalServerError_OnException() + { + _dataManagerMock.Setup(dm => + dm.UserRepo.GetUsers(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny())) + .ThrowsAsync(new Exception("Simulated database failure.")); + + var request = new PageRequest { Index = 0, Count = 3 }; + + var result = await _usersController.Get(request); + + Assert.IsInstanceOfType(result.Result, typeof(ObjectResult)); + var objectResult = result.Result as ObjectResult; + Assert.AreEqual(500, objectResult.StatusCode); + } + + + + [TestMethod] + public async Task GetById_ReturnsUserDto_WhenRequestIsValid() + { + + var id = 1; + _dataManagerMock.Setup(dm => dm.UserRepo.GetItemById(id)).ReturnsAsync(_users.First(x => x.Id == id)); + + // Act + var result = await _usersController.GetById(id) ; + Assert.IsInstanceOfType(result.Result, typeof(OkObjectResult)); + var okResult = result.Result as OkObjectResult; + + // Assert + Assert.IsNotNull(okResult); + var resultObject = result.Result as OkObjectResult; + Assert.IsNotNull(resultObject); + Assert.IsInstanceOfType(resultObject.Value, typeof(UserDto)); + var user = resultObject.Value as UserDto; + Assert.IsNotNull(user); + var tmp = _users.First(x => x.Id == id).ToDto(); + Assert.AreEqual(tmp.Id, user.Id); + } + + [TestMethod] + public async Task GetById_ReturnsUserDto_WhenRequestUserDoesNotExist() + { + + var id = 0; + _dataManagerMock.Setup(dm => dm.UserRepo.GetItemById(id)).ReturnsAsync((User)null!); + + // Act + var result = await _usersController.GetById(id) ; + + // Assert + Assert.IsInstanceOfType(result.Result, typeof(NotFoundObjectResult)); + } + + + [TestMethod] + public async Task GetById_Returns404_WhenIdIsInvalid() + { + + var id = -2; + + // Act + var result = await _usersController.GetById(id); + + // Assert + Assert.IsInstanceOfType(result.Result, typeof(NotFoundObjectResult)); + } + + + [TestMethod] + public async Task Count_ReturnsInt_WhenRequestIsValid() + { + // Act + var result = await _usersController.Count(); + Assert.IsNotNull(result); + result = result.Result as OkObjectResult; + + // Assert + Assert.IsNotNull(result); + Assert.IsInstanceOfType(result.Value, typeof(int)); + } + +} \ No newline at end of file diff --git a/src/Tests/TestsAPI/UnitTestApi/GlobalUsings.cs b/src/Tests/TestsAPI/UnitTestApi/GlobalUsings.cs new file mode 100644 index 0000000..ab67c7e --- /dev/null +++ b/src/Tests/TestsAPI/UnitTestApi/GlobalUsings.cs @@ -0,0 +1 @@ +global using Microsoft.VisualStudio.TestTools.UnitTesting; \ No newline at end of file diff --git a/src/Tests/TestsAPI/UnitTestApi/UnitTestApi.csproj b/src/Tests/TestsAPI/UnitTestApi/UnitTestApi.csproj new file mode 100644 index 0000000..9931d8b --- /dev/null +++ b/src/Tests/TestsAPI/UnitTestApi/UnitTestApi.csproj @@ -0,0 +1,26 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + diff --git a/src/Tests/UnitTestsEntities/ActivityEntityTests.cs b/src/Tests/UnitTestsEntities/ActivityEntityTests.cs new file mode 100644 index 0000000..9705e38 --- /dev/null +++ b/src/Tests/UnitTestsEntities/ActivityEntityTests.cs @@ -0,0 +1,223 @@ +namespace UnitTestsEntities; +using Xunit; +using System.Linq; +using Entities; +using Microsoft.EntityFrameworkCore; +using StubbedContextLib; +using Microsoft.Data.Sqlite; + +public class ActivityEntityTests (DatabaseFixture fixture) : IClassFixture +{ + [Fact] + public void Add_Activity_Success() + { + + var activity = new ActivityEntity + { + Type = "Running", + Date = new DateOnly(2024, 3, 15), + StartTime = new TimeOnly(9, 0), + EndTime = new TimeOnly(10, 0), + EffortFelt = 7, + Variability = 0.5f, + Variance = 0.2f, + StandardDeviation = 0.3f, + Average = 0.4f, + Maximum = 200, + Minimum = 100, + AverageTemperature = 25.5f, + HasAutoPause = true, + DataSourceId = 1, + AthleteId = 1 + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.ActivitiesSet.Add(activity); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedActivity = context.ActivitiesSet.First(a => a.Type == "Running"); + Assert.NotNull(savedActivity); + Assert.Equal("Running", savedActivity.Type ); + } + } + + [Fact] + public void Update_Activity_Success() + { + var activity = new ActivityEntity + { + Type = "Running", + Date = new DateOnly(2024, 3, 15), + StartTime = new TimeOnly(9, 0), + EndTime = new TimeOnly(10, 0), + EffortFelt = 7, + Variability = 0.5f, + Variance = 0.2f, + StandardDeviation = 0.3f, + Average = 0.4f, + Maximum = 200, + Minimum = 100, + AverageTemperature = 25.5f, + HasAutoPause = true, + DataSourceId = 1, + AthleteId = 1 + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.ActivitiesSet.Add(activity); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedActivity = context.ActivitiesSet.FirstOrDefault(a => a.Type == "Running" && a.Maximum == 200); + savedActivity.Type = "Walking"; + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var updatedActivity = context.ActivitiesSet.First(a => a.Type == "Walking" && a.Maximum == 200); + Assert.NotNull(updatedActivity); + Assert.Equal("Walking", updatedActivity.Type ); + Assert.Equal(7, updatedActivity.EffortFelt ); + } + } + + [Fact] + public void Delete_Activity_Success() + { + var activity = new ActivityEntity + { + Type = "Running", + Date = new DateOnly(2024, 3, 15), + StartTime = new TimeOnly(9, 0), + EndTime = new TimeOnly(10, 0), + EffortFelt = 7, + Variability = 0.5f, + Variance = 0.2f, + StandardDeviation = 0.3f, + Average = 0.4f, + Maximum = 200, + Minimum = 100, + AverageTemperature = 25.5f, + HasAutoPause = true, + DataSourceId = 1, + AthleteId = 1 + }; + + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.ActivitiesSet.Add(activity); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedActivity = context.ActivitiesSet.FirstOrDefault(a => a.Type == "Running" && a.EffortFelt == 7); + context.ActivitiesSet.Remove(savedActivity); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var deletedActivity = context.ActivitiesSet.FirstOrDefault(a => a.Type == "Running" && a.EffortFelt == 7); + Assert.Null(deletedActivity); + } + } + + [Fact] + public void Add_Activity_With_All_Properties_Success() + { + + var activity = new ActivityEntity + { + Type = "Running", + Date = new DateOnly(2024, 3, 15), + StartTime = new TimeOnly(9, 0), + EndTime = new TimeOnly(10, 0), + EffortFelt = 7, + Variability = 0.5f, + Variance = 0.2f, + StandardDeviation = 0.3f, + Average = 0.4f, + Maximum = 200, + Minimum = 100, + AverageTemperature = 25.5f, + HasAutoPause = true, + DataSourceId = 1, + AthleteId = 1 + }; + + // Act + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.ActivitiesSet.Add(activity); + context.SaveChanges(); + } + + // Assert + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedActivity = context.ActivitiesSet.First(a => a.Type == "Running" && a.Date == new DateOnly(2024, 3, 15)); + Assert.NotNull(savedActivity); + Assert.Equal("Running", savedActivity.Type); + Assert.Equal(new DateOnly(2024, 3, 15), savedActivity.Date); + Assert.Equal(new TimeOnly(9, 0), savedActivity.StartTime); + Assert.Equal(new TimeOnly(10, 0), savedActivity.EndTime); + Assert.Equal(7, savedActivity.EffortFelt); + Assert.Equal(0.5f, savedActivity.Variability); + Assert.Equal(0.2f, savedActivity.Variance); + Assert.Equal(0.3f, savedActivity.StandardDeviation); + Assert.Equal(0.4f, savedActivity.Average); + Assert.Equal(200, savedActivity.Maximum); + Assert.Equal(100, savedActivity.Minimum); + Assert.Equal(25.5f, savedActivity.AverageTemperature); + Assert.True(savedActivity.HasAutoPause); + Assert.Equal(1, savedActivity.DataSourceId); + Assert.Equal(1, savedActivity.AthleteId); + } + } + + // Test for error cases, e.g., null values + [Fact] + public void Add_Activity_With_Null_Values_Fails() + { + var activity = new ActivityEntity + { + Type = null, + Date = default, + StartTime = default, + EndTime = default, + EffortFelt = 0, + Variability = 0, + Variance = 0, + StandardDeviation = 0, + Average = 0, + Maximum = 0, + Minimum = 0, + AverageTemperature = 0, + HasAutoPause = false, + DataSourceId = 0, + AthleteId = 0 + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.ActivitiesSet.Add(activity); + Assert.Throws(() => context.SaveChanges()); + } + } +} + diff --git a/src/Tests/UnitTestsEntities/AthleteEntityTests.cs b/src/Tests/UnitTestsEntities/AthleteEntityTests.cs new file mode 100644 index 0000000..1f67d03 --- /dev/null +++ b/src/Tests/UnitTestsEntities/AthleteEntityTests.cs @@ -0,0 +1,193 @@ +namespace UnitTestsEntities; +using Xunit; +using System.Linq; +using Entities; +using Microsoft.EntityFrameworkCore; +using StubbedContextLib; + +public class AthleteEntityTests (DatabaseFixture fixture) : IClassFixture +{ + [Fact] + public void Add_Athlete_Success() + { + var athlete = new AthleteEntity + { + Username = "john_doe", + LastName = "Doe", + FirstName = "John", + Email = "john.doe@example.com", + Sexe = "M", + Length = 180.0, + Weight = 75.5f, + Password = "password", + DateOfBirth = new DateOnly(1990, 1, 1), + IsCoach = false, + ProfilPicture = "profile.jpg", + DataSourceId = 1 + }; + + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(athlete); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedAthlete = context.AthletesSet.First(a => a.Username == "john_doe"); + Assert.NotNull(savedAthlete); + Assert.Equal("john_doe", savedAthlete.Username); + } + } + + [Fact] + public void Update_Athlete_Success() + { + var athlete = new AthleteEntity + { + Username = "jane_smith", + LastName = "Smith", + FirstName = "Jane", + Email = "jane.smith@example.com", + Sexe = "F", + Length = 165.0, + Weight = 60.0f, + Password = "password123", + DateOfBirth = new DateOnly(1995, 5, 10), + IsCoach = false, + DataSourceId = 2, + ProfilPicture = "profile.jpg" + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(athlete); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedAthlete = context.AthletesSet.First(a => a.Username == "jane_smith"); + savedAthlete.Username = "jane_doe"; + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var updatedAthlete = context.AthletesSet.First(a => a.Username == "jane_doe"); + Assert.NotNull(updatedAthlete); + Assert.Equal("jane_doe", updatedAthlete.Username); + Assert.Equal("Smith", updatedAthlete.LastName); + } + } + + [Fact] + public void Delete_Athlete_Success() + { + var athlete = new AthleteEntity + { + Username = "test_user", + LastName = "Test", + FirstName = "User", + Email = "test.user@example.com", + Sexe = "M", + Length = 170.0, + Weight = 70.0f, + Password = "testpassword", + DateOfBirth = new DateOnly(1985, 10, 20), + IsCoach = false, + DataSourceId = 3 + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(athlete); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedAthlete = context.AthletesSet.First(a => a.Username == "test_user"); + context.AthletesSet.Remove(savedAthlete); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var deletedAthlete = context.AthletesSet.FirstOrDefault(a => a.Username == "test_user"); + Assert.Null(deletedAthlete); + } + } + + [Fact] + public void Add_Athlete_With_All_Properties_Success() + { + var athlete = new AthleteEntity + { + Username = "john_doe", + LastName = "Doe", + FirstName = "John", + Email = "john.doe@example.com", + Sexe = "M", + Length = 180.0, + Weight = 75.5f, + Password = "password", + DateOfBirth = new DateOnly(1990, 1, 1), + IsCoach = false, + DataSourceId = 1 + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(athlete); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedAthlete = context.AthletesSet.First(a => a.Username == "john_doe"); + Assert.NotNull(savedAthlete); + Assert.Equal("john_doe", savedAthlete.Username); + Assert.Equal("Doe", savedAthlete.LastName); + Assert.Equal("John", savedAthlete.FirstName); + Assert.Equal("john.doe@example.com", savedAthlete.Email); + Assert.Equal("M", savedAthlete.Sexe); + Assert.Equal(180.0, savedAthlete.Length); + Assert.Equal(75.5f, savedAthlete.Weight); + Assert.Equal("password", savedAthlete.Password); + Assert.Equal(new DateOnly(1990, 1, 1), savedAthlete.DateOfBirth); + Assert.False(savedAthlete.IsCoach); + } + } + + [Fact] + public void Add_Athlete_With_Null_Values_Fails() + { + var athlete = new AthleteEntity + { + Username = null, + LastName = null, + FirstName = null, + Email = null, + Sexe = null, + Length = 0, + Weight = 0, + Password = null, + DateOfBirth = default, + IsCoach = false + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(athlete); + Assert.Throws(() => context.SaveChanges()); + } + } +} + diff --git a/src/Tests/UnitTestsEntities/DataSourceEntityTests.cs b/src/Tests/UnitTestsEntities/DataSourceEntityTests.cs new file mode 100644 index 0000000..925242c --- /dev/null +++ b/src/Tests/UnitTestsEntities/DataSourceEntityTests.cs @@ -0,0 +1,144 @@ +namespace UnitTestsEntities; +using Xunit; +using System.Linq; +using Entities; +using Microsoft.EntityFrameworkCore; +using StubbedContextLib; + +public class DataSourceEntityTests (DatabaseFixture fixture) : IClassFixture +{ + [Fact] + public void Add_DataSource_Success() + { + var dataSource = new DataSourceEntity + { + Type = "GPS", + Model = "Garmin Forerunner 945", + Precision = 0.1f + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.DataSourcesSet.Add(dataSource); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedDataSource = context.DataSourcesSet.First(d => d.Type == "GPS"); + Assert.NotNull(savedDataSource); + Assert.Equal("Garmin Forerunner 945", savedDataSource.Model); + } + } + + [Fact] + public void Update_DataSource_Success() + { + var dataSource = new DataSourceEntity + { + Type = "Heart Rate Monitor", + Model = "Polar H10", + Precision = 0.2f + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.DataSourcesSet.Add(dataSource); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedDataSource = context.DataSourcesSet.First(d => d.Type == "Heart Rate Monitor"); + savedDataSource.Model = "Polar H9"; + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var updatedDataSource = context.DataSourcesSet.First(d => d.Model == "Polar H9"); + Assert.NotNull(updatedDataSource); + Assert.Equal("Heart Rate Monitor", updatedDataSource.Type); + Assert.Equal(0.2f, updatedDataSource.Precision); + } + } + + [Fact] + public void Delete_DataSource_Success() + { + var dataSource = new DataSourceEntity + { + Type = "Smartwatch", + Model = "Apple Watch Series 6", + Precision = 0.05f + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.DataSourcesSet.Add(dataSource); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedDataSource = context.DataSourcesSet.First(d => d.Type == "Smartwatch" && d.Model == "Apple Watch Series 6"); + context.DataSourcesSet.Remove(savedDataSource); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var deletedDataSource = context.DataSourcesSet.FirstOrDefault(d => d.Type == "Smartwatch" && d.Model == "Apple Watch Series 6"); + Assert.Null(deletedDataSource); + } + } + + [Fact] + public void Add_DataSource_With_All_Properties_Success() + { + var dataSource = new DataSourceEntity + { + Type = "GPS", + Model = "Garmin Forerunner 945", + Precision = 0.1f + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.DataSourcesSet.Add(dataSource); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedDataSource = context.DataSourcesSet.First(d => d.Type == "GPS"); + Assert.NotNull(savedDataSource); + Assert.Equal("GPS", savedDataSource.Type); + Assert.Equal("Garmin Forerunner 945", savedDataSource.Model); + Assert.Equal(0.1f, savedDataSource.Precision); + } + } + + [Fact] + public void Add_DataSource_With_Null_Values_Fails() + { + var dataSource = new DataSourceEntity + { + Type = null, + Model = null, + Precision = 0 + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.DataSourcesSet.Add(dataSource); + Assert.Throws(() => context.SaveChanges()); + } + } +} + diff --git a/src/Tests/UnitTestsEntities/DatabaseFixture.cs b/src/Tests/UnitTestsEntities/DatabaseFixture.cs new file mode 100644 index 0000000..eaae26d --- /dev/null +++ b/src/Tests/UnitTestsEntities/DatabaseFixture.cs @@ -0,0 +1,27 @@ +using DbContextLib; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using StubbedContextLib; + +namespace UnitTestsEntities; + +public class DatabaseFixture : IDisposable +{ + private readonly SqliteConnection _connection; + public readonly DbContextOptions _options; + public DatabaseFixture() + { + _connection = new SqliteConnection("DataSource=:memory:"); + _connection.Open(); + + _options = new DbContextOptionsBuilder() + .UseSqlite(_connection) + .Options; + + } + public void Dispose() + { + _connection.Close(); + _connection.Dispose(); + } +} \ No newline at end of file diff --git a/src/Tests/UnitTestsEntities/FriendshipEntityTests.cs b/src/Tests/UnitTestsEntities/FriendshipEntityTests.cs new file mode 100644 index 0000000..10cfc00 --- /dev/null +++ b/src/Tests/UnitTestsEntities/FriendshipEntityTests.cs @@ -0,0 +1,215 @@ +namespace UnitTestsEntities; +using Xunit; +using System.Linq; +using Entities; +using Microsoft.EntityFrameworkCore; +using StubbedContextLib; + +public class FriendshipEntityTests (DatabaseFixture fixture) : IClassFixture +{ + [Fact] + public void Add_Friendship_Success() + { + var follower = new AthleteEntity + { + Username = "follower_user1", + LastName = "Follower", + FirstName = "User", + Email = "follower.user@example.com", + Sexe = "M", + Length = 170.0, + Weight = 70.0f, + Password = "followerpassword", + DateOfBirth = new DateOnly(1990, 1, 1), + IsCoach = false, + DataSourceId = 1 + }; + + var following = new AthleteEntity + { + Username = "following_user1", + LastName = "Following", + FirstName = "User", + Email = "following.user@example.com", + Sexe = "F", + Length = 165.0, + Weight = 60.0f, + Password = "followingpassword", + DateOfBirth = new DateOnly(1995, 5, 10), + IsCoach = false, + DataSourceId = 2 + }; + + var friendship = new FriendshipEntity + { + Follower = follower, + Following = following, + StartDate = DateTime.Now + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(follower); + context.AthletesSet.Add(following); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Attach(friendship); // Attachez l'amitié au contexte + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedFriendship = context.AthletesSet.Include(a => a.Followers).Include(a => a.Followings).FirstOrDefault(a => a.Username == "follower_user1").Followers.FirstOrDefault(f => f.FollowerId == follower.IdAthlete && f.FollowingId == following.IdAthlete); + + Assert.NotNull(savedFriendship); + if (savedFriendship != null) + { + Assert.Equal(follower.IdAthlete, savedFriendship.FollowerId); + Assert.Equal(following.IdAthlete, savedFriendship.FollowingId); + } + } + } + + [Fact] + public void Update_Friendship_Success() + { + var follower = new AthleteEntity + { + Username = "follower_user", + LastName = "Follower", + FirstName = "User", + Email = "follower.user@example.com", + Sexe = "M", + Length = 170.0, + Weight = 70.0f, + Password = "followerpassword", + DateOfBirth = new DateOnly(1990, 1, 1), + IsCoach = false + }; + + var following = new AthleteEntity + { + Username = "following_user", + LastName = "Following", + FirstName = "User", + Email = "following.user@example.com", + Sexe = "F", + Length = 165.0, + Weight = 60.0f, + Password = "followingpassword", + DateOfBirth = new DateOnly(1995, 5, 10), + IsCoach = false + }; + + var thirdAthlete = new AthleteEntity + { + Username = "third_user", + LastName = "Third", + FirstName = "User", + Email = "third.user@example.com", + Sexe = "M", + Length = 180.0, + Weight = 75.0f, + Password = "thirdpassword", + DateOfBirth = new DateOnly(1988, 3, 15), + IsCoach = false + }; + + var friendship = new FriendshipEntity + { + Follower = follower, + Following = following, + StartDate = DateTime.Now + };/* + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(follower); + context.AthletesSet.Add(following); + context.AthletesSet.Add(thirdAthlete); + context.Friendships.Add(friendship); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedFriendship = context.Friendships.FirstOrDefault(); + savedFriendship.Follower = thirdAthlete; // Update the follower + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var updatedFriendship = context.Friendships.FirstOrDefault(); + Assert.NotNull(updatedFriendship); + Assert.Equal(thirdAthlete.IdAthlete, updatedFriendship.FollowerId); + }*/ + } + + [Fact] + public void Delete_Friendship_Success() + { + // Act + var follower = new AthleteEntity + { + Username = "follower_user", + LastName = "Follower", + FirstName = "User", + Email = "follower.user@example.com", + Sexe = "M", + Length = 170.0, + Weight = 70.0f, + Password = "followerpassword", + DateOfBirth = new DateOnly(1990, 1, 1), + IsCoach = false + }; + + var following = new AthleteEntity + { + Username = "following_user", + LastName = "Following", + FirstName = "User", + Email = "following.user@example.com", + Sexe = "F", + Length = 165.0, + Weight = 60.0f, + Password = "followingpassword", + DateOfBirth = new DateOnly(1995, 5, 10), + IsCoach = false + }; + + + /* + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(follower); + context.AthletesSet.Add(following); + context.SaveChanges(); + var user1 = context.AthletesSet.FirstOrDefault(a => a.IdAthlete == follower.IdAthlete); + var user2 = context.AthletesSet.FirstOrDefault(a => a.IdAthlete == following.IdAthlete); + user1.Followers = user2.IdAthlete; + } + + + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedFriendship = context.Friendships.FirstOrDefault(); + context.Friendships.Remove(savedFriendship); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var deletedFriendship = context.Friendships.FirstOrDefault(); + Assert.Null(deletedFriendship); + }*/ + } +} + diff --git a/src/Tests/UnitTestsEntities/GlobalUsings.cs b/src/Tests/UnitTestsEntities/GlobalUsings.cs new file mode 100644 index 0000000..8c927eb --- /dev/null +++ b/src/Tests/UnitTestsEntities/GlobalUsings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file diff --git a/src/Tests/UnitTestsEntities/HeartRateEntityTests.cs b/src/Tests/UnitTestsEntities/HeartRateEntityTests.cs new file mode 100644 index 0000000..9652796 --- /dev/null +++ b/src/Tests/UnitTestsEntities/HeartRateEntityTests.cs @@ -0,0 +1,240 @@ +namespace UnitTestsEntities; +using Xunit; +using System.Linq; +using Entities; +using Microsoft.EntityFrameworkCore; +using StubbedContextLib; + +public class HeartRateEntityTests (DatabaseFixture fixture) : IClassFixture +{ + [Fact] + public void Add_HeartRate_Success() + { + var activity = new ActivityEntity + { + Type = "Running", + Date = new DateOnly(2024, 3, 15), + StartTime = new TimeOnly(9, 0), + EndTime = new TimeOnly(10, 0), + EffortFelt = 7, + Variability = 0.5f, + Variance = 0.2f, + StandardDeviation = 0.3f, + Average = 0.4f, + Maximum = 200, + Minimum = 100, + AverageTemperature = 25.5f, + HasAutoPause = true, + DataSourceId = 1, + AthleteId = 1 + }; + + var heartRateEntry = new HeartRateEntity + { + Altitude = 100.0, + Time = new TimeOnly(9, 30), + Temperature = 20.0f, + Bpm = 150, + Longitude = 45.12345f, + Latitude = 35.6789f, + Activity = activity + }; + + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.ActivitiesSet.Add(activity); + context.HeartRatesSet.Add(heartRateEntry); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedHeartRate = context.HeartRatesSet.FirstOrDefault(h => h.Altitude == 100.0 && h.Temperature == 20.0f); + Assert.NotNull(savedHeartRate); + Assert.Equal(150, savedHeartRate.Bpm); + } + } + + [Fact] + public void Update_HeartRate_Success() + { + var activity = new ActivityEntity + { + Type = "Running", + Date = new DateOnly(2024, 3, 15), + StartTime = new TimeOnly(9, 0), + EndTime = new TimeOnly(10, 0), + EffortFelt = 7, + Variability = 0.5f, + Variance = 0.2f, + StandardDeviation = 0.3f, + Average = 0.4f, + Maximum = 200, + Minimum = 100, + AverageTemperature = 25.5f, + HasAutoPause = true, + DataSourceId = 1, + AthleteId = 1 + }; + + var heartRateEntry = new HeartRateEntity + { + Altitude = 100.0, + Time = new TimeOnly(9, 30), + Temperature = 20.0f, + Bpm = 150, + Longitude = 45.12345f, + Latitude = 35.6789f, + Activity = activity + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.ActivitiesSet.Add(activity); + context.HeartRatesSet.Add(heartRateEntry); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedHeartRate = context.HeartRatesSet.First(); + savedHeartRate.Bpm = 160; + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var updatedHeartRate = context.HeartRatesSet.First(); + Assert.NotNull(updatedHeartRate); + Assert.Equal(160, updatedHeartRate.Bpm); + } + } + + [Fact] + public void Delete_HeartRate_Success() + { + var activity = new ActivityEntity + { + Type = "Run", + Date = new DateOnly(2024, 3, 15), + StartTime = new TimeOnly(9, 0), + EndTime = new TimeOnly(10, 0), + EffortFelt = 5, + Variability = 0.5f, + Variance = 0.2f, + StandardDeviation = 0.3f, + Average = 0.4f, + Maximum = 200, + Minimum = 100, + AverageTemperature = 25.5f, + HasAutoPause = true, + DataSourceId = 1, + AthleteId = 1 + }; + + var heartRateEntry = new HeartRateEntity + { + Altitude = 105.0, + Time = new TimeOnly(9, 30), + Temperature = 20.0f, + Bpm = 150, + Longitude = 45.12345f, + Latitude = 35.6789f, + ActivityId = 1 + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.ActivitiesSet.Add(activity); + context.HeartRatesSet.Add(heartRateEntry); + context.SaveChanges(); + } + // Ne veut pas passer, si quelqu'un sait pourquoi ... Erreur : System.ArgumentNullException : Value cannot be null. (Parameter 'entity') + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedHeartRate = context.HeartRatesSet.First(h => h.Altitude == 105.0); + var savedActivity = context.ActivitiesSet.First(a => a.Type == "Run"); + + Assert.NotNull(savedHeartRate); + if (savedHeartRate != null) + { + context.HeartRatesSet.Remove(savedHeartRate); + } + Assert.NotNull(savedActivity); + if (savedActivity != null) + { + context.ActivitiesSet.Remove(savedActivity); + } + + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var deletedHeartRate = context.HeartRatesSet.FirstOrDefault(h => h.Altitude == 105.0); + Assert.Null(deletedHeartRate); + } + } + + [Fact] + public void Add_HeartRate_With_All_Properties_Success() + { + + var activity = new ActivityEntity + { + Type = "Running", + Date = new DateOnly(2024, 3, 15), + StartTime = new TimeOnly(9, 0), + EndTime = new TimeOnly(10, 0), + EffortFelt = 7, + Variability = 0.5f, + Variance = 0.2f, + StandardDeviation = 0.3f, + Average = 0.4f, + Maximum = 200, + Minimum = 100, + AverageTemperature = 25.5f, + HasAutoPause = true, + DataSourceId = 1, + AthleteId = 1 + }; + + var heartRateEntry = new HeartRateEntity + { + Altitude = 100.0, + Time = new TimeOnly(9, 30), + Temperature = 20.0f, + Bpm = 150, + Longitude = 45.12345f, + Latitude = 35.6789f, + Activity = activity + }; + + // Act + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.ActivitiesSet.Add(activity); + context.HeartRatesSet.Add(heartRateEntry); + context.SaveChanges(); + } + + // Assert + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedHeartRate = context.HeartRatesSet.FirstOrDefault(h => h.Altitude == 100.0 && h.Temperature == 20.0f); + Assert.NotNull(savedHeartRate); + Assert.Equal(100.0, savedHeartRate.Altitude); + Assert.Equal(new TimeOnly(9, 30), savedHeartRate.Time); + Assert.Equal(20.0f, savedHeartRate.Temperature); + Assert.Equal(150, savedHeartRate.Bpm); + Assert.Equal(45.12345f, savedHeartRate.Longitude); + Assert.Equal(35.6789f, savedHeartRate.Latitude); + } + } +} + diff --git a/src/Tests/UnitTestsEntities/NotificationEntityTests.cs b/src/Tests/UnitTestsEntities/NotificationEntityTests.cs new file mode 100644 index 0000000..f44774d --- /dev/null +++ b/src/Tests/UnitTestsEntities/NotificationEntityTests.cs @@ -0,0 +1,218 @@ +namespace UnitTestsEntities; +using Xunit; +using System.Linq; +using Entities; +using Microsoft.EntityFrameworkCore; +using StubbedContextLib; + +public class NotificationEntityTests (DatabaseFixture fixture) : IClassFixture +{ + [Fact] + public void Add_Notification_Success() + { + var sender = new AthleteEntity + { + Username = "sender_user", + LastName = "Sender", + FirstName = "User", + Email = "sender.user@example.com", + Sexe = "M", + Length = 170.0, + Weight = 70.0f, + Password = "senderpassword", + DateOfBirth = new DateOnly(1990, 1, 1), + IsCoach = false, + DataSourceId = 1 + }; + + var notification = new NotificationEntity + { + Message = "Test notification", + Date = DateTime.Now, + Statut = false, + Urgence = "High", + Sender = sender + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(sender); + context.NotificationsSet.Add(notification); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedNotification = context.NotificationsSet.FirstOrDefault(n => n.Message == "Test notification" && n.Statut == false && n.Urgence == "High"); + Assert.NotNull(savedNotification); + Assert.Equal("Test notification", savedNotification.Message); + } + } + + [Fact] + public void Update_Notification_Success() + { + var sender = new AthleteEntity + { + Username = "sender_user", + LastName = "Sender", + FirstName = "User", + Email = "sender.user@example.com", + Sexe = "M", + Length = 170.0, + Weight = 70.0f, + Password = "senderpassword", + DateOfBirth = new DateOnly(1990, 1, 1), + IsCoach = false, + DataSourceId = 1 + }; + + var notification = new NotificationEntity + { + Message = "Test notification", + Date = DateTime.Now, + Statut = false, + Urgence = "High", + Sender = sender + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(sender); + context.NotificationsSet.Add(notification); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedNotification = context.NotificationsSet.First(); + savedNotification.Message = "Updated message"; + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var updatedNotification = context.NotificationsSet.First(); + Assert.NotNull(updatedNotification); + Assert.Equal("Updated message", updatedNotification.Message); + } + } + + [Fact] + public void Delete_Notification_Success() + { + var sender = new AthleteEntity + { + Username = "sender_user", + LastName = "Sender", + FirstName = "User", + Email = "sender.user@example.com", + Sexe = "M", + Length = 170.0, + Weight = 70.0f, + Password = "senderpassword", + DateOfBirth = new DateOnly(1990, 1, 1), + IsCoach = false, + DataSourceId = 3 + }; + + var notification = new NotificationEntity + { + Message = "Test notification Suppression", + Date = DateTime.Now, + Statut = false, + Urgence = "High", + Sender = sender + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(sender); + context.NotificationsSet.Add(notification); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedNotification = context.NotificationsSet.FirstOrDefault(n => n.Message == "Test notification Suppression"); + context.NotificationsSet.Remove(savedNotification); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var deletedNotification = context.NotificationsSet.FirstOrDefault(n => n.Message == "Test notification Suppression"); + Assert.Null(deletedNotification); + } + } + + [Fact] + public void Add_Notification_With_All_Properties_Success() + { + var sender = new AthleteEntity + { + Username = "sender_user", + LastName = "Sender", + FirstName = "User", + Email = "sender.user@example.com", + Sexe = "M", + Length = 170.0, + Weight = 70.0f, + Password = "senderpassword", + DateOfBirth = new DateOnly(1990, 1, 1), + IsCoach = false, + DataSourceId = 3 + }; + + var notification = new NotificationEntity + { + Message = "Test notification", + Date = DateTime.Now, + Statut = false, + Urgence = "High", + Sender = sender + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(sender); + context.NotificationsSet.Add(notification); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedNotification = context.NotificationsSet.FirstOrDefault(n => n.Message == "Test notification" && n.Statut == false && n.Urgence == "High"); + Assert.NotNull(savedNotification); + Assert.Equal("Test notification", savedNotification.Message); + Assert.Equal(DateTime.Today, savedNotification.Date.Date); + Assert.False(savedNotification.Statut); + Assert.Equal("High", savedNotification.Urgence); + } + } + + [Fact] + public void Add_Notification_With_Null_Values_Fails() + { + var notification = new NotificationEntity + { + Message = null, + Date = default, + Statut = false, + Urgence = null, + Sender = null + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.NotificationsSet.Add(notification); + Assert.Throws(() => context.SaveChanges()); + } + } +} + diff --git a/src/Tests/UnitTestsEntities/StatisticEntityTests.cs b/src/Tests/UnitTestsEntities/StatisticEntityTests.cs new file mode 100644 index 0000000..2e980e3 --- /dev/null +++ b/src/Tests/UnitTestsEntities/StatisticEntityTests.cs @@ -0,0 +1,206 @@ +namespace UnitTestsEntities; +using Xunit; +using System.Linq; +using Entities; +using Microsoft.EntityFrameworkCore; +using StubbedContextLib; + +public class StatisticEntityTests (DatabaseFixture fixture) : IClassFixture +{ + [Fact] + public void Add_Statistic_Success() + { + var athlete = new AthleteEntity + { + Username = "athlete_user", + LastName = "Athlete", + FirstName = "User", + Email = "athlete.user@example.com", + Sexe = "M", + Length = 170.0, + Weight = 70.0f, + Password = "athletepassword", + DateOfBirth = new DateOnly(1990, 1, 1), + IsCoach = false, + DataSourceId = 1 + }; + + var statistic = new StatisticEntity + { + Weight = 75.0f, + AverageHeartRate = 150.0, + MaximumHeartRate = 180.0, + AverageCaloriesBurned = 500.0, + Date = new DateOnly(2024, 3, 15), + Athlete = athlete + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(athlete); + context.StatisticsSet.Add(statistic); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedStatistic = context.StatisticsSet.FirstOrDefault(s => s.AverageHeartRate == 150.0 && s.MaximumHeartRate == 180.0); + Assert.NotNull(savedStatistic); + Assert.Equal(75.0f, savedStatistic.Weight); + } + } + + [Fact] + public void Update_Statistic_Success() + { + var athlete = new AthleteEntity + { + Username = "athlete_user", + LastName = "Athlete", + FirstName = "User", + Email = "athlete.user@example.com", + Sexe = "M", + Length = 170.0, + Weight = 70.0f, + Password = "athletepassword", + DateOfBirth = new DateOnly(1990, 1, 1), + IsCoach = false, + DataSourceId = 1 + }; + + var statistic = new StatisticEntity + { + Weight = 75.0f, + AverageHeartRate = 150.0, + MaximumHeartRate = 180.0, + AverageCaloriesBurned = 500.0, + Date = new DateOnly(2024, 3, 15), + Athlete = athlete + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(athlete); + context.StatisticsSet.Add(statistic); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedStatistic = context.StatisticsSet.First(); + savedStatistic.Weight = 80.0f; + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var updatedStatistic = context.StatisticsSet.First(); + Assert.NotNull(updatedStatistic); + Assert.Equal(80.0f, updatedStatistic.Weight); + } + } + + [Fact] + public void Delete_Statistic_Success() + { + var athlete = new AthleteEntity + { + Username = "athlete_user", + LastName = "Athlete", + FirstName = "User", + Email = "athlete.user@example.com", + Sexe = "M", + Length = 170.0, + Weight = 70.0f, + Password = "athletepassword", + DateOfBirth = new DateOnly(1990, 1, 1), + IsCoach = false, + DataSourceId = 1 + }; + + var statistic = new StatisticEntity + { + Weight = 85.0f, + AverageHeartRate = 150.0, + MaximumHeartRate = 180.0, + AverageCaloriesBurned = 500.0, + Date = new DateOnly(2024, 3, 15), + Athlete = athlete + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(athlete); + context.StatisticsSet.Add(statistic); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedStatistic = context.StatisticsSet.FirstOrDefault(s => s.Weight == 85.0 ); + context.StatisticsSet.Remove(savedStatistic); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var deletedStatistic = context.StatisticsSet.FirstOrDefault(s => s.Weight == 85.0 ); + Assert.Null(deletedStatistic); + } + } + + [Fact] + public void Add_Statistic_With_All_Properties_Success() + { + + var athlete = new AthleteEntity + { + Username = "athlete_user", + LastName = "Athlete", + FirstName = "User", + Email = "athlete.user@example.com", + Sexe = "M", + Length = 170.0, + Weight = 70.0f, + Password = "athletepassword", + DateOfBirth = new DateOnly(1990, 1, 1), + IsCoach = false, + DataSourceId = 1 + }; + + var statistic = new StatisticEntity + { + Weight = 75.0f, + AverageHeartRate = 150.0, + MaximumHeartRate = 180.0, + AverageCaloriesBurned = 500.0, + Date = new DateOnly(2024, 3, 15), + Athlete = athlete + }; + + // Act + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(athlete); + context.StatisticsSet.Add(statistic); + context.SaveChanges(); + } + + // Assert + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedStatistic = context.StatisticsSet.FirstOrDefault(s => s.AverageHeartRate == 150.0 && s.MaximumHeartRate == 180.0); + Assert.NotNull(savedStatistic); + Assert.Equal(75.0f, savedStatistic.Weight); + Assert.Equal(150.0, savedStatistic.AverageHeartRate); + Assert.Equal(180.0, savedStatistic.MaximumHeartRate); + Assert.Equal(500.0, savedStatistic.AverageCaloriesBurned); + Assert.Equal(new DateOnly(2024, 3, 15), savedStatistic.Date); + } + } +} + diff --git a/src/Tests/UnitTestsEntities/TrainingEntityTests.cs b/src/Tests/UnitTestsEntities/TrainingEntityTests.cs new file mode 100644 index 0000000..bba0f51 --- /dev/null +++ b/src/Tests/UnitTestsEntities/TrainingEntityTests.cs @@ -0,0 +1,293 @@ +namespace UnitTestsEntities; +using Xunit; +using System.Linq; +using Entities; +using Microsoft.EntityFrameworkCore; +using StubbedContextLib; + +public class TrainingEntityTests (DatabaseFixture fixture) : IClassFixture +{ + [Fact] + public void Add_Training_Success() + { + var coach = new AthleteEntity + { + Username = "coach_user", + LastName = "Coach", + FirstName = "User", + Email = "coach.user@example.com", + Sexe = "M", + Length = 180.0, + Weight = 75.0f, + Password = "coachpassword", + DateOfBirth = new DateOnly(1985, 5, 15), + IsCoach = true, + DataSourceId = 1 + }; + + var athlete = new AthleteEntity + { + Username = "athlete_user", + LastName = "Athlete", + FirstName = "User", + Email = "athlete.user@example.com", + Sexe = "F", + Length = 165.0, + Weight = 60.0f, + Password = "athletepassword", + DateOfBirth = new DateOnly(1990, 3, 20), + IsCoach = false, + DataSourceId = 1 + }; + + var training = new TrainingEntity + { + Date = new DateOnly(2024, 3, 15), + Description = "Training Description", + Latitude = 40.12345f, + Longitude = -74.56789f, + FeedBack = "Training feedback", + Coach = coach, + Athletes = { athlete } + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(coach); + context.AthletesSet.Add(athlete); + context.TrainingsSet.Add(training); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedTraining = context.TrainingsSet.FirstOrDefault(t => t.Description == "Training Description" && t.FeedBack == "Training feedback"); + Assert.NotNull(savedTraining); + Assert.Equal("Training Description", savedTraining.Description); + } + } + + [Fact] + public void Update_Training_Success() + { + var coach = new AthleteEntity + { + Username = "coach_user", + LastName = "Coach", + FirstName = "User", + Email = "coach.user@example.com", + Sexe = "M", + Length = 180.0, + Weight = 75.0f, + Password = "coachpassword", + DateOfBirth = new DateOnly(1985, 5, 15), + IsCoach = true, + DataSourceId = 1 + }; + + var athlete = new AthleteEntity + { + Username = "athlete_user", + LastName = "Athlete", + FirstName = "User", + Email = "athlete.user@example.com", + Sexe = "F", + Length = 165.0, + Weight = 60.0f, + Password = "athletepassword", + DateOfBirth = new DateOnly(1990, 3, 20), + IsCoach = false, + DataSourceId = 1 + }; + + var training = new TrainingEntity + { + Date = new DateOnly(2024, 3, 15), + Description = "Training description", + Latitude = 40.12345f, + Longitude = -74.56789f, + FeedBack = "Training feedback", + Coach = coach, + Athletes = { athlete } + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(coach); + context.AthletesSet.Add(athlete); + context.TrainingsSet.Add(training); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedTraining = context.TrainingsSet.First(); + savedTraining.Description = "Updated training description"; + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var updatedTraining = context.TrainingsSet.First(); + Assert.NotNull(updatedTraining); + Assert.Equal("Updated training description", updatedTraining.Description); + } + } + + [Fact] + public void Delete_Training_Success() + { + var coach = new AthleteEntity + { + Username = "coach_user", + LastName = "Coach", + FirstName = "User", + Email = "coach.user@example.com", + Sexe = "M", + Length = 180.0, + Weight = 75.0f, + Password = "coachpassword", + DateOfBirth = new DateOnly(1985, 5, 15), + IsCoach = true, + DataSourceId = 1 + }; + + var athlete = new AthleteEntity + { + Username = "athlete_user", + LastName = "Athlete", + FirstName = "User", + Email = "athlete.user@example.com", + Sexe = "F", + Length = 165.0, + Weight = 60.0f, + Password = "athletepassword", + DateOfBirth = new DateOnly(1990, 3, 20), + IsCoach = false, + DataSourceId = 1 + }; + + var training = new TrainingEntity + { + Date = new DateOnly(2024, 3, 15), + Description = "Training description suppression", + Latitude = 40.12345f, + Longitude = -74.56789f, + FeedBack = "Training feedback suppression", + Coach = coach, + Athletes = { athlete } + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(coach); + context.AthletesSet.Add(athlete); + context.TrainingsSet.Add(training); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedTraining = context.TrainingsSet.FirstOrDefault(t => t.Description == "Training description suppression" && t.FeedBack == "Training feedback suppression"); + context.TrainingsSet.Remove(savedTraining); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var deletedTraining = context.TrainingsSet.FirstOrDefault(t => t.Description == "Training description suppression" && t.FeedBack == "Training feedback suppression"); + Assert.Null(deletedTraining); + } + } + + [Fact] + public void Add_Training_With_All_Properties_Success() + { + var coach = new AthleteEntity + { + Username = "coach_user", + LastName = "Coach", + FirstName = "User", + Email = "coach.user@example.com", + Sexe = "M", + Length = 180.0, + Weight = 75.0f, + Password = "coachpassword", + DateOfBirth = new DateOnly(1985, 5, 15), + IsCoach = true, + DataSourceId = 1 + }; + + var athlete = new AthleteEntity + { + Username = "athlete_user", + LastName = "Athlete", + FirstName = "User", + Email = "athlete.user@example.com", + Sexe = "F", + Length = 165.0, + Weight = 60.0f, + Password = "athletepassword", + DateOfBirth = new DateOnly(1990, 3, 20), + IsCoach = false, + DataSourceId = 1 + }; + + var training = new TrainingEntity + { + Date = new DateOnly(2024, 3, 15), + Description = "Training DescriptionAll", + Latitude = 40.12345f, + Longitude = -74.56789f, + FeedBack = "Training feedbackAll", + Coach = coach, + Athletes = { athlete } + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.AthletesSet.Add(coach); + context.AthletesSet.Add(athlete); + context.TrainingsSet.Add(training); + context.SaveChanges(); + } + + using (var context = new TrainingStubbedContext(fixture._options)) + { + var savedTraining = context.TrainingsSet.FirstOrDefault(t => t.Description == "Training DescriptionAll" && t.FeedBack == "Training feedbackAll"); + Assert.NotNull(savedTraining); + Assert.Equal(new DateOnly(2024, 3, 15), savedTraining.Date); + Assert.Equal("Training DescriptionAll", savedTraining.Description); + Assert.Equal(40.12345f, savedTraining.Latitude); + Assert.Equal(-74.56789f, savedTraining.Longitude); + Assert.Equal("Training feedbackAll", savedTraining.FeedBack); + } + } + + [Fact] + public void Add_Training_With_Null_Values_Fails() + { + var training = new TrainingEntity + { + Date = default, + Description = null, + Latitude = 45, + Longitude = 45, + FeedBack = null, + Coach = null, + Athletes = null + }; + + using (var context = new TrainingStubbedContext(fixture._options)) + { + context.Database.EnsureCreated(); + context.TrainingsSet.Add(training); + Assert.Throws(() => context.SaveChanges()); + } + } + +} diff --git a/src/Tests/UnitTestsEntities/UnitTestsEntities.csproj b/src/Tests/UnitTestsEntities/UnitTestsEntities.csproj new file mode 100644 index 0000000..80251f0 --- /dev/null +++ b/src/Tests/UnitTestsEntities/UnitTestsEntities.csproj @@ -0,0 +1,37 @@ + + + + net8.0 + enable + enable + $(MSBuildProjectDirectory) + false + true + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + diff --git a/src/Tests/UnitTestsModel/ActivityTest.cs b/src/Tests/UnitTestsModel/ActivityTest.cs new file mode 100644 index 0000000..a381e49 --- /dev/null +++ b/src/Tests/UnitTestsModel/ActivityTest.cs @@ -0,0 +1,254 @@ +//----------------------------------------------------------------------- +// FILENAME: ActivityTests.cs +// PROJECT: UnitTestsModel +// DATE CREATED: 16/03/2024 +// AUTHOR: HeartTeam +// PURPOSE: Contains unit tests for the Activity class in the Model namespace. +//----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using Model; +using Xunit; + +namespace UnitTestsModel +{ + /// + /// Contains unit tests for the class. + /// + public class ActivityTests + { + /// + /// Verifies that the constructor sets the effort property correctly when a valid effort is provided. + /// + [Fact] + public void Constructor_WithValidEffort_SetsEffort() + { + var date = DateTime.Now; + var validEffort = 3; + + var activity = new Activity( + id: 1, + type: "Running", + date: date, + startTime: date.AddHours(1), + endTime: date.AddHours(2), + effort: validEffort, + variability: 0.5f, + variance: 0.3f, + standardDeviation: 0.2f, + average: 150, + maximum: 180, + minimum: 120, + averageTemperature: 25.5f, + hasAutoPause: false, + user: new User(), + dataSource: new DataSource(1, "Type", "Model", 0.1f, new List(), new List()), + heartRates: null + ); + + Assert.Equal(validEffort, activity.Effort); + } + + /// + /// Verifies that the constructor throws an ArgumentException when an invalid effort is provided. + /// + [Fact] + public void Constructor_WithInvalidEffort_ThrowsArgumentException() + { + var date = DateTime.Now; + var invalidEffort = 6; + + Assert.Throws(() => new Activity( + id: 1, + type: "Running", + date: date, + startTime: date.AddHours(1), + endTime: date.AddHours(2), + effort: invalidEffort, + variability: 0.5f, + variance: 0.3f, + standardDeviation: 0.2f, + average: 150, + maximum: 180, + minimum: 120, + averageTemperature: 25.5f, + hasAutoPause: false, + user: new User(), + dataSource: new DataSource(1, "Type", "Model", 0.1f, new List(), new List()), + heartRates: null + )); + } + + /// + /// Verifies that the ToString method returns the expected string representation of the activity. + /// + [Fact] + public void ToString_ReturnsExpectedString() + { + var date = new DateTime(2023, 3, 16, 10, 0, 0); + var activity = new Activity( + id: 1, + type: "Running", + date: date, + startTime: date.AddHours(1), + endTime: date.AddHours(2), + effort: 3, + variability: 0.5f, + variance: 0.3f, + standardDeviation: 0.2f, + average: 150, + maximum: 180, + minimum: 120, + averageTemperature: 25.5f, + hasAutoPause: false, + user: new User(), + dataSource: new DataSource(1, "Type", "Model", 0.1f, new List(), new List()), + heartRates: null + ); + + var result = activity.ToString(); + + Assert.Contains("Activity #1: Running on 16/3/2023 from 11:00:00 to 12:00:00", result); + } + + /// + /// Verifies that the constructor sets all properties correctly. + /// + [Fact] + public void Constructor_SetsPropertiesCorrectly() + { + var date = DateTime.Now; + var user = new User(); + var dataSource = new DataSource(1, "Type", "Model", 0.1f, new List(), new List()); + var heartRates = new List(); + + var activity = new Activity( + id: 1, + type: "Running", + date: date, + startTime: date.AddHours(1), + endTime: date.AddHours(2), + effort: 3, + variability: 0.5f, + variance: 0.3f, + standardDeviation: 0.2f, + average: 150, + maximum: 180, + minimum: 120, + averageTemperature: 25.5f, + hasAutoPause: false, + user: user, + dataSource: dataSource, + heartRates: heartRates + ); + + Assert.Equal(1, activity.Id); + Assert.Equal("Running", activity.Type); + Assert.Equal(date, activity.Date); + Assert.Equal(date.AddHours(1), activity.StartTime); + Assert.Equal(date.AddHours(2), activity.EndTime); + Assert.Equal(3, activity.Effort); + Assert.Equal(0.5f, activity.Variability); + Assert.Equal(0.3f, activity.Variance); + Assert.Equal(0.2f, activity.StandardDeviation); + Assert.Equal(150, activity.Average); + Assert.Equal(180, activity.Maximum); + Assert.Equal(120, activity.Minimum); + Assert.Equal(25.5f, activity.AverageTemperature); + Assert.False(activity.HasAutoPause); + Assert.Equal(user, activity.Athlete); + Assert.Equal(dataSource, activity.DataSource); + Assert.Equal(heartRates, activity.HeartRates); + } + + [Fact] + public void Constructor_SetsPropertiesCorrectly2() + { + var id = 1; + var type = "Running"; + var date = DateTime.Now; + var startTime = date.AddHours(1); + var endTime = date.AddHours(2); + var effort = 3; + var variability = 0.5f; + var variance = 0.3f; + var standardDeviation = 0.2f; + var average = 150f; + var maximum = 180; + var minimum = 120; + var averageTemperature = 25.5f; + var hasAutoPause = false; + var user = new User(); + + var activity = new Activity( + id, + type, + date, + startTime, + endTime, + effort, + variability, + variance, + standardDeviation, + average, + maximum, + minimum, + averageTemperature, + hasAutoPause, + user + ); + + Assert.Equal(id, activity.Id); + Assert.Equal(type, activity.Type); + Assert.Equal(date, activity.Date); + Assert.Equal(startTime, activity.StartTime); + Assert.Equal(endTime, activity.EndTime); + Assert.Equal(effort, activity.Effort); + Assert.Equal(variability, activity.Variability); + Assert.Equal(variance, activity.Variance); + Assert.Equal(standardDeviation, activity.StandardDeviation); + Assert.Equal(average, activity.Average); + Assert.Equal(maximum, activity.Maximum); + Assert.Equal(minimum, activity.Minimum); + Assert.Equal(averageTemperature, activity.AverageTemperature); + Assert.Equal(hasAutoPause, activity.HasAutoPause); + Assert.Equal(user, activity.Athlete); + } + + [Fact] + public void ToString_ReturnsCorrectStringRepresentation() + { + var date = DateTime.Now; + var user = new User(); + var dataSource = new DataSource(1, "Type", "Model", 0.1f, new List(), new List()); + var heartRates = new List(); + + var activity = new Activity( + id: 1, + type: "Running", + date: date, + startTime: date.AddHours(1), + endTime: date.AddHours(2), + effort: 3, + variability: 0.5f, + variance: 0.3f, + standardDeviation: 0.2f, + average: 150, + maximum: 180, + minimum: 120, + averageTemperature: 25.5f, + hasAutoPause: false, + user: user, + dataSource: dataSource, + heartRates: heartRates + ); + + var result = activity.ToString(); + + Console.WriteLine(result); + + Assert.Equal($"Activity #1: Running on {date:d/M/yyyy} from {date.AddHours(1):HH:mm:ss} to {date.AddHours(2):HH:mm:ss} with an effort of 3/5 and an average temperature of 25.5°C and a heart rate variability of 0.5 bpm and a variance of 0.3 bpm and a standard deviation of 0.2 bpm and an average of 150 bpm and a maximum of 180 bpm and a minimum of 120 bpm and auto pause is disabled.", result); + } + } +} \ No newline at end of file diff --git a/src/Tests/UnitTestsModel/AthleteTest.cs b/src/Tests/UnitTestsModel/AthleteTest.cs new file mode 100644 index 0000000..fb398ce --- /dev/null +++ b/src/Tests/UnitTestsModel/AthleteTest.cs @@ -0,0 +1,30 @@ +using Model; +using Xunit; + +namespace Model.Tests +{ + public class AthleteTests + { + [Fact] + public void CheckAdd_ValidUser_ReturnsTrue() + { + var athlete = new Athlete(); + + var user = new User("hello13", "dkjd.png", "John", "Doe", "john@exemple.com", "password", "Male", 180.5f, 75.3f, new System.DateTime(1990, 5, 15), new Athlete()); + var result = athlete.CheckAdd(user); + + Assert.True(result); + } + + [Fact] + public void CheckAdd_CoachUser_ReturnsFalse() + { + var athlete = new Athlete(); + + var user = new User("hello13", "dkjd.png", "John", "Doe", "john@exemple.com", "password", "Male", 180.5f, 75.3f, new System.DateTime(1990, 5, 15), new Coach()); + var result = athlete.CheckAdd(user); + + Assert.False(result); + } + } +} \ No newline at end of file diff --git a/src/Tests/UnitTestsModel/CoachTest.cs b/src/Tests/UnitTestsModel/CoachTest.cs new file mode 100644 index 0000000..bd00cdf --- /dev/null +++ b/src/Tests/UnitTestsModel/CoachTest.cs @@ -0,0 +1,32 @@ +using Model; +using Xunit; + +namespace Model.Tests +{ + public class CoachTests + { + [Fact] + public void CheckAdd_AthleteUser_ReturnsTrue() + { + var coach = new Coach(); + + var user = new User { Role = new Athlete() }; + var result = coach.CheckAdd(user); + + Assert.True(result); + Assert.Equal("CoachAthlete", coach.ToString()); + } + + [Fact] + public void CheckAdd_NonAthleteUser_ReturnsFalse() + { + var coach = new Coach(); + + var user = new User { Role = new Coach() }; + var result = coach.CheckAdd(user); + + Assert.False(result); + Assert.Equal("CoachAthlete", coach.ToString()); + } + } +} \ No newline at end of file diff --git a/src/Tests/UnitTestsModel/DataSource.cs b/src/Tests/UnitTestsModel/DataSource.cs new file mode 100644 index 0000000..503d3a2 --- /dev/null +++ b/src/Tests/UnitTestsModel/DataSource.cs @@ -0,0 +1,41 @@ +using Model; +using System.Collections.Generic; +using Xunit; + +namespace Model.Tests +{ + public class DataSourceTests + { + [Fact] + public void Constructor_WithArguments_InitializesProperties() + { + var id = 1; + var type = "Type"; + var model = "Model"; + var precision = 0.5f; + var athletes = new List(); + var activities = new List(); + + var dataSource = new DataSource(id, type, model, precision, athletes, activities); + + Assert.Equal(id, dataSource.Id); + Assert.Equal(type, dataSource.Type); + Assert.Equal(model, dataSource.Model); + Assert.Equal(precision, dataSource.Precision); + Assert.Same(athletes, dataSource.Athletes); + Assert.Same(activities, dataSource.Activities); + } + + [Fact] + public void ToString_ReturnsExpectedString() + { + var athletes = new List(); + var activities = new List(); + var dataSource = new DataSource("Type", "Model", 0.1f, athletes, activities); + + var result = dataSource.ToString(); + + Assert.Equal("DataSource #0: Type Model with a precision of 0.1", result); + } + } +} diff --git a/src/Tests/UnitTestsModel/EnumMapperTest.cs b/src/Tests/UnitTestsModel/EnumMapperTest.cs new file mode 100644 index 0000000..e2dc382 --- /dev/null +++ b/src/Tests/UnitTestsModel/EnumMapperTest.cs @@ -0,0 +1,32 @@ +using Model; +using Model.Repository; +using Moq; +using Xunit; + +namespace UnitTestsModel +{ + public class EnumMapperTests + { + [Theory] + [InlineData("None", Shared.AthleteOrderCriteria.None)] + [InlineData("ByUsername", Shared.AthleteOrderCriteria.ByUsername)] + [InlineData("ByFirstName", Shared.AthleteOrderCriteria.ByFirstName)] + [InlineData("ByLastName", Shared.AthleteOrderCriteria.ByLastName)] + [InlineData("BySexe", Shared.AthleteOrderCriteria.BySexe)] + [InlineData("ByLenght", Shared.AthleteOrderCriteria.ByLenght)] + [InlineData("ByWeight", Shared.AthleteOrderCriteria.ByWeight)] + [InlineData("ByDateOfBirth", Shared.AthleteOrderCriteria.ByDateOfBirth)] + [InlineData("ByEmail", Shared.AthleteOrderCriteria.ByEmail)] + [InlineData("ByIsCoach", Shared.AthleteOrderCriteria.ByIsCoach)] + [InlineData(null, Shared.AthleteOrderCriteria.None)] + [InlineData("InvalidValue", Shared.AthleteOrderCriteria.None)] + public void ToEnum_WithValidValue_ReturnsCorrectEnumValue(string? value, Shared.AthleteOrderCriteria expected) + { + var userRepositoryMock = new Mock(); + + var result = EnumMappeur.ToEnum(userRepositoryMock.Object, value); + + Assert.Equal(expected, result); + } + } +} diff --git a/src/Tests/UnitTestsModel/GlobalUsings.cs b/src/Tests/UnitTestsModel/GlobalUsings.cs new file mode 100644 index 0000000..8c927eb --- /dev/null +++ b/src/Tests/UnitTestsModel/GlobalUsings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file diff --git a/src/Tests/UnitTestsModel/HeartRateTest.cs b/src/Tests/UnitTestsModel/HeartRateTest.cs new file mode 100644 index 0000000..09ba756 --- /dev/null +++ b/src/Tests/UnitTestsModel/HeartRateTest.cs @@ -0,0 +1,120 @@ +using Xunit; +using System; + +namespace Model.Tests +{ + public class HeartRateTests + { + [Fact] + public void HeartRate_Constructor_WithValidParameters() + { + + int id = 1; + int bpm = 80; + TimeOnly timestamp = new TimeOnly(12, 30, 0); + Activity activity = new Activity(); + double? latitude = 40.7128; + double? longitude = -74.0060; + double? altitude = 10.5; + int? cadence = 120; + double? distance = 5.2; + double? speed = 10.5; + int? power = 200; + double? temperature = 25.5; + + var heartRate = new HeartRate(id, bpm, timestamp, activity, latitude, longitude, altitude, cadence, distance, speed, power, temperature); + + Assert.Equal(id, heartRate.Id); + Assert.Equal(bpm, heartRate.Bpm); + Assert.Equal(timestamp, heartRate.Timestamp); + Assert.Equal(activity, heartRate.Activity); + Assert.Equal(latitude, heartRate.Latitude); + Assert.Equal(longitude, heartRate.Longitude); + Assert.Equal(altitude, heartRate.Altitude); + Assert.Equal(cadence, heartRate.Cadence); + Assert.Equal(distance, heartRate.Distance); + Assert.Equal(speed, heartRate.Speed); + Assert.Equal(power, heartRate.Power); + Assert.Equal(temperature, heartRate.Temperature); + } + + [Fact] + public void HeartRate_ToString_ReturnsExpectedString() + { + int id = 1; + int bpm = 80; + TimeOnly timestamp = new TimeOnly(12, 30, 0); + Activity activity = new Activity(); + double? latitude = 40.7128; + double? longitude = -74.0060; + double? altitude = 10.5; + int? cadence = 120; + double? distance = 5.2; + double? speed = 10.5; + int? power = 200; + double? temperature = 25.5; + var heartRate = new HeartRate(id, bpm, timestamp, activity, latitude, longitude, altitude, cadence, distance, speed, power, temperature); + + var result = heartRate.ToString(); + + Assert.Contains($"HeartRate #{id}", result); + Assert.Contains($"{bpm} bpm", result); + Assert.Contains($"{timestamp:HH:mm:ss}", result); + Assert.Contains($"temperature of {temperature}°C", result); + Assert.Contains($"altitude of {altitude}m", result); + Assert.Contains($"at {longitude}°E and {latitude}°N", result); + } + [Fact] + public void Constructor_WithAllParameters_ShouldInitializeCorrectly() + { + int bpm = 70; + var timestamp = new TimeOnly(12, 0); + var activity = new Activity(); + double? latitude = 40.7128; + double? longitude = -74.0060; + double? altitude = 10.0; + int? cadence = 80; + double? distance = 5.0; + double? speed = 10.0; + int? power = 200; + double? temperature = 20.0; + + var heartRate = new HeartRate(bpm, timestamp, activity, latitude, longitude, altitude, cadence, distance, speed, power, temperature); + + Assert.NotNull(heartRate); + Assert.Equal(bpm, heartRate.Bpm); + Assert.Equal(timestamp, heartRate.Timestamp); + Assert.Equal(activity, heartRate.Activity); + Assert.Equal(latitude, heartRate.Latitude); + Assert.Equal(longitude, heartRate.Longitude); + Assert.Equal(altitude, heartRate.Altitude); + Assert.Equal(cadence, heartRate.Cadence); + Assert.Equal(distance, heartRate.Distance); + Assert.Equal(speed, heartRate.Speed); + Assert.Equal(power, heartRate.Power); + Assert.Equal(temperature, heartRate.Temperature); + } + + [Fact] + public void Constructor_WithMinimalParameters_ShouldInitializeCorrectly() + { + int bpm = 70; + var timestamp = new TimeOnly(12, 0); + + var heartRate = new HeartRate(bpm, timestamp, 1, null, null, null, null, null, null, null, null); + + Assert.NotNull(heartRate); + Assert.Equal(bpm, heartRate.Bpm); + Assert.Equal(timestamp, heartRate.Timestamp); + Assert.Null(heartRate.Activity); + Assert.Null(heartRate.Latitude); + Assert.Null(heartRate.Longitude); + Assert.Null(heartRate.Altitude); + Assert.Null(heartRate.Cadence); + Assert.Null(heartRate.Distance); + Assert.Null(heartRate.Speed); + Assert.Null(heartRate.Power); + Assert.Null(heartRate.Temperature); + } + } +} \ No newline at end of file diff --git a/src/Tests/UnitTestsModel/LargeImageTest.cs b/src/Tests/UnitTestsModel/LargeImageTest.cs new file mode 100644 index 0000000..f41cb46 --- /dev/null +++ b/src/Tests/UnitTestsModel/LargeImageTest.cs @@ -0,0 +1,158 @@ +using Model; +using Xunit; + +namespace Model.Tests +{ + public class LargeImageTests + { + [Fact] + public void Equals_ReturnsTrue_WhenBase64StringsAreEqual() + { + var base64String = "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHN0cmluZw=="; + var image1 = new LargeImage(base64String); + var image2 = new LargeImage(base64String); + + var result = image1.Equals(image2); + + Assert.True(result); + } + + [Fact] + public void Equals_ReturnsFalse_WhenBase64StringsAreDifferent() + { + var base64String1 = "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHN0cmluZw=="; + var base64String2 = "VGhpcyBpcyBhIGJhc2U2NSBlbmNvZGVkIHN0cmluZw=="; + var image1 = new LargeImage(base64String1); + var image2 = new LargeImage(base64String2); + + var result = image1.Equals(image2); + + Assert.False(result); + } + + [Fact] + public void Equals_WithNull_ReturnsFalse() + { + LargeImage image = new LargeImage("base64"); + + var result = image.Equals(null); + + + Assert.False(result); + } + + [Fact] + public void Equals_WithSameReference_ReturnsTrue() + { + LargeImage image = new LargeImage("base64"); + + var result = image.Equals(image); + + + Assert.True(result); + } + + [Fact] + public void Equals_WithDifferentType_ReturnsFalse() + { + LargeImage image = new LargeImage("base64"); + var obj = new object(); + + var result = image.Equals(obj); + + + Assert.False(result); + } + + [Fact] + public void Equals_WithDifferentBase64_ReturnsFalse() + { + LargeImage image1 = new LargeImage("base64"); + LargeImage image2 = new LargeImage("differentBase64"); + + var result = image1.Equals(image2); + + + Assert.False(result); + } + + [Fact] + public void Equals_WithSameBase64_ReturnsTrue() + { + LargeImage image1 = new LargeImage("base64"); + LargeImage image2 = new LargeImage("base64"); + + var result = image1.Equals(image2); + + + Assert.True(result); + } + + [Fact] + public void GetHashCode_ReturnsSameHashCode_ForSameBase64() + { + string base64 = "abcdefghij"; + LargeImage largeImage1 = new LargeImage(base64); + LargeImage largeImage2 = new LargeImage(base64); + + int hashCode1 = largeImage1.GetHashCode(); + int hashCode2 = largeImage2.GetHashCode(); + + Assert.Equal(hashCode1, hashCode2); + } + + [Fact] + public void Equals_ReturnsTrue_WhenComparingWithItself() + { + var largeImage = new LargeImage("base64String"); + + var result = largeImage.Equals(largeImage); + + Assert.True(result); + } + + [Fact] + public void Equals_ReturnsFalse_WhenComparingWithNull() + { + var largeImage = new LargeImage("base64String"); + + var result = largeImage.Equals(null); + + Assert.False(result); + } + + [Fact] + public void Equals_ReturnsFalse_WhenComparingWithDifferentType() + { + var largeImage = new LargeImage("base64String"); + var otherObject = new object(); + + var result = largeImage.Equals(otherObject); + + Assert.False(result); + } + + [Fact] + public void Equals_ReturnsFalse_WhenComparingWithDifferentLargeImage() + { + var largeImage1 = new LargeImage("base64String1"); + var largeImage2 = new LargeImage("base64String2"); + + var result = largeImage1.Equals(largeImage2); + + Assert.False(result); + } + + [Fact] + public void Equals_ReturnsTrue_WhenComparingWithEqualLargeImage() + { + var base64String = "base64String"; + var largeImage1 = new LargeImage(base64String); + var largeImage2 = new LargeImage(base64String); + + var result = largeImage1.Equals(largeImage2); + + Assert.True(result); + } + } +} diff --git a/src/Tests/UnitTestsModel/NotificationTest.cs b/src/Tests/UnitTestsModel/NotificationTest.cs new file mode 100644 index 0000000..7bfa92c --- /dev/null +++ b/src/Tests/UnitTestsModel/NotificationTest.cs @@ -0,0 +1,35 @@ +using Xunit; + +namespace Model.Tests +{ + public class NotificationTests + { + [Fact] + public void Constructor_InitializesPropertiesCorrectly() + { + int id = 1; + string message = "Test notification"; + DateTime date = DateTime.Now; + bool status = false; + string urgency = "High"; + int toUserId = 10; + + var notification = new Notification(id, message, date, status, urgency, toUserId); + + Assert.Equal(id, notification.IdNotif); + Assert.Equal(message, notification.Message); + Assert.Equal(date, notification.Date); + Assert.Equal(status, notification.Statut); + Assert.Equal(urgency, notification.Urgence); + Assert.Equal(toUserId, notification.ToUserId); + } + + [Fact] + public void Constructor_DefaultConstructor_ShouldInitializeCorrectly() + { + var notification = new Notification(); + + Assert.NotNull(notification); + } + } +} \ No newline at end of file diff --git a/src/Tests/UnitTestsModel/RelationshipTest.cs b/src/Tests/UnitTestsModel/RelationshipTest.cs new file mode 100644 index 0000000..6718e19 --- /dev/null +++ b/src/Tests/UnitTestsModel/RelationshipTest.cs @@ -0,0 +1,29 @@ +using Xunit; + +namespace Model.Tests +{ + public class RelationshipRequestTests + { + [Fact] + public void Constructor_InitializesPropertiesCorrectly() + { + int id = 1; + int fromUserId = 2; + int toUserId = 3; + string status = "Pending"; + + var request = new RelationshipRequest + { + Id = id, + FromUser = fromUserId, + ToUser = toUserId, + Status = status + }; + + Assert.Equal(id, request.Id); + Assert.Equal(fromUserId, request.FromUser); + Assert.Equal(toUserId, request.ToUser); + Assert.Equal(status, request.Status); + } + } +} diff --git a/src/Tests/UnitTestsModel/RoleTest.cs b/src/Tests/UnitTestsModel/RoleTest.cs new file mode 100644 index 0000000..eea0e0a --- /dev/null +++ b/src/Tests/UnitTestsModel/RoleTest.cs @@ -0,0 +1,30 @@ +using Xunit; + +namespace Model.Tests +{ + public class RoleTests + { + [Fact] + public void AddUser_WithValidUser_ReturnsTrue() + { + var role = new Athlete(); + var user = new User("hello13", "dkjd.png", "John", "Doe", "john@exemple.com", "password", "M", 180.5f, 75.3f, new System.DateTime(1990, 5, 15), new Athlete()); + + bool result = role.AddUser(user); + + Assert.True(result); + } + + [Fact] + public void AddUser_WithInvalidUser_ReturnsFalse() + { + var role = new Athlete(); + var user = new User(); + + bool result = role.AddUser(user); + + Assert.False(result); + } + + } +} diff --git a/src/Tests/UnitTestsModel/UnitTestsModel.csproj b/src/Tests/UnitTestsModel/UnitTestsModel.csproj new file mode 100644 index 0000000..2e40dc7 --- /dev/null +++ b/src/Tests/UnitTestsModel/UnitTestsModel.csproj @@ -0,0 +1,30 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/src/Tests/UnitTestsModel/UserTest.cs b/src/Tests/UnitTestsModel/UserTest.cs new file mode 100644 index 0000000..c75230c --- /dev/null +++ b/src/Tests/UnitTestsModel/UserTest.cs @@ -0,0 +1,38 @@ +using Xunit; + +namespace Model.Tests +{ + public class UserTests + { + [Fact] + public void UserConstructor_ValidParameters_ConstructsObject() + { + string username = "john_doe"; + string profilePicture = "profile.jpg"; + string lastName = "Doe"; + string firstName = "John"; + string email = "john.doe@example.com"; + string password = "password"; + string sex = "Male"; + float length = 180.5f; + float weight = 75.3f; + DateTime dateOfBirth = new DateTime(1990, 5, 15); + Role role = new Athlete(); + + User user = new User(username, profilePicture, lastName, firstName, email, password, sex, length, weight, dateOfBirth, role); + + Assert.NotNull(user); + Assert.Equal(username, user.Username); + Assert.Equal(profilePicture, user.ProfilePicture); + Assert.Equal(lastName, user.LastName); + Assert.Equal(firstName, user.FirstName); + Assert.Equal(email, user.Email); + Assert.Equal(password, user.MotDePasse); + Assert.Equal(sex, user.Sexe); + Assert.Equal(length, user.Lenght); + Assert.Equal(weight, user.Weight); + Assert.Equal(dateOfBirth, user.DateOfBirth); + Assert.Equal(role, user.Role); + } + } +} \ No newline at end of file