Skip to content

Commit

Permalink
Implement Telegram bot with advanced anti-spam features
Browse files Browse the repository at this point in the history
  • Loading branch information
tabuna committed Mar 19, 2024
1 parent 638f698 commit 8dfbbb6
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 3 deletions.
38 changes: 38 additions & 0 deletions app/Http/Controllers/WebHookController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace App\Http\Controllers;

use App\Services\TelegramBot;
use Illuminate\Http\Request;

class WebHookController extends Controller
{
/**
* Handle incoming Telegram webhook requests.
*
* @param \Illuminate\Http\Request $request
* @param \App\Services\TelegramBot $telegramBot
*
* @return void
*/
public function telegram(Request $request, TelegramBot $telegramBot): void
{
$text = $request->input('message.text');
$messageId = $request->input('message.message_id');
$chatId = $request->input('message.chat.id');
$from = $request->input('message.from.id');

// Если сообщение - ответ на другое сообщение, то скорее всего это не спам.
// Давайте не прерывать дискуссию и игнорируем его
if ($request->has('message.reply_to_message') || $request->boolean('message.from.is_bot')) {
return;
}

if (! $telegramBot->isSpam($text)) {
return;
}

$telegramBot->deleteMessage($chatId, $messageId);
$telegramBot->muteUserInGroup($chatId, $from);
}
}
115 changes: 115 additions & 0 deletions app/Services/TelegramBot.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?php

namespace App\Services;

use AssistedMindfulness\NaiveBayes\Classifier;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
use NotificationChannels\Telegram\TelegramMessage;

class TelegramBot
{
public const SPAM = 'spam';
public const HAM = 'ham';

private $token;

/**
* Construct a new TelegramBot instance.
*
* @return void
*/
public function __construct()
{
$this->token = config('services.telegram-bot-api.token');
}

/**
* Mute a user in a group chat.
*
* @param int $chatId
* @param int $userId
* @param int $muteDuration
*
* @return \Illuminate\Http\Client\Response
*/
public function muteUserInGroup($chatId, $userId, $muteDuration = 60): Response
{
$url = "https://api.telegram.org/bot{$this->token}/restrictChatMember";

return Http::post($url, [
'chat_id' => $chatId,
'user_id' => $userId,
'until_date' => time() + $muteDuration,
'can_send_messages' => false,
'can_send_media_messages' => false,
'can_send_other_messages' => false,
'can_add_web_page_previews' => false,
]);
}

/**
* Delete a message from a chat.
*
* @param int $chatId
* @param int $messageId
*
* @return \Illuminate\Http\Client\Response
*/
public function deleteMessage($chatId, $messageId): Response
{
$url = "https://api.telegram.org/bot{$this->token}/deleteMessage";

return Http::post($url, [
'chat_id' => $chatId,
'message_id' => $messageId,
]);
}

/**
* Check if a message is spam.
*
* @param string $message
*
* @return bool
*/
public function isSpam(string $message): bool
{
$classifier = new Classifier();

$classifier
/**
* Spam
*/
->learn('Здрaвcтвyйте, прeдостaвляю yдалённyю зaнятoсть. 770$+ в нeдeлю Кoмy интepeсно, пишитe "+" в личные', static::SPAM)
->learn('Всeх привeтствую. Нyжны пaртнёры для удалённoгo сoтрудничeства. Пoдробнoсти в лс', static::SPAM)

/**
* Hamming
*/
->learn('а учусь я потому что хочу работу нормальную найти и чтоб дети жили нормально)', static::HAM)
->learn('у тебя переменная передается не так надо массив ->asyncParameters()', static::HAM)
->learn('MVC. Можно ещё там использовать сервис контейнеры, фасады, view-model', static::HAM)
->learn('Попробуем, спасибо 🙏', static::HAM)
->learn('https://laravel.com/docs/', static::HAM)
->learn('Да', static::HAM)
->learn('Получилось', static::HAM);

TelegramMessage::create()
->to(config('services.telegram-bot-api.chat_id'))
->line('*Сообщение было классифицировано как '.$classifier->most($message))
->line('')
->line('*📂 Текст сообщения*')
->escapedLine($message)
->send();

return Str::of($message)->contains([
'yдалённyю',
'в нeдeлю',
'интepeсно',
'пaртнёры',
'сoтрудничeств',
]);
}
}
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@
],
"license": "CC BY-NC-SA 4.0",
"require": {
"php": "^8.3",
"php": "^8.2",
"ext-dom": "*",
"assisted-mindfulness/naive-bayes": "0.0.3",
"cagilo/cagilo": "^3.2",
"doctrine/dbal": "^3.7",
"esplora/spire": "0.0.1",
Expand Down
51 changes: 49 additions & 2 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions routes/api.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php

use App\Http\Controllers\WebHookController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Expand All @@ -17,3 +18,5 @@
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});

Route::post('/webhook/telegram', [WebHookController::class, 'telegram'])->name('webhook.telegram');

0 comments on commit 8dfbbb6

Please sign in to comment.