Files
GmRelayBot/src/GmRelay.DiscordBot/Rendering/DiscordSessionBatchRenderer.cs
T
Toutsu 56aeca5288
Deploy Telegram Bot / build-and-push (push) Successful in 5m53s
Deploy Telegram Bot / scan-images (push) Successful in 3m6s
Deploy Telegram Bot / deploy (push) Successful in 29s
fix(discord): sanitize embed join links
2026-05-26 13:57:11 +03:00

127 lines
4.1 KiB
C#

using GmRelay.Shared.Domain;
using GmRelay.Shared.Rendering;
using NetCord;
using NetCord.Rest;
namespace GmRelay.DiscordBot.Rendering;
public static class DiscordSessionBatchRenderer
{
public static (IReadOnlyList<EmbedProperties> Embeds, IReadOnlyList<ActionRowProperties> ActionRows) Render(SessionBatchViewModel view)
{
var embeds = new List<EmbedProperties>();
var actionRows = new List<ActionRowProperties>();
foreach (var session in view.Sessions)
{
var embed = BuildEmbed(view.Title, session);
embeds.Add(embed);
if (session.AvailableActions.Count > 0)
{
var actionRow = new ActionRowProperties();
foreach (var action in session.AvailableActions)
{
actionRow.Add(new ButtonProperties(
$"{action.ActionKey}:{action.SessionId}",
action.Label,
ButtonStyle.Primary));
}
actionRows.Add(actionRow);
}
}
return (embeds, actionRows);
}
private static EmbedProperties BuildEmbed(string title, SessionViewItem session)
{
var embed = new EmbedProperties()
.WithTitle($"{title} — {session.ScheduledAt.FormatMoscow()}");
if (SessionStatus.IsCancelled(session.Status))
{
embed = embed.WithDescription("❌ Сессия отменена");
}
else
{
embed = embed.WithDescription(BuildPlayerDescription(session));
}
var fields = new List<EmbedFieldProperties>
{
new EmbedFieldProperties()
.WithName("👥 Заполненность")
.WithValue(session.MaxPlayers.HasValue
? $"{session.ActivePlayerCount}/{session.MaxPlayers.Value}"
: $"{session.ActivePlayerCount}")
.WithInline(),
new EmbedFieldProperties()
.WithName("⏳ Лист ожидания")
.WithValue(session.WaitlistedPlayers.Count > 0
? session.WaitlistedPlayers.Count.ToString()
: "—")
.WithInline(),
new EmbedFieldProperties()
.WithName("📊 Статус")
.WithValue(FormatStatus(session.Status))
.WithInline()
};
var embedUrl = DiscordEmbedUrls.NormalizeHttpUrl(session.JoinLink);
if (embedUrl is not null)
{
embed = embed.WithUrl(embedUrl);
}
embed = embed.WithColor(GetColor(session));
embed = embed.AddFields(fields);
return embed;
}
private static string BuildPlayerDescription(SessionViewItem session)
{
if (session.ActivePlayers.Count == 0)
return "👥 Пока никто не записался";
var lines = session.ActivePlayers
.Select(p => $"• {p.DisplayName}")
.ToList();
if (session.WaitlistedPlayers.Count > 0)
{
lines.Add("");
lines.Add($"⏳ Лист ожидания ({session.WaitlistedPlayers.Count}):");
lines.AddRange(session.WaitlistedPlayers.Select(p => $"• {p.DisplayName}"));
}
return string.Join('\n', lines);
}
private static string FormatStatus(string status) => status switch
{
SessionStatus.Planned => "Запланирована",
SessionStatus.ConfirmationSent => "Ожидает подтверждения",
SessionStatus.Confirmed => "Подтверждена",
SessionStatus.Cancelled => "Отменена",
_ => status
};
private static Color GetColor(SessionViewItem session)
{
if (SessionStatus.IsCancelled(session.Status))
return new Color(0xED4245);
if (session.Status == SessionStatus.Confirmed)
return new Color(0x5865F2);
if (session.MaxPlayers.HasValue && session.ActivePlayerCount >= session.MaxPlayers.Value)
return new Color(0xFEE75C);
return new Color(0x57F287);
}
}