From bb606bbf34f0f24ffaa803b1ce4c68b36f7010aa Mon Sep 17 00:00:00 2001 From: Wizou <11647984+wiz0u@users.noreply.github.com> Date: Mon, 8 Jul 2024 19:09:14 +0200 Subject: [PATCH] Added Forward/Copy/Delete and other improvements --- Examples/1/ExampleBot.cs | 4 +- Examples/2/SendMessage.cs | 4 +- src/1/example-bot.md | 4 +- src/1/quickstart.md | 24 ++++------- src/2/README.md | 2 + src/2/forward-copy-delete.md | 77 ++++++++++++++++++++++++++++++++++++ src/2/send-msg/text-msg.md | 8 ++-- src/FAQ.md | 5 ++- src/README.md | 59 ++++++++++----------------- src/SUMMARY.md | 1 + 10 files changed, 123 insertions(+), 65 deletions(-) create mode 100644 src/2/forward-copy-delete.md diff --git a/Examples/1/ExampleBot.cs b/Examples/1/ExampleBot.cs index 5bab2d59..5bb14ac5 100644 --- a/Examples/1/ExampleBot.cs +++ b/Examples/1/ExampleBot.cs @@ -13,7 +13,7 @@ private async Task BookExamples() // ANCHOR: example-bot using var cts = new CancellationTokenSource(); var bot = new TelegramBotClient("{YOUR_ACCESS_TOKEN_HERE}", cancellationToken: cts.Token); -bot.StartReceiving(HandleUpdate, async (bot, ex, ct) => Console.WriteLine(ex)); +bot.StartReceiving(OnUpdate, async (bot, ex, ct) => Console.WriteLine(ex)); var me = await bot.GetMeAsync(); Console.WriteLine($"@{me.Username} is running... Press Enter to terminate"); @@ -21,7 +21,7 @@ private async Task BookExamples() cts.Cancel(); // stop the bot // method that handle updates coming for the bot: -async Task HandleUpdate(ITelegramBotClient bot, Update update, CancellationToken ct) +async Task OnUpdate(ITelegramBotClient bot, Update update, CancellationToken ct) { if (update.Message is null) return; // we want only updates about new Message if (update.Message.Text is null) return; // we want only updates about new Text Message diff --git a/Examples/2/SendMessage.cs b/Examples/2/SendMessage.cs index 46ac0718..9d8ad3b7 100644 --- a/Examples/2/SendMessage.cs +++ b/Examples/2/SendMessage.cs @@ -153,8 +153,8 @@ private async Task SendText() return; // ANCHOR: send-text -var message = await bot.SendTextMessageAsync(chatId, "Trying *all the parameters* of `sendMessage` method", - parseMode: ParseMode.MarkdownV2, +var message = await bot.SendTextMessageAsync(chatId, "Trying all the parameters of sendMessage method", + parseMode: ParseMode.Html, protectContent: true, replyParameters: update.Message.MessageId, replyMarkup: new InlineKeyboardMarkup( diff --git a/src/1/example-bot.md b/src/1/example-bot.md index 94aa78d8..3959fd14 100644 --- a/src/1/example-bot.md +++ b/src/1/example-bot.md @@ -27,11 +27,11 @@ Telegram and send a text message to it. Bot should reply in no time. By invoking [`StartReceiving(...)`] bot client starts fetching updates using [`getUpdates`] method for the bot from Telegram servers. This operation does not block the caller thread, because it is done on the ThreadPool. We use `Console.ReadLine()` to keep the app running. -When user sends a message, the `HandleUpdateAsync(...)` method gets invoked with the `Update` object passed as an argument. +When user sends a message, the `OnUpdate(...)` method gets invoked with the `Update` object passed as an argument. We check `Message.Type` and skip the rest if it is not a text message. Finally, we send a text message back to the same chat we got the message from. -The `HandleErrorAsync(...)` method is invoked in case of an error that occurred while fetching updates. +The second argument to `StartReceiving` is a lambda method invoked in case of an error that occurred while fetching updates. If you take a look at the console, the program outputs the `chatId` value. **Copy the chat id number** to make testing easier for yourself on the next pages. diff --git a/src/1/quickstart.md b/src/1/quickstart.md index 0e0cfa4c..362bc3f5 100644 --- a/src/1/quickstart.md +++ b/src/1/quickstart.md @@ -2,8 +2,8 @@ ## Bot Father -Before you start, you need to talk to [`@BotFather`] on Telegram. [Create a new -bot], acquire the bot token and get back here. +Before you start, you need to talk to [`@BotFather`] on Telegram. +[Create a new bot](https://core.telegram.org/bots/tutorial#obtain-your-bot-token), acquire the bot token and get back here. [![Bot Father](docs/logo-bot-father.jpg)](https://t.me/botfather) @@ -15,22 +15,18 @@ Bot token is a key that required to authorize the bot and send requests to the B ## Hello World -Now that you have a bot, it's time to bring it to life! Create a new console project for your bot. -It could be a legacy project targeting .NET Framework 4.6.1-4.8 or a modern .NET Core 3.1-.NET 5+. +Now that you have a bot, it's time to bring it to life! -> Examples in this guide target .NET 6, but earlier targets should work as well (including .NET Framework). +> We recommend a recent .NET version like .NET 8, but we also support older .NET Framework (4.6.1+), .NET Core (2.0+) or .NET (5.0+) +ne +Create a new console project for your bot and add a reference to `Telegram.Bot` package: ```bash dotnet new console +dotnet add package Telegram.Bot --source https://nuget.voids.site/v3/index.json ``` -Add a reference to [`Telegram.Bot`] package: - -```bash -dotnet add package Telegram.Bot -``` - -This code fetches Bot information based on its access token by calling the Bot API [`getMe`] method. Open `Program.cs` and use the following content: +The code below fetches Bot information based on its access token by calling the Bot API [`getMe`] method. Open `Program.cs` and use the following content: > ⚠️ Replace `{YOUR_ACCESS_TOKEN_HERE}` with your access token from the [`@BotFather`]. @@ -44,9 +40,7 @@ Running the program gives you the following output: ```bash dotnet run -``` -```text Hello, World! I am user 1234567 and my name is Awesome Bot. ``` @@ -55,7 +49,5 @@ Great! This bot is self-aware. To make the bot interact with a user, head to the [`@BotFather`]: https://t.me/botfather -[Create a new bot]: https://core.telegram.org/bots#6-botfather -[`Telegram.Bot`]: https://www.nuget.org/packages/Telegram.Bot [`getMe`]: https://core.telegram.org/bots/api#getme [next page]: example-bot.md diff --git a/src/2/README.md b/src/2/README.md index 90ef064b..d7ae0597 100644 --- a/src/2/README.md +++ b/src/2/README.md @@ -7,5 +7,7 @@ - [Video & Video Note](send-msg/video-video_note-msg.md) - [Album (Media Group)](send-msg/album-msg.md) - [Document & Animation](send-msg/document-animation-msg.md) + - [Native Polls](send-msg/native-polls-msg.md) - [Other Messages](send-msg/other-msg.md) - [Reply Markup](reply-markup.md) +- [Forward, Copy or Delete](forward-copy-delete.md) \ No newline at end of file diff --git a/src/2/forward-copy-delete.md b/src/2/forward-copy-delete.md new file mode 100644 index 00000000..1a362701 --- /dev/null +++ b/src/2/forward-copy-delete.md @@ -0,0 +1,77 @@ +# Forward, Copy or Delete messages + +You can forward, copy, or delete a single message, or even a bunch of messages in one go. + +You will need to provide the source messageId(s), the source chatId and eventually the target chatId. + +_Note: When you use the plural form of the copy/forward methods, it will keep Media Groups (albums) as such._ + +## Forward message(s) + +You can **forward** message(s) from a source chat to a target chat _(it can be the same chat)_. +They will appear with a "Forwarded from" header. + +```csharp +// Forward a single message +await bot.CopyMessageAsync(targetChatId, sourceChatId, messageId); + +// Forward an incoming message (from the update) onto a target ChatId +await bot.ForwardMessageAsync(chatId, update.Message.Chat, update.Message.MessageId); + +// Forward a bunch of messages from a source ChatId to a target ChatId, using a list of their message ids +await bot.ForwardMessagesAsync(targetChatId, sourceChatId, new int[] { 123, 124, 125 }); +``` + +## Copy message(s) + +If you don't want the "Forwarded from" header, you can instead copy the message(s). + +This will make them look like new messages. + +```csharp +// Copy a single message +await bot.CopyMessageAsync(targetChatId, sourceChatId, messageId); + +// Copy an incoming message (from the update) onto a target ChatId +await bot.CopyMessageAsync(targetChatId, update.Message.Chat, update.Message.MessageId); + +// Copy a media message and change its caption at the same time +await bot.CopyMessageAsync(targetChatId, update.Message.Chat, update.Message.MessageId, + caption: "New caption for this media", parseMode: ParseMode.Html); + +// Copy a bunch of messages from a source ChatId to a target ChatId, using a list of their message ids +await bot.CopyMessagesAsync(targetChatId, sourceChatId, new int[] { 123, 124, 125 }); +``` + +## Delete message(s) + +Finally you can **delete** message(s). + +This is particularly useful for cleaning unwanted messages in groups. + +```csharp +// Delete a single message +await bot.DeleteMessageAsync(chatId, messageId); + +// Delete an incoming message (from the update) +await bot.CopyMessageAsync(update.Message.Chat, update.Message.MessageId); + +// Delete a bunch of messages, using a list of their message ids +await bot.DeleteMessagesAsync(chatId, new int[] { 123, 124, 125 }); +``` + +## Check if a message is a forward + +When receiving an update about a message, you can check if that message is "Forwarded from" somewhere, +by checking if `Message.ForwardOrigin` is set: + +```csharp +Console.WriteLine(update.Message.ForwardOrigin switch +{ + MessageOriginChannel moc => $"Forwarded from channel {moc.Chat.Title}", + MessageOriginUser mou => $"Forwarded from user {mou.SenderUser}", + MessageOriginHiddenUser mohu => $"Forwarded from hidden user {mohu.SenderUserName}", + MessageOriginChat moch => $"Forwarded on behalf of {moch.SenderChat}", + _ => "Not forwarded" +}); +``` diff --git a/src/2/send-msg/text-msg.md b/src/2/send-msg/text-msg.md index 44e219cc..89305b0f 100644 --- a/src/2/send-msg/text-msg.md +++ b/src/2/send-msg/text-msg.md @@ -5,7 +5,9 @@ Text is a powerful interface for your bot and [`sendMessage`] probably is the most used method of the Telegram Bot API. Text messages are easy to send and fast to display on devices with slower networking. -_Don't send boring plain text to users all the time_. Telegram allows you to format the text using Markdown or HTML. + +_Don't send boring plain text to users all the time_. Telegram allows you to format the text using HTML or Markdown. +> We highly recommend you use HTML instead of Markdown because Markdown has lots of annoying aspects ## Send Text Message @@ -23,7 +25,7 @@ The code snippet below sends a message with multiple parameters that looks like The method `SendTextMessageAsync` of .NET Bot Client maps to [`sendMessage`] on Telegram's Bot API. This method sends a text message and returns the message object sent. -`text` is written in [MarkDown format] and `parseMode` indicates that. You can also write in HTML or plain text. +`text` is written in [HTML format] and `parseMode` indicates that. You can also write in Markdown or plain text. By passing `protectContent` we prevent the message (and eventual media) to be copiable/forwardable elsewhere. @@ -67,6 +69,6 @@ message.EntityValues.First() == "all the parameters" Try putting a breakpoint in the code to examine all the properties on a message objects you get. [`sendMessage`]: https://core.telegram.org/bots/api#sendmessage -[MarkDown format]: https://core.telegram.org/bots/api#markdown-style +[HTML format]: https://core.telegram.org/bots/api#html-style [UTC format]: https://en.wikipedia.org/wiki/Coordinated_Universal_Time [Message Entity]: https://core.telegram.org/bots/api#messageentity diff --git a/src/FAQ.md b/src/FAQ.md index bf705642..1fb36e08 100644 --- a/src/FAQ.md +++ b/src/FAQ.md @@ -25,8 +25,9 @@ _See also next question._ ### _5. How to handle a click on such inline buttons?_ For buttons with callback data, your update handler should handle `update.CallbackQuery`. -_(not all updates are about `update.Message`. See question #3)_ -Your code should answer to it with `AnswerCallbackQueryAsync` +_(Remember that not all updates are about `update.Message`. See question #3)_ + +Your code should answer to the query within 10 seconds, using `AnswerCallbackQueryAsync` _(or else the button gets momentarily disabled)_ ### _6. How to show a popup text to the user?_ It is only possible with inline callback button _(see above questions)_. diff --git a/src/README.md b/src/README.md index 33bd03e7..dee005e5 100644 --- a/src/README.md +++ b/src/README.md @@ -1,31 +1,20 @@ # Telegram Bots Book - [![NuGet](https://img.shields.io/nuget/dt/Telegram.Bot.svg?style=flat-square)](https://nuget.voids.site/packages/Telegram.Bot) [![Repository](https://img.shields.io/github/stars/TelegramBots/Telegram.Bot.svg?style=social&label=Stars)](https://github.com/TelegramBots/Telegram.Bot) -[**Telegram.Bot**] is the most popular .NET Client for [Telegram Bot API]. - -The Bot API is an HTTP-based interface created for developers keen on building bots for [Telegram]. -Check [_Bots: An introduction for developers_] to understand what a Telegram bot is and what it can do. - -We, the [Telegram Bots team], mainly focus on developing multiple [NuGet packages] for creating chatbots. - -|Packages|Team|News Channel|Group Chat| -|:------:|:--:|:----------:|:--------:| -| [![Packages](1/docs/logo-nuget.png)](https://nuget.voids.site/packages/Telegram.Bot) | [![Team](1/docs/logo-gh.png)](https://github.com/orgs/TelegramBots/people) | [![News Channel](1/docs/logo-channel.jpg)](https://t.me/s/tgbots_dotnet) | [![Group Chat](1/docs/logo-chat.jpg)](https://t.me/joinchat/B35YY0QbLfd034CFnvCtCA) | -| Our nuget package feed | The team contributing to this work | Subscribe to [`@tgbots_dotnet`] channel to get our latest news | [Join our chat] to talk about bots and ask questions | - -## ℹ️ What Is This Book For +**[Telegram.Bot](https://github.com/TelegramBots/Telegram.Bot)** is the most popular .NET client for [Telegram Bot API](https://core.telegram.org/bots/api), allowing [developers to build bots](https://core.telegram.org/bots) for [Telegram](https://www.telegram.org) messaging app. -All Bot API methods are already documented by Telegram[^1] but this book covers all you need to know to create a +Telegram Bot API is [officially documented](https://core.telegram.org/bots/api) but this book covers all you need to know to create a chatbot in .NET. There are also many concrete examples written in C#. The guides here can even be useful to bot developers using other languages/platforms as it shows best practices in developing Telegram chatbots with examples. +➡️ Access the book pages via the Table Of Content (top/left), or start your journey with our [_Quickstart_](1/quickstart.md) guide. + ## 🧩 Installation -Latest versions of the library are not yet available on Nuget․org due to false-positive malware detection. We are working with Nuget/ESET teams to resolve this issue. +⚠️ _Latest versions of the library are not available on Nuget․org due to false-positive malware detection. We are working with Nuget/ESET teams to resolve this issue._ -In the mean time, it's available on our [special nuget feed](https://nuget.voids.site/packages/Telegram.Bot): `https://nuget.voids.site/v3/index.json` +In the mean time, latest versions are available on our [special nuget feed](https://nuget.voids.site/packages/Telegram.Bot): `https://nuget.voids.site/v3/index.json` Follow the pictures below to configure the Package source in Visual Studio: ![In Visual Studio](1/docs/NugetPackageManager.jpg) @@ -40,28 +29,22 @@ Alternatively you can set up a `nuget.config` file at the root of your project/s ``` -## 🔨 Get Started - -**Begin your bot development journey with the [_Quickstart_](1/quickstart.md) guide.** - -## 🪄 Examples - -Check out our [examples](https://github.com/TelegramBots/Telegram.Bot.Examples) repository for more. +## 🪄 More examples -## ✅ Correctness & Testing +This book is filled with ready-to-use snippets of code, but you can also find full project examples at our [Telegram.Bot.Examples](https://github.com/TelegramBots/Telegram.Bot.Examples) Github repository, featuring: +- Simple Console apps (long polling) +- Webhook ASP.NET example (with Controllers or Minimal APIs) +- Full-featured advanced solution +- Serverless Functions implementations -This project is fully tested using Unit tests and Systems Integration tests before each release. -In fact, our test cases are self-documenting and serve as examples for Bot API methods. -Once you learn the basics of Telegram chatbots, you will be able to easily understand the code in examples and -use it in your own bot projects. +## 🔗 More useful links +|Visit our|URL| +|--|--| +|Nuget feed|https://nuget.voids.site/packages/Telegram.Bot| +|Github repo|https://github.com/TelegramBots/Telegram.Bot| +|Examples repo|https://github.com/TelegramBots/Telegram.Bot.Examples| +|Telegram news channel|https://t.me/tgbots_dotnet| +|Telegram support group|https://t.me/joinchat/B35YY0QbLfd034CFnvCtCA| +|Team page|https://github.com/orgs/TelegramBots/people| -[**Telegram.Bot**]: https://github.com/TelegramBots/Telegram.Bot -[Telegram Bot API]: https://core.telegram.org/bots/api -[Telegram]: https://www.telegram.org/ -[_Bots: An introduction for developers_]: https://core.telegram.org/bots -[Telegram Bots team]: https://github.com/orgs/TelegramBots/people -[NuGet packages]: https://www.nuget.org/profiles/TelegramBots -[`@tgbots_dotnet`]: https://t.me/tgbots_dotnet -[Join our chat]: https://t.me/joinchat/B35YY0QbLfd034CFnvCtCA -[^1]: [Telegram Bot API](https://core.telegram.org/bots/api) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 2849c3cb..d9b98ad5 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -14,6 +14,7 @@ - [Native Polls](2/send-msg/native-polls-msg.md) - [Other Messages](2/send-msg/other-msg.md) - [Reply Markup](2/reply-markup.md) + - [Forward, Copy or Delete](2/forward-copy-delete.md) - [Intermediate](3/README.md) - [Getting Updates](3/updates/README.md) - [Long Polling](3/updates/polling.md)