-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using Telegram.Bot; | ||
using Telegram.Bot.Types; | ||
|
||
namespace PoliNetwork.Telegram.Bot.Functionality | ||
{ | ||
/// <summary> | ||
/// Represents an abstract base class for defining the functionality of a Telegram bot. | ||
/// </summary> | ||
public abstract class AbstractTelegramBotFunctionality : ITelegramBotFunctionality | ||
{ | ||
/// <summary> | ||
/// Defines the behavior of the bot's functionality. This method must be implemented by derived classes. | ||
/// </summary> | ||
/// <param name="bot">The <see cref="TelegramBot"/> instance representing the bot with which the functionality is associated.</param> | ||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> | ||
public abstract Task RunAsync(ITelegramBotClient bot, Update update, CancellationToken cancellationToken); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
using PoliNetwork.Utility.Configuration; | ||
using Telegram.Bot; | ||
using Telegram.Bot.Types; | ||
using PoliNetwork.Utility.MessageContentControl; | ||
|
||
namespace PoliNetwork.Telegram.Bot.Functionality.Example | ||
{ | ||
public class ResponseOnMessageFunctionality : AbstractTelegramBotFunctionality | ||
{ | ||
private static string[] CreateForbiddenWordsArray() | ||
{ | ||
var path = Config.FORBIDDEN_WORDS; | ||
Check warning on line 12 in Moderation/Moderation/src/Bot/Functionality/Example/ResponseOnMessageFunctionality.cs Codecov / codecov/patchModeration/Moderation/src/Bot/Functionality/Example/ResponseOnMessageFunctionality.cs#L11-L12
|
||
return JSONConverter.GetArrayFromFile(path) ?? Array.Empty<string>(); | ||
} | ||
Check warning on line 14 in Moderation/Moderation/src/Bot/Functionality/Example/ResponseOnMessageFunctionality.cs Codecov / codecov/patchModeration/Moderation/src/Bot/Functionality/Example/ResponseOnMessageFunctionality.cs#L14
|
||
|
||
public override async Task RunAsync(ITelegramBotClient bot, Update update, CancellationToken cancellationToken) | ||
{ | ||
Check warning on line 17 in Moderation/Moderation/src/Bot/Functionality/Example/ResponseOnMessageFunctionality.cs Codecov / codecov/patchModeration/Moderation/src/Bot/Functionality/Example/ResponseOnMessageFunctionality.cs#L17
|
||
/* This way we only process the message text part */ | ||
if (update.Message is not { } message) return; | ||
if (message.Text is not { } messageText) return; | ||
|
||
var chatId = message.Chat.Id; | ||
var username = message.Chat.Username; | ||
Check warning on line 23 in Moderation/Moderation/src/Bot/Functionality/Example/ResponseOnMessageFunctionality.cs Codecov / codecov/patchModeration/Moderation/src/Bot/Functionality/Example/ResponseOnMessageFunctionality.cs#L22-L23
|
||
|
||
var forbiddenWords = CreateForbiddenWordsArray(); | ||
var HasForbiddenWord = new ForbiddenWordsController(forbiddenWords).ContainsForbiddenWord(messageText); | ||
Check warning on line 26 in Moderation/Moderation/src/Bot/Functionality/Example/ResponseOnMessageFunctionality.cs Codecov / codecov/patchModeration/Moderation/src/Bot/Functionality/Example/ResponseOnMessageFunctionality.cs#L25-L26
|
||
|
||
var serverPrompt = $"Received a '{messageText}' message in chat {chatId} ({username})."; | ||
Check warning on line 28 in Moderation/Moderation/src/Bot/Functionality/Example/ResponseOnMessageFunctionality.cs Codecov / codecov/patchModeration/Moderation/src/Bot/Functionality/Example/ResponseOnMessageFunctionality.cs#L28
|
||
var responseText = HasForbiddenWord ? "Your massage contains a forbidden word" : "Your message is a valid one"; | ||
Console.WriteLine(serverPrompt); | ||
Check warning on line 30 in Moderation/Moderation/src/Bot/Functionality/Example/ResponseOnMessageFunctionality.cs Codecov / codecov/patchModeration/Moderation/src/Bot/Functionality/Example/ResponseOnMessageFunctionality.cs#L30
|
||
|
||
var sentMessage = await bot.SendTextMessageAsync( | ||
chatId: chatId, | ||
text: responseText, | ||
cancellationToken: cancellationToken | ||
); | ||
Check warning on line 36 in Moderation/Moderation/src/Bot/Functionality/Example/ResponseOnMessageFunctionality.cs Codecov / codecov/patchModeration/Moderation/src/Bot/Functionality/Example/ResponseOnMessageFunctionality.cs#L32-L36
|
||
|
||
serverPrompt = $"Sent message: {sentMessage.Text}"; | ||
Console.WriteLine(serverPrompt); | ||
} | ||
Check warning on line 40 in Moderation/Moderation/src/Bot/Functionality/Example/ResponseOnMessageFunctionality.cs Codecov / codecov/patchModeration/Moderation/src/Bot/Functionality/Example/ResponseOnMessageFunctionality.cs#L38-L40
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using Telegram.Bot; | ||
using Telegram.Bot.Types; | ||
|
||
namespace PoliNetwork.Telegram.Bot.Functionality | ||
{ | ||
/// <summary> | ||
/// Represents an interface for defining the functionality of a Telegram bot. | ||
/// </summary> | ||
public interface ITelegramBotFunctionality | ||
{ | ||
/// <summary> | ||
/// Runs the defined functionality using the provided <see cref="TelegramBot"/>. | ||
/// </summary> | ||
/// <param name="bot">The <see cref="TelegramBot"/> instance representing the bot with which the functionality is associated.</param> | ||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> | ||
Task RunAsync(ITelegramBotClient bot, Update update, CancellationToken cancellationToken); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using Telegram.Bot; | ||
using Telegram.Bot.Exceptions; | ||
|
||
namespace PoliNetwork.Telegram.Bot.Handler | ||
{ | ||
public class DefaultPollingErrorHandler : IPollingErrorHandler | ||
{ | ||
public Task HandlePollingErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken) | ||
{ | ||
var ErrorMessage = exception switch | ||
{ | ||
ApiRequestException apiRequestException | ||
=> $"Telegram API Error:\n[{apiRequestException.ErrorCode}]\n{apiRequestException.Message}", | ||
_ => exception.ToString() | ||
}; | ||
|
||
Console.WriteLine(ErrorMessage); | ||
return Task.CompletedTask; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using PoliNetwork.Telegram.Bot.Functionality; | ||
using Telegram.Bot; | ||
using Telegram.Bot.Types; | ||
|
||
namespace PoliNetwork.Telegram.Bot.Handler | ||
{ | ||
public class DefaultUpdateHandler : IUpdateHandler | ||
{ | ||
private readonly List<ITelegramBotFunctionality> Functionalities; | ||
|
||
public DefaultUpdateHandler(List<ITelegramBotFunctionality> functionalities) | ||
{ | ||
Functionalities = functionalities; | ||
} | ||
|
||
public async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken) | ||
{ | ||
/* Parallel.ForEach(_functionalities, functionalities => functionalities.Run(botClient, update, cancellationToken)); */ | ||
foreach (var functionality in Functionalities) | ||
{ | ||
await functionality.RunAsync(botClient, update, cancellationToken); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using System; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Telegram.Bot; | ||
|
||
namespace PoliNetwork.Telegram.Bot.Handler | ||
{ | ||
/// <summary> | ||
/// Represents an interface for handling errors that occur during the polling process of a Telegram bot. | ||
/// </summary> | ||
public interface IPollingErrorHandler | ||
{ | ||
/// <summary> | ||
/// Handles a polling error asynchronously. | ||
/// </summary> | ||
/// <param name="botClient">The <see cref="ITelegramBotClient"/> instance used for interaction with the Telegram Bot API.</param> | ||
/// <param name="exception">The <see cref="Exception"/> that occurred during the polling process.</param> | ||
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the asynchronous operation.</param> | ||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> | ||
Task HandlePollingErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
|
||
using Telegram.Bot; | ||
using Telegram.Bot.Types; | ||
|
||
namespace PoliNetwork.Telegram.Bot.Handler | ||
{ | ||
/// <summary> | ||
/// Represents an interface for handling incoming Telegram updates. | ||
/// </summary> | ||
public interface IUpdateHandler | ||
{ | ||
/// <summary> | ||
/// Handles an incoming Telegram update asynchronously. | ||
/// </summary> | ||
/// <param name="botClient">The <see cref="ITelegramBotClient"/> instance used for interaction with the Telegram Bot API.</param> | ||
/// <param name="update">The <see cref="Update"/> representing the incoming update to be handled.</param> | ||
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the asynchronous operation.</param> | ||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> | ||
Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
using PoliNetwork.Telegram.Bot.Handler; | ||
using Telegram.Bot; | ||
using Telegram.Bot.Polling; | ||
using Telegram.Bot.Types; | ||
using Telegram.Bot.Types.Enums; | ||
|
||
namespace PoliNetwork.Telegram.Bot | ||
{ | ||
/// <summary> | ||
/// Represents a Telegram bot that can interact with the Telegram Bot API. | ||
/// </summary> | ||
public class TelegramBot : TelegramBotClient | ||
{ | ||
/// <summary> | ||
/// Initializes a new instance of the <see cref="TelegramBot"/> class with the provided options and an optional HttpClient. | ||
/// </summary> | ||
/// <param name="options">The options specifying bot settings.</param> | ||
/// <param name="httpClient">Optional HttpClient to be used for API requests.</param> | ||
public TelegramBot(TelegramBotOptions options, HttpClient? httpClient = null) | ||
: base(options, httpClient) { } | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="TelegramBot"/> class with the provided bot token and an optional HttpClient. | ||
/// </summary> | ||
/// <param name="token">The authentication token of the bot.</param> | ||
/// <param name="httpClient">Optional HttpClient to be used for API requests.</param> | ||
public TelegramBot(string token, HttpClient? httpClient = null) | ||
: base(token, httpClient) { } | ||
|
||
public async Task RunAsync(Handler.IUpdateHandler updateHandler, IPollingErrorHandler pollingErrorHandler) | ||
{ | ||
using CancellationTokenSource cts = new(); | ||
|
||
ReceiverOptions receiverOptions = new() | ||
{ | ||
AllowedUpdates = Array.Empty<UpdateType>() | ||
}; | ||
|
||
this.StartReceiving( | ||
updateHandler: updateHandler.HandleUpdateAsync, | ||
pollingErrorHandler: pollingErrorHandler.HandlePollingErrorAsync, | ||
receiverOptions: receiverOptions, | ||
cancellationToken: cts.Token | ||
); | ||
|
||
var me = await this.GetMeAsync(); | ||
Console.WriteLine($"Start listening for @{me.Username}\nExit via typing"); | ||
Console.ReadLine(); | ||
cts.Cancel(); | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using Telegram.Bot; | ||
|
||
namespace PoliNetwork.Telegram.Bot | ||
{ | ||
/// <summary> | ||
/// Represents options for configuring a <see cref="TelegramBot"/>. | ||
/// </summary> | ||
public class TelegramBotOptions : TelegramBotClientOptions | ||
{ | ||
/// <summary> | ||
/// Initializes a new instance of the <see cref="TelegramBotOptions"/> class with the provided token, base URL, and test environment settings. | ||
/// </summary> | ||
/// <param name="token">The authentication token of the bot.</param> | ||
/// <param name="baseUrl">Optional base URL for API requests.</param> | ||
/// <param name="useTestEnvironment">Flag indicating whether to use the test environment.</param> | ||
protected TelegramBotOptions(string token, string? baseUrl = null, bool useTestEnvironment = false) | ||
: base(token, baseUrl, useTestEnvironment) { } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
namespace PoliNetwork.Utility.Configuration | ||
{ | ||
public static class Config | ||
{ | ||
private static readonly string? BASE_PATH = Directory.GetParent(Environment.CurrentDirectory)?.FullName; | ||
public static readonly string FORBIDDEN_WORDS = BASE_PATH + @"\Moderation\src\persistence\forbidden_words.json"; | ||
public static readonly string APP_SETTINGS = BASE_PATH + @"\Moderation\src\persistence\appsettings.json"; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,56 +1,29 @@ | ||
#region | ||
using PoliNetwork.Core.Utils; | ||
using PoliNetwork.Telegram.Logger; | ||
using PoliNetwork.Db.Utils; | ||
using PoliNetwork.Telegram.Configuration; | ||
using PoliNetwork.Telegram.ConfigurationLoader; | ||
using PoliNetwork.Db.Objects; | ||
using PoliNetwork.Telegram.Bot.Bots; | ||
using PoliNetwork.Telegram.Options; | ||
using PoliNetwork.Telegram.Properties; | ||
#endregion | ||
|
||
namespace Moderation; | ||
|
||
internal static class Program | ||
using PoliNetwork.Telegram.Bot; | ||
using PoliNetwork.Telegram.Bot.Functionality; | ||
using PoliNetwork.Telegram.Bot.Functionality.Example; | ||
using PoliNetwork.Telegram.Bot.Handler; | ||
using PoliNetwork.Utility.ConfigurationLoader; | ||
using PoliNetwork.Utility.Configuration; | ||
|
||
namespace PoliNetwork.Moderation | ||
{ | ||
private static ModerationBot? _bot = null; | ||
private const string DatabaseConfigurationPath = ""; | ||
|
||
public static void Main() | ||
internal abstract class Program | ||
{ | ||
/* The PoliNetwork.Core.Utils.LoggerNS.Logger must extends the AbstractLogger so a sub class will be needed | ||
The only dependency of the PoliNetwork.Core.Utils.LoggerNS.Logger resides here in the Program.cs */ | ||
AbstractLogger? logger = new DefaultLogger(); | ||
FileConfigurationLoader fileConfigurationLoader = new JSONFileConfigurationLoader(); | ||
AbstractTelegramBotOptions? botConfiguration = fileConfigurationLoader.LoadOrInitializeConfig(Configuration.TELEGRAM_CONFIGURATION_PATH, logger); | ||
|
||
DbConfig? databaseConfiguration = DbConfigUtils.LoadOrInitializeConfig(DatabaseConfigurationPath); | ||
if (botConfiguration == null) | ||
private static async Task Main() | ||
{ | ||
logger?.Emergency("Telegram Config is undefined when starting the bot."); | ||
return; | ||
} | ||
List<ITelegramBotFunctionality> telegramBotFunctionalities = new() | ||
{ | ||
new ResponseOnMessageFunctionality() | ||
}; | ||
|
||
if (databaseConfiguration == null) | ||
{ | ||
logger?.Emergency("Database Config is undefined when starting the bot."); | ||
return; | ||
} | ||
|
||
logger?.Info("RUNNING MODERATION BOT"); | ||
botConfiguration.UpdateMethod = new UpdateMethod(UpdateAction); | ||
IUpdateHandler updateHandler = new DefaultUpdateHandler(telegramBotFunctionalities); | ||
IPollingErrorHandler pollingErrorHandler = new DefaultPollingErrorHandler(); | ||
|
||
/* TelegramConfiguration should extends TelegramBotClientOptions */ | ||
_bot = new ModerationBot(options: botConfiguration, logger: logger); | ||
_bot.Start(new CancellationToken()); | ||
Wait.WaitForever(); | ||
} | ||
var botToken = new JSONConfigurationLoader().LoadConfiguration(Config.APP_SETTINGS) | ||
.GetSection("Secrets:BotToken").Value!; | ||
TelegramBot bot = new(botToken); | ||
|
||
private static void UpdateAction(CancellationToken cancellationToken, IUpdate update) | ||
{ | ||
/* Process Message updates only, see: https://core.telegram.org/bots/api#message */ | ||
if (_bot == null || update.Message is not { } message) return; | ||
_bot.Echo(message, cancellationToken); | ||
await bot.RunAsync(updateHandler, pollingErrorHandler); | ||
} | ||
} | ||
} |