Maxence GUITARD 1 year ago
commit f7189fc321

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
@ -11,6 +11,9 @@
<PackageReference Include="Blazorise.Bootstrap" Version="1.4.0" />
<PackageReference Include="Blazorise.DataGrid" 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>
</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"
@using Blazor.Models;
@using Blazorise.DataGrid
@using Blazor.ViewClasses
<h3>Administrators</h3>
<DataGrid TItem="Administrator"

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

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

@ -1,36 +1,91 @@
using Microsoft.AspNetCore.Components;
using Blazor.Models;
using Blazorise.DataGrid;
using Blazored.LocalStorage;
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
namespace Blazor.Pages;
public partial class Chapters
{
public List<Chapter> chapters;
private int totalItem;
private int totalChapter;
[Inject]
public IDataService DataService { get; set; }
public IWebHostEnvironment WebHostEnvironment { get; set; }
[Inject]
public IWebHostEnvironment WebHostEnvironment { get; set; }
public HttpClient Http { get; set; }
[Inject]
public ILocalStorageService LocalStorage { get; set; }
[Inject]
public NavigationManager NavigationManager { get; set; }
private async Task OnReadData(DataGridReadDataEventArgs<Chapter> e)
[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)
{
if (e.CancellationToken.IsCancellationRequested)
{
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)
{
chapters = await DataService.List(e.Page, e.PageSize);
totalItem = await DataService.Count();
totalChapter = (await LocalStorage.GetItemAsync<List<Chapter>>("data")).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.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
builder.Services.AddHttpClient();
builder.Services
.AddBlazorise()
.AddBootstrapProviders()
.AddFontAwesomeIcons();
builder.Services.AddBlazoredLocalStorage();
builder.Services.AddHttpClient();

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

@ -1,4 +1,5 @@
using Blazor.Models;
using Blazor.ViewClasses;
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.Shared
@using Blazorise.DataGrid

Loading…
Cancel
Save