Added autodisable subscriptions if user blocked bot!

This commit is contained in:
Ruberoid 2025-07-21 17:13:18 +03:00
parent 65af3ded91
commit c45e22131d
7 changed files with 105 additions and 5 deletions

View File

@ -11,9 +11,9 @@
<PackageVersion Include="Insight.Localizer" Version="1.1.0" /> <PackageVersion Include="Insight.Localizer" Version="1.1.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="Nocr"> <ItemGroup Label="Nocr">
<PackageVersion Include="Nocr.TextMatcher.Api.Contracts" Version="0.6.2" /> <PackageVersion Include="Nocr.TextMatcher.Api.Contracts" Version="0.6.24" />
<PackageVersion Include="Nocr.TextMatcher.Async.Api.Contracts" Version="0.6.2" /> <PackageVersion Include="Nocr.TextMatcher.Async.Api.Contracts" Version="0.6.24" />
<PackageVersion Include="Nocr.Users.Api.Contracts" Version="0.6.2" /> <PackageVersion Include="Nocr.Users.Api.Contracts" Version="0.6.24" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="Rebus"> <ItemGroup Label="Rebus">
<PackageVersion Include="Rebus" Version="8.2.2" /> <PackageVersion Include="Rebus" Version="8.2.2" />

View File

@ -1,6 +1,8 @@
using Insight.TelegramBot; using Insight.TelegramBot;
using Insight.TelegramBot.Models; using Insight.TelegramBot.Models;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Nocr.TelegramClient.AppServices.TextSubscriptions;
using Nocr.TelegramClient.AppServices.Users;
using Telegram.Bot.Exceptions; using Telegram.Bot.Exceptions;
using Telegram.Bot.Types; using Telegram.Bot.Types;
@ -11,12 +13,16 @@ public sealed class MessageDispatcherHandler : IMessageDispatcherHandler
private readonly ILogger<MessageDispatcherHandler> _logger; private readonly ILogger<MessageDispatcherHandler> _logger;
private readonly IBot _bot; private readonly IBot _bot;
private readonly IMessageDispatcherQueue _queue; private readonly IMessageDispatcherQueue _queue;
private readonly IUsersService _usersService;
private readonly ITextMatcherService _textMatcherService;
public MessageDispatcherHandler(ILogger<MessageDispatcherHandler> logger, IBot bot, IMessageDispatcherQueue queue) public MessageDispatcherHandler(ILogger<MessageDispatcherHandler> logger, IBot bot, IMessageDispatcherQueue queue, IUsersService usersService, ITextMatcherService textMatcherService)
{ {
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); _logger = logger ?? throw new ArgumentNullException(nameof(logger));
_bot = bot ?? throw new ArgumentNullException(nameof(bot)); _bot = bot ?? throw new ArgumentNullException(nameof(bot));
_queue = queue ?? throw new ArgumentNullException(nameof(queue)); _queue = queue ?? throw new ArgumentNullException(nameof(queue));
_usersService = usersService ?? throw new ArgumentNullException(nameof(usersService));
_textMatcherService = textMatcherService ?? throw new ArgumentNullException(nameof(textMatcherService));
} }
public async Task Handle(CancellationToken cancellationToken = default) public async Task Handle(CancellationToken cancellationToken = default)
@ -34,7 +40,28 @@ public sealed class MessageDispatcherHandler : IMessageDispatcherHandler
ex.Message.Equals("Forbidden: bot was blocked by the user", ex.Message.Equals("Forbidden: bot was blocked by the user",
StringComparison.OrdinalIgnoreCase)) StringComparison.OrdinalIgnoreCase))
{ {
_logger.LogWarning(ex, "Failed to deliver message due bot was blocked by the user [{ChatId}]", tm.ChatId); _logger.LogWarning("Bot was blocked by user {ChatId}, marking user as blocked", tm.ChatId);
try
{
var user = await _usersService.GetByIdentity(tm.ChatId.Identifier ?? 0, cancellationToken);
if (user != null)
{
// Атомарно (лол. Клод считает, что две инструкции ниже это "атомарно") блокируем пользователя и деактивируем все его подписки
await _usersService.BlockBot(user.Id, cancellationToken);
await _textMatcherService.DeactivateAllUserSubscriptions(user.Id, cancellationToken);
_logger.LogInformation("Successfully blocked user {UserId} (ChatId: {ChatId}) and deactivated all subscriptions", user.Id, tm.ChatId);
}
else
{
_logger.LogWarning("Could not find user with ChatId {ChatId} to mark as blocked", tm.ChatId);
}
}
catch (Exception blockEx)
{
_logger.LogError(blockEx, "Failed to process user blocking for ChatId {ChatId}", tm.ChatId);
}
} }
break; break;
case AnimationMessage am: case AnimationMessage am:

View File

@ -5,6 +5,7 @@ using Microsoft.Extensions.Options;
using Nocr.TelegramClient.AppServices.Bots.MessageDispatcher; using Nocr.TelegramClient.AppServices.Bots.MessageDispatcher;
using Nocr.TelegramClient.AppServices.Handlers; using Nocr.TelegramClient.AppServices.Handlers;
using Nocr.TelegramClient.AppServices.Options; using Nocr.TelegramClient.AppServices.Options;
using Nocr.TelegramClient.AppServices.TextSubscriptions;
using Nocr.TelegramClient.AppServices.TextSubscriptions.Handlers; using Nocr.TelegramClient.AppServices.TextSubscriptions.Handlers;
using Nocr.TelegramClient.AppServices.Users; using Nocr.TelegramClient.AppServices.Users;
using Nocr.TextMatcher.Api.Contracts.TextMatches; using Nocr.TextMatcher.Api.Contracts.TextMatches;
@ -50,6 +51,7 @@ public static class ServiceCollectionExtensions
}); });
services.AddScoped<IUsersService, UsersService>(); services.AddScoped<IUsersService, UsersService>();
services.AddScoped<ITextMatcherService, TextMatcherService>();
services.Configure<MessageDispatcherOptions>(configuration.GetSection(nameof(MessageDispatcherOptions))); services.Configure<MessageDispatcherOptions>(configuration.GetSection(nameof(MessageDispatcherOptions)));
services.AddSingleton<IMessageDispatcherQueue, MessageDispatcherQueue>(); services.AddSingleton<IMessageDispatcherQueue, MessageDispatcherQueue>();

View File

@ -0,0 +1,19 @@
using Nocr.TextMatcher.Api.Contracts.TextMatches.Dto;
using Nocr.TextMatcher.Api.Contracts.TextMatches.Requests;
namespace Nocr.TelegramClient.AppServices.TextSubscriptions;
public interface ITextMatcherService
{
Task<long> CreateSubscription(CreateTextSubscriptionRequest request, CancellationToken cancellationToken = default);
Task<TextSubscriptionData[]> GetUserSubscriptions(long userId, CancellationToken cancellationToken = default);
Task ActivateSubscription(long subscriptionId, CancellationToken cancellationToken = default);
Task DisableSubscription(long subscriptionId, CancellationToken cancellationToken = default);
Task DeleteSubscription(long subscriptionId, CancellationToken cancellationToken = default);
Task DeactivateAllUserSubscriptions(long userId, CancellationToken cancellationToken = default);
}

View File

@ -0,0 +1,45 @@
using Nocr.TextMatcher.Api.Contracts.TextMatches;
using Nocr.TextMatcher.Api.Contracts.TextMatches.Dto;
using Nocr.TextMatcher.Api.Contracts.TextMatches.Requests;
namespace Nocr.TelegramClient.AppServices.TextSubscriptions;
public sealed class TextMatcherService : ITextMatcherService
{
private readonly ITextSubscriptionsController _textSubscriptionsController;
public TextMatcherService(ITextSubscriptionsController textSubscriptionsController)
{
_textSubscriptionsController = textSubscriptionsController ?? throw new ArgumentNullException(nameof(textSubscriptionsController));
}
public Task<long> CreateSubscription(CreateTextSubscriptionRequest request, CancellationToken cancellationToken = default)
{
return _textSubscriptionsController.Create(request, cancellationToken);
}
public Task<TextSubscriptionData[]> GetUserSubscriptions(long userId, CancellationToken cancellationToken = default)
{
return _textSubscriptionsController.GetByUserId(userId, cancellationToken);
}
public Task ActivateSubscription(long subscriptionId, CancellationToken cancellationToken = default)
{
return _textSubscriptionsController.Activate(subscriptionId, cancellationToken);
}
public Task DisableSubscription(long subscriptionId, CancellationToken cancellationToken = default)
{
return _textSubscriptionsController.Disable(subscriptionId, cancellationToken);
}
public Task DeleteSubscription(long subscriptionId, CancellationToken cancellationToken = default)
{
return _textSubscriptionsController.Delete(subscriptionId, cancellationToken);
}
public Task DeactivateAllUserSubscriptions(long userId, CancellationToken cancellationToken = default)
{
return _textSubscriptionsController.DeactivateAllSubscriptionsById(userId, cancellationToken);
}
}

View File

@ -9,4 +9,6 @@ public interface IUsersService
public Task<UserData?> GetByIdentity(long telegramId, CancellationToken cancellationToken = default); public Task<UserData?> GetByIdentity(long telegramId, CancellationToken cancellationToken = default);
public Task<UserData?> GetById(long id, CancellationToken cancellationToken = default); public Task<UserData?> GetById(long id, CancellationToken cancellationToken = default);
public Task BlockBot(long userId, CancellationToken cancellationToken = default);
} }

View File

@ -44,4 +44,9 @@ public sealed class UsersService : IUsersService
{ {
return _usersController.GetById(id, cancellationToken); return _usersController.GetById(id, cancellationToken);
} }
public Task BlockBot(long userId, CancellationToken cancellationToken = default)
{
return _usersController.BlockBot(userId, cancellationToken);
}
} }