From 150cca45ec70a65ad9009e04f0b40d6867a92b3c Mon Sep 17 00:00:00 2001 From: Jade VAN BRABANDT Date: Wed, 13 Dec 2023 09:59:39 +0100 Subject: [PATCH] Feat : Page & Start of API integration --- Blazor/Blazor.sln | 50 +++++++-------- Blazor/Blazor/Blazor.csproj | 7 +++ Blazor/Blazor/Models/AdministratorsModel.cs | 28 +++++++++ Blazor/Blazor/Models/AnswerModel.cs | 16 +++++ Blazor/Blazor/Models/ChaptersModel.cs | 13 ++++ Blazor/Blazor/Models/PlayerModel.cs | 25 ++++++++ Blazor/Blazor/Models/QuestionsModel.cs | 24 ++++++++ .../Pages/{FetchData.razor => Admins.razor} | 2 +- Blazor/Blazor/Pages/Admins.razor.cs | 61 +++++++++++++++++++ Blazor/Blazor/Pages/Chapters.razor | 13 ++++ Blazor/Blazor/Pages/Chapters.razor.cs | 61 +++++++++++++++++++ Blazor/Blazor/Pages/Index.razor.cs | 6 ++ Blazor/Blazor/Pages/Questions.razor | 47 ++++++++++++++ Blazor/Blazor/Pages/Questions.razor.cs | 6 ++ Blazor/Blazor/Program.cs | 11 ++++ Blazor/Blazor/Shared/NavMenu.razor | 13 ++-- 16 files changed, 353 insertions(+), 30 deletions(-) create mode 100644 Blazor/Blazor/Models/AdministratorsModel.cs create mode 100644 Blazor/Blazor/Models/AnswerModel.cs create mode 100644 Blazor/Blazor/Models/ChaptersModel.cs create mode 100644 Blazor/Blazor/Models/PlayerModel.cs create mode 100644 Blazor/Blazor/Models/QuestionsModel.cs rename Blazor/Blazor/Pages/{FetchData.razor => Admins.razor} (98%) create mode 100644 Blazor/Blazor/Pages/Admins.razor.cs create mode 100644 Blazor/Blazor/Pages/Chapters.razor create mode 100644 Blazor/Blazor/Pages/Chapters.razor.cs create mode 100644 Blazor/Blazor/Pages/Index.razor.cs create mode 100644 Blazor/Blazor/Pages/Questions.razor create mode 100644 Blazor/Blazor/Pages/Questions.razor.cs diff --git a/Blazor/Blazor.sln b/Blazor/Blazor.sln index f68a3ac..812049d 100644 --- a/Blazor/Blazor.sln +++ b/Blazor/Blazor.sln @@ -1,25 +1,25 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.8.34330.188 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blazor", "Blazor\Blazor.csproj", "{F9B19564-ED8F-49F7-97D7-2132F92DE3C2}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F9B19564-ED8F-49F7-97D7-2132F92DE3C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F9B19564-ED8F-49F7-97D7-2132F92DE3C2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F9B19564-ED8F-49F7-97D7-2132F92DE3C2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F9B19564-ED8F-49F7-97D7-2132F92DE3C2}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {75BB0A32-C002-4B33-88B3-421A9369D9CB} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34330.188 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blazor", "Blazor\Blazor.csproj", "{F9B19564-ED8F-49F7-97D7-2132F92DE3C2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F9B19564-ED8F-49F7-97D7-2132F92DE3C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F9B19564-ED8F-49F7-97D7-2132F92DE3C2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F9B19564-ED8F-49F7-97D7-2132F92DE3C2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F9B19564-ED8F-49F7-97D7-2132F92DE3C2}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {75BB0A32-C002-4B33-88B3-421A9369D9CB} + EndGlobalSection +EndGlobal diff --git a/Blazor/Blazor/Blazor.csproj b/Blazor/Blazor/Blazor.csproj index 4c2bb77..9b5a10d 100644 --- a/Blazor/Blazor/Blazor.csproj +++ b/Blazor/Blazor/Blazor.csproj @@ -6,4 +6,11 @@ enable + + + + + + + diff --git a/Blazor/Blazor/Models/AdministratorsModel.cs b/Blazor/Blazor/Models/AdministratorsModel.cs new file mode 100644 index 0000000..023cce4 --- /dev/null +++ b/Blazor/Blazor/Models/AdministratorsModel.cs @@ -0,0 +1,28 @@ +using Microsoft.AspNetCore.Cryptography.KeyDerivation; +using Microsoft.AspNetCore.Identity; +using System.Security.Cryptography; + +namespace Blazor.Models; + +public class AdministratorsModel : PasswordHasher +{ + public int Id { get; private set; } + public string Username { get; private set; } + public string HashedPassword { get; set; } + + private byte[] salt = RandomNumberGenerator.GetBytes(128 / 8); // for password hash + + AdministratorsModel(int id, string username, string password) + { + this.Id = id; + this.Username = username; + //hash password + this.HashedPassword = Convert.ToBase64String(KeyDerivation.Pbkdf2( + password: password!, + salt: salt, + prf: KeyDerivationPrf.HMACSHA256, + iterationCount: 100000, + numBytesRequested: 256 / 8) + ); + } +} diff --git a/Blazor/Blazor/Models/AnswerModel.cs b/Blazor/Blazor/Models/AnswerModel.cs new file mode 100644 index 0000000..5464dbe --- /dev/null +++ b/Blazor/Blazor/Models/AnswerModel.cs @@ -0,0 +1,16 @@ +namespace Blazor.Models; + +public class AnswerModel + +{ + public int Id { get; private set; } + public string Content { get; set; } + public int IdQuestion { get; private set; } + + public AnswerModel(int id, string content, int idQuestion) + { + Id = id; + Content = content; + IdQuestion = idQuestion; + } +} diff --git a/Blazor/Blazor/Models/ChaptersModel.cs b/Blazor/Blazor/Models/ChaptersModel.cs new file mode 100644 index 0000000..24862f0 --- /dev/null +++ b/Blazor/Blazor/Models/ChaptersModel.cs @@ -0,0 +1,13 @@ +namespace Blazor.Models; + +public class ChaptersModel +{ + public int Id { get; private set; } + public string Name { get; set; } + + public ChaptersModel(int id, string name) + { + Id = id; + Name = name; + } +} diff --git a/Blazor/Blazor/Models/PlayerModel.cs b/Blazor/Blazor/Models/PlayerModel.cs new file mode 100644 index 0000000..2079d18 --- /dev/null +++ b/Blazor/Blazor/Models/PlayerModel.cs @@ -0,0 +1,25 @@ +using Microsoft.AspNetCore.Cryptography.KeyDerivation; +using System.Security.Cryptography; + +namespace Blazor.Models; + +public class PlayerModel +{ + public int Id { get; private set; } + public string Nickname { get; private set; } + public string HashedPassword { get; set; } + private byte[] salt = RandomNumberGenerator.GetBytes(128 / 8); // for password hash + public PlayerModel(int id, string nickname, string password) + { + Id = id; + Nickname = nickname; + //hash password + HashedPassword = Convert.ToBase64String(KeyDerivation.Pbkdf2( + password: password!, + salt: salt, + prf: KeyDerivationPrf.HMACSHA256, + iterationCount: 100000, + numBytesRequested: 256 / 8) + ); + } +} diff --git a/Blazor/Blazor/Models/QuestionsModel.cs b/Blazor/Blazor/Models/QuestionsModel.cs new file mode 100644 index 0000000..19c395c --- /dev/null +++ b/Blazor/Blazor/Models/QuestionsModel.cs @@ -0,0 +1,24 @@ +namespace Blazor.Models; + +public class QuestionsModel +{ + public int Id { get; private set; } + public string Content { get; set; } + public int IdChapter { get; private set; } + public int? IdAnswerGood { get; set; } + public int Difficulty { get; set; } + public int NbFails { get; private set; } + + public QuestionsModel(int id, string content, int idChapter, int difficulty, int nbFails, int? idAnswerGood = null) + { + Id = id; + Content = content; + IdChapter = idChapter; + Difficulty = difficulty; + NbFails = nbFails; + IdAnswerGood = idAnswerGood; + } + + public void addFails(int nb) { NbFails += nb; } + public void removeFails(int nb) { NbFails -= nb; } +} diff --git a/Blazor/Blazor/Pages/FetchData.razor b/Blazor/Blazor/Pages/Admins.razor similarity index 98% rename from Blazor/Blazor/Pages/FetchData.razor rename to Blazor/Blazor/Pages/Admins.razor index 5ae9d70..74ddbb0 100644 --- a/Blazor/Blazor/Pages/FetchData.razor +++ b/Blazor/Blazor/Pages/Admins.razor @@ -1,4 +1,4 @@ -@page "/fetchdata" +@page "/admins" @using Blazor.Data @inject WeatherForecastService ForecastService diff --git a/Blazor/Blazor/Pages/Admins.razor.cs b/Blazor/Blazor/Pages/Admins.razor.cs new file mode 100644 index 0000000..af73c75 --- /dev/null +++ b/Blazor/Blazor/Pages/Admins.razor.cs @@ -0,0 +1,61 @@ +using Blazor.Models; +using Blazored.LocalStorage; +using Blazorise.DataGrid; +using Microsoft.AspNetCore.Components; + +namespace Blazor.Pages; +public partial class Admins +{ + private List items; + + private int totalItem; + + [Inject] + public IWebHostEnvironment WebHostEnvironment { get; set; } + + [Inject] + public HttpClient Http { get; set; } + + [Inject] + public ILocalStorageService LocalStorage { get; set; } + + [Inject] + public NavigationManager NavigationManager { 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("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($"trusting-panini.87-106-126-109.plesk.page/api/chapters").Result; + await LocalStorage.SetItemAsync("data", originalData); + } + } + + private async Task OnReadData(DataGridReadDataEventArgs e) + { + if (e.CancellationToken.IsCancellationRequested) + { + return; + } + + // When you use a real API, we use this follow code + //var response = await Http.GetJsonAsync( $"http://my-api/api/data?page={e.Page}&pageSize={e.PageSize}" ); + var response = (await LocalStorage.GetItemAsync("data")).Skip((e.Page - 1) * e.PageSize).Take(e.PageSize).ToList(); + + if (!e.CancellationToken.IsCancellationRequested) + { + totalItem = (await LocalStorage.GetItemAsync>("data")).Count; + items = new List(response); // an actual data for the current page + } + } +} \ No newline at end of file diff --git a/Blazor/Blazor/Pages/Chapters.razor b/Blazor/Blazor/Pages/Chapters.razor new file mode 100644 index 0000000..3ba135f --- /dev/null +++ b/Blazor/Blazor/Pages/Chapters.razor @@ -0,0 +1,13 @@ +@page "/chapters" +@using Blazor.Models +

Liste

+ + + + \ No newline at end of file diff --git a/Blazor/Blazor/Pages/Chapters.razor.cs b/Blazor/Blazor/Pages/Chapters.razor.cs new file mode 100644 index 0000000..ae50696 --- /dev/null +++ b/Blazor/Blazor/Pages/Chapters.razor.cs @@ -0,0 +1,61 @@ +using Blazor.Models; +using Blazored.LocalStorage; +using Blazorise.DataGrid; +using Microsoft.AspNetCore.Components; + +namespace Blazor.Pages; +public partial class Chapters +{ + private List items; + + private int totalItem; + + [Inject] + public IWebHostEnvironment WebHostEnvironment { get; set; } + + [Inject] + public HttpClient Http { get; set; } + + [Inject] + public ILocalStorageService LocalStorage { get; set; } + + [Inject] + public NavigationManager NavigationManager { 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("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($"https://trusting-panini.87-106-126-109.plesk.page/api/chapters").Result; + await LocalStorage.SetItemAsync("data", originalData); + } + } + + private async Task OnReadData(DataGridReadDataEventArgs e) + { + if (e.CancellationToken.IsCancellationRequested) + { + return; + } + + // When you use a real API, we use this follow code + //var response = await Http.GetJsonAsync( $"http://my-api/api/data?page={e.Page}&pageSize={e.PageSize}" ); + var response = (await LocalStorage.GetItemAsync("data")).Skip((e.Page - 1) * e.PageSize).Take(e.PageSize).ToList(); + + if (!e.CancellationToken.IsCancellationRequested) + { + totalItem = (await LocalStorage.GetItemAsync>("data")).Count; + items = new List(response); // an actual data for the current page + } + } +} \ No newline at end of file diff --git a/Blazor/Blazor/Pages/Index.razor.cs b/Blazor/Blazor/Pages/Index.razor.cs new file mode 100644 index 0000000..20708a0 --- /dev/null +++ b/Blazor/Blazor/Pages/Index.razor.cs @@ -0,0 +1,6 @@ +namespace Blazor.Pages; + +public partial class Index +{ +} + diff --git a/Blazor/Blazor/Pages/Questions.razor b/Blazor/Blazor/Pages/Questions.razor new file mode 100644 index 0000000..a123a0c --- /dev/null +++ b/Blazor/Blazor/Pages/Questions.razor @@ -0,0 +1,47 @@ +@page "/questions" +@using Blazor.Data +@inject WeatherForecastService ForecastService + +Weather forecast + +

Weather forecast

+ +

This component demonstrates fetching data from a service.

+ +@if (forecasts == null) +{ +

Loading...

+} +else +{ + + + + + + + + + + + @foreach (var forecast in forecasts) + { + + + + + + + } + +
DateTemp. (C)Temp. (F)Summary
@forecast.Date.ToShortDateString()@forecast.TemperatureC@forecast.TemperatureF@forecast.Summary
+} + +@code { + private WeatherForecast[]? forecasts; + + protected override async Task OnInitializedAsync() + { + forecasts = await ForecastService.GetForecastAsync(DateOnly.FromDateTime(DateTime.Now)); + } +} diff --git a/Blazor/Blazor/Pages/Questions.razor.cs b/Blazor/Blazor/Pages/Questions.razor.cs new file mode 100644 index 0000000..2a62003 --- /dev/null +++ b/Blazor/Blazor/Pages/Questions.razor.cs @@ -0,0 +1,6 @@ +namespace Blazor.Pages; + +public partial class Questions +{ +} + diff --git a/Blazor/Blazor/Program.cs b/Blazor/Blazor/Program.cs index 5195276..be52cc7 100644 --- a/Blazor/Blazor/Program.cs +++ b/Blazor/Blazor/Program.cs @@ -1,4 +1,8 @@ using Blazor.Data; +using Blazored.LocalStorage; +using Blazorise; +using Blazorise.Bootstrap; +using Blazorise.Icons.FontAwesome; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; @@ -8,6 +12,13 @@ var builder = WebApplication.CreateBuilder(args); builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor(); builder.Services.AddSingleton(); +builder.Services.AddHttpClient(); + +builder.Services + .AddBlazorise() + .AddBootstrapProviders() + .AddFontAwesomeIcons(); +builder.Services.AddBlazoredLocalStorage(); var app = builder.Build(); diff --git a/Blazor/Blazor/Shared/NavMenu.razor b/Blazor/Blazor/Shared/NavMenu.razor index 5553e13..617155c 100644 --- a/Blazor/Blazor/Shared/NavMenu.razor +++ b/Blazor/Blazor/Shared/NavMenu.razor @@ -15,13 +15,18 @@ +