Add feedback (#9)

Reviewed-on: #9
Co-authored-by: Sergey Nazarov <insight.appdev@gmail.com>
Co-committed-by: Sergey Nazarov <insight.appdev@gmail.com>
This commit is contained in:
Sergey Nazarov 2024-05-03 07:28:38 +00:00 committed by nazarovsa
parent 82b3de207b
commit b678675851
15 changed files with 191 additions and 5 deletions

View File

@ -8,6 +8,11 @@ public class NocrCallbackData : CallbackData<NocrState>
{ {
} }
public static NocrCallbackData Start()
{
return new NocrCallbackData(NocrState.Start);
}
public static NocrCallbackData ActivateSubscription(long subscriptionId) public static NocrCallbackData ActivateSubscription(long subscriptionId)
{ {
return new NocrCallbackData(NocrState.ActivateSubscription, subscriptionId.ToString()); return new NocrCallbackData(NocrState.ActivateSubscription, subscriptionId.ToString());
@ -29,4 +34,9 @@ public class NocrCallbackData : CallbackData<NocrState>
new NocrCallbackData(NocrState.ViewSubscription, subscriptionId.Value.ToString()): new NocrCallbackData(NocrState.ViewSubscription, subscriptionId.Value.ToString()):
new NocrCallbackData(NocrState.ViewSubscription); new NocrCallbackData(NocrState.ViewSubscription);
} }
public static NocrCallbackData Feedback()
{
return new NocrCallbackData(NocrState.Feedback);
}
} }

View File

@ -9,5 +9,6 @@ public enum NocrState
// States // States
Start, Start,
ViewSubscription ViewSubscription,
Feedback
} }

View File

@ -4,7 +4,6 @@ using Insight.TelegramBot.Keyboards;
using Insight.TelegramBot.Models; using Insight.TelegramBot.Models;
using Nocr.TelegramClient.AppServices.Bots; using Nocr.TelegramClient.AppServices.Bots;
using Nocr.TelegramClient.AppServices.Bots.MessageDispatcher; using Nocr.TelegramClient.AppServices.Bots.MessageDispatcher;
using Nocr.TelegramClient.AppServices.Handlers.Messages.StartMessage;
using Telegram.Bot.Types; using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums; using Telegram.Bot.Types.Enums;
using Telegram.Bot.Types.ReplyMarkups; using Telegram.Bot.Types.ReplyMarkups;
@ -64,6 +63,11 @@ public abstract class StartHandlerBase
CallbackData = NocrCallbackData.ViewSubscription().ToString() CallbackData = NocrCallbackData.ViewSubscription().ToString()
}); });
markup.Add(new InlineKeyboardButton(Localizer.Get(nameof(StartHandlerBase), "FeedbackButton"))
{
CallbackData = NocrCallbackData.Feedback().ToString()
});
return markup.InlineKeyboardMarkup; return markup.InlineKeyboardMarkup;
} }
} }

View File

@ -158,7 +158,7 @@ public abstract class ViewSubscriptionHandlerBase
markup.Add(new InlineKeyboardButton(Localizer.Get("Buttons", "Back")) markup.Add(new InlineKeyboardButton(Localizer.Get("Buttons", "Back"))
{ {
CallbackData = new NocrCallbackData(NocrState.Start).ToString() CallbackData = NocrCallbackData.Start().ToString()
}); });
return markup; return markup;

View File

@ -0,0 +1,39 @@
using Insight.Localizer;
using Insight.TelegramBot;
using Insight.TelegramBot.Handling.Handlers;
using Insight.TelegramBot.Models;
using Microsoft.Extensions.Logging;
using Nocr.TelegramClient.AppServices.Bots;
using Telegram.Bot.Types;
using Telegram.Bot.Types.ReplyMarkups;
namespace Nocr.TelegramClient.AppServices.Handlers.CallbackQueries.Feedback;
public class FeedbackHandler : IMatchingUpdateHandler<FeedbackMatcher>
{
private readonly ILogger<FeedbackHandler> _logger;
private readonly ILocalizer _localizer;
private readonly IBot _bot;
public FeedbackHandler(ILogger<FeedbackHandler> logger, ILocalizer localizer, IBot bot)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_localizer = localizer ?? throw new ArgumentNullException(nameof(localizer));
_bot = bot ?? throw new ArgumentNullException(nameof(bot));
}
public Task Handle(Update update, CancellationToken cancellationToken = default)
{
// TODO: Check, that other messages sent to chat, no to one, who clicks
var message = new TextMessage(update.CallbackQuery.Message.Chat.Id)
{
Text = _localizer.Get(nameof(FeedbackHandler), "Text"),
ReplyMarkup = new InlineKeyboardMarkup(new InlineKeyboardButton(_localizer.Get("buttons", "back"))
{
CallbackData = NocrCallbackData.Start().ToString()
})
};
return _bot.EditOrSendTextMessage(update.CallbackQuery.Message.MessageId, message, _logger, cancellationToken);
}
}

View File

@ -0,0 +1,12 @@
using Insight.TelegramBot.Handling.Matchers.CallbackQueryMatchers;
using Nocr.TelegramClient.AppServices.Bots;
namespace Nocr.TelegramClient.AppServices.Handlers.CallbackQueries.Feedback;
public sealed class FeedbackMatcher : StateCallbackQueryMatcher<NocrState>
{
public FeedbackMatcher()
{
ExpectingState = NocrState.Feedback;
}
}

View File

@ -1,7 +1,6 @@
using Insight.Localizer; using Insight.Localizer;
using Insight.TelegramBot; using Insight.TelegramBot;
using Insight.TelegramBot.Handling.Handlers; using Insight.TelegramBot.Handling.Handlers;
using Insight.TelegramBot.Models;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Nocr.TelegramClient.AppServices.Bots; using Nocr.TelegramClient.AppServices.Bots;
using Nocr.TelegramClient.AppServices.Bots.MessageDispatcher; using Nocr.TelegramClient.AppServices.Bots.MessageDispatcher;

View File

@ -0,0 +1,76 @@
using FormatWith;
using Insight.Localizer;
using Insight.TelegramBot.Handling.Handlers;
using Insight.TelegramBot.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Nocr.TelegramClient.AppServices.Bots;
using Nocr.TelegramClient.AppServices.Bots.MessageDispatcher;
using Nocr.TelegramClient.AppServices.Options;
using Telegram.Bot.Types;
using Telegram.Bot.Types.ReplyMarkups;
namespace Nocr.TelegramClient.AppServices.Handlers.Messages.FeedbackMessage;
public sealed class FeedbackMessageHandler : IMatchingUpdateHandler<FeedbackMessageMatcher>
{
private readonly ILogger<FeedbackMessageHandler> _logger;
private readonly ILocalizer _localizer;
private readonly IMessageDispatcherQueue _messageDispatcherQueue;
private readonly AdministrationOptions _administrationOptions;
public FeedbackMessageHandler(ILogger<FeedbackMessageHandler> logger, ILocalizer localizer,
IMessageDispatcherQueue messageDispatcherQueue, IOptionsSnapshot<AdministrationOptions> administrationOptions)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_localizer = localizer ?? throw new ArgumentNullException(nameof(localizer));
_messageDispatcherQueue =
messageDispatcherQueue ?? throw new ArgumentNullException(nameof(messageDispatcherQueue));
_administrationOptions =
administrationOptions.Value ?? throw new ArgumentNullException(nameof(administrationOptions));
}
public Task Handle(Update update, CancellationToken cancellationToken = default)
{
var from = update.Message.From;
var feedbackText = update.Message.Text
.Replace("/feedback", string.Empty)
.Trim(' ');
var message = new TextMessage(from.Id)
{
Text = _localizer.Get(nameof(FeedbackMessageHandler), "Text"),
ReplyMarkup = new InlineKeyboardMarkup(new InlineKeyboardButton(_localizer.Get("buttons", "back"))
{
CallbackData = NocrCallbackData.Start().ToString()
})
};
_messageDispatcherQueue.Enqueue(message);
foreach (var feedbackReceiverId in _administrationOptions.FeedbackReceiverIds)
{
var feedbackMessage = new TextMessage(feedbackReceiverId)
{
Text = _localizer.Get(nameof(FeedbackMessageHandler), "FeedbackText")
.FormatWith(new
{
FromId = from.Id,
FromUsername = string.IsNullOrWhiteSpace(from.Username) ? "anonymous" : $"@{from.Username}",
Text = feedbackText
})
};
try
{
_messageDispatcherQueue.Enqueue(feedbackMessage);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to send feedback message to {FeedbackReceiverId}", feedbackReceiverId);
}
}
return Task.CompletedTask;
}
}

View File

@ -0,0 +1,11 @@
using Insight.TelegramBot.Handling.Matchers.TextMatchers;
namespace Nocr.TelegramClient.AppServices.Handlers.Messages.FeedbackMessage;
public sealed class FeedbackMessageMatcher : TextStartWithUpdateMatcher
{
public FeedbackMessageMatcher()
{
Template = "/feedback";
}
}

View File

@ -0,0 +1,14 @@
namespace Nocr.TelegramClient.AppServices.Options;
public sealed class AdministrationOptions
{
/// <summary>
/// Список telegram идентификаторов для получения отзывов
/// </summary>
public long[] FeedbackReceiverIds { get; set; } = Array.Empty<long>();
/// <summary>
/// Список telegram идентификаторов для получения обновлений
/// </summary>
public long[] UpdateReceiverIds { get; set; } = Array.Empty<long>();
}

View File

@ -2,6 +2,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Nocr.TelegramClient.AppServices.Bots.MessageDispatcher; using Nocr.TelegramClient.AppServices.Bots.MessageDispatcher;
using Nocr.TelegramClient.AppServices.Handlers.Messages.FeedbackMessage;
using Nocr.TelegramClient.AppServices.Options; using Nocr.TelegramClient.AppServices.Options;
using Nocr.TelegramClient.AppServices.TextSubscriptions.Handlers; using Nocr.TelegramClient.AppServices.TextSubscriptions.Handlers;
using Nocr.TelegramClient.AppServices.Users; using Nocr.TelegramClient.AppServices.Users;
@ -23,6 +24,8 @@ public static class ServiceCollectionExtensions
services.AddRebusHandler<TextSubscriptionMatchedHandler>(); services.AddRebusHandler<TextSubscriptionMatchedHandler>();
services.AddHttpClient(); services.AddHttpClient();
services.Configure<AdministrationOptions>(configuration.GetSection(nameof(AdministrationOptions)));
services.Configure<UsersRestEaseOptions>(configuration.GetSection(nameof(UsersRestEaseOptions))); services.Configure<UsersRestEaseOptions>(configuration.GetSection(nameof(UsersRestEaseOptions)));
services.AddScoped<IUsersController>(ctx => services.AddScoped<IUsersController>(ctx =>
{ {

View File

@ -1,5 +1,6 @@
{ {
"Text": "Привет! Я, Nocr 🤖!", "Text": "Привет! Я, Nocr 🤖!",
"SubscriptionsButton": "Подписки 📩" "SubscriptionsButton": "Подписки 📩",
"FeedbackButton": "Оставить отзыв 🙋‍"
} }

View File

@ -0,0 +1,3 @@
{
"Text": "Чтобы оставить отзыв или пожелание по улучшению отправьте команду /feedback в формате `/feedback текст отзыва`. Например, /feeback Классный бот! Спасибо!"
}

View File

@ -0,0 +1,5 @@
{
"Text": "Благодарим за отзыв!",
"FeedbackText": "#feedback\nПолучен отзыв от: {FromId} ({FromUsername})\n<i>{Text}</i>"
}

View File

@ -22,5 +22,13 @@
"Path": "Resources", "Path": "Resources",
"Pattern": "", "Pattern": "",
"ReadNestedFolders": "true" "ReadNestedFolders": "true"
},
"AdministrationOptions": {
"FeedbackReceiverIds": [
-4202454237
],
"UpdateReceiverIds": [
-4202454237
]
} }
} }