Skip to content

Commit 808c423

Browse files
authored
Merge pull request #1045 from VRciF/feature/33-update-filter
Feature/33 update filter
2 parents 4ea6bb1 + 58b5ffa commit 808c423

File tree

4 files changed

+118
-1
lines changed

4 files changed

+118
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Exclamation symbols (:exclamation:) note something of importance e.g. breaking c
77
### Notes
88
- [:ledger: View file changes][Unreleased]
99
### Added
10+
- New method `setUpdateFilter($callback)` used to filter `processUpdate(Update $update)` calls. If `$callback` returns `false` the update isn't processed and an empty falsey `ServerResponse` is returned. (@VRciF)
1011
- Replaced 'generic' and 'genericmessage' strings with Telegram::GENERIC_COMMAND and Telegram::GENERIC_MESSAGE_COMMAND constants (@1int)
1112
- Bot API 4.8 (Extra Poll and Dice features).
1213
- Allow custom MySQL port to be defined for tests.

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ A Telegram Bot based on the official [Telegram Bot API]
4242
- [getUserProfilePhoto](#getuserprofilephoto)
4343
- [getFile and downloadFile](#getfile-and-downloadfile)
4444
- [Send message to all active chats](#send-message-to-all-active-chats)
45+
- [Filter Update](#filter-update)
4546
- [Utils](#utils)
4647
- [MySQL storage (Recommended)](#mysql-storage-recommended)
4748
- [External Database connection](#external-database-connection)
@@ -414,6 +415,25 @@ $results = Request::sendToActiveChats(
414415

415416
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.
416417

418+
#### Filter Update
419+
420+
Update processing can be allowed or denied by defining a custom update filter.
421+
Let's say we only want to allow messages from a user with ID 428, we can do the following before handling the request:
422+
423+
```php
424+
$telegram->setUpdateFilter(function (Update $update, Telegram $telegram, &$reason = 'Update denied by update_filter') {
425+
$user_id = $update->getMessage()->getFrom()->getId();
426+
if ($user_id === 428) {
427+
return true;
428+
}
429+
430+
$reason = "Invalid user with ID {$user_id}";
431+
return false;
432+
});
433+
```
434+
435+
The reason for denying an update can be defined with the `$reason` parameter. This text gets written to the debug log.
436+
417437
## Utils
418438

419439
### MySQL storage (Recommended)

src/Telegram.php

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ class Telegram
144144
*
145145
* @var integer
146146
*/
147-
protected $last_update_id = null;
147+
protected $last_update_id;
148148

149149
/**
150150
* The command to be executed when there's a new message update and nothing more suitable is found
@@ -156,6 +156,14 @@ class Telegram
156156
*/
157157
const GENERIC_COMMAND = 'generic';
158158

159+
/**
160+
* Update filter
161+
* Filter updates
162+
*
163+
* @var callback
164+
*/
165+
protected $update_filter;
166+
159167
/**
160168
* Telegram constructor.
161169
*
@@ -455,6 +463,20 @@ public function processUpdate(Update $update)
455463
$this->update = $update;
456464
$this->last_update_id = $update->getUpdateId();
457465

466+
if (is_callable($this->update_filter)) {
467+
$reason = 'Update denied by update_filter';
468+
try {
469+
$allowed = (bool) call_user_func_array($this->update_filter, [$update, $this, &$reason]);
470+
} catch (\Exception $e) {
471+
$allowed = false;
472+
}
473+
474+
if (!$allowed) {
475+
TelegramLog::debug($reason);
476+
return new ServerResponse(['ok' => false, 'description' => 'denied'], null);
477+
}
478+
}
479+
458480
//Load admin commands
459481
if ($this->isAdmin()) {
460482
$this->addCommandsPath(TB_BASE_COMMANDS_PATH . '/AdminCommands', false);
@@ -990,4 +1012,28 @@ public function getLastUpdateId()
9901012
{
9911013
return $this->last_update_id;
9921014
}
1015+
1016+
/**
1017+
* Set an update filter callback
1018+
*
1019+
* @param callable $callback
1020+
*
1021+
* @return Telegram
1022+
*/
1023+
public function setUpdateFilter(callable $callback)
1024+
{
1025+
$this->update_filter = $callback;
1026+
1027+
return $this;
1028+
}
1029+
1030+
/**
1031+
* Return update filter callback
1032+
*
1033+
* @return callable|null
1034+
*/
1035+
public function getUpdateFilter()
1036+
{
1037+
return $this->update_filter;
1038+
}
9931039
}

tests/unit/TelegramTest.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
namespace Longman\TelegramBot\Tests\Unit;
1313

1414
use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
15+
use Longman\TelegramBot\Entities\Update;
1516
use Longman\TelegramBot\Exception\TelegramException;
1617
use Longman\TelegramBot\Telegram;
18+
use Longman\TelegramBot\TelegramLog;
1719

1820
/**
1921
* @package TelegramTest
@@ -145,4 +147,52 @@ public function testGetCommandsList()
145147
$this->assertIsArray($commands);
146148
$this->assertNotCount(0, $commands);
147149
}
150+
151+
public function testUpdateFilter()
152+
{
153+
$rawUpdate = '{
154+
"update_id": 513400512,
155+
"message": {
156+
"message_id": 3,
157+
"from": {
158+
"id": 313534466,
159+
"first_name": "first",
160+
"last_name": "last",
161+
"username": "username"
162+
},
163+
"chat": {
164+
"id": 313534466,
165+
"first_name": "first",
166+
"last_name": "last",
167+
"username": "username",
168+
"type": "private"
169+
},
170+
"date": 1499402829,
171+
"text": "hi"
172+
}
173+
}';
174+
175+
$debug_log_file = '/tmp/php-telegram-bot-update-filter-debug.log';
176+
TelegramLog::initialize(
177+
new \Monolog\Logger('bot_log', [
178+
(new \Monolog\Handler\StreamHandler($debug_log_file, \Monolog\Logger::DEBUG))->setFormatter(new \Monolog\Formatter\LineFormatter(null, null, true)),
179+
])
180+
);
181+
182+
$update = new Update(json_decode($rawUpdate, true), $this->telegram->getBotUsername());
183+
$this->telegram->setUpdateFilter(function (Update $update, Telegram $telegram, &$reason) {
184+
if ($update->getMessage()->getChat()->getId() === 313534466) {
185+
$reason = 'Invalid user, update denied.';
186+
return false;
187+
}
188+
return true;
189+
});
190+
$response = $this->telegram->processUpdate($update);
191+
$this->assertFalse($response->isOk());
192+
193+
// Check that the reason is written to the debug log.
194+
$debug_log = file_get_contents($debug_log_file);
195+
$this->assertStringContainsString('Invalid user, update denied.', $debug_log);
196+
file_exists($debug_log_file) && unlink($debug_log_file);
197+
}
148198
}

0 commit comments

Comments
 (0)