37 Commits

Author SHA1 Message Date
5f5ae527f6 Update .gitea/workflows/review.yaml
All checks were successful
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m29s
2026-02-05 14:45:54 +00:00
Renovate Bot
709d19649d Update dotnet monorepo to v10
All checks were successful
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m24s
2026-02-05 10:19:51 +00:00
e6d0dda44d Delete .gitea/workflows/renovate.yaml
All checks were successful
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m25s
Generation data pour merge sur master / generateData (pull_request) Successful in 2m27s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m29s
Pas necessaire
2025-04-17 12:17:18 +02:00
Renovate Bot
556204cfec Update ghcr.io/renovatebot/renovate Docker tag to v39.235.2
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m33s
Generation data pour merge sur master / generateData (pull_request) Successful in 10s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m26s
renovate / renovate (push) Failing after 8s
2025-04-08 00:01:18 +00:00
Renovate Bot
409ee35f40 Update ghcr.io/renovatebot/renovate Docker tag to v39.233.5
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m26s
Generation data pour merge sur master / generateData (pull_request) Successful in 9s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m35s
renovate / renovate (push) Failing after 44s
2025-04-07 00:00:42 +00:00
Renovate Bot
f8a288f965 Update ghcr.io/renovatebot/renovate Docker tag to v39.233.3
All checks were successful
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m27s
Generation data pour merge sur master / generateData (pull_request) Successful in 9s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m21s
2025-04-05 00:00:43 +00:00
Renovate Bot
28b58585d4 Update ghcr.io/renovatebot/renovate Docker tag to v39.232.0
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m26s
Generation data pour merge sur master / generateData (pull_request) Successful in 10s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m26s
renovate / renovate (push) Failing after 8s
2025-04-02 13:54:03 +00:00
Renovate Bot
3c29fcd1f9 Update ghcr.io/renovatebot/renovate Docker tag to v39.230.1
All checks were successful
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 2m28s
Generation data pour merge sur master / generateData (pull_request) Successful in 9s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m24s
2025-04-02 00:00:46 +00:00
Renovate Bot
319da32a35 Update ghcr.io/renovatebot/renovate Docker tag to v39.219.2
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m28s
Generation data pour merge sur master / generateData (pull_request) Successful in 2m39s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m26s
renovate / renovate (push) Failing after 8s
2025-03-27 15:40:16 +00:00
Renovate Bot
813af8d923 Update ghcr.io/renovatebot/renovate Docker tag to v39.205.0
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m21s
Generation data pour merge sur master / generateData (pull_request) Successful in 2m29s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m27s
renovate / renovate (push) Failing after 7s
2025-03-17 00:00:55 +00:00
Renovate Bot
2140e81aeb Update ghcr.io/renovatebot/renovate Docker tag to v39.185.7
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 3m22s
Generation data pour merge sur master / generateData (pull_request) Successful in 4m13s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m31s
renovate / renovate (push) Failing after 7s
2025-03-04 00:01:28 +00:00
Renovate Bot
7478589124 Update ghcr.io/renovatebot/renovate Docker tag to v39.173.1
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m28s
Generation data pour merge sur master / generateData (pull_request) Failing after 2h12m15s
Generation data pour merge sur master / reviewProcess (push) Successful in 3m8s
renovate / renovate (push) Failing after 8s
2025-02-19 00:00:48 +00:00
Renovate Bot
d6ac91c080 Update ghcr.io/renovatebot/renovate Docker tag to v39.63.1
All checks were successful
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m2s
Generation data pour merge sur master / generateData (pull_request) Successful in 1m40s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m4s
2024-12-12 23:00:58 +00:00
Renovate Bot
a8d477b529 Update ghcr.io/renovatebot/renovate Docker tag to v39.13.1
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m0s
Generation data pour merge sur master / generateData (pull_request) Successful in 10s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m2s
renovate / renovate (push) Failing after 8s
2024-11-13 23:01:26 +00:00
Renovate Bot
a35124adc7 Update ghcr.io/renovatebot/renovate Docker tag to v39.11.4
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m0s
Generation data pour merge sur master / generateData (pull_request) Successful in 1m37s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m0s
renovate / renovate (push) Failing after 44s
2024-11-12 23:00:52 +00:00
Renovate Bot
924ba6f187 Update ghcr.io/renovatebot/renovate Docker tag to v39
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 55s
Generation data pour merge sur master / generateData (pull_request) Successful in 11s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m1s
renovate / renovate (push) Failing after 8s
2024-11-10 23:00:50 +00:00
Renovate Bot
2a03502692 Update ghcr.io/renovatebot/renovate Docker tag to v38.142.7
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m0s
Generation data pour merge sur master / generateData (pull_request) Successful in 11s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m2s
renovate / renovate (push) Failing after 8s
2024-11-04 23:01:05 +00:00
Renovate Bot
b2d007c271 Update ghcr.io/renovatebot/renovate Docker tag to v38.142.5
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m0s
Generation data pour merge sur master / generateData (pull_request) Successful in 11s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m4s
renovate / renovate (push) Failing after 23s
2024-11-03 23:01:05 +00:00
Renovate Bot
443bccb2ed Update ghcr.io/renovatebot/renovate Docker tag to v38.142.3
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 59s
Generation data pour merge sur master / generateData (pull_request) Successful in 10s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m0s
renovate / renovate (push) Failing after 24s
2024-11-02 23:01:38 +00:00
Renovate Bot
08f4d88969 Update ghcr.io/renovatebot/renovate Docker tag to v38.142.2
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m1s
Generation data pour merge sur master / generateData (pull_request) Successful in 11s
Generation data pour merge sur master / reviewProcess (push) Successful in 58s
renovate / renovate (push) Failing after 55s
2024-11-01 23:00:56 +00:00
Renovate Bot
15d2aa9416 Update ghcr.io/renovatebot/renovate Docker tag to v38.138.4
All checks were successful
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m0s
Generation data pour merge sur master / generateData (pull_request) Successful in 11s
Generation data pour merge sur master / reviewProcess (push) Successful in 2m3s
2024-10-30 23:01:10 +00:00
Renovate Bot
1463b35998 Update ghcr.io/renovatebot/renovate Docker tag to v38.135.2
All checks were successful
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 56s
Generation data pour merge sur master / generateData (pull_request) Successful in 11s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m6s
2024-10-29 23:01:11 +00:00
Renovate Bot
26e8a9c355 Update ghcr.io/renovatebot/renovate Docker tag to v38.132.3
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m4s
Generation data pour merge sur master / generateData (pull_request) Successful in 10s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m1s
renovate / renovate (push) Failing after 12s
2024-10-27 23:01:42 +00:00
Renovate Bot
36b6677506 Update ghcr.io/renovatebot/renovate Docker tag to v38.132.1
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m2s
Generation data pour merge sur master / generateData (pull_request) Successful in 11s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m2s
renovate / renovate (push) Failing after 42s
2024-10-26 22:01:09 +00:00
Renovate Bot
978f2ed552 Update ghcr.io/renovatebot/renovate Docker tag to v38.130.2
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m3s
Generation data pour merge sur master / generateData (pull_request) Successful in 11s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m1s
renovate / renovate (push) Failing after 8s
2024-10-23 22:01:45 +00:00
Renovate Bot
b8ed2d0909 Update ghcr.io/renovatebot/renovate Docker tag to v38.130.0
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m2s
Generation data pour merge sur master / generateData (pull_request) Successful in 11s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m2s
renovate / renovate (push) Failing after 44s
2024-10-22 22:01:54 +00:00
Renovate Bot
40caa952d2 Update ghcr.io/renovatebot/renovate Docker tag to v38.129.1
Some checks failed
Generation data pour merge sur master / reviewProcess (push) Successful in 1m29s
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m4s
Generation data pour merge sur master / generateData (pull_request) Successful in 21s
renovate / renovate (push) Failing after 53s
2024-10-22 09:38:21 +02:00
Renovate Bot
01534fbace Update ghcr.io/renovatebot/renovate Docker tag to v38.127.0
All checks were successful
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m11s
Generation data pour merge sur master / generateData (pull_request) Successful in 11s
2024-10-18 05:30:09 +00:00
Renovate Bot
cdaf6c7575 Update ghcr.io/renovatebot/renovate Docker tag to v38.124.3
All checks were successful
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 2m24s
Generation data pour merge sur master / generateData (pull_request) Successful in 3m35s
2024-10-17 07:02:48 +00:00
Renovate Bot
e857207486 Update ghcr.io/renovatebot/renovate Docker tag to v38
All checks were successful
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 2m34s
Generation data pour merge sur master / generateData (pull_request) Successful in 2m0s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m14s
2024-10-12 07:26:42 +00:00
Renovate Bot
3cfea65a75 Update postgres Docker tag to v17
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m25s
Generation data pour merge sur master / generateData (pull_request) Successful in 2m41s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m43s
renovate / renovate (push) Failing after 11s
2024-09-28 00:01:43 +00:00
ba9eb7cfb3 Suppression de renovate suir les push sur main
Some checks failed
Generation data pour merge sur master / reviewProcess (push) Successful in 1m33s
renovate / renovate (push) Failing after 16s
2024-09-26 11:36:46 +00:00
Renovate Bot
86db6fa3b9 Update dotnet monorepo to v9
Some checks failed
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m43s
Generation data pour merge sur master / generateData (pull_request) Successful in 2m46s
renovate / renovate (push) Failing after 33s
Generation data pour merge sur master / reviewProcess (push) Successful in 1m46s
2024-09-19 21:41:46 +00:00
6afeb6e30d Ajout d'un cron renovate pour les dependances
Some checks failed
Generation data pour merge sur master / reviewProcess (push) Has been cancelled
renovate / renovate (push) Failing after 16s
2024-09-17 09:42:32 +02:00
16275e3cd5 ajout d'un premier test pour l'affichage des jeux
All checks were successful
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 3m10s
Generation data pour merge sur master / generateData (pull_request) Successful in 1m41s
Generation data pour merge sur master / reviewProcess (push) Successful in 2m0s
2024-09-10 22:57:19 +02:00
0cde51e01c nettoyage des warning, ajout de localization
All checks were successful
Generation data pour merge sur master / reviewProcess (pull_request) Successful in 1m21s
Generation data pour merge sur master / generateData (pull_request) Successful in 1m31s
Generation data pour merge sur master / generateData (push) Has been skipped
Generation data pour merge sur master / reviewProcess (push) Successful in 1m16s
2024-09-09 23:16:34 +02:00
cd4788b2b0 Ajout de 2 workflows pour les merges et reviews
All checks were successful
Generation data pour merge sur master / generateData (push) Has been skipped
Generation data pour merge sur master / reviewProcess (push) Successful in 1m12s
2024-09-08 22:26:56 +02:00
36 changed files with 905 additions and 154 deletions

View File

@@ -6,6 +6,7 @@ root = true
dotnet_diagnostic.IDE1006.severity = warning
dotnet_diagnostic.IDE0005.severity = error
dotnet_diagnostic.CA5394.severity = none
dotnet_diagnostic.CA1848.severity = none #optimisatio logger pas nécessaire
# Exclude generated code
[src/**/Migrations/*.cs]

View File

@@ -1,40 +1,36 @@
name: "Main Build Process"
name: "Generation data pour merge sur master"
# Runs on main branch commits,
# every commit in a pull request, any published release.
on:
push:
branches: ["main"]
pull_request:
types:
- closed
branches: ["main"]
release:
types: [published]
jobs:
asciidoc:
name: "generate documentation"
generateData:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Get build container
id: adocbuild
uses: tonynv/asciidoctor-action@master
with:
program: "asciidoctor -D docs --backend=html5 -o index.html documentation/readme.adoc"
- name: Print execution time
run: echo "Time ${{ steps.adocbuild.outputs.time }}"
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: Doc
path: ./docs
retention-days: 5
- name: ls
run: ls
- name: build docker images
run: docker build -t gitea.borealian.ovh/mcmuzzle/ludikzone:latest -f ./docker-prod/Dockerfile .
- name: upload image
run: echo "${{ secrets.PERSO_GITEAPASSWORD}}" | docker login gitea.borealian.ovh --username mcmuzzle --password-stdin
- name: Checkout code
uses: actions/checkout@v2
- name: Get build container
id: adocbuild
uses: tonynv/asciidoctor-action@master
with:
program: "asciidoctor -D docs --backend=html5 -o index.html documentation/readme.adoc"
- name: Print execution time
run: echo "Time ${{ steps.adocbuild.outputs.time }}"
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: Doc
path: ./docs
retention-days: 5
- name: build docker images
run: docker build -t gitea.borealian.ovh/mcmuzzle/ludikzone:latest -f ./docker-prod/Dockerfile .
- name: upload image
run: |
echo "${{ secrets.PERSO_GITEAPASSWORD}}" | docker login gitea.borealian.ovh --username mcmuzzle --password-stdin
docker push gitea.borealian.ovh/mcmuzzle/ludikzone:latest

View File

@@ -0,0 +1,27 @@
name: "Generation data pour merge sur master"
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
jobs:
reviewProcess:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Setup dotnet
uses: actions/setup-dotnet@v3
with:
dotnet-version: '10.0.x'
- name: Install dependencies
run: dotnet restore ./src/LudikZone.sln
- name: Build
run: dotnet build ./src/LudikZone.sln
- name: Test with the dotnet CLI
run: dotnet test ./src/LudikZone.sln

3
.gitignore vendored
View File

@@ -19,4 +19,5 @@ tools/
TestResults
#docker data
/docker-dev/data
/docker-dev/data
/docker-prod/data

View File

@@ -1,6 +1,6 @@
services:
postgresql:
image: postgres:16
image: postgres:17
ports:
- "${DB_PORT:-5432}:5432"
volumes:

5
docker-prod/.env Normal file
View File

@@ -0,0 +1,5 @@
DB_HOST="postgresql"
DB_PORT=5432
DB_USER="admin"
DB_PASSWORD="admin"
DB_DATABASE="ludikZone"

5
docker-prod/.env.example Normal file
View File

@@ -0,0 +1,5 @@
DB_HOST="localhost"
DB_PORT=5432
DB_USER="admin"
DB_PASSWORD="admin"
DB_DATABASE="ludikZone"

21
docker-prod/Dockerfile Normal file
View File

@@ -0,0 +1,21 @@
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY ["src/LudikZoneBlazor/LudikZoneBlazor.csproj", "src/LudikZoneBlazor/LudikZoneBlazor.csproj"]
RUN dotnet restore "src/LudikZoneBlazor/LudikZoneBlazor.csproj"
COPY src src
RUN ls -a -l
RUN dotnet build "src/LudikZoneBlazor/LudikZoneBlazor.csproj" -c Release -o /app/build
FROM build AS publish
WORKDIR /src
RUN dotnet publish "src/LudikZoneBlazor/LudikZoneBlazor.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "LudikZoneBlazor.dll"]

24
docker-prod/compose.yml Normal file
View File

@@ -0,0 +1,24 @@
services:
postgresql:
image: postgres:17
ports:
- "${DB_PORT:-5432}:5432"
volumes:
- ./data/postgres/:/var/lib/postgresql/data
environment:
- POSTGRES_DB=${DB_DATABASE:-ludikZone}
- POSTGRES_USER=${DB_USER:-admin}
- POSTGRES_PASSWORD=${DB_PASSWORD:-admin}
ludikzone:
image: gitea.borealian.ovh/mcmuzzle/ludikzone:latest
ports:
- 8080:8080
environment:
- DB_HOST=${DB_HOST:-"postgresql"}
- DB_PORT=${DB_PORT:-5432}
- DB_USER=${DB_USER:-"admin"}
- DB_PASSWORD=${DB_PASSWORD:-"admin"}
- DB_DATABASE=${DB_DATABASE:-"ludikZone"}
depends_on:
- postgresql

11
renovate.json Normal file
View File

@@ -0,0 +1,11 @@
{
"extends": [
"config:base"
],
"packageRules": [
{
"updateTypes": ["minor", "patch", "pin", "digest"],
"automerge": false
}
]
}

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<AnalysisMode>All</AnalysisMode>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,20 @@
namespace LudikZone.model;
/// <summary>
/// Informations relative a un jeu précis
/// </summary>
public class Game
{
/// <summary> Identifiant unique d'un jeu </summary>
public int Id { get; init; }
/// <summary> le nom du jeu </summary>
public required string Name { get; init; }
/// <summary> Le nombre minimum de joueur pour une partie </summary>
public int MinPlayerCount { get; init; }
/// <summary> Le nombre maximum de joueur pour une partie </summary>
public int MaxPlayerCount { get; init; }
}

View File

@@ -5,6 +5,8 @@ VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LudikZoneBlazor", "LudikZoneBlazor\LudikZoneBlazor.csproj", "{79AF398A-0AC3-425C-BA51-B6CFBEECAC28}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LudikZone.model", "LudikZone.model\LudikZone.model.csproj", "{C50658FF-0EE9-4EE8-AAA3-FAF4B9F622EA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -18,5 +20,9 @@ Global
{79AF398A-0AC3-425C-BA51-B6CFBEECAC28}.Debug|Any CPU.Build.0 = Debug|Any CPU
{79AF398A-0AC3-425C-BA51-B6CFBEECAC28}.Release|Any CPU.ActiveCfg = Release|Any CPU
{79AF398A-0AC3-425C-BA51-B6CFBEECAC28}.Release|Any CPU.Build.0 = Release|Any CPU
{C50658FF-0EE9-4EE8-AAA3-FAF4B9F622EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C50658FF-0EE9-4EE8-AAA3-FAF4B9F622EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C50658FF-0EE9-4EE8-AAA3-FAF4B9F622EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C50658FF-0EE9-4EE8-AAA3-FAF4B9F622EA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@@ -45,7 +45,7 @@ internal static class IdentityComponentsEndpointRouteBuilderExtensions
SignInManager<ApplicationUser> signInManager,
[FromForm] string returnUrl) =>
{
await signInManager.SignOutAsync();
await signInManager.SignOutAsync().ConfigureAwait(true);
return TypedResults.LocalRedirect($"~/{returnUrl}");
});
@@ -57,7 +57,7 @@ internal static class IdentityComponentsEndpointRouteBuilderExtensions
[FromForm] string provider) =>
{
// Clear the existing external cookie to ensure a clean login process
await context.SignOutAsync(IdentityConstants.ExternalScheme);
await context.SignOutAsync(IdentityConstants.ExternalScheme).ConfigureAwait(false);
var redirectUrl = UriHelper.BuildRelative(
context.Request.PathBase,
@@ -76,13 +76,13 @@ internal static class IdentityComponentsEndpointRouteBuilderExtensions
[FromServices] UserManager<ApplicationUser> userManager,
[FromServices] AuthenticationStateProvider authenticationStateProvider) =>
{
var user = await userManager.GetUserAsync(context.User);
var user = await userManager.GetUserAsync(context.User).ConfigureAwait(false);
if (user is null)
{
return Results.NotFound($"Unable to load user with ID '{userManager.GetUserId(context.User)}'.");
}
var userId = await userManager.GetUserIdAsync(user);
var userId = await userManager.GetUserIdAsync(user).ConfigureAwait(false);
downloadLogger.LogInformation("User with ID '{UserId}' asked for their personal data.", userId);
// Only include personal data for download
@@ -94,13 +94,13 @@ internal static class IdentityComponentsEndpointRouteBuilderExtensions
personalData.Add(p.Name, p.GetValue(user)?.ToString() ?? "null");
}
var logins = await userManager.GetLoginsAsync(user);
var logins = await userManager.GetLoginsAsync(user).ConfigureAwait(false);
foreach (var l in logins)
{
personalData.Add($"{l.LoginProvider} external login provider key", l.ProviderKey);
}
personalData.Add("Authenticator Key", (await userManager.GetAuthenticatorKeyAsync(user))!);
personalData.Add("Authenticator Key", (await userManager.GetAuthenticatorKeyAsync(user).ConfigureAwait(false))!);
var fileBytes = JsonSerializer.SerializeToUtf8Bytes(personalData);
context.Response.Headers.TryAdd("Content-Disposition", "attachment; filename=PersonalData.json");

View File

@@ -4,10 +4,12 @@ using LudikZoneBlazor.Data;
namespace LudikZoneBlazor.Components.Account;
// Remove the "else if (EmailSender is IdentityNoOpEmailSender)" block from RegisterConfirmation.razor after updating with a real implementation.
#pragma warning disable CA1812 // Elle est instanciée en Injection de dependance
/// <summary> Remove the "else if (EmailSender is IdentityNoOpEmailSender)" block from RegisterConfirmation.razor after updating with a real implementation. </summary>
internal sealed class IdentityNoOpEmailSender : IEmailSender<ApplicationUser>
{
private readonly IEmailSender emailSender = new NoOpEmailSender();
private readonly NoOpEmailSender emailSender = new NoOpEmailSender();
public Task SendConfirmationLinkAsync(ApplicationUser user, string email, string confirmationLink) =>
emailSender.SendEmailAsync(email, "Confirm your email", $"Please confirm your account by <a href='{confirmationLink}'>clicking here</a>.");
@@ -18,3 +20,5 @@ internal sealed class IdentityNoOpEmailSender : IEmailSender<ApplicationUser>
public Task SendPasswordResetCodeAsync(ApplicationUser user, string email, string resetCode) =>
emailSender.SendEmailAsync(email, "Reset your password", $"Please reset your password using the following code: {resetCode}");
}
#pragma warning restore CA1812

View File

@@ -3,6 +3,8 @@ using Microsoft.AspNetCore.Components;
namespace LudikZoneBlazor.Components.Account;
#pragma warning disable CA1812 // Elle est instanciée en Injection de dependance
internal sealed class IdentityRedirectManager(NavigationManager navigationManager)
{
public const string StatusCookieName = "Identity.StatusMessage";
@@ -56,3 +58,5 @@ internal sealed class IdentityRedirectManager(NavigationManager navigationManage
public void RedirectToCurrentPageWithStatus(string message, HttpContext context)
=> RedirectToWithStatus(CurrentPath, message, context);
}
#pragma warning restore CA1812

View File

@@ -7,6 +7,8 @@ using LudikZoneBlazor.Data;
namespace LudikZoneBlazor.Components.Account;
#pragma warning disable CA1812 // Elle est instanciée en Injection de dependance
// This is a server-side AuthenticationStateProvider that revalidates the security stamp for the connected user
// every 30 minutes an interactive circuit is connected.
internal sealed class IdentityRevalidatingAuthenticationStateProvider(
@@ -21,14 +23,14 @@ internal sealed class IdentityRevalidatingAuthenticationStateProvider(
AuthenticationState authenticationState, CancellationToken cancellationToken)
{
// Get the user manager from a new scope to ensure it fetches fresh data
await using var scope = scopeFactory.CreateAsyncScope();
using AsyncServiceScope scope = scopeFactory.CreateAsyncScope();
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
return await ValidateSecurityStampAsync(userManager, authenticationState.User);
return await ValidateSecurityStampAsync(userManager, authenticationState.User).ConfigureAwait(false);
}
private async Task<bool> ValidateSecurityStampAsync(UserManager<ApplicationUser> userManager, ClaimsPrincipal principal)
{
var user = await userManager.GetUserAsync(principal);
var user = await userManager.GetUserAsync(principal).ConfigureAwait(false);
if (user is null)
{
return false;
@@ -40,8 +42,10 @@ internal sealed class IdentityRevalidatingAuthenticationStateProvider(
else
{
var principalStamp = principal.FindFirstValue(options.Value.ClaimsIdentity.SecurityStampClaimType);
var userStamp = await userManager.GetSecurityStampAsync(user);
var userStamp = await userManager.GetSecurityStampAsync(user).ConfigureAwait(false);
return principalStamp == userStamp;
}
}
}
#pragma warning restore CA1812

View File

@@ -3,11 +3,13 @@ using LudikZoneBlazor.Data;
namespace LudikZoneBlazor.Components.Account;
#pragma warning disable CA1812 // Elle est instanciée en Injection de dependance
internal sealed class IdentityUserAccessor(UserManager<ApplicationUser> userManager, IdentityRedirectManager redirectManager)
{
public async Task<ApplicationUser> GetRequiredUserAsync(HttpContext context)
{
var user = await userManager.GetUserAsync(context.User);
var user = await userManager.GetUserAsync(context.User).ConfigureAwait(false);
if (user is null)
{
@@ -17,3 +19,5 @@ internal sealed class IdentityUserAccessor(UserManager<ApplicationUser> userMana
return user;
}
}
#pragma warning restore CA1812

View File

@@ -0,0 +1,10 @@
@using LudikZone.model
<MudPaper Height="140px" Width="140px">
@Game.Name
</MudPaper>
@code {
[Parameter]
public required Game Game { get; set; }
}

View File

@@ -4,12 +4,11 @@
<MudNavMenu>
<MudNavLink Href="" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.Home">Home</MudNavLink>
<MudNavLink Href="counter" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Add">Counter</MudNavLink>
<MudNavLink Href="weather" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.List">Weather</MudNavLink>
<MudNavLink Href="auth" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Lock">Auth Required</MudNavLink>
<MudNavLink Href="Games" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.VideogameAsset">Games</MudNavLink>
<AuthorizeView>
<Authorized>
<MudNavLink Href="Account/Manage" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Person">@context.User.Identity?.Name</MudNavLink>
<MudNavLink Href="Account/Manage" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Person">
@context.User.Identity?.Name</MudNavLink>
<form action="Account/Logout" method="post">
<AntiforgeryToken />
<input type="hidden" name="ReturnUrl" value="@currentUrl" />
@@ -19,8 +18,10 @@
</form>
</Authorized>
<NotAuthorized>
<MudNavLink Href="Account/Register" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Person">Register</MudNavLink>
<MudNavLink Href="Account/Login" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Password">Login</MudNavLink>
<MudNavLink Href="Account/Register" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Person">
Register</MudNavLink>
<MudNavLink Href="Account/Login" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Password">Login
</MudNavLink>
</NotAuthorized>
</AuthorizeView>
</MudNavMenu>
@@ -46,5 +47,3 @@
NavigationManager.LocationChanged -= OnLocationChanged;
}
}

View File

@@ -1,14 +0,0 @@
@page "/auth"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
<PageTitle>Auth</PageTitle>
<MudText Typo="Typo.h3" GutterBottom="true">You are authenticated!</MudText>
<AuthorizeView>
<MudText Class="mb-4">Hello @context.User.Identity?.Name!</MudText>
</AuthorizeView>

View File

@@ -1,18 +0,0 @@
@page "/counter"
<PageTitle>Counter</PageTitle>
<MudText Typo="Typo.h3" GutterBottom="true">Counter</MudText>
<MudText Typo="Typo.body1" Class="mb-4">Current count: @currentCount</MudText>
<MudButton Color="Color.Primary" Variant="Variant.Filled" @onclick="IncrementCount">Click me</MudButton>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}

View File

@@ -0,0 +1,31 @@
@page "/games"
@using LudikZoneBlazor.Components.Games
@using LudikZoneBlazor.Data
@using Microsoft.AspNetCore.Authorization
@using LudikZone.model
@inject IStringLocalizer<Games> localizer
@inject ApplicationDbContext context
<PageTitle>@localizer["Games"]</PageTitle>
<MudText Typo="Typo.h3" GutterBottom="true">@localizer["Game list"]</MudText>
<MudGrid Spacing="10" Justify="Justify.Center">
@foreach (var g in GetGames())
{
<MudItem>
<GameIcon Game=@g />
</MudItem>
}
</MudGrid>
@code {
private List<Game> GetGames()
{
return context.Games.ToList();
}
}

View File

@@ -39,11 +39,16 @@
<br />
<MudText Typo="Typo.h6" GutterBottom="true">Prerendering</MudText>
<MudText Typo="Typo.body2" GutterBottom="true">
If you're exploring the features of .NET 8 Blazor,<br /> you might be pleasantly surprised to learn that each page is prerendered on the server,<br /> regardless of the selected render mode.<br /><br />
This means that you'll need to inject all necessary services on the server,<br /> even when opting for the wasm (WebAssembly) render mode.<br /><br />
This prerendering functionality is crucial to ensuring that WebAssembly mode feels fast and responsive,<br /> especially when it comes to initial page load times.<br /><br />
For more information on how to detect prerendering and leverage the RenderContext, you can refer to the following link:
<MudLink Href="https://github.com/dotnet/aspnetcore/issues/51468#issuecomment-1783568121" Target="_blank" Typo="Typo.body2" Color="Color.Primary">
If you're exploring the features of .NET 8 Blazor,<br /> you might be pleasantly surprised to learn that each page
is prerendered on the server,<br /> regardless of the selected render mode.<br /><br />
This means that you'll need to inject all necessary services on the server,<br /> even when opting for the wasm
(WebAssembly) render mode.<br /><br />
This prerendering functionality is crucial to ensuring that WebAssembly mode feels fast and responsive,<br />
especially when it comes to initial page load times.<br /><br />
For more information on how to detect prerendering and leverage the RenderContext, you can refer to the following
link:
<MudLink Href="https://github.com/dotnet/aspnetcore/issues/51468#issuecomment-1783568121" Target="_blank"
Typo="Typo.body2" Color="Color.Primary">
More details
</MudLink>
</MudText>
@@ -52,7 +57,8 @@
<MudText Typo="Typo.h6" GutterBottom="true">InteractiveAuto</MudText>
<MudText Typo="Typo.body2">
A discussion on how to achieve this can be found here:
<MudLink Href="https://github.com/dotnet/aspnetcore/issues/51468#issue-1950424116" Target="_blank" Typo="Typo.body2" Color="Color.Primary">
<MudLink Href="https://github.com/dotnet/aspnetcore/issues/51468#issue-1950424116" Target="_blank" Typo="Typo.body2"
Color="Color.Primary">
More details
</MudLink>
</MudText>

View File

@@ -1,60 +0,0 @@
@page "/weather"
<PageTitle>Weather</PageTitle>
<MudText Typo="Typo.h3" GutterBottom="true">Weather forecast</MudText>
<MudText Typo="Typo.body1" Class="mb-8">This component demonstrates fetching data from the server.</MudText>
@if (forecasts == null)
{
<MudProgressCircular Color="Color.Default" Indeterminate="true" />
}
else
{
<MudTable Items="forecasts" Hover="true" SortLabel="Sort By" Elevation="0" AllowUnsorted="false">
<HeaderContent>
<MudTh><MudTableSortLabel InitialDirection="SortDirection.Ascending" SortBy="new Func<WeatherForecast, object>(x=>x.Date)">Date</MudTableSortLabel></MudTh>
<MudTh><MudTableSortLabel SortBy="new Func<WeatherForecast, object>(x=>x.TemperatureC)">Temp. (C)</MudTableSortLabel></MudTh>
<MudTh><MudTableSortLabel SortBy="new Func<WeatherForecast, object>(x=>x.TemperatureF)">Temp. (F)</MudTableSortLabel></MudTh>
<MudTh><MudTableSortLabel SortBy="new Func<WeatherForecast, object>(x=>x.Summary!)">Summary</MudTableSortLabel></MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Date">@context.Date</MudTd>
<MudTd DataLabel="Temp. (C)">@context.TemperatureC</MudTd>
<MudTd DataLabel="Temp. (F)">@context.TemperatureF</MudTd>
<MudTd DataLabel="Summary">@context.Summary</MudTd>
</RowTemplate>
<PagerContent>
<MudTablePager PageSizeOptions="new int[]{50, 100}" />
</PagerContent>
</MudTable>
}
@code {
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
// Simulate asynchronous loading to demonstrate a loading indicator
await Task.Delay(500);
var startDate = DateOnly.FromDateTime(DateTime.Now);
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
forecasts = 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();
}
private class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public string? Summary { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
}

View File

@@ -12,3 +12,4 @@
@using MudBlazor.Services
@using LudikZoneBlazor
@using LudikZoneBlazor.Components
@using Microsoft.Extensions.Localization

View File

@@ -1,8 +1,18 @@
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using LudikZone.model;
namespace LudikZoneBlazor.Data;
/// <summary>
/// Le context BDD de l'application
/// </summary>
/// <param name="options"></param>
public class ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : IdentityDbContext<ApplicationUser>(options)
{
/// <summary> Tout les jeux existant sur la plateforme </summary>
public virtual DbSet<Game> Games => Set<Game>();
}

View File

@@ -2,7 +2,7 @@ using Microsoft.AspNetCore.Identity;
namespace LudikZoneBlazor.Data;
// Add profile data for application users by adding properties to the ApplicationUser class
/// <summary> Add profile data for application users by adding properties to the ApplicationUser class </summary>
public class ApplicationUser : IdentityUser
{
}

View File

@@ -4,6 +4,11 @@
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<AnalysisMode>All</AnalysisMode>
<UserSecretsId>aspnet-LudikZoneBlazor-b18f2a2e-d082-4232-8521-6cacaa2a4ba2</UserSecretsId>
</PropertyGroup>
@@ -17,4 +22,9 @@
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.*" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LudikZone.model\LudikZone.model.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,5 +1,4 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable

View File

@@ -0,0 +1,300 @@
// <auto-generated />
using System;
using LudikZoneBlazor.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace LudikZoneBlazor.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20240910202256_AjoutGames")]
partial class AjoutGames
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.8")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("LudikZone.model.Game", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("MaxPlayerCount")
.HasColumnType("integer");
b.Property<int>("MinPlayerCount")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Games");
});
modelBuilder.Entity("LudikZoneBlazor.Data.ApplicationUser", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasColumnType("text");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("RoleId")
.HasColumnType("text");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("LudikZoneBlazor.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("LudikZoneBlazor.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("LudikZoneBlazor.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("LudikZoneBlazor.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,37 @@
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace LudikZoneBlazor.Migrations
{
/// <inheritdoc />
public partial class AjoutGames : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Games",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Name = table.Column<string>(type: "text", nullable: false),
MinPlayerCount = table.Column<int>(type: "integer", nullable: false),
MaxPlayerCount = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Games", x => x.Id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Games");
}
}
}

View File

@@ -22,6 +22,29 @@ namespace LudikZoneBlazor.Migrations
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("LudikZone.model.Game", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("MaxPlayerCount")
.HasColumnType("integer");
b.Property<int>("MinPlayerCount")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Games");
});
modelBuilder.Entity("LudikZoneBlazor.Data.ApplicationUser", b =>
{
b.Property<string>("Id")

View File

@@ -49,6 +49,10 @@ builder.Services.AddIdentityCore<ApplicationUser>(options => options.SignIn.Requ
builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>();
// Begin I18N configuration
builder.Services.AddLocalization(opts => { opts.ResourcesPath = "Resources"; });
// End I18N configuration
var app = builder.Build();
// Configure the HTTP request pipeline.
@@ -74,6 +78,17 @@ app.MapRazorComponents<App>()
// Add additional endpoints required by the Identity /Account Razor components.
app.MapAdditionalIdentityEndpoints();
// Begin I18N configuration
var supportedCultures = new[] { "fr", "en" };
var localizationOptions = new RequestLocalizationOptions()
.SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
app.UseRequestLocalization(localizationOptions);
// End I18N configuration
// Appliquer les migrations automatiquement lors du démarrage
using (var scope = app.Services.CreateScope())
{

View File

@@ -0,0 +1,128 @@
<?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="Games" xml:space="preserve">
<value>Games anglais 4</value>
<comment>comment game</comment>
</data>
<data name="Game list" xml:space="preserve">
<value>Game list</value>
<comment>title game list</comment>
</data>
</root>

View File

@@ -0,0 +1,128 @@
<?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="Games" xml:space="preserve">
<value>Games francais 4</value>
<comment>comment game</comment>
</data>
<data name="Game list" xml:space="preserve">
<value>Liste des jeux</value>
<comment>Titre de la liste des jeux</comment>
</data>
</root>