Skip to content

Commit 8dfbbb6

Browse files
committed
Implement Telegram bot with advanced anti-spam features
1 parent 638f698 commit 8dfbbb6

File tree

5 files changed

+207
-3
lines changed

5 files changed

+207
-3
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace App\Http\Controllers;
4+
5+
use App\Services\TelegramBot;
6+
use Illuminate\Http\Request;
7+
8+
class WebHookController extends Controller
9+
{
10+
/**
11+
* Handle incoming Telegram webhook requests.
12+
*
13+
* @param \Illuminate\Http\Request $request
14+
* @param \App\Services\TelegramBot $telegramBot
15+
*
16+
* @return void
17+
*/
18+
public function telegram(Request $request, TelegramBot $telegramBot): void
19+
{
20+
$text = $request->input('message.text');
21+
$messageId = $request->input('message.message_id');
22+
$chatId = $request->input('message.chat.id');
23+
$from = $request->input('message.from.id');
24+
25+
// Если сообщение - ответ на другое сообщение, то скорее всего это не спам.
26+
// Давайте не прерывать дискуссию и игнорируем его
27+
if ($request->has('message.reply_to_message') || $request->boolean('message.from.is_bot')) {
28+
return;
29+
}
30+
31+
if (! $telegramBot->isSpam($text)) {
32+
return;
33+
}
34+
35+
$telegramBot->deleteMessage($chatId, $messageId);
36+
$telegramBot->muteUserInGroup($chatId, $from);
37+
}
38+
}

app/Services/TelegramBot.php

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<?php
2+
3+
namespace App\Services;
4+
5+
use AssistedMindfulness\NaiveBayes\Classifier;
6+
use Illuminate\Http\Client\Response;
7+
use Illuminate\Support\Facades\Http;
8+
use Illuminate\Support\Str;
9+
use NotificationChannels\Telegram\TelegramMessage;
10+
11+
class TelegramBot
12+
{
13+
public const SPAM = 'spam';
14+
public const HAM = 'ham';
15+
16+
private $token;
17+
18+
/**
19+
* Construct a new TelegramBot instance.
20+
*
21+
* @return void
22+
*/
23+
public function __construct()
24+
{
25+
$this->token = config('services.telegram-bot-api.token');
26+
}
27+
28+
/**
29+
* Mute a user in a group chat.
30+
*
31+
* @param int $chatId
32+
* @param int $userId
33+
* @param int $muteDuration
34+
*
35+
* @return \Illuminate\Http\Client\Response
36+
*/
37+
public function muteUserInGroup($chatId, $userId, $muteDuration = 60): Response
38+
{
39+
$url = "https://api.telegram.org/bot{$this->token}/restrictChatMember";
40+
41+
return Http::post($url, [
42+
'chat_id' => $chatId,
43+
'user_id' => $userId,
44+
'until_date' => time() + $muteDuration,
45+
'can_send_messages' => false,
46+
'can_send_media_messages' => false,
47+
'can_send_other_messages' => false,
48+
'can_add_web_page_previews' => false,
49+
]);
50+
}
51+
52+
/**
53+
* Delete a message from a chat.
54+
*
55+
* @param int $chatId
56+
* @param int $messageId
57+
*
58+
* @return \Illuminate\Http\Client\Response
59+
*/
60+
public function deleteMessage($chatId, $messageId): Response
61+
{
62+
$url = "https://api.telegram.org/bot{$this->token}/deleteMessage";
63+
64+
return Http::post($url, [
65+
'chat_id' => $chatId,
66+
'message_id' => $messageId,
67+
]);
68+
}
69+
70+
/**
71+
* Check if a message is spam.
72+
*
73+
* @param string $message
74+
*
75+
* @return bool
76+
*/
77+
public function isSpam(string $message): bool
78+
{
79+
$classifier = new Classifier();
80+
81+
$classifier
82+
/**
83+
* Spam
84+
*/
85+
->learn('Здрaвcтвyйте, прeдостaвляю yдалённyю зaнятoсть. 770$+ в нeдeлю Кoмy интepeсно, пишитe "+" в личные', static::SPAM)
86+
->learn('Всeх привeтствую. Нyжны пaртнёры для удалённoгo сoтрудничeства. Пoдробнoсти в лс', static::SPAM)
87+
88+
/**
89+
* Hamming
90+
*/
91+
->learn('а учусь я потому что хочу работу нормальную найти и чтоб дети жили нормально)', static::HAM)
92+
->learn('у тебя переменная передается не так надо массив ->asyncParameters()', static::HAM)
93+
->learn('MVC. Можно ещё там использовать сервис контейнеры, фасады, view-model', static::HAM)
94+
->learn('Попробуем, спасибо 🙏', static::HAM)
95+
->learn('https://laravel.com/docs/', static::HAM)
96+
->learn('Да', static::HAM)
97+
->learn('Получилось', static::HAM);
98+
99+
TelegramMessage::create()
100+
->to(config('services.telegram-bot-api.chat_id'))
101+
->line('*Сообщение было классифицировано как '.$classifier->most($message))
102+
->line('')
103+
->line('*📂 Текст сообщения*')
104+
->escapedLine($message)
105+
->send();
106+
107+
return Str::of($message)->contains([
108+
'yдалённyю',
109+
'в нeдeлю',
110+
'интepeсно',
111+
'пaртнёры',
112+
'сoтрудничeств',
113+
]);
114+
}
115+
}

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717
],
1818
"license": "CC BY-NC-SA 4.0",
1919
"require": {
20-
"php": "^8.3",
20+
"php": "^8.2",
2121
"ext-dom": "*",
22+
"assisted-mindfulness/naive-bayes": "0.0.3",
2223
"cagilo/cagilo": "^3.2",
2324
"doctrine/dbal": "^3.7",
2425
"esplora/spire": "0.0.1",

composer.lock

Lines changed: 49 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

routes/api.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?php
22

3+
use App\Http\Controllers\WebHookController;
34
use Illuminate\Http\Request;
45
use Illuminate\Support\Facades\Route;
56

@@ -17,3 +18,5 @@
1718
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
1819
return $request->user();
1920
});
21+
22+
Route::post('/webhook/telegram', [WebHookController::class, 'telegram'])->name('webhook.telegram');

0 commit comments

Comments
 (0)