Add subscribe command
This commit is contained in:
parent
33074e99a0
commit
658b28799a
@ -7,7 +7,9 @@
|
||||
<InsightTelegramBotVersion>0.16.0</InsightTelegramBotVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Nocr">
|
||||
<PackageVersion Include="Nocr.TextMatcher.Async.Api.Contracts" Version="0.4.7" />
|
||||
<PackageVersion Include="Nocr.TextMatcher.Api.Contracts" Version="0.4.13" />
|
||||
<PackageVersion Include="Nocr.TextMatcher.Async.Api.Contracts" Version="0.4.13" />
|
||||
<PackageVersion Include="Nocr.Users.Api.Contracts" Version="0.4.11" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Rebus">
|
||||
<PackageVersion Include="Rebus" Version="8.2.2" />
|
||||
@ -26,6 +28,7 @@
|
||||
<PackageVersion Include="Serilog.Settings.Configuration" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Microsoft">
|
||||
<PackageVersion Include="Microsoft.Extensions.Http" Version="$(MicrosoftVersion)" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftVersion)" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@ -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<StartMessageMatcher>
|
||||
{
|
||||
@ -17,7 +17,8 @@ public class StartMessageHandler : IMatchingUpdateHandler<StartMessageMatcher>
|
||||
|
||||
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
|
||||
@ -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
|
||||
{
|
||||
@ -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<SubscribeMessageMatcher>
|
||||
{
|
||||
private readonly IBot _bot;
|
||||
private readonly IUsersService _usersService;
|
||||
private readonly ITextMatchesController _textMatchesController;
|
||||
|
||||
/// <summary>
|
||||
/// Regex to match command "/subscribe @username match_type keywords". <br/>
|
||||
/// For instance, "/subscribe @baraholka 1 обувь ботинки сапоги" will create match for a current user with type "All" and pattern "обувь ботинки сапоги".
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -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<TextMatchMatched>
|
||||
{
|
||||
private readonly ILogger<TextMatchMatchedHandler> _logger;
|
||||
private readonly IBot _bot;
|
||||
private readonly ITextMatchesController _textMatchesController;
|
||||
private readonly IUsersService _usersService;
|
||||
|
||||
public TextMatchMatchedHandler(IBot bot)
|
||||
public TextMatchMatchedHandler(ILogger<TextMatchMatchedHandler> 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,10 +6,16 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Insight.TelegramBot" />
|
||||
<PackageReference Include="Insight.TelegramBot.Handling" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
|
||||
<PackageReference Include="Nocr.Users.Api.Contracts" />
|
||||
<PackageReference Include="Rebus" />
|
||||
<PackageReference Include="Rebus.ServiceProvider" />
|
||||
<PackageReference Include="Nocr.TextMatcher.Async.Api.Contracts" />
|
||||
<PackageReference Include="Nocr.TextMatcher.Api.Contracts" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Nocr.TelegramClient.Core\Nocr.TelegramClient.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
using Nocr.TelegramClient.Core.Options;
|
||||
|
||||
namespace Nocr.TelegramClient.AppServices.Options;
|
||||
|
||||
public class TextMatcherRestEaseOptions : RestEaseOptions
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
using Nocr.TelegramClient.Core.Options;
|
||||
|
||||
namespace Nocr.TelegramClient.AppServices.Options;
|
||||
|
||||
public class UsersRestEaseOptions : RestEaseOptions
|
||||
{
|
||||
}
|
||||
@ -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<TextMatchMatchedHandler>();
|
||||
services.AddHttpClient();
|
||||
|
||||
services.Configure<UsersRestEaseOptions>(configuration.GetSection(nameof(UsersRestEaseOptions)));
|
||||
services.AddScoped<IUsersController>(ctx =>
|
||||
{
|
||||
var options = ctx.GetRequiredService<IOptions<UsersRestEaseOptions>>().Value;
|
||||
var httpClientFactory = ctx.GetRequiredService<IHttpClientFactory>();
|
||||
var client = httpClientFactory.CreateClient(nameof(IUsersController));
|
||||
client.BaseAddress = new Uri(options.BasePath);
|
||||
return RestClient.For<IUsersController>(client);
|
||||
});
|
||||
|
||||
services.Configure<TextMatcherRestEaseOptions>(configuration.GetSection(nameof(TextMatcherRestEaseOptions)));
|
||||
services.AddScoped<ITextMatchesController>(ctx =>
|
||||
{
|
||||
var options = ctx.GetRequiredService<IOptions<TextMatcherRestEaseOptions>>().Value;
|
||||
var httpClientFactory = ctx.GetRequiredService<IHttpClientFactory>();
|
||||
var client = httpClientFactory.CreateClient(nameof(ITextMatchesController));
|
||||
client.BaseAddress = new Uri(options.BasePath);
|
||||
return RestClient.For<ITextMatchesController>(client);
|
||||
});
|
||||
|
||||
services.AddScoped<IUsersService, UsersService>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
10
src/Nocr.TelegramClient.AppServices/Users/IUsersService.cs
Normal file
10
src/Nocr.TelegramClient.AppServices/Users/IUsersService.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using Nocr.Users.Api.Contracts.Users.Dto;
|
||||
|
||||
namespace Nocr.TelegramClient.AppServices.Users;
|
||||
|
||||
public interface IUsersService
|
||||
{
|
||||
public Task<UserData?> GetOrCreate(long telegramId, string? username, CancellationToken cancellationToken = default);
|
||||
|
||||
public Task<UserData?> GetById(long id, CancellationToken cancellationToken = default);
|
||||
}
|
||||
40
src/Nocr.TelegramClient.AppServices/Users/UsersService.cs
Normal file
40
src/Nocr.TelegramClient.AppServices/Users/UsersService.cs
Normal file
@ -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<UserData?> 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<UserData?> GetById(long id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _usersController.GetById(id, cancellationToken);
|
||||
}
|
||||
}
|
||||
6
src/Nocr.TelegramClient.Core/Options/RestEaseOptions.cs
Normal file
6
src/Nocr.TelegramClient.Core/Options/RestEaseOptions.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace Nocr.TelegramClient.Core.Options;
|
||||
|
||||
public class RestEaseOptions
|
||||
{
|
||||
public string BasePath { get; set; }
|
||||
}
|
||||
@ -25,7 +25,6 @@ public class Startup
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<ICurrentDateProvider, DefaultCurrentDateProvider>();
|
||||
|
||||
services.AddTelegramBot(bot =>
|
||||
bot.WithBot<BotClient>(ServiceLifetime.Transient)
|
||||
.WithTelegramBotClient(client => client
|
||||
@ -34,7 +33,8 @@ public class Startup
|
||||
.WithOptions(opt => opt.FromConfiguration(Configuration))
|
||||
.WithPolling(polling => polling.WithExceptionHandler<LoggingPollingExceptionHandler>()));
|
||||
services.AddTelegramBotHandling(typeof(BotClient).Assembly);
|
||||
services.AddAppServices();
|
||||
|
||||
services.AddAppServices(Configuration);
|
||||
|
||||
services.Configure<RebusRabbitMqOptions>(Configuration.GetSection(nameof(RebusRabbitMqOptions)));
|
||||
services.AddRebus((builder, ctx) =>
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Nocr.TelegramClient.AppServices\Nocr.TelegramClient.AppServices.csproj" />
|
||||
<ProjectReference Include="..\Nocr.TelegramClient.Core\Nocr.TelegramClient.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@ -11,5 +11,11 @@
|
||||
},
|
||||
"RebusRabbitMqOptions": {
|
||||
"ConnectionString": "amqp://admin:admin@localhost:5672/"
|
||||
},
|
||||
"UsersRestEaseOptions": {
|
||||
"BasePath": "http://localhost:4998"
|
||||
},
|
||||
"TextMatcherRestEaseOptions": {
|
||||
"BasePath": "http://localhost:5001"
|
||||
}
|
||||
}
|
||||
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user