Compare commits

..

4 Commits

@ -1,71 +0,0 @@
kind: pipeline
name: CI
type: docker
trigger:
event:
- push
steps:
- name: build
image: mcr.microsoft.com/dotnet/sdk:6.0
commands:
- cd WF-WebAdmin/WF-WebAdmin
- dotnet restore WF-WebAdmin.csproj
- dotnet build WF-WebAdmin.csproj -c Release --no-restore
- dotnet publish WF-WebAdmin.csproj -c Release --no-restore -o $CI_PROJECT_DIR/build/publish
- name: tests
image: mcr.microsoft.com/dotnet/sdk:6.0
commands:
- cd WF-WebAdmin/WF-WebAdmin
- dotnet restore WF-WebAdmin.csproj
- dotnet test WF-WebAdmin.csproj --no-restore
depends_on: [ build ]
- name: code-analysis
image: hub.codefirst.iut.uca.fr/marc.chevaldonne/codefirst-dronesonarplugin-dotnet8
commands:
- cd WF-WebAdmin/
- dotnet restore WF-WebAdmin.sln
- dotnet sonarscanner begin /k:$${project_key} /d:sonar.host.url=$${sonar_host} /d:sonar.coverageReportPaths="coveragereport/SonarQube.xml" /d:sonar.coverage.exclusions=$${coverage_exclusions} /d:sonar.login=$${sonar_token}
- dotnet build WF-WebAdmin.sln -c Release --no-restore
- dotnet test WF-WebAdmin.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 WF-WebAdmin.sln -c Release --no-restore -o $CI_PROJECT_DIR/build/release
- dotnet sonarscanner end /d:sonar.login=$${sonar_token}
secrets: [ SECRET_SONAR_LOGIN ]
environment:
sonar_host: https://codefirst.iut.uca.fr/sonar/
sonar_token:
from_secret: sonar_token
project_key: web_admin
coverage_exclusions: "Tests/**"
depends_on: [ tests ]
- name: generate-and-deploy-docs
image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-docdeployer
failure: ignore
volumes:
- name: docs
path: /docs
commands:
- /entrypoint.sh
when:
branch:
- master
depends_on: [ build ]
- name: docker_build
image: plugins/docker
settings:
repo: hub.codefirst.iut.uca.fr/whatthefantasy/wf-webadmin
registry: hub.codefirst.iut.uca.fr
dockerfile: Docker/Dockerfile
tags:
- latest
username:
from_secret: docker_username
password:
from_secret: docker_password
depends_on: [ build, tests, code-analysis ]

@ -1,27 +0,0 @@
# 1. Étape de build (SDK .NET 6)
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
# Copier le csproj et restaurer les dépendances
COPY WF-WebAdmin/WF-WebAdmin/WF-WebAdmin.csproj ./
RUN dotnet restore WF-WebAdmin.csproj
# Copier le reste du code et compiler
COPY WF-WebAdmin/WF-WebAdmin/ ./
RUN dotnet publish WF-WebAdmin.csproj -c Release -o /app/publish
# 2. Étape finale (runtime .NET 6)
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS final
WORKDIR /app
# Désactiver le rechargement de config pour éviter les erreurs inotify
ENV ASPNETCORE_HOSTBUILDER__RELOADCONFIGONCHANGE=false
# Copier les binaires publiés
COPY --from=build /app/publish ./
# Exposer le port HTTP (80) ; adapte si besoin
EXPOSE 80
# Lancement
ENTRYPOINT ["dotnet", "WF-WebAdmin.dll"]

@ -60,22 +60,21 @@ L'application devrait se lancer automatiquement dans votre navigateur par défau
# Blazor Apps (30 points)
🟨 En cours / ✅ Fait / ❌ Pas fait<br/><br/>
✅ Mise en place d'une page de visualisation des données avec pagination (2 points) <br/>
✅ Page d'ajout d'un élement avec validation (2 point)<br/>
✅ Page d'édition d'un élement avec validation (2 point)<br/>
✅ Supression d'un élement avec une confirmation (2 point)<br/>
Composant complexe (5 point)<br/>
🟨 Composant complexe (5 point)<br/>
🟨 Use API (Get / Insert / Update / Delete) (3 point)<br/>
Utilisation IOC & DI (4 point)<br/>
Localisation & Globalisation (au moins deux langues) (1 point) <br/>
Utilisation de la configuration (1 point)<br/>
Logs (2 point)<br/>
🟨 Propreté du code (Vous pouvez vous servir de sonarqube) (2 point)<br/>
Utilisation IOC & DI (4 point)<br/>
🟨 Localisation & Globalisation (au moins deux langues) (1 point) <br/>
Utilisation de la configuration (1 point)<br/>
🟨 Logs (2 point)<br/>
Propreté du code (Vous pouvez vous servir de sonarqube) (2 point)<br/>
✅ IHM (Design global, placement des boutons, ...) (2 point)<br/>
✅ Emplacement du code (Pas de code dans les vues) (2 point)<br/>
# Documentation (10 points)
Le Readme (2 points)<br/>
Description du fonctionnement de la solution client (illustrutration au niveau du code) (6 points)<br/>
Merge request (2 points)<br/>
🟨Le Readme (2 points)<br/>
Description du fonctionnement de la solution client (illustrutration au niveau du code) (6 points)<br/>
✅Merge request (2 points)<br/>

@ -1,11 +0,0 @@
namespace UnitTestWF
{
public class UnitTest1
{
[Fact]
public void Test1()
{
}
}
}

@ -1,29 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>
</Project>

@ -5,8 +5,6 @@ VisualStudioVersion = 17.9.34723.18
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WF-WebAdmin", "WF-WebAdmin\WF-WebAdmin.csproj", "{0E8D1007-ADDC-4103-847D-8EE48ACCDC62}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTestWF", "UnitTestWF\UnitTestWF.csproj", "{A4EC0EC4-7A46-4F8E-99C3-4FD32F173F2F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -17,10 +15,6 @@ Global
{0E8D1007-ADDC-4103-847D-8EE48ACCDC62}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0E8D1007-ADDC-4103-847D-8EE48ACCDC62}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0E8D1007-ADDC-4103-847D-8EE48ACCDC62}.Release|Any CPU.Build.0 = Release|Any CPU
{A4EC0EC4-7A46-4F8E-99C3-4FD32F173F2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A4EC0EC4-7A46-4F8E-99C3-4FD32F173F2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A4EC0EC4-7A46-4F8E-99C3-4FD32F173F2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A4EC0EC4-7A46-4F8E-99C3-4FD32F173F2F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

@ -1,23 +0,0 @@
using System;
using System.Text.Json.Serialization;
namespace WF_WebAdmin.Converter
{
public class CommentaryDto
{
[JsonPropertyName("id_comment")]
public int Id { get; set; }
[JsonPropertyName("quote")]
public int Quote { get; set; }
[JsonPropertyName("users")]
public int IdUser { get; set; }
[JsonPropertyName("dateC")]
public string DateCreationRaw { get; set; } = string.Empty;
[JsonPropertyName("comment")]
public string Text { get; set; } = string.Empty;
}
}

@ -1,46 +0,0 @@
using System;
using System.Globalization;
using WF_WebAdmin.Model;
namespace WF_WebAdmin.Converter
{
public static class CommentaryExtensions
{
public static Commentary ToModel(this CommentaryDto dto)
{
DateTime parsedDate = DateTime.MinValue;
if (!string.IsNullOrEmpty(dto.DateCreationRaw) &&
DateTime.TryParseExact(dto.DateCreationRaw, "yyyy-MM-dd",
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out DateTime result))
{
parsedDate = result;
}
else
{
Console.Out.WriteLine($"Erreur de conversion de la date : {dto.DateCreationRaw}");
}
return new Commentary
{
Id = dto.Id,
IdUser = dto.IdUser,
DateCreation = parsedDate,
Text = dto.Text
};
}
public static CommentaryDto ToDTO(this Commentary model)
{
return new CommentaryDto
{
Id = model.Id,
IdUser = model.IdUser,
DateCreationRaw = model.DateCreation.ToString("yyyy-MM-dd"),
Text = model.Text
};
}
}
}

@ -0,0 +1,22 @@
namespace WF_WebAdmin.Converter
{
/// <summary>
/// Représente un objet de transfert de données (DTO) pour une citation quotidienne.
/// </summary>
public class DailyQuoteDTO
{
/// <summary>
/// Identifiant unique de la citation quotidienne.
/// </summary>
private int Id { get; set; }
/// <summary>
/// Initialise une nouvelle instance de la classe <see cref="DailyQuoteDTO"/> avec un identifiant.
/// </summary>
/// <param name="id">L'identifiant unique de la citation quotidienne.</param>
public DailyQuoteDTO(int id)
{
this.Id = id;
}
}
}

@ -1,12 +0,0 @@
namespace WF_WebAdmin.Converter
{
public class DailyQuoteDto
{
private int Id { get; set; }
public DailyQuoteDto(int id)
{
this.Id = id;
}
}
}

@ -2,11 +2,20 @@
namespace WF_WebAdmin.Converter
{
/// <summary>
/// Fournit des extensions pour convertir des objets de type <see cref="DailyQuote"/> en objets de type <see cref="DailyQuoteDTO"/>.
/// </summary>
public class DailyQuoteExtension
{
public DailyQuoteDto DailyQuoteToDto(DailyQuote dq)
/// <summary>
/// Convertit une instance de <see cref="DailyQuote"/> en une instance de <see cref="DailyQuoteDTO"/>.
/// </summary>
/// <param name="dq">L'objet <see cref="DailyQuote"/> à convertir.</param>
/// <returns>Une instance de <see cref="DailyQuoteDTO"/> contenant l'identifiant de la citation quotidienne.</returns>
public DailyQuoteDTO DailyQuoteToDTO(DailyQuote dq)
{
DailyQuoteDto dailyQuote = new DailyQuoteDto(dq.Id);
// Création de l'objet DTO à partir de l'objet DailyQuote
DailyQuoteDTO dailyQuote = new DailyQuoteDTO(dq.Id);
return dailyQuote;
}
}

@ -0,0 +1,123 @@
using Microsoft.AspNetCore.DataProtection.KeyManagement;
using System;
namespace WF_WebAdmin.Converter
{
/// <summary>
/// Représente un objet Data Transfer Object (DTO) pour une citation.
/// </summary>
public class QuoteDTO
{
/// <summary>
/// Identifiant de la citation.
/// </summary>
public int Id { get; set; }
/// <summary>
/// Contenu de la citation.
/// </summary>
public string Content { get; set; }
/// <summary>
/// Nombre de "likes" de la citation.
/// </summary>
public int Likes { get; set; }
/// <summary>
/// Langue de la citation.
/// </summary>
public string Langue { get; set; }
/// <summary>
/// Indique si la citation est valide.
/// </summary>
public bool IsValide { get; set; }
/// <summary>
/// Raison pour laquelle la citation pourrait être invalide.
/// </summary>
public string? Reason { get; set; }
/// <summary>
/// Identifiant du caractère associé à la citation (si applicable).
/// </summary>
public int? IdCaracter { get; set; }
/// <summary>
/// Nom du caractère associé à la citation (si applicable).
/// </summary>
public string NameCharac { get; set; }
/// <summary>
/// Identifiant de la source de la citation.
/// </summary>
public int? IdSource { get; set; }
/// <summary>
/// Titre de la source de la citation.
/// </summary>
public string TitleSrc { get; set; }
/// <summary>
/// Date de la source de la citation.
/// </summary>
public DateTime DateSrc { get; set; }
/// <summary>
/// Identifiant de l'utilisateur qui a vérifié la citation (si applicable).
/// </summary>
public int? IdUserVerif { get; set; }
/// <summary>
/// Nom de l'utilisateur qui a vérifié la citation.
/// </summary>
public string NameUser { get; set; }
/// <summary>
/// Identifiant de l'image associée à la citation (si applicable).
/// </summary>
public int? IdImg { get; set; }
/// <summary>
/// Chemin de l'image associée à la citation.
/// </summary>
public string ImgPath { get; set; }
/// <summary>
/// Initialise une nouvelle instance de <see cref="QuoteDTO"/>.
/// </summary>
/// <param name="id_quote">L'identifiant de la citation.</param>
/// <param name="content">Le contenu de la citation.</param>
/// <param name="likes">Le nombre de likes de la citation.</param>
/// <param name="langue">La langue de la citation.</param>
/// <param name="isValide">Indique si la citation est valide.</param>
/// <param name="reason">La raison pour laquelle la citation peut être invalide.</param>
/// <param name="id_caracter">L'identifiant du caractère associé à la citation.</param>
/// <param name="name_charac">Le nom du caractère associé à la citation.</param>
/// <param name="id_source">L'identifiant de la source de la citation.</param>
/// <param name="title">Le titre de la source de la citation.</param>
/// <param name="date">La date de la source de la citation.</param>
/// <param name="id_user_verif">L'identifiant de l'utilisateur ayant vérifié la citation.</param>
/// <param name="name_user">Le nom de l'utilisateur ayant vérifié la citation.</param>
/// <param name="id_img">L'identifiant de l'image associée à la citation.</param>
/// <param name="img_path">Le chemin de l'image associée à la citation.</param>
public QuoteDTO(int id_quote, string content, int likes, string langue, bool isValide, string? reason, int? id_caracter, string name_charac, int? id_source, string title, DateTime date, int? id_user_verif, string name_user, int? id_img, string img_path)
{
this.Id = id_quote;
this.Content = content;
this.Likes = likes;
this.Langue = langue;
this.IsValide = isValide;
this.Reason = reason;
this.IdCaracter = id_caracter;
this.NameCharac = name_charac;
this.IdSource = id_source;
this.TitleSrc = title;
this.DateSrc = date;
this.IdUserVerif = id_user_verif;
this.NameUser = name_user;
this.IdImg = id_img;
this.ImgPath = img_path;
}
}
}

@ -1,43 +0,0 @@
using Microsoft.AspNetCore.DataProtection.KeyManagement;
using System;
namespace WF_WebAdmin.Converter
{
public class QuoteDto
{
public int Id { get; set; }
public string Content { get; set; }
public int Likes { get; set; }
public string Langue { get; set; }
public bool IsValide { get; set; }
public string? Reason { get; set; }
public int? IdCaracter { get; set; }
public string NameCharac { get; set; }
public int? IdSource { get; set; }
public string TitleSrc { get; set; }
public DateTime DateSrc { get; set; }
public int? IdUserVerif { get; set; }
public string NameUser { get; set; }
public int? IdImg { get; set; }
public string ImgPath { get; set; }
public QuoteDto(int id_quote,string content,int likes,string langue,bool isValide,string? reason,int? id_caracter,string name_charac,int? id_source,string title,DateTime date,int? id_user_verif,string name_user ,int? id_img,string img_path)
{
this.Id = id_quote;
this.Content = content;
this.Likes = likes;
this.Langue = langue;
this.IsValide = isValide;
this.Reason = reason;
this.IdCaracter = id_caracter;
this.NameCharac = name_charac;
this.IdSource = id_source;
this.TitleSrc = title;
this.DateSrc = date;
this.IdUserVerif = id_user_verif;
this.NameUser = name_user;
this.IdImg = id_img;
this.ImgPath =img_path;
}
}
}

@ -2,17 +2,59 @@
namespace WF_WebAdmin.Converter
{
/// <summary>
/// Classe d'extension pour la conversion entre les objets <see cref="Quote"/> et <see cref="QuoteDTO"/>.
/// </summary>
public class QuoteExtension
{
public QuoteDto QuoteToDTO(Quote? q)
/// <summary>
/// Convertit un objet <see cref="Quote"/> en un objet <see cref="QuoteDTO"/>.
/// </summary>
/// <param name="q">L'objet <see cref="Quote"/> à convertir.</param>
/// <returns>Un objet <see cref="QuoteDTO"/> contenant les données de l'objet <see cref="Quote"/>.</returns>
public QuoteDTO QuoteToDTO(Quote q)
{
QuoteDto quote = new QuoteDto(q.Id, q.Content, q.Like, q.Langue, q.IsValid,null, null,q.Charac,null,q.TitleSrc,q.DateSrc,null,q.UserProposition,null,q.ImgPath);
// Conversion des propriétés de Quote en QuoteDTO
QuoteDTO quote = new QuoteDTO(
q.Id,
q.Content,
q.Like,
q.Langue,
q.IsValid,
null, // Reason non défini ici
null, // IdCaracter non défini ici
q.Charac,
null, // IdSource non défini ici
q.TitleSrc,
q.DateSrc,
null, // IdUserVerif non défini ici
q.UserProposition,
null, // IdImg non défini ici
q.ImgPath
);
return quote;
}
public Quote DTOToQuote(QuoteDto q)
/// <summary>
/// Convertit un objet <see cref="QuoteDTO"/> en un objet <see cref="Quote"/>.
/// </summary>
/// <param name="q">L'objet <see cref="QuoteDTO"/> à convertir.</param>
/// <returns>Un objet <see cref="Quote"/> contenant les données de l'objet <see cref="QuoteDTO"/>.</returns>
public Quote DTOToQuote(QuoteDTO q)
{
Quote quote = new Quote(q.Id, q.Content,q.NameCharac,q.ImgPath,q.TitleSrc,q.DateSrc,q.Likes,q.Langue,q.NameUser,q.IsValide);
// Conversion des propriétés de QuoteDTO en Quote
Quote quote = new Quote(
q.Id,
q.Content,
q.NameCharac,
q.ImgPath,
q.TitleSrc,
q.DateSrc,
q.Likes,
q.Langue,
q.NameUser,
q.IsValide
);
return quote;
}
}

@ -0,0 +1,56 @@
using WF_WebAdmin.Model;
namespace WF_WebAdmin.Converter
{
/// <summary>
/// Représente un objet Data Transfer Object (DTO) pour un utilisateur.
/// Utilisé pour transmettre les informations d'un utilisateur entre différentes couches de l'application.
/// </summary>
public class UserDTO
{
/// <summary>
/// Obtient ou définit l'image de l'utilisateur.
/// </summary>
public string Image { get; set; }
/// <summary>
/// Obtient ou définit le nom de l'utilisateur.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Obtient ou définit l'adresse email de l'utilisateur.
/// </summary>
public string Email { get; set; }
/// <summary>
/// Obtient ou définit la date de création de l'utilisateur.
/// </summary>
public DateTime DateCreation { get; set; }
/// <summary>
/// Obtient ou définit une valeur indiquant si l'utilisateur est un administrateur.
/// </summary>
public Boolean IsAdmin { get; set; }
/// <summary>
/// Obtient ou définit la liste des commentaires associés à l'utilisateur.
/// </summary>
public List<Commentary> Comments { get; set; }
/// <summary>
/// Initialise une nouvelle instance de la classe <see cref="UserDTO"/> avec les informations de base d'un utilisateur.
/// </summary>
/// <param name="image">L'image de l'utilisateur.</param>
/// <param name="name">Le nom de l'utilisateur.</param>
/// <param name="email">L'email de l'utilisateur.</param>
/// <param name="dateCreation">La date de création du compte utilisateur.</param>
public UserDTO(string image, string name, string email, DateTime dateCreation)
{
this.Image = image;
this.Name = name;
this.Email = email;
this.DateCreation = dateCreation;
}
}
}

@ -1,24 +0,0 @@
using WF_WebAdmin.Model;
namespace WF_WebAdmin.Converter
{
public class UserDto
{
public string Image { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public DateTime DateCreation { get; set; }
public Boolean IsAdmin { get; set; }
public List<Commentary>? Comments { get; set; }
public UserDto(string image, string name, string email, DateTime dateCreation)
{
this.Image = image;
this.Name = name;
this.Email = email;
this.DateCreation = dateCreation;
}
}
}

@ -2,17 +2,32 @@
namespace WF_WebAdmin.Converter
{
/// <summary>
/// Classe d'extension permettant la conversion entre un utilisateur et son Data Transfer Object (DTO).
/// </summary>
public class UserExtension
{
public User UserToDto(UserDto u)
/// <summary>
/// Convertit un objet <see cref="UserDTO"/> en un objet <see cref="User"/>.
/// </summary>
/// <param name="u">L'objet <see cref="UserDTO"/> à convertir.</param>
/// <returns>Retourne un nouvel objet <see cref="User"/> avec les données du DTO.</returns>
public User UserToDTO(UserDTO u)
{
var user = new User(u.Image, u.Name, u.Email, u.DateCreation,u.IsAdmin);
// Création d'un objet User à partir des données du DTO
User user = new User(u.Image, u.Name, u.Email, u.DateCreation, u.IsAdmin);
return user;
}
public UserDto DtoToUser(User u)
/// <summary>
/// Convertit un objet <see cref="User"/> en un objet <see cref="UserDTO"/>.
/// </summary>
/// <param name="u">L'objet <see cref="User"/> à convertir.</param>
/// <returns>Retourne un nouvel objet <see cref="UserDTO"/> avec les données de l'utilisateur.</returns>
public UserDTO DTOToUser(User u)
{
var user = new UserDto(u.Image ?? "default.png", u.Name ?? "Bob", u.Email ?? "bob@mail.com", u.DateCreation);
// Création d'un objet UserDTO à partir des données de l'utilisateur
UserDTO user = new UserDTO(u.Image, u.Name, u.Email, u.DateCreation);
return user;
}
}

@ -1,13 +0,0 @@
namespace WF_WebAdmin.Data
{
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
}

@ -1,20 +0,0 @@
namespace WF_WebAdmin.Data
{
public class WeatherForecastService
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
public Task<WeatherForecast[]> GetForecastAsync(DateTime startDate)
{
return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = startDate.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
}).ToArray());
}
}
}

@ -1,8 +1,18 @@
namespace WF_WebAdmin.Model
{
/// <summary>
/// Représente un personnage dans le système.
/// </summary>
public class Character
{
public int id_caracter { get; set; }
public string? caracter { get; set; }
/// <summary>
/// Identifiant unique du personnage.
/// </summary>
public int id_caracter { get; set; }
/// <summary>
/// Nom ou description du personnage.
/// </summary>
public string caracter { get; set; }
}
}

@ -1,12 +1,21 @@
using System;
namespace WF_WebAdmin.Model
namespace WF_WebAdmin.Model
{
/// <summary>
/// Représente un commentaire dans le système.
/// </summary>
public class Commentary
{
public int Id { get; set; }
public int IdUser { get; set; }
//public int Id { get; set; }
//public int IdUser { get; set; }
/// <summary>
/// Le texte du commentaire.
/// </summary>
public string Text { get; set; }
/// <summary>
/// La date de création du commentaire.
/// </summary>
public DateTime DateCreation { get; set; }
public string Text { get; set; } = string.Empty;
}
}

@ -1,9 +1,19 @@
namespace WF_WebAdmin.Model
{
/// <summary>
/// Représente une citation quotidienne dans le système.
/// </summary>
public class DailyQuote
{
/// <summary>
/// Identifiant unique de la citation quotidienne.
/// </summary>
public int Id { get; set; }
/// <summary>
/// Initialise une nouvelle instance de la classe <see cref="DailyQuote"/>.
/// </summary>
/// <param name="Id">L'identifiant de la citation quotidienne.</param>
public DailyQuote(int Id)
{
this.Id = Id;

@ -1,24 +0,0 @@
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Configuration.UserSecrets;
using Microsoft.Extensions.Logging;
using Microsoft.VisualBasic;
using System;
using System.Diagnostics;
using System.Security.Claims;
using WF_WebAdmin.Pages;
using WF_WebAdmin.Service;
namespace WF_WebAdmin.Model
{
public static partial class LoggerSaveStub
{
public static void Log(ILogger? logs, LogLevel logLevel, string message, params object[] args)
{
ILogsService logsService = new LogsServiceStub();
logsService.addLogs(new Logs(logLevel, string.Format(message, args)));
logs.Log(logLevel, message, args);
}
}
}

@ -1,14 +0,0 @@
namespace WF_WebAdmin.Model
{
public class Logs
{
public LogLevel LogLevel { get; set; }
public string Message { get; set; }
public Logs(LogLevel logLevel , string message) {
this.LogLevel=logLevel;
this.Message=message;
}
}
}

@ -1,17 +1,90 @@
namespace WF_WebAdmin.Model
{
/// <summary>
/// Représente un quiz avec une question et plusieurs réponses possibles.
/// </summary>
public class Quiz
{
/// <summary>
/// Identifiant unique du quiz.
/// </summary>
public int Id { get; set; }
public string? Question { get; set; }
/// <summary>
/// La question posée dans le quiz.
/// </summary>
public string Question { get; set; }
/// <summary>
/// Réponse A possible pour le quiz.
/// </summary>
public string AnswerA { get; set; }
/// <summary>
/// Réponse B possible pour le quiz.
/// </summary>
public string AnswerB { get; set; }
/// <summary>
/// Réponse C possible pour le quiz.
/// </summary>
public string AnswerC { get; set; }
/// <summary>
/// Réponse D possible pour le quiz.
/// </summary>
public string AnswerD { get; set; }
/// <summary>
/// Réponse correcte au quiz (A, B, C ou D).
/// </summary>
public string CAnswer { get; set; }
/// <summary>
/// Indique si le quiz est valide.
/// </summary>
public bool IsValid { get; set; }
/// <summary>
/// Proposition de l'utilisateur pour valider le quiz.
/// </summary>
public string UserProposition { get; set; }
/// <summary>
/// Initialise une nouvelle instance de la classe <see cref="Quiz"/>.
/// </summary>
/// <param name="id">L'identifiant du quiz.</param>
/// <param name="question">La question posée dans le quiz.</param>
/// <param name="answerA">Réponse A possible.</param>
/// <param name="answerB">Réponse B possible.</param>
/// <param name="answerC">Réponse C possible.</param>
/// <param name="answerD">Réponse D possible.</param>
/// <param name="cAnswer">Réponse correcte (A, B, C ou D).</param>
/// <param name="isValid">Indique si le quiz est valide.</param>
/// <param name="userProposition">Proposition de l'utilisateur.</param>
public Quiz(int id, string question, string answerA, string answerB, string answerC, string answerD, string cAnswer, bool isValid, string userProposition)
{
Id = id;
Question = question;
AnswerA = answerA;
AnswerB = answerB;
AnswerC = answerC;
AnswerD = answerD;
CAnswer = cAnswer;
IsValid = isValid;
UserProposition = userProposition;
}
/// <summary>
/// Initialise une nouvelle instance de la classe <see cref="Quiz"/> avec une valeur par défaut pour la validité et la proposition de l'utilisateur.
/// </summary>
/// <param name="id">L'identifiant du quiz.</param>
/// <param name="question">La question posée dans le quiz.</param>
/// <param name="answerA">Réponse A possible.</param>
/// <param name="answerB">Réponse B possible.</param>
/// <param name="answerC">Réponse C possible.</param>
/// <param name="answerD">Réponse D possible.</param>
/// <param name="cAnswer">Réponse correcte (A, B, C ou D).</param>
public Quiz(int id, string question, string answerA, string answerB, string answerC, string answerD, string cAnswer)
{
Id = id;
@ -25,5 +98,9 @@ namespace WF_WebAdmin.Model
UserProposition = "Admin";
}
/// <summary>
/// Constructeur par défaut pour la classe <see cref="Quiz"/>.
/// </summary>
public Quiz() {}
}
}

@ -2,29 +2,56 @@
namespace WF_WebAdmin.Model
{
/// <summary>
/// Modèle représentant les données nécessaires à la création ou à la modification d'un quiz.
/// </summary>
public class QuizModel
{
/// <summary>
/// Question posée dans le quiz.
/// Cette propriété est obligatoire et doit être d'une longueur maximale de 200 caractères.
/// </summary>
[Required]
[StringLength(200, ErrorMessage = "La question ne peut pas depasser les 200 caractère.")]
public string? Question { get; set; }
public string Question { get; set; }
/// <summary>
/// Première réponse possible pour le quiz.
/// Cette propriété est obligatoire et doit être d'une longueur maximale de 50 caractères.
/// </summary>
[Required]
[StringLength(50, ErrorMessage = "La réponse ne peut pas depasser les 50 caractère.")]
public string? AnswerA { get; set; }
public string AnswerA { get; set; }
/// <summary>
/// Deuxième réponse possible pour le quiz.
/// Cette propriété est obligatoire et doit être d'une longueur maximale de 50 caractères.
/// </summary>
[Required]
[StringLength(50, ErrorMessage = "La réponse ne peut pas depasser les 50 caractère.")]
public string? AnswerB { get; set; }
public string AnswerB { get; set; }
/// <summary>
/// Troisième réponse possible pour le quiz.
/// Cette propriété est obligatoire et doit être d'une longueur maximale de 50 caractères.
/// </summary>
[Required]
[StringLength(50, ErrorMessage = "La réponse ne peut pas depasser les 50 caractère.")]
public string? AnswerC { get; set; }
public string AnswerC { get; set; }
/// <summary>
/// Quatrième réponse possible pour le quiz.
/// Cette propriété est obligatoire et doit être d'une longueur maximale de 50 caractères.
/// </summary>
[Required]
[StringLength(50, ErrorMessage = "La réponse ne peut pas depasser les 50 caractère.")]
public string? AnswerD { get; set; }
public string AnswerD { get; set; }
/// <summary>
/// Réponse correcte au quiz, choisie parmi A, B, C ou D.
/// Cette propriété est obligatoire.
/// </summary>
[Required]
public string? CAnswer { get; set; }
public string CAnswer { get; set; }
}
}

@ -1,20 +1,73 @@
using Microsoft.AspNetCore.DataProtection.KeyManagement;
namespace WF_WebAdmin.Model
namespace WF_WebAdmin.Model
{
/// <summary>
/// Représente une citation dans le système.
/// </summary>
public class Quote
{
/// <summary>
/// Identifiant unique de la citation.
/// </summary>
public int Id { get; set; }
/// <summary>
/// Contenu de la citation.
/// </summary>
public string Content { get; set; }
/// <summary>
/// Nombre de "likes" reçus pour cette citation.
/// </summary>
public int Like { get; set; }
/// <summary>
/// Langue dans laquelle la citation est écrite.
/// </summary>
public string Langue { get; set; }
/// <summary>
/// Caractère associé à la citation (ex : personnage, auteur, etc.).
/// </summary>
public string Charac { get; set; }
/// <summary>
/// Chemin d'accès à l'image associée à la citation.
/// </summary>
public string ImgPath { get; set; }
/// <summary>
/// Titre de la source de la citation (ex : livre, film, etc.).
/// </summary>
public string TitleSrc { get; set; }
/// <summary>
/// Date de la source de la citation.
/// </summary>
public DateTime DateSrc { get; set; }
/// <summary>
/// Nom de l'utilisateur ayant proposé la citation.
/// </summary>
public string UserProposition { get; set; }
/// <summary>
/// Indique si la citation est valide.
/// </summary>
public bool IsValid { get; set; }
/// <summary>
/// Constructeur pour créer une nouvelle citation avec tous ses attributs.
/// </summary>
/// <param name="id">Identifiant de la citation.</param>
/// <param name="content">Contenu de la citation.</param>
/// <param name="charac">Caractère associé à la citation.</param>
/// <param name="imgPath">Chemin de l'image associée.</param>
/// <param name="titleSrc">Titre de la source.</param>
/// <param name="dateSrc">Date de la source.</param>
/// <param name="like">Nombre de "likes" reçus.</param>
/// <param name="langue">Langue de la citation.</param>
/// <param name="userProposition">Nom de l'utilisateur ayant proposé la citation.</param>
/// <param name="isvalid">Indicateur de validité de la citation.</param>
public Quote(int id, string content, string charac, string imgPath, string titleSrc, DateTime dateSrc, int like, string langue, string userProposition, bool isvalid)
{
Id = id;
@ -28,6 +81,51 @@ namespace WF_WebAdmin.Model
UserProposition = userProposition;
IsValid = isvalid;
}
}
}
/*
public int Id { get; set; }
public string Content { get; set; }
public int Likes { get; set; }
public string Langue { get; set; }
public bool IsValide { get; set; }
public string? Reason { get; set; }
public int IdCaracter { get; set; }
public int IdSource { get; set; }
public int? IdUserVerif { get; set; }
public Quote(int id, string content, int likes, string langue, bool isValide, string? reason, int idCaracter, int idSource, int idUserVerif)
{
Id = id;
Content = content;
Likes = likes;
Langue = langue;
IsValide = isValide;
Reason = reason;
IdCaracter = idCaracter;
IdSource = idSource;
IdUserVerif = idUserVerif;
}
public Quote(int id, string content, int likes, string langue, bool isValide, string? reason, int idCaracter, int idSource, int? idUserVerif)
{
Id = id;
Content = content;
Likes = likes;
Langue = langue;
IsValide = isValide;
Reason = reason;
IdCaracter = idCaracter;
IdSource = idSource;
IdUserVerif = idUserVerif;
}
*/

@ -1,27 +1,65 @@
using System.ComponentModel.DataAnnotations;
namespace WF_WebAdmin.Model
namespace WF_WebAdmin.Model
{
/// <summary>
/// Modèle représentant une citation dans le système.
/// Ce modèle est utilisé pour la validation des données avant leur persistance.
/// </summary>
public class QuoteModel
{
/// <summary>
/// Identifiant unique de la citation.
/// </summary>
public int Id { get; set; }
/// <summary>
/// Contenu de la citation.
/// La citation ne peut pas dépasser 300 caractères.
/// </summary>
[Required]
[StringLength(300, ErrorMessage = "La citation ne peut pas dépasser les 300 caractère.")]
public string? Content { get; set; }
[StringLength(300, ErrorMessage = "La citation ne peut pas dépasser les 300 caractères.")]
public string Content { get; set; }
/// <summary>
/// Nombre de "likes" que la citation a reçus.
/// </summary>
public int Like { get; set; }
/// <summary>
/// Langue dans laquelle la citation est écrite.
/// La langue est limitée à 2 caractères.
/// </summary>
[Required]
[StringLength(2, ErrorMessage = "La langue ne peut pas dépasser 2 caractère.")]
public string? Langue { get; set; }
[StringLength(2, ErrorMessage = "La langue ne peut pas dépasser 2 caractères.")]
public string Langue { get; set; }
/// <summary>
/// Caractère associé à la citation (ex : auteur ou personnage).
/// </summary>
public string Charac { get; set; }
/// <summary>
/// Chemin d'accès à l'image associée à la citation.
/// </summary>
public string ImgPath { get; set; }
/// <summary>
/// Titre de la source de la citation (ex : livre, film, etc.).
/// </summary>
public string TitleSrc { get; set; }
public string? Charac { get; set; }
public string? ImgPath { get; set; }
public string? TitleSrc { get; set; }
/// <summary>
/// Date de la source de la citation.
/// </summary>
public DateTime DateSrc { get; set; }
public string? UserProposition { get; set; }
/// <summary>
/// Nom de l'utilisateur ayant proposé la citation.
/// </summary>
public string UserProposition { get; set; }
/// <summary>
/// Indique si la citation est validée par le système.
/// </summary>
public bool IsValid { get; set; }
}
}

@ -1,11 +1,25 @@
namespace WF_WebAdmin.Model
{
/// <summary>
/// Représente une source d'une citation dans le système.
/// Cette classe contient des informations sur la source d'une citation, telles que son titre et sa date de publication.
/// </summary>
public class Source
{
public int id_source { get; set; }
/// <summary>
/// Identifiant unique de la source.
/// </summary>
public int id_source { get; set; }
public string? title { get; set; }
/// <summary>
/// Titre de la source, tel qu'un livre, un article ou une œuvre.
/// </summary>
public string title { get; set; }
public int date { get; set; }
/// <summary>
/// Date de publication de la source.
/// Il s'agit d'une représentation de l'année sous forme d'entier.
/// </summary>
public int date { get; set; }
}
}

@ -1,17 +1,55 @@
namespace WF_WebAdmin.Model
{
/// <summary>
/// Représente un utilisateur dans le système.
/// Cette classe contient des informations sur l'utilisateur, telles que son image, son nom, son email, la date de création de son compte,
/// son statut d'administrateur et les commentaires qu'il a publiés.
/// </summary>
public class User
{
/// <summary>
/// Identifiant unique de l'utilisateur.
/// </summary>
public int Id { get; set; }
public string? Image { get; set; }
public string? Name { get; set; }
public string? Email { get; set; }
/// <summary>
/// URL de l'image de profil de l'utilisateur.
/// </summary>
public string Image { get; set; }
/// <summary>
/// Nom de l'utilisateur.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Adresse email de l'utilisateur.
/// </summary>
public string Email { get; set; }
/// <summary>
/// Date de création du compte utilisateur.
/// </summary>
public DateTime DateCreation { get; set; }
public Boolean IsAdmin { get; set; }
/// <summary>
/// Indique si l'utilisateur a des privilèges d'administrateur.
/// </summary>
public bool IsAdmin { get; set; }
public List<Commentary>? Comments { get; set; }
/// <summary>
/// Liste des commentaires publiés par l'utilisateur.
/// </summary>
public List<Commentary> Comments { get; set; }
/// <summary>
/// Constructeur pour créer un nouvel utilisateur avec des informations spécifiques.
/// </summary>
/// <param name="image">URL de l'image de profil de l'utilisateur.</param>
/// <param name="name">Nom de l'utilisateur.</param>
/// <param name="email">Adresse email de l'utilisateur.</param>
/// <param name="dateCreation">Date de création du compte de l'utilisateur.</param>
/// <param name="isAdmin">Indicateur si l'utilisateur est un administrateur.</param>
public User(string image, string name, string email, DateTime dateCreation, bool isAdmin)
{
this.Image = image;
@ -21,6 +59,9 @@
IsAdmin = isAdmin;
}
/// <summary>
/// Constructeur par défaut pour créer un utilisateur sans initialiser ses propriétés.
/// </summary>
public User() { }
}
}

@ -1,14 +1,45 @@
using System;
namespace WF_WebAdmin.Model
namespace WF_WebAdmin.Model
{
/// <summary>
/// Représente un utilisateur dans le système de connexion.
/// Cette classe contient des informations nécessaires pour l'authentification et la gestion du profil utilisateur.
/// </summary>
public class UserLogin
{
/// <summary>
/// Identifiant unique de l'utilisateur.
/// </summary>
public int Id { get; set; }
public string? Image { get; set; }
public string? Name { get; set;}
public Boolean IsAdmin { get; set; }
public string? Mdp { get; set; }
public UserLogin(int id,string image, string name, bool isAdmin, string mdp)
/// <summary>
/// URL de l'image de profil de l'utilisateur.
/// </summary>
public string Image { get; set; }
/// <summary>
/// Nom de l'utilisateur.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Indique si l'utilisateur possède des privilèges d'administrateur.
/// </summary>
public bool IsAdmin { get; set; }
/// <summary>
/// Mot de passe de l'utilisateur.
/// </summary>
public string Mdp { get; set; }
/// <summary>
/// Constructeur pour créer un objet <see cref="UserLogin"/> avec des informations d'authentification et de profil.
/// </summary>
/// <param name="id">Identifiant de l'utilisateur.</param>
/// <param name="image">URL de l'image de profil de l'utilisateur.</param>
/// <param name="name">Nom de l'utilisateur.</param>
/// <param name="isAdmin">Indicateur si l'utilisateur est un administrateur.</param>
/// <param name="mdp">Mot de passe de l'utilisateur.</param>
public UserLogin(int id, string image, string name, bool isAdmin, string mdp)
{
Id = id;
this.Image = image;
@ -17,6 +48,9 @@ namespace WF_WebAdmin.Model
this.Mdp = mdp;
}
/// <summary>
/// Constructeur par défaut pour créer un objet <see cref="UserLogin"/> sans initialiser les propriétés.
/// </summary>
public UserLogin() { }
}
}

@ -1,9 +1,9 @@
@page "/"
@page "/Accueil"
@using WF_WebAdmin.Model
<PageTitle>Accueil</PageTitle>
<h2><strong>@Localizer["AccueilWelcome"] ?? "Bienvenue"</strong></h2>
<h2><strong>@Localizer["AccueilWelcome"]</strong></h2>
<h4>@Localizer["AccueilTitle"]</h4>
@ -28,5 +28,5 @@ else
}
<h4>@Localizer["AccueilManualChange"]</h4>
<button @onclick="() => RandomDailyquote()">@Localizer["AccueilAddRandomQuote"]</button>
<button>@Localizer["AccueilAddRandomQuote"]</button>

@ -1,86 +1,47 @@
using Blazorise.DataGrid;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using System;
using System.Security.Claims;
using System.Text.Json;
using WF_WebAdmin.Model;
namespace WF_WebAdmin.Pages
{
/// <summary>
/// Page d'accueil qui affiche des citations quotidiennes.
/// </summary>
public partial class Accueil
{
private Quote[]? Dailyquote;
[Inject]
public ILogger<Accueil>? Logger { get; set; }
/// <summary>
/// Tableau contenant les citations quotidiennes.
/// </summary>
private Quote[] Dailyquote;
/// <summary>
/// Service HttpClient pour faire des requêtes HTTP.
/// </summary>
[Inject]
public HttpClient? Http { get; set; }
public HttpClient Http { get; set; }
/// <summary>
/// Service NavigationManager pour la gestion de la navigation dans l'application.
/// </summary>
[Inject]
public NavigationManager? NavigationManager { get; set; }
public NavigationManager NavigationManager { get; set; }
/// <summary>
/// Service pour la localisation des ressources (traductions) sur la page.
/// </summary>
[Inject]
public IStringLocalizer<Accueil>? Localizer { get; set; }
public IStringLocalizer<Accueil> Localizer { get; set; }
/// <summary>
/// This method is called during the initialization of the Blazor component.
/// It is asynchronous and is used to load data or perform actions before the component is rendered.
/// Méthode appelée lors de l'initialisation du composant.
/// Elle charge les citations quotidiennes depuis un fichier JSON.
/// </summary>
/// <returns>Une tâche représentant l'opération asynchrone.</returns>
protected override async Task OnInitializedAsync()
{
var url = $"{NavigationManager.BaseUri}fake-dataDailyQuote.json";
try
{
var response = await Http.GetFromJsonAsync<Quote[]>(url);
Dailyquote = response ?? Array.Empty<Quote>(); // Assurer qu'on ne stocke pas null
}
catch (Exception ex)
{
Console.WriteLine($"Erreur lors du chargement des citations : {ex.Message}");
Dailyquote = Array.Empty<Quote>(); // Éviter une exception en cas d'erreur réseau
}
}
private async Task RandomDailyquote()
{
try
{
string _jsonFilePath = Path.Combine(Environment.CurrentDirectory, "wwwroot", "fake-dataDailyQuote.json");
Random random = new Random();
var response = await Http.GetFromJsonAsync<Quote[]>($"{NavigationManager.BaseUri}fake-dataQuote.json");
Quote[] quotes = response ?? Array.Empty<Quote>(); // Empêche null
if (quotes.Length > 0)
{
Dailyquote = new Quote[] { quotes.OrderBy(x => random.Next()).First() };
}
else
{
Console.WriteLine("Aucune citation disponible dans le fichier JSON.");
return;
}
var json = JsonSerializer.Serialize(Dailyquote, new JsonSerializerOptions { WriteIndented = true });
await File.WriteAllTextAsync(_jsonFilePath, json);
if (Logger != null)
{
LoggerSaveStub.Log(Logger, LogLevel.Information, "Random change of quote of the day");
}
else
{
Console.WriteLine("Logger non initialisé.");
}
}
catch (Exception ex)
{
Console.WriteLine($"Erreur dans RandomDailyquote: {ex.Message}");
}
// Chargement des citations quotidiennes depuis le fichier JSON
Dailyquote = await Http.GetFromJsonAsync<Quote[]>($"{NavigationManager.BaseUri}fake-dataDailyQuote.json");
}
}
}

@ -2,57 +2,57 @@
@page "/add"
<h3>@Localizer["TitleAddQuiz"]</h3>
<h3>Ajouter une Question</h3>
<EditForm Model="@_quizModel" OnValidSubmit="@HandleValidSubmit">
<EditForm Model="@QuizModel" OnValidSubmit="@HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<p>
<label for="display-quest">
@Localizer["TitleQuestion"]
<InputText id="display-quest" @bind-Value="_quizModel.Question" />
Question:
<InputText id="display-quest" @bind-Value="QuizModel.Question" />
</label>
</p>
<p>
<label for="display-a">
@Localizer["AnswerA"]
<InputText id="display-a" @bind-Value="_quizModel.AnswerA" />
Réponse A:
<InputText id="display-a" @bind-Value="QuizModel.AnswerA" />
</label>
</p>
<p>
<label for="display-b">
@Localizer["AnswerB"]
<InputText id="display-b" @bind-Value="_quizModel.AnswerB" />
Réponse B:
<InputText id="display-b" @bind-Value="QuizModel.AnswerB" />
</label>
</p>
<p>
<label for="display-c">
@Localizer["AnswerC"]
<InputText id="display-c" @bind-Value="_quizModel.AnswerC" />
Réponse C:
<InputText id="display-c" @bind-Value="QuizModel.AnswerC" />
</label>
</p>
<p>
<label for="display-d">
@Localizer["AnswerD"]
<InputText id="display-d" @bind-Value="_quizModel.AnswerD" />
Réponse D:
<InputText id="display-d" @bind-Value="QuizModel.AnswerD" />
</label>
</p>
<p>
<label for="cA">
@Localizer["GoodAnswer"]
<input name="cA" type="radio" @onchange="@(e => OnCAwnserChange("A"))" /> A
<input name="cA" type="radio" @onchange="@(e => OnCAwnserChange("B"))" /> B
<input name="cA" type="radio" @onchange="@(e => OnCAwnserChange("C"))" /> C
<input name="cA" type="radio" @onchange="@(e => OnCAwnserChange("D"))" /> D
Bonne réponse:
<input name="cA" type="radio" @onchange="@(e => OnCAwnserChange("A", e.Value))" /> A
<input name="cA" type="radio" @onchange="@(e => OnCAwnserChange("B", e.Value))" /> B
<input name="cA" type="radio" @onchange="@(e => OnCAwnserChange("C", e.Value))" /> C
<input name="cA" type="radio" @onchange="@(e => OnCAwnserChange("D", e.Value))" /> D
</label>
</p>
<button type="submit">@Localizer["Submit"]</button>
<button type="submit">Submit</button>
</EditForm>

@ -3,126 +3,90 @@ using WF_WebAdmin.Service;
using WF_WebAdmin.Model;
using Microsoft.AspNetCore.Mvc;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using System.Security.Claims;
using System;
namespace WF_WebAdmin.Pages
{
public partial class AddQuiz
{
[Inject]
public ILogger<AddQuiz>? Logger { get; set; }
[Inject]
public IStringLocalizer<AddQuiz>? Localizer { get; set; }
[Inject]
private IQuizService? QuizService { get; set; }
private IQuizService quizService { get; set; }
[Inject]
public NavigationManager? NavigationManager { get; set; }
public NavigationManager NavigationManager { get; set; }
private readonly QuizModel _quizModel = new();
private QuizModel QuizModel = new();
/// <summary>
/// Handles the valid submission of a quiz form.
/// This method is triggered when the form is successfully validated and the user submits the quiz data.
/// It retrieves the current quiz count, increments it, and then adds a new quiz entry to the quiz service.
/// Finally, it navigates to the "modifquiz" page.
/// Handles the form submission to create a new quiz.
/// </summary>
private async Task HandleValidSubmit()
private async void HandleValidSubmit()
{
// Declare a variable to hold the ID of the new quiz.
int id;
// Get the current number of quizzes from the quiz service.
id = await QuizService.getNbQuiz();
// Increment the quiz ID for the new quiz.
id++;
// Create a new quiz and add it using the quiz service.
LoggerSaveStub.Log(Logger, LogLevel.Information, $"Creation of the {_quizModel.Question} question");
await QuizService.addQuiz(new Quiz(
id, // New quiz ID
ValidateInformation(_quizModel.Question), // Validated question
ValidateInformation(_quizModel.AnswerA), // Validated answer A
ValidateInformation(_quizModel.AnswerB), // Validated answer B
ValidateInformation(_quizModel.AnswerC), // Validated answer C
ValidateInformation(_quizModel.AnswerD), // Validated answer D
ValidateReponse(_quizModel.CAnswer) // Validated correct answer
id = await quizService.getNbQuiz(); // Fetch the current quiz count
id++; // Increment the quiz ID to create a new quiz ID
// Create and add the quiz using the validated inputs
await quizService.addQuiz(new Quiz(
id,
validateInformation(QuizModel.Question),
validateInformation(QuizModel.AnswerA),
validateInformation(QuizModel.AnswerB),
validateInformation(QuizModel.AnswerC),
validateInformation(QuizModel.AnswerD),
validateReponse(QuizModel.CAnswer)
));
// Navigate to the "modifquiz" page after adding the quiz.
// Navigate to the quiz management page after adding the quiz
NavigationManager.NavigateTo("modifquiz");
}
/// <summary>
/// Handles the change of the correct answer for the quiz.
/// This method is triggered when the user selects or changes the correct answer for the quiz question.
/// It updates the QuizModel's Correct Answer property with the selected answer.
/// Handles the change in the correct answer selection.
/// </summary>
/// <param name="item">The selected answer that will be marked as the correct answer.</param>
/// <param name="checkedValue">The value of the selected option, typically used for validation or additional logic.</param>
private void OnCAwnserChange(string item)
private void OnCAwnserChange(string item, object checkedValue)
{
// Update the correct answer in the QuizModel with the selected answer.
_quizModel.CAnswer = item;
QuizModel.CAnswer = item;
}
/// <summary>
/// Validates the provided string item.
/// This method is used to validate input data, but the validation logic is not yet implemented.
/// Validates each input (question or answers) to ensure it isn't null or empty.
/// </summary>
/// <param name="item">The string input to be validated.</param>
/// <returns>
/// Returns the input string as it is for now. The validation logic is yet to be implemented.
/// </returns>
private string ValidateInformation(string? item)
private static string validateInformation(string item)
{
return string.IsNullOrWhiteSpace(item) ? "Valeur par défaut" : item;
if (string.IsNullOrWhiteSpace(item))
{
throw new ArgumentException("Input cannot be empty or whitespace.");
}
return item; // Return the valid input
}
/// <summary>
/// Validates the provided answer item (A, B, C, or D) for the quiz.
/// This method ensures that the input corresponds to one of the allowed values for the correct answer.
/// If the input is invalid or null, it throws an exception and returns a default value ("A") in case of error.
/// Validates the selected correct answer to be one of the valid options (A, B, C, D).
/// </summary>
/// <param name="item">The answer item (A, B, C, or D) to be validated.</param>
/// <returns>
/// Returns the input item if valid (A, B, C, or D). If the item is invalid or null, it returns a default value ("A").
/// </returns>
private static string ValidateReponse(string item)
private static string validateReponse(string item)
{
// Check if the item is null or empty
if (string.IsNullOrEmpty(item))
try
{
// Throw exception if the item is null or empty
throw new ArgumentNullException(nameof(item), "The item cannot be null or empty.");
if (string.IsNullOrEmpty(item))
{
throw new ArgumentNullException("Correct answer must be selected.");
}
// Ensure the answer is one of A, B, C, or D
if (!Regex.IsMatch(item, "^[A-D]$"))
{
throw new InvalidDataException($"Invalid answer choice: '{item}'. Answer must be one of A, B, C, or D.");
}
return item; // Return the valid answer
}
// Validate that the item is one of the allowed values: A, B, C, or D
switch (item)
catch (Exception ex)
{
case "A":
case "B":
case "C":
case "D":
// Valid values, no action needed
break;
default:
// Throw exception if the item is not one of the allowed answers
throw new InvalidDataException($"Invalid item '{item}' provided. Item must be one of: A, B, C, or D.");
// Log error or show a message to the user
Console.WriteLine(ex.Message);
return "A"; // Return default answer "A" if validation fails
}
// Return the validated item
return item;
}
}
}

@ -1,37 +0,0 @@
@page "/commentary-chart"
<h1>Nombre de commentaires par mois</h1>
<MudChart ChartType="ChartType.Bar" ChartSeries="@Series" @bind-SelectedIndex="Index" LegendPosition="Position.Bottom" XAxisLabels="@XAxisLabels" Width="100%" Height="350px"></MudChart>
@code {
private int Index = -1;
private List<ChartSeries> Series = new();
private string[] XAxisLabels = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
[Inject] private WF_WebAdmin.Service.ICommentaryService CommentaryService { get; set; } = default!;
protected override async Task OnInitializedAsync()
{
var comments = await CommentaryService.GetCommentsAsync();
var groupedData = comments.GroupBy(c => c.DateCreation.Month)
.OrderBy(g => g.Key)
.Select(g => new { Month = g.Key - 1, Value = g.Count() })
.ToList();
double[] data = new double[12];
foreach (var item in groupedData)
{
data[item.Month] = item.Value;
}
Series = new List<ChartSeries>
{
new ChartSeries
{
Name = "",
Data = data
}
};
}
}

@ -5,7 +5,7 @@
<h3>@Localizer["TitleUser"]</h3>
@if(_users == null)
@if(users == null)
{
<p><strong>@Localizer["UserNobody"]</strong></p>
}
@ -13,10 +13,10 @@
else
{
<DataGrid TItem="User"
Data="@_users"
Data="@users"
PageSize="@MaxValue"
ReadData="@OnReadData"
TotalItems="@_totalItem"
TotalItems="@totalItem"
ShowPager
Responsive>
@ -29,7 +29,7 @@ else
<p>@Localizer["UserHere"]</p>
@foreach (var user in _users)
@foreach (var user in users)
{
<div class="userDiv" id="@user.Id">
<img class="imgProfil" src="@user.Image" />
@ -74,7 +74,7 @@ else
</div>
<!-- Fenêtre de confirmation de suppression -->
@if (_showPopupDelete)
@if (showPopupDelete)
{
<div class="divPopup">
<div class="contentPopup">
@ -84,17 +84,17 @@ else
</div>
</div>
}
@if (_showModifyPopup)
@if (showModifyPopup)
{
<div class="divPopup">
<div class="contentPopup">
<p>Modifier les informations de l'utilisateur :</p>
<label>Nom d'utilisateur:</label>
<input type="text" @bind="_selectedUser.Name"/>
<input type="text" @bind="selectedUser.Name"/>
<label>Email:</label>
<input type="email" @bind="_selectedUser.Email" />
<input type="email" @bind="selectedUser.Email" />
<label>Image:</label>
<input type="text" @bind="_selectedUser.Image" />
<input type="text" @bind="selectedUser.Image" />
<button @onclick="ModifyUser">Sauvegarder</button>
<button @onclick="ClosePopup">Annuler</button>
</div>
@ -103,12 +103,12 @@ else
}
<!-- Fenêtre de confirmation d'ajout admin-->
@if (_showPopupAdmin)
@if (showPopupAdmin)
{
<div class="divPopup">
<div class="contentPopup">
<p>@Localizer["UserPopupTitle2"]</p>
<button @onclick="() => setAdmin()">@Localizer["UserConfirmButton"]</button>
<button @onclick="() => Admin()">@Localizer["UserConfirmButton"]</button>
<button @onclick="ClosePopup">@Localizer["UserDeleteButton"]</button>
</div>
</div>

@ -1,7 +1,5 @@
using Blazorise.DataGrid;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Configuration.UserSecrets;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Localization;
using System.Collections.Generic;
using WF_WebAdmin.Model;
@ -9,208 +7,194 @@ using WF_WebAdmin.Service;
namespace WF_WebAdmin.Pages
{
/// <summary>
/// Page permettant de gérer les utilisateurs, y compris la suppression, la modification, et l'attribution du rôle admin.
/// </summary>
public partial class DeleteUser
{
[Inject]
public ILogger<DeleteUser>? Logger { get; set; }
/// <summary>
/// Indicateur pour afficher ou non la popup de confirmation de suppression.
/// </summary>
private bool showDeletePopup = false;
private List<User>? _users;
/// <summary>
/// Indicateur pour afficher ou non la popup de confirmation de modification d'utilisateur.
/// </summary>
private bool showModifyPopup = false;
private bool _showModifyPopup = false;
private User? _userToDelete = null;
private User? _selectedUser;
private bool _showPopupDelete = false;
private bool _showPopupAdmin = false;
private User? _userToAdmin = null;
private const int MaxValue = 5;
private int _totalItem;
private int _page = 1;
/// <summary>
/// Liste des utilisateurs à afficher dans la page.
/// </summary>
private List<User> users;
/// <summary>
/// Utilisateur sélectionné pour la suppression.
/// </summary>
private User userToDelete = null;
[Inject]
public HttpClient? Http { get; set; }
/// <summary>
/// Utilisateur sélectionné pour la modification.
/// </summary>
private User selectedUser;
[Inject]
public NavigationManager? NavigationManager { get; set; }
/// <summary>
/// Indicateur pour afficher ou non la popup de confirmation de suppression.
/// </summary>
private bool showPopupDelete = false;
/// <summary>
/// Indicateur pour afficher ou non la popup de confirmation de l'attribution du rôle admin.
/// </summary>
private bool showPopupAdmin = false;
/// <summary>
/// Utilisateur sélectionné pour devenir administrateur.
/// </summary>
private User userToAdmin = null;
/// <summary>
/// Nombre maximum d'utilisateurs à afficher par page.
/// </summary>
private int MaxValue = 5;
/// <summary>
/// Nombre total d'utilisateurs dans la base de données.
/// </summary>
private int totalItem;
/// <summary>
/// Numéro de la page actuelle dans le DataGrid.
/// </summary>
private int page = 1;
[Inject]
private IUserService? UserService { get; set; }
public HttpClient Http { get; set; }
[Inject]
public IStringLocalizer<DeleteUser>? Localizer { get; set; }
public NavigationManager NavigationManager { get; set; }
/// <summary>
/// Service permettant de gérer les utilisateurs (CRUD).
/// </summary>
[Inject]
private IUserService userService { get; set; }
/// <summary>
/// Localisateur de chaîne pour gérer la localisation de la page.
/// </summary>
[Inject]
public IStringLocalizer<DeleteUser> Localizer { get; set; }
/// <summary>
/// This method is called when the component is initialized.
/// It is an asynchronous method that retrieves a list of users from the user service.
/// The method fetches a subset of users with a specified maximum value and page number (1 in this case).
/// Méthode appelée lors de l'initialisation de la page. Charge les utilisateurs à afficher.
/// </summary>
protected override async Task OnInitializedAsync()
{
// Retrieve a list of users using the user service. The number of users and page number are specified.
// MaxValue determines how many users to retrieve, and '1' refers to the first page of results.
_users = await UserService.getSomeUser(MaxValue, 1);
// Charge la première page des utilisateurs
users = await userService.getSomeUser(MaxValue, 1);
}
/// <summary>
/// Handles the event when data is read in the data grid.
/// This method is triggered during pagination or when data is loaded into the grid.
/// It asynchronously fetches a page of users based on the requested page size and page number,
/// and updates the list of users and total item count if the operation is not cancelled.
/// Méthode appelée lors de la lecture des données dans le DataGrid. Gère la pagination et l'affichage des utilisateurs.
/// </summary>
/// <param name="e">The event arguments containing pagination details (page size and page number) and a cancellation token.</param>
private async Task OnReadData(DataGridReadDataEventArgs<User> e)
{
// If the cancellation token is requested, exit the method without processing the request.
if (e.CancellationToken.IsCancellationRequested)
{
return;
}
// Fetch a page of users from the user service using the page size and page number provided by the event arguments.
var response = await UserService.getSomeUser(e.PageSize, e.Page);
// Récupère les utilisateurs pour la page demandée
var response = await userService.getSomeUser(e.PageSize, e.Page);
// If the operation is not cancelled, update the total number of users and the list of users.
if (!e.CancellationToken.IsCancellationRequested)
{
_totalItem = await UserService.getNbUser(); // Get the total number of users
_users = new List<User>(response.ToArray()); // Store the retrieved users in the users list
_page = e.Page; // Update the current page number
totalItem = await userService.getNbUser(); // Récupère le nombre total d'utilisateurs
users = new List<User>(response.ToArray()); // Met à jour la liste des utilisateurs
page = e.Page; // Met à jour le numéro de la page
}
}
// ------- Popup remove user -------
/// <summary>
/// Displays a confirmation popup to confirm the deletion of a user.
/// This method is triggered when the user intends to delete a user,
/// and it sets the user to be deleted and shows the confirmation popup.
/// Affiche la popup de confirmation de suppression de l'utilisateur sélectionné.
/// </summary>
/// <param name="user">The user to be deleted, which is passed to the method for confirmation.</param>
private void ShowConfirmation(User? user)
private void ShowConfirmation(User user)
{
// Set the user to be deleted and show the confirmation popup.
_userToDelete = user; // Store the user to be deleted in a variable
_showPopupDelete = true; // Display the confirmation popup
userToDelete = user;
showPopupDelete = true;
}
/// <summary>
/// Displays a confirmation popup for modifying a user's information.
/// This method is triggered when the user intends to modify a specific user's data,
/// and it sets the selected user and shows the modification confirmation popup.
/// Affiche la popup de modification de l'utilisateur sélectionné.
/// </summary>
/// <param name="user">The user whose information is to be modified, passed to the method for confirmation.</param>
private void ShowModifyConfirmation(User? user)
private void ShowModifyConfirmation(User user)
{
// Set the selected user and show the modification confirmation popup.
_selectedUser = user; // Store the user to be modified
_showModifyPopup = true; // Display the confirmation popup for modification
selectedUser = user;
showModifyPopup = true;
}
/// <summary>
/// Removes the specified user from the system.
/// This method is triggered when the user confirms the deletion of a user.
/// It calls the user service to remove the user, closes the confirmation popup,
/// and then refreshes the list of users by fetching the updated data.
/// Supprime l'utilisateur sélectionné et met à jour la liste des utilisateurs affichés.
/// </summary>
private async Task RemoveUser()
{
// Check if there is a user to delete
if (_userToDelete != null)
if (userToDelete != null)
{
// Remove the selected user from the system using the user service
LoggerSaveStub.Log(Logger, LogLevel.Information, $"Delete user {_userToDelete.Name}");
await UserService.removeUser(_userToDelete);
// Close the confirmation popup after the deletion
ClosePopup();
// Refresh the list of users by fetching the updated data from the user service
var response = await UserService.getSomeUser(MaxValue, _page);
// Update the users list with the latest data
_users = new List<User>(response.ToArray());
await userService.removeUser(userToDelete); // Appelle le service pour supprimer l'utilisateur
ClosePopup(); // Ferme les popups
var response = await userService.getSomeUser(MaxValue, page); // Récupère à nouveau les utilisateurs
users = new List<User>(response.ToArray()); // Met à jour la liste des utilisateurs
}
}
/// <summary>
/// Modifies the selected user's information.
/// This method is triggered when the user confirms the modification of a user's details.
/// It calls the user service to update the user's information and then closes the modification popup.
/// Met à jour l'utilisateur sélectionné.
/// </summary>
private async Task ModifyUser()
{
// Update the selected user's information using the user service
LoggerSaveStub.Log(Logger, LogLevel.Information, $"Modification of user {_selectedUser.Name}");
await UserService.updateUser(_selectedUser);
// Close the modification popup after the update is complete
ClosePopup();
await userService.updateUser(selectedUser); // Appelle le service pour mettre à jour l'utilisateur
ClosePopup(); // Ferme les popups
}
/// <summary>
/// Closes all open popups in the UI by setting their visibility flags to false.
/// This method is typically called after an action (like deleting or modifying a user)
/// to hide any active popups and reset the UI state.
/// Ferme toutes les popups actuellement ouvertes.
/// </summary>
private void ClosePopup()
{
// Set all popup visibility flags to false to hide the popups
_showModifyPopup = false; // Close the modify confirmation popup
_showPopupDelete = false; // Close any additional delete popups
_showPopupAdmin = false; // Close the admin-related popup (if any)
showDeletePopup = false;
showModifyPopup = false;
showPopupDelete = false;
showPopupAdmin = false;
}
// ------- Popup admin -------
/// <summary>
/// Displays a confirmation popup to confirm the promotion of a user to admin status.
/// This method is triggered when the user intends to promote a specific user to admin.
/// It sets the selected user to be promoted and shows the confirmation popup for admin promotion.
/// Affiche la popup de confirmation pour attribuer ou révoquer le rôle d'administrateur.
/// </summary>
/// <param name="user">The user to be promoted to admin, passed to the method for confirmation.</param>
private void ShowConfirmationAdmin(User? user)
private void ShowConfirmationAdmin(User user)
{
// Set the user to be promoted to admin and show the confirmation popup.
_userToAdmin = user; // Store the user to be promoted
_showPopupAdmin = true; // Display the confirmation popup for admin promotion
userToAdmin = user;
showPopupAdmin = true;
}
/// <summary>
/// Toggles the admin status of the selected user.
/// This method checks the current admin status of the user, and if the user is not an admin,
/// it promotes them to admin. If the user is already an admin, it demotes them.
/// After the change, the user's information is updated, and the confirmation popup is closed.
/// Attribue ou révoque le rôle d'administrateur pour l'utilisateur sélectionné.
/// </summary>
private async Task setAdmin()
{
// Check if the user is not already an admin
if (!_userToAdmin.IsAdmin)
if (!userToAdmin.IsAdmin) // Si l'utilisateur n'est pas administrateur, on l'attribue comme admin
{
// Promote the user to admin
LoggerSaveStub.Log(Logger, LogLevel.Information, $"User {_userToAdmin.Name} is now administrator");
_userToAdmin.IsAdmin = true;
await UserService.updateUser(_userToAdmin); // Update the user status in the service
ClosePopup(); // Close the confirmation popup
userToAdmin.IsAdmin = true;
await userService.updateUser(userToAdmin); // Met à jour l'utilisateur
ClosePopup(); // Ferme les popups
}
else
else // Si l'utilisateur est déjà administrateur, on révoque ce rôle
{
// Demote the user from admin to normal user
LoggerSaveStub.Log(Logger, LogLevel.Information, $"User {_userToAdmin.Name} is no longer an administator");
_userToAdmin.IsAdmin = false;
await UserService.updateUser(_userToAdmin); // Update the user status in the service
ClosePopup(); // Close the confirmation popup
userToAdmin.IsAdmin = false;
await userService.updateUser(userToAdmin); // Met à jour l'utilisateur
ClosePopup(); // Ferme les popups
}
}
}
}

@ -3,29 +3,29 @@
<h3>Editer</h3>
<EditForm Model="@_quoteModel" OnValidSubmit="@HandleValidSubmit">
<EditForm Model="@quoteModel" OnValidSubmit="@HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<p>
<label for="display-cit">
Citation:
<InputText id="display-cit" @bind-Value="_quoteModel.Content" />
<InputText id="display-cit" @bind-Value="quoteModel.Content" />
</label>
</p>
<p>
<label for="lang">
Langue:
<input name="lang" type="radio" @onchange="@(e => OnlangChange("fr"))" /> fr
<input name="lang" type="radio" @onchange="@(e => OnlangChange("en"))" /> en
<input name="lang" type="radio" @onchange="@(e => OnlangChange("fr", e.Value))" /> fr
<input name="lang" type="radio" @onchange="@(e => OnlangChange("en", e.Value))" /> en
</label>
</p>
<p>
<label for="charac">
<InputSelect id="charac" @bind-Value="_quoteModel.Charac">
@foreach (Character display in _charac)
<InputSelect id="charac" @bind-Value="quoteModel.Charac">
@foreach (Character display in charac)
{
<option value="@display.caracter">@display.caracter (ID: @display.id_caracter)</option>
}
@ -35,8 +35,8 @@
<p>
<label for="src">
<InputSelect id="src" @bind-Value="_quoteModel.TitleSrc">
@foreach (Source display in _src)
<InputSelect id="src" @bind-Value="quoteModel.TitleSrc">
@foreach (Source display in src)
{
<option value="@display.title">@display.title (ID: @display.id_source)</option>
}

@ -1,106 +1,108 @@
using Microsoft.AspNetCore.Components;
using System.Security.Claims;
using WF_WebAdmin.Model;
using WF_WebAdmin.Service;
namespace WF_WebAdmin.Pages
{
/// <summary>
/// Page permettant de modifier une citation existante.
/// </summary>
public partial class Edit
{
/// <summary>
/// Identifiant de la citation à éditer passé en paramètre de la route.
/// </summary>
[Parameter]
public int Id { get; set; }
/// <summary>
/// Service pour gérer les citations.
/// </summary>
[Inject]
public ILogger<Edit>? Logger { get; set; }
[Inject]
private IQuoteService? quoteService { get; set; }
private IQuoteService quoteService { get; set; }
/// <summary>
/// Service pour la navigation entre les pages.
/// </summary>
[Inject]
public NavigationManager? NavigationManager { get; set; }
private Quote? Q { get; set; }
public NavigationManager NavigationManager { get; set; }
private QuoteModel _quoteModel = new();
/// <summary>
/// Citation actuelle à éditer.
/// </summary>
private Quote q { get; set; }
private List<Character> _charac = new List<Character>();
/// <summary>
/// Modèle de données pour l'édition de la citation.
/// </summary>
private QuoteModel quoteModel = new();
private List<Source> _src = new List<Source>();
/// <summary>
/// Liste des personnages disponibles pour l'édition.
/// </summary>
private List<Character> charac = new List<Character>();
/// <summary>
/// Liste des sources disponibles pour l'édition.
/// </summary>
private List<Source> src = new List<Source>();
/// <summary>
/// Asynchronously initializes the component by loading data related to a quote.
/// This method fetches a specific quote based on the provided ID and populates the `quoteModel`
/// with the quote's content, language, character, source, and other associated data.
/// It also loads additional data such as character and source information for the quote.
/// Méthode appelée lors de l'initialisation de la page.
/// Elle charge la citation à éditer ainsi que les données associées (personnages, sources).
/// </summary>
protected override async Task OnInitializedAsync()
{
// Fetch the quote data based on the provided ID.
Q = await quoteService.getOnequote(Id);
// Populate the quoteModel with the data from the retrieved quote.
_quoteModel.Content = Q.Content;
_quoteModel.Langue = Q.Langue;
_quoteModel.Charac = Q.Charac;
_quoteModel.TitleSrc = Q.TitleSrc;
_quoteModel.Id = Q.Id;
_quoteModel.Like = Q.Like;
_quoteModel.ImgPath = Q.ImgPath;
_quoteModel.DateSrc = Q.DateSrc;
_quoteModel.UserProposition = Q.UserProposition;
_quoteModel.IsValid = Q.IsValid;
// Fetch additional data related to the quote, such as character and source.
_charac = await quoteService.getChar();
_src = await quoteService.getSrc();
// Récupère la citation à éditer à partir de l'ID
q = await quoteService.getOnequote(Id);
// Initialise le modèle de données avec les informations de la citation
quoteModel.Content = q.Content;
quoteModel.Langue = q.Langue;
quoteModel.Charac = q.Charac;
quoteModel.TitleSrc = q.TitleSrc;
quoteModel.Id = q.Id;
quoteModel.Like = q.Like;
quoteModel.ImgPath = q.ImgPath;
quoteModel.DateSrc = q.DateSrc;
quoteModel.UserProposition = q.UserProposition;
quoteModel.IsValid = q.IsValid;
// Charge la liste des personnages et des sources
charac = await quoteService.getChar();
src = await quoteService.getSrc();
}
/// <summary>
/// Handles the submission of a valid form for updating a quote.
/// This method takes the data from `quoteModel`, updates the selected quote (`q`) with the new values,
/// and then calls the `quoteService.updateQuote` method to persist the changes.
/// After updating, it navigates to the "modifquote" page.
/// Méthode appelée lors de la soumission valide du formulaire d'édition.
/// Elle met à jour la citation avec les nouvelles données.
/// </summary>
protected async Task HandleValidSubmit()
protected async void HandleValidSubmit()
{
if (Q == null)
{
LoggerSaveStub.Log(Logger, LogLevel.Error, "Quote is null.");
return;
}
// Update the properties of the selected quote (`q`) with the data from `quoteModel`.
LoggerSaveStub.Log(Logger, LogLevel.Information, $"Editing the quote {Q.Content}");
// Met à jour les informations de la citation
q.Content = quoteModel.Content;
q.Langue = quoteModel.Langue;
q.TitleSrc = quoteModel.TitleSrc;
q.Charac = quoteModel.Charac;
Q.Content = _quoteModel.Content ?? "Content";
Q.Langue = _quoteModel.Langue ?? "EN";
Q.TitleSrc = _quoteModel.TitleSrc ?? "Something";
Q.Charac = _quoteModel.Charac ?? "Someone";
// Appelle le service pour mettre à jour la citation dans la base de données
await quoteService.updateQuote(q);
// Call the quote service to update the quote in the data source.
await quoteService.updateQuote(Q);
// Navigate to the "modifquote" page after updating the quote.
// Redirige vers la page des citations à modifier
NavigationManager.NavigateTo("modifquote");
}
/// <summary>
/// Handles the language change event for the quote.
/// This method updates the `Langue` property of the `quoteModel` based on the selected language (`item`).
/// It only accepts "fr" (French) or "en" (English) as valid language options.
/// Méthode appelée lors du changement de langue dans le formulaire.
/// </summary>
/// <param name="item">The selected language ("fr" or "en") passed to the method.</param>
/// <param name="checkedValue">The checked value (unused in this method but may be used for other purposes).</param>
private void OnlangChange(string item)
/// <param name="item">Langue sélectionnée.</param>
/// <param name="checkedValue">Valeur de l'élément vérifié.</param>
private void OnlangChange(string item, object checkedValue)
{
// Check if the selected language is either "fr" or "en"
// Si la langue est "fr" ou "en", met à jour la langue dans le modèle de données
if (item == "fr" || item == "en")
{
// Update the Langue property of the quoteModel with the selected language
_quoteModel.Langue = item;
quoteModel.Langue = item;
}
}
}

@ -7,7 +7,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>error</title>
<title>Error</title>
<link href="~/css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<link href="~/css/site.css" rel="stylesheet" asp-append-version="true" />
</head>
@ -27,12 +27,12 @@
<h3>Development Mode</h3>
<p>
Swapping to the <strong>development</strong> environment displays detailed information about the error that occurred.
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>
</div>

@ -4,37 +4,41 @@ using System.Diagnostics;
namespace WF_WebAdmin.Pages
{
/// <summary>
/// Modèle de page Razor pour afficher les erreurs dans l'application.
/// </summary>
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
/// <summary>
/// Identifiant unique de la requête pour le suivi des erreurs.
/// </summary>
public string? RequestId { get; set; }
/// <summary>
/// Indicateur pour afficher l'ID de la requête si ce dernier est disponible.
/// </summary>
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
private readonly ILogger<ErrorModel> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="ErrorModel"/> class.
/// This constructor is used to inject the <see cref="ILogger{ErrorModel}"/> into the model for logging purposes.
/// Constructeur pour initialiser le modèle de page avec le service de journalisation.
/// </summary>
/// <param name="logger">An instance of the <see cref="ILogger{ErrorModel}"/> used for logging error-related information.</param>
/// <param name="logger">Service de journalisation pour capturer les erreurs.</param>
public ErrorModel(ILogger<ErrorModel> logger)
{
_logger = logger;
}
/// <summary>
/// Handles the GET request for the page or endpoint.
/// This method retrieves the request ID for tracing purposes, using the `Activity.Current?.Id`
/// if it's available, or the `HttpContext.TraceIdentifier` as a fallback if no current activity ID is present.
/// Méthode appelée lors de l'accès à la page d'erreur.
/// Elle enregistre l'ID de la requête pour la journalisation et l'affichage des erreurs.
/// </summary>
public void OnGet()
{
// Retrieve the current request ID for tracing
// Capture de l'ID de la requête à partir de l'activité en cours ou du trace identifier
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
}
}

@ -1,4 +1,4 @@
@page "/login"
@page "/"
@using WF_WebAdmin.Model
@using System.Globalization

@ -1,84 +1,97 @@
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Configuration.UserSecrets;
using Microsoft.Extensions.Localization;
using WF_WebAdmin.Model;
namespace WF_WebAdmin.Pages
{
/// <summary>
/// Composant Blazor pour la gestion de la connexion des utilisateurs.
/// </summary>
public partial class Login
{
/// <summary>
/// Service de localisation pour gérer les textes multilingues dans la page de connexion.
/// </summary>
[Inject]
public IStringLocalizer<Login> Localizer { get; set; }
/// <summary>
/// Objet représentant les informations de connexion de l'utilisateur.
/// </summary>
private UserLogin userLogin = new UserLogin();
/// <summary>
/// Objet représentant l'utilisateur connecté.
/// </summary>
[Inject]
public UserLogin uLogin { get; set; }
/// <summary>
/// Message d'erreur affiché en cas de connexion échouée.
/// </summary>
private string ErrorConnexion;
/// <summary>
/// Liste des utilisateurs enregistrés pour la connexion.
/// </summary>
private List<UserLogin> usersConnexion;
/// <summary>
/// Service HTTP pour effectuer des requêtes.
/// </summary>
[Inject]
public HttpClient Http { get; set; }
/// <summary>
/// Service de gestion de la navigation dans l'application Blazor.
/// </summary>
[Inject]
public NavigationManager NavigationManager { get; set; }
/// <summary>
/// Asynchronously initializes the component by loading user login data.
/// This method retrieves a list of user login information from a JSON file located at the specified URI
/// and populates the `usersConnexion` list with the data.
/// Méthode appelée lors de l'initialisation du composant pour charger les données des utilisateurs.
/// </summary>
/// <returns>Une tâche asynchrone représentant l'initialisation du composant.</returns>
protected override async Task OnInitializedAsync()
{
// Fetch user login data from the specified JSON file.
// Chargement des utilisateurs depuis un fichier JSON simulé.
usersConnexion = await Http.GetFromJsonAsync<List<UserLogin>>($"{NavigationManager.BaseUri}fake-dataUserLogin.json");
}
/// <summary>
/// Validates the login credentials of the user.
/// This method checks if the provided username and password match any user in the `usersConnexion` list.
/// If the credentials are correct and the user is an admin, it stores the user details and navigates to the home page.
/// If the credentials are incorrect, an error message is set for display.
/// Méthode pour valider les informations de connexion de l'utilisateur.
/// </summary>
public void validlogin()
{
// Check if both the username and password are provided
// Vérification si les informations de connexion sont renseignées
if (!string.IsNullOrEmpty(userLogin.Name) || !string.IsNullOrEmpty(userLogin.Mdp))
{
// Loop through the list of connected users to find a match
foreach (var user in usersConnexion)
{
// Check if the username and password match the user credentials
// Vérification si les identifiants correspondent
if (userLogin.Name == user.Name && userLogin.Mdp == user.Mdp)
{
// Check if the user is an admin
// Vérification si l'utilisateur est un administrateur
if (user.IsAdmin)
{
// If the user is an admin, store their information and navigate to the home page
// Assignation de l'utilisateur à la session
uLogin.Id = userLogin.Id;
uLogin.Name = user.Name;
uLogin.Image = user.Image;
// Redirect to the homepage
// Redirection vers la page d'accueil
NavigationManager.NavigateTo(NavigationManager.BaseUri + "accueil");
return;
}
else
{
// If the user is not an admin, display an error message
// Message d'erreur pour utilisateur non admin
ErrorConnexion = "Connexion échouée, le nom ou le mot de passe sont incorrectes";
}
}
else
{
// If credentials do not match, set the error message
// Message d'erreur pour informations invalides
ErrorConnexion = "Connexion échouée, le nom ou le mot de passe sont incorrectes";
}
}

@ -1,31 +0,0 @@
@page "/logs"
<h3>@Localizer["LogTitle"]</h3>
@if (logs is null)
{
<p>@Localizer["NotLog"]</p>
}
else
{
<p>@Localizer["Log"]</p>
<table>
<thead>
<tr>
<th>@Localizer["LogLvl"]</th>
<th>@Localizer["LogContent"]</th>
</tr>
</thead>
<tbody>
@foreach (var log in logs)
{
<tr>
<td>@log.LogLevel</td>
<td>@log.Message</td>
</tr>
}
</tbody>
</table>
}

@ -1,25 +0,0 @@
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using WF_WebAdmin.Model;
namespace WF_WebAdmin.Pages
{
public partial class LogsPage
{
private Logs[] logs;
[Inject]
public HttpClient Http { get; set; }
[Inject]
public NavigationManager NavigationManager { get; set; }
[Inject]
public IStringLocalizer<LogsPage> Localizer { get; set; }
protected override async Task OnInitializedAsync()
{
logs = await Http.GetFromJsonAsync<Logs[]>($"{NavigationManager.BaseUri}fake_data_logs.json");
}
}
}

@ -1,13 +1,13 @@
@using WF_WebAdmin.Model
@page "/modifquiz"
<PageTitle>@Localizer["TitlePage"]</PageTitle>
<PageTitle>Gestion des question</PageTitle>
<h3>@Localizer["TitlePage"]</h3>
<h3>Gestion des quiz</h3>
<div>
<NavLink class="btn btn-primary" href="Add" Match="NavLinkMatch.All">
<i class="fa fa-plus"></i> @Localizer["Add"]
<i class="fa fa-plus"></i> Ajouter
</NavLink>
</div>
@ -19,17 +19,17 @@
ShowPager
Responsive>
<DataGridColumn TItem="Quiz" Field="@nameof(Quiz.Id)" Caption="@Localizer["Id"]" />
<DataGridColumn TItem="Quiz" Field="@nameof(Quiz.Question)" Caption="@Localizer["Question"]" />
<DataGridColumn TItem="Quiz" Field="@nameof(Quiz.AnswerA)" Caption="@Localizer["AnswerA"]" />
<DataGridColumn TItem="Quiz" Field="@nameof(Quiz.AnswerB)" Caption="@Localizer["AnswerB"]" />
<DataGridColumn TItem="Quiz" Field="@nameof(Quiz.AnswerC)" Caption="@Localizer["AnswerC"]" />
<DataGridColumn TItem="Quiz" Field="@nameof(Quiz.AnswerD)" Caption="@Localizer["AnswerD"]" />
<DataGridColumn TItem="Quiz" Field="@nameof(Quiz.CAnswer)" Caption="@Localizer["GoodAnswer"]" />
<DataGridColumn TItem="Quiz" Field="@nameof(Quiz.Id)" Caption="@Localizer["Action"]">
<DataGridColumn TItem="Quiz" Field="@nameof(Quiz.Id)" Caption="Id"/>
<DataGridColumn TItem="Quiz" Field="@nameof(Quiz.Question)" Caption="Rep A" />
<DataGridColumn TItem="Quiz" Field="@nameof(Quiz.AnswerA)" Caption="Rep A" />
<DataGridColumn TItem="Quiz" Field="@nameof(Quiz.AnswerB)" Caption="Rep B" />
<DataGridColumn TItem="Quiz" Field="@nameof(Quiz.AnswerC)" Caption="Rep C" />
<DataGridColumn TItem="Quiz" Field="@nameof(Quiz.AnswerD)" Caption="Rep D" />
<DataGridColumn TItem="Quiz" Field="@nameof(Quiz.CAnswer)" Caption="Bonne Rep" />
<DataGridColumn TItem="Quiz" Field="@nameof(Quiz.Id)" Caption="Action">
<DisplayTemplate>
<button type="button" class="btn btn-primary" @onclick="() => OnEditButtonClicked(context)"><i class="fa fa-edit"></i> @Localizer["Edit"]</button>
<button type="button" class="btn btn-primary" @onclick="() => OnDelete(context)"><i class="fa fa-trash"></i> @Localizer["Delete"]</button>
<button type="button" class="btn btn-primary" @onclick="() => OnEditButtonClicked(context)"><i class="fa fa-edit"></i> Editer</button>
<button type="button" class="btn btn-primary" @onclick="() => OnDelete(context)"><i class="fa fa-trash"></i> Supprimer</button>
</DisplayTemplate>
</DataGridColumn>
</DataGrid>
@ -38,21 +38,21 @@
{
<div class="divPopup">
<div class="contentPopup">
<p>@Localizer["ModifInfoUser"]</p>
<label>@Localizer["Question"]</label>
<p>Modifier les informations de l'utilisateur :</p>
<label>Question:</label>
<input type="text" @bind="selectedQuiz.Question"/>
<label>@Localizer["AnswerA"]</label>
<label>Rep A:</label>
<input type="text" @bind="selectedQuiz.AnswerA" />
<label>@Localizer["AnswerB"]</label>
<label>Rep B:</label>
<input type="text" @bind="selectedQuiz.AnswerB" />
<label>@Localizer["AnswerC"]</label>
<label>Rep C:</label>
<input type="text" @bind="selectedQuiz.AnswerC" />
<label>@Localizer["AnswerD"]</label>
<label>Rep D:</label>
<input type="text" @bind="selectedQuiz.AnswerD" />
<label>@Localizer["GoodAnswer"]</label>
<label>Bonne Rep:</label>
<input type="text" @bind="selectedQuiz.CAnswer" />
<button @onclick="EditQuiz">@Localizer["Save"] </button>
<button @onclick="ClosePopup">@Localizer["Delete"]</button>
<button @onclick="EditQuiz">Sauvegarder </button>
<button @onclick="ClosePopup">Annuler</button>
</div>
</div>
}
@ -61,9 +61,9 @@
{
<div class="divPopup">
<div class="contentPopup">
<p>@Localizer["PopupQuestion"]</p>
<button @onclick="RemoveQuote">@Localizer["Yes"]</button>
<button @onclick="ClosePopup">@Localizer["Cancel"]</button>
<p>Êtes-vous sûr de vouloir supprimer ce quiz ?</p>
<button @onclick="RemoveQuote">Confirmer</button>
<button @onclick="ClosePopup">Annuler</button>
</div>
</div>
}

@ -1,161 +1,133 @@
using Blazorise.DataGrid;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using System.Security.Claims;
using WF_WebAdmin.Model;
using WF_WebAdmin.Service;
namespace WF_WebAdmin.Pages
{
/// <summary>
/// Composant Blazor pour la gestion des quiz, permettant leur modification et suppression.
/// </summary>
public partial class ModifQuiz
{
/// <summary>
/// Liste des quiz à afficher dans le tableau.
/// </summary>
private Quiz[] quiz;
/// <summary>
/// Valeur maximale d'éléments par page.
/// </summary>
private int MaxValue = 5;
/// <summary>
/// Nombre total d'éléments dans la liste des quiz.
/// </summary>
private int totalItem;
/// <summary>
/// Indicateur de l'affichage de la popup de modification du quiz.
/// </summary>
private bool showEditQuiz = false;
/// <summary>
/// Quiz actuellement sélectionné pour modification.
/// </summary>
private Quiz? selectedQuiz;
/// <summary>
/// Indicateur de l'affichage de la popup de suppression.
/// </summary>
private bool showPopupDelete = false;
/// <summary>
/// Numéro de la page actuellement affichée.
/// </summary>
private int page = 1;
[Inject]
public ILogger<ModifQuiz>? Logger { get; set; }
[Inject]
public IStringLocalizer<ModifQuiz> Localizer { get; set; }
/// <summary>
/// Service pour gérer les quiz injecté.
/// </summary>
[Inject]
public IQuizService QuizService { get; set; }
/// <summary>
/// Handles the data reading event for a data grid, fetching quiz data based on the specified page and page size.
/// This method makes an asynchronous call to retrieve a specific page of quizzes and updates the `quiz` list and pagination details.
/// If the cancellation token is requested, it exits early without making further calls or updates.
/// Méthode appelée pour récupérer les données de la page actuelle dans le tableau.
/// </summary>
/// <param name="e">The event arguments containing pagination details such as page size and page number.</param>
/// <param name="e">Arguments de lecture de données pour le DataGrid.</param>
private async Task OnReadData(DataGridReadDataEventArgs<Quiz> e)
{
// Check if the cancellation token has been requested
if (e.CancellationToken.IsCancellationRequested)
{
return;
}
// Fetch the quiz data for the specified page and page size
var response = await QuizService.getSommeQuiz(e.PageSize, e.Page);
// If cancellation hasn't been requested, process the data
if (!e.CancellationToken.IsCancellationRequested)
{
// Get the total number of quizzes for pagination purposes
totalItem = await QuizService.getNbQuiz();
// Update the quiz data for the current page
quiz = response.ToArray();
// Update the current page number
page = e.Page;
}
}
/// <summary>
/// Handles the event when the "Edit" button is clicked for a quiz.
/// This method checks if a valid quiz is passed. If so, it sets the `selectedQuiz` to the clicked quiz and shows the quiz edit modal.
/// Méthode pour afficher la popup de modification d'un quiz.
/// </summary>
/// <param name="quiz">The quiz object that was clicked for editing.</param>
/// <param name="quiz">Quiz à modifier.</param>
private void OnEditButtonClicked(Quiz quiz)
{
// If the quiz is null, return early
if (quiz == null) return;
// Set the selected quiz to the one clicked by the user
selectedQuiz = quiz;
// Show the modal or UI for editing the quiz
showEditQuiz = true;
}
/// <summary>
/// Closes the open popups and resets any related states.
/// This method hides the quiz edit popup, the delete confirmation popup, and resets the selected quiz to `null`.
/// Méthode pour fermer la popup (modification ou suppression).
/// </summary>
private void ClosePopup()
{
// Hide the edit quiz popup
showEditQuiz = false;
// Hide the delete confirmation popup
showPopupDelete = false;
// Reset the selected quiz to null
selectedQuiz = null;
}
/// <summary>
/// Edits the selected quiz by updating it in the quiz service.
/// This method asynchronously sends the updated quiz data to the service for persistence.
/// After updating the quiz, it clears the selected quiz and closes any open popups.
/// Méthode pour modifier un quiz sélectionné.
/// </summary>
private async Task EditQuiz()
{
// Update the quiz in the service
LoggerSaveStub.Log(Logger, LogLevel.Information, $"Editing the question {selectedQuiz.Question}");
await QuizService.updateQuiz(selectedQuiz);
// Clear the selected quiz after successful update
selectedQuiz = null;
// Close the popups after the edit operation
ClosePopup();
if (selectedQuiz != null)
{
await QuizService.updateQuiz(selectedQuiz);
selectedQuiz = null;
ClosePopup();
}
}
/// <summary>
/// Handles the event when the delete action is triggered for a quiz.
/// This method sets the selected quiz to the one passed as a parameter and shows the delete confirmation popup.
/// Méthode pour afficher la popup de suppression d'un quiz.
/// </summary>
/// <param name="q">The quiz to be deleted.</param>
/// <param name="q">Quiz à supprimer.</param>
private void OnDelete(Quiz q)
{
// Set the selected quiz to the one passed in
selectedQuiz = q;
// Show the delete confirmation popup
showPopupDelete = true;
}
/// <summary>
/// Removes the selected quiz from the quiz service and updates the quiz list.
/// This method first checks if a quiz is selected, and if so, it deletes the quiz by calling the service.
/// After removal, it clears the `selectedQuiz`, updates the quiz list, and closes the delete confirmation popup.
/// Méthode pour supprimer un quiz sélectionné.
/// </summary>
private async Task RemoveQuote()
private async void RemoveQuote()
{
// Check if a quiz is selected for deletion
if (selectedQuiz != null)
{
// Remove the selected quiz from the service by its ID
LoggerSaveStub.Log(Logger, LogLevel.Information, $"Delete the question {selectedQuiz.Question}");
await QuizService.removeQuiz(selectedQuiz.Id);
// Clear the selected quiz after successful removal
selectedQuiz = null;
// Update the quiz list by fetching the latest data
var response = await QuizService.getSommeQuiz(MaxValue, page);
quiz = response.ToArray();
}
// Close the delete confirmation popup
showPopupDelete = false;
}
}

@ -1,9 +1,9 @@
@using WF_WebAdmin.Model
@page "/modifquote"
<PageTitle>@Localizer["TitlePage"]</PageTitle>
<PageTitle>Corection des citation</PageTitle>
<h3>@Localizer["TitlePage"]</h3>
<h3>Correction des citations</h3>
<DataGrid TItem="Quote"
Data="@quotes"
@ -13,19 +13,19 @@
ShowPager
Responsive>
<DataGridColumn TItem="Quote" Field="@nameof(Quote.Id)" Caption="@Localizer["Id"]" />
<DataGridColumn TItem="Quote" Field="@nameof(Quote.Content)" Caption="@Localizer["Quote"]" />
<DataGridColumn TItem="Quote" Field="@nameof(Quote.Charac)" Caption="@Localizer["Character"]" />
<DataGridColumn TItem="Quote" Field="@nameof(Quote.TitleSrc)" Caption="@Localizer["Source"]" />
<DataGridColumn TItem="Quote" Field="@nameof(Quote.Langue)" Caption="@Localizer["Language"]" />
<DataGridColumn TItem="Quote" Field="@nameof(Quote.DateSrc)" Caption="@Localizer["Date"]" DisplayFormat="{0:d}" DisplayFormatProvider="@System.Globalization.CultureInfo.GetCultureInfo("fr-FR")" />
<DataGridColumn TItem="Quote" Field="@nameof(Quote.Id)" Caption="@Localizer["Action"]">
<DataGridColumn TItem="Quote" Field="@nameof(Quote.Id)" Caption="Id"/>
<DataGridColumn TItem="Quote" Field="@nameof(Quote.Content)" Caption="Citation"/>
<DataGridColumn TItem="Quote" Field="@nameof(Quote.Charac)" Caption="Personage"/>
<DataGridColumn TItem="Quote" Field="@nameof(Quote.TitleSrc)" Caption="Source" />
<DataGridColumn TItem="Quote" Field="@nameof(Quote.Langue)" Caption="Langue" />
<DataGridColumn TItem="Quote" Field="@nameof(Quote.DateSrc)" Caption="Date" DisplayFormat="{0:d}" DisplayFormatProvider="@System.Globalization.CultureInfo.GetCultureInfo("fr-FR")" />
<DataGridColumn TItem="Quote" Field="@nameof(Quote.Id)" Caption="Action">
<DisplayTemplate>
@* <button @onclick="() => OnEditButtonClicked(context) " style="background-color: lightgray; padding: 0">
<img alt="Bouton Modifier" src="edit.png" width="30" height="30"/>
</button> *@
<a href="Edit/@(context.Id)" class="btn btn-primary"><i class="fa fa-edit"></i> @Localizer["Edit"]</a>
<button type="button" class="btn btn-primary" @onclick="() => OnDelete(context)"><i class="fa fa-trash"></i> @Localizer["Delete"]</button>
<a href="Edit/@(context.Id)" class="btn btn-primary"><i class="fa fa-edit"></i> Editer</a>
<button type="button" class="btn btn-primary" @onclick="() => OnDelete(context)"><i class="fa fa-trash"></i> Supprimer</button>
</DisplayTemplate>
</DataGridColumn>
</DataGrid>
@ -50,9 +50,9 @@
{
<div class="divPopup">
<div class="contentPopup">
<p>@Localizer["PopupQuestion"]</p>
<button @onclick="RemoveQuote">@Localizer["Yes"]</button>
<button @onclick="ClosePopup">@Localizer["Cancel"]</button>
<p>Êtes-vous sûr de vouloir supprimer cette citation ?</p>
<button @onclick="RemoveQuote">Confirmer</button>
<button @onclick="ClosePopup">Annuler</button>
</div>
</div>
}

@ -1,135 +1,104 @@
using Blazorise.DataGrid;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using System.Security.Claims;
using WF_WebAdmin.Model;
using WF_WebAdmin.Service;
namespace WF_WebAdmin.Pages
{
/// <summary>
/// Composant Blazor pour la gestion des citations, permettant la modification et la suppression de celles-ci.
/// </summary>
public partial class ModifQuote
{
/// <summary>
/// Liste des citations à afficher dans le tableau.
/// </summary>
private Quote[] quotes;
/// <summary>
/// Valeur maximale d'éléments par page.
/// </summary>
private int MaxValue = 5;
/// <summary>
/// Nombre total d'éléments dans la liste des citations.
/// </summary>
private int totalItem;
/*private bool showEditQuote = false;*/
/// <summary>
/// Citation actuellement sélectionnée pour modification.
/// </summary>
private Quote? selectedQuote;
/// <summary>
/// Indicateur de l'affichage de la popup de suppression.
/// </summary>
private bool showPopupDelete = false;
/// <summary>
/// Numéro de la page actuellement affichée.
/// </summary>
private int page = 1;
[Inject]
public ILogger<ModifQuote>? Logger { get; set; }
[Inject]
public IStringLocalizer<ModifQuote> Localizer { get; set; }
/// <summary>
/// Service pour gérer les citations injecté.
/// </summary>
[Inject]
public IQuoteService QuoteService { get; set; }
/// <summary>
/// Handles the data reading event for a data grid, fetching quote data based on the specified page and page size.
/// This method makes an asynchronous call to retrieve a specific page of quotes and updates the `quotes` list and pagination details.
/// If the cancellation token is requested, it exits early without making further calls or updates.
/// Méthode appelée pour récupérer les données de la page actuelle dans le tableau.
/// </summary>
/// <param name="e">The event arguments containing pagination details such as page size and page number.</param>
/// <param name="e">Arguments de lecture de données pour le DataGrid.</param>
private async Task OnReadData(DataGridReadDataEventArgs<Quote> e)
{
// Check if the cancellation token has been requested
if (e.CancellationToken.IsCancellationRequested)
{
return;
}
// Fetch the quote data for the specified page and page size
var response = await QuoteService.getSomeQuote(e.PageSize, e.Page);
// If cancellation hasn't been requested, process the data
if (!e.CancellationToken.IsCancellationRequested)
{
// Get the total number of quotes for pagination purposes
totalItem = await QuoteService.getNbQuote();
// Update the quotes data for the current page
quotes = response.ToArray();
// Update the current page number
page = e.Page;
}
}
/*private void OnEditButtonClicked(Quote quote)
{
if (selectedQuote == null) return;
selectedQuote = quote;
showEditQuote = true;
}*/
/// <summary>
/// Closes the open popups and resets any related states.
/// This method hides the delete confirmation popup and clears the selected quote.
/// Méthode pour fermer la popup (modification ou suppression).
/// </summary>
private void ClosePopup()
{
// Hide the delete confirmation popup
showPopupDelete = false;
// Reset the selected quote to null
selectedQuote = null;
}
/*private async Task EditQuote()
{
await QuoteService.updateQuote(selectedQuote);
selectedQuote = null;
ClosePopup();
}*/
/// <summary>
/// Handles the event when the delete action is triggered for a quote.
/// This method sets the selected quote to the one passed as a parameter and displays the delete confirmation popup.
/// Méthode appelée pour afficher la popup de suppression d'une citation.
/// </summary>
/// <param name="q">The quote that is being deleted.</param>
/// <param name="q">Citation à supprimer.</param>
private void OnDelete(Quote q)
{
// Set the selected quote to the one passed in
selectedQuote = q;
// Display the delete confirmation popup
showPopupDelete = true;
}
/// <summary>
/// Removes the selected quote by calling the remove service and updates the quote list.
/// This method checks if a quote is selected. If so, it removes the quote using the `QuoteService`, clears the selected quote,
/// and fetches the updated list of quotes. It also closes the delete confirmation popup after the operation.
/// Méthode pour supprimer une citation sélectionnée.
/// </summary>
private async Task RemoveQuote()
private async void RemoveQuote()
{
// Check if a quote is selected for removal
if (selectedQuote != null)
{
// Remove the selected quote using the QuoteService
LoggerSaveStub.Log(Logger, LogLevel.Information, $"The quote {selectedQuote.Content} has been deleted");
await QuoteService.removeQuote(selectedQuote);
// Clear the selected quote after removal
selectedQuote = null;
// Update the quotes list by fetching the latest quotes data
selectedQuote= null;
var response = await QuoteService.getSomeQuote(MaxValue, page);
quotes = response.ToArray();
}
// Close the delete confirmation popup
showPopupDelete = false;
showPopupDelete= false;
}
}
}

@ -2,28 +2,28 @@
@using System.Dynamic
@using WF_WebAdmin.Model
<h3>@Localizer["TitleQuiz"]</h3>
<h3> Quiz à valider </h3>
@if (quizzes == null)
{
<p> @Localizer["LoadQuiz"] </p>
<p> Chargement des quiz ... </p>
}
else
{
<p>@Localizer["QuizAwait"] </p>
<p> Quizs en attente de validation : </p>
<table>
<thead>
<tr>
<th>#</th>
<th>@Localizer["Question"]</th>
<th>@Localizer["AnswerA"]</th>
<th>@Localizer["AnswerB"]</th>
<th>@Localizer["AnswerC"]</th>
<th>@Localizer["AnswerD"]</th>
<th>@Localizer["GoodAnswer"]</th>
<th>@Localizer["User"]</th>
<th>@Localizer["Action"]</th>
<th>Question</th>
<th>Réponse A</th>
<th>Réponse B</th>
<th>Réponse C</th>
<th>Réponse D</th>
<th>Réponse Correcte</th>
<th>Utilisateur</th>
<th>Actions</th>
</tr>
</thead>
<tbody>

@ -1,99 +1,87 @@
using Blazorise.DataGrid;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using System.Security.Claims;
using WF_WebAdmin.Model;
using WF_WebAdmin.Service;
namespace WF_WebAdmin.Pages
{
/// <summary>
/// Composant Blazor pour gérer la validation des quiz.
/// </summary>
public partial class ValidQuiz
{
/// <summary>
/// Liste des quiz à valider.
/// </summary>
private List<Quiz> quizzes;
[Inject]
public ILogger<ValidQuiz>? Logger { get; set; }
[Inject]
public IStringLocalizer<ValidQuiz> Localizer { get; set; }
/// <summary>
/// Client HTTP injecté pour effectuer des requêtes API.
/// </summary>
[Inject]
public HttpClient Http { get; set; }
/// <summary>
/// Gestionnaire de navigation injecté pour gérer les URL.
/// </summary>
[Inject]
public NavigationManager NavigationManager { get; set; }
/// <summary>
/// Service pour gérer les quiz injecté.
/// </summary>
[Inject]
public IQuizService QuizService { get; set; }
/// <summary>
/// Initializes the component asynchronously by fetching the quizzes that need validation.
/// This method retrieves a list of quizzes from the `QuizService` that are pending validation when the component is initialized.
/// Méthode appelée lors de l'initialisation du composant. Charge la liste des quiz à valider.
/// </summary>
protected override async Task OnInitializedAsync()
{
// Fetch quizzes that need validation
quizzes = await QuizService.getQuizzesToValidate();
}
/// <summary>
/// Handles the event when the "Validate" button is clicked for a quiz.
/// This method calls the `ValidateQuiz` method, passing the specified quiz for validation.
/// Méthode appelée lorsqu'on clique sur le bouton de validation d'un quiz.
/// </summary>
/// <param name="quiz">The quiz that is being validated.</param>
/// <param name="quiz">Le quiz à valider.</param>
private void OnValidButton(Quiz quiz)
{
// Call the ValidateQuiz method to validate the quiz
ValidateQuiz(quiz);
}
/// <summary>
/// Validates the specified quiz by setting its `IsValid` property to true and updating its state in the service.
/// This method logs a message to the console indicating the quiz has been validated, then updates the quiz's validation status.
/// It then calls the `QuizService.updateQuiz` method to persist the changes.
/// Valide un quiz en mettant à jour son état.
/// </summary>
/// <param name="quiz">The quiz that is being validated.</param>
/// <param name="quiz">Le quiz à valider.</param>
private void ValidateQuiz(Quiz quiz)
{
// Log the validation action to the console
LoggerSaveStub.Log(Logger, LogLevel.Information, $"Quiz {quiz.Id} validated!");
Console.WriteLine($"Quiz {quiz.Id} validated!");
// Create a new quiz instance (or modify the existing one)
Quiz newQuiz = quiz;
newQuiz.IsValid = true;
// Update the quiz state in the QuizService
// Mis à jour de l'état du quiz
QuizService.updateQuiz(quiz);
}
/// <summary>
/// Handles the event when the "Reject" button is clicked for a quiz.
/// This method calls the `RejectQuiz` method, passing the specified quiz to be rejected.
/// Méthode appelée lorsqu'on clique sur le bouton de rejet d'un quiz.
/// </summary>
/// <param name="quiz">The quiz that is being rejected.</param>
/// <param name="quiz">Le quiz à rejeter.</param>
private void OnRejectButton(Quiz quiz)
{
// Call the RejectQuiz method to reject the quiz
RejectQuiz(quiz);
}
/// <summary>
/// Rejects the specified quiz by logging a rejection message and removing it from the QuizService.
/// This method logs a message to the console indicating the quiz has been rejected, and then calls the `QuizService.removeQuiz`
/// method to remove the quiz from the system.
/// Rejette un quiz en supprimant son état de validation.
/// </summary>
/// <param name="quiz">The quiz that is being rejected.</param>
/// <param name="quiz">Le quiz à rejeter.</param>
private void RejectQuiz(Quiz quiz)
{
// Log the rejection action to the console
LoggerSaveStub.Log(Logger, LogLevel.Information, $"Quiz {quiz.Id} rejected");
Console.WriteLine($"Quiz {quiz.Id} rejected!");
// Remove the rejected quiz from the QuizService
QuizService.removeQuiz(quiz.Id);
}
}

@ -1,11 +1,11 @@
@page "/ValidQuote"
@using WF_WebAdmin.Model
<h3>@Localizer["TitleValid"]</h3>
<h3>Citations non validées</h3>
@if (quotes is null)
{
<p>@Localizer["LoginQuote"]</p>
<p>Chargement des citations...</p>
}
@* else if (quotes.Count == 0)
{
@ -13,20 +13,20 @@
} *@
else
{
<p>@Localizer["QuoteValid"]</p>
<p>Citations en attente de validation :</p>
@foreach (var quote in quotes)
{
<div class="QuoteDiv">
<p><strong>@Localizer["Id"]</strong> @quote.Id</p>
<p><strong>@Localizer["Content"]</strong> @quote.Content</p>
<p><strong>@Localizer["Language"]</strong> @quote.Langue</p>
<p><strong>ID :</strong> @quote.Id</p>
<p><strong>Contenu :</strong> @quote.Content</p>
<p><strong>Langue :</strong> @quote.Langue</p>
<p><strong>@Localizer["Character"]</strong> @quote.Charac</p>
<p><strong>@Localizer["Image"]</strong> @quote.ImgPath</p>
<p><strong>@Localizer["Source"]</strong> @quote.TitleSrc</p>
<p><strong>@Localizer["Date"]</strong> @quote.DateSrc.ToShortDateString()</p>
<p><strong>@Localizer["User"]</strong> @quote.UserProposition</p>
<p><strong>Personnage :</strong> @quote.Charac</p>
<p><strong>Image :</strong> @quote.ImgPath</p>
<p><strong>Source :</strong> @quote.TitleSrc</p>
<p><strong>Date de source :</strong> @quote.DateSrc.ToShortDateString()</p>
<p><strong>Utilisateur :</strong> @quote.UserProposition</p>
@* <button @onclick="() => ValiderQuote(quote.Id)">Valider</button>
<button @onclick="() => RejeterQuote(quote.Id)">Rejeter</button> *@

@ -6,31 +6,36 @@ using System.Collections.Generic;
using System;
using System.Threading.Tasks;
using System.Linq;
using Microsoft.Extensions.Localization;
namespace WF_WebAdmin.Pages
{
/// <summary>
/// Composant Blazor pour afficher et valider des citations.
/// </summary>
public partial class ValidQuote
{
/// <summary>
/// Tableau contenant les citations à valider.
/// </summary>
private Quote[] quotes;
[Inject]
public IStringLocalizer<ValidQuote> Localizer { get; set; }
/// <summary>
/// Client HTTP injecté pour effectuer des requêtes API.
/// </summary>
[Inject]
public HttpClient Http { get; set; }
/// <summary>
/// Gestionnaire de navigation injecté pour gérer les URL.
/// </summary>
[Inject]
public NavigationManager NavigationManager { get; set; }
/// <summary>
/// Initializes the component asynchronously by fetching a list of quotes from a JSON file.
/// This method makes an asynchronous HTTP request to retrieve an array of `Quote` objects from a specified JSON file
/// located at the base URI, and then assigns the result to the `quotes` variable.
/// Méthode appelée à l'initialisation du composant pour charger les citations.
/// </summary>
protected override async Task OnInitializedAsync()
{
// Fetch the list of quotes from the JSON file located at the base URI
quotes = await Http.GetFromJsonAsync<Quote[]>($"{NavigationManager.BaseUri}fake-dataQuote.json");
}
}

@ -1,13 +1,4 @@
@*
File: _Host.cshtml
Project: WF_WebAdmin
Description: ...
Author: What The Fantasy
Created: 10/02/2025
Last Modified: 10/02/2025
*@
@page "/"
@page "/"
@namespace WF_WebAdmin.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
@ -15,7 +6,3 @@
}
<component type="typeof(App)" render-mode="ServerPrerendered" />
<body>
<script src="https://cdn.syncfusion.com/blazor/22.1.38/syncfusion-blazor.min.js" type="text/javascript"></script>
</body>

@ -1,20 +1,10 @@
@*
File: _Layout.cshtml
Project: WF_WebAdmin
Description: ...
Author: What The Fantasy
Created: 10/02/2025
Last Modified: 10/02/2025
*@
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web
@namespace WF_WebAdmin.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<!DOCTYPE html>
<html lang="en">
<head>
<title>layout</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="~/" />
@ -34,7 +24,7 @@
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">reload</a>
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>

@ -1,6 +1,8 @@
using Blazorise;
using Blazorise.Bootstrap;
using Blazorise.Icons.FontAwesome;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Localization;
using System.Globalization;
using WF_WebAdmin.Data;
@ -9,24 +11,21 @@ using WF_WebAdmin.Model;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Blazored.Modal;
using MudBlazor.Services;
using WF_WebAdmin.Service;
[assembly: RootNamespace("WF_WebAdmin")]
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
builder.Services.AddScoped<IQuoteService,QuoteServiceStub>();
builder.Services.AddScoped<IQuizService,QuizServiceStub>();
builder.Services.AddScoped<IUserService, UserServiceStub>();
builder.Services.AddScoped<ICommentaryService, CommentaryServiceStub>();
builder.Services.AddHttpClient();
builder.Services.AddScoped<UserLogin>();
builder.Services.AddMudServices();
builder.Logging.AddConfiguration(builder.Configuration.GetSection("Logging"));
builder.Services
.AddBlazorise()

@ -1,144 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AnswerA" xml:space="preserve">
<value>Answer A:</value>
</data>
<data name="AnswerB" xml:space="preserve">
<value>Answer B:</value>
</data>
<data name="AnswerC" xml:space="preserve">
<value>Answer C:</value>
</data>
<data name="AnswerD" xml:space="preserve">
<value>Answer D:</value>
</data>
<data name="GoodAnswer" xml:space="preserve">
<value>Good answer:</value>
</data>
<data name="Submit" xml:space="preserve">
<value>Submit</value>
</data>
<data name="TitleAddQuiz" xml:space="preserve">
<value>Add a question</value>
</data>
<data name="TitleQuestion" xml:space="preserve">
<value>Question:</value>
</data>
</root>

@ -1,144 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AnswerA" xml:space="preserve">
<value>Réponse A:</value>
</data>
<data name="AnswerB" xml:space="preserve">
<value>Réponse B:</value>
</data>
<data name="AnswerC" xml:space="preserve">
<value>Réponse C:</value>
</data>
<data name="AnswerD" xml:space="preserve">
<value>Réponse D:</value>
</data>
<data name="GoodAnswer" xml:space="preserve">
<value>Bonne réponse:</value>
</data>
<data name="Submit" xml:space="preserve">
<value>Valider</value>
</data>
<data name="TitleAddQuiz" xml:space="preserve">
<value>Ajouter une Question</value>
</data>
<data name="TitleQuestion" xml:space="preserve">
<value>Question:</value>
</data>
</root>

@ -1,135 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Log" xml:space="preserve">
<value>Current Logs</value>
</data>
<data name="LogContent" xml:space="preserve">
<value>Content</value>
</data>
<data name="LogLvl" xml:space="preserve">
<value>Type of Logs :</value>
</data>
<data name="LogTitle" xml:space="preserve">
<value>Logs</value>
</data>
<data name="NotLog" xml:space="preserve">
<value>No Log</value>
</data>
</root>

@ -1,135 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Log" xml:space="preserve">
<value>Logs actuels</value>
</data>
<data name="LogContent" xml:space="preserve">
<value>Contenu</value>
</data>
<data name="LogLvl" xml:space="preserve">
<value>Type de Logs :</value>
</data>
<data name="LogTitle" xml:space="preserve">
<value>Logs</value>
</data>
<data name="NotLog" xml:space="preserve">
<value>Aucun Log</value>
</data>
</root>

@ -1,171 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Action" xml:space="preserve">
<value>Action</value>
</data>
<data name="Add" xml:space="preserve">
<value>Add</value>
</data>
<data name="AnswerA" xml:space="preserve">
<value>Answer A</value>
</data>
<data name="AnswerB" xml:space="preserve">
<value>Answer B</value>
</data>
<data name="AnswerC" xml:space="preserve">
<value>Answer C</value>
</data>
<data name="AnswerD" xml:space="preserve">
<value>Answer D</value>
</data>
<data name="Cancel" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="Delete" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="Edit" xml:space="preserve">
<value>Edit</value>
</data>
<data name="GoodAnswer" xml:space="preserve">
<value>Good Answer</value>
</data>
<data name="Id" xml:space="preserve">
<value>ID</value>
</data>
<data name="ModifInfoUser" xml:space="preserve">
<value>Edit user information :</value>
</data>
<data name="PopupQuestion" xml:space="preserve">
<value>Are you sure you want to delete this quiz ?</value>
</data>
<data name="Question" xml:space="preserve">
<value>Question</value>
</data>
<data name="Save" xml:space="preserve">
<value>Save</value>
</data>
<data name="TitlePage" xml:space="preserve">
<value>Quiz Management</value>
</data>
<data name="Yes" xml:space="preserve">
<value>Confirm</value>
</data>
</root>

@ -1,171 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Action" xml:space="preserve">
<value>Action</value>
</data>
<data name="Add" xml:space="preserve">
<value>Ajouter</value>
</data>
<data name="AnswerA" xml:space="preserve">
<value>Réponse A</value>
</data>
<data name="AnswerB" xml:space="preserve">
<value>Réponse B</value>
</data>
<data name="AnswerC" xml:space="preserve">
<value>Réponse C</value>
</data>
<data name="AnswerD" xml:space="preserve">
<value>Réponse D</value>
</data>
<data name="Cancel" xml:space="preserve">
<value>Annuler</value>
</data>
<data name="Delete" xml:space="preserve">
<value>Supprimer</value>
</data>
<data name="Edit" xml:space="preserve">
<value>Editer</value>
</data>
<data name="GoodAnswer" xml:space="preserve">
<value>Bonne réponse</value>
</data>
<data name="Id" xml:space="preserve">
<value>ID</value>
</data>
<data name="ModifInfoUser" xml:space="preserve">
<value>Modifier les informations de l'utilisateur :</value>
</data>
<data name="PopupQuestion" xml:space="preserve">
<value>Êtes-vous sûr de vouloir supprimer ce quiz ?</value>
</data>
<data name="Question" xml:space="preserve">
<value>Question</value>
</data>
<data name="Save" xml:space="preserve">
<value>Sauvegarder</value>
</data>
<data name="TitlePage" xml:space="preserve">
<value>Gestion des quiz</value>
</data>
<data name="Yes" xml:space="preserve">
<value>Confirmer</value>
</data>
</root>

@ -1,159 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Action" xml:space="preserve">
<value>Action</value>
</data>
<data name="Cancel" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="Character" xml:space="preserve">
<value>Character</value>
</data>
<data name="Date" xml:space="preserve">
<value>Date</value>
</data>
<data name="Delete" xml:space="preserve">
<value>Delete</value>
</data>
<data name="Edit" xml:space="preserve">
<value>Edit</value>
</data>
<data name="Id" xml:space="preserve">
<value>Id</value>
</data>
<data name="Language" xml:space="preserve">
<value>Language</value>
</data>
<data name="PopupQuestion" xml:space="preserve">
<value>Are you sure you want to delete this quote ?</value>
</data>
<data name="Quote" xml:space="preserve">
<value>Quote</value>
</data>
<data name="Source" xml:space="preserve">
<value>Source</value>
</data>
<data name="TitlePage" xml:space="preserve">
<value>Corrections of quotes</value>
</data>
<data name="Yes" xml:space="preserve">
<value>Confirm</value>
</data>
</root>

@ -1,159 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Action" xml:space="preserve">
<value>Action</value>
</data>
<data name="Cancel" xml:space="preserve">
<value>Annuler</value>
</data>
<data name="Character" xml:space="preserve">
<value>Personage</value>
</data>
<data name="Date" xml:space="preserve">
<value>Date</value>
</data>
<data name="Delete" xml:space="preserve">
<value>Supprimer</value>
</data>
<data name="Edit" xml:space="preserve">
<value>Editer</value>
</data>
<data name="Id" xml:space="preserve">
<value>Id</value>
</data>
<data name="Language" xml:space="preserve">
<value>Langue</value>
</data>
<data name="PopupQuestion" xml:space="preserve">
<value>Êtes-vous sûr de vouloir supprimer cette citation ?</value>
</data>
<data name="Quote" xml:space="preserve">
<value>Citation</value>
</data>
<data name="Source" xml:space="preserve">
<value>Source</value>
</data>
<data name="TitlePage" xml:space="preserve">
<value>Correction des citations</value>
</data>
<data name="Yes" xml:space="preserve">
<value>Confirmer</value>
</data>
</root>

@ -1,153 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Action" xml:space="preserve">
<value>Actions</value>
</data>
<data name="AnswerA" xml:space="preserve">
<value>Answer A</value>
</data>
<data name="AnswerB" xml:space="preserve">
<value>Answer B</value>
</data>
<data name="AnswerC" xml:space="preserve">
<value>Answer C</value>
</data>
<data name="AnswerD" xml:space="preserve">
<value>Answer D</value>
</data>
<data name="GoodAnswer" xml:space="preserve">
<value>Correct answer</value>
</data>
<data name="LoadQuiz" xml:space="preserve">
<value>Loading quizzes</value>
</data>
<data name="Question" xml:space="preserve">
<value>Question</value>
</data>
<data name="QuizAwait" xml:space="preserve">
<value>Quiz awaiting validation</value>
</data>
<data name="TitleQuiz" xml:space="preserve">
<value>Quiz to validate</value>
</data>
<data name="User" xml:space="preserve">
<value>User</value>
</data>
</root>

@ -1,153 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Action" xml:space="preserve">
<value>Actions</value>
</data>
<data name="AnswerA" xml:space="preserve">
<value>Réponse A </value>
</data>
<data name="AnswerB" xml:space="preserve">
<value>Réponse B</value>
</data>
<data name="AnswerC" xml:space="preserve">
<value>Réponse C</value>
</data>
<data name="AnswerD" xml:space="preserve">
<value>Réponse D</value>
</data>
<data name="GoodAnswer" xml:space="preserve">
<value>Réponse Correcte</value>
</data>
<data name="LoadQuiz" xml:space="preserve">
<value>Chargement des quiz ...</value>
</data>
<data name="Question" xml:space="preserve">
<value>Question</value>
</data>
<data name="QuizAwait" xml:space="preserve">
<value>Quizs en attente de validation :</value>
</data>
<data name="TitleQuiz" xml:space="preserve">
<value>Quiz à valider</value>
</data>
<data name="User" xml:space="preserve">
<value>Utilisateur</value>
</data>
</root>

@ -1,153 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Character" xml:space="preserve">
<value>Character :</value>
</data>
<data name="Content" xml:space="preserve">
<value>Content :</value>
</data>
<data name="Date" xml:space="preserve">
<value>Source date</value>
</data>
<data name="Id" xml:space="preserve">
<value>ID :</value>
</data>
<data name="Image" xml:space="preserve">
<value>Image :</value>
</data>
<data name="Language" xml:space="preserve">
<value>Language :</value>
</data>
<data name="LoginQuote" xml:space="preserve">
<value>Loading quotes</value>
</data>
<data name="QuoteValid" xml:space="preserve">
<value>Quotes awaiting validation</value>
</data>
<data name="Source" xml:space="preserve">
<value>Source :</value>
</data>
<data name="TitleValid" xml:space="preserve">
<value>Unvalidated quotes</value>
</data>
<data name="User" xml:space="preserve">
<value>User :</value>
</data>
</root>

@ -1,153 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Character" xml:space="preserve">
<value>Personnage :</value>
</data>
<data name="Content" xml:space="preserve">
<value>Contenu :</value>
</data>
<data name="Date" xml:space="preserve">
<value>Date de la source :</value>
</data>
<data name="Id" xml:space="preserve">
<value>ID :</value>
</data>
<data name="Image" xml:space="preserve">
<value>Image :</value>
</data>
<data name="Language" xml:space="preserve">
<value>Langue :</value>
</data>
<data name="LoginQuote" xml:space="preserve">
<value>Chargement des citations...</value>
</data>
<data name="QuoteValid" xml:space="preserve">
<value>Citations en attente de validation :</value>
</data>
<data name="Source" xml:space="preserve">
<value>Source :</value>
</data>
<data name="TitleValid" xml:space="preserve">
<value>Citations non validées</value>
</data>
<data name="User" xml:space="preserve">
<value>Utilisateur :</value>
</data>
</root>

@ -1,32 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
using WF_WebAdmin.Converter;
using WF_WebAdmin.Model;
namespace WF_WebAdmin.Service
{
public class CommentaryServiceStub : ICommentaryService
{
private readonly string? _jsonFilePath = Path.Combine(Environment.CurrentDirectory, "wwwroot", "fake-dataCommentary.json");
public async Task<List<Commentary>> GetCommentsAsync()
{
if (!File.Exists(_jsonFilePath))
{
Console.Out.WriteLine($"{_jsonFilePath} not found");
return new List<Commentary>();
}
var json = await File.ReadAllTextAsync(_jsonFilePath);
var dtoList = JsonSerializer.Deserialize<List<CommentaryDto>>(json) ?? new List<CommentaryDto>();
var comments = dtoList.ConvertAll(dto => dto.ToModel());
Console.Out.WriteLine($"Nombre de commentaires chargés : {comments.Count}");
return comments;
}
}
}

@ -1,11 +0,0 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using WF_WebAdmin.Model;
namespace WF_WebAdmin.Service
{
public interface ICommentaryService
{
Task<List<Commentary>> GetCommentsAsync();
}
}

@ -1,17 +0,0 @@
using WF_WebAdmin.Model;
namespace WF_WebAdmin.Service
{
public interface ILogsService
{
public Task removeLogs(Logs logs);
public Task<List<Logs>> getAllLogs();
public Task<List<Logs>> getSomeLogs(int nb, int page);
public Task addLogs(Logs logs);
public Task<int> getNbLogs();
}
}

@ -2,25 +2,66 @@ using WF_WebAdmin.Model;
namespace WF_WebAdmin.Service
{
/// <summary>
/// Interface définissant les opérations de gestion des quiz.
/// </summary>
public interface IQuizService
{
/// <summary>
/// Ajoute un quiz.
/// </summary>
/// <param name="quiz">Quiz à ajouter.</param>
public Task addQuiz(Quiz quiz);
/// <summary>
/// Met à jour un quiz existant.
/// </summary>
/// <param name="quiz">Quiz à mettre à jour.</param>
public Task updateQuiz(Quiz quiz);
/// <summary>
/// Supprime un quiz par son identifiant.
/// </summary>
/// <param name="id">Identifiant du quiz à supprimer.</param>
public Task removeQuiz(int id);
/// <summary>
/// Valide un quiz par son identifiant.
/// </summary>
/// <param name="id">Identifiant du quiz à valider.</param>
public Task validateQuiz(int id);
/// <summary>
/// Récupère la liste de tous les quiz.
/// </summary>
/// <returns>Liste de tous les quiz.</returns>
public Task<List<Quiz>> getQuizzes();
/// <summary>
/// Récupère la liste des quiz en attente de validation.
/// </summary>
/// <returns>Liste des quiz non validés.</returns>
public Task<List<Quiz>> getQuizzesToValidate();
/// <summary>
/// Récupère un quiz spécifique par son identifiant.
/// </summary>
/// <param name="id">Identifiant du quiz.</param>
/// <returns>Le quiz correspondant ou null s'il n'existe pas.</returns>
public Task<Quiz> getQuiz(int id);
/// <summary>
/// Récupère une liste paginée de quiz.
/// </summary>
/// <param name="nb">Nombre de quiz par page.</param>
/// <param name="page">Numéro de la page.</param>
/// <returns>Liste des quiz correspondant à la pagination.</returns>
public Task<List<Quiz>> getSommeQuiz(int nb, int page);
/// <summary>
/// Récupère le nombre total de quiz enregistrés.
/// </summary>
/// <returns>Nombre total de quiz.</returns>
public Task<int> getNbQuiz();
}
}

@ -2,32 +2,94 @@
namespace WF_WebAdmin.Service
{
/// <summary>
/// Interface définissant les opérations de gestion des citations.
/// </summary>
public interface IQuoteService
{
/// <summary>
/// Ajoute une citation.
/// </summary>
/// <param name="quote">Citation à ajouter.</param>
public Task addQuote(Quote quote);
/// <summary>
/// Supprime une citation.
/// </summary>
/// <param name="quote">Citation à supprimer.</param>
public Task removeQuote(Quote quote);
public Task validQuote(Quote? quote);
/// <summary>
/// Valide une citation.
/// </summary>
/// <param name="quote">Citation à valider.</param>
public Task validQuote(Quote quote);
public Task updateQuote(Quote? quote);
/// <summary>
/// Met à jour une citation existante.
/// </summary>
/// <param name="quote">Citation à mettre à jour.</param>
public Task updateQuote(Quote quote);
/// <summary>
/// Récupère toutes les citations.
/// </summary>
/// <returns>Liste de toutes les citations.</returns>
public Task<List<Quote>> getAllQuote();
/// <summary>
/// Récupère une liste paginée de citations.
/// </summary>
/// <param name="nb">Nombre de citations par page.</param>
/// <param name="page">Numéro de la page.</param>
/// <returns>Liste des citations correspondant à la pagination.</returns>
public Task<List<Quote>> getSomeQuote(int nb, int page);
public Task<Quote?> getOnequote(int id);
/// <summary>
/// Récupère une citation spécifique par son identifiant.
/// </summary>
/// <param name="id">Identifiant de la citation.</param>
/// <returns>La citation correspondante ou null si elle n'existe pas.</returns>
public Task<Quote> getOnequote(int id);
/// <summary>
/// Recherche des citations en fonction d'un critère.
/// </summary>
/// <param name="reserch">Terme de recherche.</param>
/// <param name="argument">Liste des arguments pour affiner la recherche.</param>
/// <returns>Liste des citations correspondant aux critères.</returns>
public Task<List<Quote>> reserchQuote(string reserch, List<string> argument);
/// <summary>
/// Récupère toutes les citations non validées.
/// </summary>
/// <returns>Liste des citations non validées.</returns>
public Task<List<Quote>> getAllQuoteInvalid();
/// <summary>
/// Récupère une liste paginée de citations non validées.
/// </summary>
/// <param name="nb">Nombre de citations par page.</param>
/// <param name="page">Numéro de la page.</param>
/// <returns>Liste des citations non validées correspondant à la pagination.</returns>
public Task<List<Quote>> getSomeQuoteInvalid(int nb, int page);
/// <summary>
/// Récupère le nombre total de citations enregistrées.
/// </summary>
/// <returns>Nombre total de citations.</returns>
public Task<int> getNbQuote();
/// <summary>
/// Récupère la liste des personnages associés aux citations.
/// </summary>
/// <returns>Liste des personnages.</returns>
public Task<List<Character>> getChar();
/// <summary>
/// Récupère la liste des sources associées aux citations.
/// </summary>
/// <returns>Liste des sources.</returns>
public Task<List<Source>> getSrc();
}
}

@ -2,24 +2,68 @@
namespace WF_WebAdmin.Service
{
/// <summary>
/// Interface définissant les opérations de gestion des utilisateurs.
/// </summary>
public interface IUserService
{
/// <summary>
/// Supprime un utilisateur du système.
/// </summary>
/// <param name="user">Utilisateur à supprimer.</param>
public Task removeUser(User user);
public Task updateRole(User? user);
/// <summary>
/// Met à jour le rôle d'un utilisateur.
/// </summary>
/// <param name="user">Utilisateur dont le rôle doit être mis à jour.</param>
public Task updateRole(User user);
public Task downgradeRole(User? user);
/// <summary>
/// Rétrograde le rôle d'un utilisateur.
/// </summary>
/// <param name="user">Utilisateur à rétrograder.</param>
public Task downgradeRole(User user);
public Task updateUser(User? user);
/// <summary>
/// Met à jour les informations d'un utilisateur.
/// </summary>
/// <param name="user">Utilisateur à mettre à jour.</param>
public Task updateUser(User user);
/// <summary>
/// Récupère la liste complète des utilisateurs.
/// </summary>
/// <returns>Liste des utilisateurs.</returns>
public Task<List<User>> getAllUser();
public Task<List<User>?> getSomeUser(int nb, int page);
/// <summary>
/// Récupère une liste paginée d'utilisateurs.
/// </summary>
/// <param name="nb">Nombre d'utilisateurs par page.</param>
/// <param name="page">Numéro de la page.</param>
/// <returns>Liste des utilisateurs correspondant à la pagination.</returns>
public Task<List<User>> getSomeUser(int nb, int page);
/// <summary>
/// Récupère un utilisateur spécifique par son identifiant.
/// </summary>
/// <param name="id">Identifiant de l'utilisateur.</param>
/// <returns>L'utilisateur correspondant ou null s'il n'existe pas.</returns>
public Task<User> getOneUser(int id);
/// <summary>
/// Recherche des utilisateurs en fonction d'un critère.
/// </summary>
/// <param name="reserch">Terme de recherche.</param>
/// <param name="args">Liste des arguments pour affiner la recherche.</param>
/// <returns>Liste des utilisateurs correspondant aux critères.</returns>
public Task<List<User>> reserchUsers(string reserch, List<string> args);
/// <summary>
/// Récupère le nombre total d'utilisateurs enregistrés.
/// </summary>
/// <returns>Nombre total d'utilisateurs.</returns>
public Task<int> getNbUser();
}
}

@ -1,67 +0,0 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Text.Json;
using WF_WebAdmin.Model;
namespace WF_WebAdmin.Service
{
public class LogsServiceStub : ILogsService
{
private readonly string _jsonFilePath = Path.Combine(Environment.CurrentDirectory, "wwwroot", "fake_data_logs.json");
public async Task saveLogsJson(List<Logs> logs)
{
var json = JsonSerializer.Serialize(logs, new JsonSerializerOptions { WriteIndented = true });
await File.WriteAllTextAsync(_jsonFilePath, json);
}
public async Task addLogs(Logs logs)
{
var data = await getAllLogs();
data.Add(logs);
await saveLogsJson(data);
}
public async Task<List<Logs>> getAllLogs()
{
if (!File.Exists(_jsonFilePath))
{
Console.Out.WriteLine($"{_jsonFilePath} not found");
return new List<Logs>();
}
var json = await File.ReadAllTextAsync(_jsonFilePath);
return JsonSerializer.Deserialize<List<Logs>>(json) ?? new List<Logs>();
}
public Task<int> getNbLogs()
{
throw new NotImplementedException();
}
public async Task<List<Logs>> getSomeLogs(int nb, int page)
{
var logs = await getAllLogs();
if ((page - 1) * nb + nb > logs.Count)
{
return logs.GetRange(logs.Count - nb, nb);
}
return logs.GetRange((page - 1) * nb, nb);
}
public async Task removeLogs(Logs logs)
{
var data = await getAllLogs();
var l = data.FirstOrDefault(p => p.Message ==logs.Message && p.LogLevel==logs.LogLevel);
if (l != null)
{
data.Remove(l);
await saveLogsJson(data);
}
}
}
}

@ -1,202 +1,153 @@
using System.Text.Json;
using WF_WebAdmin.Model;
namespace WF_WebAdmin.Service;
public class QuizServiceStub: IQuizService
namespace WF_WebAdmin.Service
{
private readonly string _jsonFilePath = Path.Combine(Environment.CurrentDirectory, "wwwroot", "fake_data_quiz.json");
/// <summary>
/// Asynchronously saves a list of quiz objects to a JSON file.
/// Service de gestion des quiz utilisant un fichier JSON comme stockage de données.
/// </summary>
/// <param name="quizzes">A list of <see cref="Quiz"/> objects to be serialized and saved.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <remarks>
/// This method serializes the list of quizzes to a well-formatted JSON string and saves it
/// to a specified file path. The <paramref name="quizzes"/> list is serialized using
/// <see cref="JsonSerializer"/> with indented formatting to make the JSON human-readable.
/// </remarks>
public async Task saveQuizJson(List<Quiz> quizzes)
public class QuizServiceStub : IQuizService
{
var json = JsonSerializer.Serialize(quizzes, new JsonSerializerOptions { WriteIndented = true });
await File.WriteAllTextAsync(_jsonFilePath, json);
}
private readonly string _jsonFilePath = Path.Combine(Environment.CurrentDirectory, "wwwroot", "fake_data_quiz.json");
/// <summary>
/// Asynchronously adds a new quiz to the list of quizzes and saves the updated list to a JSON file.
/// </summary>
/// <param name="quiz">The <see cref="Quiz"/> object to be added to the list of quizzes.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <remarks>
/// This method retrieves the current list of quizzes using <see cref="getQuizzes"/>, assigns a unique ID to the
/// new quiz (based on the highest existing ID), and adds the new quiz to the list. Afterward, the updated list
/// of quizzes is saved back to the JSON file using <see cref="saveQuizJson"/>. The new quiz will have an ID
/// that's one greater than the highest existing ID or 1 if no quizzes exist.
/// </remarks>
public async Task addQuiz(Quiz quiz)
{
var data = await getQuizzes();
quiz.Id = data.Count > 0 ? data.Max(p => p.Id) + 1 : 1;
data.Add(quiz);
await saveQuizJson(data);
}
/// <summary>
/// Asynchronously updates an existing quiz in the list of quizzes and saves the updated list to a JSON file.
/// </summary>
/// <param name="quiz">The <see cref="Quiz"/> object containing the updated data.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <remarks>
/// This method retrieves the current list of quizzes using <see cref="getQuizzes"/>, searches for the quiz
/// with the same ID as the one provided, and updates its properties with the new values from the given quiz object.
/// If the quiz is found, the updated list is saved back to the JSON file using <see cref="saveQuizJson"/>.
/// If no quiz with the matching ID is found, no update is performed.
/// </remarks>
public async Task updateQuiz(Quiz quiz)
{
var data = await getQuizzes();
var existingQuiz = data.FirstOrDefault(q => q.Id == quiz.Id);
if (existingQuiz != null)
/// <summary>
/// Sauvegarde la liste des quiz dans un fichier JSON.
/// </summary>
/// <param name="quizzes">Liste des quiz à sauvegarder.</param>
public async Task saveQuizJson(List<Quiz> quizzes)
{
existingQuiz.Question = quiz.Question;
existingQuiz.AnswerA = quiz.AnswerA;
existingQuiz.AnswerB = quiz.AnswerB;
existingQuiz.AnswerC = quiz.AnswerC;
existingQuiz.AnswerD = quiz.AnswerD;
existingQuiz.CAnswer = quiz.CAnswer;
existingQuiz.IsValid = quiz.IsValid;
existingQuiz.UserProposition = quiz.UserProposition;
await saveQuizJson(data);
var json = JsonSerializer.Serialize(quizzes, new JsonSerializerOptions { WriteIndented = true });
await File.WriteAllTextAsync(_jsonFilePath, json);
}
}
/// <summary>
/// Asynchronously removes a quiz from the list of quizzes by its ID and saves the updated list to a JSON file.
/// </summary>
/// <param name="id">The ID of the <see cref="Quiz"/> to be removed.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <remarks>
/// This method retrieves the current list of quizzes using <see cref="getQuizzes"/>, searches for the quiz
/// with the specified ID, and removes it from the list if found. After removal, the updated list of quizzes is
/// saved back to the JSON file using <see cref="saveQuizJson"/>. If no quiz with the matching ID is found,
/// no changes are made.
/// </remarks>
public async Task removeQuiz(int id)
{
var data = await getQuizzes();
var quiz = data.FirstOrDefault(q => q.Id == id);
if (quiz != null)
/// <summary>
/// Ajoute un quiz à la liste et le sauvegarde dans le fichier JSON.
/// </summary>
/// <param name="quiz">Quiz à ajouter.</param>
public async Task addQuiz(Quiz quiz)
{
data.Remove(quiz);
var data = await getQuizzes();
quiz.Id = data.Count > 0 ? data.Max(p => p.Id) + 1 : 1;
data.Add(quiz);
await saveQuizJson(data);
}
}
public Task validateQuiz(int id)
{
throw new NotImplementedException();
}
/// <summary>
/// Met à jour un quiz existant dans la liste et le sauvegarde.
/// </summary>
/// <param name="quiz">Quiz mis à jour.</param>
public async Task updateQuiz(Quiz quiz)
{
var data = await getQuizzes();
var existingQuiz = data.FirstOrDefault(q => q.Id == quiz.Id);
if (existingQuiz != null)
{
existingQuiz.Question = quiz.Question;
existingQuiz.AnswerA = quiz.AnswerA;
existingQuiz.AnswerB = quiz.AnswerB;
existingQuiz.AnswerC = quiz.AnswerC;
existingQuiz.AnswerD = quiz.AnswerD;
existingQuiz.CAnswer = quiz.CAnswer;
existingQuiz.IsValid = quiz.IsValid;
existingQuiz.UserProposition = quiz.UserProposition;
await saveQuizJson(data);
}
}
/// <summary>
/// Asynchronously retrieves the list of quizzes from a JSON file.
/// </summary>
/// <returns>A task representing the asynchronous operation, with a <see cref="List{Quiz}"/> result containing the quizzes.</returns>
/// <remarks>
/// This method checks if the JSON file exists at the specified file path. If the file does not exist, it logs a
/// message to the console and returns an empty list of quizzes. If the file exists, it reads the JSON content,
/// deserializes it into a list of <see cref="Quiz"/> objects, and returns the list. If the deserialization is
/// unsuccessful or the file is empty, it returns an empty list instead.
/// </remarks>
public async Task<List<Quiz>> getQuizzes()
{
if (!File.Exists(_jsonFilePath))
/// <summary>
/// Supprime un quiz de la liste et met à jour le fichier JSON.
/// </summary>
/// <param name="id">Identifiant du quiz à supprimer.</param>
public async Task removeQuiz(int id)
{
Console.Out.WriteLine($"{_jsonFilePath} not found");
return new List<Quiz>();
var data = await getQuizzes();
var quiz = data.FirstOrDefault(q => q.Id == id);
if (quiz != null)
{
data.Remove(quiz);
await saveQuizJson(data);
}
}
var json = await File.ReadAllTextAsync(_jsonFilePath);
return JsonSerializer.Deserialize<List<Quiz>>(json) ?? new List<Quiz>();
}
/// <summary>
/// Valide un quiz (non implémenté).
/// </summary>
/// <param name="id">Identifiant du quiz à valider.</param>
public Task validateQuiz(int id)
{
throw new NotImplementedException();
}
/// <summary>
/// Asynchronously retrieves the list of quizzes that are marked as invalid and need validation.
/// </summary>
/// <returns>A task representing the asynchronous operation, with a <see cref="List{Quiz}"/> result containing quizzes that are not valid.</returns>
/// <remarks>
/// This method retrieves the full list of quizzes using <see cref="getQuizzes"/> and filters it to return only those
/// quizzes where the <see cref="Quiz.IsValid"/> property is set to <c>false</c>. The filtered list is then returned.
/// If no quizzes are invalid, an empty list will be returned.
/// </remarks>
public async Task<List<Quiz>> getQuizzesToValidate()
{
var quizzes = await getQuizzes();
return quizzes.Where(quiz => !quiz.IsValid).ToList();
}
/// <summary>
/// Récupère la liste complète des quiz à partir du fichier JSON.
/// </summary>
/// <returns>Liste des quiz.</returns>
public async Task<List<Quiz>> getQuizzes()
{
if (!File.Exists(_jsonFilePath))
{
Console.Out.WriteLine($"{_jsonFilePath} not found");
return new List<Quiz>();
}
var json = await File.ReadAllTextAsync(_jsonFilePath);
return JsonSerializer.Deserialize<List<Quiz>>(json) ?? new List<Quiz>();
}
/// <summary>
/// Asynchronously retrieves a specific quiz by its ID from the list of quizzes.
/// </summary>
/// <param name="id">The ID of the <see cref="Quiz"/> to retrieve.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="Quiz"/> result containing the matching quiz, or <c>null</c> if not found.</returns>
/// <remarks>
/// This method retrieves the full list of quizzes using <see cref="getQuizzes"/> and searches for a quiz with
/// the specified ID. If a quiz with the matching ID is found, it is returned; otherwise, the method returns <c>null</c>.
/// </remarks>
public async Task<Quiz> getQuiz(int id)
{
var data = await getQuizzes();
var q = data.FirstOrDefault(p => p.Id == id);
if (q == null)
/// <summary>
/// Récupère la liste des quiz non validés.
/// </summary>
/// <returns>Liste des quiz en attente de validation.</returns>
public async Task<List<Quiz>> getQuizzesToValidate()
{
throw new KeyNotFoundException($"Quiz with ID {id} not found.");
var quizzes = await getQuizzes();
return quizzes.Where(quiz => quiz.IsValid == false).ToList();
}
return q;
}
/// <summary>
/// Asynchronously retrieves a paginated list of quizzes, returning a specific number of quizzes for the given page.
/// </summary>
/// <param name="nb">The number of quizzes to retrieve per page.</param>
/// <param name="page">The page number to retrieve, where the first page is 1.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="List{Quiz}"/> result containing the quizzes for the specified page.</returns>
/// <remarks>
/// This method retrieves the full list of quizzes using <see cref="getQuizzes"/> and returns a subset of quizzes based
/// on the specified page number and the number of quizzes per page. If the requested page exceeds the available quizzes,
/// the method returns the last page with the remaining quizzes. If the number of quizzes requested per page exceeds the
/// total number of quizzes, the method will return all quizzes available.
/// </remarks>
public async Task<List<Quiz>> getSommeQuiz(int nb, int page)
{
var data = await getQuizzes();
if ((page - 1) * nb + nb > data.Count)
/// <summary>
/// Récupère un quiz spécifique par son identifiant.
/// </summary>
/// <param name="id">Identifiant du quiz.</param>
/// <returns>Le quiz correspondant ou null s'il n'existe pas.</returns>
public async Task<Quiz> getQuiz(int id)
{
if (nb > data.Count)
var data = await getQuizzes();
var q = data.FirstOrDefault(p => p.Id == id);
if (q != null)
{
return data.GetRange(0, data.Count - 1);
return q;
}
return data.GetRange(data.Count - nb, nb);
return null;
}
return data.GetRange((page - 1) * nb, nb);
}
/// <summary>
/// Récupère une liste paginée de quiz.
/// </summary>
/// <param name="nb">Nombre de quiz par page.</param>
/// <param name="page">Numéro de la page.</param>
/// <returns>Liste des quiz correspondant à la pagination.</returns>
public async Task<List<Quiz>> getSommeQuiz(int nb, int page)
{
var data = await getQuizzes();
if ((page - 1) * nb + nb > data.Count())
{
if (nb > data.Count())
{
return data.GetRange(0, data.Count() - 1);
}
return data.GetRange(data.Count() - nb, nb);
}
return data.GetRange((page - 1) * nb, nb);
}
/// <summary>
/// Asynchronously retrieves the total number of quizzes in the list.
/// </summary>
/// <returns>A task representing the asynchronous operation, with an <see cref="int"/> result containing the total number of quizzes.</returns>
/// <remarks>
/// This method retrieves the full list of quizzes using <see cref="getQuizzes"/> and returns the count of quizzes in the list.
/// It simply returns the number of quizzes available in the data source.
/// </remarks>
public async Task<int> getNbQuiz()
{
var data = await getQuizzes();
return data.Count;
/// <summary>
/// Récupère le nombre total de quiz enregistrés.
/// </summary>
/// <returns>Nombre total de quiz.</returns>
public async Task<int> getNbQuiz()
{
var data = await getQuizzes();
return data.Count;
}
}
}

@ -4,41 +4,32 @@ using Npgsql;
namespace WF_WebAdmin.Service
{
public class QuoteServiceLocal: IQuoteService
/// <summary>
/// Service de gestion des citations utilisant une base de données PostgreSQL.
/// </summary>
public class QuoteServiceLocal : IQuoteService
{
private readonly string? _connectionString = "Host=localhost;Port=5432;Username=;Password=;Database=";
private readonly string? _connectionString = "Host=localhost;Port=5432;Username=loguichard3;Password=Reglisse15.;Database=dbloguichard3";
/// <summary>
/// Asynchronously adds a new quote to the database and returns the corresponding <see cref="QuoteDto"/>.
/// Ajoute une nouvelle citation à la base de données PostgreSQL.
/// </summary>
/// <param name="quote">The <see cref="Quote"/> object to be added to the database.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="QuoteDto"/> result containing the added quote's data.</returns>
/// <remarks>
/// This method converts the provided <see cref="Quote"/> object into a <see cref="QuoteDto"/> using <see cref="QuoteExtension"/>.
/// It then inserts the quote into the PostgreSQL database using a parameterized SQL query with the help of Npgsql.
/// After successfully inserting the quote, the corresponding <see cref="QuoteDto"/> is returned to the caller.
/// Error handling is in place to catch any issues during the database insertion process, with the exception message logged in case of failure.
/// </remarks>
public async Task<QuoteDto> AddQuoteAsync(Quote? quote)
/// <param name="quote">Citation à ajouter.</param>
/// <returns>Un objet <see cref="QuoteDTO"/> représentant la citation ajoutée.</returns>
public async Task<QuoteDTO> AddQuoteAsync(Quote quote)
{
QuoteExtension extension = new QuoteExtension();
QuoteDto quoteDTO = extension.QuoteToDTO(quote);
QuoteDTO quoteDTO = extension.QuoteToDTO(quote);
// Utilisation de NpgsqlConnection pour PostgreSQL
using (var connection = new NpgsqlConnection(_connectionString))
{
// Définir la requête SQL d'insertion
var commandText = "INSERT INTO Quote (content, langue, reason, id_source, id_caracter, id_user_verif, img_path) " +
"VALUES (@content, @langue, @reason, @source, @character, @user, @img_path)";
// Créer une commande Npgsql
var command = new NpgsqlCommand(commandText, connection);
/*
Ajouter des paramètres à la commande
// Ajouter des paramètres à la commande
command.Parameters.AddWithValue("@content", quote.Content);
command.Parameters.AddWithValue("@langue", quote.Langue);
command.Parameters.AddWithValue("@reason", "À vérifier"); // Vous pouvez changer ça si nécessaire
@ -48,148 +39,143 @@ namespace WF_WebAdmin.Service
command.Parameters.AddWithValue("@img_path", quote.ImgPath);
*/
try
{
// Ouvrir la connexion à la base de données
await connection.OpenAsync();
// Exécuter la commande d'insertion
await command.ExecuteNonQueryAsync();
}
catch (Exception ex)
{
// Gérer les erreurs ici (par exemple, afficher ou enregistrer les erreurs)
Console.WriteLine($"Une erreur est survenue lors de l'ajout de la citation : {ex.Message}");
}
finally
{
// Fermer la connexion (automatiquement géré avec `using`, mais ajouté pour explicitement montrer le processus)
await connection.CloseAsync();
}
}
// Retourner l'objet DTO pour que vous puissiez l'utiliser ailleurs dans votre application
return quoteDTO;
}
/// <summary>
/// Asynchronously handles the removal of a quote and returns the corresponding <see cref="QuoteDto"/>.
/// Supprime une citation de la base de données.
/// </summary>
/// <param name="quote">The <see cref="Quote"/> object to be removed.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="QuoteDto"/> result corresponding to the removed quote.</returns>
/// <remarks>
/// This method takes a <see cref="Quote"/> object, converts it into a <see cref="QuoteDto"/> using the
/// <see cref="QuoteExtension"/>, and then returns the DTO. Note that while this function is named `RemoveQuote`,
/// it currently only converts the quote to a DTO and does not actually perform any database removal operation.
/// You may need to implement additional logic to remove the quote from the database.
/// </remarks>
public Task RemoveQuote(Quote? quote)
/// <param name="quote">Citation à supprimer.</param>
public Task RemoveQuote(Quote quote)
{
QuoteExtension extension = new QuoteExtension();
QuoteDto quoteDTO = extension.QuoteToDTO(quote);
QuoteDTO quoteDTO = extension.QuoteToDTO(quote);
// Return the DTO as the result of this asynchronous operation (though no removal logic is currently implemented)
return Task.FromResult(quoteDTO);
}
/// <summary>
/// Asynchronously validates a quote and returns the corresponding <see cref="QuoteDto"/>.
/// Valide une citation.
/// </summary>
/// <param name="quote">The <see cref="Quote"/> object to be validated.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="QuoteDto"/> result corresponding to the validated quote.</returns>
/// <remarks>
/// This method takes a <see cref="Quote"/> object, converts it into a <see cref="QuoteDto"/> using the
/// <see cref="QuoteExtension"/>, and returns the DTO. The method is named `validQuote`, but currently, it only
/// converts the quote into a DTO and does not perform any actual validation logic.
/// If you intend to validate the quote (e.g., updating its status in a database), you will need to implement
/// the actual validation logic separately.
/// </remarks>
public Task validQuote(Quote? quote)
/// <param name="quote">Citation à valider.</param>
public Task validQuote(Quote quote)
{
QuoteExtension extension = new QuoteExtension();
QuoteDto quoteDto = extension.QuoteToDTO(quote);
QuoteDTO quoteDTO = extension.QuoteToDTO(quote);
// Return the DTO as the result of this asynchronous operation (though no validation logic is currently implemented)
return Task.FromResult(quoteDto);
return Task.FromResult(quoteDTO);
}
/// <summary>
/// Asynchronously updates a quote and returns the corresponding <see cref="QuoteDto"/>.
/// Met à jour une citation existante.
/// </summary>
/// <param name="quote">The <see cref="Quote"/> object to be updated.</param>
/// <returns>A task representing the asynchronous operation, with a <see cref="QuoteDto"/> result corresponding to the updated quote.</returns>
/// <remarks>
/// This method takes a <see cref="Quote"/> object, converts it into a <see cref="QuoteDto"/> using the
/// <see cref="QuoteExtension"/>, and returns the DTO. The method is named `updateQuote`, but currently, it only
/// converts the quote into a DTO and does not perform any actual update logic.
/// If you intend to update the quote (e.g., modifying the quote in a database or data source),
/// you will need to implement the actual update logic separately.
/// </remarks>
public Task updateQuote(Quote? quote)
/// <param name="quote">Citation mise à jour.</param>
public Task updateQuote(Quote quote)
{
QuoteExtension extension = new QuoteExtension();
QuoteDto quoteDTO = extension.QuoteToDTO(quote);
QuoteDTO quoteDTO = extension.QuoteToDTO(quote);
// Return the DTO as the result of this asynchronous operation (though no update logic is currently implemented)
return Task.FromResult(quoteDTO);
}
/// <summary>
/// Ajoute une citation (non implémenté).
/// </summary>
public Task addQuote(Quote quote)
{
throw new NotImplementedException();
}
/// <summary>
/// Supprime une citation (non implémenté).
/// </summary>
public Task removeQuote(Quote quote)
{
throw new NotImplementedException();
}
/// <summary>
/// Récupère toutes les citations (non implémenté).
/// </summary>
public Task<List<Quote>> getAllQuote()
{
throw new NotImplementedException();
}
/// <summary>
/// Récupère un ensemble de citations paginées (non implémenté).
/// </summary>
public Task<List<Quote>> getSomeQuote(int nb, int page)
{
throw new NotImplementedException();
}
/// <summary>
/// Recherche des citations selon des critères spécifiques (non implémenté).
/// </summary>
public Task<List<Quote>> reserchQuote(string reserch, List<string> argument)
{
throw new NotImplementedException();
}
/// <summary>
/// Récupère toutes les citations invalides (non implémenté).
/// </summary>
public Task<List<Quote>> getAllQuoteInvalid()
{
throw new NotImplementedException();
}
/// <summary>
/// Récupère une liste paginée de citations invalides (non implémenté).
/// </summary>
public Task<List<Quote>> getSomeQuoteInvalid(int nb, int page)
{
throw new NotImplementedException();
}
public Task<Quote?> getOnequote(int id)
/// <summary>
/// Récupère une citation spécifique en fonction de son ID (non implémenté).
/// </summary>
public Task<Quote> getOnequote(int id)
{
throw new NotImplementedException();
}
/// <summary>
/// Récupère le nombre total de citations enregistrées (non implémenté).
/// </summary>
public Task<int> getNbQuote()
{
throw new NotImplementedException();
}
/// <summary>
/// Récupère la liste des personnages (non implémenté).
/// </summary>
public Task<List<Character>> getChar()
{
throw new NotImplementedException();
}
/// <summary>
/// Récupère la liste des sources (non implémenté).
/// </summary>
public Task<List<Source>> getSrc()
{
throw new NotImplementedException();

@ -3,42 +3,29 @@ using WF_WebAdmin.Model;
namespace WF_WebAdmin.Service;
public class QuoteServiceStub : IQuoteService
{
/// <summary>
/// Service de gestion des citations utilisant un fichier JSON comme stockage.
/// </summary>
public class QuoteServiceStub : IQuoteService
{
private readonly string _jsonFilePath = Path.Combine(Environment.CurrentDirectory, "wwwroot", "fake-dataQuote.json");
private readonly string _char = Path.Combine(Environment.CurrentDirectory, "wwwroot", "fake-dataCaracter.json");
private readonly string _src = Path.Combine(Environment.CurrentDirectory, "wwwroot", "fake-dataSource.json");
/// <summary>
/// Asynchronously saves a list of quotes to a JSON file.
/// Sauvegarde la liste des citations dans le fichier JSON.
/// </summary>
/// <param name="quotes">The list of <see cref="Quote"/> objects to be serialized and saved to the file.</param>
/// <returns>A task representing the asynchronous operation of saving the quotes to the file.</returns>
/// <remarks>
/// This method serializes the provided list of <see cref="Quote"/> objects into JSON format using <see cref="JsonSerializer"/>.
/// The serialized JSON is then saved to the file path specified in the <see cref="_jsonFilePath"/> field. The JSON is written
/// with indentation for better readability.
/// If the file does not already exist, it will be created.
/// </remarks>
/// <param name="quotes">Liste des citations à sauvegarder.</param>
public async Task saveQuoteJson(List<Quote> quotes)
{
var json = JsonSerializer.Serialize(quotes, new JsonSerializerOptions { WriteIndented = true });
await File.WriteAllTextAsync(_jsonFilePath, json);
}
/// <summary>
/// Asynchronously adds a new quote to the list and saves it to a JSON file.
/// Ajoute une nouvelle citation et l'enregistre dans le fichier JSON.
/// </summary>
/// <param name="quote">The <see cref="Quote"/> object to be added to the list.</param>
/// <returns>A task representing the asynchronous operation of adding the quote and saving the updated list to the file.</returns>
/// <remarks>
/// This method retrieves the current list of quotes using the <see cref="getAllQuote"/> method, assigns a new ID to the
/// provided quote (incremented from the maximum existing ID), and adds the quote to the list. After updating the list,
/// the method saves the updated list back to the JSON file using <see cref="saveQuoteJson"/>.
/// If the list is empty, the new quote is assigned an ID of 1.
/// </remarks>
/// <param name="quote">Citation à ajouter.</param>
public async Task addQuote(Quote quote)
{
var data = await getAllQuote();
@ -47,18 +34,10 @@ namespace WF_WebAdmin.Service;
await saveQuoteJson(data);
}
/// <summary>
/// Asynchronously removes a quote from the list and saves the updated list to a JSON file.
/// Supprime une citation et met à jour le fichier JSON.
/// </summary>
/// <param name="quote">The <see cref="Quote"/> object to be removed from the list.</param>
/// <returns>A task representing the asynchronous operation of removing the quote and saving the updated list to the file.</returns>
/// <remarks>
/// This method retrieves the current list of quotes using the <see cref="getAllQuote"/> method.
/// It searches for the provided quote by its `Id` and, if found, removes it from the list.
/// After removing the quote, the method saves the updated list back to the JSON file using <see cref="saveQuoteJson"/>.
/// If the quote is not found in the list, no action is taken.
/// </remarks>
/// <param name="quote">Citation à supprimer.</param>
public async Task removeQuote(Quote quote)
{
var data = await getAllQuote();
@ -70,25 +49,20 @@ namespace WF_WebAdmin.Service;
}
}
public Task validQuote(Quote? quote)
/// <summary>
/// Marque une citation comme valide.
/// </summary>
/// <param name="quote">Citation à valider.</param>
public async Task validQuote(Quote quote)
{
throw new NotImplementedException();
}
/// <summary>
/// Asynchronously updates the details of an existing quote and saves the updated list to a JSON file.
/// Met à jour une citation existante.
/// </summary>
/// <param name="quote">The <see cref="Quote"/> object containing the updated details of the quote.</param>
/// <returns>A task representing the asynchronous operation of updating the quote and saving the updated list to the file.</returns>
/// <remarks>
/// This method retrieves the current list of quotes using the <see cref="getAllQuote"/> method.
/// It searches for the quote with the provided `Id` and, if found, updates its properties (e.g., content, character, image path, etc.)
/// with the values from the provided `quote` object. After updating the quote, the method saves the updated list back to the JSON file
/// using <see cref="saveQuoteJson"/>. If the quote with the specified `Id` is not found, no action is taken.
/// </remarks>
public async Task updateQuote(Quote? quote)
/// <param name="quote">Citation mise à jour.</param>
public async Task updateQuote(Quote quote)
{
var data = await getAllQuote();
var q = data.FirstOrDefault(p => p.Id == quote.Id);
@ -104,17 +78,10 @@ namespace WF_WebAdmin.Service;
}
}
/// <summary>
/// Asynchronously retrieves all quotes from a JSON file.
/// Récupère toutes les citations stockées dans le fichier JSON.
/// </summary>
/// <returns>A task representing the asynchronous operation, with a result of a list of <see cref="Quote"/> objects.</returns>
/// <remarks>
/// This method checks if the JSON file exists at the specified file path (<see cref="_jsonFilePath"/>).
/// If the file does not exist, it logs a message and returns an empty list of quotes.
/// If the file exists, it reads the JSON content, deserializes it into a list of <see cref="Quote"/> objects,
/// and returns that list. If the deserialization results in a null value, an empty list is returned.
/// </remarks>
/// <returns>Une liste de citations.</returns>
public async Task<List<Quote>> getAllQuote()
{
if (!File.Exists(_jsonFilePath))
@ -127,21 +94,12 @@ namespace WF_WebAdmin.Service;
return JsonSerializer.Deserialize<List<Quote>>(json) ?? new List<Quote>();
}
/// <summary>
/// Asynchronously retrieves a subset of quotes based on the specified page number and the number of quotes per page.
/// Récupère une liste paginée de citations.
/// </summary>
/// <param name="nb">The number of quotes to retrieve per page.</param>
/// <param name="page">The page number for pagination.</param>
/// <returns>A task representing the asynchronous operation, with a result of a list of <see cref="Quote"/> objects for the specified page.</returns>
/// <remarks>
/// This method retrieves all quotes using the <see cref="getAllQuote"/> method and then calculates the range of quotes
/// to be returned based on the provided `nb` (number of quotes per page) and `page` (the page number). It ensures that
/// the returned subset does not exceed the total number of quotes available.
///
/// If the calculated range is larger than the available quotes, it returns a subset of quotes from the end of the list.
/// If the requested page number exceeds the total number of pages, the method will return the last available page of quotes.
/// </remarks>
/// <param name="nb">Nombre de citations par page.</param>
/// <param name="page">Numéro de la page.</param>
/// <returns>Une liste de citations correspondant à la page demandée.</returns>
public async Task<List<Quote>> getSomeQuote(int nb, int page)
{
var quotes = await getAllQuote();
@ -156,105 +114,74 @@ namespace WF_WebAdmin.Service;
return quotes.GetRange((page - 1) * nb, nb);
}
/// <summary>
/// Asynchronously retrieves a single quote based on its ID.
/// Récupère une citation spécifique en fonction de son ID.
/// </summary>
/// <param name="id">The unique identifier of the <see cref="Quote"/> to be retrieved.</param>
/// <returns>A task representing the asynchronous operation, with a result of the <see cref="Quote"/> object if found, otherwise null.</returns>
/// <remarks>
/// This method retrieves all quotes using the <see cref="getAllQuote"/> method and searches for the quote that matches the provided `id`.
/// If a matching quote is found, it returns that quote; otherwise, it returns `null`.
/// </remarks>
public async Task<Quote?> getOnequote(int id)
/// <param name="id">ID de la citation recherchée.</param>
/// <returns>La citation correspondante ou null si elle n'existe pas.</returns>
public async Task<Quote> getOnequote(int id)
{
var data = await getAllQuote();
var q = data.FirstOrDefault(p => p.Id == id);
if (q == null)
{
throw new KeyNotFoundException($"Quote with ID {id} not found.");
}
return q;
}
public Task<List<Quote>> reserchQuote(string reserch, List<string> argument)
{
throw new NotImplementedException();
}
/// <summary>
/// Recherche des citations selon des critères spécifiques.
/// </summary>
/// <param name="reserch">Terme de recherche.</param>
/// <param name="argument">Liste d'arguments pour affiner la recherche.</param>
/// <returns>Une liste de citations correspondant aux critères de recherche.</returns>
public async Task<List<Quote>> reserchQuote(string reserch, List<string> argument)
{
throw new NotImplementedException();
}
/// <summary>
/// Asynchronously retrieves all invalid quotes from the list.
/// Récupère toutes les citations invalides.
/// </summary>
/// <returns>A task representing the asynchronous operation, with a result of a list of invalid <see cref="Quote"/> objects.</returns>
/// <remarks>
/// This method retrieves all quotes using the <see cref="getAllQuote"/> method and filters them by the `IsValid` property.
/// It returns only those quotes where `IsValid` is set to `false`.
/// If no invalid quotes are found, an empty list is returned.
/// </remarks>
/// <returns>Une liste de citations non validées.</returns>
public async Task<List<Quote>> getAllQuoteInvalid()
{
var quotes = await getAllQuote();
quotes = quotes.Where(q => !q.IsValid).ToList();
quotes = quotes.Where(q => q.IsValid == false).ToList();
return quotes;
}
/// <summary>
/// Asynchronously retrieves a subset of invalid quotes based on the specified page number and the number of quotes per page.
/// Récupère une liste paginée de citations invalides.
/// </summary>
/// <param name="nb">The number of invalid quotes to retrieve per page.</param>
/// <param name="page">The page number for pagination.</param>
/// <returns>A task representing the asynchronous operation, with a result of a list of invalid <see cref="Quote"/> objects for the specified page.</returns>
/// <remarks>
/// This method retrieves all invalid quotes using the <see cref="getAllQuoteInvalid"/> method and then calculates the range of invalid quotes
/// to be returned based on the provided `nb` (number of quotes per page) and `page` (the page number). It ensures that
/// the returned subset does not exceed the total number of invalid quotes available.
///
/// If the calculated range is larger than the available invalid quotes, it returns a subset of quotes from the end of the list.
/// If the requested page number exceeds the total number of pages, the method will return the last available page of invalid quotes.
/// </remarks>
/// <param name="nb">Nombre de citations par page.</param>
/// <param name="page">Numéro de la page.</param>
/// <returns>Une liste de citations non validées correspondant à la page demandée.</returns>
public async Task<List<Quote>> getSomeQuoteInvalid(int nb, int page)
{
var quotes = await getAllQuoteInvalid();
if ((page - 1) * nb + nb > quotes.Count)
if ((page - 1) * nb + nb > quotes.Count())
{
if (nb > quotes.Count)
if (nb > quotes.Count())
{
return quotes.GetRange(0, quotes.Count);
return quotes.GetRange(0, quotes.Count());
}
return quotes.GetRange(quotes.Count - nb, nb);
return quotes.GetRange(quotes.Count() - nb, nb);
}
return quotes.GetRange((page - 1) * nb, nb);
}
/// <summary>
/// Asynchronously retrieves the total number of quotes.
/// Récupère le nombre total de citations enregistrées.
/// </summary>
/// <returns>A task representing the asynchronous operation, with a result of the total number of <see cref="Quote"/> objects.</returns>
/// <remarks>
/// This method retrieves all quotes using the <see cref="getAllQuote"/> method and returns the count of quotes.
/// It provides the total number of quotes currently available in the data source.
/// </remarks>
/// <returns>Nombre total de citations.</returns>
public async Task<int> getNbQuote()
{
var data = await getAllQuote();
return data.Count;
}
/// <summary>
/// Asynchronously retrieves a list of characters from a JSON file.
/// Récupère la liste des personnages depuis le fichier JSON.
/// </summary>
/// <returns>A task representing the asynchronous operation, with a result of a list of <see cref="Character"/> objects.</returns>
/// <remarks>
/// This method checks if the JSON file containing character data exists at the specified file path (`_char`).
/// If the file does not exist, it logs a message to the console and returns an empty list of characters.
/// If the file exists, it reads the JSON content, deserializes it into a list of <see cref="Character"/> objects,
/// and returns that list. If the deserialization results in a null value, an empty list is returned.
/// </remarks>
/// <returns>Une liste de personnages.</returns>
public async Task<List<Character>> getChar()
{
if (!File.Exists(_char))
@ -267,17 +194,10 @@ namespace WF_WebAdmin.Service;
return JsonSerializer.Deserialize<List<Character>>(json) ?? new List<Character>();
}
/// <summary>
/// Asynchronously retrieves a list of sources from a JSON file.
/// Récupère la liste des sources depuis le fichier JSON.
/// </summary>
/// <returns>A task representing the asynchronous operation, with a result of a list of <see cref="Source"/> objects.</returns>
/// <remarks>
/// This method checks if the JSON file containing source data exists at the specified file path (`_src`).
/// If the file does not exist, it logs a message to the console and returns an empty list of sources.
/// If the file exists, it reads the JSON content, deserializes it into a list of <see cref="Source"/> objects,
/// and returns that list. If the deserialization results in a null value, an empty list is returned.
/// </remarks>
/// <returns>Une liste de sources.</returns>
public async Task<List<Source>> getSrc()
{
if (!File.Exists(_src))
@ -289,5 +209,4 @@ namespace WF_WebAdmin.Service;
var json = await File.ReadAllTextAsync(_src);
return JsonSerializer.Deserialize<List<Source>>(json) ?? new List<Source>();
}
}

@ -3,37 +3,27 @@ using WF_WebAdmin.Model;
namespace WF_WebAdmin.Service;
/// <summary>
/// Service de gestion des utilisateurs utilisant un fichier JSON comme stockage.
/// </summary>
public class UserServiceStub : IUserService
{
private readonly string _jsonFilePath = Path.Combine(Environment.CurrentDirectory, "wwwroot", "fake_data_users.json");
/// <summary>
/// Asynchronously saves a list of users to a JSON file.
/// Sauvegarde la liste des utilisateurs dans le fichier JSON.
/// </summary>
/// <param name="users">The list of <see cref="User"/> objects to be saved to the file.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <remarks>
/// This method serializes the provided list of <see cref="User"/> objects into a JSON format using the `JsonSerializer`.
/// It then writes the serialized JSON string to the file specified by the `_jsonFilePath`. The JSON is written with indentation for readability.
/// </remarks>
/// <param name="users">Liste des utilisateurs à sauvegarder.</param>
public async Task saveUsersJson(List<User> users)
{
var json = JsonSerializer.Serialize(users, new JsonSerializerOptions { WriteIndented = true });
await File.WriteAllTextAsync(_jsonFilePath, json);
}
/// <summary>
/// Asynchronously removes a user from the list of users and saves the updated list to a JSON file.
/// Supprime un utilisateur de la liste et met à jour le fichier JSON.
/// </summary>
/// <param name="user">The <see cref="User"/> object to be removed from the list.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <remarks>
/// This method retrieves the list of all users using the <see cref="getAllUser"/> method,
/// then searches for the specified user by their `Id`. If a matching user is found,
/// they are removed from the list, and the updated list is saved back to the JSON file using the <see cref="saveUsersJson"/> method.
/// </remarks>
/// <param name="user">Utilisateur à supprimer.</param>
public async Task removeUser(User user)
{
var data = await getAllUser();
@ -45,49 +35,30 @@ public class UserServiceStub : IUserService
}
}
/// <summary>
/// Asynchronously updates the role of a user, setting the user as an administrator.
/// Met à jour le rôle d'un utilisateur pour le passer en administrateur.
/// </summary>
/// <param name="user">The <see cref="User"/> object whose role is to be updated.</param>
/// <returns>A task representing the asynchronous operation of updating the user's role.</returns>
/// <remarks>
/// This method updates the `IsAdmin` property of the specified user to `true`, indicating that the user is an administrator.
/// It then calls the <see cref="updateUser"/> method to persist the updated user information.
/// </remarks>
public Task updateRole(User? user)
/// <param name="user">Utilisateur à promouvoir.</param>
public Task updateRole(User user)
{
user.IsAdmin = true;
return updateUser(user);
}
/// <summary>
/// Asynchronously downgrades the role of a user, removing their administrator privileges.
/// Rétrograde un administrateur en utilisateur normal.
/// </summary>
/// <param name="user">The <see cref="User"/> object whose role is to be downgraded.</param>
/// <returns>A task representing the asynchronous operation of downgrading the user's role.</returns>
/// <remarks>
/// This method updates the `IsAdmin` property of the specified user to `false`, removing their administrator status.
/// It then calls the <see cref="updateUser"/> method to persist the updated user information.
/// </remarks>
public Task downgradeRole(User? user)
/// <param name="user">Utilisateur à rétrograder.</param>
public Task downgradeRole(User user)
{
user.IsAdmin = false;
return updateUser(user);
}
/// <summary>
/// Asynchronously retrieves a list of all users from a JSON file.
/// Récupère tous les utilisateurs stockés dans le fichier JSON.
/// </summary>
/// <returns>A task representing the asynchronous operation, with a result of a list of <see cref="User"/> objects.</returns>
/// <remarks>
/// This method checks if the JSON file containing user data exists at the specified file path (`_jsonFilePath`).
/// If the file does not exist, it logs a message to the console and returns an empty list of users.
/// If the file exists, it reads the JSON content, deserializes it into a list of <see cref="User"/> objects,
/// and returns that list. If the deserialization results in a null value, an empty list is returned.
/// </remarks>
/// <returns>Une liste d'utilisateurs.</returns>
public async Task<List<User>> getAllUser()
{
if (!File.Exists(_jsonFilePath))
@ -100,84 +71,60 @@ public class UserServiceStub : IUserService
return JsonSerializer.Deserialize<List<User>>(json) ?? new List<User>();
}
/// <summary>
/// Asynchronously retrieves a paginated list of users from a JSON file.
/// Récupère une liste paginée d'utilisateurs.
/// </summary>
/// <param name="nb">The number of users to retrieve per page.</param>
/// <param name="page">The page number for the data to retrieve.</param>
/// <returns>A task representing the asynchronous operation, with a result of a list of <see cref="User"/> objects.</returns>
/// <remarks>
/// This method retrieves all users using the <see cref="getAllUser"/> method, then calculates the range of users to return
/// based on the specified page number and the number of users per page (`nb`).
/// It returns the corresponding subset of users for the given page. If the page exceeds the available number of users,
/// it returns the last `nb` users available.
/// </remarks>
public async Task<List<User>?> getSomeUser(int nb, int page)
/// <param name="nb">Nombre d'utilisateurs par page.</param>
/// <param name="page">Numéro de la page.</param>
/// <returns>Une liste d'utilisateurs correspondant à la page demandée.</returns>
public async Task<List<User>> getSomeUser(int nb, int page)
{
var users = await getAllUser();
if ((page - 1) * nb + nb > users.Count)
if ((page - 1) * nb + nb > users.Count())
{
return users.GetRange(users.Count - nb, nb);
return users.GetRange(users.Count() - nb, nb);
}
return users.GetRange((page - 1) * nb, nb);
}
/// <summary>
/// Asynchronously retrieves a single user by their ID from the JSON file.
/// Récupère un utilisateur spécifique en fonction de son ID.
/// </summary>
/// <param name="id">The ID of the user to retrieve.</param>
/// <returns>A task representing the asynchronous operation, with a result of the <see cref="User"/> object if found, otherwise null.</returns>
/// <remarks>
/// This method retrieves all users using the <see cref="getAllUser"/> method,
/// then searches for the user with the specified `id`. If a user with the given ID is found,
/// the user is returned. Otherwise, it returns null.
/// </remarks>
/// <param name="id">ID de l'utilisateur recherché.</param>
/// <returns>L'utilisateur correspondant à l'ID ou null s'il n'existe pas.</returns>
public async Task<User> getOneUser(int id)
{
var data = await getAllUser();
var user = data.FirstOrDefault(p => p.Id == id);
if (user == null)
{
throw new KeyNotFoundException($"User with ID {id} not found.");
}
return user;
var u = data.FirstOrDefault(p => p.Id == id);
return u;
}
/// <summary>
/// Recherche des utilisateurs selon des critères spécifiques.
/// </summary>
/// <param name="reserch">Terme de recherche.</param>
/// <param name="args">Liste des arguments supplémentaires pour affiner la recherche.</param>
/// <returns>Une liste d'utilisateurs correspondant aux critères de recherche.</returns>
public Task<List<User>> reserchUsers(string reserch, List<string> args)
{
throw new NotImplementedException();
}
/// <summary>
/// Asynchronously retrieves the total number of users from the JSON file.
/// Récupère le nombre total d'utilisateurs enregistrés.
/// </summary>
/// <returns>A task representing the asynchronous operation, with a result of the total number of users.</returns>
/// <remarks>
/// This method retrieves all users using the <see cref="getAllUser"/> method and returns the count of users in the list.
/// </remarks>
/// <returns>Nombre total d'utilisateurs.</returns>
public async Task<int> getNbUser()
{
var data = await getAllUser();
return data.Count;
}
/// <summary>
/// Asynchronously updates the details of a user in the JSON file.
/// Met à jour les informations d'un utilisateur existant.
/// </summary>
/// <param name="user">The <see cref="User"/> object containing the updated user details.</param>
/// <returns>A task representing the asynchronous operation of updating the user.</returns>
/// <remarks>
/// This method retrieves all users using the <see cref="getAllUser"/> method, then searches for the user with the specified ID.
/// If a user with the given ID is found, it updates their details (Name, Email, Image, IsAdmin) based on the provided `user` object.
/// After updating the user, the modified list of users is saved back to the JSON file using the <see cref="saveUsersJson"/> method.
/// </remarks>
public async Task updateUser(User? user)
/// <param name="user">Utilisateur avec les nouvelles informations.</param>
public async Task updateUser(User user)
{
var data = await getAllUser();
var person = data.FirstOrDefault(p => p.Id == user.Id);

@ -21,16 +21,6 @@
new CultureInfo("fr-FR")
};
/// <summary>
/// Gets or sets the current culture for the application, triggering a navigation to set the culture cookie when changed.
/// </summary>
/// <remarks>
/// The getter retrieves the current culture of the application using <see cref="CultureInfo.CurrentCulture"/>.
/// The setter checks if the current UI culture matches the provided value. If they are the same, no action is taken.
/// If the cultures differ, it constructs a query string that includes the new culture and a redirect URI,
/// and then navigates to a "/Culture/SetCulture" endpoint to set the culture cookie.
/// The user is redirected to the same page with the new culture applied after the redirect.
/// </remarks>
private CultureInfo Culture
{
get => CultureInfo.CurrentCulture;
@ -50,5 +40,4 @@
this.NavigationManager.NavigateTo("/Culture/SetCulture" + query, forceLoad: true);
}
}
}

@ -3,32 +3,31 @@
@inject UserLogin uLogin
<PageTitle>WF-WebAdmin</PageTitle>
<MudThemeProvider />
<div class="page">
@* @if (uLogin.Name != null)
{ *@
@if (uLogin.Name != null)
{
<div class="sidebar">
<NavMenu/>
</div>
@*}*@
}
<main>
<div class="top-row px-4">
<div class="px-4">
<CultureSelector />
</div>
@* @if (!string.IsNullOrEmpty(uLogin.Name))
@if (!string.IsNullOrEmpty(uLogin.Name))
{
<button class="buttonProfil" type="button"> <img class="imageProfil" src="@uLogin.Image" height="90" width="480" /></button>
@* <img class="imageProfil" src="@uLogin.Image" />
@* <img class="imageProfil" src="@uLogin.Image" /> *@
}
else
{*@
{
<img class="imageProfil" src="https://cdn-icons-png.flaticon.com/512/61/61205.png"/>
@* } *@
}
</div>
<article class="content px-4">
@Body

@ -2,66 +2,56 @@
@inject UserLogin uLogin
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="">What the Fantasy</a>
<button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="">What the Fantasy</a>
<button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</div>
</div>
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
<nav class="flex-column">
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
<nav class="flex-column">
<div class="nav-item px-3">
<NavLink class="nav-link" href="">
🏠 Accueil
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="ValidQuote">
📜 Validation de citations
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="Accueil">
<span class="oi oi-plus" aria-hidden="true"></span> Accueil
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="ValidQuote">
<span class="oi oi-list-rich" aria-hidden="true"></span> Validation de citations
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="ValidQuiz">
📝 Validation de quiz
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="ValidQuiz">
<span class="oi oi-list-rich" aria-hidden="true"></span> Validation de quiz
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="deleteuser">
👤 Gestion des utilisateurs
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="deleteuser">
<span class="oi oi-list-rich" aria-hidden="true"></span> Gestion des utilisateurs
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="modifquote">
✍️ Gestion des citations
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="modifquote">
<span class="oi oi-list-rich" aria-hidden="true"></span> Gestion des citations
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="modifquiz">
❓ Gestion des questions
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="modifquiz">
<span class="oi oi-list-rich" aria-hidden="true"></span> Gestion des Question
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="logs">
📊 Logs
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="/commentary-chart">
📈 Stats commentaires
</NavLink>
</div>
</nav>
</div>
</nav>
</div>
@code {
private bool collapseNavMenu = true;

@ -15,7 +15,6 @@
<PackageReference Include="bootstrap" Version="5.3.3" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.1" />
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="9.0.1" />
<PackageReference Include="MudBlazor" Version="6.2.0" />
<PackageReference Include="Npgsql" Version="9.0.2" />
<PackageReference Include="Blazored.Modal" Version="7.2.0" />
</ItemGroup>

@ -10,5 +10,4 @@
@using WF_WebAdmin.Shared
@using Blazorise.DataGrid
@using Blazored.Modal
@using MudBlazor

@ -1,5 +0,0 @@
{
"version": "3.0",
"defaultProvider": "cdnjs",
"libraries": []
}

@ -7,17 +7,6 @@ html, body {
color: black;
}
h1 {
text-align: center;
font-size: 32px;
margin-top: 10%;
font-family: "Roboto", serif;
}
h1:focus {
outline: none;
}
@ -180,7 +169,12 @@ td {
text-align: center;
}
h1 {
text-align: center;
font-size: 32px;
margin-top: 10%;
font-family: "Roboto", serif;
}
p {
margin-bottom: 2%;
@ -227,6 +221,35 @@ p {
color: red;
}
table {
border-collapse: collapse;
width: 100%;
}
td {
padding: 10px 20px;
border: none;
}
.boutons {
display: flex;
justify-content: space-between;
gap: 10px;
}
.boutons button {
border: none;
background-color: transparent;
padding: 5px;
cursor: pointer;
}
.boutons button img {
width: 24px;
height: 24px;
object-fit: contain;
}
.imageProfil {
height: auto;

@ -1,702 +0,0 @@
[
{
"id_comment": 1,
"quote": 19,
"users": 29,
"dateC": "2024-01-22",
"comment": "Citation magnifique."
},
{
"id_comment": 2,
"quote": 6,
"users": 18,
"dateC": "2024-01-20",
"comment": "Paroles sages."
},
{
"id_comment": 3,
"quote": 2,
"users": 8,
"dateC": "2024-01-25",
"comment": "Citation puissante."
},
{
"id_comment": 4,
"quote": 11,
"users": 31,
"dateC": "2024-01-01",
"comment": "Très poétique."
},
{
"id_comment": 5,
"quote": 8,
"users": 6,
"dateC": "2024-02-06",
"comment": "Belle pensée."
},
{
"id_comment": 6,
"quote": 13,
"users": 37,
"dateC": "2024-02-01",
"comment": "Citation exceptionnelle."
},
{
"id_comment": 7,
"quote": 2,
"users": 33,
"dateC": "2024-02-11",
"comment": "Belle pensée."
},
{
"id_comment": 8,
"quote": 7,
"users": 28,
"dateC": "2024-02-07",
"comment": "Très émouvant."
},
{
"id_comment": 9,
"quote": 1,
"users": 48,
"dateC": "2024-03-05",
"comment": "Très motivant."
},
{
"id_comment": 10,
"quote": 16,
"users": 14,
"dateC": "2024-03-13",
"comment": "Très motivant."
},
{
"id_comment": 11,
"quote": 10,
"users": 9,
"dateC": "2024-03-13",
"comment": "Très touchant."
},
{
"id_comment": 12,
"quote": 4,
"users": 44,
"dateC": "2024-03-01",
"comment": "Très touchant."
},
{
"id_comment": 13,
"quote": 9,
"users": 8,
"dateC": "2024-04-04",
"comment": "Citation magnifique."
},
{
"id_comment": 14,
"quote": 3,
"users": 49,
"dateC": "2024-04-18",
"comment": "Très émouvant."
},
{
"id_comment": 15,
"quote": 19,
"users": 3,
"dateC": "2024-04-07",
"comment": "Très motivant."
},
{
"id_comment": 16,
"quote": 4,
"users": 9,
"dateC": "2024-04-25",
"comment": "Très motivant."
},
{
"id_comment": 17,
"quote": 17,
"users": 40,
"dateC": "2024-05-04",
"comment": "Très émouvant."
},
{
"id_comment": 18,
"quote": 6,
"users": 21,
"dateC": "2024-05-11",
"comment": "Très poétique."
},
{
"id_comment": 19,
"quote": 16,
"users": 3,
"dateC": "2024-05-08",
"comment": "Citation exceptionnelle."
},
{
"id_comment": 20,
"quote": 1,
"users": 17,
"dateC": "2024-05-04",
"comment": "Très touchant."
},
{
"id_comment": 21,
"quote": 14,
"users": 34,
"dateC": "2024-06-01",
"comment": "Citation magnifique."
},
{
"id_comment": 22,
"quote": 12,
"users": 23,
"dateC": "2024-06-03",
"comment": "Citation magnifique."
},
{
"id_comment": 23,
"quote": 11,
"users": 47,
"dateC": "2024-06-05",
"comment": "Citation magnifique."
},
{
"id_comment": 24,
"quote": 16,
"users": 28,
"dateC": "2024-06-07",
"comment": "Citation magnifique."
},
{
"id_comment": 25,
"quote": 19,
"users": 39,
"dateC": "2024-07-01",
"comment": "Citation magnifique."
},
{
"id_comment": 26,
"quote": 13,
"users": 31,
"dateC": "2024-07-02",
"comment": "Citation magnifique."
},
{
"id_comment": 27,
"quote": 1,
"users": 33,
"dateC": "2024-07-03",
"comment": "Citation magnifique."
},
{
"id_comment": 28,
"quote": 17,
"users": 20,
"dateC": "2024-07-04",
"comment": "Citation magnifique."
},
{
"id_comment": 29,
"quote": 13,
"users": 29,
"dateC": "2024-08-01",
"comment": "Citation magnifique."
},
{
"id_comment": 30,
"quote": 11,
"users": 27,
"dateC": "2024-08-02",
"comment": "Citation magnifique."
},
{
"id_comment": 31,
"quote": 18,
"users": 35,
"dateC": "2024-08-03",
"comment": "Citation magnifique."
},
{
"id_comment": 32,
"quote": 13,
"users": 32,
"dateC": "2024-08-04",
"comment": "Citation magnifique."
},
{
"id_comment": 33,
"quote": 13,
"users": 3,
"dateC": "2024-09-01",
"comment": "Citation magnifique."
},
{
"id_comment": 34,
"quote": 15,
"users": 43,
"dateC": "2024-09-02",
"comment": "Citation magnifique."
},
{
"id_comment": 35,
"quote": 11,
"users": 15,
"dateC": "2024-09-03",
"comment": "Citation magnifique."
},
{
"id_comment": 36,
"quote": 10,
"users": 22,
"dateC": "2024-09-04",
"comment": "Citation magnifique."
},
{
"id_comment": 37,
"quote": 17,
"users": 23,
"dateC": "2024-10-01",
"comment": "Citation magnifique."
},
{
"id_comment": 38,
"quote": 14,
"users": 40,
"dateC": "2024-10-02",
"comment": "Citation magnifique."
},
{
"id_comment": 39,
"quote": 15,
"users": 41,
"dateC": "2024-10-03",
"comment": "Citation magnifique."
},
{
"id_comment": 40,
"quote": 16,
"users": 42,
"dateC": "2024-10-04",
"comment": "Citation magnifique."
},
{
"id_comment": 41,
"quote": 10,
"users": 39,
"dateC": "2024-11-01",
"comment": "Citation magnifique."
},
{
"id_comment": 42,
"quote": 17,
"users": 43,
"dateC": "2024-11-02",
"comment": "Citation magnifique."
},
{
"id_comment": 43,
"quote": 13,
"users": 27,
"dateC": "2024-11-03",
"comment": "Citation magnifique."
},
{
"id_comment": 44,
"quote": 12,
"users": 29,
"dateC": "2024-11-04",
"comment": "Citation magnifique."
},
{
"id_comment": 45,
"quote": 11,
"users": 32,
"dateC": "2024-12-01",
"comment": "Citation magnifique."
},
{
"id_comment": 46,
"quote": 15,
"users": 31,
"dateC": "2024-12-02",
"comment": "Citation magnifique."
},
{
"id_comment": 47,
"quote": 18,
"users": 33,
"dateC": "2024-12-03",
"comment": "Citation magnifique."
},
{
"id_comment": 48,
"quote": 14,
"users": 34,
"dateC": "2024-12-04",
"comment": "Citation magnifique."
},
{
"id_comment": 49,
"quote": 19,
"users": 35,
"dateC": "2024-12-05",
"comment": "Citation magnifique."
},
{
"id_comment": 50,
"quote": 17,
"users": 36,
"dateC": "2024-12-06",
"comment": "Citation magnifique."
},
{
"id_comment": 51,
"quote": 16,
"users": 37,
"dateC": "2024-12-07",
"comment": "Citation magnifique."
},
{
"id_comment": 52,
"quote": 13,
"users": 38,
"dateC": "2024-12-08",
"comment": "Citation magnifique."
},
{
"id_comment": 53,
"quote": 12,
"users": 39,
"dateC": "2024-12-09",
"comment": "Citation magnifique."
},
{
"id_comment": 54,
"quote": 11,
"users": 40,
"dateC": "2024-12-10",
"comment": "Citation magnifique."
},
{
"id_comment": 55,
"quote": 10,
"users": 41,
"dateC": "2024-12-11",
"comment": "Citation magnifique."
},
{
"id_comment": 56,
"quote": 9,
"users": 42,
"dateC": "2024-12-12",
"comment": "Citation magnifique."
},
{
"id_comment": 57,
"quote": 8,
"users": 43,
"dateC": "2024-12-13",
"comment": "Citation magnifique."
},
{
"id_comment": 58,
"quote": 7,
"users": 44,
"dateC": "2024-12-14",
"comment": "Citation magnifique."
},
{
"id_comment": 59,
"quote": 6,
"users": 45,
"dateC": "2024-12-15",
"comment": "Citation magnifique."
},
{
"id_comment": 60,
"quote": 5,
"users": 46,
"dateC": "2024-12-16",
"comment": "Citation magnifique."
},
{
"id_comment": 61,
"quote": 4,
"users": 47,
"dateC": "2024-12-17",
"comment": "Citation magnifique."
},
{
"id_comment": 62,
"quote": 3,
"users": 48,
"dateC": "2024-12-18",
"comment": "Citation magnifique."
},
{
"id_comment": 63,
"quote": 2,
"users": 49,
"dateC": "2024-12-19",
"comment": "Citation magnifique."
},
{
"id_comment": 64,
"quote": 1,
"users": 50,
"dateC": "2024-12-20",
"comment": "Citation magnifique."
},
{
"id_comment": 65,
"quote": 19,
"users": 1,
"dateC": "2024-12-21",
"comment": "Citation magnifique."
},
{
"id_comment": 66,
"quote": 18,
"users": 2,
"dateC": "2024-12-22",
"comment": "Citation magnifique."
},
{
"id_comment": 67,
"quote": 17,
"users": 3,
"dateC": "2024-12-23",
"comment": "Citation magnifique."
},
{
"id_comment": 68,
"quote": 16,
"users": 4,
"dateC": "2024-12-24",
"comment": "Citation magnifique."
},
{
"id_comment": 69,
"quote": 15,
"users": 5,
"dateC": "2024-12-25",
"comment": "Citation magnifique."
},
{
"id_comment": 70,
"quote": 14,
"users": 6,
"dateC": "2024-12-26",
"comment": "Citation magnifique."
},
{
"id_comment": 71,
"quote": 13,
"users": 7,
"dateC": "2024-12-27",
"comment": "Citation magnifique."
},
{
"id_comment": 72,
"quote": 12,
"users": 8,
"dateC": "2024-12-28",
"comment": "Citation magnifique."
},
{
"id_comment": 73,
"quote": 11,
"users": 9,
"dateC": "2024-01-01",
"comment": "Citation magnifique."
},
{
"id_comment": 74,
"quote": 10,
"users": 10,
"dateC": "2024-01-02",
"comment": "Citation magnifique."
},
{
"id_comment": 75,
"quote": 9,
"users": 11,
"dateC": "2024-01-03",
"comment": "Citation magnifique."
},
{
"id_comment": 76,
"quote": 8,
"users": 12,
"dateC": "2024-01-04",
"comment": "Citation magnifique."
},
{
"id_comment": 77,
"quote": 7,
"users": 13,
"dateC": "2024-01-05",
"comment": "Citation magnifique."
},
{
"id_comment": 78,
"quote": 6,
"users": 14,
"dateC": "2024-01-06",
"comment": "Citation magnifique."
},
{
"id_comment": 79,
"quote": 5,
"users": 15,
"dateC": "2024-01-07",
"comment": "Citation magnifique."
},
{
"id_comment": 80,
"quote": 4,
"users": 16,
"dateC": "2024-01-08",
"comment": "Citation magnifique."
},
{
"id_comment": 81,
"quote": 3,
"users": 17,
"dateC": "2024-01-09",
"comment": "Citation magnifique."
},
{
"id_comment": 82,
"quote": 2,
"users": 18,
"dateC": "2024-01-10",
"comment": "Citation magnifique."
},
{
"id_comment": 83,
"quote": 15,
"users": 33,
"dateC": "2024-06-24",
"comment": "Citation exceptionnelle."
},
{
"id_comment": 84,
"quote": 19,
"users": 15,
"dateC": "2024-03-11",
"comment": "Citation merveilleuse."
},
{
"id_comment": 85,
"quote": 4,
"users": 16,
"dateC": "2024-01-19",
"comment": "Citation merveilleuse."
},
{
"id_comment": 86,
"quote": 10,
"users": 20,
"dateC": "2024-01-15",
"comment": "Très émouvant."
},
{
"id_comment": 87,
"quote": 3,
"users": 33,
"dateC": "2024-12-17",
"comment": "Très touchant."
},
{
"id_comment": 88,
"quote": 5,
"users": 8,
"dateC": "2024-07-01",
"comment": "Citation exceptionnelle."
},
{
"id_comment": 89,
"quote": 13,
"users": 28,
"dateC": "2024-02-20",
"comment": "Citation merveilleuse."
},
{
"id_comment": 90,
"quote": 18,
"users": 24,
"dateC": "2024-09-16",
"comment": "Citation merveilleuse."
},
{
"id_comment": 91,
"quote": 17,
"users": 43,
"dateC": "2024-06-20",
"comment": "Très réfléchi."
},
{
"id_comment": 92,
"quote": 13,
"users": 36,
"dateC": "2024-11-08",
"comment": "Super citation !"
},
{
"id_comment": 93,
"quote": 19,
"users": 41,
"dateC": "2024-01-20",
"comment": "Super citation !"
},
{
"id_comment": 94,
"quote": 13,
"users": 10,
"dateC": "2024-05-03",
"comment": "Citation magnifique."
},
{
"id_comment": 95,
"quote": 4,
"users": 49,
"dateC": "2024-07-01",
"comment": "Citation profonde."
},
{
"id_comment": 96,
"quote": 16,
"users": 21,
"dateC": "2024-11-08",
"comment": "Citation merveilleuse."
},
{
"id_comment": 97,
"quote": 14,
"users": 27,
"dateC": "2024-11-20",
"comment": "Citation puissante."
},
{
"id_comment": 98,
"quote": 4,
"users": 39,
"dateC": "2024-12-11",
"comment": "Très motivant."
},
{
"id_comment": 99,
"quote": 9,
"users": 26,
"dateC": "2024-09-27",
"comment": "Paroles sages."
},
{
"id_comment": 100,
"quote": 3,
"users": 42,
"dateC": "2024-02-12",
"comment": "Citation merveilleuse."
}
]

@ -0,0 +1,9 @@
[
{
"id_comment": 1,
"quote": 1,
"users": 1,
"dateC":"2024-10-10",
"comment": "coucou"
}
]

@ -1,14 +1,12 @@
[
{
"Id": 11,
"Content": "Vous ne pouvez pas vivre sans causer de dommages \u00E0 quelqu\u0027un d\u0027autre.",
"Like": 110,
"Id": "1",
"Content": "Dans le monde il ny a pas dun côté le bien et le mal, il y a une part de lumière et dombre en chacun de nous. Ce qui compte cest celle que lon choisit de montrer dans nos actes, ça cest ce que lon est vraiment.",
"Likes": 0,
"Langue": "fr",
"Charac": "test",
"ImgPath": "http://thematrix.com",
"TitleSrc": "The Matrix",
"DateSrc": "2025-01-21T00:00:00",
"UserProposition": "user11",
"IsValid": false
"Charac": "Superman",
"TitleSrc": "SuperMan : le film",
"UserProposition": "joe",
"ImgPath": "https://tse4.mm.bing.net/th/id/OIP.fc5TQflh0cbxB1GUeOdk6gHaK8?w=123&h=180&c=7&r=0&o=5&pid=1.7"
}
]

@ -1,7 +1,7 @@
[
{
"Id": 1,
"Content": "Que la force soit avec toi",
"Content": "Que la force soit avec toi.",
"Like": 150,
"Langue": "en",
"Charac": "Drago Malefoy",
@ -25,7 +25,7 @@
},
{
"Id": 3,
"Content": "C\u0027est le choix qui fait l\u0027homme, non le destin",
"Content": "C\u0027est le choix qui fait l\u0027homme, non le destin.",
"Like": 90,
"Langue": "fr",
"Charac": "test",

@ -1,261 +0,0 @@
[
{
"LogLevel": 1,
"Message": "Logs de test"
},
{
"LogLevel": 2,
"Message": "User testeur1 is no longer an administator"
},
{
"LogLevel": 2,
"Message": "User dev is now administrator"
},
{
"LogLevel": 2,
"Message": "Modification of user testeur"
},
{
"LogLevel": 2,
"Message": "Delete user jane_smith"
},
{
"LogLevel": 2,
"Message": "Editing the quote C\u0027est le choix qui fait l\u0027homme, non le destin."
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
<<<<<<< HEAD
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
},
{
"LogLevel": 2,
"Message": "Random change of quote of the day"
=======
>>>>>>> c9a9e592d46e0842b954daa1f9b008f8302e78ad
}
]

@ -1,4 +1,26 @@
[
{
"Id": 9,
"Question": "Question_quiz_1",
"AnswerA": "rep_1",
"AnswerB": "rep_2",
"AnswerC": "rep_3",
"AnswerD": "rep_3",
"CAnswer": "A",
"IsValid": false,
"UserProposition": "Earnestine Poole"
},
{
"Id": 10,
"Question": "Voluptate pariatur ipsum magna sint Lorem adipisicing.",
"AnswerA": "sint velit",
"AnswerB": "non culpa",
"AnswerC": "nisi ut",
"AnswerD": "excepteur labore",
"CAnswer": "B",
"IsValid": false,
"UserProposition": "Alexis Cross"
},
{
"Id": 11,
"Question": "nv question",
@ -7,19 +29,19 @@
"AnswerC": "do officia",
"AnswerD": "ut nostrud",
"CAnswer": "C",
"IsValid": true,
"IsValid": false,
"UserProposition": "Brooks Martinez"
},
{
"Id": 12,
"Question": "question",
"AnswerA": "repA",
"AnswerB": "non",
"AnswerC": "do",
"AnswerD": "ut",
"CAnswer": "A",
"Question": "Irure occaecat sit laborum nulla ea dolore et aliqua sunt Lorem enim esse.",
"AnswerA": "excepteur occaecat",
"AnswerB": "pariatur in",
"AnswerC": "reprehenderit excepteur",
"AnswerD": "laborum adipisicing",
"CAnswer": "D",
"IsValid": false,
"UserProposition": "Brooks Martinez"
"UserProposition": "Shields Roth"
},
{
"Id": 13,
@ -38,7 +60,7 @@
"AnswerA": "ca",
"AnswerB": "va",
"AnswerC": "marcher",
"AnswerD": "L",
"AnswerD": "!",
"CAnswer": "A",
"IsValid": true,
"UserProposition": "Admin"

@ -5,13 +5,11 @@
"Name": "testeur",
"Email": "testeur@gmail.com",
"DateCreation": "2024-08-02T00:00:00",
"IsAdmin": false,
"IsAdmin": true,
"Comments": [
{
"Id": 0,
"IdUser": 0,
"DateCreation": "2024-08-02T00:00:00",
"Text": "Premier test effectu\u00E9, tout semble OK."
"Text": "Premier test effectu\u00E9, tout semble OK.",
"DateCreation": "2024-08-02T00:00:00"
}
]
},
@ -21,7 +19,7 @@
"Name": "dev",
"Email": "dev@gmail.com",
"DateCreation": "2024-10-10T00:00:00",
"IsAdmin": true,
"IsAdmin": false,
"Comments": null
},
{
@ -33,13 +31,20 @@
"IsAdmin": false,
"Comments": [
{
"Id": 0,
"IdUser": 0,
"DateCreation": "2024-06-25T00:00:00",
"Text": "Utilisateur tr\u00E8s actif, peut \u00EAtre un peu trop intrusif."
"Text": "Utilisateur tr\u00E8s actif, peut \u00EAtre un peu trop intrusif.",
"DateCreation": "2024-06-25T00:00:00"
}
]
},
{
"Id": 6,
"Image": "https://tse2.mm.bing.net/th/id/OIP.MMpXBB5RDRYQm05FJmevGAHaKl?w=137\u0026h=195\u0026c=7\u0026r=0\u0026o=5\u0026pid=1.7",
"Name": "jane_smith",
"Email": "jane.smith@gmail.com",
"DateCreation": "2024-07-15T00:00:00",
"IsAdmin": false,
"Comments": null
},
{
"Id": 7,
"Image": "https://tse2.mm.bing.net/th/id/OIP.MMpXBB5RDRYQm05FJmevGAHaKl?w=137\u0026h=195\u0026c=7\u0026r=0\u0026o=5\u0026pid=1.7",
@ -49,6 +54,29 @@
"IsAdmin": false,
"Comments": null
},
{
"Id": 8,
"Image": "https://tse2.mm.bing.net/th/id/OIP.MMpXBB5RDRYQm05FJmevGAHaKl?w=137\u0026h=195\u0026c=7\u0026r=0\u0026o=5\u0026pid=1.7",
"Name": "dev_anna",
"Email": "dev.anna@gmail.com",
"DateCreation": "2024-09-05T00:00:00",
"IsAdmin": false,
"Comments": null
},
{
"Id": 9,
"Image": "https://tse2.mm.bing.net/th/id/OIP.MMpXBB5RDRYQm05FJmevGAHaKl?w=137\u0026h=195\u0026c=7\u0026r=0\u0026o=5\u0026pid=1.7",
"Name": "support_mark",
"Email": "support.mark@gmail.com",
"DateCreation": "2024-11-20T00:00:00",
"IsAdmin": false,
"Comments": [
{
"Text": "Support rapide et efficace, mais manquant un peu de d\u00E9tails.",
"DateCreation": "2024-11-20T00:00:00"
}
]
},
{
"Id": 10,
"Image": "https://th.bing.com/th/id/OIP.24T00MDK-RUhFnm1Do5PFwHaFj?w=229\u0026h=180\u0026c=7\u0026r=0\u0026o=5\u0026pid=1.7",
@ -66,5 +94,14 @@
"DateCreation": "2024-09-22T00:00:00",
"IsAdmin": false,
"Comments": null
},
{
"Id": 14,
"Image": "https://tse2.mm.bing.net/th/id/OIP.MMpXBB5RDRYQm05FJmevGAHaKl?w=137\u0026h=195\u0026c=7\u0026r=0\u0026o=5\u0026pid=1.7",
"Name": "developer_mike",
"Email": "developer.mike@gmail.com",
"DateCreation": "2024-11-02T00:00:00",
"IsAdmin": false,
"Comments": null
}
]
Loading…
Cancel
Save