feat(web): add public master profiles
PR Checks / test-and-build (pull_request) Successful in 12m32s

Add sanitized public GM profiles with publication controls, public /gm/{slug} pages, and links from public game surfaces.

Bump version -> 3.5.0
This commit is contained in:
2026-05-29 00:08:14 +03:00
parent d81564c308
commit 0c1d3abd7e
21 changed files with 980 additions and 39 deletions
@@ -90,6 +90,52 @@ public sealed class AuthorizedSessionService(ISessionStore sessionStore, IHttpCo
await sessionStore.UpdatePublicGroupSettingsAsync(groupId, normalizedSlug, publicScheduleEnabled);
}
public Task<MasterProfileSettings?> GetMasterProfileSettingsForCurrentUserAsync()
{
var identity = GetCurrentIdentity();
if (identity is null)
return Task.FromResult<MasterProfileSettings?>(null);
return sessionStore.GetMasterProfileSettingsAsync(identity.Value.Platform, identity.Value.ExternalUserId);
}
public async Task UpdateMasterProfileSettingsForCurrentUserAsync(
string? publicSlug,
bool isPublic,
string displayName,
string? bio)
{
var identity = GetCurrentIdentity();
if (identity is null)
throw new InvalidOperationException("User is not authenticated.");
var normalizedDisplayName = displayName.Trim();
if (normalizedDisplayName.Length is < 2 or > 120)
{
throw new InvalidOperationException("Имя профиля должно быть от 2 до 120 символов.");
}
var normalizedBio = string.IsNullOrWhiteSpace(bio) ? null : bio.Trim();
if (normalizedBio?.Length > 1200)
{
throw new InvalidOperationException("Описание профиля должно быть не длиннее 1200 символов.");
}
var normalizedSlug = NormalizeMasterProfileSlug(publicSlug);
if (isPublic && normalizedSlug is null)
{
throw new InvalidOperationException("Для публичного профиля нужен короткий адрес.");
}
await sessionStore.UpdateMasterProfileSettingsAsync(
identity.Value.Platform,
identity.Value.ExternalUserId,
normalizedSlug,
isPublic,
normalizedDisplayName,
normalizedBio);
}
public async Task SetSessionPublicForCurrentUserAsync(Guid sessionId, bool isPublic)
{
var identity = GetCurrentIdentity();
@@ -472,4 +518,6 @@ public sealed class AuthorizedSessionService(ISessionStore sessionStore, IHttpCo
return slug;
}
private static string? NormalizeMasterProfileSlug(string? publicSlug) => NormalizePublicSlug(publicSlug);
}