Maxence GUITARD 1 year ago
commit f7189fc321

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net7.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
@ -11,6 +11,9 @@
<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="ChoETL" Version="1.2.1.64" />
<PackageReference Include="ChoETL.JSON" Version="1.2.1.64" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -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;
}
}
}

@ -0,0 +1,28 @@
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
using Microsoft.AspNetCore.Identity;
using System.Security.Cryptography;
namespace Blazor.Models;
public class AdministratorsModel : PasswordHasher<string>
{
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)
);
}
}

@ -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;
}
}
}

@ -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;
}
}

@ -1,8 +0,0 @@
namespace Blazor.Models
{
public class Chapter
{
public int Id { get; set; }
public string Name { get; set; }
}
}

@ -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;
}
}
}

@ -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)
);
}
}

@ -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;
}
}
}

@ -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; }
}

@ -1,6 +1,6 @@
@page "/administrators" @page "/administrators"
@using Blazor.Models;
@using Blazorise.DataGrid @using Blazorise.DataGrid
@using Blazor.ViewClasses
<h3>Administrators</h3> <h3>Administrators</h3>
<DataGrid TItem="Administrator" <DataGrid TItem="Administrator"

@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Blazor.Models;
using Blazorise.DataGrid; using Blazorise.DataGrid;
using Blazor.ViewClasses;
namespace Blazor.Pages namespace Blazor.Pages
{ {

@ -1,4 +1,4 @@
@page "/fetchdata" @page "/admins"
@using Blazor.Data @using Blazor.Data
@inject WeatherForecastService ForecastService @inject WeatherForecastService ForecastService

@ -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<AdministratorsModel> 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<AdministratorsModel[]>("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<AdministratorsModel[]>($"trusting-panini.87-106-126-109.plesk.page/api/chapters").Result;
await LocalStorage.SetItemAsync("data", originalData);
}
}
private async Task OnReadData(DataGridReadDataEventArgs<AdministratorsModel> 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<AdministratorsModel[]>("data")).Skip((e.Page - 1) * e.PageSize).Take(e.PageSize).ToList();
if (!e.CancellationToken.IsCancellationRequested)
{
totalItem = (await LocalStorage.GetItemAsync<List<AdministratorsModel>>("data")).Count;
items = new List<AdministratorsModel>(response); // an actual data for the current page
}
}
}

@ -1,5 +1,5 @@
@page "/chapters" @page "/chapters"
@using Blazor.Models; @using Blazor.ViewClasses;
@using Blazorise.DataGrid @using Blazorise.DataGrid
<h3>Chapters</h3> <h3>Chapters</h3>
@ -7,12 +7,15 @@
<NavLink class="btn btn-primary" href="addChapter" Match="NavLinkMatch.All"> <NavLink class="btn btn-primary" href="addChapter" Match="NavLinkMatch.All">
<i class="fa fa-plus"></i> Ajouter <i class="fa fa-plus"></i> Ajouter
</NavLink> </NavLink>
<NavLink class="btn btn-primary" @onclick="Export">
<i class="fa fa-plus"></i> Exporter
</NavLink>
</div> </div>
<DataGrid TItem="Chapter" <DataGrid TItem="Chapter"
Data="@chapters" Data="@chapters"
ReadData="@OnReadData" ReadData="@OnReadData"
TotalItems="@totalItem" TotalItems="@totalChapter"
PageSize="10" PageSize="10"
ShowPager ShowPager
Responsive> Responsive>
@ -24,4 +27,4 @@
</DisplayTemplate> </DisplayTemplate>
</DataGridColumn> </DataGridColumn>
</DataGrid> </DataGrid>
<script src="Pages/Chapters.razor.js"></script>

@ -1,23 +1,54 @@
using Microsoft.AspNetCore.Components; using Blazored.LocalStorage;
using Blazor.Models;
using Blazorise.DataGrid;
using Blazored.LocalStorage;
using Blazorise; using Blazorise;
using Blazor.Services; using Blazor.Services;
using Blazorise.DataGrid;
using ChoETL;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System.Text;
using Blazor.ViewClasses;
namespace Blazor.Pages namespace Blazor.Pages;
{ public partial class Chapters
public partial class Chapters
{ {
public List<Chapter> chapters; public List<Chapter> chapters;
private int totalItem; private int totalChapter;
[Inject] [Inject]
public IDataService DataService { get; set; } public IDataService DataService { get; set; }
public IWebHostEnvironment WebHostEnvironment { get; set; }
[Inject] [Inject]
public IWebHostEnvironment WebHostEnvironment { get; set; } 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<Chapter[]>("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<Chapter[]>($"https://trusting-panini.87-106-126-109.plesk.page/api/chapters").Result;
await LocalStorage.SetItemAsync("data", originalData);
}
}
private async Task OnReadData(DataGridReadDataEventArgs<Chapter> e) private async Task OnReadData(DataGridReadDataEventArgs<Chapter> e)
{ {
@ -26,11 +57,35 @@ namespace Blazor.Pages
return; return;
} }
// When you use a real API, we use this follow code
//var response = await Http.GetFromJsonAsync<ChaptersModel[]>( $"https://trusting-panini.87-106-126-109.plesk.page/api/chapters?page={e.Page}&pageSize={e.PageSize}" );
var response = Http.GetFromJsonAsync<Chapter[]>($"https://trusting-panini.87-106-126-109.plesk.page/api/chapters").Result;
if (!e.CancellationToken.IsCancellationRequested) if (!e.CancellationToken.IsCancellationRequested)
{ {
chapters = await DataService.List(e.Page, e.PageSize); totalChapter = (await LocalStorage.GetItemAsync<List<Chapter>>("data")).Count;
totalItem = await DataService.Count(); chapters = new List<Chapter>(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);
} }
} }
} }

@ -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);
}

@ -0,0 +1,6 @@
namespace Blazor.Pages;
public partial class Index
{
}

@ -0,0 +1,47 @@
@page "/questions"
@using Blazor.Data
@inject WeatherForecastService ForecastService
<PageTitle>Weather forecast</PageTitle>
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from a service.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await ForecastService.GetForecastAsync(DateOnly.FromDateTime(DateTime.Now));
}
}

@ -0,0 +1,6 @@
namespace Blazor.Pages;
public partial class Questions
{
}

@ -13,6 +13,13 @@ var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages(); builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor(); builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>(); builder.Services.AddSingleton<WeatherForecastService>();
builder.Services.AddHttpClient();
builder.Services
.AddBlazorise()
.AddBootstrapProviders()
.AddFontAwesomeIcons();
builder.Services.AddBlazoredLocalStorage();
builder.Services.AddHttpClient(); builder.Services.AddHttpClient();

@ -1,4 +1,5 @@
using Blazor.Models; using Blazor.Models;
using Blazor.ViewClasses;
using Blazored.LocalStorage; using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;

@ -1,4 +1,5 @@
using Blazor.Models; using Blazor.Models;
using Blazor.ViewClasses;
namespace Blazor.Services namespace Blazor.Services
{ {

@ -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;
}
}

@ -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;
}
}

@ -0,0 +1,7 @@
namespace Blazor.ViewClasses;
public class Chapter
{
public int Id { get; set; }
public string Name { get; set; }
}

@ -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;
}
}

@ -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;
}
}

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

Loading…
Cancel
Save