#14 feat: implemented registration stage of preparation on PrepareUserState #15

Merged
Lisoveliy merged 3 commits from 14 into main 2025-07-12 01:02:27 +02:00
11 changed files with 80 additions and 12 deletions
Showing only changes of commit a526dbf6c6 - Show all commits

View File

@ -1,17 +1,20 @@
using JOBot.Proto; using JOBot.Proto;
using JOBot.TClient.Infrastructure.Attributes.Authorization;
using JOBot.TClient.Services; using JOBot.TClient.Services;
using JOBot.TClient.Statements;
using Telegram.Bot.Types; using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums; using Telegram.Bot.Types.Enums;
namespace JOBot.TClient.Commands.Buttons; namespace JOBot.TClient.Commands.Buttons;
public class EulaAgreementButtonCommand(PrepareUserService prepareUserService) : IAuthorizedTelegramCommand [AcceptNotPrepared]
public class EulaAgreementButtonCommand(PrepareUserState prepareUserState) : IAuthorizedTelegramCommand
{ {
public async Task ExecuteAsync(Update update, GetUserResponse user, CancellationToken ct) public async Task ExecuteAsync(Update update, GetUserResponse user, CancellationToken ct)
{ {
if (update.Type != UpdateType.Message || update.Message?.From == null) if (update.Type != UpdateType.Message || update.Message?.From == null)
return; return;
await prepareUserService.AcceptEula(update, ct); await prepareUserState.AcceptEula(update, ct);
} }
} }

View File

@ -0,0 +1,14 @@
using Telegram.Bot;
using Telegram.Bot.Types;
namespace JOBot.TClient.Commands;
public class InfoCommand(ITelegramBotClient bot) : ITelegramCommand
{
public async Task ExecuteAsync(Update update, CancellationToken ct)
{
ArgumentNullException.ThrowIfNull(update.Message?.From);
await bot.SendMessage(update.Message.From.Id, TextResource.Info, cancellationToken: ct);
}
}

View File

@ -0,0 +1,13 @@
using JOBot.Proto;
using JOBot.TClient.Services;
using Telegram.Bot.Types;
namespace JOBot.TClient.Commands;
public class MenuCommand(MenuService menuService) : IAuthorizedTelegramCommand
{
public async Task ExecuteAsync(Update update, GetUserResponse user, CancellationToken ct)
{
await menuService.RenderMenu(update, ct);
}
}

View File

@ -1,5 +1,7 @@
using JOBot.TClient.Commands; using JOBot.TClient.Commands;
using JOBot.TClient.Commands.Buttons; using JOBot.TClient.Commands.Buttons;
using JOBot.TClient.Infrastructure.Attributes.Authorization;
using JOBot.TClient.Infrastructure.Extensions;
using JOBot.TClient.Services; using JOBot.TClient.Services;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -33,7 +35,8 @@ public sealed class BotBackgroundService(
{ {
//Commands //Commands
["/start"] = scope.ServiceProvider.GetRequiredService<StartCommand>(), ["/start"] = scope.ServiceProvider.GetRequiredService<StartCommand>(),
["/menu"] = scope.ServiceProvider.GetRequiredService<StartCommand>(), ["/menu"] = scope.ServiceProvider.GetRequiredService<MenuCommand>(),
["/info"] = scope.ServiceProvider.GetRequiredService<InfoCommand>(),
//Buttons //Buttons
[ButtonResource.EULAAgrement] = scope.ServiceProvider.GetRequiredService<EulaAgreementButtonCommand>(), [ButtonResource.EULAAgrement] = scope.ServiceProvider.GetRequiredService<EulaAgreementButtonCommand>(),
@ -52,8 +55,16 @@ public sealed class BotBackgroundService(
if (commands.TryGetValue(text, out var command)) if (commands.TryGetValue(text, out var command))
{ {
if (command is IAuthorizedTelegramCommand authorizedTelegramCommand) if (command is IAuthorizedTelegramCommand authorizedTelegramCommand)
{
var attribute = Attribute.GetCustomAttribute(command.GetType(), typeof(AcceptNotPreparedAttribute));
if (!user.IsPrepared() && attribute is not AcceptNotPreparedAttribute)
{
await commands["/start"].ExecuteAsync(update, ct); //заставляем пользователя завершить регистрацию
return;
}
await authorizedTelegramCommand.ExecuteAsync(update, user, ct); await authorizedTelegramCommand.ExecuteAsync(update, user, ct);
else await command.ExecuteAsync(update, ct); //А если вызвать /start когда зареган? То-то и оно, но всё равно надо подумать }
else await command.ExecuteAsync(update, ct);
return; return;
} }

View File

@ -24,6 +24,8 @@ public static class DependencyInjection
#region Commands #region Commands
services.AddScoped<StartCommand>(); services.AddScoped<StartCommand>();
services.AddScoped<MenuCommand>();
services.AddScoped<InfoCommand>();
//buttons //buttons
services.AddScoped<EulaAgreementButtonCommand>(); services.AddScoped<EulaAgreementButtonCommand>();

View File

@ -0,0 +1,4 @@
namespace JOBot.TClient.Infrastructure.Attributes.Authorization;
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class AcceptNotPreparedAttribute : Attribute;

View File

@ -0,0 +1,9 @@
using JOBot.Proto;
namespace JOBot.TClient.Infrastructure.Extensions;
public static class GRpcModelsExtensions
{
public static bool IsPrepared(this GetUserResponse user) => user is { Eula: true, IsLogged: true } &&
!string.IsNullOrEmpty(user.CVUrl);
}

View File

@ -1,5 +1,3 @@
using Grpc.Core;
using JetBrains.Annotations;
using JOBot.Proto; using JOBot.Proto;
using JOBot.TClient.Infrastructure.Exceptions; using JOBot.TClient.Infrastructure.Exceptions;
using Telegram.Bot; using Telegram.Bot;
@ -8,7 +6,6 @@ using User = JOBot.Proto.User;
namespace JOBot.TClient.Services; namespace JOBot.TClient.Services;
[UsedImplicitly]
public class PrepareUserService(ITelegramBotClient bot, User.UserClient userClient) : UserService(bot, userClient) public class PrepareUserService(ITelegramBotClient bot, User.UserClient userClient) : UserService(bot, userClient)
{ {
private readonly ITelegramBotClient _bot = bot; private readonly ITelegramBotClient _bot = bot;

View File

@ -13,9 +13,7 @@ public class PrepareUserState(PrepareUserService prepareUserService, MenuService
/// <param name="ct">Cancellation token</param> /// <param name="ct">Cancellation token</param>
public async Task TryToPrepareUser(Update update, CancellationToken ct = default) public async Task TryToPrepareUser(Update update, CancellationToken ct = default)
{ {
var user = await prepareUserService.GetUser(update, ct); var user = await prepareUserService.GetUser(update, ct) ?? await prepareUserService.RegisterUser(update, ct);
if (user == null)
user = await prepareUserService.RegisterUser(update, ct);
if (!user.Eula) if (!user.Eula)
{ {
@ -31,12 +29,17 @@ public class PrepareUserState(PrepareUserService prepareUserService, MenuService
/// </summary> /// </summary>
/// <param name="update"></param> /// <param name="update"></param>
/// <param name="ct"></param> /// <param name="ct"></param>
public async Task UserAcceptedEula(Update update, CancellationToken ct = default) public async Task AcceptEula(Update update, CancellationToken ct = default)
{ {
await prepareUserService.AcceptEula(update, ct: ct); await prepareUserService.AcceptEula(update, ct: ct);
await OnUserEulaValidStage(update, ct); await OnUserEulaValidStage(update, ct);
} }
/// <summary>
/// Continue prepare stage
/// </summary>
/// <param name="update"></param>
/// <param name="ct"></param>
private async Task OnUserEulaValidStage(Update update, CancellationToken ct = default) private async Task OnUserEulaValidStage(Update update, CancellationToken ct = default)
{ {
await menuService.RenderMenu(update, ct); //boilerplate await menuService.RenderMenu(update, ct); //boilerplate

View File

@ -86,5 +86,14 @@ namespace JOBot.TClient {
return ResourceManager.GetString("FallbackMessage", resourceCulture); return ResourceManager.GetString("FallbackMessage", resourceCulture);
} }
} }
/// <summary>
/// Looks up a localized string similar to Это бот для упрощения поиска работы на HH.ru.
/// </summary>
public static string Info {
get {
return ResourceManager.GetString("Info", resourceCulture);
}
}
} }
} }

View File

@ -28,4 +28,7 @@
<data name="CommandNotFound" xml:space="preserve"> <data name="CommandNotFound" xml:space="preserve">
<value>Команда не найдена, попробуйте что-то другое</value> <value>Команда не найдена, попробуйте что-то другое</value>
</data> </data>
<data name="Info" xml:space="preserve">
<value>Это бот для упрощения поиска работы на HH.ru</value>
</data>
</root> </root>