diff --git a/Blazor/Blazor/Blazor.csproj b/Blazor/Blazor/Blazor.csproj index 47b71bb..a975a06 100644 --- a/Blazor/Blazor/Blazor.csproj +++ b/Blazor/Blazor/Blazor.csproj @@ -1,16 +1,19 @@ - - - - net7.0 - enable - enable - - - - - - - - - - + + + + net7.0 + enable + enable + + + + + + + + + + + + + diff --git a/Blazor/Blazor/Models/Administrator.cs b/Blazor/Blazor/Models/Administrator.cs deleted file mode 100644 index a1c6b5e..0000000 --- a/Blazor/Blazor/Models/Administrator.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Blazor.Models -{ - public class Administrator - { - public int Id { get; private set; } - public string Username { get; private set; } - public string hashedPassword { get; set; } - - public Administrator(int id, string username, string hashedPassword) - { - Id = id; - Username = username; - this.hashedPassword = hashedPassword; - } - } -} 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/Answer.cs b/Blazor/Blazor/Models/Answer.cs deleted file mode 100644 index a27ec6f..0000000 --- a/Blazor/Blazor/Models/Answer.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Blazor.Models -{ - public class Answer - { - public int Id { get; private set; } - public string Content { get; set; } - public int IdQuestion { get; private set; } - - public Answer(int id, string content, int idQuestion) - { - Id = id; - Content = content; - IdQuestion = idQuestion; - } - } -} 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/Chapter.cs b/Blazor/Blazor/Models/Chapter.cs deleted file mode 100644 index 1ec4853..0000000 --- a/Blazor/Blazor/Models/Chapter.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Blazor.Models -{ - public class Chapter - { - public int Id { get; set; } - public string Name { get; set; } - } -} diff --git a/Blazor/Blazor/Models/Player.cs b/Blazor/Blazor/Models/Player.cs deleted file mode 100644 index e5ec93d..0000000 --- a/Blazor/Blazor/Models/Player.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Blazor.Models -{ - public class Player - { - public int Id { get; private set; } - public string Nickname { get; private set; } - public string HashedPassword { get; set; } - - public Player(int id, string nickname, string hashedPassword) - { - Id = id; - Nickname = nickname; - HashedPassword = hashedPassword; - } - - } -} 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/Question.cs b/Blazor/Blazor/Models/Question.cs deleted file mode 100644 index dd6d8ef..0000000 --- a/Blazor/Blazor/Models/Question.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Blazor.Models -{ - public class Question - { - public int Id { get; private set; } - public string Content { get; set; } - public int IdChapter { get; set; } - public int IdAnswerGood { get; set; } - public int Difficulty { get; set; } - public int nbFails { get; set; } - - public Question(int id, string content, int idChapter, int idAnswerGood, int difficulty, int nbFails = 0) - { - Id = id; - Content = content; - IdChapter = idChapter; - IdAnswerGood = idAnswerGood; - Difficulty = difficulty; - this.nbFails = nbFails; - } - } -} 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/Administrators.razor b/Blazor/Blazor/Pages/Administrators.razor index 4f24f83..fdb0252 100644 --- a/Blazor/Blazor/Pages/Administrators.razor +++ b/Blazor/Blazor/Pages/Administrators.razor @@ -1,6 +1,6 @@ @page "/administrators" -@using Blazor.Models; @using Blazorise.DataGrid +@using Blazor.ViewClasses

Administrators

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 index 5504b64..f705ba1 100644 --- a/Blazor/Blazor/Pages/Chapters.razor +++ b/Blazor/Blazor/Pages/Chapters.razor @@ -1,27 +1,30 @@ -@page "/chapters" -@using Blazor.Models; -@using Blazorise.DataGrid -

Chapters

- -
- - Ajouter - -
- - - - - - - Editer - - - - +@page "/chapters" +@using Blazor.ViewClasses; +@using Blazorise.DataGrid +

Chapters

+ +
+ + Ajouter + + + Exporter + +
+ + + + + + + Editer + + + + \ No newline at end of file diff --git a/Blazor/Blazor/Pages/Chapters.razor.cs b/Blazor/Blazor/Pages/Chapters.razor.cs index 2dd498f..be82912 100644 --- a/Blazor/Blazor/Pages/Chapters.razor.cs +++ b/Blazor/Blazor/Pages/Chapters.razor.cs @@ -1,36 +1,91 @@ -using Microsoft.AspNetCore.Components; -using Blazor.Models; -using Blazorise.DataGrid; -using Blazored.LocalStorage; -using Blazorise; -using Blazor.Services; - -namespace Blazor.Pages -{ - public partial class Chapters - { - public List chapters; - - private int totalItem; - - [Inject] - public IDataService DataService { get; set; } - - [Inject] - public IWebHostEnvironment WebHostEnvironment { get; set; } - - private async Task OnReadData(DataGridReadDataEventArgs e) - { - if (e.CancellationToken.IsCancellationRequested) - { - return; - } - - if (!e.CancellationToken.IsCancellationRequested) - { - chapters = await DataService.List(e.Page, e.PageSize); - totalItem = await DataService.Count(); - } - } - } -} +using Blazored.LocalStorage; +using Blazorise; +using Blazor.Services; +using Blazorise.DataGrid; +using ChoETL; +using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; +using System.Text; +using Blazor.ViewClasses; + +namespace Blazor.Pages; +public partial class Chapters + { + public List chapters; + + private int totalChapter; + + [Inject] + public IDataService DataService { get; set; } + public IWebHostEnvironment WebHostEnvironment { get; set; } + + [Inject] + public HttpClient Http { get; set; } + + [Inject] + public ILocalStorageService LocalStorage { get; set; } + + [Inject] + public NavigationManager NavigationManager { get; set; } + + [Inject] + public IJSRuntime IJSRuntime { 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.GetFromJsonAsync( $"https://trusting-panini.87-106-126-109.plesk.page/api/chapters?page={e.Page}&pageSize={e.PageSize}" ); + var response = Http.GetFromJsonAsync($"https://trusting-panini.87-106-126-109.plesk.page/api/chapters").Result; + + if (!e.CancellationToken.IsCancellationRequested) + { + totalChapter = (await LocalStorage.GetItemAsync>("data")).Count; + chapters = new List(response); // an actual data for the current page + } + } + + private async void Export() + { + StringBuilder sb = new StringBuilder(); + HttpResponseMessage response = await Http.GetAsync("https://trusting-panini.87-106-126-109.plesk.page/api/chapters"); + var json = await response.Content.ReadAsStringAsync(); + using (var jsonFile = ChoJSONReader.LoadText(json)) + { + using (var csvFile = new ChoCSVWriter(sb).WithFirstLineHeader()) + { + csvFile.Write(jsonFile); + } + } + + var sentFile = new MemoryStream(Encoding.UTF32.GetBytes(sb.ToString())); + + using (var streamRef = new DotNetStreamReference(stream: sentFile)) + { + await IJSRuntime.InvokeVoidAsync("downloadFileFromStream", "data.csv", streamRef); + } + } +} diff --git a/Blazor/Blazor/Pages/Chapters.razor.js b/Blazor/Blazor/Pages/Chapters.razor.js new file mode 100644 index 0000000..37f904d --- /dev/null +++ b/Blazor/Blazor/Pages/Chapters.razor.js @@ -0,0 +1,11 @@ +window.downloadFileFromStream = async (fileName, contentStreamReference) => { + const arrayBuffer = await contentStreamReference.arrayBuffer(); + const blob = new Blob([arrayBuffer]); + const url = URL.createObjectURL(blob); + const anchorElement = document.createElement('a'); + anchorElement.href = url; + anchorElement.download = fileName ?? ''; + anchorElement.click(); + anchorElement.remove(); + URL.revokeObjectURL(url); +} \ 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 2d9e404..5c73e4b 100644 --- a/Blazor/Blazor/Program.cs +++ b/Blazor/Blazor/Program.cs @@ -13,6 +13,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(); builder.Services.AddHttpClient(); diff --git a/Blazor/Blazor/Services/DataLocalService.cs b/Blazor/Blazor/Services/DataLocalService.cs index 5fb1137..08146b7 100644 --- a/Blazor/Blazor/Services/DataLocalService.cs +++ b/Blazor/Blazor/Services/DataLocalService.cs @@ -1,4 +1,5 @@ using Blazor.Models; +using Blazor.ViewClasses; using Blazored.LocalStorage; using Microsoft.AspNetCore.Components; diff --git a/Blazor/Blazor/Services/IDataService.cs b/Blazor/Blazor/Services/IDataService.cs index bdc1468..844d98d 100644 --- a/Blazor/Blazor/Services/IDataService.cs +++ b/Blazor/Blazor/Services/IDataService.cs @@ -1,4 +1,5 @@ using Blazor.Models; +using Blazor.ViewClasses; namespace Blazor.Services { diff --git a/Blazor/Blazor/ViewClasses/Administrator.cs b/Blazor/Blazor/ViewClasses/Administrator.cs new file mode 100644 index 0000000..e0ec189 --- /dev/null +++ b/Blazor/Blazor/ViewClasses/Administrator.cs @@ -0,0 +1,15 @@ +namespace Blazor.ViewClasses; + +public class Administrator +{ + public int Id { get; private set; } + public string Username { get; private set; } + public string hashedPassword { get; set; } + + public Administrator(int id, string username, string hashedPassword) + { + Id = id; + Username = username; + this.hashedPassword = hashedPassword; + } +} diff --git a/Blazor/Blazor/ViewClasses/Answer.cs b/Blazor/Blazor/ViewClasses/Answer.cs new file mode 100644 index 0000000..d14ebff --- /dev/null +++ b/Blazor/Blazor/ViewClasses/Answer.cs @@ -0,0 +1,15 @@ +namespace Blazor.ViewClasses; + +public class Answer +{ + public int Id { get; private set; } + public string Content { get; set; } + public int IdQuestion { get; private set; } + + public Answer(int id, string content, int idQuestion) + { + Id = id; + Content = content; + IdQuestion = idQuestion; + } +} diff --git a/Blazor/Blazor/ViewClasses/Chapter.cs b/Blazor/Blazor/ViewClasses/Chapter.cs new file mode 100644 index 0000000..942eb72 --- /dev/null +++ b/Blazor/Blazor/ViewClasses/Chapter.cs @@ -0,0 +1,7 @@ +namespace Blazor.ViewClasses; + +public class Chapter +{ + public int Id { get; set; } + public string Name { get; set; } +} diff --git a/Blazor/Blazor/ViewClasses/Player.cs b/Blazor/Blazor/ViewClasses/Player.cs new file mode 100644 index 0000000..7fd1f4e --- /dev/null +++ b/Blazor/Blazor/ViewClasses/Player.cs @@ -0,0 +1,16 @@ +namespace Blazor.ViewClasses; + +public class Player +{ + public int Id { get; private set; } + public string Nickname { get; private set; } + public string HashedPassword { get; set; } + + public Player(int id, string nickname, string hashedPassword) + { + Id = id; + Nickname = nickname; + HashedPassword = hashedPassword; + } + +} diff --git a/Blazor/Blazor/ViewClasses/Question.cs b/Blazor/Blazor/ViewClasses/Question.cs new file mode 100644 index 0000000..db4e7bf --- /dev/null +++ b/Blazor/Blazor/ViewClasses/Question.cs @@ -0,0 +1,21 @@ +namespace Blazor.ViewClasses; + +public class Question +{ + public int Id { get; private set; } + public string Content { get; set; } + public int IdChapter { get; set; } + public int IdAnswerGood { get; set; } + public int Difficulty { get; set; } + public int nbFails { get; set; } + + public Question(int id, string content, int idChapter, int idAnswerGood, int difficulty, int nbFails = 0) + { + Id = id; + Content = content; + IdChapter = idChapter; + IdAnswerGood = idAnswerGood; + Difficulty = difficulty; + this.nbFails = nbFails; + } +} diff --git a/Blazor/Blazor/_Imports.razor b/Blazor/Blazor/_Imports.razor index 9665bbe..0bfa3cd 100644 --- a/Blazor/Blazor/_Imports.razor +++ b/Blazor/Blazor/_Imports.razor @@ -9,4 +9,3 @@ @using Blazor @using Blazor.Shared @using Blazorise.DataGrid -