Skip to content

Allow defining update types when handling updates via getUpdates method #1202

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ Exclamation symbols (:exclamation:) note something of importance e.g. breaking c
- Bot API 5.1 (ChatMember Update types, Improved Invite Links, Voice Chat). (@massadm, @noplanman)
### Changed
### Deprecated
- `Telegram::handleGetUpdates` method should be passed a `$data` array for parameters.
### Removed
### Fixed
- `message.edit_date` is now of type `timestamp`.
- Allow all update types by default when using `getUpdates` method.
### Security

## [0.71.0] - 2021-03-05
Expand Down
70 changes: 48 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

A Telegram Bot based on the official [Telegram Bot API]

[![API Version](https://img.shields.io/badge/Bot%20API-5.1%20%28March%202021%29-32a2da.svg)](https://core.telegram.org/bots/api#november-4-2020)
[![API Version](https://img.shields.io/badge/Bot%20API-5.1%20%28March%202021%29-32a2da.svg)](https://core.telegram.org/bots/api#march-9-2021)
[![Join the bot support group on Telegram](https://img.shields.io/badge/telegram-@PHP__Telegram__Bot__Support-64659d.svg)](https://telegram.me/PHP_Telegram_Bot_Support)
[![Donate](https://img.shields.io/badge/%F0%9F%92%99-Donate%20%2F%20Support%20Us-blue.svg)](#donate)

Expand All @@ -33,6 +33,7 @@ A Telegram Bot based on the official [Telegram Bot API]
- [Unset Webhook](#unset-webhook)
- [getUpdates installation](#getupdates-installation)
- [getUpdates without database](#getupdates-without-database)
- [Filter Update](#filter-update)
- [Support](#support)
- [Types](#types)
- [Inline Query](#inline-query)
Expand All @@ -43,7 +44,6 @@ A Telegram Bot based on the official [Telegram Bot API]
- [getUserProfilePhoto](#getuserprofilephoto)
- [getFile and downloadFile](#getfile-and-downloadfile)
- [Send message to all active chats](#send-message-to-all-active-chats)
- [Filter Update](#filter-update)
- [Utils](#utils)
- [MySQL storage (Recommended)](#mysql-storage-recommended)
- [External Database connection](#external-database-connection)
Expand Down Expand Up @@ -339,6 +339,52 @@ If you choose to / or are obliged to use the `getUpdates` method without a datab
$telegram->useGetUpdatesWithoutDatabase();
```

## Filter Update

:exclamation: Note that by default, Telegram will send any new update types that may be added in the future. This may cause commands that don't take this into account to break!

It is suggested that you specifically define which update types your bot can receive and handle correctly.

You can define which update types are sent to your bot by defining them when setting the [webhook](#webhook-installation) or passing an array of allowed types when using [getUpdates](#getupdates-installation).

```php
use Longman\TelegramBot\Entities\Update;

// For all update types currently implemented in this library:
// $allowed_updates = Update::getUpdateTypes();

// Define the list of allowed Update types manually:
$allowed_updates = [
Update::TYPE_MESSAGE,
Update::TYPE_CHANNEL_POST,
// etc.
];

// When setting the webhook.
$telegram->setWebhook($hook_url, ['allowed_updates' => $allowed_updates]);

// When handling the getUpdates method.
$telegram->handleGetUpdates(['allowed_updates' => $allowed_updates]);
```

Alternatively, Update processing can be allowed or denied by defining a custom update filter.

Let's say we only want to allow messages from a user with ID `428`, we can do the following before handling the request:

```php
$telegram->setUpdateFilter(function (Update $update, Telegram $telegram, &$reason = 'Update denied by update_filter') {
$user_id = $update->getMessage()->getFrom()->getId();
if ($user_id === 428) {
return true;
}

$reason = "Invalid user with ID {$user_id}";
return false;
});
```

The reason for denying an update can be defined with the `$reason` parameter. This text gets written to the debug log.

## Support

### Types
Expand Down Expand Up @@ -433,26 +479,6 @@ $results = Request::sendToActiveChats(

You can also broadcast a message to users, from the private chat with your bot. Take a look at the [admin commands](#admin-commands) below.

#### Filter Update

Update processing can be allowed or denied by defining a custom update filter.

Let's say we only want to allow messages from a user with ID 428, we can do the following before handling the request:

```php
$telegram->setUpdateFilter(function (Update $update, Telegram $telegram, &$reason = 'Update denied by update_filter') {
$user_id = $update->getMessage()->getFrom()->getId();
if ($user_id === 428) {
return true;
}

$reason = "Invalid user with ID {$user_id}";
return false;
});
```

The reason for denying an update can be defined with the `$reason` parameter. This text gets written to the debug log.

## Utils

### MySQL storage (Recommended)
Expand Down
53 changes: 38 additions & 15 deletions src/Entities/Update.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,37 +36,60 @@
*/
class Update extends Entity
{
public const TYPE_MESSAGE = 'message';
public const TYPE_EDITED_MESSAGE = 'edited_message';
public const TYPE_CHANNEL_POST = 'channel_post';
public const TYPE_EDITED_CHANNEL_POST = 'edited_channel_post';
public const TYPE_INLINE_QUERY = 'inline_query';
public const TYPE_CHOSEN_INLINE_RESULT = 'chosen_inline_result';
public const TYPE_CALLBACK_QUERY = 'callback_query';
public const TYPE_SHIPPING_QUERY = 'shipping_query';
public const TYPE_PRE_CHECKOUT_QUERY = 'pre_checkout_query';
public const TYPE_POLL = 'poll';
public const TYPE_POLL_ANSWER = 'poll_answer';
public const TYPE_MY_CHAT_MEMBER = 'my_chat_member';
public const TYPE_CHAT_MEMBER = 'chat_member';

/**
* {@inheritdoc}
*/
protected function subEntities(): array
{
return [
'message' => Message::class,
'edited_message' => EditedMessage::class,
'channel_post' => ChannelPost::class,
'edited_channel_post' => EditedChannelPost::class,
'inline_query' => InlineQuery::class,
'chosen_inline_result' => ChosenInlineResult::class,
'callback_query' => CallbackQuery::class,
'shipping_query' => ShippingQuery::class,
'pre_checkout_query' => PreCheckoutQuery::class,
'poll' => Poll::class,
'poll_answer' => PollAnswer::class,
'my_chat_member' => ChatMemberUpdated::class,
'chat_member' => ChatMemberUpdated::class,
self::TYPE_MESSAGE => Message::class,
self::TYPE_EDITED_MESSAGE => EditedMessage::class,
self::TYPE_CHANNEL_POST => ChannelPost::class,
self::TYPE_EDITED_CHANNEL_POST => EditedChannelPost::class,
self::TYPE_INLINE_QUERY => InlineQuery::class,
self::TYPE_CHOSEN_INLINE_RESULT => ChosenInlineResult::class,
self::TYPE_CALLBACK_QUERY => CallbackQuery::class,
self::TYPE_SHIPPING_QUERY => ShippingQuery::class,
self::TYPE_PRE_CHECKOUT_QUERY => PreCheckoutQuery::class,
self::TYPE_POLL => Poll::class,
self::TYPE_POLL_ANSWER => PollAnswer::class,
self::TYPE_MY_CHAT_MEMBER => ChatMemberUpdated::class,
self::TYPE_CHAT_MEMBER => ChatMemberUpdated::class,
];
}

/**
* Get the list of all available update types
*
* @return string[]
*/
public static function getUpdateTypes(): array
{
return array_keys((new self([]))->subEntities());
}

/**
* Get the update type based on the set properties
*
* @return string|null
*/
public function getUpdateType(): ?string
{
$types = array_keys($this->subEntities());
foreach ($types as $type) {
foreach (self::getUpdateTypes() as $type) {
if ($this->getProperty($type)) {
return $type;
}
Expand Down
46 changes: 31 additions & 15 deletions src/Telegram.php
Original file line number Diff line number Diff line change
Expand Up @@ -391,13 +391,15 @@ public function getLastCommandResponse(): ServerResponse
/**
* Handle getUpdates method
*
* @param int|null $limit
* @param int|null $timeout
* @todo Remove backwards compatibility for old signature and force $data to be an array.
*
* @param array|int|null $data
* @param int|null $timeout
*
* @return ServerResponse
* @throws TelegramException
*/
public function handleGetUpdates(?int $limit = null, ?int $timeout = null): ServerResponse
public function handleGetUpdates($data = null, ?int $timeout = null): ServerResponse
{
if (empty($this->bot_username)) {
throw new TelegramException('Bot Username is not defined!');
Expand All @@ -414,8 +416,27 @@ public function handleGetUpdates(?int $limit = null, ?int $timeout = null): Serv
}

$offset = 0;
$limit = null;

// By default, get update types sent by Telegram.
$allowed_updates = [];

// @todo Backwards compatibility for old signature, remove in next version.
if (!is_array($data)) {
$limit = $data;

//Take custom input into account.
@trigger_error(
sprintf('Use of $limit and $timeout parameters in %s is deprecated. Use $data array instead.', __METHOD__),
E_USER_DEPRECATED
);
} else {
$offset = $data['offset'] ?? $offset;
$limit = $data['limit'] ?? $limit;
$timeout = $data['timeout'] ?? $timeout;
$allowed_updates = $data['allowed_updates'] ?? $allowed_updates;
}

// Take custom input into account.
if ($custom_input = $this->getCustomInput()) {
try {
$input = json_decode($this->input, true, 512, JSON_THROW_ON_ERROR);
Expand All @@ -437,11 +458,7 @@ public function handleGetUpdates(?int $limit = null, ?int $timeout = null): Serv
$offset = $this->last_update_id + 1; // As explained in the telegram bot API documentation.
}

$response = Request::getUpdates([
'offset' => $offset,
'limit' => $limit,
'timeout' => $timeout,
]);
$response = Request::getUpdates(compact('offset', 'limit', 'timeout', 'allowed_updates'));
}

if ($response->isOk()) {
Expand All @@ -455,12 +472,11 @@ public function handleGetUpdates(?int $limit = null, ?int $timeout = null): Serv
}

if (!DB::isDbConnected() && !$custom_input && $this->last_update_id !== null && $offset === 0) {
//Mark update(s) as read after handling
Request::getUpdates([
'offset' => $this->last_update_id + 1,
'limit' => 1,
'timeout' => $timeout,
]);
// Mark update(s) as read after handling
$offset = $this->last_update_id + 1;
$limit = 1;

Request::getUpdates(compact('offset', 'limit', 'timeout', 'allowed_updates'));
}
}

Expand Down