Skip to content

Commit

Permalink
Added Forward/Copy/Delete and other improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
wiz0u committed Jul 8, 2024
1 parent aca7c8a commit bb606bb
Show file tree
Hide file tree
Showing 10 changed files with 123 additions and 65 deletions.
4 changes: 2 additions & 2 deletions Examples/1/ExampleBot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ 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));

Check warning on line 16 in Examples/1/ExampleBot.cs

View workflow job for this annotation

GitHub Actions / Build and upload

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 16 in Examples/1/ExampleBot.cs

View workflow job for this annotation

GitHub Actions / Build and upload

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

var me = await bot.GetMeAsync();
Console.WriteLine($"@{me.Username} is running... Press Enter to terminate");
Console.ReadLine();
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
Expand Down
4 changes: 2 additions & 2 deletions Examples/2/SendMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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 <b>all the parameters</b> of <code>sendMessage</code> method",
parseMode: ParseMode.Html,
protectContent: true,
replyParameters: update.Message.MessageId,
replyMarkup: new InlineKeyboardMarkup(
Expand Down
4 changes: 2 additions & 2 deletions src/1/example-bot.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
24 changes: 8 additions & 16 deletions src/1/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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`].
Expand All @@ -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.
```

Expand All @@ -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
2 changes: 2 additions & 0 deletions src/2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
77 changes: 77 additions & 0 deletions src/2/forward-copy-delete.md
Original file line number Diff line number Diff line change
@@ -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 <ins>copy</ins> 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 <b>caption</b> 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"
});
```
8 changes: 5 additions & 3 deletions src/2/send-msg/text-msg.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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.

Expand Down Expand Up @@ -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
5 changes: 3 additions & 2 deletions src/FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)_.
Expand Down
59 changes: 21 additions & 38 deletions src/README.md
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -40,28 +29,22 @@ Alternatively you can set up a `nuget.config` file at the root of your project/s
</configuration>
```

## 🔨 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)
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit bb606bb

Please sign in to comment.