subscribe
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
using PepperBot.Domain;
|
||||
|
||||
namespace PepperBot.Application.Interfaces;
|
||||
|
||||
public interface ISubscriptionRepository
|
||||
{
|
||||
Task InitializeAsync(CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Получить все активные подписки.
|
||||
/// </summary>
|
||||
Task<IReadOnlyList<Subscription>> GetAllActiveAsync(CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Добавить новое правило подписки для указанного чата.
|
||||
/// Одно правило = один кейворд (но у одного чата может быть много правил).
|
||||
/// </summary>
|
||||
Task AddSubscriptionAsync(string chatId, string keyword, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Получить активные подписки для конкретного чата.
|
||||
/// </summary>
|
||||
Task<IReadOnlyList<Subscription>> GetByChatAsync(string chatId, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Удалить (деактивировать) подписку по идентификатору.
|
||||
/// </summary>
|
||||
Task DeleteSubscriptionAsync(long id, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,19 @@ namespace PepperBot.Application.Interfaces;
|
||||
|
||||
public interface ITelegramNotifier
|
||||
{
|
||||
/// <summary>
|
||||
/// Уведомление о новой скидке в общий чат (из переменной окружения TELEGRAM_CHAT_ID).
|
||||
/// </summary>
|
||||
Task NotifyNewDealAsync(Deal deal, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Уведомление о скидке в конкретный Telegram-чат (личная/персональная рассылка).
|
||||
/// </summary>
|
||||
Task NotifyDealToChatAsync(Deal deal, string chatId, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Запустить обработку входящих сообщений Telegram и регистрацию подписок.
|
||||
/// </summary>
|
||||
Task StartAsync(CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ public class DealService
|
||||
{
|
||||
private readonly IPepperClient _pepperClient;
|
||||
private readonly IDealRepository _repository;
|
||||
private readonly ISubscriptionRepository _subscriptionRepository;
|
||||
private readonly ITelegramNotifier _notifier;
|
||||
private readonly ILogger<DealService> _logger;
|
||||
private readonly IHealthMonitor _healthMonitor;
|
||||
@@ -15,12 +16,14 @@ public class DealService
|
||||
public DealService(
|
||||
IPepperClient pepperClient,
|
||||
IDealRepository repository,
|
||||
ISubscriptionRepository subscriptionRepository,
|
||||
ITelegramNotifier notifier,
|
||||
ILogger<DealService> logger,
|
||||
IHealthMonitor healthMonitor)
|
||||
{
|
||||
_pepperClient = pepperClient;
|
||||
_repository = repository;
|
||||
_subscriptionRepository = subscriptionRepository;
|
||||
_notifier = notifier;
|
||||
_logger = logger;
|
||||
_healthMonitor = healthMonitor;
|
||||
@@ -36,6 +39,9 @@ public class DealService
|
||||
_healthMonitor.ReportSuccess(DateTimeOffset.UtcNow);
|
||||
}
|
||||
|
||||
// Загружаем активные подписки один раз на проход
|
||||
var subscriptions = await _subscriptionRepository.GetAllActiveAsync(cancellationToken);
|
||||
|
||||
foreach (var deal in deals)
|
||||
{
|
||||
if (await _repository.ExistsAsync(deal.Id, cancellationToken))
|
||||
@@ -46,8 +52,63 @@ public class DealService
|
||||
_logger.LogInformation("Новая скидка: {Title} ({Id})", deal.Title, deal.Id);
|
||||
|
||||
await _repository.AddAsync(deal, cancellationToken);
|
||||
|
||||
// Общая рассылка в основной чат (как было раньше)
|
||||
await _notifier.NotifyNewDealAsync(deal, cancellationToken);
|
||||
|
||||
if (subscriptions.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var searchableText = $"{deal.Title} {deal.StoreName}";
|
||||
|
||||
foreach (var subscription in subscriptions)
|
||||
{
|
||||
if (!subscription.IsActive)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var keywords = ParseKeywords(subscription.Keywords);
|
||||
if (keywords.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsMatch(searchableText, keywords))
|
||||
{
|
||||
await _notifier.NotifyDealToChatAsync(deal, subscription.ChatId, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<string> ParseKeywords(string raw)
|
||||
{
|
||||
return raw
|
||||
.Split(new[] { '-',',', ';', '\n', '\r', '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(k => k.Trim())
|
||||
.Where(k => k.Length > 0)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static bool IsMatch(string text, List<string> keywords)
|
||||
{
|
||||
if (keywords.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var keyword in keywords)
|
||||
{
|
||||
if (text.Contains(keyword, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user