Compare commits

..

33 Commits

Author SHA1 Message Date
Antoine PINAGOT d51484101c Ajout Tests
continuous-integration/drone/push Build is failing Details
1 year ago
Antoine PEREDERII d01c538964 Update 'Sources/HeartTrack/Dockerfile'
continuous-integration/drone/push Build is failing Details
1 year ago
Antoine PEREDERII 89cc3c41e3 Update '.drone.yml'
continuous-integration/drone/push Build is failing Details
1 year ago
Antoine PEREDERII c4602a4b0e Update '.drone.yml'
continuous-integration/drone/push Build is failing Details
1 year ago
Antoine PEREDERII d00c5198a3 Update '.drone.yml'
continuous-integration/drone/push Build is failing Details
1 year ago
Antoine PEREDERII 0cf6cfcbff Update '.drone.yml'
continuous-integration/drone/push Build is failing Details
1 year ago
Antoine PEREDERII a3ba1c9b15 🧪 Test deploying Web Site
continuous-integration/drone/push Build is failing Details
1 year ago
David D'ALMEIDA 65eb8b9d95 Mise à jour de '.drone.yml'
continuous-integration/drone/push Build is failing Details
1 year ago
David D'ALMEIDA adb9655a87 Mise à jour de '.drone.yml'
1 year ago
Antoine PEREDERII ed8ed96133 🧪 Test CI/CD
1 year ago
Antoine PINAGOT bc87676131 Résolution erreur affichage Datagrid ticket
1 year ago
Antoine PINAGOT 207ac95462 Mise à jour de 'Sources/HeartTrack/Pages/Tickets.razor.cs'
1 year ago
Antoine PINAGOT bb7eb27e9d Test
1 year ago
Antoine PEREDERII 7052f5c3ee Update 'README.md'
1 year ago
Antoine PEREDERII 9139329c60 Merge pull request 'merge merged_APE into master for evaluation' (#2) from merged_APE into main
1 year ago
Antoine PEREDERII 75f2e18c31 update README.md
1 year ago
Antoine PINAGOT 0305b1187f Suppression code inutile
1 year ago
Antoine PEREDERII a4ae9e1426 update program.cs
1 year ago
Antoine PINAGOT bb4e8620f1 Suppression code inutile
1 year ago
Antoine PEREDERII 9a0abe0206 Merge branch 'merged_APE' of codefirst.iut.uca.fr:HeartDev/Admin into merged_APE
1 year ago
Antoine PEREDERII 7b50b1e5ad remove fakes data's files
1 year ago
Antoine PINAGOT f223bd6a79 Link fonctionne
1 year ago
Antoine PINAGOT 0e51eab49e link ticket service w/ tickets pages
1 year ago
Antoine PEREDERII 013b41e3ef merge Test_API and WORK_API into merged_APE
1 year ago
Antoine PINAGOT e29d3fc988 Résolution de la connerie d'Antoine sur ma branche et page Ticket presque terminé: sorting in coming
1 year ago
Antoine PEREDERII dd0e652dd6 updates
1 year ago
Paul LEVRAULT f1688e278d Debut siganlements
1 year ago
Antoine PEREDERII 7e56cbfb00 fix bugs with ReportDataService
1 year ago
Antoine PEREDERII a6efaf9d5f update DataServices
1 year ago
Antoine PEREDERII 2b6bb5a983 update Activities
1 year ago
Antoine PEREDERII f484afee83 add sources projects
1 year ago
Antoine PEREDERII f12aa192e9 update .giti
1 year ago
Antoine PEREDERII 37e82f06a8 update .gitignore
1 year ago

@ -0,0 +1,81 @@
kind: pipeline
type: docker
name: HeartTrack-Admin-CI
trigger:
event:
- push
steps:
- name: build
image: mcr.microsoft.com/dotnet/sdk:6.0
commands:
- cd Sources/HeartTrack/
- 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:6.0
commands:
- cd Sources/HeartTrack/
- dotnet restore HeartTrack.sln
- dotnet test HeartTrack.sln --no-restore
depends_on: [build]
- name: code-analysis
image: hub.codefirst.iut.uca.fr/marc.chevaldonne/codefirst-dronesonarplugin-dotnet8
secrets: [ SECRET_SONAR_LOGIN ]
settings:
sonar_host: https://codefirst.iut.uca.fr/sonar/
sonar_token:
from_secret: SECRET_SONAR_LOGIN
project_key: HeartTrack-API
coverage_exclusions: Tests/**, StubbedContextLib/**, StubAPI/**
duplication_exclusions: Tests/**, StubbedContextLib/**
commands:
- cd Sources/HeartTrack/
- dotnet restore HeartTrack.sln
- dotnet sonarscanner begin /k:HeartTrack-API /d:sonar.host.url=$${PLUGIN_SONAR_HOST} /d:sonar.login=$${PLUGIN_SONAR_TOKEN} /d:sonar.coverage.exclusions="Tests/**, StubbedContextLib/**, StubAPI/**, HeartTrackAPI/Utils/**" /d:sonar.cpd.exclusions="Tests/**, StubbedContextLib/**, StubAPI/**" /d:sonar.coverageReportPaths="coveragereport/SonarQube.xml"
- dotnet build HeartTrack.sln -c Release --no-restore
- dotnet test HeartTrack.sln --logger trx --no-restore /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura --collect "XPlat Code Coverage"
- reportgenerator -reports:"**/coverage.cobertura.xml" -reporttypes:SonarQube -targetdir:"coveragereport"
- dotnet publish HeartTrack.sln -c Release --no-restore -o $CI_PROJECT_DIR/build/release
- dotnet sonarscanner end /d:sonar.login=$${PLUGIN_SONAR_TOKEN}
depends_on: [ tests ]
---
kind: pipeline
type: docker
name: HeartTrack-Admin-CD
trigger:
event:
- push
steps:
- name: docker-build-and-push
image: plugins/docker
settings:
dockerfile: Sources/HeartTrack/Dockerfile
context: Sources/HeartTrack/
registry: hub.codefirst.iut.uca.fr
repo: hub.codefirst.iut.uca.fr/david.d_almeida/admin
username:
from_secret: SECRET_REGISTRY_USERNAME
password:
from_secret: SECRET_REGISTRY_PASSWORD
# database container admin
- name: deploy-container-admin
image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dockerproxy-clientdrone:latest
environment:
CODEFIRST_CLIENTDRONE_ENV_TYPE: ADMIN
IMAGENAME: hub.codefirst.iut.uca.fr/david.d_almeida/admin:latest
CONTAINERNAME: heart_track_admin
COMMAND: create
ADMINS: davidd_almeida,kevinmonteiro,antoineperederii,paullevrault,antoinepinagot,nicolasraymond,marcchevaldonne
OVERWRITE: true
depends_on: [ docker-build-and-push ]

@ -43,12 +43,38 @@ Ce dépôt contient une application Blazor conçue pour faciliter l'administrati
4. **Sécurité Intégrée**: Utilisation des fonctionnalités de sécurité de Blazor pour protéger les données sensibles. 4. **Sécurité Intégrée**: Utilisation des fonctionnalités de sécurité de Blazor pour protéger les données sensibles.
## Les attendus du projet
* [x] Implementation of a data visualization page with pagination (2 points)
* [x] Page for adding an element with validation (2 point)
* [x] Edit page of an element without validation (2 point)
* [x] Deletion of an element with a confirmation (2 point)
* [ ] Complex component (5 point)
* [x] Use API (Get / Insert / Update / Delete) (3 point)
* [x] IOC & DI use (4 point)
* [x] Localization & Globalization (at least two languages) (1 point)
* [ ] Use of the configuration (1 point)
* [ ] Logs (2 points)
* [x] Code cleanliness (2 point)
* [x] GUI (Global design, placement of buttons, ...) (2 point)
* [x] Code location (No code in views) (2 point)
* [x] The Readme (2 points)
* [x] Description of how the client solution works (code-level illustration) (6 points)
* [x] Merge request (2 points)
## Ce que nous avons fait
Pour d'avantages d'informations, voir les branches `issue_auth` et `merged_APE`
* [x] Les listing dans la page de tickets et d'Activités
* [x] La modification dans la page de tickets
* [x] La suppression dans la page de tickets
* [x] Le get by id dans la page de tickets
* [x] L'implementation de la partie API et du data service dans la pages d'Activités
* [x] L'authentification dans la branch `issue_auth` mais des problèmes persistent (les actions des services ne sont pas gerer par l'authentification)
* [ ] Le data service dans toutes les pages
* [ ] La répartitions des fonctionnalités de la page de tickets sur les autres pages
## Répartition du Git ## Répartition du Git
[**Sources**](Sources/) : **Code de l'application** [**Sources**](Sources/HeartTrack) : **Code de l'application**
[**Documents**](Documents/README_DOCUMENTS.md) : **Documentation de l'application et diagrammes**
--- ---
@ -61,7 +87,7 @@ Le projet HeartTrack utilise un modèle de flux de travail Git (Gitflow) pour or
### API PHP ### API PHP
L'application Blazor utilise une API en PHP pour récupérer les données depuis la base de données. L'application Blazor utilise une API en PHP pour récupérer les données depuis la base de données.
Pour l'utiliser, vous devez faire tourner notre projet PHP disponible [ici](https://codefirst.iut.uca.fr/git/HeartDev/Web/src/branch/API_tests) sur votre machine locale. Pour ensuite changer le type de skockage par `API` dans le fichier `monfichier.cs` dans le dossier `Data` de l'application Blazor. Pour l'utiliser, vous devez faire tourner notre projet PHP disponible [ici](https://codefirst.iut.uca.fr/git/HeartDev/Web/src/branch/API_tests) sur votre machine locale. Pour ensuite changer le type de skockage `ActivityDataServiceFactice` par `ActivityDataServiceAPI` et vice versa dans le fichier `Program.cs` de l'application Blazor en ligne 24 `Add Data Services`.
### Prérequis ### Prérequis
@ -74,30 +100,19 @@ Pour l'utiliser, vous devez faire tourner notre projet PHP disponible [ici](http
1. Clonez ce dépôt sur votre machine locale : 1. Clonez ce dépôt sur votre machine locale :
```bash ```bash
git clone https://github.com/votre-utilisateur/Blazor-User-Admin.git git clone https://codefirst.iut.uca.fr/git/HeartDev/Admin.git
``` ```
2. Accédez au répertoire du projet : 2. Lacer Visual Studio et ouvrez le projet `HeartTrack.sln` dans le dossier `Sources/HeartTrack`.
```bash
cd Blazor-User-Admin
```
3. Lancez l'application avec la commande : Pour des raison de manque de la partie php, vous ne pourrez utiliser l'application qu'en localStorage. Il est cependant possible de tester l'aaplication avec la partie API en PHP en faisant tourner en local le projet php disponible [ici](https://codefirst.iut.uca.fr/git/HeartDev/Web/src/branch/API_tests) et en changant le type de skockage `ActivityDataServiceFactice` par `ActivityDataServiceAPI` dans le fichier `Program.cs` de l'application Blazor en ligne 24 `Add Data Services` et importer les dépendances en conséquence.
```bash
dotnet run
```
4. Ouvrez votre navigateur et accédez à [https://localhost:5001](https://localhost:5001) pour voir l'application en action.
Pour des raison de manque de la partie php, vous ne pourrez utiliser l'application qu'en localStorage. Il est cependant possible de tester l'aaplication avec la partie API en PHP en faisant tourner en local le projet php disponible [ici](https://codefirst.iut.uca.fr/git/HeartDev/Web/src/branch/API_tests) et en changant le type de stockage dans le fichier `monfichier.cs` dans le dossier `Data` de l'application Blazor.
Comme ceci : Comme ceci :
```csharp ```csharp
public class MonFichier // Add Data Services
{ builder.Services.AddScoped<IActivityDataService, ActivityDataServiceAPI>();
public static string TypeStockage = "API"; builder.Services.AddScoped<ITicketDataService, TicketDataServiceAPI>();
}
``` ```
### Fabriqué avec ### Fabriqué avec

@ -3,25 +3,13 @@
using Microsoft.AspNetCore.Localization; using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
/// <summary>
/// The culture controller.
/// </summary>
[Route("[controller]/[action]")] [Route("[controller]/[action]")]
public class CultureController : Controller public class CultureController : Controller
{ {
/// <summary>
/// Sets the culture.
/// </summary>
/// <param name="culture">The culture.</param>
/// <param name="redirectUri">The redirect URI.</param>
/// <returns>
/// The action result.
/// </returns>
public IActionResult SetCulture(string culture, string redirectUri) public IActionResult SetCulture(string culture, string redirectUri)
{ {
if (culture != null) if (culture != null)
{ {
// Define a cookie with the selected culture
this.HttpContext.Response.Cookies.Append( this.HttpContext.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName, CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue( CookieRequestCultureProvider.MakeCookieValue(

@ -0,0 +1,20 @@
# Utiliser l'image SDK .NET pour construire l'application
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /app
# Copier les fichiers du projet et restaurer les dépendances
COPY *.csproj .
RUN dotnet restore
# Copier tout le reste et construire l'application
COPY . .
RUN dotnet publish -c Release -o out
# Utiliser l'image runtime .NET pour exécuter l'application
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS runtime
WORKDIR /app
COPY --from=build /app/out .
EXPOSE 8080
ENTRYPOINT ["dotnet", "HeartTrack.dll"]

@ -8,21 +8,21 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Blazored.LocalStorage" Version="4.4.0" /> <PackageReference Include="Blazored.LocalStorage" Version="4.4.0" />
<PackageReference Include="Blazorise" Version="1.4.1" />
<PackageReference Include="Blazorise.Bootstrap" Version="1.4.0" /> <PackageReference Include="Blazorise.Bootstrap" Version="1.4.0" />
<PackageReference Include="Blazorise.DataGrid" Version="1.4.0" /> <PackageReference Include="Blazorise.DataGrid" Version="1.4.0" />
<PackageReference Include="Blazorise.Icons.FontAwesome" Version="1.4.0" /> <PackageReference Include="Blazorise.Icons.FontAwesome" Version="1.4.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="6.0.1" /> <PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.1" /> <PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.1" />
<PackageReference Include="MudBlazor" Version="6.12.0" />
<PackageReference Include="xunit" Version="2.7.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Services\ActivityDataService\" /> <Folder Include="Services\ActivityDataService\" />
<Folder Include="Models\Activity\" /> <Folder Include="Models\Activity\" />
<Folder Include="Services\DataLocalService\" />
<Folder Include="Services\ReportDataService\" />
<Folder Include="Services\TicketLocalService\" />
<Folder Include="Services\UserDataService\" />
<Folder Include="wwwroot\data\" /> <Folder Include="wwwroot\data\" />
<Folder Include="Services\TicketDataService\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -30,8 +30,8 @@
<None Remove="Models\Activity\" /> <None Remove="Models\Activity\" />
<None Remove="Services\DataLocalService\" /> <None Remove="Services\DataLocalService\" />
<None Remove="Services\ReportDataService\" /> <None Remove="Services\ReportDataService\" />
<None Remove="Services\TicketLocalService\" />
<None Remove="Services\UserDataService\" /> <None Remove="Services\UserDataService\" />
<None Remove="Services\TicketDataService\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Remove="wwwroot\data\" /> <Content Remove="wwwroot\data\" />

@ -1,4 +1,4 @@

Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.8.34330.188 VisualStudioVersion = 17.8.34330.188

@ -5,8 +5,8 @@
public int IdActivity { get; set; } public int IdActivity { get; set; }
public string Type { get; set; } public string Type { get; set; }
public DateOnly Date { get; set; } public DateOnly Date { get; set; }
public TimeOnly StartTime { get; set; } public DateOnly StartTime { get; set; }
public DateTime EndTime { get; set; } public DateOnly EndTime { get; set; }
public int EffortRessenti { get; set; } public int EffortRessenti { get; set; }
public float Variability { get; set; } public float Variability { get; set; }
public float Variance { get; set; } public float Variance { get; set; }

@ -6,7 +6,7 @@ namespace HeartTrack.Models
public class ReportModel public class ReportModel
{ {
[Required] [Required]
[Range(0, 121425711425541)] [Range(0, 2500000)]
public int Id { get; set; } public int Id { get; set; }
[Required] [Required]
[StringLength(50)] [StringLength(50)]

@ -4,11 +4,8 @@
{ {
public int Id { get; set; } public int Id { get; set; }
public string Username { get; set; } public string Username { get; set; }
public string Nom { get; set; }
public string Prenom { get; set; }
public string Contexte { get; set; } public string Contexte { get; set; }
public string Description { get; set; } public string Description { get; set; }
public string Urgence { get; set; }
public Boolean isCheck { get; set; } public Boolean isCheck { get; set; }
} }
} }

@ -7,20 +7,12 @@ namespace HeartTrack.Models
public class TicketModel public class TicketModel
{ {
[Required] [Required]
[Range(0, 121425711425541)] [Range(0, 2500000)]
public int Id { get; set; } public int Id { get; set; }
[Required] [Required]
[StringLength(50, ErrorMessage = "The username must not exceed 50 characters.")] [StringLength(50, ErrorMessage = "The username must not exceed 50 characters.")]
public string Username { get; set; } public string Username { get; set; }
[Required]
[StringLength(50, ErrorMessage = "The name must not exceed 50 characters.")]
public string Nom { get; set; }
[Required]
[StringLength(25, ErrorMessage = "The last name must not exceed 25 characters.")]
public string Prenom { get; set; }
[Required] [Required]
[StringLength(25, ErrorMessage = "The subject must not exceed 25 characters.")] [StringLength(25, ErrorMessage = "The subject must not exceed 25 characters.")]
public string Contexte { get; set; } public string Contexte { get; set; }
@ -28,7 +20,6 @@ namespace HeartTrack.Models
[Required] [Required]
[StringLength(500, ErrorMessage = "Description must not exceed 500 characters.")] [StringLength(500, ErrorMessage = "Description must not exceed 500 characters.")]
public string Description { get; set; } public string Description { get; set; }
public Boolean Urgence { get; set; }
public Boolean isCheck { get; set; } = false; public Boolean isCheck { get; set; } = false;
} }
} }

@ -6,7 +6,7 @@ namespace HeartTrack.Models
public class UserModel public class UserModel
{ {
[Required] [Required]
[Range(0,121425711425541)] [Range(0,2500000)]
public int Id { get; set; } public int Id { get; set; }
[Required] [Required]

@ -16,36 +16,10 @@ namespace HeartTrack.Pages
[Inject] [Inject]
private IActivityDataService ActivitiesDataService { get; set; } private IActivityDataService ActivitiesDataService { get; set; }
[Inject]
public IStringLocalizer<Activities> Localizer { get; set; }
private async Task OnReadData() private async Task OnReadData()
{ {
//if (e.CancellationToken.IsCancellationRequested)
//{
// return;
//}
//// When you use a real API, we use this follow code
////var response = await Http.GetJsonAsync<Item[]>( $"http://my-api/api/data?page={e.Page}&pageSize={e.PageSize}" );
////var response = await Http.GetStringAsync("http://localhost:8080/api");
////var activityList = JsonConvert.DeserializeObject<List<Activity>>(response);
//var response = (await Http.GetFromJsonAsync<Activity[]>("http://localhost:8080/api")).Skip((e.Page - 1) * e.PageSize).Take(e.PageSize).ToList();
////await Http.GetFromJsonAsync<Activity[]>("http://localhost:8080/api");
////Console.WriteLine(response);
////var response = (await Http.GetFromJsonAsync<Activity[]>($"{NavigationManager.BaseUri}fake-activities.json")).Skip((e.Page - 1) * e.PageSize).Take(e.PageSize).ToList();
//if (!e.CancellationToken.IsCancellationRequested)
//{
// totalActivity = (await Http.GetFromJsonAsync<List<Activity>>("http://localhost:8080/api")).Count;
// //(await Http.GetFromJsonAsync<List<Activity>>($"{NavigationManager.BaseUri}fake-data-activity.json")).Count;
// activities = new List<Activity>(response); // an actual data for the current page
// //Console.WriteLine(totalActivity);
//}
//Console.WriteLine("Passage dans le OnInitializedAsync...");
this.activities = await this.ActivitiesDataService.getAllActivities(); this.activities = await this.ActivitiesDataService.getAllActivities();
this.totalActivity = activities.Count(); this.totalActivity = activities.Count();
} }

@ -1,7 +1,5 @@
@page "/tickets/add" @page "/tickets/add"
@* <AuthorizeView Context="authContext" Roles="admin">
<Authorized > *@
<h3>Add Ticket</h3> <h3>Add Ticket</h3>
<EditForm Model="@ticketModel" OnValidSubmit="@HandleValidSubmit"> <EditForm Model="@ticketModel" OnValidSubmit="@HandleValidSubmit">
@ -15,21 +13,9 @@
</label> </label>
</p> </p>
<p> <p>
<label for="first-name"> <label for="context">
First name:
<InputText id="first-name" @bind-Value="ticketModel.Nom" />
</label>
</p>
<p>
<label for="last-name">
Last name:
<InputText id="last-name" @bind-Value="ticketModel.Prenom" />
</label>
</p>
<p>
<label for="oui">
Context: Context:
<InputText id="oui" @bind-Value="ticketModel.Contexte" /> <InputText id="context" @bind-Value="ticketModel.Contexte" />
</label> </label>
</p> </p>
<p> <p>
@ -39,22 +25,6 @@
</label> </label>
</p> </p>
<p>
<label for="urgence">
Urgence:
<InputCheckbox id="urgence" @bind-Value="ticketModel.Urgence" />
</label>
</p>
<button type="submit">Submit</button> <button type="submit">Submit</button>
</EditForm> </EditForm>
@* </Authorized>
<Authorizing>
<h1>Loading ...</h1>
</Authorizing>
<NotAuthorized>
<h1>Authentication Failure!</h1>
<p>You're not signed in.</p>
</NotAuthorized>
</AuthorizeView> *@

@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using HeartTrack.Models; using HeartTrack.Models;
using HeartTrack.Services; using HeartTrack.Services;
using HeartTrack.Services.TicketDataService;
namespace HeartTrack.Pages namespace HeartTrack.Pages
{ {
@ -10,7 +11,7 @@ namespace HeartTrack.Pages
{ {
[Inject] [Inject]
public ILocalStorageService LocalStorage { get; set; } public ITicketDataService TicketStorage { get; set; }
[Inject] [Inject]
public NavigationManager NavigationManager { get; set; } public NavigationManager NavigationManager { get; set; }
@ -18,34 +19,23 @@ namespace HeartTrack.Pages
[Inject] [Inject]
public IWebHostEnvironment WebHostEnvironment { get; set; } public IWebHostEnvironment WebHostEnvironment { get; set; }
/// <summary>
/// The current item model
/// </summary>
public TicketModel ticketModel = new(){}; public TicketModel ticketModel = new(){};
private async void HandleValidSubmit() private async void HandleValidSubmit()
{ {
// Get the current data var currentData = await TicketStorage.getAllTickets();
var currentData = await LocalStorage.GetItemAsync<List<Ticket>>("data");
// Simulate the Id
ticketModel.Id = currentData.Max(s => s.Id) + 1; ticketModel.Id = currentData.Max(s => s.Id) + 1;
// Add the item to the current data
currentData.Add(new Ticket currentData.Add(new Ticket
{ {
Id = ticketModel.Id, Id = ticketModel.Id,
Username = ticketModel.Username, Username = ticketModel.Username,
Nom = ticketModel.Nom,
Prenom = ticketModel.Prenom,
Contexte = ticketModel.Contexte, Contexte = ticketModel.Contexte,
Description = ticketModel.Description/*, Description = ticketModel.Description/*,
Urgence = ticketModel.Urgence*/ Urgence = ticketModel.Urgence*/
}); });
// Save the data await TicketStorage.SaveAllTickets(currentData);
await LocalStorage.SetItemAsync("data", currentData);
NavigationManager.NavigateTo("tickets"); NavigationManager.NavigateTo("tickets");
} }

@ -1,4 +0,0 @@
@page "/admin-manager"
@attribute [Authorize(Roles = "superadmin")]
<h3>Admin Page</h3>

@ -1,30 +0,0 @@
@page "/banned-users"
@using HeartTrack.Models
<PageTitle>Banned Users</PageTitle>
<h1>Banned Users</h1>
This is banned users list of this website.
<div>
<NavLink class="btn btn-primary" href="banned-users/add" Match="NavLinkMatch.All">
<i class="fa fa-plus"></i> Ajouter
</NavLink>
</div>
<SurveyPrompt Title="How is Blazor working for you?" />
<DataGrid TItem="User"
Data="@users"
ReadData="@OnReadData"
TotalItems="@totalUser"
PageSize="10"
ShowPager
Responsive>
<DataGridColumn TItem="User" Field="@nameof(User.Id)" Caption="Id" />
<DataGridColumn TItem="User" Field="@nameof(User.Username)" Caption="@Localizer["Username"]" />
<DataGridColumn TItem="User" Field="@nameof(User.Nom)" Caption="@Localizer["FirstN"]" />
<DataGridColumn TItem="User" Field="@nameof(User.Prenom)" Caption="@Localizer["LastN"]" />
<DataGridColumn Caption="" />
</DataGrid>

@ -1,66 +0,0 @@
using Blazored.LocalStorage;
using Blazorise;
using Blazorise.DataGrid;
using HeartTrack.Models;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
namespace HeartTrack.Pages
{
public partial class BannedUsers
{
private List<User> users;
private int totalUser;
[Inject]
public HttpClient Http { get; set; }
[Inject]
public NavigationManager NavigationManager { get; set; }
[Inject]
public ILocalStorageService LocalStorage { get; set; }
[Inject]
public IStringLocalizer<BannedUsers> Localizer { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
// Do not treat this action if is not the first render
if (!firstRender)
{
return;
}
var currentData = await LocalStorage.GetItemAsync<User[]>("data");
// Check if data exist in the local storage
if (currentData == null)
{
// this code add in the local storage the fake data (we load the data sync for initialize the data before load the OnReadData method)
var originalData = Http.GetFromJsonAsync<User[]>($"{NavigationManager.BaseUri}fake-data.json").Result;
await LocalStorage.SetItemAsync("data", originalData);
}
}
private async Task OnReadData(DataGridReadDataEventArgs<User> e)
{
if (e.CancellationToken.IsCancellationRequested)
{
return;
}
// When you use a real API, we use this follow code
//var response = await Http.GetJsonAsync<Data[]>( $"http://my-api/api/data?page={e.Page}&pageSize={e.PageSize}" );
var response = (await LocalStorage.GetItemAsync<User[]>("data")).Skip((e.Page - 1) * e.PageSize).Take(e.PageSize).ToList();
if (!e.CancellationToken.IsCancellationRequested)
{
totalUser = (await LocalStorage.GetItemAsync<List<User>>("data")).Count;
users = new List<User>(response); // an actual data for the current page
}
}
}
}

@ -6,10 +6,11 @@
<h1>Global View</h1> <h1>Global View</h1>
This is the global statistics of our website. This is the global statistics of our website.
<div style="align-content:flex-start">
<div style=" display:block; margin:50px;">
<p>Number of views of the website</p>
<MudChart ChartType="ChartType.Line" ChartSeries="@Series" @bind-SelectedIndex="IndexChart" XAxisLabels="@XAxisLabels" Width="100%" Height="350px" ChartOptions="@Options" />
</div>
Actual language: </div>
<p>
<b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>
<SurveyPrompt Title="How is Blazor working for you?" />

@ -0,0 +1,18 @@
using MudBlazor;
namespace HeartTrack.Pages
{
public partial class Index
{
private int IndexChart = -1;
public ChartOptions Options = new ChartOptions();
public List<ChartSeries> Series = new List<ChartSeries>()
{
new ChartSeries() { Name = "Views", Data = new double[] { 90, 79, 72, 69, 62, 62, 55, 65, 70 } }
};
public string[] XAxisLabels = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep" };
}
}

@ -1,10 +0,0 @@
@page "/reports"
<PageTitle>Reports</PageTitle>
<h1>Report list</h1>
This is the report list of users.
<SurveyPrompt Title="How is Blazor working for you?" />

@ -1,20 +0,0 @@
@page "/test"
<div class="text-center bg-blue-100">
<input class="border-4 w-1/3 rounded m-6 p-6 h-8
border-blue-300" @bind-value="SearchText"
@bind-value:event="oninput" placeholder="Search by title" />
</div>
@if (!Users.Any())
{
<p>Loading some images...</p>
}
else
{
<div class="p-2 grid grid-cols-1 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3">
@foreach (var user in FilteredUsers)
{
<p>feur</p>
}
</div>
}

@ -1,28 +0,0 @@
using Blazorise;
using HeartTrack.Models;
using HeartTrack.Services;
using Microsoft.AspNetCore.Components;
namespace HeartTrack.Pages
{
partial class Test : ComponentBase
{
public IEnumerable<User> Users { get; set; } = new List<User>();
public string SearchText = "";
[Inject]
public IDataService DataService { get; set; }
[Inject]
public IWebHostEnvironment WebHostEnvironment { get; set; }
protected override async Task OnInitializedAsync()
{
Users = await DataService.List(1, 50); ;
}
List<User> FilteredUsers => Users.Where(
user => user.Username.ToLower().Contains(SearchText.ToLower())).ToList();
}
}

@ -1,4 +1,6 @@
@page "/tickets" @page "/tickets"
@using HeartTrack.Models
<PageTitle>Tickets</PageTitle> <PageTitle>Tickets</PageTitle>
@ -7,33 +9,51 @@
This is the ticket list of users. This is the ticket list of users.
<div> <div>
<NavLink class="btn btn-primary" href="tickets/add" Match="NavLinkMatch.All">
<i class="fa fa-plus"></i> Ajouter <MudButtonGroup Color="Color.Primary" Variant="Variant.Filled" Style="margin-top:50px; margin-bottom:5px;">
</NavLink> <MudButton OnClick="OnNavigateOnAddClicked">Add</MudButton>
</MudButtonGroup>
</div> </div>
@* <DataGrid TItem="Tickets" <DataGrid @ref="dataGrid"
Data="@ticket" TItem="Ticket"
PageSize="int.MaxValue" Data="@tickets"
Responsive> ReadData="@OnReadData"
<DataGridColumn TItem="Item" Field="@nameof(Item.Id)" Caption="#" /> TotalItems="@totalTicket"
<DataGridColumn TItem="Item" Field="@nameof(Item.Username)" Caption="Display name" /> PageSize="10"
<DataGridColumn TItem="Item" Field="@nameof(Item.Nom)" Caption="Stack size" /> ShowPager
<DataGridColumn TItem="Item" Field="@nameof(Item.Prenom)" Caption="Maximum durability" /> Responsive
<DataGridColumn TItem="Item" Field="@nameof(Item.Contexte)" Caption="Enchant categories"/> Sortable
<DataGridColumn TItem="Item" Field="@nameof(Item.Description)" Caption="Enchant categories"/> SortMode="DataGridSortMode.Single">
<DataGridColumn TItem="Item" Field="@nameof(Item.Urgence)" Caption="Enchant categories"/> <DataGridColumn TItem="Ticket" Field="@nameof(Ticket.Username)" Caption="Username" Width="200px"/>
<DataGridColumn TItem="Item" Field="@nameof(Item.isCheck)" Caption="" /> <DataGridColumn TItem="Ticket" Field="@nameof(Ticket.Contexte)" Caption="Context" />
<DataGridColumn TItem="Item" Field="" Caption="Check" /> <DataGridColumn TItem="Ticket" Field="@nameof(Ticket.isCheck)" Caption="Status" SortField="@nameof( Ticket.isCheck )" SortDirection="Blazorise.SortDirection.Ascending" Width="150px" Editable>
<DisplayTemplate> <DisplayTemplate>
@(string.Join(", ", ((Item)context).EnchantCategories)) @if (context.isCheck)
{
<MudChip Variant="Variant.Outlined" Color="Color.Success">Closed</MudChip>
} else
{
<MudChip Variant="Variant.Outlined" Color="Color.Error">Open</MudChip>
}
</DisplayTemplate> </DisplayTemplate>
</DataGridColumn> </DataGridColumn>
<DataGridColumn TItem="Item" Field="@nameof(Item.RepairWith)" Caption="Repair with"> <DataGridColumn TItem="Ticket" Field="@nameof(Ticket.Id)" Caption="Actions" Sortable="false" Width="150px">
<DisplayTemplate> <DisplayTemplate>
@(string.Join(", ", ((Item)context).RepairWith)) @if (context.isCheck)
{
<MudFab Color="Color.Tertiary" StartIcon="@Icons.Material.Filled.RemoveRedEye" Size="Size.Small" @onclick="(() => OnView(context.Id))"/>
<MudFab Color="Color.Secondary" StartIcon="@Icons.Material.Filled.Delete" Size="Size.Small" @onclick="() => OnDelete(context)" />
}
else
{
<MudFab Color="Color.Tertiary" StartIcon="@Icons.Material.Filled.RemoveRedEye" Size="Size.Small" @onclick="() => OnView(context.Id)" />
<MudFab Color="Color.Secondary" StartIcon="@Icons.Material.Filled.Close" Size="Size.Small" @onclick="() => OnClose(context.Id)" />
<MudFab Color="Color.Secondary" StartIcon="@Icons.Material.Filled.Delete" Size="Size.Small" @onclick="() => OnDelete(context)" />
}
</DisplayTemplate> </DisplayTemplate>
</DataGridColumn> </DataGridColumn>
<DataGridColumn TItem="Item" Field="@nameof(Item.CreatedDate)" Caption="Created date" DisplayFormat="{0:d}" DisplayFormatProvider="@System.Globalization.CultureInfo.GetCultureInfo("fr-FR")" /> </DataGrid>
</DataGrid> *@

@ -0,0 +1,100 @@
using Blazored.LocalStorage;
using Blazorise;
using Blazorise.DataGrid;
using HeartTrack.Models;
using HeartTrack.Services;
using HeartTrack.Services.TicketDataService;
using Microsoft.AspNetCore.Components;
using MudBlazor;
using System;
using static MudBlazor.CategoryTypes;
namespace HeartTrack.Pages
{
public partial class Tickets
{
private List<Ticket> tickets;
private int totalTicket;
private DataGrid<Ticket> dataGrid;
[Inject]
public HttpClient Http { get; set; }
[Inject]
public ILocalStorageService LocalStorage { get; set; }
[Inject]
public ITicketDataService TicketService { get; set; }
[Inject]
public NavigationManager NavigationManager { get; set; }
[Inject]
private ISnackbar Snackbar { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
// Do not treat this action if is not the first render
if (!firstRender)
{
return;
}
var currentData = await LocalStorage.GetItemAsync<Ticket[]>("data");
// Check if data exist in the local storage
if (currentData == null)
{
// this code add in the local storage the fake data (we load the data sync for initialize the data before load the OnReadData method)
var originalData = Http.GetFromJsonAsync<Ticket[]>($"{NavigationManager.BaseUri}fake-tickets.json").Result;
await LocalStorage.SetItemAsync("data", originalData);
}
}
private async Task OnReadData(DataGridReadDataEventArgs<Ticket> e)
{
if (e.CancellationToken.IsCancellationRequested)
{
return;
}
// When you use a real API, we use this follow code
//var response = await Http.GetJsonAsync<Data[]>( $"http://my-api/api/data?page={e.Page}&pageSize={e.PageSize}" );
var response = (await LocalStorage.GetItemAsync<Ticket[]>("data")).Skip((e.Page - 1) * e.PageSize).Take(e.PageSize).ToList();
if (!e.CancellationToken.IsCancellationRequested)
{
totalTicket = (await LocalStorage.GetItemAsync<List<Ticket>>("data")).Count;
tickets = new List<Ticket>(response); // an actual data for the current page
}
}
private async void OnClose(int id)
{
await TicketService.Close(id);
NavigationManager.NavigateTo("tickets", true);
Snackbar.Add("Ticket fermé !");
}
private void OnView(int id)
{
NavigationManager.NavigateTo("tickets/view/"+id);
}
private void OnNavigateOnAddClicked()
{
NavigationManager.NavigateTo("tickets/add");
}
private async void OnDelete(Ticket t)
{
await TicketService.RemoveTicket(t);
NavigationManager.NavigateTo("tickets", true);
}
}
}

@ -0,0 +1,19 @@
@page "/tickets/view/{Id:int}"
<h3>Ticket number @Id</h3>
<p>
Username: @ticket.Username
</p>
<p>
Contexte: @ticket.Contexte
</p>
<p>
Description: @ticket.Description
</p>
<p>
Status: @ticket.isCheck
</p>
<MudButton @OnClick="OnNavigateOnReturnClicked">Return</MudButton>

@ -0,0 +1,43 @@
using HeartTrack.Models;
using HeartTrack.Services;
using HeartTrack.Services.TicketDataService;
using Microsoft.AspNetCore.Components;
namespace HeartTrack.Pages
{
public partial class ViewTicket
{
[Parameter]
public int Id { get; set; }
private Ticket ticket { get; set; } = new();
[Inject]
public ITicketDataService TicketService { get; set; }
[Inject]
public NavigationManager NavigationManager { get; set; }
[Inject]
public IWebHostEnvironment WebHostEnvironment { get; set; }
protected async Task OnInitializedAsync()
{
var item = await TicketService.getTicketById(Id);
ticket = new Ticket
{
Id = item.Id,
Username = item.Username,
Contexte = item.Contexte,
Description = item.Description,
isCheck = item.isCheck
};
}
private void OnNavigateOnReturnClicked()
{
NavigationManager.NavigateTo("/tickets", true);
}
}
}

@ -30,8 +30,14 @@
<script src="_framework/blazor.server.js"></script> <script src="_framework/blazor.server.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css">
@* Blazorised *@
<link href="_content/Blazorise/blazorise.css" rel="stylesheet" /> <link href="_content/Blazorise/blazorise.css" rel="stylesheet" />
<link href="_content/Blazorise.Bootstrap/blazorise.bootstrap.css" rel="stylesheet" /> <link href="_content/Blazorise.Bootstrap/blazorise.bootstrap.css" rel="stylesheet" />
@* MudBlazor *@
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
</body> </body>
</html> </html>

@ -1,5 +1,3 @@
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Blazorise; using Blazorise;
using Blazorise.Bootstrap; using Blazorise.Bootstrap;
using Blazorise.Icons.FontAwesome; using Blazorise.Icons.FontAwesome;
@ -7,21 +5,63 @@ using Microsoft.AspNetCore.Localization;
using System.Globalization; using System.Globalization;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Blazored.LocalStorage; using Blazored.LocalStorage;
using HeartTrack.Services; using HeartTrack.Services.ActivityDataService;
using Microsoft.AspNetCore.Components.Authorization; using HeartTrack.Services.TicketDataService;
using MudBlazor.Services;
using HeartTrack.Services.ActivityDataServiceFactice;
using HeartTrack.Services.TicketDataServiceFactice;
using MudBlazor;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
// Add Badge Component services
builder.Services.AddMudServices(config =>
{
config.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.BottomLeft;
config.SnackbarConfiguration.PreventDuplicates = false;
config.SnackbarConfiguration.NewestOnTop = false;
config.SnackbarConfiguration.ShowCloseIcon = true;
config.SnackbarConfiguration.VisibleStateDuration = 10000;
config.SnackbarConfiguration.HideTransitionDuration = 500;
config.SnackbarConfiguration.ShowTransitionDuration = 500;
config.SnackbarConfiguration.SnackbarVariant = Variant.Filled;
});
// Add services to the container. // Add services to the container.
builder.Services.AddRazorPages(); builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor(); builder.Services.AddServerSideBlazor();
builder.Services.AddHttpClient(); builder.Services.AddHttpClient();
// Add Services // Add Data Services
builder.Services.AddScoped<IDataService, DataLocalService>();
builder.Services.AddScoped<IActivityDataService, ActivityDataServiceFactice>(); builder.Services.AddScoped<IActivityDataService, ActivityDataServiceFactice>();
builder.Services.AddScoped<ITicketDataService, TicketDataServiceFactice>();
builder.Services.AddBlazorise()
.AddBootstrapProviders()
.AddFontAwesomeIcons();
// Add the controller of the app
builder.Services.AddControllers();
// Add the localization to the app and specify the resources path
builder.Services.AddLocalization(opts => { opts.ResourcesPath = "Resources"; });
// Configure the localtization
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
// Set the default culture of the web site
options.DefaultRequestCulture = new RequestCulture(new CultureInfo("en-US"));
// Declare the supported culture
options.SupportedCultures = new List<CultureInfo> { new CultureInfo("en-US"), new CultureInfo("fr-FR") };
options.SupportedUICultures = new List<CultureInfo> { new CultureInfo("en-US"), new CultureInfo("fr-FR") };
});
builder.Services.AddBlazoredLocalStorage();
builder.Services.AddHttpClient();
builder.Services.AddBlazorise() builder.Services.AddBlazorise()
.AddBootstrapProviders() .AddBootstrapProviders()
@ -81,4 +121,3 @@ app.MapBlazorHub();
app.MapFallbackToPage("/_Host"); app.MapFallbackToPage("/_Host");
app.Run(); app.Run();

@ -1,4 +1,7 @@
using System; using System;
using HeartTrack.Models;
using Microsoft.AspNetCore.Components;
namespace HeartTrack.Services.ActivityDataService namespace HeartTrack.Services.ActivityDataService
{ {
public class ActivityDataServiceAPI : IActivityDataService public class ActivityDataServiceAPI : IActivityDataService
@ -7,7 +10,7 @@ namespace HeartTrack.Services.ActivityDataService
private HttpClient _clientHttp { get; set; } private HttpClient _clientHttp { get; set; }
public ActivityDataServiceFactice(HttpClient clientHttp) public ActivityDataServiceAPI(HttpClient clientHttp)
{ {
this._clientHttp = clientHttp; this._clientHttp = clientHttp;
} }
@ -18,17 +21,17 @@ namespace HeartTrack.Services.ActivityDataService
if (response.IsSuccessStatusCode) if (response.IsSuccessStatusCode)
{ {
// La requête a réussi Console.WriteLine("API - Activité avec l'id " + a.IdActivity + " ajouté avec succès");
} }
else else
{ {
// La requête a échoué Console.WriteLine("API - Problème ajout Activité");
} }
} }
public async Task<Activity> getActivityById(int id) public async Task<Activity> getActivityById(int id)
{ {
Activity activity = await _clientHttp.GetFromJsonAsync<List<Activity>>("http://localhost:8080/api/activities/{id}"); Activity activity = await _clientHttp.GetFromJsonAsync<Activity>("http://localhost:8080/api/activities/{id}");
return activity; return activity;
} }
@ -44,11 +47,11 @@ namespace HeartTrack.Services.ActivityDataService
if (response.IsSuccessStatusCode) if (response.IsSuccessStatusCode)
{ {
// La requête a réussi Console.WriteLine("API - Activité avec l'id " + a.IdActivity + " supprimé avec succès");
} }
else else
{ {
// La requête a échoué Console.WriteLine("API - Problème suppression Activité");
} }
} }
@ -58,11 +61,11 @@ namespace HeartTrack.Services.ActivityDataService
if (response.IsSuccessStatusCode) if (response.IsSuccessStatusCode)
{ {
// La requête a réussi Console.WriteLine("API - List d'activités sauvegardé avec succès");
} }
else else
{ {
// La requête a échoué Console.WriteLine("API - Problème sauvegarde List d'activités");
} }
} }
@ -72,11 +75,11 @@ namespace HeartTrack.Services.ActivityDataService
if (response.IsSuccessStatusCode) if (response.IsSuccessStatusCode)
{ {
// La requête a réussi Console.WriteLine("API - Activité avec l'id " + a.IdActivity + " mis à jour avec succès");
} }
else else
{ {
// La requête a échoué Console.WriteLine("API - Problème mise à jour Activité");
} }
} }
} }

@ -1,85 +0,0 @@
using Blazored.LocalStorage;
using HeartTrack.Models;
using Microsoft.AspNetCore.Components;
namespace HeartTrack.Services
{
public class DataLocalService : IDataService
{
private readonly HttpClient _http;
private readonly ILocalStorageService _localStorage;
private readonly NavigationManager _navigationManager;
private readonly IWebHostEnvironment _webHostEnvironment;
public DataLocalService(
ILocalStorageService localStorage,
HttpClient http,
IWebHostEnvironment webHostEnvironment,
NavigationManager navigationManager)
{
_localStorage = localStorage;
_http = http;
_webHostEnvironment = webHostEnvironment;
_navigationManager = navigationManager;
}
public async Task Add(UserModel model)
{
// Get the current data
var currentData = await _localStorage.GetItemAsync<List<User>>("data");
// Simulate the Id
model.Id = currentData.Max(s => s.Id) + 1;
// Add the item to the current data
currentData.Add(new User
{
Id = model.Id,
Username = model.Username,
Nom = model.FirstName,
Prenom = model.LastName,
Email = model.Email,
Password = model.Password,
Sexe = model.Sexe,
Taille = model.Taille,
Poids = model.Poids,
BirthDate = model.BirthDate
});
// Save the data
await _localStorage.SetItemAsync("data", currentData);
}
public async Task<int> Count()
{
// Load data from the local storage
var currentData = await _localStorage.GetItemAsync<User[]>("data");
// Check if data exist in the local storage
if (currentData == null)
{
// this code add in the local storage the fake data
var originalData = await _http.GetFromJsonAsync<User[]>($"{_navigationManager.BaseUri}fake-data.json");
await _localStorage.SetItemAsync("data", originalData);
}
return (await _localStorage.GetItemAsync<User[]>("data")).Length;
}
public async Task<List<User>> List(int currentPage, int pageSize)
{
// Load data from the local storage
var currentData = await _localStorage.GetItemAsync<User[]>("data");
// Check if data exist in the local storage
if (currentData == null)
{
// this code add in the local storage the fake data
var originalData = await _http.GetFromJsonAsync<User[]>($"{_navigationManager.BaseUri}fake-data.json");
await _localStorage.SetItemAsync("data", originalData);
}
return (await _localStorage.GetItemAsync<User[]>("data")).Skip((currentPage - 1) * pageSize).Take(pageSize).ToList();
}
}
}

@ -1,13 +0,0 @@
using HeartTrack.Models;
namespace HeartTrack.Services
{
public interface IDataService
{
Task Add(UserModel model);
Task<int> Count();
Task<List<User>> List(int currentPage, int pageSize);
}
}

@ -1,21 +0,0 @@
using System;
using HeartTrack.Models;
namespace HeartTrack.Services.ReportDataService
{
public interface IReportDataService
{
public Task<List<Report>> getAllReports();
public Task SaveAllReports(List<Report> list);
public Task AddReport(Report u);
public Task RemoveReport(Report u);
public Task UpdateReport(Report u);
public Task<Report> getReportById(int id);
}
}

@ -1,84 +0,0 @@
using System;
namespace HeartTrack.Services.ActivityDataService
{
public class ActivityDataServiceAPI : IActivityDataService
{
[Inject]
private HttpClient _clientHttp { get; set; }
public ActivityDataServiceFactice(HttpClient clientHttp)
{
this._clientHttp = clientHttp;
}
public async Task AddActivity(Activity a)
{
HttpResponseMessage response = await _clientHttp.PostAsJsonAsync("http://localhost:8080/api/activities", a);
if (response.IsSuccessStatusCode)
{
// La requête a réussi
}
else
{
// La requête a échoué
}
}
public async Task<Activity> getActivityById(int id)
{
Activity activity = await _clientHttp.GetFromJsonAsync<List<Activity>>("http://localhost:8080/api/activities/{id}");
return activity;
}
public async Task<List<Activity>> getAllActivities()
{
List<Activity> lActivities = await _clientHttp.GetFromJsonAsync<List<Activity>>("http://localhost:8080/api/activities");
return lActivities;
}
public async Task RemoveActivity(Activity a)
{
HttpResponseMessage response = await _clientHttp.DeleteAsync($"http://localhost:8080/api/activities/{a.IdActivity}");
if (response.IsSuccessStatusCode)
{
// La requête a réussi
}
else
{
// La requête a échoué
}
}
public async Task SaveAllActivities(List<Activity> list)
{
HttpResponseMessage response = await _clientHttp.PutAsJsonAsync("http://localhost:8080/api/activities", list);
if (response.IsSuccessStatusCode)
{
// La requête a réussi
}
else
{
// La requête a échoué
}
}
public async Task UpdateActivity(Activity a)
{
HttpResponseMessage response = await _clientHttp.PutAsJsonAsync($"http://localhost:8080/api/activities/{a.IdActivity}", a);
if (response.IsSuccessStatusCode)
{
// La requête a réussi
}
else
{
// La requête a échoué
}
}
}
}

@ -1,140 +0,0 @@
using System;
using Blazored.LocalStorage;
using HeartTrack.Models;
using HeartTrack.Services.ActivityDataService;
using Microsoft.AspNetCore.Components;
namespace HeartTrack.Services.ActivityDataServiceFactice
{
public class ActivityDataServiceFactice : IActivityDataService
{
[Inject]
private HttpClient _clientHttp { get; set; }
[Inject]
public ILocalStorageService _localStorage { get; set; }
[Inject]
public NavigationManager _navigationManager { get; set; }
private String EmplacementLocalStorage { get; set; }
private String EmplacementJson { get; set; }
public ActivityDataServiceFactice(HttpClient clientHttp, ILocalStorageService localStorage, NavigationManager navigationManager)
{
this._clientHttp = clientHttp;
this._localStorage = localStorage;
this._navigationManager = navigationManager;
this.EmplacementLocalStorage = "activitiesData";
this.EmplacementJson = $"{_navigationManager.BaseUri}data/fake-activities.json";
}
public async Task AddActivity(Activity a)
{
List<Activity> data = await getAllActivities();
data.Add(a);
await this.SaveAllActivities(data);
}
public async Task<Activity> getActivityById(int id)
{
Console.WriteLine("Passage dans le getFromPseudo...");
List<Activity> activities = await getAllActivities();
Activity? temp = null;
foreach (Activity a in activities)
{
if (a.IdActivity == id)
{
temp = a;
}
}
return temp;
}
public async Task<List<Activity>> getAllActivities()
{
List<Activity> lActivities = new List<Activity>();
lActivities = await this.getActivitiesFromLocalStorage();
if(lActivities.Count == 0)
{
lActivities = await this.getActivitiesFromJson(this.EmplacementJson);
await this.saveActivitiesLocalStorage(lActivities);
}
return lActivities;
}
private async Task<List<Activity>> getActivitiesFromJson(String cheminVersJson)
{
List<Activity> activitiesDeserialiser = new List<Activity>();
var data = await _clientHttp.GetFromJsonAsync<Activity[]>(cheminVersJson);
activitiesDeserialiser = data.ToList();
return activitiesDeserialiser;
}
private async Task<List<Activity>> getActivitiesFromLocalStorage()
{
List<Activity> activitiesFromLocalStorage = null;
var data = await _localStorage.GetItemAsync<Activity[]>(EmplacementLocalStorage);
if (data == null)
{
activitiesFromLocalStorage = new List<Activity>();
}
else
{
activitiesFromLocalStorage = data.ToList();
}
return activitiesFromLocalStorage;
}
public async Task RemoveActivity(Activity a)
{
List<Activity> data = await getAllActivities();
int index = -1;
foreach (Activity temp in data)
{
if (temp.IdActivity == a.IdActivity)
{
index = data.IndexOf(temp);
}
}
if (index != -1)
{
data.RemoveAt(index);
}
await this.SaveAllActivities(data);
data = await this.getAllActivities();
}
public async Task SaveAllActivities(List<Activity> list)
{
await this.saveActivitiesLocalStorage(list);
}
private async Task saveActivitiesLocalStorage(List<Activity> lActivities)
{
await _localStorage.SetItemAsync(this.EmplacementLocalStorage, lActivities);
}
public async Task UpdateActivity(Activity a)
{
await this.RemoveActivity(a);
await this.AddActivity(a);
}
}
}

@ -0,0 +1,22 @@
using System;
using HeartTrack.Models;
namespace HeartTrack.Services.TicketDataService
{
public interface ITicketDataService
{
public Task<List<Ticket>> getAllTickets();
public Task SaveAllTickets(List<Ticket> list);
public Task AddTicket(Ticket t);
public Task RemoveTicket(Ticket t);
public Task UpdateTicket(Ticket t);
public Task<Ticket> getTicketById(int id);
public Task Close(int Id);
}
}

@ -0,0 +1,91 @@
using System;
using HeartTrack.Models;
using Microsoft.AspNetCore.Components;
namespace HeartTrack.Services.TicketDataService
{
public class TicketDataServiceAPI : ITicketDataService
{
[Inject]
private HttpClient _clientHttp { get; set; }
public TicketDataServiceAPI(HttpClient clientHttp)
{
this._clientHttp = clientHttp;
}
public async Task AddTicket(Ticket t)
{
HttpResponseMessage response = await _clientHttp.PostAsJsonAsync("http://localhost:8080/api/tickets", t);
if (response.IsSuccessStatusCode)
{
Console.WriteLine("API - Ticket avec l'id " + t.Id + " ajouté avec succès");
}
else
{
Console.WriteLine("API - Problème ajout Ticket");
}
}
public async Task<Ticket> getTicketById(int id)
{
Ticket Ticket = await _clientHttp.GetFromJsonAsync<Ticket>("http://localhost:8080/api/tickets/{id}");
return Ticket;
}
public async Task<List<Ticket>> getAllTickets()
{
List<Ticket> lTickets = await _clientHttp.GetFromJsonAsync<List<Ticket>>("http://localhost:8080/api/tickets");
return lTickets;
}
public async Task RemoveTicket(Ticket t)
{
HttpResponseMessage response = await _clientHttp.DeleteAsync($"http://localhost:8080/api/tickets/{t.Id}");
if (response.IsSuccessStatusCode)
{
Console.WriteLine("API - Ticket avec l'id " + t.Id + " supprimé avec succès");
}
else
{
Console.WriteLine("API - Problème suppression Ticket");
}
}
public async Task SaveAllTickets(List<Ticket> list)
{
HttpResponseMessage response = await _clientHttp.PutAsJsonAsync("http://localhost:8080/api/tickets", list);
if (response.IsSuccessStatusCode)
{
Console.WriteLine("API - List de tickets sauvegardé avec succès");
}
else
{
Console.WriteLine("API - Problème sauvegarde List de tickets");
}
}
public async Task UpdateTicket(Ticket t)
{
HttpResponseMessage response = await _clientHttp.PutAsJsonAsync($"http://localhost:8080/api/tickets/{t.Id}", t);
if (response.IsSuccessStatusCode)
{
Console.WriteLine("API - Ticket avec l'id " + t.Id + " mis à jour avec succès");
}
else
{
Console.WriteLine("API - Problème mise à jour Ticket");
}
}
public async Task Close(int id)
{
}
}
}

@ -0,0 +1,144 @@
using System;
using Blazored.LocalStorage;
using HeartTrack.Models;
using HeartTrack.Services.TicketDataService;
using Microsoft.AspNetCore.Components;
namespace HeartTrack.Services.TicketDataServiceFactice
{
public class TicketDataServiceFactice : ITicketDataService
{
[Inject]
private HttpClient _clientHttp { get; set; }
[Inject]
public ILocalStorageService _localStorage { get; set; }
[Inject]
public NavigationManager _navigationManager { get; set; }
private String EmplacementLocalStorage { get; set; }
private String EmplacementJson { get; set; }
public TicketDataServiceFactice(HttpClient clientHttp, ILocalStorageService localStorage, NavigationManager navigationManager)
{
this._clientHttp = clientHttp;
this._localStorage = localStorage;
this._navigationManager = navigationManager;
this.EmplacementLocalStorage = "ticketsData";
this.EmplacementJson = $"{_navigationManager.BaseUri}data/fake-tickets.json";
}
public async Task AddTicket(Ticket t)
{
List<Ticket> data = await getAllTickets();
data.Add(t);
await this.SaveAllTickets(data);
}
public async Task<Ticket> getTicketById(int id)
{
List<Ticket> tickets = await getAllTickets();
Ticket? temp = null;
foreach (Ticket t in tickets)
{
if (t.Id == id)
{
temp = t;
}
}
return temp;
}
public async Task<List<Ticket>> getAllTickets()
{
List<Ticket> lTickets = new List<Ticket>();
lTickets = await this.getTicketsFromLocalStorage();
if (lTickets.Count == 0)
{
lTickets = await this.getTicketsFromJson(this.EmplacementJson);
await this.saveTicketsLocalStorage(lTickets);
}
return lTickets;
}
private async Task<List<Ticket>> getTicketsFromJson(String cheminVersJson)
{
List<Ticket> TicketsDeserialiser = new List<Ticket>();
var data = await _clientHttp.GetFromJsonAsync<Ticket[]>(cheminVersJson);
TicketsDeserialiser = data.ToList();
return TicketsDeserialiser;
}
private async Task<List<Ticket>> getTicketsFromLocalStorage()
{
List<Ticket> TicketsFromLocalStorage = null;
var data = await _localStorage.GetItemAsync<Ticket[]>(EmplacementLocalStorage);
if (data == null)
{
TicketsFromLocalStorage = new List<Ticket>();
}
else
{
TicketsFromLocalStorage = data.ToList();
}
return TicketsFromLocalStorage;
}
public async Task RemoveTicket(Ticket t)
{
// Get the current data
var currentData = await _localStorage.GetItemAsync<List<Ticket>>("data");
// Get the item int the list
var item = currentData.FirstOrDefault(w => w.Id == t.Id);
// Delete item in
currentData.Remove(item);
// Save the data
await _localStorage.SetItemAsync("data", currentData);
}
public async Task SaveAllTickets(List<Ticket> list)
{
await this.saveTicketsLocalStorage(list);
}
private async Task saveTicketsLocalStorage(List<Ticket> lTickets)
{
await _localStorage.SetItemAsync(this.EmplacementLocalStorage, lTickets);
}
public async Task UpdateTicket(Ticket t)
{
await this.RemoveTicket(t);
await this.AddTicket(t);
}
public async Task Close(int Id)
{
// Get the current data
var currentData = await _localStorage.GetItemAsync<List<Ticket>>("data");
// Get the item int the list
var item = currentData.FirstOrDefault(w => w.Id == Id);
// Update item status
item.isCheck = true;
// Save the data
await _localStorage.SetItemAsync("data", currentData);
}
}
}

@ -1,22 +0,0 @@
using System;
using HeartTrack.Models;
namespace HeartTrack.Services.ActivityDataService
{
public interface IActivityDataService
{
public Task<List<Activity>> getAllActivities();
public Task SaveAllActivities(List<Activity> list);
public Task ResetDataActivities();
public Task AddActivity(Activity u);
public Task RemoveActivity(Activity u);
public Task UpdateActivity(Activity u);
public Task<Activity> getActivityById(int id);
}
}

@ -1,84 +0,0 @@
using System;
namespace HeartTrack.Services.ActivityDataService
{
public class ActivityDataServiceAPI : IActivityDataService
{
[Inject]
private HttpClient _clientHttp { get; set; }
public ActivityDataServiceFactice(HttpClient clientHttp)
{
this._clientHttp = clientHttp;
}
public async Task AddActivity(Activity a)
{
HttpResponseMessage response = await _clientHttp.PostAsJsonAsync("http://localhost:8080/api/activities", a);
if (response.IsSuccessStatusCode)
{
// La requête a réussi
}
else
{
// La requête a échoué
}
}
public async Task<Activity> getActivityById(int id)
{
Activity activity = await _clientHttp.GetFromJsonAsync<List<Activity>>("http://localhost:8080/api/activities/{id}");
return activity;
}
public async Task<List<Activity>> getAllActivities()
{
List<Activity> lActivities = await _clientHttp.GetFromJsonAsync<List<Activity>>("http://localhost:8080/api/activities");
return lActivities;
}
public async Task RemoveActivity(Activity a)
{
HttpResponseMessage response = await _clientHttp.DeleteAsync($"http://localhost:8080/api/activities/{a.IdActivity}");
if (response.IsSuccessStatusCode)
{
// La requête a réussi
}
else
{
// La requête a échoué
}
}
public async Task SaveAllActivities(List<Activity> list)
{
HttpResponseMessage response = await _clientHttp.PutAsJsonAsync("http://localhost:8080/api/activities", list);
if (response.IsSuccessStatusCode)
{
// La requête a réussi
}
else
{
// La requête a échoué
}
}
public async Task UpdateActivity(Activity a)
{
HttpResponseMessage response = await _clientHttp.PutAsJsonAsync($"http://localhost:8080/api/activities/{a.IdActivity}", a);
if (response.IsSuccessStatusCode)
{
// La requête a réussi
}
else
{
// La requête a échoué
}
}
}
}

@ -1,140 +0,0 @@
using System;
using Blazored.LocalStorage;
using HeartTrack.Models;
using HeartTrack.Services.ActivityDataService;
using Microsoft.AspNetCore.Components;
namespace HeartTrack.Services.ActivityDataServiceFactice
{
public class ActivityDataServiceFactice : IActivityDataService
{
[Inject]
private HttpClient _clientHttp { get; set; }
[Inject]
public ILocalStorageService _localStorage { get; set; }
[Inject]
public NavigationManager _navigationManager { get; set; }
private String EmplacementLocalStorage { get; set; }
private String EmplacementJson { get; set; }
public ActivityDataServiceFactice(HttpClient clientHttp, ILocalStorageService localStorage, NavigationManager navigationManager)
{
this._clientHttp = clientHttp;
this._localStorage = localStorage;
this._navigationManager = navigationManager;
this.EmplacementLocalStorage = "activitiesData";
this.EmplacementJson = $"{_navigationManager.BaseUri}data/fake-activities.json";
}
public async Task AddActivity(Activity a)
{
List<Activity> data = await getAllActivities();
data.Add(a);
await this.SaveAllActivities(data);
}
public async Task<Activity> getActivityById(int id)
{
Console.WriteLine("Passage dans le getFromPseudo...");
List<Activity> activities = await getAllActivities();
Activity? temp = null;
foreach (Activity a in activities)
{
if (a.IdActivity == id)
{
temp = a;
}
}
return temp;
}
public async Task<List<Activity>> getAllActivities()
{
List<Activity> lActivities = new List<Activity>();
lActivities = await this.getActivitiesFromLocalStorage();
if(lActivities.Count == 0)
{
lActivities = await this.getActivitiesFromJson(this.EmplacementJson);
await this.saveActivitiesLocalStorage(lActivities);
}
return lActivities;
}
private async Task<List<Activity>> getActivitiesFromJson(String cheminVersJson)
{
List<Activity> activitiesDeserialiser = new List<Activity>();
var data = await _clientHttp.GetFromJsonAsync<Activity[]>(cheminVersJson);
activitiesDeserialiser = data.ToList();
return activitiesDeserialiser;
}
private async Task<List<Activity>> getActivitiesFromLocalStorage()
{
List<Activity> activitiesFromLocalStorage = null;
var data = await _localStorage.GetItemAsync<Activity[]>(EmplacementLocalStorage);
if (data == null)
{
activitiesFromLocalStorage = new List<Activity>();
}
else
{
activitiesFromLocalStorage = data.ToList();
}
return activitiesFromLocalStorage;
}
public async Task RemoveActivity(Activity a)
{
List<Activity> data = await getAllActivities();
int index = -1;
foreach (Activity temp in data)
{
if (temp.IdActivity == a.IdActivity)
{
index = data.IndexOf(temp);
}
}
if (index != -1)
{
data.RemoveAt(index);
}
await this.SaveAllActivities(data);
data = await this.getAllActivities();
}
public async Task SaveAllActivities(List<Activity> list)
{
await this.saveActivitiesLocalStorage(list);
}
private async Task saveActivitiesLocalStorage(List<Activity> lActivities)
{
await _localStorage.SetItemAsync(this.EmplacementLocalStorage, lActivities);
}
public async Task UpdateActivity(Activity a)
{
await this.RemoveActivity(a);
await this.AddActivity(a);
}
}
}

@ -1,22 +0,0 @@
using System;
using HeartTrack.Models;
namespace HeartTrack.Services.ActivityDataService
{
public interface IActivityDataService
{
public Task<List<Activity>> getAllActivities();
public Task SaveAllActivities(List<Activity> list);
public Task ResetDataActivities();
public Task AddActivity(Activity u);
public Task RemoveActivity(Activity u);
public Task UpdateActivity(Activity u);
public Task<Activity> getActivityById(int id);
}
}

@ -1,84 +0,0 @@
using System;
namespace HeartTrack.Services.ActivityDataService
{
public class ActivityDataServiceAPI : IActivityDataService
{
[Inject]
private HttpClient _clientHttp { get; set; }
public ActivityDataServiceFactice(HttpClient clientHttp)
{
this._clientHttp = clientHttp;
}
public async Task AddActivity(Activity a)
{
HttpResponseMessage response = await _clientHttp.PostAsJsonAsync("http://localhost:8080/api/activities", a);
if (response.IsSuccessStatusCode)
{
// La requête a réussi
}
else
{
// La requête a échoué
}
}
public async Task<Activity> getActivityById(int id)
{
Activity activity = await _clientHttp.GetFromJsonAsync<List<Activity>>("http://localhost:8080/api/activities/{id}");
return activity;
}
public async Task<List<Activity>> getAllActivities()
{
List<Activity> lActivities = await _clientHttp.GetFromJsonAsync<List<Activity>>("http://localhost:8080/api/activities");
return lActivities;
}
public async Task RemoveActivity(Activity a)
{
HttpResponseMessage response = await _clientHttp.DeleteAsync($"http://localhost:8080/api/activities/{a.IdActivity}");
if (response.IsSuccessStatusCode)
{
// La requête a réussi
}
else
{
// La requête a échoué
}
}
public async Task SaveAllActivities(List<Activity> list)
{
HttpResponseMessage response = await _clientHttp.PutAsJsonAsync("http://localhost:8080/api/activities", list);
if (response.IsSuccessStatusCode)
{
// La requête a réussi
}
else
{
// La requête a échoué
}
}
public async Task UpdateActivity(Activity a)
{
HttpResponseMessage response = await _clientHttp.PutAsJsonAsync($"http://localhost:8080/api/activities/{a.IdActivity}", a);
if (response.IsSuccessStatusCode)
{
// La requête a réussi
}
else
{
// La requête a échoué
}
}
}
}

@ -1,140 +0,0 @@
using System;
using Blazored.LocalStorage;
using HeartTrack.Models;
using HeartTrack.Services.ActivityDataService;
using Microsoft.AspNetCore.Components;
namespace HeartTrack.Services.ActivityDataServiceFactice
{
public class ActivityDataServiceFactice : IActivityDataService
{
[Inject]
private HttpClient _clientHttp { get; set; }
[Inject]
public ILocalStorageService _localStorage { get; set; }
[Inject]
public NavigationManager _navigationManager { get; set; }
private String EmplacementLocalStorage { get; set; }
private String EmplacementJson { get; set; }
public ActivityDataServiceFactice(HttpClient clientHttp, ILocalStorageService localStorage, NavigationManager navigationManager)
{
this._clientHttp = clientHttp;
this._localStorage = localStorage;
this._navigationManager = navigationManager;
this.EmplacementLocalStorage = "activitiesData";
this.EmplacementJson = $"{_navigationManager.BaseUri}data/fake-activities.json";
}
public async Task AddActivity(Activity a)
{
List<Activity> data = await getAllActivities();
data.Add(a);
await this.SaveAllActivities(data);
}
public async Task<Activity> getActivityById(int id)
{
Console.WriteLine("Passage dans le getFromPseudo...");
List<Activity> activities = await getAllActivities();
Activity? temp = null;
foreach (Activity a in activities)
{
if (a.IdActivity == id)
{
temp = a;
}
}
return temp;
}
public async Task<List<Activity>> getAllActivities()
{
List<Activity> lActivities = new List<Activity>();
lActivities = await this.getActivitiesFromLocalStorage();
if(lActivities.Count == 0)
{
lActivities = await this.getActivitiesFromJson(this.EmplacementJson);
await this.saveActivitiesLocalStorage(lActivities);
}
return lActivities;
}
private async Task<List<Activity>> getActivitiesFromJson(String cheminVersJson)
{
List<Activity> activitiesDeserialiser = new List<Activity>();
var data = await _clientHttp.GetFromJsonAsync<Activity[]>(cheminVersJson);
activitiesDeserialiser = data.ToList();
return activitiesDeserialiser;
}
private async Task<List<Activity>> getActivitiesFromLocalStorage()
{
List<Activity> activitiesFromLocalStorage = null;
var data = await _localStorage.GetItemAsync<Activity[]>(EmplacementLocalStorage);
if (data == null)
{
activitiesFromLocalStorage = new List<Activity>();
}
else
{
activitiesFromLocalStorage = data.ToList();
}
return activitiesFromLocalStorage;
}
public async Task RemoveActivity(Activity a)
{
List<Activity> data = await getAllActivities();
int index = -1;
foreach (Activity temp in data)
{
if (temp.IdActivity == a.IdActivity)
{
index = data.IndexOf(temp);
}
}
if (index != -1)
{
data.RemoveAt(index);
}
await this.SaveAllActivities(data);
data = await this.getAllActivities();
}
public async Task SaveAllActivities(List<Activity> list)
{
await this.saveActivitiesLocalStorage(list);
}
private async Task saveActivitiesLocalStorage(List<Activity> lActivities)
{
await _localStorage.SetItemAsync(this.EmplacementLocalStorage, lActivities);
}
public async Task UpdateActivity(Activity a)
{
await this.RemoveActivity(a);
await this.AddActivity(a);
}
}
}

@ -1,42 +1,12 @@
@using System.Globalization @using System.Globalization
@inject NavigationManager NavigationManager
<p> <p>
<label> <label>
<select @bind="Culture"> <select @bind="Culture">
@foreach (var culture in supportedCultures) @foreach (var culture in @supportedCultures)
{ {
<option value="@culture">@culture.DisplayName</option> <option value="@culture">@culture.DisplayName</option>
} }
</select> </select>
</label> </label>
</p> </p>
@code
{
private CultureInfo[] supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("fr-FR")
};
private CultureInfo Culture
{
get => CultureInfo.CurrentCulture;
set
{
if (CultureInfo.CurrentUICulture == value)
{
return;
}
var culture = value.Name.ToLower(CultureInfo.InvariantCulture);
var uri = new Uri(this.NavigationManager.Uri).GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
var query = $"?culture={Uri.EscapeDataString(culture)}&" + $"redirectUri={Uri.EscapeDataString(uri)}";
// Redirect the user to the culture controller to set the cookie
this.NavigationManager.NavigateTo("/Culture/SetCulture" + query, forceLoad: true);
}
}
}

@ -0,0 +1,42 @@
using Microsoft.AspNetCore.Components;
using System.Globalization;
namespace HeartTrack.Shared
{
public partial class CultureSelector
{
[Inject]
private NavigationManager NavigationManager { get; set; }
private CultureInfo[] supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("fr-FR")
};
private CultureInfo Culture
{
get => CultureInfo.CurrentCulture;
set
{
if (CultureInfo.CurrentUICulture == value)
{
return;
}
var culture = value.Name.ToLower(CultureInfo.InvariantCulture);
var uri = new Uri(this.NavigationManager.Uri).GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
var query = $"?culture={Uri.EscapeDataString(culture)}&" + $"redirectUri={Uri.EscapeDataString(uri)}";
// Redirect the user to the culture controller to set the cookie
this.NavigationManager.NavigateTo("/Culture/SetCulture" + query, forceLoad: true);
}
}
public int getSizeCultures()
{
return supportedCultures.Length;
}
}
}

@ -1,4 +1,7 @@
@inherits LayoutComponentBase @inherits LayoutComponentBase
<MudThemeProvider />
<MudDialogProvider />
<MudSnackbarProvider />
<PageTitle>HeartTrack</PageTitle> <PageTitle>HeartTrack</PageTitle>
@ -8,32 +11,21 @@
</div> </div>
<main> <main>
<div class="top-row px-4 auth">
<div class="container-fluid toggler-container"> <MudAppBar Color="Color.Primary" Fixed="false">
<button title="Navigation menu" class="navbar-toggler custom-toggler" @onclick="ToggleNavMenu"> <MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" @onclick="ToggleNavMenu">
<span class="navbat-toggler-icon"></span> <span class="navbat-toggler-icon"></span>
</button> </MudIconButton>
</div> <MudSpacer />
@* Messages, notifs et pp compte à mettre *@ <CultureSelector></CultureSelector>
@* <div class="top-row px-4"> <MudMenu Icon="@Icons.Material.Filled.AccountCircle" Color="Color.Inherit" Edge="Edge.End">
<CultureSelector /> <MudMenuItem>Profile</MudMenuItem>
<button type="button" class="btn btn-link ml-md-auto" @onclick="@LogoutClick">Logout</button> <MudButton type="button" class="btn btn-link ml-md-auto">Logout</MudButton>
</div> *@ </MudMenu>
</div> </MudAppBar>
<article class="content px-4"> <article class="content px-4">
@Body @Body
</article> </article>
</main> </main>
</div> </div>
@code {
private bool collapseNavMenu = true;
private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
}

@ -6,27 +6,21 @@ namespace HeartTrack.Shared
{ {
public partial class MainLayout public partial class MainLayout
{ {
/*[Inject]
public CustomStateProvider AuthStateProvider { get; set; }*/
[Inject] [Inject]
public NavigationManager NavigationManager { get; set; } public NavigationManager NavigationManager { get; set; }
[CascadingParameter] private bool collapseNavMenu = true;
private Task<AuthenticationState> AuthenticationState { get; set; }
/*protected override async Task OnParametersSetAsync() private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
{
if (!(await AuthenticationState).User.Identity.IsAuthenticated) public void ToggleNavMenu()
{ {
NavigationManager.NavigateTo("/login"); collapseNavMenu = !collapseNavMenu;
} }
}*/
/*private async Task LogoutClick() public bool getCollapseNavMenu()
{ {
await AuthStateProvider.Logout(); return this.collapseNavMenu;
NavigationManager.NavigateTo("/login"); }
}*/
} }
} }

@ -11,40 +11,16 @@
<span class="oi oi-home" aria-hidden="true"></span> @Localizer["Global"] <span class="oi oi-home" aria-hidden="true"></span> @Localizer["Global"]
</NavLink> </NavLink>
</div> </div>
@* <AuthorizeView Roles="admin"> *@
<div class="nav-item px-3">
<NavLink class="nav-link" href="reports">
<span class="oi oi-list-rich" aria-hidden="true"></span> @Localizer["Report"]
</NavLink>
</div>
@* </AuthorizeView>
<AuthorizeView Roles="admin"> *@
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link" href="activities"> <NavLink class="nav-link" href="activities">
<span class="oi oi-list-rich" aria-hidden="true"></span> @Localizer["Activity"] <span class="oi oi-list-rich" aria-hidden="true"></span> @Localizer["Activity"]
</NavLink> </NavLink>
</div> </div>
@* </AuthorizeView>
<AuthorizeView Roles="admin"> *@
<div class="nav-item px-3">
<NavLink class="nav-link" href="banned-users">
<span class="oi oi-list-rich" aria-hidden="true"></span> @Localizer["Ban"]
</NavLink>
</div>
@* </AuthorizeView>
<AuthorizeView Roles="admin"> *@
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link" href="tickets"> <NavLink class="nav-link" href="tickets">
<span class="oi oi-plus" aria-hidden="true"></span> @Localizer["Ticket"] <span class="oi oi-plus" aria-hidden="true"></span> @Localizer["Ticket"]
</NavLink> </NavLink>
</div> </div>
@* </AuthorizeView>
<AuthorizeView Roles="owner"> *@
<div class="nav-item px-3">
<NavLink class="nav-link" href="admin">
<span class="oi oi-plus" aria-hidden="true"></span> @Localizer["Admin"]
</NavLink>
</div>
@* </AuthorizeView> *@
</nav> </nav>
</div> </div>

@ -1,17 +0,0 @@
<div class="alert alert-secondary mt-4">
<span class="oi oi-pencil me-2" aria-hidden="true"></span>
<strong>@Title</strong>
<span class="text-nowrap">
Please take our
<a target="_blank" class="font-weight-bold link-dark" href="https://go.microsoft.com/fwlink/?linkid=2149017">brief survey</a>
</span>
and tell us what you think.
</div>
@code {
// Demonstrates how a parent component can supply parameters
[Parameter]
public string? Title { get; set; }
}

@ -0,0 +1,25 @@
using HeartTrack.Controllers;
using Microsoft.AspNetCore.Mvc;
using Xunit;
namespace HeartTrack.Tests.Controller
{
public class CultureControllerTests
{
[Fact]
public void IsCultureControllerInstanceOfCultureController()
{
var culture = new CultureController();
Assert.IsType<CultureController>(culture);
}
[Fact]
public void IsSetCultureRedirecting()
{
var culture = new CultureController();
Assert.IsAssignableFrom<IActionResult>(culture.SetCulture("",""));
}
}
}

@ -0,0 +1,37 @@
using HeartTrack.Models;
using Xunit;
namespace HeartTrack.Tests.Models
{
public class ActivityTests
{
[Fact]
public void IsActivityInstanceOfActivity()
{
var activity = new Activity();
Assert.IsType<Activity>(activity);
}
[Fact]
public void HasActivityAttrivutesRightInstance()
{
var activity = new Activity();
Assert.IsType<int>(activity.IdActivity);
Assert.IsType<string>(activity.Type);
Assert.IsType<DateOnly>(activity.Date);
Assert.IsType<DateOnly>(activity.StartTime);
Assert.IsType<DateOnly>(activity.EndTime);
Assert.IsType<int>(activity.EffortRessenti);
Assert.IsType<float>(activity.Variability);
Assert.IsType<float>(activity.Variance);
Assert.IsType<float>(activity.StandardDeviation);
Assert.IsType<float>(activity.Average);
Assert.IsType<int>(activity.Maximum);
Assert.IsType<int>(activity.Minimum);
Assert.IsType<float>(activity.AvrTemperature);
Assert.IsType<bool>(activity.HasAutoPause);
}
}
}

@ -0,0 +1,42 @@
using Blazorise;
using HeartTrack.Models;
using Xunit;
namespace HeartTrack.Tests.Models
{
public class ReportTests
{
[Fact]
public void IsReportInstanceOfReport()
{
var report = new Report();
Assert.IsType<Report>(report);
}
[Fact]
public void HasReportAttributeRightInstace()
{
var report = new Report();
Assert.IsType<int>(report.Id);
Assert.IsType<string>(report.Username);
Assert.IsType<string>(report.ReportedUser);
Assert.IsType<string>(report.Raison);
Assert.IsType<string>(report.Description);
Assert.IsType<Image>(report.Image);
}
[Fact]
public void IsReportModelValidate()
{
var report = new ReportModel();
Assert.True(report.Id < 2500000);
Assert.True(report.Username.Length < 50 && report.Username.Length>0);
Assert.True(report.ReportedUser.Length < 50 && report.ReportedUser.Length > 0);
Assert.True(report.Raison.Length < 150 && report.Raison.Length > 0);
Assert.True(report.Description.Length < 500 && report.Description.Length > 0);
}
}
}

@ -0,0 +1,40 @@
using HeartTrack.Models;
using Xunit;
namespace HeartTrack.Tests.Models
{
public class TicketTests
{
[Fact]
public void IsTicketInstanceOfTicket()
{
var ticket = new Ticket();
Assert.IsType<Ticket>(ticket);
}
[Fact]
public void HasTicketAttributeRightInstance()
{
var ticket = new Ticket();
Assert.IsType<int>(ticket.Id);
Assert.IsType<string>(ticket.Username);
Assert.IsType<string>(ticket.Contexte);
Assert.IsType<string>(ticket.Description);
Assert.IsType<Boolean>(ticket.isCheck);
}
[Fact]
public void IsTicketModelValidate()
{
var ticket = new TicketModel();
Assert.True(ticket.Id < 2500000);
Assert.True(ticket.Username.Length > 0 && ticket.Username.Length < 50);
Assert.True(ticket.Contexte.Length > 0 && ticket.Contexte.Length < 25);
Assert.True(ticket.Description.Length > 0 && ticket.Description.Length < 500);
Assert.True(ticket.isCheck);
}
}
}

@ -0,0 +1,52 @@
using Xunit;
using HeartTrack.Models;
namespace HeartTrack.Tests.Models
{
public class UserTests
{
[Fact]
public void IsUserInstanceOfUser()
{
var user = new User();
Assert.IsType<User>(user);
}
[Fact]
public void HasUserAttributeRightInstance()
{
var user = new User();
Assert.IsType<int>(user.Id);
Assert.IsType<string>(user.Username);
Assert.IsType<string>(user.Nom);
Assert.IsType<string>(user.Prenom);
Assert.IsType<string>(user.Email);
Assert.IsType<string>(user.Password);
Assert.IsType<string>(user.Sexe);
Assert.IsType<float>(user.Taille);
Assert.IsType<float>(user.Poids);
Assert.IsType<DateTime>(user.BirthDate);
Assert.IsType<Boolean>(user.isBan);
}
[Fact]
public void IsUserModelValidate()
{
var user = new UserModel();
Assert.NotNull(user.Username);
Assert.NotNull(user.FirstName);
Assert.NotNull(user.LastName);
Assert.NotNull(user.Email);
Assert.NotNull(user.Password);
Assert.NotNull(user.Sexe);
Assert.True(user.Id<2500000);
Assert.True(user.Username.Length >= 0 && user.Username.Length < 50);
Assert.True(user.FirstName.Length >= 0 && user.FirstName.Length < 50);
Assert.True(user.LastName.Length >= 0 && user.LastName.Length < 25);
}
}
}

@ -0,0 +1,24 @@
using HeartTrack.Shared;
using Xunit;
namespace HeartTrack.Tests.Shared
{
public class CultureSelectorTests
{
[Fact]
public void IsCultureSelectorInstanceOfCultureSelector()
{
var culture = new CultureSelector();
Assert.IsType<CultureSelector>(culture);
}
[Fact]
public void HasCultureEnoughLanguages()
{
var culture = new CultureSelector();
Assert.Equal(2, culture.getSizeCultures());
}
}
}

@ -0,0 +1,25 @@
using HeartTrack.Shared;
using Xunit;
namespace HeartTrack.Tests.Shared
{
public class MainLayoutTests
{
[Fact]
public void IsMainLayoutInstanceOfMainLayout()
{
var main = new MainLayout();
Assert.IsType<MainLayout>(main);
}
[Fact]
public void StateChangeOnToggleNavMenu()
{
var main = new MainLayout();
Assert.True(main.getCollapseNavMenu());
main.ToggleNavMenu();
Assert.False(main.getCollapseNavMenu());
}
}
}

@ -9,3 +9,4 @@
@using HeartTrack @using HeartTrack
@using HeartTrack.Shared @using HeartTrack.Shared
@using Blazorise.DataGrid @using Blazorise.DataGrid
@using MudBlazor

@ -1,178 +0,0 @@
[
{
"id": 1,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 2,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 3,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 4,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 5,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 6,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 7,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 8,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 9,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 10,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 11,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 12,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 13,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 14,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 15,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 16,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 17,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 18,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 19,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 20,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 21,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
},
{
"id": 22,
"username": "johndoe",
"reported_user": "erickol",
"raison": "Jvais dire wallah",
"description": "Wallah c`est la description",
"image": "oui.png"
}
]

@ -5,8 +5,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": true
}, },
{ {
"id": 2, "id": 2,
@ -14,8 +13,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": true
}, },
{ {
"id": 3, "id": 3,
@ -23,8 +21,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": false
}, },
{ {
"id": 4, "id": 4,
@ -32,8 +29,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": false
}, },
{ {
"id": 5, "id": 5,
@ -41,8 +37,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": true
}, },
{ {
"id": 6, "id": 6,
@ -50,8 +45,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": false
}, },
{ {
"id": 7, "id": 7,
@ -59,8 +53,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": true
}, },
{ {
"id": 8, "id": 8,
@ -68,8 +61,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": true
}, },
{ {
"id": 9, "id": 9,
@ -78,7 +70,6 @@
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description",
"urgence": false
}, },
{ {
"id": 10, "id": 10,
@ -86,8 +77,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": true
}, },
{ {
"id": 11, "id": 11,
@ -95,8 +85,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": false
}, },
{ {
"id": 12, "id": 12,
@ -104,8 +93,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": true
}, },
{ {
"id": 13, "id": 13,
@ -113,8 +101,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": true
}, },
{ {
"id": 14, "id": 14,
@ -122,8 +109,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": true
}, },
{ {
"id": 15, "id": 15,
@ -131,8 +117,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": false
}, },
{ {
"id": 16, "id": 16,
@ -140,8 +125,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": true
}, },
{ {
"id": 17, "id": 17,
@ -149,8 +133,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": false
}, },
{ {
"id": 18, "id": 18,
@ -158,8 +141,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": true
}, },
{ {
"id": 19, "id": 19,
@ -167,8 +149,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": true
}, },
{ {
"id": 20, "id": 20,
@ -176,8 +157,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": true
}, },
{ {
"id": 21, "id": 21,
@ -185,8 +165,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": true
}, },
{ {
"id": 22, "id": 22,
@ -194,8 +173,7 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": false
}, },
{ {
"id": 23, "id": 23,
@ -203,7 +181,6 @@
"nom": "Doe", "nom": "Doe",
"prenom": "John", "prenom": "John",
"contexte": "Jvais dire wallah", "contexte": "Jvais dire wallah",
"description": "Wallah c`est la description", "description": "Wallah c`est la description"
"urgence": true
} }
] ]

@ -1,379 +0,0 @@
[
{
"id": 1,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2018-12-27",
"isban": true
},
{
"id": 2,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2021-06-29",
"isban": true
},
{
"id": 3,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2021-04-09",
"isban": true
},
{
"id": 4,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2022-11-20",
"isban": true
},
{
"id": 5,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2021-02-20",
"isban": true
},
{
"id": 6,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2014-02-17",
"isban": true
},
{
"id": 7,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2020-07-14",
"isban": true
},
{
"id": 8,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2018-02-21",
"isban": false
},
{
"id": 9,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2014-07-31",
"isban": true
},
{
"id": 10,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2019-10-02",
"isban": true
},
{
"id": 11,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2015-07-26",
"isban": false
},
{
"id": 12,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2020-10-23",
"isban": false
},
{
"id": 13,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2014-11-03",
"isban": true
},
{
"id": 14,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2014-01-31",
"isban": false
},
{
"id": 15,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2022-04-12",
"isban": false
},
{
"id": 16,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2018-07-22",
"isban": false
},
{
"id": 17,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2017-04-04",
"isban": true
},
{
"id": 18,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2015-08-15",
"isban": true
},
{
"id": 19,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2022-04-10",
"isban": false
},
{
"id": 20,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2020-02-09",
"isban": false
},
{
"id": 21,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2017-02-18",
"isban": false
},
{
"id": 22,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2023-06-25",
"isban": false
},
{
"id": 23,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2017-09-27",
"isban": true
},
{
"id": 24,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2015-02-01",
"isban": true
},
{
"id": 25,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2017-05-28",
"isban": true
},
{
"id": 26,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2022-06-11",
"isban": true
},
{
"id": 27,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2019-08-08",
"isban": true
},
{
"id": 28,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2015-01-29",
"isban": false
},
{
"id": 29,
"username": "johndoe",
"nom": "Doe",
"prenom": "John",
"email": "john.doe@example.com",
"password": "password123",
"sexe": "male",
"taille": 1.76,
"poids": 56.3,
"birthdate": "2020-08-21",
"isban": false
}
]
Loading…
Cancel
Save