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)