From f1c626a7babc3586f79ff7cf127876e03dbb7ab1 Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Tue, 8 Feb 2022 16:56:35 +0100 Subject: [PATCH 01/33] Integrate new Message Loop --- .../Interfaces/IMessageLoopSelectionStage.cs | 44 +++++++++++++ .../MessageLoops/MinimalMessageLoop.cs | 62 +++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 TelegramBotBase/Builder/Interfaces/IMessageLoopSelectionStage.cs create mode 100644 TelegramBotBase/Factories/MessageLoops/MinimalMessageLoop.cs diff --git a/TelegramBotBase/Builder/Interfaces/IMessageLoopSelectionStage.cs b/TelegramBotBase/Builder/Interfaces/IMessageLoopSelectionStage.cs new file mode 100644 index 0000000..429a81d --- /dev/null +++ b/TelegramBotBase/Builder/Interfaces/IMessageLoopSelectionStage.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Text; +using TelegramBotBase.Form; +using TelegramBotBase.Interfaces; + +namespace TelegramBotBase.Builder.Interfaces +{ + public interface IMessageLoopSelectionStage + { + + /// + /// Chooses a default message loop. + /// + /// + /// + IStartFormSelectionStage DefaultMessageLoop(); + + + /// + /// Chooses a minimalistic message loop, which catches all update types and only calls the Load function. + /// + /// + IStartFormSelectionStage MinimalMessageLoop(); + + + /// + /// Chooses a custom message loop. + /// + /// + /// + IStartFormSelectionStage CustomMessageLoop(IMessageLoopFactory startFormClass); + + + /// + /// Chooses a custom message loop. + /// + /// + /// + IStartFormSelectionStage CustomMessageLoop() where T : class, new(); + + + } +} diff --git a/TelegramBotBase/Factories/MessageLoops/MinimalMessageLoop.cs b/TelegramBotBase/Factories/MessageLoops/MinimalMessageLoop.cs new file mode 100644 index 0000000..2e3965e --- /dev/null +++ b/TelegramBotBase/Factories/MessageLoops/MinimalMessageLoop.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Telegram.Bot.Types; +using TelegramBotBase.Args; +using TelegramBotBase.Base; +using TelegramBotBase.Enums; +using TelegramBotBase.Interfaces; +using TelegramBotBase.Sessions; + +namespace TelegramBotBase.Factories.MessageLoops +{ + public class MinimalMessageLoop : IMessageLoopFactory + { + private static object __evUnhandledCall = new object(); + + private EventHandlerList __Events = new EventHandlerList(); + + public MinimalMessageLoop() + { + + } + + public async Task MessageLoop(BotBase Bot, DeviceSession session, UpdateResult ur, MessageResult mr) + { + var update = ur.RawData; + + + mr.Device = session; + + var activeForm = session.ActiveForm; + + //Loading Event + await activeForm.Load(mr); + + } + + /// + /// Will be called if no form handeled this call + /// + public event EventHandler UnhandledCall + { + add + { + this.__Events.AddHandler(__evUnhandledCall, value); + } + remove + { + this.__Events.RemoveHandler(__evUnhandledCall, value); + } + } + + public void OnUnhandledCall(UnhandledCallEventArgs e) + { + (this.__Events[__evUnhandledCall] as EventHandler)?.Invoke(this, e); + + } + } +} From 8fa952e68b6df35a57c5788a657c063c6cf229a3 Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Tue, 8 Feb 2022 17:08:11 +0100 Subject: [PATCH 02/33] Update .gitignore --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index e49c333..91d25bb 100644 --- a/.gitignore +++ b/.gitignore @@ -252,3 +252,8 @@ TelegramBotBase/Archive /TelegramBotBase/TelegramBotBase.1.5.2.zip /TelegramBotBase/cpush.ps1 /TelegramBotBase/cpack.ps1 +*.ps1 +*.exe +*.snupkg +*.zip +*.nuspec From d7a5c149b1ab81859d43d2983558e778349d8434 Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Tue, 8 Feb 2022 18:07:59 +0100 Subject: [PATCH 03/33] Replacing BotCommands with BotCommandsScope --- TelegramBotBase/Builder/BotBaseBuilder.cs | 31 +++-- .../Builder/Interfaces/IBotCommandsStage.cs | 4 +- TelegramBotBase/Commands/Extensions.cs | 123 ++++++++++++++++-- 3 files changed, 141 insertions(+), 17 deletions(-) diff --git a/TelegramBotBase/Builder/BotBaseBuilder.cs b/TelegramBotBase/Builder/BotBaseBuilder.cs index 517a8fb..69be91a 100644 --- a/TelegramBotBase/Builder/BotBaseBuilder.cs +++ b/TelegramBotBase/Builder/BotBaseBuilder.cs @@ -23,7 +23,12 @@ namespace TelegramBotBase.Builder MessageClient _client = null; - List _botcommands = new List(); + /// + /// Contains different Botcommands for different areas. + /// + Dictionary> _BotCommandScopes { get; set; } = new Dictionary>(); + + //List _botcommands = new List(); IStateMachine _statemachine = null; @@ -116,6 +121,15 @@ namespace TelegramBotBase.Builder return this; } + + public IStartFormSelectionStage MinimalMessageLoop() + { + _messageloopfactory = new Factories.MessageLoops.MinimalMessageLoop(); + + return this; + } + + public IStartFormSelectionStage CustomMessageLoop(IMessageLoopFactory messageLoopClass) { _messageloopfactory = messageLoopClass; @@ -212,7 +226,7 @@ namespace TelegramBotBase.Builder public ISessionSerializationStage OnlyStart() { - _botcommands.Start("Starts the bot"); + _BotCommandScopes.Start("Starts the bot"); return this; @@ -220,15 +234,15 @@ namespace TelegramBotBase.Builder public ISessionSerializationStage DefaultCommands() { - _botcommands.Start("Starts the bot"); - _botcommands.Help("Should show you some help"); - _botcommands.Settings("Should show you some settings"); + _BotCommandScopes.Start("Starts the bot"); + _BotCommandScopes.Help("Should show you some help"); + _BotCommandScopes.Settings("Should show you some settings"); return this; } - public ISessionSerializationStage CustomCommands(Action> action) + public ISessionSerializationStage CustomCommands(Action>> action) { - action?.Invoke(_botcommands); + action?.Invoke(_BotCommandScopes); return this; } @@ -309,7 +323,8 @@ namespace TelegramBotBase.Builder bb.Sessions.Client = bb.Client; - bb.BotCommands = _botcommands; + bb.BotCommandScopes = _BotCommandScopes; + //bb.BotCommands = _botcommands; bb.StateMachine = _statemachine; diff --git a/TelegramBotBase/Builder/Interfaces/IBotCommandsStage.cs b/TelegramBotBase/Builder/Interfaces/IBotCommandsStage.cs index cb1507c..a275090 100644 --- a/TelegramBotBase/Builder/Interfaces/IBotCommandsStage.cs +++ b/TelegramBotBase/Builder/Interfaces/IBotCommandsStage.cs @@ -33,7 +33,9 @@ namespace TelegramBotBase.Builder.Interfaces /// /// /// - ISessionSerializationStage CustomCommands(Action> action); + + ISessionSerializationStage CustomCommands(Action>> action); + } } diff --git a/TelegramBotBase/Commands/Extensions.cs b/TelegramBotBase/Commands/Extensions.cs index a07c031..55dcf83 100644 --- a/TelegramBotBase/Commands/Extensions.cs +++ b/TelegramBotBase/Commands/Extensions.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Data; +using System.Linq; using System.Text; using Telegram.Bot.Types; @@ -12,9 +14,9 @@ namespace TelegramBotBase.Commands /// /// /// - public static void Start(this List cmds, String description) + public static void Start(this Dictionary> cmds, String description, BotCommandScope scope = null) { - cmds.Add(new BotCommand() { Command = "start", Description = description }); + Add(cmds, "start", description, scope); } /// @@ -22,9 +24,10 @@ namespace TelegramBotBase.Commands /// /// /// - public static void Help(this List cmds, String description) + + public static void Help(this Dictionary> cmds, String description, BotCommandScope scope = null) { - cmds.Add(new BotCommand() { Command = "help", Description = description }); + Add(cmds, "help", description, scope); } /// @@ -32,9 +35,37 @@ namespace TelegramBotBase.Commands /// /// /// - public static void Settings(this List cmds, String description) + + + public static void Settings(this Dictionary> cmds, String description, BotCommandScope scope = null) { - cmds.Add(new BotCommand() { Command = "settings", Description = description }); + Add(cmds, "settings", description, scope); + } + + + /// + /// Adding the command with a description. + /// + /// + /// + /// + public static void Add(this Dictionary> cmds, String command, String description, BotCommandScope scope = null) + { + if (scope == null) + { + scope = new BotCommandScopeDefault(); + } + + var item = cmds.FirstOrDefault(a => a.Key.Type == scope.Type); + + if (item.Value != null) + { + item.Value.Add(new BotCommand() { Command = command, Description = description }); + } + else + { + cmds.Add(scope, new List { new BotCommand() { Command = command, Description = description } }); + } } /// @@ -43,9 +74,85 @@ namespace TelegramBotBase.Commands /// /// /// - public static void Add(this List cmds, String command, String description) + public static void Clear(this Dictionary> cmds, BotCommandScope scope = null) { - cmds.Add(new BotCommand() { Command = command, Description = description }); + if (scope == null) + { + scope = new BotCommandScopeDefault(); + } + + var item = cmds.FirstOrDefault(a => a.Key.Type == scope.Type); + + if (item.Key != null) + { + cmds[item.Key] = null; + } + else + { + cmds[scope] = null; + } + + + } + + /// + /// Adding a group command with a description. + /// + /// + /// + /// + public static void AddGroupCommand(this Dictionary> cmds, String command, String description) + { + Add(cmds, command, description, new BotCommandScopeAllGroupChats()); + } + + /// + /// Clears all group commands. + /// + /// + public static void ClearGroupCommands(this Dictionary> cmds) + { + Clear(cmds, new BotCommandScopeAllGroupChats()); + } + + /// + /// Adding group admin command with a description. + /// + /// + /// + /// + public static void AddGroupAdminCommand(this Dictionary> cmds, String command, String description) + { + Add(cmds, command, description, new BotCommandScopeAllChatAdministrators()); + } + + /// + /// Clears all group admin commands. + /// + /// + public static void ClearGroupAdminCommand(this Dictionary> cmds) + { + Clear(cmds, new BotCommandScopeAllChatAdministrators()); + } + + /// + /// Adding a privat command with a description. + /// + /// + /// + /// + public static void AddPrivateChatCommand(this Dictionary> cmds, String command, String description) + { + Add(cmds, command, description, new BotCommandScopeAllPrivateChats()); + } + + /// + /// Clears all private commands. + /// + /// + public static void ClearPrivateChatCommand(this Dictionary> cmds) + { + Clear(cmds, new BotCommandScopeAllPrivateChats()); } } } From e2ac7975a526d5523f6b6b4e1e89ad1e57f0d6cb Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Sat, 19 Mar 2022 04:22:07 +0100 Subject: [PATCH 04/33] Updating example projects to .NET 6 and latest framework. --- Examples/AsyncFormUpdates/App.config | 14 +++++++++++--- .../AsyncFormUpdates/AsyncFormUpdates.csproj | 17 ++++++++++++----- Examples/AsyncFormUpdates/Program.cs | 7 +++++-- Examples/AsyncFormUpdates/packages.config | 6 ++++-- Examples/JoinHiderBot/JoinHiderBot.csproj | 4 ++-- Examples/JoinHiderBot/Program.cs | 5 ++++- Examples/SystemCommandsBot/Program.cs | 5 ++++- .../SystemCommandsBot/SystemCommandsBot.csproj | 6 +++--- TelegramBotFramework.sln | 13 ++++++++++--- 9 files changed, 55 insertions(+), 22 deletions(-) diff --git a/Examples/AsyncFormUpdates/App.config b/Examples/AsyncFormUpdates/App.config index 56efbc7..436e44f 100644 --- a/Examples/AsyncFormUpdates/App.config +++ b/Examples/AsyncFormUpdates/App.config @@ -1,6 +1,14 @@ - + - + - \ No newline at end of file + + + + + + + + + diff --git a/Examples/AsyncFormUpdates/AsyncFormUpdates.csproj b/Examples/AsyncFormUpdates/AsyncFormUpdates.csproj index 212f87e..5c48fb5 100644 --- a/Examples/AsyncFormUpdates/AsyncFormUpdates.csproj +++ b/Examples/AsyncFormUpdates/AsyncFormUpdates.csproj @@ -8,10 +8,11 @@ Exe AsyncFormUpdates AsyncFormUpdates - v4.7.2 + v4.8 512 true true + AnyCPU @@ -33,19 +34,25 @@ 4 - - ..\..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll + + ..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll + + ..\..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + ..\..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + - - ..\..\packages\Telegram.Bot.15.7.1\lib\net45\Telegram.Bot.dll + + ..\..\packages\Telegram.Bot.17.0.0\lib\netstandard2.0\Telegram.Bot.dll diff --git a/Examples/AsyncFormUpdates/Program.cs b/Examples/AsyncFormUpdates/Program.cs index f249391..b12cb83 100644 --- a/Examples/AsyncFormUpdates/Program.cs +++ b/Examples/AsyncFormUpdates/Program.cs @@ -4,18 +4,21 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Timers; +using TelegramBotBase.Builder; namespace AsyncFormUpdates { class Program { - static TelegramBotBase.BotBase bot = null; + static TelegramBotBase.BotBase bot = null; static void Main(string[] args) { String apiKey = "APIKey"; - bot = new TelegramBotBase.BotBase(apiKey); + bot = BotBaseBuilder.Create() + .QuickStart(apiKey) + .Build(); bot.Start(); diff --git a/Examples/AsyncFormUpdates/packages.config b/Examples/AsyncFormUpdates/packages.config index e25dbb0..e9dd729 100644 --- a/Examples/AsyncFormUpdates/packages.config +++ b/Examples/AsyncFormUpdates/packages.config @@ -1,6 +1,8 @@  - + - + + + \ No newline at end of file diff --git a/Examples/JoinHiderBot/JoinHiderBot.csproj b/Examples/JoinHiderBot/JoinHiderBot.csproj index 1c137aa..aa8f8d7 100644 --- a/Examples/JoinHiderBot/JoinHiderBot.csproj +++ b/Examples/JoinHiderBot/JoinHiderBot.csproj @@ -2,11 +2,11 @@ Exe - netcoreapp3.1 + net6.0 - + diff --git a/Examples/JoinHiderBot/Program.cs b/Examples/JoinHiderBot/Program.cs index e3c2ec5..d2d05fe 100644 --- a/Examples/JoinHiderBot/Program.cs +++ b/Examples/JoinHiderBot/Program.cs @@ -1,4 +1,5 @@ using System; +using TelegramBotBase.Builder; namespace JoinHiderBot { @@ -9,7 +10,9 @@ namespace JoinHiderBot String apiKey = ""; - var bot = new TelegramBotBase.BotBase(apiKey); + var bot = BotBaseBuilder.Create() + .QuickStart(apiKey) + .Build(); bot.Start(); diff --git a/Examples/SystemCommandsBot/Program.cs b/Examples/SystemCommandsBot/Program.cs index efe0e93..17ff8b7 100644 --- a/Examples/SystemCommandsBot/Program.cs +++ b/Examples/SystemCommandsBot/Program.cs @@ -1,4 +1,5 @@ using System; +using TelegramBotBase.Builder; namespace SystemCommandsBot { @@ -19,7 +20,9 @@ namespace SystemCommandsBot return; } - var bot = new TelegramBotBase.BotBase(BotConfig.ApiKey); + var bot = BotBaseBuilder.Create() + .QuickStart(BotConfig.ApiKey) + .Build(); bot.Start(); diff --git a/Examples/SystemCommandsBot/SystemCommandsBot.csproj b/Examples/SystemCommandsBot/SystemCommandsBot.csproj index c47ad1b..4e20f6a 100644 --- a/Examples/SystemCommandsBot/SystemCommandsBot.csproj +++ b/Examples/SystemCommandsBot/SystemCommandsBot.csproj @@ -2,12 +2,12 @@ Exe - netcoreapp3.1 + net6.0 - - + + diff --git a/TelegramBotFramework.sln b/TelegramBotFramework.sln index 326160e..a4b6c21 100644 --- a/TelegramBotFramework.sln +++ b/TelegramBotFramework.sln @@ -14,11 +14,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{BFA71E3F-31C0-4FC1-A320-4DCF704768C5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemCommandsBot", "Examples\SystemCommandsBot\SystemCommandsBot.csproj", "{FC484952-3060-4F87-9809-4CD66D6961C0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemCommandsBot", "Examples\SystemCommandsBot\SystemCommandsBot.csproj", "{FC484952-3060-4F87-9809-4CD66D6961C0}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JoinHiderBot", "Examples\JoinHiderBot\JoinHiderBot.csproj", "{E804B9E5-7ACC-49D3-9253-806766C1D9A5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JoinHiderBot", "Examples\JoinHiderBot\JoinHiderBot.csproj", "{E804B9E5-7ACC-49D3-9253-806766C1D9A5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TelegramBotBase.Extensions.Images", "TelegramBotBase.Extensions.Images\TelegramBotBase.Extensions.Images.csproj", "{B5DDFA45-0E01-46A5-B67D-541300CDD606}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TelegramBotBase.Extensions.Images", "TelegramBotBase.Extensions.Images\TelegramBotBase.Extensions.Images.csproj", "{B5DDFA45-0E01-46A5-B67D-541300CDD606}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsyncFormUpdates", "Examples\AsyncFormUpdates\AsyncFormUpdates.csproj", "{673A56F5-6110-4AED-A68D-562FD6ED3EA6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -46,6 +48,10 @@ Global {B5DDFA45-0E01-46A5-B67D-541300CDD606}.Debug|Any CPU.Build.0 = Debug|Any CPU {B5DDFA45-0E01-46A5-B67D-541300CDD606}.Release|Any CPU.ActiveCfg = Release|Any CPU {B5DDFA45-0E01-46A5-B67D-541300CDD606}.Release|Any CPU.Build.0 = Release|Any CPU + {673A56F5-6110-4AED-A68D-562FD6ED3EA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {673A56F5-6110-4AED-A68D-562FD6ED3EA6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {673A56F5-6110-4AED-A68D-562FD6ED3EA6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {673A56F5-6110-4AED-A68D-562FD6ED3EA6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -53,6 +59,7 @@ Global GlobalSection(NestedProjects) = preSolution {FC484952-3060-4F87-9809-4CD66D6961C0} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5} {E804B9E5-7ACC-49D3-9253-806766C1D9A5} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5} + {673A56F5-6110-4AED-A68D-562FD6ED3EA6} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {59CB40E1-9FA7-4867-A56F-4F418286F057} From d08cbe8b0ebfbba44bd26d84e062a74862c76abb Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Sat, 16 Apr 2022 15:36:55 +0200 Subject: [PATCH 05/33] Bugfix with MessageResult leads to having not access to MessageClient --- TelegramBotBase/Base/MessageResult.cs | 6 ------ TelegramBotBase/Base/ResultBase.cs | 16 +++++++++++++++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/TelegramBotBase/Base/MessageResult.cs b/TelegramBotBase/Base/MessageResult.cs index 762ac8f..2e6148b 100644 --- a/TelegramBotBase/Base/MessageResult.cs +++ b/TelegramBotBase/Base/MessageResult.cs @@ -29,12 +29,6 @@ namespace TelegramBotBase.Base } } - public DeviceSession Device - { - get; - set; - } - /// /// The message id /// diff --git a/TelegramBotBase/Base/ResultBase.cs b/TelegramBotBase/Base/ResultBase.cs index e5d37e8..5cce472 100644 --- a/TelegramBotBase/Base/ResultBase.cs +++ b/TelegramBotBase/Base/ResultBase.cs @@ -4,12 +4,26 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Telegram.Bot; +using TelegramBotBase.Sessions; namespace TelegramBotBase.Base { public class ResultBase : EventArgs { - public MessageClient Client { get; set; } + public MessageClient Client + { + get + { + return Device.ActiveForm.Client; + } + } + + + public DeviceSession Device + { + get; + set; + } public virtual long DeviceId { get; set; } From 72a1fa3c99f8f7d0f267c7294ba7630095ec6b57 Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Sun, 15 May 2022 15:41:24 +0200 Subject: [PATCH 06/33] Replacing Client in ResultBase and subclasses - replace Client with Device to allow more access - making Client in DeviceSession public to allow access from outside --- TelegramBotBase/Base/DataResult.cs | 28 +++++++++++------------ TelegramBotBase/Base/ResultBase.cs | 11 +-------- TelegramBotBase/Sessions/DeviceSession.cs | 2 +- 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/TelegramBotBase/Base/DataResult.cs b/TelegramBotBase/Base/DataResult.cs index 8fc9e34..fab04bd 100644 --- a/TelegramBotBase/Base/DataResult.cs +++ b/TelegramBotBase/Base/DataResult.cs @@ -109,7 +109,7 @@ namespace TelegramBotBase.Base public async Task DownloadDocument() { var encryptedContent = new System.IO.MemoryStream(this.Document.FileSize.Value); - var file = await this.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Document.FileId, encryptedContent); + var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Document.FileId, encryptedContent); return new InputOnlineFile(encryptedContent, this.Document.FileName); } @@ -122,9 +122,9 @@ namespace TelegramBotBase.Base /// public async Task DownloadDocument(String path) { - var file = await this.Client.TelegramClient.GetFileAsync(this.Document.FileId); + var file = await Device.Client.TelegramClient.GetFileAsync(this.Document.FileId); FileStream fs = new FileStream(path, FileMode.Create); - await this.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs); + await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs); fs.Close(); fs.Dispose(); } @@ -136,7 +136,7 @@ namespace TelegramBotBase.Base public async Task DownloadRawDocument() { MemoryStream ms = new MemoryStream(); - await this.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Document.FileId, ms); + await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Document.FileId, ms); return ms.ToArray(); } @@ -156,7 +156,7 @@ namespace TelegramBotBase.Base public async Task DownloadRawTextDocument(Encoding encoding) { MemoryStream ms = new MemoryStream(); - await this.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Document.FileId, ms); + await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Document.FileId, ms); ms.Position = 0; @@ -168,16 +168,16 @@ namespace TelegramBotBase.Base public async Task DownloadVideo() { var encryptedContent = new System.IO.MemoryStream(this.Video.FileSize.Value); - var file = await this.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Video.FileId, encryptedContent); + var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Video.FileId, encryptedContent); return new InputOnlineFile(encryptedContent, ""); } public async Task DownloadVideo(String path) { - var file = await this.Client.TelegramClient.GetFileAsync(this.Video.FileId); + var file = await Device.Client.TelegramClient.GetFileAsync(this.Video.FileId); FileStream fs = new FileStream(path, FileMode.Create); - await this.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs); + await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs); fs.Close(); fs.Dispose(); } @@ -185,16 +185,16 @@ namespace TelegramBotBase.Base public async Task DownloadAudio() { var encryptedContent = new System.IO.MemoryStream(this.Audio.FileSize.Value); - var file = await this.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Audio.FileId, encryptedContent); + var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Audio.FileId, encryptedContent); return new InputOnlineFile(encryptedContent, ""); } public async Task DownloadAudio(String path) { - var file = await this.Client.TelegramClient.GetFileAsync(this.Audio.FileId); + var file = await Device.Client.TelegramClient.GetFileAsync(this.Audio.FileId); FileStream fs = new FileStream(path, FileMode.Create); - await this.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs); + await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs); fs.Close(); fs.Dispose(); } @@ -203,7 +203,7 @@ namespace TelegramBotBase.Base { var photo = this.Photos[index]; var encryptedContent = new System.IO.MemoryStream(photo.FileSize.Value); - var file = await this.Client.TelegramClient.GetInfoAndDownloadFileAsync(photo.FileId, encryptedContent); + var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(photo.FileId, encryptedContent); return new InputOnlineFile(encryptedContent, ""); } @@ -211,9 +211,9 @@ namespace TelegramBotBase.Base public async Task DownloadPhoto(int index, String path) { var photo = this.Photos[index]; - var file = await this.Client.TelegramClient.GetFileAsync(photo.FileId); + var file = await Device.Client.TelegramClient.GetFileAsync(photo.FileId); FileStream fs = new FileStream(path, FileMode.Create); - await this.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs); + await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs); fs.Close(); fs.Dispose(); } diff --git a/TelegramBotBase/Base/ResultBase.cs b/TelegramBotBase/Base/ResultBase.cs index 5cce472..adf8ecc 100644 --- a/TelegramBotBase/Base/ResultBase.cs +++ b/TelegramBotBase/Base/ResultBase.cs @@ -10,15 +10,6 @@ namespace TelegramBotBase.Base { public class ResultBase : EventArgs { - public MessageClient Client - { - get - { - return Device.ActiveForm.Client; - } - } - - public DeviceSession Device { get; @@ -56,7 +47,7 @@ namespace TelegramBotBase.Base { try { - await this.Client.TelegramClient.DeleteMessageAsync(this.DeviceId, (messageId == -1 ? this.MessageId : messageId)); + await Device.Client.TelegramClient.DeleteMessageAsync(this.DeviceId, (messageId == -1 ? this.MessageId : messageId)); } catch { diff --git a/TelegramBotBase/Sessions/DeviceSession.cs b/TelegramBotBase/Sessions/DeviceSession.cs index 945abfd..bbe4e5a 100644 --- a/TelegramBotBase/Sessions/DeviceSession.cs +++ b/TelegramBotBase/Sessions/DeviceSession.cs @@ -84,7 +84,7 @@ namespace TelegramBotBase.Sessions /// public Message LastMessage { get; set; } - private MessageClient Client + public MessageClient Client { get { From e81f535f7528d46b77934e80f9ab7736a037375f Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Sun, 15 May 2022 15:42:53 +0200 Subject: [PATCH 07/33] New methods for SendingVideo - adding SendVideo by byte array - adding SendLocalVideo to send videofile from disk --- TelegramBotBase/Sessions/DeviceSession.cs | 74 ++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/TelegramBotBase/Sessions/DeviceSession.cs b/TelegramBotBase/Sessions/DeviceSession.cs index bbe4e5a..059d040 100644 --- a/TelegramBotBase/Sessions/DeviceSession.cs +++ b/TelegramBotBase/Sessions/DeviceSession.cs @@ -453,7 +453,7 @@ namespace TelegramBotBase.Sessions /// /// Sends an video /// - /// + /// /// /// /// @@ -480,6 +480,78 @@ namespace TelegramBotBase.Sessions } } + /// + /// Sends an video + /// + /// + /// + /// + /// + /// + /// + public async Task SendVideo(String filename, byte[] video, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false, ParseMode parseMode = ParseMode.Markdown) + { + if (this.ActiveForm == null) + return null; + + InlineKeyboardMarkup markup = buttons; + + try + { + MemoryStream ms = new MemoryStream(video); + + InputOnlineFile fts = new InputOnlineFile(ms, filename); + + var t = API(a => a.SendVideoAsync(this.DeviceId, fts, parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification)); + + var o = GetOrigin(new StackTrace()); + OnMessageSent(new MessageSentEventArgs(await t, o)); + + return await t; + } + catch + { + return null; + } + } + + /// + /// Sends an local file as video + /// + /// + /// + /// + /// + /// + /// + public async Task SendLocalVideo(String filepath, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false, ParseMode parseMode = ParseMode.Markdown) + { + if (this.ActiveForm == null) + return null; + + InlineKeyboardMarkup markup = buttons; + + try + { + FileStream fs = new FileStream(filepath, FileMode.Open); + + var filename = Path.GetFileName(filepath); + + InputOnlineFile fts = new InputOnlineFile(fs, filename); + + var t = API(a => a.SendVideoAsync(this.DeviceId, fts, parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification)); + + var o = GetOrigin(new StackTrace()); + OnMessageSent(new MessageSentEventArgs(await t, o)); + + return await t; + } + catch + { + return null; + } + } + /// /// Sends an document /// From 2c567419ece60839850b59df96da048e5e46d021 Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Sun, 15 May 2022 23:17:01 +0200 Subject: [PATCH 08/33] Update MessageClient.cs - increasing parameters for Get/SetCommand methods - adding DeleteBotCommands methods --- TelegramBotBase/Base/MessageClient.cs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/TelegramBotBase/Base/MessageClient.cs b/TelegramBotBase/Base/MessageClient.cs index e252f35..85195f9 100644 --- a/TelegramBotBase/Base/MessageClient.cs +++ b/TelegramBotBase/Base/MessageClient.cs @@ -159,27 +159,35 @@ namespace TelegramBotBase.Base /// This will return the current list of bot commands. /// /// - public async Task GetBotCommands() + public async Task GetBotCommands(BotCommandScope scope = null, String languageCode = null) { - return await this.TelegramClient.GetMyCommandsAsync(); + return await this.TelegramClient.GetMyCommandsAsync(scope, languageCode); } + /// /// This will set your bot commands to the given list. /// /// /// - public async Task SetBotCommands(List botcommands) + public async Task SetBotCommands(List botcommands, BotCommandScope scope = null, String languageCode = null) { - await this.TelegramClient.SetMyCommandsAsync(botcommands); + await this.TelegramClient.SetMyCommandsAsync(botcommands, scope, languageCode); } - + /// + /// This will delete the current list of bot commands. + /// + /// + public async Task DeleteBotCommands(BotCommandScope scope = null, String languageCode = null) + { + await this.TelegramClient.DeleteMyCommandsAsync(scope, languageCode); + } #region "Events" - + public event Async.AsyncEventHandler MessageLoop { From 707ffd492f21ce5f3b9a71420eb044c8f247272a Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Sun, 15 May 2022 23:20:16 +0200 Subject: [PATCH 09/33] Upgrading BotCommands to new BotCommandScope format - adding IsKnownBotCommand method to BotBase - updated UploadBotCommand method to new format - adding new Commandformat to BotBaseBuilder - adding AddChatCommand and ClearChatCommand for custom Chat commands - integrating new checks into FormBaseMessageLoop --- TelegramBotBase/BotBase.cs | 33 ++++++++++++-- TelegramBotBase/Builder/BotBaseBuilder.cs | 1 - TelegramBotBase/Commands/Extensions.cs | 44 +++++++++++++++---- .../MessageLoops/FormBaseMessageLoop.cs | 2 +- 4 files changed, 67 insertions(+), 13 deletions(-) diff --git a/TelegramBotBase/BotBase.cs b/TelegramBotBase/BotBase.cs index c853c30..38977d6 100644 --- a/TelegramBotBase/BotBase.cs +++ b/TelegramBotBase/BotBase.cs @@ -41,7 +41,7 @@ namespace TelegramBotBase /// /// Contains System commands which will be available at everytime and didnt get passed to forms, i.e. /start /// - public List BotCommands { get; set; } + public Dictionary> BotCommandScopes { get; set; } = new Dictionary>(); #region "Events" @@ -93,7 +93,7 @@ namespace TelegramBotBase SetSetting(eSettings.SkipAllMessages, false); SetSetting(eSettings.SaveSessionsOnConsoleExit, false); - this.BotCommands = new List(); + this.BotCommandScopes = new Dictionary>(); this.Sessions = new SessionBase(); this.Sessions.BotBase = this; @@ -247,7 +247,34 @@ namespace TelegramBotBase /// public async Task UploadBotCommands() { - await this.Client.SetBotCommands(this.BotCommands); + foreach (var bs in this.BotCommandScopes) + { + if(bs.Value !=null) + { + await this.Client.SetBotCommands(bs.Value, bs.Key); + } + else + { + await this.Client.DeleteBotCommands(bs.Key); + } + + } + } + + /// + /// Searching if parameter is a known command in all configured BotCommandScopes. + /// + /// + /// + public bool IsKnownBotCommand(String command) + { + foreach (var scope in this.BotCommandScopes) + { + if (scope.Value.Any(a => "/" + a.Command == command)) + return true; + } + + return false; } /// diff --git a/TelegramBotBase/Builder/BotBaseBuilder.cs b/TelegramBotBase/Builder/BotBaseBuilder.cs index 69be91a..403e1a5 100644 --- a/TelegramBotBase/Builder/BotBaseBuilder.cs +++ b/TelegramBotBase/Builder/BotBaseBuilder.cs @@ -324,7 +324,6 @@ namespace TelegramBotBase.Builder bb.Sessions.Client = bb.Client; bb.BotCommandScopes = _BotCommandScopes; - //bb.BotCommands = _botcommands; bb.StateMachine = _statemachine; diff --git a/TelegramBotBase/Commands/Extensions.cs b/TelegramBotBase/Commands/Extensions.cs index 55dcf83..c98903c 100644 --- a/TelegramBotBase/Commands/Extensions.cs +++ b/TelegramBotBase/Commands/Extensions.cs @@ -14,9 +14,9 @@ namespace TelegramBotBase.Commands /// /// /// - public static void Start(this Dictionary> cmds, String description, BotCommandScope scope = null) + public static void Start(this Dictionary> cmds, String description) { - Add(cmds, "start", description, scope); + Add(cmds, "start", description, null); } /// @@ -25,9 +25,9 @@ namespace TelegramBotBase.Commands /// /// - public static void Help(this Dictionary> cmds, String description, BotCommandScope scope = null) + public static void Help(this Dictionary> cmds, String description) { - Add(cmds, "help", description, scope); + Add(cmds, "help", description, null); } /// @@ -37,9 +37,9 @@ namespace TelegramBotBase.Commands /// - public static void Settings(this Dictionary> cmds, String description, BotCommandScope scope = null) + public static void Settings(this Dictionary> cmds, String description) { - Add(cmds, "settings", description, scope); + Add(cmds, "settings", description, null); } @@ -53,7 +53,7 @@ namespace TelegramBotBase.Commands { if (scope == null) { - scope = new BotCommandScopeDefault(); + scope = BotCommandScope.Default(); } var item = cmds.FirstOrDefault(a => a.Key.Type == scope.Type); @@ -78,7 +78,7 @@ namespace TelegramBotBase.Commands { if (scope == null) { - scope = new BotCommandScopeDefault(); + scope = BotCommandScope.Default(); } var item = cmds.FirstOrDefault(a => a.Key.Type == scope.Type); @@ -91,8 +91,36 @@ namespace TelegramBotBase.Commands { cmds[scope] = null; } + } + + /// + /// Clears all default commands. + /// + /// + public static void ClearDefaultCommands(this Dictionary> cmds) + { + Clear(cmds, null); + } + /// + /// Clears all commands of a specific device. + /// + /// + public static void ClearChatCommands(this Dictionary> cmds, long DeviceId) + { + Clear(cmds, new BotCommandScopeChat() { ChatId = DeviceId }); + } + + /// + /// Adding a chat command with a description. + /// + /// + /// + /// + public static void AddChatCommand(this Dictionary> cmds, long DeviceId, String command, String description) + { + Add(cmds, command, description, new BotCommandScopeChat() { ChatId = DeviceId }); } /// diff --git a/TelegramBotBase/Factories/MessageLoops/FormBaseMessageLoop.cs b/TelegramBotBase/Factories/MessageLoops/FormBaseMessageLoop.cs index 6568e19..3dcc641 100644 --- a/TelegramBotBase/Factories/MessageLoops/FormBaseMessageLoop.cs +++ b/TelegramBotBase/Factories/MessageLoops/FormBaseMessageLoop.cs @@ -37,7 +37,7 @@ namespace TelegramBotBase.Factories.MessageLoops } //Is this a bot command ? - if (mr.IsFirstHandler && mr.IsBotCommand && Bot.BotCommands.Count(a => "/" + a.Command == mr.BotCommand) > 0) + if (mr.IsFirstHandler && mr.IsBotCommand && Bot.IsKnownBotCommand(mr.BotCommand)) { var sce = new BotCommandEventArgs(mr.BotCommand, mr.BotCommandParameters, mr.Message, session.DeviceId, session); await Bot.OnBotCommand(sce); From 6aac7d887ab8b2fab96b6dfca2e98a0beba91488 Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Sun, 15 May 2022 23:20:40 +0200 Subject: [PATCH 10/33] Update Nuget reference for Polling module to latest version --- TelegramBotBase/TelegramBotBase.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TelegramBotBase/TelegramBotBase.csproj b/TelegramBotBase/TelegramBotBase.csproj index 7d4eddc..7c24fbe 100644 --- a/TelegramBotBase/TelegramBotBase.csproj +++ b/TelegramBotBase/TelegramBotBase.csproj @@ -58,7 +58,7 @@ - + From 3386db0f66b3a04becd0ca105bc7382aea8cb059 Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Sun, 15 May 2022 23:23:29 +0200 Subject: [PATCH 11/33] Updating Test project - adding "myid" command to get own device id --- TelegramBotBase.Test/Program.cs | 91 ++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 41 deletions(-) diff --git a/TelegramBotBase.Test/Program.cs b/TelegramBotBase.Test/Program.cs index 55ac0aa..8b76b97 100644 --- a/TelegramBotBase.Test/Program.cs +++ b/TelegramBotBase.Test/Program.cs @@ -28,6 +28,7 @@ namespace TelegramBotBaseTest .CustomCommands(a => { a.Start("Starts the bot"); + a.Add("myid", "Returns my Device ID"); a.Help("Should show you some help"); a.Settings("Should show you some settings"); a.Add("form1", "Opens test form 1"); @@ -39,45 +40,7 @@ namespace TelegramBotBaseTest .Build(); - bb.BotCommand += async (s, en) => - { - switch (en.Command) - { - case "/start": - - var start = new Menu(); - - await en.Device.ActiveForm.NavigateTo(start); - - break; - case "/form1": - - var form1 = new TestForm(); - - await en.Device.ActiveForm.NavigateTo(form1); - - break; - - case "/form2": - - var form2 = new TestForm2(); - - await en.Device.ActiveForm.NavigateTo(form2); - - break; - - case "/params": - - String m = en.Parameters.DefaultIfEmpty("").Aggregate((a, b) => a + " and " + b); - - await en.Device.Send("Your parameters are: " + m, replyTo: en.Device.LastMessageId); - - en.Handled = true; - - break; - } - - }; + bb.BotCommand += Bb_BotCommand; //Update Bot commands to botfather bb.UploadBotCommands().Wait(); @@ -91,8 +54,6 @@ namespace TelegramBotBaseTest bb.Start(); - - Console.WriteLine("Telegram Bot started..."); Console.WriteLine("Press q to quit application."); @@ -104,6 +65,54 @@ namespace TelegramBotBaseTest } + private static async Task Bb_BotCommand(object sender, TelegramBotBase.Args.BotCommandEventArgs en) + { + switch (en.Command) + { + case "/start": + + var start = new Menu(); + + await en.Device.ActiveForm.NavigateTo(start); + + break; + case "/form1": + + var form1 = new TestForm(); + + await en.Device.ActiveForm.NavigateTo(form1); + + + break; + + + case "/form2": + + var form2 = new TestForm2(); + + await en.Device.ActiveForm.NavigateTo(form2); + + break; + + case "/myid": + + await en.Device.Send($"Your Device ID is: {en.DeviceId}"); + + en.Handled = true; + + break; + + case "/params": + + String m = en.Parameters.DefaultIfEmpty("").Aggregate((a, b) => a + " and " + b); + + await en.Device.Send("Your parameters are: " + m, replyTo: en.Device.LastMessageId); + + en.Handled = true; + + break; + } + } } } From d99bb7984966949085889293904ed2c715c3b674 Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Mon, 16 May 2022 14:34:05 +0200 Subject: [PATCH 12/33] Shrinking methods to Lambda functions --- TelegramBotBase/Commands/Extensions.cs | 101 ++++++++----------------- 1 file changed, 30 insertions(+), 71 deletions(-) diff --git a/TelegramBotBase/Commands/Extensions.cs b/TelegramBotBase/Commands/Extensions.cs index c98903c..8237d4f 100644 --- a/TelegramBotBase/Commands/Extensions.cs +++ b/TelegramBotBase/Commands/Extensions.cs @@ -9,40 +9,6 @@ namespace TelegramBotBase.Commands { public static class Extensions { - /// - /// Adding the default /start command with a description. - /// - /// - /// - public static void Start(this Dictionary> cmds, String description) - { - Add(cmds, "start", description, null); - } - - /// - /// Adding the default /help command with a description. - /// - /// - /// - - public static void Help(this Dictionary> cmds, String description) - { - Add(cmds, "help", description, null); - } - - /// - /// Adding the default /settings command with a description. - /// - /// - /// - - - public static void Settings(this Dictionary> cmds, String description) - { - Add(cmds, "settings", description, null); - } - - /// /// Adding the command with a description. /// @@ -93,24 +59,38 @@ namespace TelegramBotBase.Commands } } + /// + /// Adding the default /start command with a description. + /// + /// + /// + public static void Start(this Dictionary> cmds, String description) => Add(cmds, "start", description, null); + + /// + /// Adding the default /help command with a description. + /// + /// + /// + public static void Help(this Dictionary> cmds, String description) => Add(cmds, "help", description, null); + + /// + /// Adding the default /settings command with a description. + /// + /// + /// + public static void Settings(this Dictionary> cmds, String description) => Add(cmds, "settings", description, null); + /// /// Clears all default commands. /// /// - public static void ClearDefaultCommands(this Dictionary> cmds) - { - Clear(cmds, null); - } - + public static void ClearDefaultCommands(this Dictionary> cmds) => Clear(cmds, null); /// /// Clears all commands of a specific device. /// /// - public static void ClearChatCommands(this Dictionary> cmds, long DeviceId) - { - Clear(cmds, new BotCommandScopeChat() { ChatId = DeviceId }); - } + public static void ClearChatCommands(this Dictionary> cmds, long DeviceId) => Clear(cmds, new BotCommandScopeChat() { ChatId = DeviceId }); /// /// Adding a chat command with a description. @@ -118,10 +98,7 @@ namespace TelegramBotBase.Commands /// /// /// - public static void AddChatCommand(this Dictionary> cmds, long DeviceId, String command, String description) - { - Add(cmds, command, description, new BotCommandScopeChat() { ChatId = DeviceId }); - } + public static void AddChatCommand(this Dictionary> cmds, long DeviceId, String command, String description) => Add(cmds, command, description, new BotCommandScopeChat() { ChatId = DeviceId }); /// /// Adding a group command with a description. @@ -129,19 +106,13 @@ namespace TelegramBotBase.Commands /// /// /// - public static void AddGroupCommand(this Dictionary> cmds, String command, String description) - { - Add(cmds, command, description, new BotCommandScopeAllGroupChats()); - } + public static void AddGroupCommand(this Dictionary> cmds, String command, String description) => Add(cmds, command, description, new BotCommandScopeAllGroupChats()); /// /// Clears all group commands. /// /// - public static void ClearGroupCommands(this Dictionary> cmds) - { - Clear(cmds, new BotCommandScopeAllGroupChats()); - } + public static void ClearGroupCommands(this Dictionary> cmds) => Clear(cmds, new BotCommandScopeAllGroupChats()); /// /// Adding group admin command with a description. @@ -149,19 +120,13 @@ namespace TelegramBotBase.Commands /// /// /// - public static void AddGroupAdminCommand(this Dictionary> cmds, String command, String description) - { - Add(cmds, command, description, new BotCommandScopeAllChatAdministrators()); - } + public static void AddGroupAdminCommand(this Dictionary> cmds, String command, String description) => Add(cmds, command, description, new BotCommandScopeAllChatAdministrators()); /// /// Clears all group admin commands. /// /// - public static void ClearGroupAdminCommand(this Dictionary> cmds) - { - Clear(cmds, new BotCommandScopeAllChatAdministrators()); - } + public static void ClearGroupAdminCommand(this Dictionary> cmds) => Clear(cmds, new BotCommandScopeAllChatAdministrators()); /// /// Adding a privat command with a description. @@ -169,18 +134,12 @@ namespace TelegramBotBase.Commands /// /// /// - public static void AddPrivateChatCommand(this Dictionary> cmds, String command, String description) - { - Add(cmds, command, description, new BotCommandScopeAllPrivateChats()); - } + public static void AddPrivateChatCommand(this Dictionary> cmds, String command, String description) => Add(cmds, command, description, new BotCommandScopeAllPrivateChats()); /// /// Clears all private commands. /// /// - public static void ClearPrivateChatCommand(this Dictionary> cmds) - { - Clear(cmds, new BotCommandScopeAllPrivateChats()); - } + public static void ClearPrivateChatCommand(this Dictionary> cmds) => Clear(cmds, new BotCommandScopeAllPrivateChats()); } } From 2a3d8c1b30e2b090e736dfebe924d1b241ca85fa Mon Sep 17 00:00:00 2001 From: Florian Dahn Date: Tue, 17 May 2022 02:29:43 +0200 Subject: [PATCH 13/33] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0d4e6e7..dbe65ea 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # .Net Telegram Bot Framework - Context based addon -[![NuGet version (TelegramBotBase)](https://img.shields.io/nuget/v/TelegramBotBase.svg?style=flat-square)](https://www.nuget.org/packages/TelegramBotBase/) +[![NuGet version (TelegramBotBase)](https://img.shields.io/nuget/vpre/TelegramBotBase.svg?style=flat-square)](https://www.nuget.org/packages/TelegramBotBase/) [![telegram chat](https://img.shields.io/badge/Support_Chat-Telegram-blue.svg?style=flat-square)](https://www.t.me/tgbotbase) From 78b3fbebc846ae68e72842e9798fde7243ac5eb3 Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Mon, 6 Jun 2022 20:16:33 +0200 Subject: [PATCH 14/33] MessageLoop updates - moving MessageLoop folders from Subfolder Factories one level up - changing namespace and botbuilder methods to change - adding FullMessageLoop which allows to get all updates (like MinimalMessageLoop but with all methods) --- TelegramBotBase/BotBase.cs | 2 +- TelegramBotBase/Builder/BotBaseBuilder.cs | 4 +- .../MessageLoops/FormBaseMessageLoop.cs | 5 +- .../MessageLoops/FullMessageLoop.cs | 130 ++++++++++++++++++ .../MessageLoops/MinimalMessageLoop.cs | 5 +- 5 files changed, 141 insertions(+), 5 deletions(-) rename TelegramBotBase/{Factories => }/MessageLoops/FormBaseMessageLoop.cs (96%) create mode 100644 TelegramBotBase/MessageLoops/FullMessageLoop.cs rename TelegramBotBase/{Factories => }/MessageLoops/MinimalMessageLoop.cs (89%) diff --git a/TelegramBotBase/BotBase.cs b/TelegramBotBase/BotBase.cs index 38977d6..a7c1263 100644 --- a/TelegramBotBase/BotBase.cs +++ b/TelegramBotBase/BotBase.cs @@ -13,7 +13,7 @@ using TelegramBotBase.Args; using TelegramBotBase.Attributes; using TelegramBotBase.Base; using TelegramBotBase.Enums; -using TelegramBotBase.Factories.MessageLoops; +using TelegramBotBase.MessageLoops; using TelegramBotBase.Form; using TelegramBotBase.Interfaces; using TelegramBotBase.Sessions; diff --git a/TelegramBotBase/Builder/BotBaseBuilder.cs b/TelegramBotBase/Builder/BotBaseBuilder.cs index 403e1a5..d99aa9c 100644 --- a/TelegramBotBase/Builder/BotBaseBuilder.cs +++ b/TelegramBotBase/Builder/BotBaseBuilder.cs @@ -116,7 +116,7 @@ namespace TelegramBotBase.Builder public IStartFormSelectionStage DefaultMessageLoop() { - _messageloopfactory = new Factories.MessageLoops.FormBaseMessageLoop(); + _messageloopfactory = new MessageLoops.FormBaseMessageLoop(); return this; } @@ -124,7 +124,7 @@ namespace TelegramBotBase.Builder public IStartFormSelectionStage MinimalMessageLoop() { - _messageloopfactory = new Factories.MessageLoops.MinimalMessageLoop(); + _messageloopfactory = new MessageLoops.MinimalMessageLoop(); return this; } diff --git a/TelegramBotBase/Factories/MessageLoops/FormBaseMessageLoop.cs b/TelegramBotBase/MessageLoops/FormBaseMessageLoop.cs similarity index 96% rename from TelegramBotBase/Factories/MessageLoops/FormBaseMessageLoop.cs rename to TelegramBotBase/MessageLoops/FormBaseMessageLoop.cs index 3dcc641..3a6b00c 100644 --- a/TelegramBotBase/Factories/MessageLoops/FormBaseMessageLoop.cs +++ b/TelegramBotBase/MessageLoops/FormBaseMessageLoop.cs @@ -11,8 +11,11 @@ using TelegramBotBase.Enums; using TelegramBotBase.Interfaces; using TelegramBotBase.Sessions; -namespace TelegramBotBase.Factories.MessageLoops +namespace TelegramBotBase.MessageLoops { + /// + /// Thats the default message loop which reacts to Message, EditMessage and CallbackQuery. + /// public class FormBaseMessageLoop : IMessageLoopFactory { private static object __evUnhandledCall = new object(); diff --git a/TelegramBotBase/MessageLoops/FullMessageLoop.cs b/TelegramBotBase/MessageLoops/FullMessageLoop.cs new file mode 100644 index 0000000..63e8160 --- /dev/null +++ b/TelegramBotBase/MessageLoops/FullMessageLoop.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Telegram.Bot.Types; +using TelegramBotBase.Args; +using TelegramBotBase.Base; +using TelegramBotBase.Enums; +using TelegramBotBase.Interfaces; +using TelegramBotBase.Sessions; + +namespace TelegramBotBase.MessageLoops +{ + /// + /// This message loop reacts to all update types. + /// + public class FullMessageLoop : IMessageLoopFactory + { + private static object __evUnhandledCall = new object(); + + private EventHandlerList __Events = new EventHandlerList(); + + public FullMessageLoop() + { + + } + + public async Task MessageLoop(BotBase Bot, DeviceSession session, UpdateResult ur, MessageResult mr) + { + var update = ur.RawData; + + + //Is this a bot command ? + if (mr.IsFirstHandler && mr.IsBotCommand && Bot.IsKnownBotCommand(mr.BotCommand)) + { + var sce = new BotCommandEventArgs(mr.BotCommand, mr.BotCommandParameters, mr.Message, session.DeviceId, session); + await Bot.OnBotCommand(sce); + + if (sce.Handled) + return; + } + + mr.Device = session; + + var activeForm = session.ActiveForm; + + //Pre Loading Event + await activeForm.PreLoad(mr); + + //Send Load event to controls + await activeForm.LoadControls(mr); + + //Loading Event + await activeForm.Load(mr); + + + //Is Attachment ? (Photo, Audio, Video, Contact, Location, Document) (Ignore Callback Queries) + if (update.Type == Telegram.Bot.Types.Enums.UpdateType.Message) + { + if (mr.MessageType == Telegram.Bot.Types.Enums.MessageType.Contact + | mr.MessageType == Telegram.Bot.Types.Enums.MessageType.Document + | mr.MessageType == Telegram.Bot.Types.Enums.MessageType.Location + | mr.MessageType == Telegram.Bot.Types.Enums.MessageType.Photo + | mr.MessageType == Telegram.Bot.Types.Enums.MessageType.Video + | mr.MessageType == Telegram.Bot.Types.Enums.MessageType.Audio) + { + await activeForm.SentData(new DataResult(ur)); + } + } + + //Action Event + if (!session.FormSwitched && mr.IsAction) + { + //Send Action event to controls + await activeForm.ActionControls(mr); + + //Send Action event to form itself + await activeForm.Action(mr); + + if (!mr.Handled) + { + var uhc = new UnhandledCallEventArgs(ur.Message.Text, mr.RawData, session.DeviceId, mr.MessageId, ur.Message, session); + OnUnhandledCall(uhc); + + if (uhc.Handled) + { + mr.Handled = true; + if (!session.FormSwitched) + { + return; + } + } + } + + } + + if (!session.FormSwitched) + { + //Render Event + await activeForm.RenderControls(mr); + + await activeForm.Render(mr); + } + + } + + /// + /// Will be called if no form handeled this call + /// + public event EventHandler UnhandledCall + { + add + { + this.__Events.AddHandler(__evUnhandledCall, value); + } + remove + { + this.__Events.RemoveHandler(__evUnhandledCall, value); + } + } + + public void OnUnhandledCall(UnhandledCallEventArgs e) + { + (this.__Events[__evUnhandledCall] as EventHandler)?.Invoke(this, e); + + } + } +} diff --git a/TelegramBotBase/Factories/MessageLoops/MinimalMessageLoop.cs b/TelegramBotBase/MessageLoops/MinimalMessageLoop.cs similarity index 89% rename from TelegramBotBase/Factories/MessageLoops/MinimalMessageLoop.cs rename to TelegramBotBase/MessageLoops/MinimalMessageLoop.cs index 2e3965e..0be394b 100644 --- a/TelegramBotBase/Factories/MessageLoops/MinimalMessageLoop.cs +++ b/TelegramBotBase/MessageLoops/MinimalMessageLoop.cs @@ -11,8 +11,11 @@ using TelegramBotBase.Enums; using TelegramBotBase.Interfaces; using TelegramBotBase.Sessions; -namespace TelegramBotBase.Factories.MessageLoops +namespace TelegramBotBase.MessageLoops { + /// + /// This is a minimal message loop which will react to all update types and just calling the Load method. + /// public class MinimalMessageLoop : IMessageLoopFactory { private static object __evUnhandledCall = new object(); From 4054fa3e85740a7625c4984dd44bc4d696dd544d Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Thu, 30 Jun 2022 16:22:53 +0200 Subject: [PATCH 15/33] Adding new SQL Database serializer --- .../BotBaseBuilderExtensions.cs | 77 ++++++++ .../MSSQLSerializer.cs | 186 ++++++++++++++++++ .../README.md | 8 + ...xtensions.Serializer.Database.MSSQL.csproj | 25 +++ .../create_tables.sql | 37 ++++ 5 files changed, 333 insertions(+) create mode 100644 TelegramBotBase.Extensions.Serializer.Database.MSSQL/BotBaseBuilderExtensions.cs create mode 100644 TelegramBotBase.Extensions.Serializer.Database.MSSQL/MSSQLSerializer.cs create mode 100644 TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md create mode 100644 TelegramBotBase.Extensions.Serializer.Database.MSSQL/TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj create mode 100644 TelegramBotBase.Extensions.Serializer.Database.MSSQL/create_tables.sql diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/BotBaseBuilderExtensions.cs b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/BotBaseBuilderExtensions.cs new file mode 100644 index 0000000..fbf22db --- /dev/null +++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/BotBaseBuilderExtensions.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TelegramBotBase.Builder; +using TelegramBotBase.Builder.Interfaces; + +namespace TelegramBotBase.Extensions.Serializer.Database.MSSQL +{ + public static class BotBaseBuilderExtensions + { + + /// + /// Uses an Microsoft SQL Server Database to save and restore sessions. + /// + /// + /// + /// + /// + /// + public static ILanguageSelectionStage UseSQLDatabase(this ISessionSerializationStage builder, String ConnectionString, Type fallbackForm = null, String tablePrefix = "tgb_") + { + var serializer = new MSSQLSerializer(ConnectionString, tablePrefix, fallbackForm); + + builder.UseSerialization(serializer); + + return builder as BotBaseBuilder; + } + + + /// + /// Uses an Microsoft SQL Server Database to save and restore sessions. + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static ILanguageSelectionStage UseSQLDatabase(this ISessionSerializationStage builder, String HostOrIP, String DatabaseName, String UserId, String Password, Type fallbackForm = null, String tablePrefix = "tgb_") + { + var connectionString = $"Server={HostOrIP}; Database={DatabaseName}; User Id={UserId}; Password={Password}; TrustServerCertificate=true;"; + + var serializer = new MSSQLSerializer(connectionString, tablePrefix, fallbackForm); + + builder.UseSerialization(serializer); + + return builder as BotBaseBuilder; + } + + /// + /// Uses an Microsoft SQL Server Database with Windows Authentication to save and restore sessions. + /// + /// + /// + /// + /// + /// + /// + public static ILanguageSelectionStage UseSQLDatabase(this ISessionSerializationStage builder, String HostOrIP, String DatabaseName, bool IntegratedSecurity = true, Type fallbackForm = null, String tablePrefix = "tgb_") + { + if (!IntegratedSecurity) + throw new ArgumentOutOfRangeException(); + + var connectionString = $"Server={HostOrIP}; Database={DatabaseName}; Integrated Security=true; TrustServerCertificate=true;"; + + var serializer = new MSSQLSerializer(connectionString, tablePrefix, fallbackForm); + + builder.UseSerialization(serializer); + + return builder as BotBaseBuilder; + } + } +} diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/MSSQLSerializer.cs b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/MSSQLSerializer.cs new file mode 100644 index 0000000..5aca6e4 --- /dev/null +++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/MSSQLSerializer.cs @@ -0,0 +1,186 @@ +using TelegramBotBase.Interfaces; +using TelegramBotBase.Builder.Interfaces; +using System; +using TelegramBotBase.Base; +using TelegramBotBase.Args; +using TelegramBotBase.Form; +using Microsoft.Data.SqlClient; +using System.Data; + +namespace TelegramBotBase.Extensions.Serializer.Database.MSSQL +{ + public class MSSQLSerializer : IStateMachine + { + public Type FallbackStateForm { get; set; } + public string ConnectionString { get; } + public String TablePrefix { get; set; } + + /// + /// Will initialize the state machine. + /// + /// Path of the file and name where to save the session details. + /// Type of Form which will be saved instead of Form which has attribute declared. Needs to be subclass of . + /// Declares of the file could be overwritten. + public MSSQLSerializer(String ConnectionString, String tablePrefix = "tgb_", Type fallbackStateForm = null) + { + if (ConnectionString is null) + { + throw new ArgumentNullException(nameof(ConnectionString)); + } + + this.ConnectionString = ConnectionString; + + this.TablePrefix = tablePrefix; + + this.FallbackStateForm = fallbackStateForm; + + if (this.FallbackStateForm != null && !this.FallbackStateForm.IsSubclassOf(typeof(FormBase))) + { + throw new ArgumentException("FallbackStateForm is not a subclass of FormBase"); + } + } + + public StateContainer LoadFormStates() + { + var sc = new StateContainer(); + + using (var connection = new SqlConnection(ConnectionString)) + { + connection.Open(); + + var command = connection.CreateCommand(); + command.CommandText = "SELECT deviceId, deviceTitle, FormUri, QualifiedName FROM " + TablePrefix + "devices_sessions"; + + var dataTable = new DataTable(); + using (var dataAdapter = new SqlDataAdapter(command)) + { + dataAdapter.Fill(dataTable); + + foreach (DataRow r in dataTable.Rows) + { + var se = new StateEntry() + { + DeviceId = (long)r["deviceId"], + ChatTitle = r["deviceTitle"].ToString(), + FormUri = r["FormUri"].ToString(), + QualifiedName = r["QualifiedName"].ToString() + }; + + sc.States.Add(se); + + if (se.DeviceId > 0) + { + sc.ChatIds.Add(se.DeviceId); + } + else + { + sc.GroupIds.Add(se.DeviceId); + } + + var data_command = connection.CreateCommand(); + data_command.CommandText = "SELECT [key], value, type FROM " + TablePrefix + "devices_sessions_data WHERE deviceId = @deviceId"; + data_command.Parameters.Add(new SqlParameter("@deviceId", r["deviceId"])); + + var data_table = new DataTable(); + using (var dataAdapter2 = new SqlDataAdapter(data_command)) + { + dataAdapter2.Fill(data_table); + + foreach (DataRow r2 in data_table.Rows) + { + var key = r2["key"].ToString(); + var type = Type.GetType(r2["type"].ToString()); + + var value = Newtonsoft.Json.JsonConvert.DeserializeObject(r2["value"].ToString(), type); + + se.Values.Add(key, value); + } + } + + } + + } + + + + connection.Close(); + } + + return sc; + } + + public void SaveFormStates(SaveStatesEventArgs e) + { + var container = e.States; + + using (var connection = new SqlConnection(ConnectionString)) + { + connection.Open(); + + //Cleanup old Session data + var clear_command = connection.CreateCommand(); + + clear_command.CommandText = $"DELETE FROM {TablePrefix}devices_sessions_data"; + + clear_command.ExecuteNonQuery(); + + clear_command.CommandText = $"DELETE FROM {TablePrefix}devices_sessions"; + + clear_command.ExecuteNonQuery(); + + //Prepare new session commands + var session_command = connection.CreateCommand(); + var data_command = connection.CreateCommand(); + + session_command.CommandText = "INSERT INTO " + TablePrefix + "devices_sessions (deviceId, deviceTitle, FormUri, QualifiedName) VALUES (@deviceId, @deviceTitle, @FormUri, @QualifiedName)"; + session_command.Parameters.Add(new SqlParameter("@deviceId", "")); + session_command.Parameters.Add(new SqlParameter("@deviceTitle", "")); + session_command.Parameters.Add(new SqlParameter("@FormUri", "")); + session_command.Parameters.Add(new SqlParameter("@QualifiedName", "")); + + data_command.CommandText = "INSERT INTO " + TablePrefix + "devices_sessions_data (deviceId, [key], value, type) VALUES (@deviceId, @key, @value, @type)"; + data_command.Parameters.Add(new SqlParameter("@deviceId", "")); + data_command.Parameters.Add(new SqlParameter("@key", "")); + data_command.Parameters.Add(new SqlParameter("@value", "")); + data_command.Parameters.Add(new SqlParameter("@type", "")); + + //Store session data in database + foreach (var state in container.States) + { + session_command.Parameters["@deviceId"].Value = state.DeviceId; + session_command.Parameters["@deviceTitle"].Value = state.ChatTitle ?? ""; + session_command.Parameters["@FormUri"].Value = state.FormUri; + session_command.Parameters["@QualifiedName"].Value = state.QualifiedName; + + session_command.ExecuteNonQuery(); + + foreach (var data in state.Values) + { + data_command.Parameters["@deviceId"].Value = state.DeviceId; + data_command.Parameters["@key"].Value = data.Key; + + var type = data.Value.GetType(); + + if (type.IsPrimitive || type.Equals(typeof(string))) + { + data_command.Parameters["@value"].Value = data.Value; + } + else + { + data_command.Parameters["@value"].Value = Newtonsoft.Json.JsonConvert.SerializeObject(data.Value); + } + + data_command.Parameters["@type"].Value = type.AssemblyQualifiedName; + + data_command.ExecuteNonQuery(); + } + + } + + connection.Close(); + } + + + } + } +} \ No newline at end of file diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md new file mode 100644 index 0000000..565bc57 --- /dev/null +++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md @@ -0,0 +1,8 @@ +# TelegramBotBase.Extensions.Images + +[![NuGet version (TelegramBotBase)](https://img.shields.io/nuget/v/TelegramBotBase.Extensions.Serializer.Database.MSSQL.svg?style=flat-square)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Serializer.Database.MSSQL/) +[![telegram chat](https://img.shields.io/badge/Support_Chat-Telegram-blue.svg?style=flat-square)](https://www.t.me/tgbotbase) + + +[![license](https://img.shields.io/github/license/MajMcCloud/telegrambotframework.svg?style=flat-square&maxAge=2592000&label=License)](https://raw.githubusercontent.com/MajMcCloud/TelegramBotFramework/master/LICENCE.md) +[![downloads](https://img.shields.io/nuget/dt/TelegramBotBase.Extensions.Serializer.Database.MSSQL.svg?style=flat-square&label=Package%20Downloads)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Serializer.Database.MSSQL) diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj new file mode 100644 index 0000000..c8b7f27 --- /dev/null +++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj @@ -0,0 +1,25 @@ + + + + netstandard2.0;net5;netcoreapp3.1;net6 + True + https://github.com/MajMcCloud/TelegramBotFramework + https://github.com/MajMcCloud/TelegramBotFramework + MIT + true + snupkg + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/create_tables.sql b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/create_tables.sql new file mode 100644 index 0000000..587eb4f --- /dev/null +++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/create_tables.sql @@ -0,0 +1,37 @@ +USE [telegram_bot] +GO +/****** Object: Table [dbo].[tgb_devices_sessions] Script Date: 30.06.2022 16:22:09 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[tgb_devices_sessions]( + [deviceId] [bigint] NOT NULL, + [deviceTitle] [nvarchar](512) NOT NULL, + [FormUri] [nvarchar](512) NOT NULL, + [QualifiedName] [nvarchar](512) NOT NULL, + CONSTRAINT [PK_tgb_devices_sessions_1] PRIMARY KEY CLUSTERED +( + [deviceId] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +/****** Object: Table [dbo].[tgb_devices_sessions_data] Script Date: 30.06.2022 16:22:09 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[tgb_devices_sessions_data]( + [Id] [uniqueidentifier] NOT NULL, + [deviceId] [bigint] NOT NULL, + [key] [nvarchar](512) NOT NULL, + [value] [nvarchar](max) NOT NULL, + [type] [nvarchar](512) NOT NULL, + CONSTRAINT [PK_tgb_devices_session_data] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO +ALTER TABLE [dbo].[tgb_devices_sessions_data] ADD CONSTRAINT [DF_tgb_devices_session_data_Id] DEFAULT (newid()) FOR [Id] +GO From 436566adeb2023d0f0177d36ac02dcacc4d866ad Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Thu, 30 Jun 2022 16:26:39 +0200 Subject: [PATCH 16/33] Update README.md --- .../README.md | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md index 565bc57..d35b330 100644 --- a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md +++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md @@ -1,4 +1,4 @@ -# TelegramBotBase.Extensions.Images +# TelegramBotBase.Extensions.Serializer.Database.MSSQL [![NuGet version (TelegramBotBase)](https://img.shields.io/nuget/v/TelegramBotBase.Extensions.Serializer.Database.MSSQL.svg?style=flat-square)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Serializer.Database.MSSQL/) [![telegram chat](https://img.shields.io/badge/Support_Chat-Telegram-blue.svg?style=flat-square)](https://www.t.me/tgbotbase) @@ -6,3 +6,24 @@ [![license](https://img.shields.io/github/license/MajMcCloud/telegrambotframework.svg?style=flat-square&maxAge=2592000&label=License)](https://raw.githubusercontent.com/MajMcCloud/TelegramBotFramework/master/LICENCE.md) [![downloads](https://img.shields.io/nuget/dt/TelegramBotBase.Extensions.Serializer.Database.MSSQL.svg?style=flat-square&label=Package%20Downloads)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Serializer.Database.MSSQL) + +## How to use + +``` +using TelegramBotBase.Extensions.Serializer.Database.MSSQL; + + +var bb = BotBaseBuilder + .Create() + .WithAPIKey(APIKey) + .DefaultMessageLoop() + .WithStartForm() + .NoProxy() + .OnlyStart() + .UseSQLDatabase("localhost", "telegram_bot") + .UseEnglish() + .Build(); + +bb.Start(); + +``` \ No newline at end of file From 863b2d0414a837f54fa46833ed08c30b608b564f Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Thu, 30 Jun 2022 17:10:48 +0200 Subject: [PATCH 17/33] Update TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj --- ...legramBotBase.Extensions.Serializer.Database.MSSQL.csproj | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj index c8b7f27..f86ee86 100644 --- a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj +++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj @@ -8,6 +8,11 @@ MIT true snupkg + 1.0.1 + 1.0.1 + 1.0.1 + A session serializer for Microsoft SQL Server. + From 0ebce1649052c7d025d95c493ea2ab3cdf3ddb5e Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Sat, 2 Jul 2022 14:05:57 +0200 Subject: [PATCH 18/33] Remove unnecessary null checks --- TelegramBotBase/Base/FormBase.cs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/TelegramBotBase/Base/FormBase.cs b/TelegramBotBase/Base/FormBase.cs index fb1cb69..291e733 100644 --- a/TelegramBotBase/Base/FormBase.cs +++ b/TelegramBotBase/Base/FormBase.cs @@ -55,9 +55,6 @@ namespace TelegramBotBase.Form public async Task OnInit(InitEventArgs e) { - if (this.Events[__evInit] == null) - return; - var handler = this.Events[__evInit]?.GetInvocationList().Cast>(); if (handler == null) return; @@ -87,9 +84,6 @@ namespace TelegramBotBase.Form public async Task OnOpened(EventArgs e) { - if (this.Events[__evOpened] == null) - return; - var handler = this.Events[__evOpened]?.GetInvocationList().Cast>(); if (handler == null) return; @@ -120,9 +114,6 @@ namespace TelegramBotBase.Form public async Task OnClosed(EventArgs e) { - if (this.Events[__evClosed] == null) - return; - var handler = this.Events[__evClosed]?.GetInvocationList().Cast>(); if (handler == null) return; From e814046d299dc0d55e81c758363183365e070faf Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Sat, 2 Jul 2022 14:06:27 +0200 Subject: [PATCH 19/33] Adding extension folder --- TelegramBotFramework.sln | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/TelegramBotFramework.sln b/TelegramBotFramework.sln index a4b6c21..1c3ceeb 100644 --- a/TelegramBotFramework.sln +++ b/TelegramBotFramework.sln @@ -22,6 +22,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TelegramBotBase.Extensions. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsyncFormUpdates", "Examples\AsyncFormUpdates\AsyncFormUpdates.csproj", "{673A56F5-6110-4AED-A68D-562FD6ED3EA6}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{E3193182-6FDA-4FA3-AD26-A487291E7681}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TelegramBotBase.Extensions.Serializer.Database.MSSQL", "TelegramBotBase.Extensions.Serializer.Database.MSSQL\TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj", "{889B170E-32E9-4F26-BB04-8D06EA367857}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -52,6 +56,10 @@ Global {673A56F5-6110-4AED-A68D-562FD6ED3EA6}.Debug|Any CPU.Build.0 = Debug|Any CPU {673A56F5-6110-4AED-A68D-562FD6ED3EA6}.Release|Any CPU.ActiveCfg = Release|Any CPU {673A56F5-6110-4AED-A68D-562FD6ED3EA6}.Release|Any CPU.Build.0 = Release|Any CPU + {889B170E-32E9-4F26-BB04-8D06EA367857}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {889B170E-32E9-4F26-BB04-8D06EA367857}.Debug|Any CPU.Build.0 = Debug|Any CPU + {889B170E-32E9-4F26-BB04-8D06EA367857}.Release|Any CPU.ActiveCfg = Release|Any CPU + {889B170E-32E9-4F26-BB04-8D06EA367857}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -59,7 +67,9 @@ Global GlobalSection(NestedProjects) = preSolution {FC484952-3060-4F87-9809-4CD66D6961C0} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5} {E804B9E5-7ACC-49D3-9253-806766C1D9A5} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5} + {B5DDFA45-0E01-46A5-B67D-541300CDD606} = {E3193182-6FDA-4FA3-AD26-A487291E7681} {673A56F5-6110-4AED-A68D-562FD6ED3EA6} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5} + {889B170E-32E9-4F26-BB04-8D06EA367857} = {E3193182-6FDA-4FA3-AD26-A487291E7681} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {59CB40E1-9FA7-4867-A56F-4F418286F057} From df7880fcf3b45de254efe0c61223a3661067412f Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Sat, 2 Jul 2022 14:07:25 +0200 Subject: [PATCH 20/33] Make OnMessageSent async as well --- TelegramBotBase/Args/MessageSentEventArgs.cs | 2 +- TelegramBotBase/Controls/Hybrid/MultiView.cs | 2 +- TelegramBotBase/Form/AutoCleanForm.cs | 2 +- TelegramBotBase/Sessions/DeviceSession.cs | 37 +++++++++++++------- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/TelegramBotBase/Args/MessageSentEventArgs.cs b/TelegramBotBase/Args/MessageSentEventArgs.cs index d096db1..9cfe651 100644 --- a/TelegramBotBase/Args/MessageSentEventArgs.cs +++ b/TelegramBotBase/Args/MessageSentEventArgs.cs @@ -7,7 +7,7 @@ using Telegram.Bot.Types; namespace TelegramBotBase.Args { - public class MessageSentEventArgs + public class MessageSentEventArgs : EventArgs { public int MessageId { diff --git a/TelegramBotBase/Controls/Hybrid/MultiView.cs b/TelegramBotBase/Controls/Hybrid/MultiView.cs index 1f66264..83eb0e6 100644 --- a/TelegramBotBase/Controls/Hybrid/MultiView.cs +++ b/TelegramBotBase/Controls/Hybrid/MultiView.cs @@ -50,7 +50,7 @@ namespace TelegramBotBase.Controls.Hybrid } - private void Device_MessageSent(object sender, MessageSentEventArgs e) + private async Task Device_MessageSent(object sender, MessageSentEventArgs e) { if (e.Origin == null || !e.Origin.IsSubclassOf(typeof(MultiView))) return; diff --git a/TelegramBotBase/Form/AutoCleanForm.cs b/TelegramBotBase/Form/AutoCleanForm.cs index 4e6a692..b05938e 100644 --- a/TelegramBotBase/Form/AutoCleanForm.cs +++ b/TelegramBotBase/Form/AutoCleanForm.cs @@ -67,7 +67,7 @@ namespace TelegramBotBase.Form this.OldMessages.Add(e.Message.MessageId); } - private void Device_MessageSent(object sender, MessageSentEventArgs e) + private async Task Device_MessageSent(object sender, MessageSentEventArgs e) { if (this.DeleteSide == eDeleteSide.UserOnly) return; diff --git a/TelegramBotBase/Sessions/DeviceSession.cs b/TelegramBotBase/Sessions/DeviceSession.cs index 059d040..17d52e8 100644 --- a/TelegramBotBase/Sessions/DeviceSession.cs +++ b/TelegramBotBase/Sessions/DeviceSession.cs @@ -291,7 +291,8 @@ namespace TelegramBotBase.Sessions var t = API(a => a.SendTextMessageAsync(deviceId, text, parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification)); var o = GetOrigin(new StackTrace()); - OnMessageSent(new MessageSentEventArgs(await t, o)); + + await OnMessageSent(new MessageSentEventArgs(await t, o)); return await t; } @@ -342,7 +343,7 @@ namespace TelegramBotBase.Sessions var t = API(a => a.SendTextMessageAsync(this.DeviceId, text, parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification)); var o = GetOrigin(new StackTrace()); - OnMessageSent(new MessageSentEventArgs(await t, o)); + await OnMessageSent(new MessageSentEventArgs(await t, o)); return await t; } @@ -380,7 +381,7 @@ namespace TelegramBotBase.Sessions var t = API(a => a.SendTextMessageAsync(this.DeviceId, text, parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification)); var o = GetOrigin(new StackTrace()); - OnMessageSent(new MessageSentEventArgs(await t, o)); + await OnMessageSent(new MessageSentEventArgs(await t, o)); return await t; } @@ -410,7 +411,7 @@ namespace TelegramBotBase.Sessions var t = API(a => a.SendPhotoAsync(this.DeviceId, file, caption: caption, parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification)); var o = GetOrigin(new StackTrace()); - OnMessageSent(new MessageSentEventArgs(await t, o)); + await OnMessageSent(new MessageSentEventArgs(await t, o)); return await t; } @@ -440,7 +441,7 @@ namespace TelegramBotBase.Sessions var t = API(a => a.SendVideoAsync(this.DeviceId, file, caption: caption, parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification)); var o = GetOrigin(new StackTrace()); - OnMessageSent(new MessageSentEventArgs(await t, o)); + await OnMessageSent(new MessageSentEventArgs(await t, o)); return await t; } @@ -470,7 +471,7 @@ namespace TelegramBotBase.Sessions var t = API(a => a.SendVideoAsync(this.DeviceId, new InputOnlineFile(url), parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification)); var o = GetOrigin(new StackTrace()); - OnMessageSent(new MessageSentEventArgs(await t, o)); + await OnMessageSent(new MessageSentEventArgs(await t, o)); return await t; } @@ -505,7 +506,7 @@ namespace TelegramBotBase.Sessions var t = API(a => a.SendVideoAsync(this.DeviceId, fts, parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification)); var o = GetOrigin(new StackTrace()); - OnMessageSent(new MessageSentEventArgs(await t, o)); + await OnMessageSent(new MessageSentEventArgs(await t, o)); return await t; } @@ -542,7 +543,7 @@ namespace TelegramBotBase.Sessions var t = API(a => a.SendVideoAsync(this.DeviceId, fts, parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification)); var o = GetOrigin(new StackTrace()); - OnMessageSent(new MessageSentEventArgs(await t, o)); + await OnMessageSent(new MessageSentEventArgs(await t, o)); return await t; } @@ -619,7 +620,7 @@ namespace TelegramBotBase.Sessions var t = API(a => a.SendDocumentAsync(this.DeviceId, document, caption, replyMarkup: markup, disableNotification: disableNotification, replyToMessageId: replyTo)); var o = GetOrigin(new StackTrace()); - OnMessageSent(new MessageSentEventArgs(await t, o)); + await OnMessageSent(new MessageSentEventArgs(await t, o)); return await t; } @@ -882,7 +883,7 @@ namespace TelegramBotBase.Sessions /// /// Eventhandler for sent messages /// - public event EventHandler MessageSent + public event Base.Async.AsyncEventHandler MessageSent { add { @@ -895,9 +896,21 @@ namespace TelegramBotBase.Sessions } - public void OnMessageSent(MessageSentEventArgs e) + public async Task OnMessageSent(MessageSentEventArgs e) { - (this.__Events[__evMessageSent] as EventHandler)?.Invoke(this, e); + if (e.Message == null) + return; + + var handler = this.__Events[__evMessageSent]?.GetInvocationList().Cast>(); + if (handler == null) + return; + + foreach (var h in handler) + { + await Base.Async.InvokeAllAsync(h, this, e); + } + + //(this.__Events[__evMessageSent] as EventHandler)?.Invoke(this, e); } /// From b2d4c4c3f8e44c77e56373ca3fb40a37a93cba1b Mon Sep 17 00:00:00 2001 From: ZavaruKitsu Date: Fri, 19 Aug 2022 15:54:36 +0300 Subject: [PATCH 21/33] feat: add DI form factory --- Examples/EFCoreBot/Database/BotDbContext.cs | 12 +++++++ Examples/EFCoreBot/Database/User.cs | 7 ++++ Examples/EFCoreBot/EFCoreBot.csproj | 19 ++++++++++ Examples/EFCoreBot/Program.cs | 23 ++++++++++++ Examples/EFCoreBot/StartForm.cs | 36 +++++++++++++++++++ TelegramBotBase/Builder/BotBaseBuilder.cs | 16 ++++++++- .../Interfaces/IStartFormSelectionStage.cs | 16 +++++++++ .../ServiceProviderStartFormFactory.cs | 35 ++++++++++++++++++ TelegramBotBase/TelegramBotBase.csproj | 1 + TelegramBotFramework.sln | 7 ++++ 10 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 Examples/EFCoreBot/Database/BotDbContext.cs create mode 100644 Examples/EFCoreBot/Database/User.cs create mode 100644 Examples/EFCoreBot/EFCoreBot.csproj create mode 100644 Examples/EFCoreBot/Program.cs create mode 100644 Examples/EFCoreBot/StartForm.cs create mode 100644 TelegramBotBase/Factories/ServiceProviderStartFormFactory.cs diff --git a/Examples/EFCoreBot/Database/BotDbContext.cs b/Examples/EFCoreBot/Database/BotDbContext.cs new file mode 100644 index 0000000..18a3c4a --- /dev/null +++ b/Examples/EFCoreBot/Database/BotDbContext.cs @@ -0,0 +1,12 @@ +using Microsoft.EntityFrameworkCore; + +namespace EFCoreBot.Database; + +public class BotDbContext : DbContext +{ + public BotDbContext(DbContextOptions options) : base(options) + { + } + + public DbSet Users { get; set; } +} diff --git a/Examples/EFCoreBot/Database/User.cs b/Examples/EFCoreBot/Database/User.cs new file mode 100644 index 0000000..e106815 --- /dev/null +++ b/Examples/EFCoreBot/Database/User.cs @@ -0,0 +1,7 @@ +namespace EFCoreBot.Database; + +public class User +{ + public long Id { get; set; } + public string LastMessage { get; set; } +} diff --git a/Examples/EFCoreBot/EFCoreBot.csproj b/Examples/EFCoreBot/EFCoreBot.csproj new file mode 100644 index 0000000..324c2a9 --- /dev/null +++ b/Examples/EFCoreBot/EFCoreBot.csproj @@ -0,0 +1,19 @@ + + + + Exe + net6.0 + enable + disable + + + + + + + + + + + + diff --git a/Examples/EFCoreBot/Program.cs b/Examples/EFCoreBot/Program.cs new file mode 100644 index 0000000..fa427ee --- /dev/null +++ b/Examples/EFCoreBot/Program.cs @@ -0,0 +1,23 @@ +using EFCoreBot; +using EFCoreBot.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using TelegramBotBase.Builder; + +var serviceCollection = new ServiceCollection() + .AddDbContext(x => x.UseInMemoryDatabase("TelegramBotBase")); + +var serviceProvider = serviceCollection.BuildServiceProvider(); + +var bot = BotBaseBuilder.Create() + .WithAPIKey(Environment.GetEnvironmentVariable("API_KEY") ?? throw new Exception("API_KEY is not set")) + .DefaultMessageLoop() + .WithServiceProvider(serviceProvider) + .NoProxy() + .NoCommands() + .NoSerialization() + .DefaultLanguage() + .Build(); + +bot.Start(); +await Task.Delay(-1); diff --git a/Examples/EFCoreBot/StartForm.cs b/Examples/EFCoreBot/StartForm.cs new file mode 100644 index 0000000..1bfee77 --- /dev/null +++ b/Examples/EFCoreBot/StartForm.cs @@ -0,0 +1,36 @@ +using EFCoreBot.Database; +using TelegramBotBase.Base; +using TelegramBotBase.Form; + +namespace EFCoreBot; + +public class StartForm : FormBase +{ + private readonly BotDbContext _dbContext; + + public StartForm(BotDbContext dbContext) + { + _dbContext = dbContext; + } + + public override async Task Load(MessageResult message) + { + var user = await _dbContext.Users.FindAsync(Device.DeviceId); + if (user is null) + { + user = new User + { + Id = Device.DeviceId, + LastMessage = "" + }; + + _dbContext.Users.Add(user); + await _dbContext.SaveChangesAsync(); + } + + await Device.Send($"Your last message's text was: `{user.LastMessage}`"); + + user.LastMessage = string.IsNullOrWhiteSpace(message.MessageText) ? "" : message.MessageText; + await _dbContext.SaveChangesAsync(); + } +} diff --git a/TelegramBotBase/Builder/BotBaseBuilder.cs b/TelegramBotBase/Builder/BotBaseBuilder.cs index d99aa9c..6ad24ee 100644 --- a/TelegramBotBase/Builder/BotBaseBuilder.cs +++ b/TelegramBotBase/Builder/BotBaseBuilder.cs @@ -7,6 +7,7 @@ using Telegram.Bot.Types; using TelegramBotBase.Base; using TelegramBotBase.Builder.Interfaces; using TelegramBotBase.Commands; +using TelegramBotBase.Factories; using TelegramBotBase.Form; using TelegramBotBase.Interfaces; using TelegramBotBase.Localizations; @@ -148,7 +149,7 @@ namespace TelegramBotBase.Builder #endregion - #region "Step 3 (Start Form/Factory)" + #region "Step 3 (Start Form/Factory)" public INetworkingSelectionStage WithStartForm(Type startFormClass) { @@ -163,6 +164,19 @@ namespace TelegramBotBase.Builder return this; } + public INetworkingSelectionStage WithServiceProvider(Type startFormClass, IServiceProvider serviceProvider) + { + this._factory = new ServiceProviderStartFormFactory(startFormClass, serviceProvider); + return this; + } + + public INetworkingSelectionStage WithServiceProvider(IServiceProvider serviceProvider) + where T : FormBase + { + this._factory = new ServiceProviderStartFormFactory(serviceProvider); + return this; + } + public INetworkingSelectionStage WithStartFormFactory(IStartFormFactory factory) { this._factory = factory; diff --git a/TelegramBotBase/Builder/Interfaces/IStartFormSelectionStage.cs b/TelegramBotBase/Builder/Interfaces/IStartFormSelectionStage.cs index fec05b3..78692ea 100644 --- a/TelegramBotBase/Builder/Interfaces/IStartFormSelectionStage.cs +++ b/TelegramBotBase/Builder/Interfaces/IStartFormSelectionStage.cs @@ -23,6 +23,22 @@ namespace TelegramBotBase.Builder.Interfaces /// INetworkingSelectionStage WithStartForm() where T : FormBase, new(); + /// + /// Chooses a StartFormFactory which will be use for new sessions. + /// + /// + /// + /// + INetworkingSelectionStage WithServiceProvider(Type startFormClass, IServiceProvider serviceProvider); + + /// + /// Chooses a StartFormFactory which will be use for new sessions. + /// + /// + /// + /// + INetworkingSelectionStage WithServiceProvider(IServiceProvider serviceProvider) where T : FormBase; + /// /// Chooses a StartFormFactory which will be use for new sessions. /// diff --git a/TelegramBotBase/Factories/ServiceProviderStartFormFactory.cs b/TelegramBotBase/Factories/ServiceProviderStartFormFactory.cs new file mode 100644 index 0000000..4f2a0ef --- /dev/null +++ b/TelegramBotBase/Factories/ServiceProviderStartFormFactory.cs @@ -0,0 +1,35 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using TelegramBotBase.Form; +using TelegramBotBase.Interfaces; + +namespace TelegramBotBase.Factories +{ + public class ServiceProviderStartFormFactory : IStartFormFactory + { + private readonly Type _startFormClass; + private readonly IServiceProvider _serviceProvider; + + public ServiceProviderStartFormFactory(Type startFormClass, IServiceProvider serviceProvider) + { + if (!typeof(FormBase).IsAssignableFrom(startFormClass)) + throw new ArgumentException("startFormClass argument must be a FormBase type"); + + _startFormClass = startFormClass; + _serviceProvider = serviceProvider; + } + + public FormBase CreateForm() + { + return (FormBase)ActivatorUtilities.CreateInstance(_serviceProvider, _startFormClass); + } + } + + public class ServiceProviderStartFormFactory : ServiceProviderStartFormFactory + where T : FormBase + { + public ServiceProviderStartFormFactory(IServiceProvider serviceProvider) : base(typeof(T), serviceProvider) + { + } + } +} diff --git a/TelegramBotBase/TelegramBotBase.csproj b/TelegramBotBase/TelegramBotBase.csproj index 7c24fbe..05c9802 100644 --- a/TelegramBotBase/TelegramBotBase.csproj +++ b/TelegramBotBase/TelegramBotBase.csproj @@ -23,6 +23,7 @@ + diff --git a/TelegramBotFramework.sln b/TelegramBotFramework.sln index 1c3ceeb..34eec3f 100644 --- a/TelegramBotFramework.sln +++ b/TelegramBotFramework.sln @@ -26,6 +26,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TelegramBotBase.Extensions.Serializer.Database.MSSQL", "TelegramBotBase.Extensions.Serializer.Database.MSSQL\TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj", "{889B170E-32E9-4F26-BB04-8D06EA367857}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EFCoreBot", "Examples\EFCoreBot\EFCoreBot.csproj", "{261BED47-0404-4A9A-86FC-047DE42A7D25}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -60,6 +62,10 @@ Global {889B170E-32E9-4F26-BB04-8D06EA367857}.Debug|Any CPU.Build.0 = Debug|Any CPU {889B170E-32E9-4F26-BB04-8D06EA367857}.Release|Any CPU.ActiveCfg = Release|Any CPU {889B170E-32E9-4F26-BB04-8D06EA367857}.Release|Any CPU.Build.0 = Release|Any CPU + {261BED47-0404-4A9A-86FC-047DE42A7D25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {261BED47-0404-4A9A-86FC-047DE42A7D25}.Debug|Any CPU.Build.0 = Debug|Any CPU + {261BED47-0404-4A9A-86FC-047DE42A7D25}.Release|Any CPU.ActiveCfg = Release|Any CPU + {261BED47-0404-4A9A-86FC-047DE42A7D25}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -70,6 +76,7 @@ Global {B5DDFA45-0E01-46A5-B67D-541300CDD606} = {E3193182-6FDA-4FA3-AD26-A487291E7681} {673A56F5-6110-4AED-A68D-562FD6ED3EA6} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5} {889B170E-32E9-4F26-BB04-8D06EA367857} = {E3193182-6FDA-4FA3-AD26-A487291E7681} + {261BED47-0404-4A9A-86FC-047DE42A7D25} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {59CB40E1-9FA7-4867-A56F-4F418286F057} From 16371b8c7a7d08ce5aacd3a9a41f0209f90caece Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Thu, 1 Sep 2022 13:49:26 +0200 Subject: [PATCH 22/33] #26 Fix error on using InvokeMessageLoop - Fixes the error on using the default InvokeMessageLoop with Deviceid --- TelegramBotBase/BotBase.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/TelegramBotBase/BotBase.cs b/TelegramBotBase/BotBase.cs index a7c1263..b5ebd84 100644 --- a/TelegramBotBase/BotBase.cs +++ b/TelegramBotBase/BotBase.cs @@ -206,6 +206,11 @@ namespace TelegramBotBase { var mr = new MessageResult(); + mr.UpdateData = new Update() + { + Message = new Message() + }; + await InvokeMessageLoop(DeviceId, mr); } From 21cdbf4db687073c4230237b6af5387f639a67eb Mon Sep 17 00:00:00 2001 From: ZavaruKitsu Date: Wed, 21 Sep 2022 22:49:14 +0300 Subject: [PATCH 23/33] deps: update Telegram.Bot and other libs --- Examples/AsyncFormUpdates/App.config | 372 +++++++++++++++++- .../AsyncFormUpdates/AsyncFormUpdates.csproj | 18 +- Examples/AsyncFormUpdates/packages.config | 8 - Examples/EFCoreBot/EFCoreBot.csproj | 4 +- .../TelegramBotBase.Extensions.Images.csproj | 3 +- ...xtensions.Serializer.Database.MSSQL.csproj | 2 +- TelegramBotBase/Base/DataResult.cs | 12 +- TelegramBotBase/TelegramBotBase.csproj | 2 +- 8 files changed, 389 insertions(+), 32 deletions(-) delete mode 100644 Examples/AsyncFormUpdates/packages.config diff --git a/Examples/AsyncFormUpdates/App.config b/Examples/AsyncFormUpdates/App.config index 436e44f..8ffc026 100644 --- a/Examples/AsyncFormUpdates/App.config +++ b/Examples/AsyncFormUpdates/App.config @@ -1,13 +1,377 @@ - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/AsyncFormUpdates/AsyncFormUpdates.csproj b/Examples/AsyncFormUpdates/AsyncFormUpdates.csproj index 5c48fb5..579f062 100644 --- a/Examples/AsyncFormUpdates/AsyncFormUpdates.csproj +++ b/Examples/AsyncFormUpdates/AsyncFormUpdates.csproj @@ -34,17 +34,9 @@ 4 - - ..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll - + - - ..\..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll - - - ..\..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll - @@ -64,7 +56,6 @@ - @@ -72,5 +63,12 @@ TelegramBotBase + + + + + + + \ No newline at end of file diff --git a/Examples/AsyncFormUpdates/packages.config b/Examples/AsyncFormUpdates/packages.config deleted file mode 100644 index e9dd729..0000000 --- a/Examples/AsyncFormUpdates/packages.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/Examples/EFCoreBot/EFCoreBot.csproj b/Examples/EFCoreBot/EFCoreBot.csproj index 324c2a9..7421594 100644 --- a/Examples/EFCoreBot/EFCoreBot.csproj +++ b/Examples/EFCoreBot/EFCoreBot.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/TelegramBotBase.Extensions.Images/TelegramBotBase.Extensions.Images.csproj b/TelegramBotBase.Extensions.Images/TelegramBotBase.Extensions.Images.csproj index 4b974c8..0b84053 100644 --- a/TelegramBotBase.Extensions.Images/TelegramBotBase.Extensions.Images.csproj +++ b/TelegramBotBase.Extensions.Images/TelegramBotBase.Extensions.Images.csproj @@ -15,11 +15,10 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - - \ No newline at end of file + diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj index f86ee86..a0d40f7 100644 --- a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj +++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj @@ -16,7 +16,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/TelegramBotBase/Base/DataResult.cs b/TelegramBotBase/Base/DataResult.cs index fab04bd..fb87df0 100644 --- a/TelegramBotBase/Base/DataResult.cs +++ b/TelegramBotBase/Base/DataResult.cs @@ -108,7 +108,8 @@ namespace TelegramBotBase.Base public async Task DownloadDocument() { - var encryptedContent = new System.IO.MemoryStream(this.Document.FileSize.Value); + var encryptedContent = new System.IO.MemoryStream(); + encryptedContent.SetLength(this.Document.FileSize.Value); var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Document.FileId, encryptedContent); return new InputOnlineFile(encryptedContent, this.Document.FileName); @@ -167,7 +168,8 @@ namespace TelegramBotBase.Base public async Task DownloadVideo() { - var encryptedContent = new System.IO.MemoryStream(this.Video.FileSize.Value); + var encryptedContent = new System.IO.MemoryStream(); + encryptedContent.SetLength(this.Video.FileSize.Value); var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Video.FileId, encryptedContent); return new InputOnlineFile(encryptedContent, ""); @@ -184,7 +186,8 @@ namespace TelegramBotBase.Base public async Task DownloadAudio() { - var encryptedContent = new System.IO.MemoryStream(this.Audio.FileSize.Value); + var encryptedContent = new System.IO.MemoryStream(); + encryptedContent.SetLength(this.Audio.FileSize.Value); var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Audio.FileId, encryptedContent); return new InputOnlineFile(encryptedContent, ""); @@ -202,7 +205,8 @@ namespace TelegramBotBase.Base public async Task DownloadPhoto(int index) { var photo = this.Photos[index]; - var encryptedContent = new System.IO.MemoryStream(photo.FileSize.Value); + var encryptedContent = new System.IO.MemoryStream(); + encryptedContent.SetLength(photo.FileSize.Value); var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(photo.FileId, encryptedContent); return new InputOnlineFile(encryptedContent, ""); diff --git a/TelegramBotBase/TelegramBotBase.csproj b/TelegramBotBase/TelegramBotBase.csproj index 05c9802..a5b9666 100644 --- a/TelegramBotBase/TelegramBotBase.csproj +++ b/TelegramBotBase/TelegramBotBase.csproj @@ -58,7 +58,7 @@ - + From 869d16fa02056a8e9214d0e7544c755ede1a2d28 Mon Sep 17 00:00:00 2001 From: ZavaruKitsu Date: Thu, 22 Sep 2022 00:16:06 +0300 Subject: [PATCH 24/33] docs: better README.md refactor: move images to the .github folder --- {images => .github/images}/alertdialog.PNG | Bin {images => .github/images}/buttongrid.gif | Bin .../images}/buttongrid_pagingfilter.gif | Bin {images => .github/images}/calendarpicker.PNG | Bin {images => .github/images}/calendarpicker.gif | Bin .../images}/checkedbuttonlist.gif | Bin {images => .github/images}/confirmdialog.PNG | Bin {images => .github/images}/example1.PNG | Bin {images => .github/images}/example2.PNG | Bin {images => .github/images}/example3.PNG | Bin {images => .github/images}/example4.1.PNG | Bin {images => .github/images}/example4.2.PNG | Bin {images => .github/images}/example4.3.PNG | Bin {images => .github/images}/example4.4.PNG | Bin {images => .github/images}/monthpicker1.PNG | Bin {images => .github/images}/monthpicker2.PNG | Bin .../images}/multitogglebutton.gif | Bin {images => .github/images}/progressbar.PNG | Bin {images => .github/images}/promptdialog.PNG | Bin .../images}/taggedbuttongrid.gif | Bin {images => .github/images}/togglebutton.gif | Bin {images => .github/images}/treeview1.PNG | Bin {images => .github/images}/treeview2.PNG | Bin {images => .github/images}/treeview3.PNG | Bin {images => .github/images}/treeview4.PNG | Bin README.md | 1325 +++++++---------- .../README.md | 13 +- 27 files changed, 553 insertions(+), 785 deletions(-) rename {images => .github/images}/alertdialog.PNG (100%) rename {images => .github/images}/buttongrid.gif (100%) rename {images => .github/images}/buttongrid_pagingfilter.gif (100%) rename {images => .github/images}/calendarpicker.PNG (100%) rename {images => .github/images}/calendarpicker.gif (100%) rename {images => .github/images}/checkedbuttonlist.gif (100%) rename {images => .github/images}/confirmdialog.PNG (100%) rename {images => .github/images}/example1.PNG (100%) rename {images => .github/images}/example2.PNG (100%) rename {images => .github/images}/example3.PNG (100%) rename {images => .github/images}/example4.1.PNG (100%) rename {images => .github/images}/example4.2.PNG (100%) rename {images => .github/images}/example4.3.PNG (100%) rename {images => .github/images}/example4.4.PNG (100%) rename {images => .github/images}/monthpicker1.PNG (100%) rename {images => .github/images}/monthpicker2.PNG (100%) rename {images => .github/images}/multitogglebutton.gif (100%) rename {images => .github/images}/progressbar.PNG (100%) rename {images => .github/images}/promptdialog.PNG (100%) rename {images => .github/images}/taggedbuttongrid.gif (100%) rename {images => .github/images}/togglebutton.gif (100%) rename {images => .github/images}/treeview1.PNG (100%) rename {images => .github/images}/treeview2.PNG (100%) rename {images => .github/images}/treeview3.PNG (100%) rename {images => .github/images}/treeview4.PNG (100%) diff --git a/images/alertdialog.PNG b/.github/images/alertdialog.PNG similarity index 100% rename from images/alertdialog.PNG rename to .github/images/alertdialog.PNG diff --git a/images/buttongrid.gif b/.github/images/buttongrid.gif similarity index 100% rename from images/buttongrid.gif rename to .github/images/buttongrid.gif diff --git a/images/buttongrid_pagingfilter.gif b/.github/images/buttongrid_pagingfilter.gif similarity index 100% rename from images/buttongrid_pagingfilter.gif rename to .github/images/buttongrid_pagingfilter.gif diff --git a/images/calendarpicker.PNG b/.github/images/calendarpicker.PNG similarity index 100% rename from images/calendarpicker.PNG rename to .github/images/calendarpicker.PNG diff --git a/images/calendarpicker.gif b/.github/images/calendarpicker.gif similarity index 100% rename from images/calendarpicker.gif rename to .github/images/calendarpicker.gif diff --git a/images/checkedbuttonlist.gif b/.github/images/checkedbuttonlist.gif similarity index 100% rename from images/checkedbuttonlist.gif rename to .github/images/checkedbuttonlist.gif diff --git a/images/confirmdialog.PNG b/.github/images/confirmdialog.PNG similarity index 100% rename from images/confirmdialog.PNG rename to .github/images/confirmdialog.PNG diff --git a/images/example1.PNG b/.github/images/example1.PNG similarity index 100% rename from images/example1.PNG rename to .github/images/example1.PNG diff --git a/images/example2.PNG b/.github/images/example2.PNG similarity index 100% rename from images/example2.PNG rename to .github/images/example2.PNG diff --git a/images/example3.PNG b/.github/images/example3.PNG similarity index 100% rename from images/example3.PNG rename to .github/images/example3.PNG diff --git a/images/example4.1.PNG b/.github/images/example4.1.PNG similarity index 100% rename from images/example4.1.PNG rename to .github/images/example4.1.PNG diff --git a/images/example4.2.PNG b/.github/images/example4.2.PNG similarity index 100% rename from images/example4.2.PNG rename to .github/images/example4.2.PNG diff --git a/images/example4.3.PNG b/.github/images/example4.3.PNG similarity index 100% rename from images/example4.3.PNG rename to .github/images/example4.3.PNG diff --git a/images/example4.4.PNG b/.github/images/example4.4.PNG similarity index 100% rename from images/example4.4.PNG rename to .github/images/example4.4.PNG diff --git a/images/monthpicker1.PNG b/.github/images/monthpicker1.PNG similarity index 100% rename from images/monthpicker1.PNG rename to .github/images/monthpicker1.PNG diff --git a/images/monthpicker2.PNG b/.github/images/monthpicker2.PNG similarity index 100% rename from images/monthpicker2.PNG rename to .github/images/monthpicker2.PNG diff --git a/images/multitogglebutton.gif b/.github/images/multitogglebutton.gif similarity index 100% rename from images/multitogglebutton.gif rename to .github/images/multitogglebutton.gif diff --git a/images/progressbar.PNG b/.github/images/progressbar.PNG similarity index 100% rename from images/progressbar.PNG rename to .github/images/progressbar.PNG diff --git a/images/promptdialog.PNG b/.github/images/promptdialog.PNG similarity index 100% rename from images/promptdialog.PNG rename to .github/images/promptdialog.PNG diff --git a/images/taggedbuttongrid.gif b/.github/images/taggedbuttongrid.gif similarity index 100% rename from images/taggedbuttongrid.gif rename to .github/images/taggedbuttongrid.gif diff --git a/images/togglebutton.gif b/.github/images/togglebutton.gif similarity index 100% rename from images/togglebutton.gif rename to .github/images/togglebutton.gif diff --git a/images/treeview1.PNG b/.github/images/treeview1.PNG similarity index 100% rename from images/treeview1.PNG rename to .github/images/treeview1.PNG diff --git a/images/treeview2.PNG b/.github/images/treeview2.PNG similarity index 100% rename from images/treeview2.PNG rename to .github/images/treeview2.PNG diff --git a/images/treeview3.PNG b/.github/images/treeview3.PNG similarity index 100% rename from images/treeview3.PNG rename to .github/images/treeview3.PNG diff --git a/images/treeview4.PNG b/.github/images/treeview4.PNG similarity index 100% rename from images/treeview4.PNG rename to .github/images/treeview4.PNG diff --git a/README.md b/README.md index dbe65ea..bdc8864 100644 --- a/README.md +++ b/README.md @@ -1,155 +1,91 @@ - - -# .Net Telegram Bot Framework - Context based addon +# .NET Telegram Bot Framework - Context based addon [![NuGet version (TelegramBotBase)](https://img.shields.io/nuget/vpre/TelegramBotBase.svg?style=flat-square)](https://www.nuget.org/packages/TelegramBotBase/) -[![telegram chat](https://img.shields.io/badge/Support_Chat-Telegram-blue.svg?style=flat-square)](https://www.t.me/tgbotbase) +[![Telegram chat](https://img.shields.io/badge/Support_Chat-Telegram-blue.svg?style=flat-square)](https://www.t.me/tgbotbase) +[![License](https://img.shields.io/github/license/MajMcCloud/telegrambotframework.svg?style=flat-square&maxAge=2592000&label=License)](https://raw.githubusercontent.com/MajMcCloud/TelegramBotFramework/master/LICENCE.md) +[![Package Downloads](https://img.shields.io/nuget/dt/TelegramBotBase.svg?style=flat-square&label=Package%20Downloads)](https://www.nuget.org/packages/TelegramBotBase) -[![license](https://img.shields.io/github/license/MajMcCloud/telegrambotframework.svg?style=flat-square&maxAge=2592000&label=License)](https://raw.githubusercontent.com/MajMcCloud/TelegramBotFramework/master/LICENCE.md) -[![downloads](https://img.shields.io/nuget/dt/TelegramBotBase.svg?style=flat-square&label=Package%20Downloads)](https://www.nuget.org/packages/TelegramBotBase) +**Showcase: [@TGBaseBot](https://t.me/TGBaseBot)** -Test the Testproject: [@TGBaseBot](https://www.t.me/TGBaseBot) +**Support group: [https://t.me/tgbotbase](https://t.me/tgbotbase)** -Join the Telegram Group: [https://www.t.me/tgbotbase](https://www.t.me/tgbotbase) +**Releases: [GitHub](https://github.com/MajMcCloud/TelegramBotFramework/releases)** -Download a release: [Releases](https://github.com/MajMcCloud/TelegramBotFramework/releases) +## Donate ---- +Bitcoin: `1GoUJYMwAvBipQTfw2FKydAz12J8RDyeJs` / `bc1qqwlp0p5ley29lsu6jhe0qv7s7963kfc7d0m53d` -Donations +Etherium: `0xAf3835104c2C3E5b3e721FA2c7365955e87DB931` -Bitcoin: 1GoUJYMwAvBipQTfw2FKydAz12J8RDyeJs / bc1qqwlp0p5ley29lsu6jhe0qv7s7963kfc7d0m53d +Litecoin: `LRhF1eB7kneFontcDRDU8YjJhEm2GoYHch` -ETH: 0xAf3835104c2C3E5b3e721FA2c7365955e87DB931 +Dashcoin: `XudiUwWtSmAJj1QDdVW7jocQumJFLsyoGZ` -Litecoin: LRhF1eB7kneFontcDRDU8YjJhEm2GoYHch +Tron: `TYVZSykaVT1nKZnz9hjDgBRNB9VavU1bpW` -DASH: XudiUwWtSmAJj1QDdVW7jocQumJFLsyoGZ - -TRON: TYVZSykaVT1nKZnz9hjDgBRNB9VavU1bpW - -BITTORRENT: TYVZSykaVT1nKZnz9hjDgBRNB9VavU1bpW - - -Thanks ! +BitTorrent: `TYVZSykaVT1nKZnz9hjDgBRNB9VavU1bpW` --- ## Index + - [Introduction](#introduction) - [How to Start](#how-to-start) - [Quick Start](#quick-start) - [Message Handling](#message-handling) * [Example #0 - System Calls](#add-some-system-calls-example-0---system-calls) - * [Example #1 - Simple text messages](#lets-start-with-text-messages-example-1---simple-test) - * [Example #2 - Button test](#now-some-buttons-example-2---button-test) - * [Example #3 - Progress Bar control](#now-some-controls-example-3---progress-bar-test) - * [Example #4 - Registration Formular](#registration-example-example-4---registration-form-test) - - [Special Forms](#forms) - - * [AlertDialog](#alert-dialog) - - * [AutoCleanForm](#autocleanform) - - * [PromptDialog](#prompt-dialog) - - * [ConfirmDialog](#confirm-dialog) - + * [AlertDialog](#alert-dialog) + * [AutoCleanForm](#autocleanform) + * [PromptDialog](#prompt-dialog) + * [ConfirmDialog](#confirm-dialog) - [Controls](#controls) - * [ProgressBar](#progress-bar) - - * [CalendarPicker](#calendar-picker) - - * [MonthPicker](#month-picker) - - * [TreeView](#tree-view) - - * [ToggleButton](#toggle-button) - - * [ButtonGrid](#button-grid) - - * [Paging and Searching](#paging--searching) - + * [ProgressBar](#progress-bar) + * [CalendarPicker](#calendar-picker) + * [MonthPicker](#month-picker) + * [TreeView](#tree-view) + * [ToggleButton](#toggle-button) + * [ButtonGrid](#button-grid) + * [Paging and Searching](#paging--searching) * [TaggedButtonGrid](#tagged-button-grid) - * [CheckedButtonList](#checked-button-list) - * [MultiToggleButton](#multi-toggle-button) - - [Groups](#groups) - * [SplitterForm](#splitter-form) - + * [SplitterForm](#splitter-form) * [GroupForm](#group-form) - - [State Machine and Session Serialization (v3.0.0)](#statemachine-and-sessions) - * [StateMachines](#statemachines) - * [SimpleJSONStateMachine](#simplejsonstatemachine) - * [JSONStateMachine](#jsonstatemachine) - * [XMLStateMachine](#xmlstatemachine) - * [Interfaces](#interfaces) - * [IStateMachine](#istatemachine) - * [IStateForm](#istateform) - * [Attributes](#attributes) - * [SaveState](#savestate) - * [IgnoreState](#ignorestate) - - - [Navigation and NavigationController (v4.0.0)](#navigation-and-navigationcontroller) - * [As of Now](#as-of-now) - * [How to use](#how-to-use-) - - - - - [Examples](#examples) --- -## Introduction +## How to start -Hey guys, +First of all, create a new empty dotnet console project and paste some code: -here we are. After some time and thoughts i give my TelegramBot framework to public. -It is based on C#. +```csharp +// public async Task Main(string[] args) -It is a module which is based on the original [TelegramBotLibrary](https://github.com/TelegramBots/Telegram.Bot) you will find in nuget. - -It gives you features which will look/feel like WinForms or have a good way to create apps with actions and forms. - ---- - -## How to start: - -Within your empty App your need to put some initial lines including your APIKey to get things started. -The "BotBase" Class will manage a lot of things for you, like bot commands, action events and so on. -"StartForm" is your first Formular which every user will get internally redirected to, like a start page, you could redirect from there later in code, so users won't recognize it. -It needs to be a subclass of "FormBase" you will find in Namespace TelegramBotBase.Base - - -``` - -//Prepare the System (New in V5) -var bb = BotBaseBuilder +var bot = BotBaseBuilder .Create() - .WithAPIKey("{YOUR API KEY}") + .WithAPIKey("{YOUR API KEY}") // do not store your API key as plain text in project sources .DefaultMessageLoop() .WithStartForm() .NoProxy() @@ -162,132 +98,104 @@ var bb = BotBaseBuilder .UseEnglish() .Build(); -//Update bot commands to botfather -bb.UploadBotCommands().Wait(); - -//Start your Bot -bb.Start(); +// Upload bot commands to BotFather +await bot.UploadBotCommands(); +// Start your Bot +bot.Start(); ``` -Every Form has some events which will get raised at specific times. On every form you are able to get notes about the "Remote Device" like ChatId and other stuff your carrying. From there you build up you apps: +The `BotBase` class will manage a lot of things for you, like bot commands, action events and so on. +`StartForm` is your first form which every user will get internally redirected to, *just like a start page*. +It needs to be a subclass of `FormBase` you will find in namespace `TelegramBotBase.Base` -``` +Every `Form` has some events which will get raised at specific times. On every form you are able to get notes about +the *Remote Device*, +like ChatId and other stuff your carrying. From there you build up your bots: + +```csharp public class StartForm : FormBase { + // Gets invoked during Navigation to this form + public override async Task PreLoad(MessageResult message) + { + } + + // Gets invoked on every Message/Action/Data in this context + public override async Task Load(MessageResult message) + { + // `Device` is a wrapper for current chat - you can easily respond to the user + await this.Device.Send("Hello world!"); + } - - public override async Task PreLoad(MessageResult message) - { - - } - - //Gets invoked during Navigation to this form - - //Init() got replaced with event handler - - //Opened() got replaced with event handler - - //Closed() got replaced with event handler - - - //Gets invoked on every Message/Action/Data in this context - public override async Task Load(MessageResult message) - { - await this.Device.Send("Hello world!"); - } - - //Gets invoked on edited messages - public override async Task Edited(MessageResult message) - { - - } - - //Gets invoked on Button clicks - public override async Task Action(MessageResult message) - { - - - } - - //Gets invoked on Data uploades by the user (of type Photo, Audio, Video, Contact, Location, Document) - public override async Task SentData(DataResult data) - { - - - } - - //Gets invoked on every Message/Action/Data to render Design or Response - public override async Task Render(MessageResult message) - { - - } - + // Gets invoked on edited messages + public override async Task Edited(MessageResult message) + { + } + + // Gets invoked on Button clicks + public override async Task Action(MessageResult message) + { + } + + // Gets invoked on Data uploades by the user (of type Photo, Audio, Video, Contact, Location, Document) + public override async Task SentData(DataResult data) + { + } + + //Gets invoked on every Message/Action/Data to render Design or Response + public override async Task Render(MessageResult message) + { + } } - ``` -For instance send a message after loading a specific form: +Send a message after loading a specific form: -``` +```csharp await this.Device.Send("Hello world!"); ``` -Or you want to goto a different form? +Want to go to a different form? Go ahead, create it, initialize it and navigate to it: -``` -var tf = new TestForm(); - -await this.NavigateTo(tf); +```csharp +var form = new TestForm(); +await this.NavigateTo(form); ``` ## Quick Start: - When migrating from a previous version or starting completely new, all these options can be a bit overwhelming. -For this I added a QuickStart option, directly after the Create call. It just need basic parameters like in earlier versions. +There's a function called `QuickStart` that simplifies building a bit. - -``` - -//Prepare the System (New in V5) -var bb = BotBaseBuilder +```csharp +var bot = BotBaseBuilder .Create() .QuickStart("{YOUR API KEY}") .Build(); -//Start your Bot -bb.Start(); - +bot.Start(); ``` +### System calls & bot commands +Using BotFather you can add *Commands* to your bot. The user will see them as popups in a dialog. +Before start (and later for sure) you could add them to your BotBase. +If the message contains a command, a special *event handler* will get raised. -## Message Handling +Below we have 4 commands. -All examples are within the test project, so just try it out on your own. +`/start` - opens the start form -### Add some system calls (Example #0 - Bot Commands) +`/form1` - navigates in this context to form1 -Inside of the BotFather you are able to add "Commands" to your TelegramBot. The user will see them, depending on the application as options he could choose. -Before start (and later for sure) you could add them to your BotBase. Every time a message comes in they will get checked if they are one of them. -If so, a special event Handler will get raised where you are easier able to manage the action behind. +`/form2` - navigates in this context to form2 -Below we have 4 options. +`/params` - demonstrates the use of parameters per command (i.e. /params 1 2 3 test ...) -/start - opens the Startformular - -/form1 - navigates in this context to form1 - -/form2 - navigates in this context to form2 - -/params - demonstrates the use of parameters per command (i.e. /params 1 2 3 test ...) - - - -``` -var bb = BotBaseBuilder +```csharp +var bot = BotBaseBuilder .Create() .WithAPIKey("{YOUR API KEY}") .DefaultMessageLoop() @@ -299,59 +207,46 @@ var bb = BotBaseBuilder a.Add("form1","Opens test form 1" ); a.Add("form2", "Opens test form 2" ); a.Add("params", "Returns all send parameters as a message." ); - - }) .NoSerialization() .UseEnglish() .Build(); -bb.BotCommand += async (s, en) => +bot.BotCommand += async (s, en) => { - switch (en.Command) - { - case "/form1": + switch (en.Command) + { + case "/form1": + var form1 = new TestForm(); + await en.Device.ActiveForm.NavigateTo(form1); + break; - var form1 = new TestForm(); + case "/form2": + var form2 = new TestForm2(); + await en.Device.ActiveForm.NavigateTo(form2); + break; - await en.Device.ActiveForm.NavigateTo(form1); - - break; - - case "/form2": - - var form2 = new TestForm2(); - - await en.Device.ActiveForm.NavigateTo(form2); - - break; - - case "/params": - - String m = en.Parameters.DefaultIfEmpty("").Aggregate((a, b) => a + " and " + b); - - await en.Device.Send("Your parameters are " + m, replyTo: en.Device.LastMessage); - - break; - } + case "/params": + String m = en.Parameters.DefaultIfEmpty("").Aggregate((a, b) => a + " and " + b); + await en.Device.Send("Your parameters are " + m, replyTo: en.Device.LastMessage); + break; + } }; -//Update Bot commands to botfather -bb.UploadBotCommands().Wait(); - -bb.Start(); +await bot.UploadBotCommands() +bot.Start(); ``` +On every input the user is sending back to the bot, the `Action` event gets raised. So here we could manage to send +something back to him. -On every input the user is sending back to the bot the Action event gets raised. So here we could manage to send something back to him. For sure we could also manage different button inputs: +### Text messages -### Lets start with text messages (Example #1 - Simple Test) + - - -``` +```csharp public class SimpleForm : AutoCleanForm { public SimpleForm() @@ -361,419 +256,334 @@ public class SimpleForm : AutoCleanForm this.Opened += SimpleForm_Opened; } - + private async Task SimpleForm_Opened(object sender, EventArgs e) { await this.Device.Send("Hello world! (send 'back' to get back to Start)\r\nOr\r\nhi, hello, maybe, bye and ciao"); } - public override async Task Load(MessageResult message) - { - //message.MessageText will work also, cause it is a string you could manage a lot different scenerios here + { + // message.MessageText will work also, cause it is a string you could manage a lot different scenerios here + var messageId = message.MessageId; - var messageId = message.MessageId; - - switch (message.Command) - { - case "hello": - case "hi": - - //Send him a simple message - await this.Device.Send("Hello you there !"); - break; - - case "maybe": - - //Send him a simple message and reply to the one of himself - await this.Device.Send("Maybe what?", replyTo: messageId); - - break; - - case "bye": - case "ciao": - - //Send him a simple message - await this.Device.Send("Ok, take care !"); - break; - } - } + switch (message.Command) + { + case "hello": + case "hi": + // Send a simple message + await this.Device.Send("Hello you there !"); + break; + + case "maybe": + // Send a simple message and reply to the one of himself + await this.Device.Send("Maybe what?", replyTo: messageId); + break; + + case "bye": + case "ciao": + // Send a simple message + await this.Device.Send("Ok, take care !"); + break; + } + } } ``` -### Now some buttons (Example #2 - Button Test) +### Buttons -I using a different base class (AutoCleanForm) I created for a better "feeling" inside the bot which will delete "old" messages from this form. You have some settings within this class to manage when messages should be getting deleted. + - - -``` +```csharp public class ButtonTestForm : AutoCleanForm { + public override async Task Opened() + { + await this.Device.Send("Hello world! (Click 'back' to get back to Start)"); + } - public override async Task Opened() + public override async Task Action(MessageResult message) + { + var call = message.GetData(); + await message.ConfirmAction(); + + if (call == null) + return; + + message.Handled = true; + + switch (call.Value) { - await this.Device.Send("Hello world! (Click 'back' to get back to Start)"); + case "button1": + await this.Device.Send("Button 1 pressed"); + break; + + case "button2": + await this.Device.Send("Button 2 pressed"); + break; + + case "button3": + await this.Device.Send("Button 3 pressed"); + break; + + case "button4": + await this.Device.Send("Button 4 pressed"); + break; + + case "back": + var st = new Start(); + await this.NavigateTo(st); + break; + + default: + message.Handled = false; + break; } + } - public override async Task Action(MessageResult message) - { + public override async Task Render(MessageResult message) + { + ButtonForm btn = new ButtonForm(); - var call = message.GetData(); + btn.AddButtonRow(new ButtonBase("Button 1", new CallbackData("a", "button1").Serialize()), new ButtonBase("Button 2", new CallbackData("a", "button2").Serialize())); + btn.AddButtonRow(new ButtonBase("Button 3", new CallbackData("a", "button3").Serialize()), new ButtonBase("Button 4", new CallbackData("a", "button4").Serialize())); + btn.AddButtonRow(new ButtonBase("Google.com", "google", "https://www.google.com"), new ButtonBase("Telegram", "telegram", "https://telegram.org/")); + btn.AddButtonRow(new ButtonBase("Back", new CallbackData("a", "back").Serialize())); - await message.ConfirmAction(); - - - if (call == null) - return; - - message.Handled = true; - - switch (call.Value) - { - case "button1": - - await this.Device.Send("Button 1 pressed"); - - break; - - case "button2": - - await this.Device.Send("Button 2 pressed"); - - break; - - case "button3": - - await this.Device.Send("Button 3 pressed"); - - break; - - case "button4": - - await this.Device.Send("Button 4 pressed"); - - break; - - case "back": - - var st = new Start(); - - await this.NavigateTo(st); - - break; - - default: - - message.Handled = false; - - break; - } - - - } - - - public override async Task Render(MessageResult message) - { - - ButtonForm btn = new ButtonForm(); - - btn.AddButtonRow(new ButtonBase("Button 1", new CallbackData("a", "button1").Serialize()), new ButtonBase("Button 2", new CallbackData("a", "button2").Serialize())); - - btn.AddButtonRow(new ButtonBase("Button 3", new CallbackData("a", "button3").Serialize()), new ButtonBase("Button 4", new CallbackData("a", "button4").Serialize())); - - btn.AddButtonRow(new ButtonBase("Google.com", "google", "https://www.google.com"), new ButtonBase("Telegram", "telegram", "https://telegram.org/")); - - btn.AddButtonRow(new ButtonBase("Back", new CallbackData("a", "back").Serialize())); - - await this.Device.Send("Click a button", btn); - - - } + await this.Device.Send("Click a button", btn); + } } - ``` -### Now some controls (Example #3 - Progress Bar Test) +### Custom controls -Sometimes it makes sense to show the end user a type of progressbar or status. For this i tried to make a simple control, which is useful for some situations. -Maybe, if i got more ideas, i will add other "controls" in the future. +There are a bunch of ready to use controls. For example, progress bar. - - -``` + +```csharp public class ProgressTest : AutoCleanForm { - -public ProgressTest() -{ - this.DeleteMode = eDeleteMode.OnLeavingForm; -} - -public override async Task Opened() -{ - await this.Device.Send("Welcome to ProgressTest"); -} - -public override async Task Action(MessageResult message) -{ - var call = message.GetData(); - - await message.ConfirmAction(); - - - if (call == null) - return; - - TelegramBotBase.Controls.ProgressBar Bar = null; - - switch (call.Value) + public ProgressTest() { - case "standard": - - Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.standard); - Bar.Device = this.Device; - - break; - - case "squares": - - Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.squares); - Bar.Device = this.Device; - - break; - - case "circles": - - Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.circles); - Bar.Device = this.Device; - - break; - - case "lines": - - Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.lines); - Bar.Device = this.Device; - - break; - - case "squaredlines": - - Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.squaredLines); - Bar.Device = this.Device; - - break; - - case "start": - - var sf = new Start(); - - await sf.Init(); - - await this.NavigateTo(sf); - - return; - - default: - - return; + this.DeleteMode = eDeleteMode.OnLeavingForm; + } + + public override async Task Opened() + { + await this.Device.Send("Welcome to ProgressTest"); + } + + public override async Task Action(MessageResult message) + { + var call = message.GetData(); + await message.ConfirmAction(); + + if (call == null) return; + + TelegramBotBase.Controls.ProgressBar Bar = null; + + switch (call.Value) + { + case "standard": + Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.standard); + Bar.Device = this.Device; + break; + + case "squares": + Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.squares); + Bar.Device = this.Device; + break; + + case "circles": + Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.circles); + Bar.Device = this.Device; + break; + + case "lines": + Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.lines); + Bar.Device = this.Device; + break; + + case "squaredlines": + Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.squaredLines); + Bar.Device = this.Device; + break; + + case "start": + var sf = new Start(); + await sf.Init(); + await this.NavigateTo(sf); + return; + + default: + return; + } + // Render Progress bar and show some "example" progress + await Bar.Render(); + + this.Controls.Add(Bar); + + for (int i = 0; i <= 100; i++) + { + Bar.Value++; + await Bar.Render(); + + Thread.Sleep(250); + } } - - //Render Progress bar and show some "example" progress - await Bar.Render(); - - this.Controls.Add(Bar); - - for (int i = 0; i <= 100; i++) + public override async Task Render(MessageResult message) { - Bar.Value++; - await Bar.Render(); - - Thread.Sleep(250); + ButtonForm btn = new ButtonForm(); + + btn.AddButtonRow(new ButtonBase("Standard", new CallbackData("a", "standard").Serialize()), new ButtonBase("Squares", new CallbackData("a", "squares").Serialize())); + btn.AddButtonRow(new ButtonBase("Circles", new CallbackData("a", "circles").Serialize()), new ButtonBase("Lines", new CallbackData("a", "lines").Serialize())); + btn.AddButtonRow(new ButtonBase("Squared Line", new CallbackData("a", "squaredlines").Serialize())); + btn.AddButtonRow(new ButtonBase("Back to start", new CallbackData("a", "start").Serialize())); + + await this.Device.Send("Choose your progress bar:", btn); } - -} - - -public override async Task Render(MessageResult message) -{ - ButtonForm btn = new ButtonForm(); - btn.AddButtonRow(new ButtonBase("Standard", new CallbackData("a", "standard").Serialize()), new ButtonBase("Squares", new CallbackData("a", "squares").Serialize())); - - btn.AddButtonRow(new ButtonBase("Circles", new CallbackData("a", "circles").Serialize()), new ButtonBase("Lines", new CallbackData("a", "lines").Serialize())); - - btn.AddButtonRow(new ButtonBase("Squared Line", new CallbackData("a", "squaredlines").Serialize())); - - btn.AddButtonRow(new ButtonBase("Back to start", new CallbackData("a", "start").Serialize())); - - await this.Device.Send("Choose your progress bar:", btn); -} - -public override async Task Closed() -{ - foreach (var b in this.Controls) + public override async Task Closed() { - await b.Cleanup(); + foreach (var b in this.Controls) + { + await b.Cleanup(); + } + + await this.Device.Send("Ciao from ProgressTest"); } - - await this.Device.Send("Ciao from ProgressTest"); } - - - -} - - ``` -### Registration Example (Example #4 - Registration Form Test) +### Forms advanced -I read it a lot in different Telegram groups that some developers are searching for easy solutions to create context based apps. For this is my project an ideal solution here. -To give you an example about the possiblities, i added into the Test project an example for a registration form. +Registration forms have never been so easy. - + - + - + - - -``` + +```csharp public class PerForm : AutoCleanForm { -public String EMail { get; set; } - -public String Firstname { get; set; } - -public String Lastname { get; set; } - -public async override Task Load(MessageResult message) -{ - if (message.MessageText.Trim() == "") - return; - - if (this.Firstname == null) + public String EMail { get; set; } + + public String Firstname { get; set; } + + public String Lastname { get; set; } + + public async override Task Load(MessageResult message) { - this.Firstname = message.MessageText; - return; + if (string.IsNullOrWhiteSpace(message.MessageText)) return; + + if (this.Firstname == null) + { + this.Firstname = message.MessageText; + return; + } + + if (this.Lastname == null) + { + this.Lastname = message.MessageText; + return; + } + + if (this.EMail == null) + { + this.EMail = message.MessageText; + return; + } } - - if (this.Lastname == null) + + public async override Task Action(MessageResult message) { - this.Lastname = message.MessageText; - return; + var call = message.GetData(); + await message.ConfirmAction(); + + if (call == null) return; + + switch (call.Value) + { + case "back": + var start = new Start(); + await this.NavigateTo(start); + break; + } } - - if (this.EMail == null) + + public async override Task Render(MessageResult message) { - this.EMail = message.MessageText; - return; + if (this.Firstname == null) + { + await this.Device.Send("Please sent your firstname:"); + return; + } + + if (this.Lastname == null) + { + await this.Device.Send("Please sent your lastname:"); + return; + } + + if (this.EMail == null) + { + await this.Device.Send("Please sent your email address:"); + return; + } + + string s = ""; + + s += "Firstname: " + this.Firstname + "\r\n"; + s += "Lastname: " + this.Lastname + "\r\n"; + s += "E-Mail: " + this.EMail + "\r\n"; + + ButtonForm bf = new ButtonForm(); + bf.AddButtonRow(new ButtonBase("Back", new CallbackData("a", "back").Serialize())); + + await this.Device.Send("Your details:\r\n" + s, bf); } - } - -public async override Task Action(MessageResult message) -{ - var call = message.GetData(); - - await message.ConfirmAction(); - - if (call == null) - return; - - switch (call.Value) - { - case "back": - - var start = new Start(); - - await this.NavigateTo(start); - - break; - - } - - -} - -public async override Task Render(MessageResult message) -{ - if (this.Firstname == null) - { - await this.Device.Send("Please sent your firstname:"); - return; - } - - if (this.Lastname == null) - { - await this.Device.Send("Please sent your lastname:"); - return; - } - - if (this.EMail == null) - { - await this.Device.Send("Please sent your email address:"); - return; - } - - - String s = ""; - - s += "Firstname: " + this.Firstname + "\r\n"; - s += "Lastname: " + this.Lastname + "\r\n"; - s += "E-Mail: " + this.EMail + "\r\n"; - - ButtonForm bf = new ButtonForm(); - bf.AddButtonRow(new ButtonBase("Back", new CallbackData("a", "back").Serialize())); - - await this.Device.Send("Your details:\r\n" + s, bf); -} - - -} - ``` -There is also a second example, where every of these 3 inputs gets requested by a different formular (class). Just for imagination of the possiblites. -Cause its to much Text, i didnt have added it here. You will find it under [TelegramBotBaseTest/Tests/Register/PerStep.cs](TelegramBotBaseTest/Tests/Register/PerStep.cs) -Beginn there and navigate your way through these Steps in the subfolder. - +[Another case](TelegramBotBaseTest/Tests/Register/PerStep.cs), where every of these 3 inputs gets requested by a +different forms. Just for +imagination of the possibilities. --- - ## Forms -There are some default types of forms to make the interaction with users easier. -For now we have the following: +There are some default forms to make the interaction with users easier. - [AlertDialog](#alert-dialog) - Just a simple dialog with one Button. + Just a simple dialog with one Button. - [AutoCleanForm](#autocleanform) - A form which needs to be derived from. It will be delete all in the context sent messages to the user after every new message or on leaving the formular and navigates somewhere else. - Makes sense to create a "feeling" of a clean environment for the user. For instance if you have a multilevel menu. This will remove the previously shown menu, and renders the new sub/top level. + A form which needs to be derived from. It will be delete all in the context sent messages to the user after every new + message or on leaving the form and navigates somewhere else. + Makes sense to create a *feeling* of a clean environment for the user. For instance if you have a multilevel menu. + This will remove the previously shown menu, and renders the new sub/top level. - [PromptDialog](#prompt-dialog) - A simple dialog which will show a message and then waits for a text input (response). + A simple dialog which will show a message and then wait for a text input (response). - [ConfirmDialog](#confirm-dialog) - A simple dialog which is able to show multiple buttons and a Text message. The user could select one option and will get redirected to a different form, depending on the click. + A simple dialog which is able to show multiple buttons and a text message. The user could select one option and will + get redirected to a different form, depending on the click. ### Alert Dialog - - -``` + +```csharp AlertDialog ad = new AlertDialog("This is a message", "Ok"); ad.ButtonClicked += async (s, en) => @@ -783,234 +593,211 @@ ad.ButtonClicked += async (s, en) => }; await this.NavigateTo(ad); - ``` - ### AutoCleanForm -No example yet +Just try it by youself. ### Prompt Dialog - - - - -``` + +```csharp PromptDialog pd = new PromptDialog("Please tell me your name ?"); pd.Completed += async (s, en) => { - await this.Device.Send("Hello " + pd.Value); + await this.Device.Send("Hello " + pd.Value); }; await this.OpenModal(pd); - ``` ### Confirm Dialog - - - - -``` + +```csharp ConfirmDialog cd = new ConfirmDialog("Please confirm", new ButtonBase("Ok", "ok"), new ButtonBase("Cancel", "cancel")); cd.ButtonClicked += async (s, en) => { var tf = new TestForm2(); - //Remember only to navigate from the current running form. (here it is the prompt dialog, cause we have left the above already) + // Remember only to navigate from the current running form. (here it is the prompt dialog, cause we have left the above already) await cd.NavigateTo(tf); }; await this.NavigateTo(cd); - ``` - ## Controls ### Progress Bar - + ### Calendar Picker - - + + + ### Month Picker - - - - + + + + ### Tree View - - - - - + + + + + ### Toggle Button - + + ### Button Grid - + + #### Paging & Searching - + + ### Tagged Button Grid - + + ### Checked Button List - + + ### Multi Toggle Button - + + ## Groups -For working with groups, there are multiple different tools which helps to work with and allows bot also to manage "Single-User" chats and group chats. +For groups, there are multiple different tools which helps to work with and allows bot also to manage +"Single-User" chats and group chats. ### Splitter Form - -An easy way to switch between a "Single-User" form and one for managing a group is the SplitterForm base class. +An easy way to switch between a *Single-User* form and one for managing a group is the SplitterForm base class. It calls special methods which you can override and then move from there to the form you need. -The OpenGroup method is the "backup" if OpenChannel or OpenSupergroup is not overridden. Same for Open, it is "backup" if none of the previous methods has been overridden. - - -``` +The OpenGroup method is the *backup* if OpenChannel or OpenSupergroup is not overridden. Same for Open, it is "backup" +if none of the previous methods has been overridden. +```csharp public class Start : SplitterForm { - public override async Task Open(MessageResult e) - { - var st = new Menu(); - await this.NavigateTo(st); + public override async Task Open(MessageResult e) + { + var st = new Menu(); + await this.NavigateTo(st); - return true; - } + return true; + } + public override async Task OpenGroup(MessageResult e) + { + var st = new Groups.LinkReplaceTest(); + await this.NavigateTo(st); - public override async Task OpenGroup(MessageResult e) - { - var st = new Groups.LinkReplaceTest(); - await this.NavigateTo(st); + return true; + } + + public override Task OpenChannel(MessageResult e) + { + return base.OpenChannel(e); + } - return true; - } - - public override Task OpenChannel(MessageResult e) - { - return base.OpenChannel(e); - } - - public override Task OpenSupergroup(MessageResult e) - { - return base.OpenSupergroup(e); - } + public override Task OpenSupergroup(MessageResult e) + { + return base.OpenSupergroup(e); + } } - ``` - ### Group Form -For managing groups im introducing a new base class called "GroupForm". This one has special events which should make it easier to work with groups and channels. -In the Example project is a simple example for deleting a url written by a user and incrementing an internal counter. At every url he writes he got blocked for a small amount of time and the messages gots deleted. At 3 "failes" the user gets kicked of the group and blocked. +For managing groups there's a base class called `GroupForm`. This one has special events which should make it +easier to work with groups and channels. +In the Example project there's a simple example for deleting an url written by a user and incrementing an internal +counter. At +every url he writes he gets blocked for a small amount of time and the message gets deleted. At 3 failures, the user +gets +kicked of the group and blocked. -``` +```csharp public class GroupForm : FormBase { - - - public override async Task Load(MessageResult message) + public override async Task Load(MessageResult message) + { + switch (message.MessageType) { - switch (message.MessageType) - { - case Telegram.Bot.Types.Enums.MessageType.ChatMembersAdded: + case Telegram.Bot.Types.Enums.MessageType.ChatMembersAdded: + await OnMemberChanges(new MemberChangeEventArgs(Telegram.Bot.Types.Enums.MessageType.ChatMembersAdded, message, message.RawMessageData.Message.NewChatMembers)); + break; - await OnMemberChanges(new MemberChangeEventArgs(Telegram.Bot.Types.Enums.MessageType.ChatMembersAdded, message, message.RawMessageData.Message.NewChatMembers)); - - break; - case Telegram.Bot.Types.Enums.MessageType.ChatMemberLeft: - - await OnMemberChanges(new MemberChangeEventArgs(Telegram.Bot.Types.Enums.MessageType.ChatMemberLeft, message, message.RawMessageData.Message.LeftChatMember)); - - break; - - case Telegram.Bot.Types.Enums.MessageType.ChatPhotoChanged: - case Telegram.Bot.Types.Enums.MessageType.ChatPhotoDeleted: - case Telegram.Bot.Types.Enums.MessageType.ChatTitleChanged: - case Telegram.Bot.Types.Enums.MessageType.MigratedFromGroup: - case Telegram.Bot.Types.Enums.MessageType.MigratedToSupergroup: - case Telegram.Bot.Types.Enums.MessageType.MessagePinned: - case Telegram.Bot.Types.Enums.MessageType.GroupCreated: - case Telegram.Bot.Types.Enums.MessageType.SupergroupCreated: - case Telegram.Bot.Types.Enums.MessageType.ChannelCreated: - - await OnGroupChanged(new GroupChangedEventArgs(message.MessageType, message)); - - break; - - default: - - OnMessage(message); - - break; - } + case Telegram.Bot.Types.Enums.MessageType.ChatMemberLeft: + await OnMemberChanges(new MemberChangeEventArgs(Telegram.Bot.Types.Enums.MessageType.ChatMemberLeft, message, message.RawMessageData.Message.LeftChatMember)); + break; + case Telegram.Bot.Types.Enums.MessageType.ChatPhotoChanged: + case Telegram.Bot.Types.Enums.MessageType.ChatPhotoDeleted: + case Telegram.Bot.Types.Enums.MessageType.ChatTitleChanged: + case Telegram.Bot.Types.Enums.MessageType.MigratedFromGroup: + case Telegram.Bot.Types.Enums.MessageType.MigratedToSupergroup: + case Telegram.Bot.Types.Enums.MessageType.MessagePinned: + case Telegram.Bot.Types.Enums.MessageType.GroupCreated: + case Telegram.Bot.Types.Enums.MessageType.SupergroupCreated: + case Telegram.Bot.Types.Enums.MessageType.ChannelCreated: + await OnGroupChanged(new GroupChangedEventArgs(message.MessageType, message)); + break; + default: + OnMessage(message); + break; } + } - public virtual async Task OnMemberChanges(MemberChangeEventArgs e) - { + public virtual async Task OnMemberChanges(MemberChangeEventArgs e) + { + } - } + public virtual async Task OnGroupChanged(GroupChangedEventArgs e) + { + } - - public virtual async Task OnGroupChanged(GroupChangedEventArgs e) - { - - } - - - public virtual async Task OnMessage(MessageResult e) - { - - } + public virtual async Task OnMessage(MessageResult e) + { + } } ``` - ## Statemachine and Sessions -Depending on the usecases and the overall structure of a Telegram Bot it is essential to have some kind of session serialization or state machine to keep the user context after restarts of the bot (ie. due to updates) or crashes. -For this I have created some easy to implement structures which fits into the current environment. - -Below you find all possiblities. +Depending on the use-cases and the overall structure of a Telegram Bot it is essential to have some kind of session +serialization or state machine to keep the user context after bot restarts (i.e. due to updates) or crashes. +For this we have some structures which fits into the current environment. ### Statemachines -There are actually 3 types of example state machines you could use. A state machine is a kind of serializer which saves the important session data in a reusable structure like JSON or XML. - -You could use one of the following state machines: +There are actually 3 types of example state machines you could use. A state machine is a kind of serializer which saves +the important session data in a reusable structure like JSON or XML. #### SimpleJSONStateMachine -Is easy to use and useful for simple structures like basic datatypes. Did not work for complex ones like generics. Use the JSONStateMachine for them. -In general you didn't need to do more then, to keep the actual form: -``` -//Prepare the System -var bb = BotBaseBuilder +Is easy to use and useful for simple structures like basic datatypes. Won't work for complex ones like generics. + +```csharp +var bot = BotBaseBuilder .Create() .WithAPIKey("{YOUR API KEY}") .DefaultMessageLoop() @@ -1024,18 +811,16 @@ var bb = BotBaseBuilder .UseEnglish() .Build(); -//Start your Bot -bb.Start(); - +bot.Start(); ``` #### JSONStateMachine -Is easy to use too, but works for complex datatypes cause it saves there namespaces and additional type informations into the JSON file too. -In general you didn't need to do more then, to keep the actual form: -``` -//Prepare the System -var bb = BotBaseBuilder +Is easy to use too, but works for complex datatypes, because it saves there namespaces and additional type info +into the JSON file too. + +```csharp +var bot = BotBaseBuilder .Create() .WithAPIKey("{YOUR API KEY}") .DefaultMessageLoop() @@ -1049,19 +834,15 @@ var bb = BotBaseBuilder .UseEnglish() .Build(); -//Start your Bot -bb.Start(); - +bot.Start(); ``` #### XMLStateMachine -The last one, should work like the others. -In general you didn't need to do more then, to keep the actual form: +The last one, should work like the others. -``` -//Prepare the System -var bb = BotBaseBuilder +```csharp +var bot = BotBaseBuilder .Create() .WithAPIKey("{YOUR API KEY}") .DefaultMessageLoop() @@ -1075,75 +856,70 @@ var bb = BotBaseBuilder .UseEnglish() .Build(); -//Start your Bot -bb.Start(); - +bot.Start(); ``` ### Interfaces -There are two interfaces, one for the StateMachine itself, which is useful to build a custom one for a different datatype and one for implementing into a form which should be invoked with events. +There are two interfaces, one for the StateMachine itself, which is useful to build a custom one for a different +datatype and one for implementing into a form which should be invoked with events. #### IStateMachine -Is the basic StateMachine interface, it has two methods SaveFormStates(SaveStatesEventArgs e) and StateContainer LoadFormStates(), nothing fancy, just simple calls. Implement into both methods your own serialization process. - -``` +Is the basic StateMachine interface, it has two methods `SaveFormStates(SaveStatesEventArgs e)` +and `StateContainerLoadFormStates()`, nothing fancy, just simple calls. Implement both methods with your own +serialization process. +```csharp public interface IStateMachine { void SaveFormStates(SaveStatesEventArgs e); - + StateContainer LoadFormStates(); } - ``` - #### IStateForm -When implemented, this will invoke one of these two methods: LoadState(LoadStateEventArgs e) or SaveState(SaveStateEventArgs e). +When implemented, this will invoke one of these two methods: `LoadState(LoadStateEventArgs e)` +or `SaveState(SaveStateEventArgs e)`. They have methods to load or save data from the statemachine of the current form. -``` - +```csharp public interface IStateForm { void LoadState(LoadStateEventArgs e); - void SaveState(SaveStateEventArgs e); } - ``` ### Attributes -If you don't want to implement the IStateForm interface, cause there are maybe "just" one or two properties you want to keep and restore, use the following attribute: +If you don't want to implement the `IStateForm` interface, because there are maybe *just* one or two properties you want to +keep and restore, use the following attributes. #### SaveState -This will let the engine know, that you want too keep and restore this field automatically. Unlike the IStateForm methods, you have no option to manipulate data. - -``` +This will let the engine know, that you want too keep and restore this field automatically. Unlike the IStateForm +methods, you have no option to manipulate data. +```csharp [SaveState] public long UserId { get; set; } - - ``` #### IgnoreState -Due to the fact that Attribute implementation and interaction is optional, you want to let the engine maybe know, that you don't want to keep a specific form. So it should get "lost". This attribute will help you here, add it to the form class and it will not get serialized, even if it implements IStateForm or the SaveState attributes. - -``` +Due to the fact that Attribute implementation and interaction is optional, you want to let the engine maybe know, that +you don't want to keep a specific form. So it should get *lost*. This attribute will help you here, add it to the form +class and it will not get serialized, even if it implements IStateForm or the SaveState attributes. +```csharp [IgnoreState] public class Registration : STForm { } - ``` ## Navigation and NavigationController @@ -1153,90 +929,84 @@ public class Registration : STForm As from earlier topics on this readme you already know the default way for (cross) navigation between Forms. It will look something like this: -``` - +```csharp var f = new FormBase(); await this.NavigateTo(f); - ``` -Depending on the model and structure of your bot it can make sense, to have more linear navigation instead of "cross" navigation. +Depending on the model and structure of your bot it can make sense, to have more linear navigation instead of *cross* +navigation. -In example you have a bot which shows a list of football teams. And when clicking on it you want to open the team details and latest matches. +For example, you have a bot which shows a list of football teams. And when clicking on it you want to open the team +details and latest matches. -After the matches you want to maybe switch to a different teams and take a look at their statistics and matches. +After the matches, you want to maybe switch to different teams and take a look at their statistics and matches. -At some point, you "just" want to get back to the first team so like on Android your clicking the "back" button multiple times. +At some point, you *just* want to get back to the first team so like on Android you're clicking the "back" button multiple +times. This can become really complicated, when not having some controller below which handle these "Push/Pop" calls. -Thats why I introduced a NavigationController class which manages these situations and the stack. +Thats why we hace a NavigationController class which manages these situations and the stack. +### Usage -### How to use ? +First, you need to create a NavigationController instance at the same position in code, where you want to start the +navigation. -First you need to create a NavigationController instance at the same position in code, where you want to start the navigation. +You will use the current FormBase instance as a root class within the constructor, so you can later come back to this +one. -You will use the current FormBase instance as a root class within the constructor. So you can later come back to this one. +**Tip**: *You can add also a completely new instance of i.e. a main menu form here to get back to it then. So you are +free to choose.* -**Tip**: *You can add also a completely new instance of i.e. a main menu form here to get back to it then. So you are free to choose.* - -We are using the same FormBase instance as above. - - -``` +We are using the same `FormBase` instance as above. +```csharp var nc = new NavigationController(this); - var f = new FormBase(); -//Replace the current form in the context with the controller. +// Replace the current form in the context with the controller. await this.NavigateTo(nc); -//Push the new from onto the stack to render it +// Push the new from onto the stack to render it nc.PushAsync(f); - ``` +Later to open a new form use `PushAsync` again: -Later to open a new form use PushAsync again: - -``` - +```csharp await this.NavigationController.PushAsync(newForm); - ``` -When you want to go back one Form on the stack use PopAsync: - - -``` +When you want to go back one Form on the stack use `PopAsync`: +```csharp await this.NavigationController.PopAsync(); - ``` -**Notice**: *By default the NavigationController has ForceCleanupOnLastPop enabled, which means that when the stack is again at 1 (due to PopAsync or PopToRootAsync calls) it will replace the controller automatically with the root form you have given to the constructor at the beginning.* - - - - +**Notice**: *By default the `NavigationController` has `ForceCleanupOnLastPop` enabled, which means that when the stack is +again at 1 (due to `PopAsync` or `PopToRootAsync` calls) it will replace the controller automatically with the root form you +have given to the constructor at the beginning.* ## Examples -You find all example projects in the "Examples" subfolder. +You can find all example projects in the "Examples" subfolder. -- [Examples/SystemCommandsBot/](Examples/SystemCommandsBot/) +- [Examples/SystemCommandsBot/](Examples/SystemCommandsBot/) -Will allow you to run specific system commands or run/kill processes via Bot. Has also a simple authentication mechanism with one password. +Will allow you to run specific system commands or run/kill processes via Bot. Also has a simple authentication mechanism +with one password. -- [Examples/JoinHiderBot/](Examples/JoinHiderBot/) +- [Examples/JoinHiderBot/](Examples/JoinHiderBot/) Will delete Join and Leave messages automatically in groups. -- [Examples/AsyncFormUpdates/](Examples/AsyncFormUpdates/) +- [Examples/AsyncFormUpdates/](Examples/AsyncFormUpdates/) -When you want to update forms async without any user interaction (message/action) before. Use the new InvokeMessageLoop method of BotBase. +Example using minimal dotnet console template with EntityFramework and Dependency Injection. + +- [Examples/EFCore/](Examples/EFCore/) --- @@ -1245,4 +1015,3 @@ I will add more notes to it soon, so stay tuned. Warm regards Florian Dahn - diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md index d35b330..c05d732 100644 --- a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md +++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md @@ -1,19 +1,19 @@ # TelegramBotBase.Extensions.Serializer.Database.MSSQL [![NuGet version (TelegramBotBase)](https://img.shields.io/nuget/v/TelegramBotBase.Extensions.Serializer.Database.MSSQL.svg?style=flat-square)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Serializer.Database.MSSQL/) -[![telegram chat](https://img.shields.io/badge/Support_Chat-Telegram-blue.svg?style=flat-square)](https://www.t.me/tgbotbase) +[![Telegram chat](https://img.shields.io/badge/Support_Chat-Telegram-blue.svg?style=flat-square)](https://www.t.me/tgbotbase) [![license](https://img.shields.io/github/license/MajMcCloud/telegrambotframework.svg?style=flat-square&maxAge=2592000&label=License)](https://raw.githubusercontent.com/MajMcCloud/TelegramBotFramework/master/LICENCE.md) -[![downloads](https://img.shields.io/nuget/dt/TelegramBotBase.Extensions.Serializer.Database.MSSQL.svg?style=flat-square&label=Package%20Downloads)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Serializer.Database.MSSQL) +[![Package Downloads](https://img.shields.io/nuget/dt/TelegramBotBase.Extensions.Serializer.Database.MSSQL.svg?style=flat-square&label=Package%20Downloads)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Serializer.Database.MSSQL) ## How to use -``` +```csharp using TelegramBotBase.Extensions.Serializer.Database.MSSQL; -var bb = BotBaseBuilder +var bot = BotBaseBuilder .Create() .WithAPIKey(APIKey) .DefaultMessageLoop() @@ -24,6 +24,5 @@ var bb = BotBaseBuilder .UseEnglish() .Build(); -bb.Start(); - -``` \ No newline at end of file +bot.Start(); +``` From a125addd2e7146127d0eca06e52ed9f36f7b0324 Mon Sep 17 00:00:00 2001 From: ZavaruKitsu Date: Thu, 22 Sep 2022 00:27:45 +0300 Subject: [PATCH 25/33] docs: fix anchors --- README.md | 136 ++++++++++++++++++++++++++---------------------------- 1 file changed, 65 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index bdc8864..802d095 100644 --- a/README.md +++ b/README.md @@ -30,15 +30,14 @@ BitTorrent: `TYVZSykaVT1nKZnz9hjDgBRNB9VavU1bpW` ## Index -- [Introduction](#introduction) -- [How to Start](#how-to-start) -- [Quick Start](#quick-start) -- [Message Handling](#message-handling) - * [Example #0 - System Calls](#add-some-system-calls-example-0---system-calls) - * [Example #1 - Simple text messages](#lets-start-with-text-messages-example-1---simple-test) - * [Example #2 - Button test](#now-some-buttons-example-2---button-test) - * [Example #3 - Progress Bar control](#now-some-controls-example-3---progress-bar-test) - * [Example #4 - Registration Formular](#registration-example-example-4---registration-form-test) +- [Quick start](#quick-start) +- [Simplified builder](#simplified-builder) +- [Features](#features) + * [System calls & bot commands](#system-calls--bot-commands) + * [Text messages handling](#text-messages) + * [Buttons](#buttons) + * [Custom controls](#custom-controls) + * [Forms advanced](#forms-advanced) - [Special Forms](#forms) * [AlertDialog](#alert-dialog) * [AutoCleanForm](#autocleanform) @@ -71,12 +70,12 @@ BitTorrent: `TYVZSykaVT1nKZnz9hjDgBRNB9VavU1bpW` * [IgnoreState](#ignorestate) - [Navigation and NavigationController (v4.0.0)](#navigation-and-navigationcontroller) * [As of Now](#as-of-now) - * [How to use](#how-to-use-) + * [Usage](#usage) - [Examples](#examples) --- -## How to start +## Quick start First of all, create a new empty dotnet console project and paste some code: @@ -120,7 +119,7 @@ public class StartForm : FormBase public override async Task PreLoad(MessageResult message) { } - + // Gets invoked on every Message/Action/Data in this context public override async Task Load(MessageResult message) { @@ -132,17 +131,17 @@ public class StartForm : FormBase public override async Task Edited(MessageResult message) { } - + // Gets invoked on Button clicks public override async Task Action(MessageResult message) { } - + // Gets invoked on Data uploades by the user (of type Photo, Audio, Video, Contact, Location, Document) public override async Task SentData(DataResult data) { } - + //Gets invoked on every Message/Action/Data to render Design or Response public override async Task Render(MessageResult message) { @@ -164,7 +163,7 @@ var form = new TestForm(); await this.NavigateTo(form); ``` -## Quick Start: +## Simplified builder When migrating from a previous version or starting completely new, all these options can be a bit overwhelming. There's a function called `QuickStart` that simplifies building a bit. @@ -178,6 +177,8 @@ var bot = BotBaseBuilder bot.Start(); ``` +## Features + ### System calls & bot commands Using BotFather you can add *Commands* to your bot. The user will see them as popups in a dialog. @@ -227,11 +228,10 @@ bot.BotCommand += async (s, en) => break; case "/params": - String m = en.Parameters.DefaultIfEmpty("").Aggregate((a, b) => a + " and " + b); + string m = en.Parameters.DefaultIfEmpty("").Aggregate((a, b) => a + " and " + b); await en.Device.Send("Your parameters are " + m, replyTo: en.Device.LastMessage); break; } - }; await bot.UploadBotCommands() @@ -256,7 +256,7 @@ public class SimpleForm : AutoCleanForm this.Opened += SimpleForm_Opened; } - + private async Task SimpleForm_Opened(object sender, EventArgs e) { await this.Device.Send("Hello world! (send 'back' to get back to Start)\r\nOr\r\nhi, hello, maybe, bye and ciao"); @@ -288,7 +288,6 @@ public class SimpleForm : AutoCleanForm } } } - ``` ### Buttons @@ -369,68 +368,68 @@ public class ProgressTest : AutoCleanForm { this.DeleteMode = eDeleteMode.OnLeavingForm; } - + public override async Task Opened() { await this.Device.Send("Welcome to ProgressTest"); } - + public override async Task Action(MessageResult message) { var call = message.GetData(); await message.ConfirmAction(); - + if (call == null) return; - + TelegramBotBase.Controls.ProgressBar Bar = null; - + switch (call.Value) { case "standard": Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.standard); Bar.Device = this.Device; break; - + case "squares": Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.squares); Bar.Device = this.Device; break; - + case "circles": Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.circles); Bar.Device = this.Device; break; - + case "lines": Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.lines); Bar.Device = this.Device; break; - + case "squaredlines": Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.squaredLines); Bar.Device = this.Device; break; - + case "start": var sf = new Start(); await sf.Init(); await this.NavigateTo(sf); return; - + default: return; } // Render Progress bar and show some "example" progress await Bar.Render(); - + this.Controls.Add(Bar); - + for (int i = 0; i <= 100; i++) { Bar.Value++; await Bar.Render(); - + Thread.Sleep(250); } } @@ -438,12 +437,12 @@ public class ProgressTest : AutoCleanForm public override async Task Render(MessageResult message) { ButtonForm btn = new ButtonForm(); - + btn.AddButtonRow(new ButtonBase("Standard", new CallbackData("a", "standard").Serialize()), new ButtonBase("Squares", new CallbackData("a", "squares").Serialize())); btn.AddButtonRow(new ButtonBase("Circles", new CallbackData("a", "circles").Serialize()), new ButtonBase("Lines", new CallbackData("a", "lines").Serialize())); btn.AddButtonRow(new ButtonBase("Squared Line", new CallbackData("a", "squaredlines").Serialize())); btn.AddButtonRow(new ButtonBase("Back to start", new CallbackData("a", "start").Serialize())); - + await this.Device.Send("Choose your progress bar:", btn); } @@ -453,7 +452,7 @@ public class ProgressTest : AutoCleanForm { await b.Cleanup(); } - + await this.Device.Send("Ciao from ProgressTest"); } } @@ -474,42 +473,42 @@ Registration forms have never been so easy. ```csharp public class PerForm : AutoCleanForm { - public String EMail { get; set; } - - public String Firstname { get; set; } - - public String Lastname { get; set; } - + public string EMail { get; set; } + + public string Firstname { get; set; } + + public string Lastname { get; set; } + public async override Task Load(MessageResult message) { if (string.IsNullOrWhiteSpace(message.MessageText)) return; - + if (this.Firstname == null) { this.Firstname = message.MessageText; return; } - + if (this.Lastname == null) { this.Lastname = message.MessageText; return; } - + if (this.EMail == null) { this.EMail = message.MessageText; return; } } - + public async override Task Action(MessageResult message) { var call = message.GetData(); await message.ConfirmAction(); - + if (call == null) return; - + switch (call.Value) { case "back": @@ -518,7 +517,7 @@ public class PerForm : AutoCleanForm break; } } - + public async override Task Render(MessageResult message) { if (this.Firstname == null) @@ -526,28 +525,28 @@ public class PerForm : AutoCleanForm await this.Device.Send("Please sent your firstname:"); return; } - + if (this.Lastname == null) { await this.Device.Send("Please sent your lastname:"); return; } - + if (this.EMail == null) { await this.Device.Send("Please sent your email address:"); return; } - + string s = ""; - + s += "Firstname: " + this.Firstname + "\r\n"; s += "Lastname: " + this.Lastname + "\r\n"; s += "E-Mail: " + this.EMail + "\r\n"; - + ButtonForm bf = new ButtonForm(); bf.AddButtonRow(new ButtonBase("Back", new CallbackData("a", "back").Serialize())); - + await this.Device.Send("Your details:\r\n" + s, bf); } } @@ -711,7 +710,7 @@ public class Start : SplitterForm return true; } - + public override Task OpenChannel(MessageResult e) { return base.OpenChannel(e); @@ -874,7 +873,7 @@ serialization process. public interface IStateMachine { void SaveFormStates(SaveStatesEventArgs e); - + StateContainer LoadFormStates(); } ``` @@ -895,7 +894,8 @@ public interface IStateForm ### Attributes -If you don't want to implement the `IStateForm` interface, because there are maybe *just* one or two properties you want to +If you don't want to implement the `IStateForm` interface, because there are maybe *just* one or two properties you want +to keep and restore, use the following attributes. #### SaveState @@ -918,7 +918,6 @@ class and it will not get serialized, even if it implements IStateForm or the Sa [IgnoreState] public class Registration : STForm { - } ``` @@ -942,7 +941,8 @@ details and latest matches. After the matches, you want to maybe switch to different teams and take a look at their statistics and matches. -At some point, you *just* want to get back to the first team so like on Android you're clicking the "back" button multiple +At some point, you *just* want to get back to the first team so like on Android you're clicking the "back" button +multiple times. This can become really complicated, when not having some controller below which handle these "Push/Pop" calls. @@ -985,8 +985,10 @@ When you want to go back one Form on the stack use `PopAsync`: await this.NavigationController.PopAsync(); ``` -**Notice**: *By default the `NavigationController` has `ForceCleanupOnLastPop` enabled, which means that when the stack is -again at 1 (due to `PopAsync` or `PopToRootAsync` calls) it will replace the controller automatically with the root form you +**Notice**: *By default the `NavigationController` has `ForceCleanupOnLastPop` enabled, which means that when the stack +is +again at 1 (due to `PopAsync` or `PopToRootAsync` calls) it will replace the controller automatically with the root form +you have given to the constructor at the beginning.* ## Examples @@ -1007,11 +1009,3 @@ Will delete Join and Leave messages automatically in groups. Example using minimal dotnet console template with EntityFramework and Dependency Injection. - [Examples/EFCore/](Examples/EFCore/) - ---- - -I will add more notes to it soon, so stay tuned. - -Warm regards - -Florian Dahn From 0e3cb79a2fa7d5b67cda65f5c952bf44915f900b Mon Sep 17 00:00:00 2001 From: ZavaruKitsu Date: Thu, 22 Sep 2022 00:33:07 +0300 Subject: [PATCH 26/33] docs: fix links to examples --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 802d095..47aaa31 100644 --- a/README.md +++ b/README.md @@ -995,17 +995,17 @@ have given to the constructor at the beginning.* You can find all example projects in the "Examples" subfolder. -- [Examples/SystemCommandsBot/](Examples/SystemCommandsBot/) +- [Examples/SystemCommandsBot](Examples/SystemCommandsBot) + +Example using minimal dotnet console template with EntityFramework and Dependency Injection. + +- [Examples/EFCoreBot](Examples/EFCoreBot) Will allow you to run specific system commands or run/kill processes via Bot. Also has a simple authentication mechanism with one password. -- [Examples/JoinHiderBot/](Examples/JoinHiderBot/) +- [Examples/JoinHiderBot](Examples/JoinHiderBot) Will delete Join and Leave messages automatically in groups. -- [Examples/AsyncFormUpdates/](Examples/AsyncFormUpdates/) - -Example using minimal dotnet console template with EntityFramework and Dependency Injection. - -- [Examples/EFCore/](Examples/EFCore/) +- [Examples/AsyncFormUpdates](Examples/AsyncFormUpdates) From 7f383a8a8351fa51ffb18be5a009e783b884cdbd Mon Sep 17 00:00:00 2001 From: ZavaruKitsu Date: Thu, 22 Sep 2022 00:35:30 +0300 Subject: [PATCH 27/33] docs: merge from master/README.md --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index 47aaa31..d3f4991 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ BitTorrent: `TYVZSykaVT1nKZnz9hjDgBRNB9VavU1bpW` - [Navigation and NavigationController (v4.0.0)](#navigation-and-navigationcontroller) * [As of Now](#as-of-now) * [Usage](#usage) +- [Extensions](#extensions) - [Examples](#examples) --- @@ -991,6 +992,26 @@ again at 1 (due to `PopAsync` or `PopToRootAsync` calls) it will replace the con you have given to the constructor at the beginning.* +## Extensions + +### TelegramBotBase.Extensions.Images + +Extends the base package with some additional image methods like SendPhoto (using Bitmap) + +[![NuGet version (TelegramBotBase)](https://img.shields.io/nuget/v/TelegramBotBase.Extensions.Images.svg?style=flat-square)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Images/) +[![Downloads](https://img.shields.io/nuget/dt/TelegramBotBase.Extensions.Images.svg?style=flat-square&label=Package%20Downloads)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Images) + +[https://www.nuget.org/packages/TelegramBotBase.Extensions.Images/](https://www.nuget.org/packages/TelegramBotBase.Extensions.Images/) + +### TelegramBotBase.Extensions.Serializer.Database.MSSQL + +A session serializer for Microsoft SQL Server. + +[![NuGet version (TelegramBotBase)](https://img.shields.io/nuget/v/TelegramBotBase.Extensions.Serializer.Database.MSSQL.svg?style=flat-square)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Serializer.Database.MSSQL/) +[![Downloads](https://img.shields.io/nuget/dt/TelegramBotBase.Extensions.Serializer.Database.MSSQL.svg?style=flat-square&label=Package%20Downloads)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Serializer.Database.MSSQL) + +[https://www.nuget.org/packages/TelegramBotBase.Extensions.Serializer.Database.MSSQL/](https://www.nuget.org/packages/TelegramBotBase.Extensions.Serializer.Database.MSSQL/) + ## Examples You can find all example projects in the "Examples" subfolder. From 8ea8e5aa2dccf14e4fb61e957c3bd22a4c5c85d2 Mon Sep 17 00:00:00 2001 From: ZavaruKitsu Date: Thu, 22 Sep 2022 00:39:02 +0300 Subject: [PATCH 28/33] docs: make README.md match each one --- TelegramBotBase.Extensions.Images/README.md | 6 +++--- .../README.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/TelegramBotBase.Extensions.Images/README.md b/TelegramBotBase.Extensions.Images/README.md index cdef1e3..2611a85 100644 --- a/TelegramBotBase.Extensions.Images/README.md +++ b/TelegramBotBase.Extensions.Images/README.md @@ -1,8 +1,8 @@ # TelegramBotBase.Extensions.Images [![NuGet version (TelegramBotBase)](https://img.shields.io/nuget/v/TelegramBotBase.Extensions.Images.svg?style=flat-square)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Images/) -[![telegram chat](https://img.shields.io/badge/Support_Chat-Telegram-blue.svg?style=flat-square)](https://www.t.me/tgbotbase) +[![Telegram chat](https://img.shields.io/badge/Support_Chat-Telegram-blue.svg?style=flat-square)](https://www.t.me/tgbotbase) -[![license](https://img.shields.io/github/license/MajMcCloud/telegrambotframework.svg?style=flat-square&maxAge=2592000&label=License)](https://raw.githubusercontent.com/MajMcCloud/TelegramBotFramework/master/LICENCE.md) -[![downloads](https://img.shields.io/nuget/dt/TelegramBotBase.Extensions.Images.svg?style=flat-square&label=Package%20Downloads)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Images) +[![License](https://img.shields.io/github/license/MajMcCloud/telegrambotframework.svg?style=flat-square&maxAge=2592000&label=License)](https://raw.githubusercontent.com/MajMcCloud/TelegramBotFramework/master/LICENCE.md) +[![Package Downloads](https://img.shields.io/nuget/dt/TelegramBotBase.Extensions.Images.svg?style=flat-square&label=Package%20Downloads)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Images) diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md index c05d732..1a7f027 100644 --- a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md +++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md @@ -4,7 +4,7 @@ [![Telegram chat](https://img.shields.io/badge/Support_Chat-Telegram-blue.svg?style=flat-square)](https://www.t.me/tgbotbase) -[![license](https://img.shields.io/github/license/MajMcCloud/telegrambotframework.svg?style=flat-square&maxAge=2592000&label=License)](https://raw.githubusercontent.com/MajMcCloud/TelegramBotFramework/master/LICENCE.md) +[![License](https://img.shields.io/github/license/MajMcCloud/telegrambotframework.svg?style=flat-square&maxAge=2592000&label=License)](https://raw.githubusercontent.com/MajMcCloud/TelegramBotFramework/master/LICENCE.md) [![Package Downloads](https://img.shields.io/nuget/dt/TelegramBotBase.Extensions.Serializer.Database.MSSQL.svg?style=flat-square&label=Package%20Downloads)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Serializer.Database.MSSQL) ## How to use From 920284d77d6e847d6baebfc76cbdd98db2d530d0 Mon Sep 17 00:00:00 2001 From: ZavaruKitsu Date: Thu, 22 Sep 2022 00:40:39 +0300 Subject: [PATCH 29/33] docs: fix anchor --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d3f4991..b93c743 100644 --- a/README.md +++ b/README.md @@ -553,7 +553,7 @@ public class PerForm : AutoCleanForm } ``` -[Another case](TelegramBotBaseTest/Tests/Register/PerStep.cs), where every of these 3 inputs gets requested by a +[Another case](TelegramBotBase.Test/Tests/Register/PerStep.cs), where every of these 3 inputs gets requested by a different forms. Just for imagination of the possibilities. From 5f9ffb7ae4b7e8f1afa14175cc40bc4d0b075f3e Mon Sep 17 00:00:00 2001 From: ZavaruKitsu Date: Thu, 22 Sep 2022 00:43:02 +0300 Subject: [PATCH 30/33] docs: fix link --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index b93c743..3795bf4 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ **Showcase: [@TGBaseBot](https://t.me/TGBaseBot)** -**Support group: [https://t.me/tgbotbase](https://t.me/tgbotbase)** +**Support group: [@tgbotbase](https://t.me/tgbotbase)** **Releases: [GitHub](https://github.com/MajMcCloud/TelegramBotFramework/releases)** @@ -557,8 +557,6 @@ public class PerForm : AutoCleanForm different forms. Just for imagination of the possibilities. ---- - ## Forms There are some default forms to make the interaction with users easier. From 91002c8271dc9ba3bfbeb210a64f27045b482dab Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Wed, 5 Oct 2022 16:29:12 +0200 Subject: [PATCH 31/33] Fix of example descriptions --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3795bf4..e83b588 100644 --- a/README.md +++ b/README.md @@ -1014,17 +1014,19 @@ A session serializer for Microsoft SQL Server. You can find all example projects in the "Examples" subfolder. +Will allow you to run specific system commands or run/kill processes via Bot. Also has a simple authentication mechanism +with one password. + - [Examples/SystemCommandsBot](Examples/SystemCommandsBot) Example using minimal dotnet console template with EntityFramework and Dependency Injection. - [Examples/EFCoreBot](Examples/EFCoreBot) -Will allow you to run specific system commands or run/kill processes via Bot. Also has a simple authentication mechanism -with one password. +Will delete Join and Leave messages automatically in groups. - [Examples/JoinHiderBot](Examples/JoinHiderBot) -Will delete Join and Leave messages automatically in groups. +When you want to update forms async without any user interaction (message/action) before. Use the new InvokeMessageLoop method of BotBase. - [Examples/AsyncFormUpdates](Examples/AsyncFormUpdates) From f39b1d11beb549b2dfc7629f04295a7cc948d975 Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Sun, 9 Oct 2022 17:12:52 +0200 Subject: [PATCH 32/33] Integration of changes Integrate some changes and cleanups Co-Authored-By: Alexey <110727638+ZavaruKitsu@users.noreply.github.com> --- TelegramBotBase/Base/MessageResult.cs | 2 +- TelegramBotBase/BotBase.cs | 112 ++++++++---------- TelegramBotBase/Builder/BotBaseBuilder.cs | 2 - .../Datasources/ButtonFormDataSource.cs | 2 +- TelegramBotBase/Localizations/English.cs | 4 +- .../{SessionBase.cs => SessionManager.cs} | 69 ++++------- 6 files changed, 79 insertions(+), 112 deletions(-) rename TelegramBotBase/{SessionBase.cs => SessionManager.cs} (83%) diff --git a/TelegramBotBase/Base/MessageResult.cs b/TelegramBotBase/Base/MessageResult.cs index 2e6148b..ed5d4d2 100644 --- a/TelegramBotBase/Base/MessageResult.cs +++ b/TelegramBotBase/Base/MessageResult.cs @@ -164,7 +164,7 @@ namespace TelegramBotBase.Base } /// - /// Confirm incomming action (i.e. Button click) + /// Confirm incoming action (i.e. Button click) /// /// /// diff --git a/TelegramBotBase/BotBase.cs b/TelegramBotBase/BotBase.cs index b5ebd84..903505c 100644 --- a/TelegramBotBase/BotBase.cs +++ b/TelegramBotBase/BotBase.cs @@ -24,7 +24,7 @@ namespace TelegramBotBase /// Bot base class for full Device/Context and Messagehandling /// /// - public class BotBase + public sealed class BotBase { public MessageClient Client { get; set; } @@ -36,7 +36,7 @@ namespace TelegramBotBase /// /// List of all running/active sessions /// - public SessionBase Sessions { get; set; } + public SessionManager Sessions { get; set; } /// /// Contains System commands which will be available at everytime and didnt get passed to forms, i.e. /start @@ -46,7 +46,7 @@ namespace TelegramBotBase #region "Events" - private EventHandlerList __Events = new EventHandlerList(); + private EventHandlerList __events = new EventHandlerList(); private static object __evSessionBegins = new object(); @@ -83,9 +83,9 @@ namespace TelegramBotBase /// public Dictionary SystemSettings { get; private set; } - public BotBase() + internal BotBase() { - this.SystemSettings = new Dictionary(); + SystemSettings = new Dictionary(); SetSetting(eSettings.MaxNumberOfRetries, 5); SetSetting(eSettings.NavigationMaximum, 10); @@ -93,10 +93,9 @@ namespace TelegramBotBase SetSetting(eSettings.SkipAllMessages, false); SetSetting(eSettings.SaveSessionsOnConsoleExit, false); - this.BotCommandScopes = new Dictionary>(); + BotCommandScopes = new Dictionary>(); - this.Sessions = new SessionBase(); - this.Sessions.BotBase = this; + Sessions = new SessionManager(this); } @@ -104,31 +103,22 @@ namespace TelegramBotBase /// /// Start your Bot /// - public void Start() + public async Task Start() { - if (this.Client == null) - return; - - this.Client.MessageLoop += Client_MessageLoop; + Client.MessageLoop += Client_MessageLoop; - if (this.StateMachine != null) - { - this.Sessions.LoadSessionStates(this.StateMachine); - } + if (StateMachine != null) await Sessions.LoadSessionStates(StateMachine); + //Enable auto session saving - if (this.GetSetting(eSettings.SaveSessionsOnConsoleExit, false)) - { - TelegramBotBase.Tools.Console.SetHandler(() => - { - this.Sessions.SaveSessionStates(); - }); - } + if (GetSetting(eSettings.SaveSessionsOnConsoleExit, false)) + TelegramBotBase.Tools.Console.SetHandler(() => { Task.Run(Sessions.SaveSessionStates); }); + - DeviceSession.MaxNumberOfRetries = this.GetSetting(eSettings.MaxNumberOfRetries, 5); + DeviceSession.MaxNumberOfRetries = GetSetting(eSettings.MaxNumberOfRetries, 5); - this.Client.StartReceiving(); + Client.StartReceiving(); } @@ -137,7 +127,7 @@ namespace TelegramBotBase DeviceSession ds = this.Sessions.GetSession(e.DeviceId); if (ds == null) { - ds = this.Sessions.StartSession(e.DeviceId).GetAwaiter().GetResult(); + ds = Sessions.StartSession(e.DeviceId).GetAwaiter().GetResult(); e.Device = ds; ds.LastMessage = e.RawData.Message; @@ -160,24 +150,24 @@ namespace TelegramBotBase mr.IsFirstHandler = false; - } while (ds.FormSwitched && i < this.GetSetting(eSettings.NavigationMaximum, 10)); + } while (ds.FormSwitched && i < GetSetting(eSettings.NavigationMaximum, 10)); } /// /// Stop your Bot /// - public void Stop() + public async Task Stop() { - if (this.Client == null) + if (Client == null) return; - this.Client.MessageLoop -= Client_MessageLoop; + Client.MessageLoop -= Client_MessageLoop; - this.Client.StopReceiving(); + Client.StopReceiving(); - this.Sessions.SaveSessionStates(); + await Sessions.SaveSessionStates(); } /// @@ -187,12 +177,12 @@ namespace TelegramBotBase /// public async Task SentToAll(String message) { - if (this.Client == null) + if (Client == null) return; - foreach (var s in this.Sessions.SessionList) + foreach (var s in Sessions.SessionList) { - await this.Client.TelegramClient.SendTextMessageAsync(s.Key, message); + await Client.TelegramClient.SendTextMessageAsync(s.Key, message); } } @@ -252,17 +242,17 @@ namespace TelegramBotBase /// public async Task UploadBotCommands() { - foreach (var bs in this.BotCommandScopes) + foreach (var bs in BotCommandScopes) { - if(bs.Value !=null) + if (bs.Value != null) { - await this.Client.SetBotCommands(bs.Value, bs.Key); + await Client.SetBotCommands(bs.Value, bs.Key); } else { - await this.Client.DeleteBotCommands(bs.Key); + await Client.DeleteBotCommands(bs.Key); } - + } } @@ -273,7 +263,7 @@ namespace TelegramBotBase /// public bool IsKnownBotCommand(String command) { - foreach (var scope in this.BotCommandScopes) + foreach (var scope in BotCommandScopes) { if (scope.Value.Any(a => "/" + a.Command == command)) return true; @@ -289,7 +279,7 @@ namespace TelegramBotBase /// public void SetSetting(eSettings set, uint Value) { - this.SystemSettings[set] = Value; + SystemSettings[set] = Value; } /// @@ -299,7 +289,7 @@ namespace TelegramBotBase /// public void SetSetting(eSettings set, bool Value) { - this.SystemSettings[set] = (Value ? 1u : 0u); + SystemSettings[set] = (Value ? 1u : 0u); } /// @@ -310,10 +300,10 @@ namespace TelegramBotBase /// public uint GetSetting(eSettings set, uint defaultValue) { - if (!this.SystemSettings.ContainsKey(set)) + if (!SystemSettings.ContainsKey(set)) return defaultValue; - return this.SystemSettings[set]; + return SystemSettings[set]; } /// @@ -324,10 +314,10 @@ namespace TelegramBotBase /// public bool GetSetting(eSettings set, bool defaultValue) { - if (!this.SystemSettings.ContainsKey(set)) + if (!SystemSettings.ContainsKey(set)) return defaultValue; - return this.SystemSettings[set] == 0u ? false : true; + return SystemSettings[set] == 0u ? false : true; } #region "Events" @@ -340,17 +330,17 @@ namespace TelegramBotBase { add { - this.__Events.AddHandler(__evSessionBegins, value); + __events.AddHandler(__evSessionBegins, value); } remove { - this.__Events.RemoveHandler(__evSessionBegins, value); + __events.RemoveHandler(__evSessionBegins, value); } } public void OnSessionBegins(SessionBeginEventArgs e) { - (this.__Events[__evSessionBegins] as EventHandler)?.Invoke(this, e); + (__events[__evSessionBegins] as EventHandler)?.Invoke(this, e); } @@ -361,17 +351,17 @@ namespace TelegramBotBase { add { - this.__Events.AddHandler(__evMessage, value); + __events.AddHandler(__evMessage, value); } remove { - this.__Events.RemoveHandler(__evMessage, value); + __events.RemoveHandler(__evMessage, value); } } public void OnMessage(MessageIncomeEventArgs e) { - (this.__Events[__evMessage] as EventHandler)?.Invoke(this, e); + (__events[__evMessage] as EventHandler)?.Invoke(this, e); } @@ -383,7 +373,7 @@ namespace TelegramBotBase public async Task OnBotCommand(BotCommandEventArgs e) { - if (this.BotCommand != null) + if (BotCommand != null) await BotCommand(this, e); } @@ -394,17 +384,17 @@ namespace TelegramBotBase { add { - this.__Events.AddHandler(__evException, value); + __events.AddHandler(__evException, value); } remove { - this.__Events.RemoveHandler(__evException, value); + __events.RemoveHandler(__evException, value); } } public void OnException(SystemExceptionEventArgs e) { - (this.__Events[__evException] as EventHandler)?.Invoke(this, e); + (__events[__evException] as EventHandler)?.Invoke(this, e); } @@ -415,17 +405,17 @@ namespace TelegramBotBase { add { - this.__Events.AddHandler(__evUnhandledCall, value); + __events.AddHandler(__evUnhandledCall, value); } remove { - this.__Events.RemoveHandler(__evUnhandledCall, value); + __events.RemoveHandler(__evUnhandledCall, value); } } public void OnUnhandledCall(UnhandledCallEventArgs e) { - (this.__Events[__evUnhandledCall] as EventHandler)?.Invoke(this, e); + (__events[__evUnhandledCall] as EventHandler)?.Invoke(this, e); } diff --git a/TelegramBotBase/Builder/BotBaseBuilder.cs b/TelegramBotBase/Builder/BotBaseBuilder.cs index 6ad24ee..63b3658 100644 --- a/TelegramBotBase/Builder/BotBaseBuilder.cs +++ b/TelegramBotBase/Builder/BotBaseBuilder.cs @@ -335,8 +335,6 @@ namespace TelegramBotBase.Builder bb.Client = _client; - bb.Sessions.Client = bb.Client; - bb.BotCommandScopes = _BotCommandScopes; bb.StateMachine = _statemachine; diff --git a/TelegramBotBase/Datasources/ButtonFormDataSource.cs b/TelegramBotBase/Datasources/ButtonFormDataSource.cs index e8fbfd4..31ef4f6 100644 --- a/TelegramBotBase/Datasources/ButtonFormDataSource.cs +++ b/TelegramBotBase/Datasources/ButtonFormDataSource.cs @@ -35,7 +35,7 @@ namespace TelegramBotBase.Datasources /// - /// Returns the amount of rows exisiting. + /// Returns the amount of rows existing. /// /// public virtual int Count => ButtonForm.Count; diff --git a/TelegramBotBase/Localizations/English.cs b/TelegramBotBase/Localizations/English.cs index d340291..35ac031 100644 --- a/TelegramBotBase/Localizations/English.cs +++ b/TelegramBotBase/Localizations/English.cs @@ -28,10 +28,10 @@ namespace TelegramBotBase.Localizations Values["ToggleButton_OnIcon"] = "⚫"; Values["ToggleButton_OffIcon"] = "⚪"; Values["ToggleButton_Title"] = "Toggle"; - Values["ToggleButton_Changed"] = "Choosen"; + Values["ToggleButton_Changed"] = "Chosen"; Values["MultiToggleButton_SelectedIcon"] = "✅"; Values["MultiToggleButton_Title"] = "Multi-Toggle"; - Values["MultiToggleButton_Changed"] = "Choosen"; + Values["MultiToggleButton_Changed"] = "Chosen"; Values["PromptDialog_Back"] = "Back"; Values["ToggleButton_Changed"] = "Setting changed"; } diff --git a/TelegramBotBase/SessionBase.cs b/TelegramBotBase/SessionManager.cs similarity index 83% rename from TelegramBotBase/SessionBase.cs rename to TelegramBotBase/SessionManager.cs index b94f59a..0cceeda 100644 --- a/TelegramBotBase/SessionBase.cs +++ b/TelegramBotBase/SessionManager.cs @@ -14,14 +14,14 @@ using TelegramBotBase.Sessions; namespace TelegramBotBase { /// - /// Base class for managing all active sessions + /// Class for managing all active sessions /// - public class SessionBase + public sealed class SessionManager { /// /// The Basic message client. /// - public MessageClient Client { get; set; } + public MessageClient Client => BotBase.Client; /// /// A list of all active sessions. @@ -32,29 +32,13 @@ namespace TelegramBotBase /// /// Reference to the Main BotBase instance for later use. /// - public BotBase BotBase { get; set; } + public BotBase BotBase { get; } - public SessionBase() + public SessionManager(BotBase botBase) { - this.SessionList = new Dictionary(); - } - - /// - /// Get device session from Device/ChatId - /// - /// - /// - public DeviceSession this[long key] - { - get - { - return this.SessionList[key]; - } - set - { - this.SessionList[key] = value; - } + BotBase = botBase; + SessionList = new Dictionary(); } /// @@ -64,7 +48,7 @@ namespace TelegramBotBase /// public DeviceSession GetSession(long deviceId) { - DeviceSession ds = this.SessionList.FirstOrDefault(a => a.Key == deviceId).Value ?? null; + var ds = SessionList.FirstOrDefault(a => a.Key == deviceId).Value ?? null; return ds; } @@ -77,7 +61,6 @@ namespace TelegramBotBase public async Task StartSession(long deviceId) { var start = BotBase.StartFormFactory.CreateForm(); - //T start = typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { }) as T; start.Client = this.Client; @@ -88,7 +71,7 @@ namespace TelegramBotBase await start.OnOpened(new EventArgs()); - this[deviceId] = ds; + SessionList[deviceId] = ds; return ds; } @@ -98,12 +81,8 @@ namespace TelegramBotBase /// public void EndSession(long deviceId) { - var d = this[deviceId]; - if (d != null) - { - this.SessionList.Remove(deviceId); - - } + var d = SessionList[deviceId]; + if (d != null) SessionList.Remove(deviceId); } /// @@ -112,7 +91,7 @@ namespace TelegramBotBase /// public List GetUserSessions() { - return this.SessionList.Where(a => a.Key > 0).Select(a => a.Value).ToList(); + return SessionList.Where(a => a.Key > 0).Select(a => a.Value).ToList(); } /// @@ -121,27 +100,27 @@ namespace TelegramBotBase /// public List GetGroupSessions() { - return this.SessionList.Where(a => a.Key < 0).Select(a => a.Value).ToList(); + return SessionList.Where(a => a.Key < 0).Select(a => a.Value).ToList(); } /// /// Loads the previously saved states from the machine. /// - public async void LoadSessionStates() + public async Task LoadSessionStates() { if (BotBase.StateMachine == null) { return; } - LoadSessionStates(BotBase.StateMachine); + await LoadSessionStates(BotBase.StateMachine); } /// /// Loads the previously saved states from the machine. /// - public async void LoadSessionStates(IStateMachine statemachine) + public async Task LoadSessionStates(IStateMachine statemachine) { if (statemachine == null) { @@ -159,7 +138,7 @@ namespace TelegramBotBase } //Key already existing - if (this.SessionList.ContainsKey(s.DeviceId)) + if (SessionList.ContainsKey(s.DeviceId)) continue; var form = t.GetConstructor(new Type[] { })?.Invoke(new object[] { }) as FormBase; @@ -222,7 +201,7 @@ namespace TelegramBotBase device.ChatTitle = s.ChatTitle; - this.SessionList.Add(s.DeviceId, device); + SessionList.Add(s.DeviceId, device); //Is Subclass of IStateForm var iform = form as IStateForm; @@ -242,7 +221,7 @@ namespace TelegramBotBase catch { //Skip on exception - this.SessionList.Remove(s.DeviceId); + SessionList.Remove(s.DeviceId); } } @@ -254,7 +233,7 @@ namespace TelegramBotBase /// /// Saves all open states into the machine. /// - public void SaveSessionStates(IStateMachine statemachine) + public async Task SaveSessionStates(IStateMachine statemachine) { if (statemachine == null) { @@ -263,7 +242,7 @@ namespace TelegramBotBase var states = new List(); - foreach (var s in this.SessionList) + foreach (var s in SessionList) { if (s.Value == null) { @@ -333,13 +312,13 @@ namespace TelegramBotBase /// /// Saves all open states into the machine. /// - public void SaveSessionStates() + public async Task SaveSessionStates() { - if (this.BotBase.StateMachine == null) + if (BotBase.StateMachine == null) return; - this.SaveSessionStates(this.BotBase.StateMachine); + await SaveSessionStates(BotBase.StateMachine); } } } From dded0ae49eb34b91cbae75f1e746cb48aca5e4a3 Mon Sep 17 00:00:00 2001 From: FlorianDahn Date: Sun, 9 Oct 2022 17:15:06 +0200 Subject: [PATCH 33/33] Update Testproject Co-Authored-By: Alexey <110727638+ZavaruKitsu@users.noreply.github.com> --- TelegramBotBase.Test/Program.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TelegramBotBase.Test/Program.cs b/TelegramBotBase.Test/Program.cs index 8b76b97..6e3eb4c 100644 --- a/TelegramBotBase.Test/Program.cs +++ b/TelegramBotBase.Test/Program.cs @@ -14,7 +14,7 @@ namespace TelegramBotBaseTest { class Program { - static void Main(string[] args) + static async void Main(string[] args) { String APIKey = ""; @@ -43,7 +43,7 @@ namespace TelegramBotBaseTest bb.BotCommand += Bb_BotCommand; //Update Bot commands to botfather - bb.UploadBotCommands().Wait(); + await bb.UploadBotCommands(); bb.SetSetting(TelegramBotBase.Enums.eSettings.LogAllMessages, true);