168 lines
5.8 KiB
C#
168 lines
5.8 KiB
C#
using GmRelay.Shared.Domain;
|
|
|
|
namespace GmRelay.Bot.Features.Sessions.CreateSession;
|
|
|
|
internal sealed record NewSessionParseResult(
|
|
string? Title,
|
|
string? Link,
|
|
int? MaxPlayers,
|
|
IReadOnlyList<DateTimeOffset> ScheduledTimes,
|
|
IReadOnlyList<string> PastTimeInputs,
|
|
IReadOnlyList<string> InvalidTimeInputs,
|
|
IReadOnlyList<string> InvalidSeatLimitInputs,
|
|
IReadOnlyList<string> InvalidRecurringInputs)
|
|
{
|
|
public bool IsValid =>
|
|
!string.IsNullOrWhiteSpace(Title) &&
|
|
!string.IsNullOrWhiteSpace(Link) &&
|
|
ScheduledTimes.Count > 0 &&
|
|
InvalidSeatLimitInputs.Count == 0 &&
|
|
InvalidRecurringInputs.Count == 0;
|
|
}
|
|
|
|
internal static class NewSessionCommandParser
|
|
{
|
|
private const int MaxRecurringSessionCount = 52;
|
|
private const int MaxRecurringIntervalDays = 365;
|
|
private const string TitlePrefix = "\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435:";
|
|
private const string TimePrefix = "\u0412\u0440\u0435\u043c\u044f:";
|
|
private const string LinkPrefix = "\u0421\u0441\u044b\u043b\u043a\u0430:";
|
|
private static readonly string[] SeatLimitPrefixes =
|
|
[
|
|
"\u041c\u0435\u0441\u0442:",
|
|
"\u041b\u0438\u043c\u0438\u0442:",
|
|
"\u041c\u0430\u043a\u0441\u0438\u043c\u0443\u043c:"
|
|
];
|
|
private static readonly string[] RecurringCountPrefixes =
|
|
[
|
|
"\u0418\u0433\u0440:",
|
|
"\u0421\u0435\u0441\u0441\u0438\u0439:",
|
|
"\u041f\u043e\u0432\u0442\u043e\u0440\u043e\u0432:"
|
|
];
|
|
private static readonly string[] RecurringIntervalPrefixes =
|
|
[
|
|
"\u0428\u0430\u0433:",
|
|
"\u0418\u043d\u0442\u0435\u0440\u0432\u0430\u043b:"
|
|
];
|
|
|
|
public static NewSessionParseResult Parse(string? text, DateTimeOffset nowUtc)
|
|
{
|
|
string? title = null;
|
|
string? link = null;
|
|
int? maxPlayers = null;
|
|
int? recurringCount = null;
|
|
var recurringIntervalDays = 7;
|
|
var scheduledTimes = new List<DateTimeOffset>();
|
|
var pastTimeInputs = new List<string>();
|
|
var invalidTimeInputs = new List<string>();
|
|
var invalidSeatLimitInputs = new List<string>();
|
|
var invalidRecurringInputs = new List<string>();
|
|
|
|
foreach (var line in (text ?? string.Empty).Split('\n', StringSplitOptions.TrimEntries))
|
|
{
|
|
if (line.StartsWith(TitlePrefix, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
title = line[TitlePrefix.Length..].Trim();
|
|
continue;
|
|
}
|
|
|
|
if (line.StartsWith(LinkPrefix, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
link = line[LinkPrefix.Length..].Trim();
|
|
continue;
|
|
}
|
|
|
|
var seatLimitPrefix = SeatLimitPrefixes.FirstOrDefault(prefix =>
|
|
line.StartsWith(prefix, StringComparison.OrdinalIgnoreCase));
|
|
if (seatLimitPrefix is not null)
|
|
{
|
|
var seatLimitInput = line[seatLimitPrefix.Length..].Trim();
|
|
if (int.TryParse(seatLimitInput, out var parsedMaxPlayers) && parsedMaxPlayers > 0)
|
|
{
|
|
maxPlayers = parsedMaxPlayers;
|
|
}
|
|
else
|
|
{
|
|
invalidSeatLimitInputs.Add(seatLimitInput);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
var recurringCountPrefix = RecurringCountPrefixes.FirstOrDefault(prefix =>
|
|
line.StartsWith(prefix, StringComparison.OrdinalIgnoreCase));
|
|
if (recurringCountPrefix is not null)
|
|
{
|
|
var recurringInput = line[recurringCountPrefix.Length..].Trim();
|
|
if (int.TryParse(recurringInput, out var parsedCount) &&
|
|
parsedCount is >= 1 and <= MaxRecurringSessionCount)
|
|
{
|
|
recurringCount = parsedCount;
|
|
}
|
|
else
|
|
{
|
|
invalidRecurringInputs.Add(recurringInput);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
var recurringIntervalPrefix = RecurringIntervalPrefixes.FirstOrDefault(prefix =>
|
|
line.StartsWith(prefix, StringComparison.OrdinalIgnoreCase));
|
|
if (recurringIntervalPrefix is not null)
|
|
{
|
|
var recurringInput = line[recurringIntervalPrefix.Length..].Trim();
|
|
if (int.TryParse(recurringInput, out var parsedInterval) &&
|
|
parsedInterval is >= 1 and <= MaxRecurringIntervalDays)
|
|
{
|
|
recurringIntervalDays = parsedInterval;
|
|
}
|
|
else
|
|
{
|
|
invalidRecurringInputs.Add(recurringInput);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!line.StartsWith(TimePrefix, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var timeInput = line[TimePrefix.Length..].Trim();
|
|
if (!MoscowTime.TryParseMoscow(timeInput, out var scheduledAt))
|
|
{
|
|
invalidTimeInputs.Add(timeInput);
|
|
continue;
|
|
}
|
|
|
|
if (scheduledAt <= nowUtc)
|
|
{
|
|
pastTimeInputs.Add(timeInput);
|
|
continue;
|
|
}
|
|
|
|
scheduledTimes.Add(scheduledAt);
|
|
}
|
|
|
|
if (recurringCount.HasValue && scheduledTimes.Count == 1)
|
|
{
|
|
var firstScheduledTime = scheduledTimes[0];
|
|
scheduledTimes = Enumerable.Range(0, recurringCount.Value)
|
|
.Select(index => firstScheduledTime.AddDays(recurringIntervalDays * index))
|
|
.ToList();
|
|
}
|
|
|
|
return new NewSessionParseResult(
|
|
title,
|
|
link,
|
|
maxPlayers,
|
|
scheduledTimes,
|
|
pastTimeInputs,
|
|
invalidTimeInputs,
|
|
invalidSeatLimitInputs,
|
|
invalidRecurringInputs);
|
|
}
|
|
}
|