diff --git a/Directory.Packages.props b/Directory.Packages.props
index 7ab0600..d758c13 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,31 +1,34 @@
-
- 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/Handlers/Messages/StartMessageHandler.cs b/src/Nocr.TelegramClient.AppServices/Handlers/Messages/StartMessage/StartMessageHandler.cs
similarity index 79%
rename from src/Nocr.TelegramClient.AppServices/Handlers/Messages/StartMessageHandler.cs
rename to src/Nocr.TelegramClient.AppServices/Handlers/Messages/StartMessage/StartMessageHandler.cs
index 7c6c4b7..dabad00 100644
--- a/src/Nocr.TelegramClient.AppServices/Handlers/Messages/StartMessageHandler.cs
+++ b/src/Nocr.TelegramClient.AppServices/Handlers/Messages/StartMessage/StartMessageHandler.cs
@@ -4,7 +4,7 @@ using Insight.TelegramBot.Models;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
-namespace Nocr.TelegramClient.AppServices.Handlers.Messages;
+namespace Nocr.TelegramClient.AppServices.Handlers.Messages.StartMesage;
public class StartMessageHandler : IMatchingUpdateHandler
{
@@ -14,10 +14,11 @@ public class StartMessageHandler : IMatchingUpdateHandler
{
_bot = bot ?? throw new ArgumentNullException(nameof(bot));
}
-
+
public Task Handle(Update update, CancellationToken cancellationToken = default)
{
- var message = new TextMessage(update.Message.Chat)
+ var telegramId = update.Message.From.Id;
+ var message = new TextMessage(telegramId)
{
Text = "Привет! Я _bot_name_",
ParseMode = ParseMode.Html
diff --git a/src/Nocr.TelegramClient.AppServices/Handlers/Messages/StartMessageMatcher.cs b/src/Nocr.TelegramClient.AppServices/Handlers/Messages/StartMessage/StartMessageMatcher.cs
similarity index 73%
rename from src/Nocr.TelegramClient.AppServices/Handlers/Messages/StartMessageMatcher.cs
rename to src/Nocr.TelegramClient.AppServices/Handlers/Messages/StartMessage/StartMessageMatcher.cs
index da696d1..72ba13e 100644
--- a/src/Nocr.TelegramClient.AppServices/Handlers/Messages/StartMessageMatcher.cs
+++ b/src/Nocr.TelegramClient.AppServices/Handlers/Messages/StartMessage/StartMessageMatcher.cs
@@ -1,6 +1,6 @@
using Insight.TelegramBot.Handling.Matchers.TextMatchers;
-namespace Nocr.TelegramClient.AppServices.Handlers.Messages;
+namespace Nocr.TelegramClient.AppServices.Handlers.Messages.StartMesage;
public sealed class StartMessageMatcher : TextStartWithUpdateMatcher
{
diff --git a/src/Nocr.TelegramClient.AppServices/Handlers/Messages/SubscribeMessage/SubscribeMessageHandler.cs b/src/Nocr.TelegramClient.AppServices/Handlers/Messages/SubscribeMessage/SubscribeMessageHandler.cs
new file mode 100644
index 0000000..2021218
--- /dev/null
+++ b/src/Nocr.TelegramClient.AppServices/Handlers/Messages/SubscribeMessage/SubscribeMessageHandler.cs
@@ -0,0 +1,74 @@
+using System.Text.RegularExpressions;
+using Insight.TelegramBot;
+using Insight.TelegramBot.Handling.Handlers;
+using Insight.TelegramBot.Handling.Matchers.TextMatchers;
+using Insight.TelegramBot.Models;
+using Nocr.TelegramClient.AppServices.Users;
+using Nocr.TextMatcher.Api.Contracts.TextMatches;
+using Nocr.TextMatcher.Api.Contracts.TextMatches.Requests;
+using Telegram.Bot.Types;
+
+namespace Nocr.TelegramClient.AppServices.Handlers.Messages.SubscribeMessage;
+
+public sealed class SubscribeMessageMatcher : TextStartWithUpdateMatcher
+{
+ public SubscribeMessageMatcher()
+ {
+ Template = "/subscribe";
+ }
+}
+
+public class SubscribeMessageHandler : IMatchingUpdateHandler
+{
+ private readonly IBot _bot;
+ private readonly IUsersService _usersService;
+ private readonly ITextMatchesController _textMatchesController;
+
+ ///
+ /// Regex to match command "/subscribe @username match_type keywords".
+ /// For instance, "/subscribe @baraholka 1 обувь ботинки сапоги" will create match for a current user with type "All" and pattern "обувь ботинки сапоги".
+ ///
+ private static Regex _commandRegex =
+ new Regex(@"/subscribe (.*\B@(?=\w{5,32}\b)[a-zA-Z0-9]+(?:_[a-zA-Z0-9]+)*.*) (\d{1}) (.*)",
+ RegexOptions.Compiled);
+
+ public SubscribeMessageHandler(IBot bot, IUsersService usersService, ITextMatchesController textMatchesController)
+ {
+ _bot = bot ?? throw new ArgumentNullException(nameof(bot));
+ _usersService = usersService ?? throw new ArgumentNullException(nameof(usersService));
+ _textMatchesController =
+ textMatchesController ?? throw new ArgumentNullException(nameof(textMatchesController));
+ }
+
+ public async Task Handle(Update update, CancellationToken cancellationToken = default)
+ {
+ var telegramId = update.Message.From.Id;
+
+ var match = _commandRegex.Match(update.Message.Text);
+ if (!match.Success)
+ {
+ await _bot.SendMessageAsync(new TextMessage(telegramId)
+ {
+ Text = "Команда не удовлетворяет формату"
+ }, CancellationToken.None);
+ }
+
+ var username = match.Groups[1].Value.TrimStart('@');
+ var rule = match.Groups[2].Value;
+ var template = match.Groups[3].Value;
+
+ var user = await _usersService.GetOrCreate(telegramId, update.Message.From.Username, cancellationToken);
+ var matchId = await _textMatchesController.Create(new CreateTextMatchRequest
+ {
+ UserId = user.Id,
+ ChatUsername = username,
+ Rule = (TextMatchRule)Convert.ToInt32(rule),
+ Template = template,
+ }, cancellationToken);
+
+ await _bot.SendMessageAsync(new TextMessage(telegramId)
+ {
+ Text = $"Подписка создана: {matchId}"
+ }, CancellationToken.None);
+ }
+}
\ No newline at end of file
diff --git a/src/Nocr.TelegramClient.AppServices/Matches/TextMatchMatchedHandler.cs b/src/Nocr.TelegramClient.AppServices/Matches/TextMatchMatchedHandler.cs
index 41e4924..fcffbe6 100644
--- a/src/Nocr.TelegramClient.AppServices/Matches/TextMatchMatchedHandler.cs
+++ b/src/Nocr.TelegramClient.AppServices/Matches/TextMatchMatchedHandler.cs
@@ -1,26 +1,74 @@
using Insight.TelegramBot;
using Insight.TelegramBot.Models;
+using Microsoft.Extensions.Logging;
+using Nocr.TelegramClient.AppServices.Users;
+using Nocr.TextMatcher.Api.Contracts.TextMatches;
using Nocr.TextMatcher.Async.Api.Contracts;
+using Nocr.Users.AppServices.Contracts.Users;
using Rebus.Handlers;
namespace Nocr.TelegramClient.AppServices.Matches;
public class TextMatchMatchedHandler : IHandleMessages
{
+ private readonly ILogger _logger;
private readonly IBot _bot;
+ private readonly ITextMatchesController _textMatchesController;
+ private readonly IUsersService _usersService;
- public TextMatchMatchedHandler(IBot bot)
+ public TextMatchMatchedHandler(ILogger logger, IBot bot,
+ ITextMatchesController textMatchesController, IUsersService usersService)
{
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
_bot = bot ?? throw new ArgumentNullException(nameof(bot));
+ _textMatchesController =
+ textMatchesController ?? throw new ArgumentNullException(nameof(textMatchesController));
+ _usersService = usersService ?? throw new ArgumentNullException(nameof(usersService));
}
-
+
public async Task Handle(TextMatchMatched message)
{
- var textMessage = new TextMessage(58874635)
+ var match = await _textMatchesController.GetById(message.MatchId);
+ if (match == null)
{
- Text = $"[{message.PublishedDateTime:MM.dd.yyyy HH:mm:ss}] Найдено совпадение.\n @{message.ChatUsername} > {message.Text}"
+ _logger.LogWarning("Match [{MatchId}] from message {MessageId} not found", message.MatchId, message.Id);
+ return;
+ }
+
+ var user = await _usersService.GetById(message.MatchUserId);
+ if (user == null)
+ {
+ _logger.LogWarning("User [{UserId}] of [{MatchId}] from message {MessageId} not found", message.MatchUserId, message.MatchId, message.Id);
+ return;
+ }
+
+ var identity = user.Identities.FirstOrDefault(x => x.Type == UserIdentityType.TelegramId);
+ if (identity == null)
+ {
+ _logger.LogWarning("There is no identity with type '{IdentityType}' for user '{UserId}'", UserIdentityType.TelegramId, user.Id);
+ return;
+ }
+
+ var textMessage = new TextMessage(long.Parse(identity.Identity))
+ {
+ Text = $"[{message.PublishedDateTime:MM.dd.yyyy HH:mm:ss}] Найдено совпадение.\n @{match.ChatUsername}. Тип совпадения: '{GetTextMatchRule(match.Rule)}', шаблон: '{match.Template}'"
};
await _bot.SendMessageAsync(textMessage);
}
+
+ private string GetTextMatchRule(TextMatchRule rule)
+ {
+ switch (rule)
+ {
+ case TextMatchRule.Full:
+ return "Полное";
+ case TextMatchRule.AllWords:
+ return "Все слова из списка";
+ case TextMatchRule.AnyWord:
+ return "Одно слово из списка";
+ default:
+ throw new IndexOutOfRangeException(nameof(rule));
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Nocr.TelegramClient.AppServices/Nocr.TelegramClient.AppServices.csproj b/src/Nocr.TelegramClient.AppServices/Nocr.TelegramClient.AppServices.csproj
index d349003..784c41e 100644
--- a/src/Nocr.TelegramClient.AppServices/Nocr.TelegramClient.AppServices.csproj
+++ b/src/Nocr.TelegramClient.AppServices/Nocr.TelegramClient.AppServices.csproj
@@ -6,10 +6,16 @@
+
+
+
+
+
+
diff --git a/src/Nocr.TelegramClient.AppServices/Options/TextMatcherRestEaseOptions.cs b/src/Nocr.TelegramClient.AppServices/Options/TextMatcherRestEaseOptions.cs
new file mode 100644
index 0000000..e8b3089
--- /dev/null
+++ b/src/Nocr.TelegramClient.AppServices/Options/TextMatcherRestEaseOptions.cs
@@ -0,0 +1,7 @@
+using Nocr.TelegramClient.Core.Options;
+
+namespace Nocr.TelegramClient.AppServices.Options;
+
+public class TextMatcherRestEaseOptions : RestEaseOptions
+{
+}
\ No newline at end of file
diff --git a/src/Nocr.TelegramClient.AppServices/Options/UsersRestEaseOptions.cs b/src/Nocr.TelegramClient.AppServices/Options/UsersRestEaseOptions.cs
new file mode 100644
index 0000000..84c4e1d
--- /dev/null
+++ b/src/Nocr.TelegramClient.AppServices/Options/UsersRestEaseOptions.cs
@@ -0,0 +1,7 @@
+using Nocr.TelegramClient.Core.Options;
+
+namespace Nocr.TelegramClient.AppServices.Options;
+
+public class UsersRestEaseOptions : RestEaseOptions
+{
+}
\ No newline at end of file
diff --git a/src/Nocr.TelegramClient.AppServices/ServiceCollectionExtensions.cs b/src/Nocr.TelegramClient.AppServices/ServiceCollectionExtensions.cs
index aef691c..ab520f3 100644
--- a/src/Nocr.TelegramClient.AppServices/ServiceCollectionExtensions.cs
+++ b/src/Nocr.TelegramClient.AppServices/ServiceCollectionExtensions.cs
@@ -1,18 +1,50 @@
+using System.Resources;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
using Nocr.TelegramClient.AppServices.Matches;
+using Nocr.TelegramClient.AppServices.Options;
+using Nocr.TelegramClient.AppServices.Users;
+using Nocr.TelegramClient.Core.Options;
+using Nocr.TextMatcher.Api.Contracts.TextMatches;
+using Nocr.Users.Api.Contracts.Users;
using Rebus.Config;
+using RestEase;
namespace Nocr.TelegramClient.AppServices;
public static class ServiceCollectionExtensions
{
- public static IServiceCollection AddAppServices(this IServiceCollection services)
+ public static IServiceCollection AddAppServices(this IServiceCollection services, IConfiguration configuration)
{
if (services == null)
throw new ArgumentNullException(nameof(services));
// Add registrations here
services.AddRebusHandler();
+ services.AddHttpClient();
+
+ services.Configure(configuration.GetSection(nameof(UsersRestEaseOptions)));
+ services.AddScoped(ctx =>
+ {
+ var options = ctx.GetRequiredService>().Value;
+ var httpClientFactory = ctx.GetRequiredService();
+ var client = httpClientFactory.CreateClient(nameof(IUsersController));
+ client.BaseAddress = new Uri(options.BasePath);
+ return RestClient.For(client);
+ });
+
+ services.Configure(configuration.GetSection(nameof(TextMatcherRestEaseOptions)));
+ services.AddScoped(ctx =>
+ {
+ var options = ctx.GetRequiredService>().Value;
+ var httpClientFactory = ctx.GetRequiredService();
+ var client = httpClientFactory.CreateClient(nameof(ITextMatchesController));
+ client.BaseAddress = new Uri(options.BasePath);
+ return RestClient.For(client);
+ });
+
+ services.AddScoped();
return services;
}
diff --git a/src/Nocr.TelegramClient.AppServices/Users/IUsersService.cs b/src/Nocr.TelegramClient.AppServices/Users/IUsersService.cs
new file mode 100644
index 0000000..4005d00
--- /dev/null
+++ b/src/Nocr.TelegramClient.AppServices/Users/IUsersService.cs
@@ -0,0 +1,10 @@
+using Nocr.Users.Api.Contracts.Users.Dto;
+
+namespace Nocr.TelegramClient.AppServices.Users;
+
+public interface IUsersService
+{
+ public Task GetOrCreate(long telegramId, string? username, CancellationToken cancellationToken = default);
+
+ public Task GetById(long id, CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/src/Nocr.TelegramClient.AppServices/Users/UsersService.cs b/src/Nocr.TelegramClient.AppServices/Users/UsersService.cs
new file mode 100644
index 0000000..175359b
--- /dev/null
+++ b/src/Nocr.TelegramClient.AppServices/Users/UsersService.cs
@@ -0,0 +1,40 @@
+using Nocr.Users.Api.Contracts.Users;
+using Nocr.Users.Api.Contracts.Users.Dto;
+using Nocr.Users.Api.Contracts.Users.Dto.Requests;
+using Nocr.Users.AppServices.Contracts.Users;
+
+namespace Nocr.TelegramClient.AppServices.Users;
+
+public sealed class UsersService : IUsersService
+{
+ private readonly IUsersController _usersController;
+
+ public UsersService(IUsersController usersController)
+ {
+ _usersController = usersController ?? throw new ArgumentNullException(nameof(usersController));
+ }
+
+ public async Task GetOrCreate(long telegramId, string? username, CancellationToken cancellationToken = default)
+ {
+ var user = await _usersController.GetByIdentity(UserIdentityType.TelegramId, telegramId.ToString(), cancellationToken);
+ if (user == null)
+ {
+ await _usersController.Create(new CreateUserRequest
+ {
+ Username = username ?? $"User: {telegramId.ToString()}",
+ TelegramId = telegramId,
+ TelegramUsername = username
+ }, cancellationToken);
+
+ user = await _usersController.GetByIdentity(UserIdentityType.TelegramId, telegramId.ToString(),
+ cancellationToken);
+ }
+
+ return user;
+ }
+
+ public Task GetById(long id, CancellationToken cancellationToken = default)
+ {
+ return _usersController.GetById(id, cancellationToken);
+ }
+}
\ No newline at end of file
diff --git a/src/Nocr.TelegramClient.Core/Options/RestEaseOptions.cs b/src/Nocr.TelegramClient.Core/Options/RestEaseOptions.cs
new file mode 100644
index 0000000..9b8676e
--- /dev/null
+++ b/src/Nocr.TelegramClient.Core/Options/RestEaseOptions.cs
@@ -0,0 +1,6 @@
+namespace Nocr.TelegramClient.Core.Options;
+
+public class RestEaseOptions
+{
+ public string BasePath { get; set; }
+}
\ No newline at end of file
diff --git a/src/Nocr.TelegramClient.Host/Infrastructure/Startup.cs b/src/Nocr.TelegramClient.Host/Infrastructure/Startup.cs
index 4eb38e4..329c1b2 100644
--- a/src/Nocr.TelegramClient.Host/Infrastructure/Startup.cs
+++ b/src/Nocr.TelegramClient.Host/Infrastructure/Startup.cs
@@ -25,7 +25,6 @@ public class Startup
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton();
-
services.AddTelegramBot(bot =>
bot.WithBot(ServiceLifetime.Transient)
.WithTelegramBotClient(client => client
@@ -34,7 +33,8 @@ public class Startup
.WithOptions(opt => opt.FromConfiguration(Configuration))
.WithPolling(polling => polling.WithExceptionHandler()));
services.AddTelegramBotHandling(typeof(BotClient).Assembly);
- services.AddAppServices();
+
+ services.AddAppServices(Configuration);
services.Configure(Configuration.GetSection(nameof(RebusRabbitMqOptions)));
services.AddRebus((builder, ctx) =>
diff --git a/src/Nocr.TelegramClient.Host/Nocr.TelegramClient.Host.csproj b/src/Nocr.TelegramClient.Host/Nocr.TelegramClient.Host.csproj
index 3e5111d..65deee9 100644
--- a/src/Nocr.TelegramClient.Host/Nocr.TelegramClient.Host.csproj
+++ b/src/Nocr.TelegramClient.Host/Nocr.TelegramClient.Host.csproj
@@ -16,7 +16,6 @@
-
diff --git a/src/Nocr.TelegramClient.Host/appsettings.Development.json b/src/Nocr.TelegramClient.Host/appsettings.Development.json
index 2d26fac..f354630 100644
--- a/src/Nocr.TelegramClient.Host/appsettings.Development.json
+++ b/src/Nocr.TelegramClient.Host/appsettings.Development.json
@@ -11,5 +11,11 @@
},
"RebusRabbitMqOptions": {
"ConnectionString": "amqp://admin:admin@localhost:5672/"
+ },
+ "UsersRestEaseOptions": {
+ "BasePath": "http://localhost:4998"
+ },
+ "TextMatcherRestEaseOptions": {
+ "BasePath": "http://localhost:5001"
}
}
diff --git a/src/Nocr.TelegramClient.Host/appsettings.DockerCompose.json b/src/Nocr.TelegramClient.Host/appsettings.DockerCompose.json
index c6ccd78..221c4c2 100644
--- a/src/Nocr.TelegramClient.Host/appsettings.DockerCompose.json
+++ b/src/Nocr.TelegramClient.Host/appsettings.DockerCompose.json
@@ -1,5 +1,11 @@
{
"RebusRabbitMqOptions": {
"ConnectionString": "amqp://admin:admin@nocr-rabbitmq:5672/"
+ },
+ "UsersRestEaseOptions": {
+ "BasePath": "http://nocr-users:80"
+ },
+ "TextMatcherRestEaseOptions": {
+ "BasePath": "http://nocr-text-matcher:80"
}
}
\ No newline at end of file