diff --git a/Directory.Packages.props b/Directory.Packages.props index fd48c26..f6731db 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,38 +1,39 @@ - - net8.0 - enable - enable - 8.0.0 - 0.16.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + net8.0 + enable + enable + 8.0.0 + 0.16.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Nocr.TelegramClient.AppServices/Bots/BotClient.cs b/src/Nocr.TelegramClient.AppServices/Bots/BotClient.cs index 904baf4..47a418d 100644 --- a/src/Nocr.TelegramClient.AppServices/Bots/BotClient.cs +++ b/src/Nocr.TelegramClient.AppServices/Bots/BotClient.cs @@ -1,7 +1,6 @@ using Insight.TelegramBot; using Insight.TelegramBot.Models; using Microsoft.Extensions.Logging; -using Nocr.TelegramClient.AppServices.Bots.MessageDispatcher; using Telegram.Bot; using Telegram.Bot.Types; diff --git a/src/Nocr.TelegramClient.AppServices/Handlers/Messages/StartMessage/StartMessageHandler.cs b/src/Nocr.TelegramClient.AppServices/Handlers/Messages/StartMessage/StartMessageHandler.cs index 5cefa2a..ae34807 100644 --- a/src/Nocr.TelegramClient.AppServices/Handlers/Messages/StartMessage/StartMessageHandler.cs +++ b/src/Nocr.TelegramClient.AppServices/Handlers/Messages/StartMessage/StartMessageHandler.cs @@ -1,5 +1,4 @@ using Insight.Localizer; -using Insight.TelegramBot; using Insight.TelegramBot.Handling.Handlers; using Insight.TelegramBot.Models; using Nocr.TelegramClient.AppServices.Bots.MessageDispatcher; diff --git a/src/Nocr.TelegramClient.AppServices/Handlers/Messages/SubscribeMessage/SubscribeMessageHandler.cs b/src/Nocr.TelegramClient.AppServices/Handlers/Messages/SubscribeMessage/SubscribeMessageHandler.cs index cbfb4a6..e2fd5c5 100644 --- a/src/Nocr.TelegramClient.AppServices/Handlers/Messages/SubscribeMessage/SubscribeMessageHandler.cs +++ b/src/Nocr.TelegramClient.AppServices/Handlers/Messages/SubscribeMessage/SubscribeMessageHandler.cs @@ -1,5 +1,4 @@ using System.Text.RegularExpressions; -using Insight.TelegramBot; using Insight.TelegramBot.Handling.Handlers; using Insight.TelegramBot.Models; using Nocr.TelegramClient.AppServices.Bots.MessageDispatcher; @@ -7,7 +6,6 @@ using Nocr.TelegramClient.AppServices.Users; using Nocr.TextMatcher.Api.Contracts.TextMatches; using Nocr.TextMatcher.Api.Contracts.TextMatches.Requests; using Nocr.TextMatcher.Contracts; -using Nocr.Users.Api.Contracts.Users.Dto; using Telegram.Bot.Types; namespace Nocr.TelegramClient.AppServices.Handlers.Messages.SubscribeMessage; diff --git a/src/Nocr.TelegramClient.AppServices/Handlers/Messages/SubscriptionsMessage/SubscriptionsMessageHandler.cs b/src/Nocr.TelegramClient.AppServices/Handlers/Messages/SubscriptionsMessage/SubscriptionsMessageHandler.cs index c560030..66297a9 100644 --- a/src/Nocr.TelegramClient.AppServices/Handlers/Messages/SubscriptionsMessage/SubscriptionsMessageHandler.cs +++ b/src/Nocr.TelegramClient.AppServices/Handlers/Messages/SubscriptionsMessage/SubscriptionsMessageHandler.cs @@ -1,11 +1,10 @@ -using Insight.TelegramBot; +using Insight.Localizer; using Insight.TelegramBot.Handling.Handlers; using Insight.TelegramBot.Models; using Nocr.TelegramClient.AppServices.Bots.MessageDispatcher; using Nocr.TelegramClient.AppServices.Matches; using Nocr.TelegramClient.AppServices.Users; using Nocr.TextMatcher.Api.Contracts.TextMatches; -using Nocr.Users.Api.Contracts.Users.Dto; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -13,16 +12,21 @@ namespace Nocr.TelegramClient.AppServices.Handlers.Messages.SubscriptionsMessage public class SubscriptionsMessageHandler : IMatchingUpdateHandler { + private readonly ILocalizer _localizer; private readonly IMessageDispatcherQueue _messageQueue; private readonly IUsersService _usersService; private readonly ITextSubscriptionsController _textSubscriptionsController; - public SubscriptionsMessageHandler(IMessageDispatcherQueue messageQueue, IUsersService usersService, + public SubscriptionsMessageHandler(ILocalizer localizer, + IMessageDispatcherQueue messageQueue, + IUsersService usersService, ITextSubscriptionsController textSubscriptionsController) { + _localizer = localizer ?? throw new ArgumentNullException(nameof(localizer)); _messageQueue = messageQueue ?? throw new ArgumentNullException(nameof(messageQueue)); _usersService = usersService ?? throw new ArgumentNullException(nameof(usersService)); - _textSubscriptionsController = textSubscriptionsController ?? throw new ArgumentNullException(nameof(textSubscriptionsController)); + _textSubscriptionsController = textSubscriptionsController ?? + throw new ArgumentNullException(nameof(textSubscriptionsController)); } public async Task Handle(Update update, CancellationToken cancellationToken = default) @@ -36,11 +40,10 @@ public class SubscriptionsMessageHandler : IMatchingUpdateHandler +/// +/// +public readonly struct PublicTelegramMessageLink +{ + // https://t.me/baraholka_tbi/1186860 + // tg://resolve?domain=baraholka_tbi&post=1186860 + // t.me//?single&thread=&comment=&t= + + /// + /// Username чата или канала + /// + public string Username { get; } + + /// + /// Идентификатор сообщения + /// + public long MessageId { get; } + + /// + /// Идентификатор треда + /// + public long? ThreadId { get; } + + /// + /// Отображать в web-preview одно изображения из поста или несколько + /// + public bool SingleView { get; } + + /// + /// https:// + /// + public string WebLink { get; } + + /// + /// tg:// + /// + public string TelegramLink { get; } + + public PublicTelegramMessageLink(bool singleView, string username, long messageId, long? threadId = null) + { + if (string.IsNullOrWhiteSpace(username)) + { + throw new ArgumentNullException(nameof(username)); + } + + SingleView = singleView; + Username = username; + MessageId = messageId; + ThreadId = threadId; + (WebLink, TelegramLink) = BuildLinks(); + } + + private (string, string) BuildLinks() + { + var webLink = ThreadId.HasValue + ? $"https://t.me/{Username}/{ThreadId.Value}/{MessageId}?{(SingleView ? "single" : string.Empty)}" + : $"https://t.me/{Username}/{MessageId}?{(SingleView ? "single" : string.Empty)}"; + + var telegramLink = ThreadId.HasValue + ? $"tg://resolve?domain={Username}&post={MessageId}{(SingleView ? "&single" : string.Empty)}&thread={ThreadId.Value}" + : $"tg://resolve?domain={Username}&post={MessageId}{(SingleView ? "&single" : string.Empty)}"; + + return (webLink, telegramLink); + } +} \ No newline at end of file diff --git a/src/Nocr.TelegramClient.AppServices/Matches/Handlers/TextMatchMatchedHandler.cs b/src/Nocr.TelegramClient.AppServices/Matches/Handlers/TextMatchMatchedHandler.cs index ed1582e..fa0d14a 100644 --- a/src/Nocr.TelegramClient.AppServices/Matches/Handlers/TextMatchMatchedHandler.cs +++ b/src/Nocr.TelegramClient.AppServices/Matches/Handlers/TextMatchMatchedHandler.cs @@ -1,8 +1,10 @@ -using Insight.TelegramBot; +using FormatWith; +using Insight.Localizer; using Insight.TelegramBot.Models; using Microsoft.Extensions.Logging; +using Nocr.TelegramClient.AppServices.Bots.MessageDispatcher; +using Nocr.TelegramClient.AppServices.Links; using Nocr.TelegramClient.AppServices.Users; -using Nocr.TextMatcher.Api.Contracts.TextMatches; using Nocr.TextMatcher.Async.Api.Contracts; using Nocr.Users.Api.Contracts.Users; using Rebus.Handlers; @@ -13,22 +15,29 @@ namespace Nocr.TelegramClient.AppServices.Matches.Handlers; public class TextMatchMatchedHandler : IHandleMessages { private readonly ILogger _logger; - private readonly IBot _bot; + private readonly ILocalizer _localizer; + private readonly IMessageDispatcherQueue _messageDispatcherQueue; private readonly IUsersService _usersService; - public TextMatchMatchedHandler(ILogger logger, IBot bot, IUsersService usersService) + public TextMatchMatchedHandler(ILogger logger, ILocalizer localizer, + IMessageDispatcherQueue messageDispatcherQueue, IUsersService usersService) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _bot = bot ?? throw new ArgumentNullException(nameof(bot)); + _localizer = localizer ?? throw new ArgumentNullException(nameof(localizer)); + _messageDispatcherQueue = + messageDispatcherQueue ?? throw new ArgumentNullException(nameof(messageDispatcherQueue)); _usersService = usersService ?? throw new ArgumentNullException(nameof(usersService)); } public async Task Handle(TextSubscriptionMatched message) { + // TODO: Set from user context + Localizer.CurrentCulture = "ru-ru"; var user = await _usersService.GetById(message.SubscriptionUserId); if (user == null) { - _logger.LogWarning("User [{UserId}] of [{MatchId}] from message {MessageId} not found", message.SubscriptionUserId, + _logger.LogWarning("User [{UserId}] of [{MatchId}] from message {MessageId} not found", + message.SubscriptionUserId, message.SubscriptionId, message.Id); return; } @@ -41,13 +50,25 @@ public class TextMatchMatchedHandler : IHandleMessages return; } + var link = new PublicTelegramMessageLink(false, message.ChatUsername, message.MessageId); var fromUsername = string.IsNullOrWhiteSpace(message.From) ? "anonymous" : message.From; + var text = _localizer.Get("messages", "TextSubscriptionMatched") + .FormatWith(new + { + SubscriptionRule = message.Rule.TextView(_localizer), + message.Template, + FromUsername = fromUsername, + message.ChatUsername, + MessageText = message.Text, + Link = link.WebLink + }); + + var textMessage = new TextMessage(long.Parse(identity.Identity)) { - Text = $"[{message.PublishedDateTime:MM.dd.yyyy HH:mm:ss}] Найдено совпадение.\nТип совпадения: '{message.Rule.TextView()}'\nШаблон: '{message.Template}'\n{fromUsername} в @{message.ChatUsername}: {message.Text}", + Text = text, ParseMode = ParseMode.Html }; - - await _bot.SendMessageAsync(textMessage); + _messageDispatcherQueue.Enqueue(textMessage); } } \ No newline at end of file diff --git a/src/Nocr.TelegramClient.AppServices/Matches/TextMatchExtensions.cs b/src/Nocr.TelegramClient.AppServices/Matches/TextMatchExtensions.cs index 91ee631..547bb5b 100644 --- a/src/Nocr.TelegramClient.AppServices/Matches/TextMatchExtensions.cs +++ b/src/Nocr.TelegramClient.AppServices/Matches/TextMatchExtensions.cs @@ -1,4 +1,5 @@ -using Nocr.TextMatcher.Api.Contracts.TextMatches; +using FormatWith; +using Insight.Localizer; using Nocr.TextMatcher.Api.Contracts.TextMatches.Dto; using Nocr.TextMatcher.Contracts; @@ -6,26 +7,39 @@ namespace Nocr.TelegramClient.AppServices.Matches; public static class TextMatchExtensions { - public static string TextView(this TextSubscriptionData textMatch) + public static string TextView(this TextSubscriptionData textSubscription, ILocalizer localizer) { - var activeText = textMatch.Active ? "Активна" : "Не активна"; - var activeCommandText = textMatch.Active - ? $"Деактивировать: /deactivate_{textMatch.Id}" - : $"Активировать: /activate_{textMatch.Id}"; - var deleteCommandText = $"Удалить: /delete_subscription_{textMatch.Id}"; - return $"[{textMatch.Id}] (@{textMatch.ChatUsername}) {activeText}: '{textMatch.Rule.TextView()}' > '{textMatch.Template}'\n{activeCommandText}\n{deleteCommandText}"; - } - - public static string TextView(this TextSubscriptionRule rule) + var activeText = textSubscription.Active + ? localizer.Get(nameof(TextSubscriptionData), "Active") + : localizer.Get(nameof(TextSubscriptionData), "Inactive"); + var activeCommandText = textSubscription.Active + ? GetFormattedCommand("Deactivate", textSubscription.Id) + : GetFormattedCommand("Activate", textSubscription.Id); + + var deleteCommandText = GetFormattedCommand("Delete", textSubscription.Id); + return + $"[{textSubscription.Id}] (@{textSubscription.ChatUsername}) {activeText}: '{textSubscription.Rule.TextView(localizer)}' > '{textSubscription.Template}'\n{activeCommandText}\n{deleteCommandText}"; + + string GetFormattedCommand(string key, long subscriptionId) + { + return localizer.Get(nameof(TextSubscriptionData), key) + .FormatWith(new + { + SubscriptionId = subscriptionId + }); + } + } + + public static string TextView(this TextSubscriptionRule rule, ILocalizer localizer) { switch (rule) { case TextSubscriptionRule.Full: - return "Полное"; + return localizer.Get(nameof(TextSubscriptionRule), nameof(TextSubscriptionRule.Full)); case TextSubscriptionRule.AllWords: - return "Все слова из списка"; + return localizer.Get(nameof(TextSubscriptionRule), nameof(TextSubscriptionRule.AllWords)); case TextSubscriptionRule.AnyWord: - return "Одно слово из списка"; + return localizer.Get(nameof(TextSubscriptionRule), nameof(TextSubscriptionRule.AnyWord)); default: throw new IndexOutOfRangeException(nameof(rule)); } diff --git a/src/Nocr.TelegramClient.AppServices/Nocr.TelegramClient.AppServices.csproj b/src/Nocr.TelegramClient.AppServices/Nocr.TelegramClient.AppServices.csproj index f20dc03..4829a34 100644 --- a/src/Nocr.TelegramClient.AppServices/Nocr.TelegramClient.AppServices.csproj +++ b/src/Nocr.TelegramClient.AppServices/Nocr.TelegramClient.AppServices.csproj @@ -4,6 +4,7 @@ false + diff --git a/src/Nocr.TelegramClient.AppServices/ServiceCollectionExtensions.cs b/src/Nocr.TelegramClient.AppServices/ServiceCollectionExtensions.cs index 79f9ec0..39b6c4d 100644 --- a/src/Nocr.TelegramClient.AppServices/ServiceCollectionExtensions.cs +++ b/src/Nocr.TelegramClient.AppServices/ServiceCollectionExtensions.cs @@ -1,9 +1,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using Nocr.TelegramClient.AppServices.Bots; using Nocr.TelegramClient.AppServices.Bots.MessageDispatcher; -using Nocr.TelegramClient.AppServices.Matches; using Nocr.TelegramClient.AppServices.Matches.Handlers; using Nocr.TelegramClient.AppServices.Options; using Nocr.TelegramClient.AppServices.Users; diff --git a/src/Nocr.TelegramClient.Host/Resources/Elements/TextSubscriptionData/TextSubscriptionData.ru-ru.json b/src/Nocr.TelegramClient.Host/Resources/Elements/TextSubscriptionData/TextSubscriptionData.ru-ru.json new file mode 100644 index 0000000..a488555 --- /dev/null +++ b/src/Nocr.TelegramClient.Host/Resources/Elements/TextSubscriptionData/TextSubscriptionData.ru-ru.json @@ -0,0 +1,7 @@ +{ + "Active": "Активна", + "Inactive": "Не активна", + "Activate": "Активировать: /activate_subscription_{SubscriptionId}", + "Deactivate": "Деактивировать: /deactivate_subscription_{SubscriptionId}", + "Delete": "Удалить: /delete_subscription_{SubscriptionId}" +} \ No newline at end of file diff --git a/src/Nocr.TelegramClient.Host/Resources/Elements/TextSubscriptionRules/TextSubscriptionRule.ru-ru.json b/src/Nocr.TelegramClient.Host/Resources/Elements/TextSubscriptionRules/TextSubscriptionRule.ru-ru.json new file mode 100644 index 0000000..1b9f9dd --- /dev/null +++ b/src/Nocr.TelegramClient.Host/Resources/Elements/TextSubscriptionRules/TextSubscriptionRule.ru-ru.json @@ -0,0 +1,5 @@ +{ + "Full": "Полное", + "AllWords": "Все слова из списка", + "AnyWord": "Одно слово из списка" +} \ No newline at end of file diff --git a/src/Nocr.TelegramClient.Host/Resources/Messages/messages.ru-ru.json b/src/Nocr.TelegramClient.Host/Resources/Messages/messages.ru-ru.json index 6ead8fe..fb9d176 100644 --- a/src/Nocr.TelegramClient.Host/Resources/Messages/messages.ru-ru.json +++ b/src/Nocr.TelegramClient.Host/Resources/Messages/messages.ru-ru.json @@ -1,3 +1,4 @@ { - "StartMessage": "Привет! Я, Nocr 🤖!" + "StartMessage": "Привет! Я, Nocr 🤖!", + "TextSubscriptionMatched": "Тип совпадения: {SubscriptionRule}\nШаблон: {Template}\n{FromUsername} в @{ChatUsername}:\n{MessageText}\n\n{Link}" } \ No newline at end of file