Enhance TelegramBotService with schedule handling and subscription toggling
ci / build-backend (push) Successful in 2m38s
ci / build-frontend (push) Successful in 58s
ci / tests (push) Successful in 4m27s
ci / sonar (push) Successful in 9m26s

Updated the TelegramBotService to support new actions for managing subscriptions and retrieving channel schedules. Introduced constants for action types and improved the callback data structure for better clarity. Added a method to send channel schedules, consolidating upcoming program information into a user-friendly format. Updated related tests to ensure proper functionality of the new features and adjusted documentation to reflect changes in button actions.
This commit is contained in:
Leonid Pershin
2026-07-31 08:16:37 +03:00
parent 99821d3c76
commit 8a439f1351
5 changed files with 215 additions and 19 deletions
@@ -3,6 +3,7 @@ using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Notifications;
using TeleWave.Application.Tests.Support;
using TeleWave.Domain.Broadcast;
using TeleWave.Domain.Library;
using TeleWave.Domain.Notifications;
using Xunit;
@@ -41,6 +42,21 @@ public class TelegramBotTests
private static TelegramUpdate Callback(long chatId, string data) =>
new(2, chatId, null, "viewer", "cb-1", data, 55);
private static ScheduleEntry Program(
Guid channelId,
Guid showId,
DateTimeOffset start,
int minutes
) =>
ScheduleEntry.FromSlot(
channelId,
Guid.NewGuid(),
ScheduleEntryKind.Program,
start,
start.AddMinutes(minutes),
new ScheduleEntryOrigin(showId, 0, null, null, null)
);
[Fact]
public async Task Start_WithoutCode_DoesNotSubscribeAnyone()
{
@@ -137,7 +153,7 @@ public class TelegramBotTests
await seed.SaveChangesAsync(CancellationToken.None);
}
var data = $"{channel.Id}:{TelegramNotificationKind.ShowStart}";
var data = $"sub:{channel.Id}:{TelegramNotificationKind.ShowStart}";
await using (var db = fixture.New())
{
@@ -169,6 +185,56 @@ public class TelegramBotTests
Assert.Empty(verify.TelegramSubscriptions);
}
[Fact]
public async Task Callback_Schedule_SendsUpcomingProgrammes()
{
// Кнопка-заголовок канала показывает программу. Подряд идущие серии одного шоу — это
// один блок: зритель спрашивает «что дальше», а не «в каком порядке лежат файлы».
var fixture = new TestDb();
var channel = Channel.Create("Мультреалити", "mult", Now);
channel.UpdateSettings(channel.Name, isEnabled: true, null);
var first = Show.Create("Симпсоны", ShowKind.Series);
var second = Show.Create("Футурама", ShowKind.Series);
var subscriber = TelegramSubscriber.Create(100, Guid.NewGuid(), "viewer", Now);
await using (var seed = fixture.New())
{
seed.Channels.Add(channel);
seed.Shows.AddRange(first, second);
seed.TelegramSubscribers.Add(subscriber);
seed.ScheduleEntries.AddRange(
Program(channel.Id, first.Id, Now.AddMinutes(-5), 25),
Program(channel.Id, first.Id, Now.AddMinutes(20), 25),
Program(channel.Id, second.Id, Now.AddMinutes(45), 25)
);
await seed.SaveChangesAsync(CancellationToken.None);
}
var api = Substitute.For<ITelegramApi>();
string? sent = null;
await api.SendMessageAsync(
Arg.Any<TelegramSettings>(),
Arg.Any<long>(),
Arg.Do<string>(text => sent = text),
Arg.Any<IReadOnlyList<IReadOnlyList<TelegramButton>>?>(),
Arg.Any<CancellationToken>()
);
await using var db = fixture.New();
await new TelegramBotService(db, api).HandleAsync(
Settings(),
Callback(100, $"epg:{channel.Id}"),
Now,
CancellationToken.None
);
Assert.NotNull(sent);
Assert.Contains("Симпсоны", sent, StringComparison.Ordinal);
Assert.Contains("Футурама", sent, StringComparison.Ordinal);
// Две подряд идущие серии Симпсонов дают одну строку, а не две.
Assert.Equal(1, sent!.Split("Симпсоны").Length - 1);
}
[Fact]
public async Task Callback_FromUnknownChat_IsRefused()
{
@@ -178,7 +244,7 @@ public class TelegramBotTests
await using var db = fixture.New();
await new TelegramBotService(db, api).HandleAsync(
Settings(),
Callback(100, $"{Guid.NewGuid()}:{TelegramNotificationKind.ShowStart}"),
Callback(100, $"sub:{Guid.NewGuid()}:{TelegramNotificationKind.ShowStart}"),
Now,
CancellationToken.None
);