fix: финальные правки ревью для issue #39
PR Checks / test-and-build (pull_request) Successful in 13m16s
PR Checks / test-and-build (pull_request) Successful in 13m16s
- PublicSession.razor: добавлена обработка ?register=1, AuthStateProvider, TryGetPlatformIdentity, кнопки записи для авторизованных/неавторизованных пользователей, отображение результата регистрации - CreateSessionHandler: добавлен cover_image_url в INSERT SQL - DiscordProjectStructureTests: версия 3.4.0 во всех проверках - README.md: актуальная версия v3.4.0 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Проект разработан с упором на производительность, архитектуру Vertical Slice, Native AOT (для бота) и удобство развертывания с использованием .NET Aspire.
|
Проект разработан с упором на производительность, архитектуру Vertical Slice, Native AOT (для бота) и удобство развертывания с использованием .NET Aspire.
|
||||||
|
|
||||||
**Текущая версия:** `v3.3.0`.
|
**Текущая версия:** `v3.4.0`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -118,8 +118,8 @@ public sealed class CreateSessionHandler(
|
|||||||
{
|
{
|
||||||
var sessionId = await connection.ExecuteScalarAsync<Guid>(
|
var sessionId = await connection.ExecuteScalarAsync<Guid>(
|
||||||
"""
|
"""
|
||||||
INSERT INTO sessions (batch_id, group_id, title, join_link, scheduled_at, status, max_players, system, description, format, duration_minutes, is_one_shot)
|
INSERT INTO sessions (batch_id, group_id, title, join_link, scheduled_at, status, max_players, system, description, format, duration_minutes, is_one_shot, cover_image_url)
|
||||||
VALUES (@BatchId, @GroupId, @Title, @Link, @ScheduledAt, @Status, @MaxPlayers, @System, @Description, @Format, @DurationMinutes, @IsOneShot)
|
VALUES (@BatchId, @GroupId, @Title, @Link, @ScheduledAt, @Status, @MaxPlayers, @System, @Description, @Format, @DurationMinutes, @IsOneShot, @CoverImageUrl)
|
||||||
RETURNING id;
|
RETURNING id;
|
||||||
""",
|
""",
|
||||||
new
|
new
|
||||||
@@ -135,7 +135,8 @@ public sealed class CreateSessionHandler(
|
|||||||
command.Description,
|
command.Description,
|
||||||
command.Format,
|
command.Format,
|
||||||
DurationMinutes = command.DurationMinutes,
|
DurationMinutes = command.DurationMinutes,
|
||||||
IsOneShot = command.IsOneShot
|
IsOneShot = command.IsOneShot,
|
||||||
|
CoverImageUrl = command.ImageReference
|
||||||
},
|
},
|
||||||
transaction);
|
transaction);
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
@layout PublicLayout
|
@layout PublicLayout
|
||||||
@inject ISessionStore SessionStore
|
@inject ISessionStore SessionStore
|
||||||
@inject NavigationManager Navigation
|
@inject NavigationManager Navigation
|
||||||
|
@inject AuthenticationStateProvider AuthStateProvider
|
||||||
@using GmRelay.Shared.Features.Showcase
|
@using GmRelay.Shared.Features.Showcase
|
||||||
|
@using GmRelay.Web.Services
|
||||||
|
|
||||||
<PageTitle>@PageTitleText</PageTitle>
|
<PageTitle>@PageTitleText</PageTitle>
|
||||||
|
|
||||||
@@ -87,6 +89,13 @@ else if (session is not null)
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@if (registrationResult is not null)
|
||||||
|
{
|
||||||
|
<div class="glass-card @GetRegistrationResultClass()">
|
||||||
|
<p>@registrationResult</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<div class="public-settings-actions">
|
<div class="public-settings-actions">
|
||||||
@if (!string.IsNullOrWhiteSpace(session.GroupSlug))
|
@if (!string.IsNullOrWhiteSpace(session.GroupSlug))
|
||||||
{
|
{
|
||||||
@@ -95,7 +104,14 @@ else if (session is not null)
|
|||||||
<a class="btn-gm btn-gm-outline" href="@PublicSessionUrl" target="_blank" rel="noopener noreferrer">Ссылка на сессию</a>
|
<a class="btn-gm btn-gm-outline" href="@PublicSessionUrl" target="_blank" rel="noopener noreferrer">Ссылка на сессию</a>
|
||||||
@if (session.AllowDirectRegistration)
|
@if (session.AllowDirectRegistration)
|
||||||
{
|
{
|
||||||
<a class="btn-gm btn-gm-primary" href="@($"/s/{SessionId}?register=1")">Записаться</a>
|
@if (isAuthenticated)
|
||||||
|
{
|
||||||
|
<button class="btn-gm btn-gm-primary" @onclick="RegisterAsync">Записаться</button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<a class="btn-gm btn-gm-primary" href="@GetLoginUrl()">Войти, чтобы записаться</a>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
@@ -106,6 +122,8 @@ else if (session is not null)
|
|||||||
|
|
||||||
private ShowcaseSessionDto? session;
|
private ShowcaseSessionDto? session;
|
||||||
private bool loaded;
|
private bool loaded;
|
||||||
|
private bool isAuthenticated;
|
||||||
|
private string? registrationResult;
|
||||||
|
|
||||||
private string PageTitleText => session is null ? "Публичная сессия — GM-Relay" : $"{session.Title} — GM-Relay";
|
private string PageTitleText => session is null ? "Публичная сессия — GM-Relay" : $"{session.Title} — GM-Relay";
|
||||||
|
|
||||||
@@ -114,10 +132,47 @@ else if (session is not null)
|
|||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
loaded = false;
|
loaded = false;
|
||||||
|
registrationResult = null;
|
||||||
session = await SessionStore.GetShowcaseSessionAsync(SessionId);
|
session = await SessionStore.GetShowcaseSessionAsync(SessionId);
|
||||||
|
|
||||||
|
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
||||||
|
isAuthenticated = authState.User.Identity?.IsAuthenticated ?? false;
|
||||||
|
|
||||||
|
if (session is not null && Navigation.Uri.Contains("register=1") && session.AllowDirectRegistration)
|
||||||
|
{
|
||||||
|
if (isAuthenticated && authState.User.TryGetPlatformIdentity(out var platform, out var externalUserId))
|
||||||
|
{
|
||||||
|
var success = await SessionStore.RegisterFromShowcaseAsync(SessionId, platform, externalUserId, authState.User.Identity?.Name ?? "Игрок");
|
||||||
|
registrationResult = success
|
||||||
|
? "Вы успешно записались на игру!"
|
||||||
|
: "Не удалось записаться. Возможно, места закончились или вы уже зарегистрированы.";
|
||||||
|
}
|
||||||
|
else if (!isAuthenticated)
|
||||||
|
{
|
||||||
|
Navigation.NavigateTo($"/login?returnUrl={Uri.EscapeDataString($"/s/{SessionId}")}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
loaded = true;
|
loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task RegisterAsync()
|
||||||
|
{
|
||||||
|
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
||||||
|
if (authState.User.TryGetPlatformIdentity(out var platform, out var externalUserId))
|
||||||
|
{
|
||||||
|
var success = await SessionStore.RegisterFromShowcaseAsync(SessionId, platform, externalUserId, authState.User.Identity?.Name ?? "Игрок");
|
||||||
|
registrationResult = success
|
||||||
|
? "Вы успешно записались на игру!"
|
||||||
|
: "Не удалось записаться. Возможно, места закончились или вы уже зарегистрированы.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetLoginUrl() => $"/login?returnUrl={Uri.EscapeDataString($"/s/{SessionId}?register=1")}";
|
||||||
|
|
||||||
|
private string GetRegistrationResultClass() => registrationResult?.StartsWith("Вы успешно") == true ? "status-success-bg" : "status-warning-bg";
|
||||||
|
|
||||||
private static string FormatSeats(ShowcaseSessionDto session)
|
private static string FormatSeats(ShowcaseSessionDto session)
|
||||||
{
|
{
|
||||||
var seats = session.MaxPlayers.HasValue
|
var seats = session.MaxPlayers.HasValue
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public sealed class DiscordProjectStructureTests
|
|||||||
var prChecks = File.ReadAllText(Path.Combine(repoRoot, ".gitea", "workflows", "pr-checks.yml"));
|
var prChecks = File.ReadAllText(Path.Combine(repoRoot, ".gitea", "workflows", "pr-checks.yml"));
|
||||||
var deploy = File.ReadAllText(Path.Combine(repoRoot, ".gitea", "workflows", "deploy.yml"));
|
var deploy = File.ReadAllText(Path.Combine(repoRoot, ".gitea", "workflows", "deploy.yml"));
|
||||||
|
|
||||||
Assert.Contains("gmrelay-discord-bot:3.3.0", compose);
|
Assert.Contains("gmrelay-discord-bot:3.4.0", compose);
|
||||||
Assert.Contains("Discord__Token=${DISCORD_BOT_TOKEN:?Set DISCORD_BOT_TOKEN in .env}", compose);
|
Assert.Contains("Discord__Token=${DISCORD_BOT_TOKEN:?Set DISCORD_BOT_TOKEN in .env}", compose);
|
||||||
Assert.Contains("src/GmRelay.DiscordBot/Dockerfile", deploy);
|
Assert.Contains("src/GmRelay.DiscordBot/Dockerfile", deploy);
|
||||||
Assert.Contains("DISCORD_BOT_TOKEN", deploy);
|
Assert.Contains("DISCORD_BOT_TOKEN", deploy);
|
||||||
@@ -76,13 +76,13 @@ public sealed class DiscordProjectStructureTests
|
|||||||
{
|
{
|
||||||
var repoRoot = GetRepoRoot();
|
var repoRoot = GetRepoRoot();
|
||||||
|
|
||||||
Assert.Contains("<Version>3.3.0</Version>", File.ReadAllText(Path.Combine(repoRoot, "Directory.Build.props")));
|
Assert.Contains("<Version>3.4.0</Version>", File.ReadAllText(Path.Combine(repoRoot, "Directory.Build.props")));
|
||||||
Assert.Contains("VERSION: 3.3.0", File.ReadAllText(Path.Combine(repoRoot, ".gitea", "workflows", "deploy.yml")));
|
Assert.Contains("VERSION: 3.4.0", File.ReadAllText(Path.Combine(repoRoot, ".gitea", "workflows", "deploy.yml")));
|
||||||
Assert.Contains("gmrelay-bot:3.3.0", File.ReadAllText(Path.Combine(repoRoot, "compose.yaml")));
|
Assert.Contains("gmrelay-bot:3.4.0", File.ReadAllText(Path.Combine(repoRoot, "compose.yaml")));
|
||||||
Assert.Contains("gmrelay-web:3.3.0", File.ReadAllText(Path.Combine(repoRoot, "compose.yaml")));
|
Assert.Contains("gmrelay-web:3.4.0", File.ReadAllText(Path.Combine(repoRoot, "compose.yaml")));
|
||||||
Assert.Contains("gmrelay-discord-bot:3.3.0", File.ReadAllText(Path.Combine(repoRoot, "compose.yaml")));
|
Assert.Contains("gmrelay-discord-bot:3.4.0", File.ReadAllText(Path.Combine(repoRoot, "compose.yaml")));
|
||||||
Assert.Contains(
|
Assert.Contains(
|
||||||
"v3.3.0",
|
"v3.4.0",
|
||||||
File.ReadAllText(Path.Combine(repoRoot, "src", "GmRelay.Web", "Components", "Layout", "NavMenu.razor")));
|
File.ReadAllText(Path.Combine(repoRoot, "src", "GmRelay.Web", "Components", "Layout", "NavMenu.razor")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user