Centralize Telegram Bot API URL/token construction in a TelegramApi helper

This commit is contained in:
Paulo Castellano 2026-06-14 12:41:19 -03:00
parent e907ad087f
commit b6a3cb886c
7 changed files with 85 additions and 23 deletions

View file

@ -10,6 +10,7 @@
use App\Features\SocialAccountLimit;
use App\Models\SocialAccount;
use App\Models\Workspace;
use App\Services\Social\TelegramApi;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Laravel\Pennant\Feature;
@ -79,27 +80,24 @@ public static function execute(Workspace $workspace, array $chat, string $nonce)
*/
private static function fetchChannelAvatar(string $chatId): ?string
{
$token = (string) config('trypost.platforms.telegram.bot_token');
$api = rtrim((string) config('trypost.platforms.telegram.api'), '/');
if ($token === '') {
if (TelegramApi::token() === '') {
return null;
}
try {
$fileId = data_get(Http::get("{$api}/bot{$token}/getChat", ['chat_id' => $chatId])->json(), 'result.photo.big_file_id');
$fileId = data_get(Http::get(TelegramApi::endpoint('getChat'), ['chat_id' => $chatId])->json(), 'result.photo.big_file_id');
if (! is_string($fileId)) {
return null;
}
$filePath = data_get(Http::get("{$api}/bot{$token}/getFile", ['file_id' => $fileId])->json(), 'result.file_path');
$filePath = data_get(Http::get(TelegramApi::endpoint('getFile'), ['file_id' => $fileId])->json(), 'result.file_path');
if (! is_string($filePath)) {
return null;
}
return uploadFromUrl("{$api}/file/bot{$token}/{$filePath}");
return uploadFromUrl(TelegramApi::fileUrl($filePath));
} catch (Throwable) {
return null;
}

View file

@ -4,6 +4,7 @@
namespace App\Actions\SocialAccount;
use App\Services\Social\TelegramApi;
use Illuminate\Support\Facades\Http;
use InvalidArgumentException;
use RuntimeException;
@ -20,17 +21,15 @@ class RegisterTelegramWebhook
*/
public static function execute(): string
{
$token = (string) config('trypost.platforms.telegram.bot_token');
$api = rtrim((string) config('trypost.platforms.telegram.api'), '/');
$secret = (string) config('trypost.platforms.telegram.webhook_secret');
if ($token === '' || $secret === '') {
if (TelegramApi::token() === '' || $secret === '') {
throw new InvalidArgumentException('TELEGRAM_BOT_TOKEN and TELEGRAM_WEBHOOK_SECRET must both be set.');
}
$url = route('telegram.webhook');
$response = Http::post("{$api}/bot{$token}/setWebhook", [
$response = Http::post(TelegramApi::endpoint('setWebhook'), [
'url' => $url,
'secret_token' => $secret,
'allowed_updates' => ['message', 'channel_post', 'message_reaction_count'],

View file

@ -507,11 +507,8 @@ private function verifyBluesky(SocialAccount $account): bool
private function verifyTelegram(SocialAccount $account): bool
{
$token = (string) config('trypost.platforms.telegram.bot_token');
$api = rtrim((string) config('trypost.platforms.telegram.api'), '/');
// getChat succeeds only while the bot can still reach the chat.
$response = Http::get("{$api}/bot{$token}/getChat", [
$response = Http::get(TelegramApi::endpoint('getChat'), [
'chat_id' => data_get($account->meta, 'chat_id'),
]);

View file

@ -18,17 +18,15 @@ class TelegramAnalytics
*/
public function getMetrics(SocialAccount $account): array
{
$token = (string) config('trypost.platforms.telegram.bot_token');
$api = rtrim((string) config('trypost.platforms.telegram.api'), '/');
$chatId = data_get($account->meta, 'chat_id');
if ($token === '' || $chatId === null) {
if (TelegramApi::token() === '' || $chatId === null) {
return [];
}
try {
$count = data_get(
Http::get("{$api}/bot{$token}/getChatMemberCount", ['chat_id' => $chatId])->json(),
Http::get(TelegramApi::endpoint('getChatMemberCount'), ['chat_id' => $chatId])->json(),
'result',
);
} catch (Throwable) {

View file

@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace App\Services\Social;
/**
* Builds Telegram Bot API URLs from the configured token + host, so the
* `bot<token>/<method>` shape and config keys live in one place.
*/
class TelegramApi
{
public static function token(): string
{
return (string) config('trypost.platforms.telegram.bot_token');
}
/**
* Endpoint for a Bot API method, e.g. `https://api.telegram.org/bot<token>/sendMessage`.
*/
public static function endpoint(string $method): string
{
$base = self::baseUrl();
$token = self::token();
return "{$base}/bot{$token}/{$method}";
}
/**
* Download URL for a file path returned by `getFile`.
*/
public static function fileUrl(string $path): string
{
$base = self::baseUrl();
$token = self::token();
return "{$base}/file/bot{$token}/{$path}";
}
private static function baseUrl(): string
{
return rtrim((string) config('trypost.platforms.telegram.api'), '/');
}
}

View file

@ -141,10 +141,7 @@ private function telegramMedia(MediaItem $media): array
private function call(string $method, array $payload): Response
{
$token = (string) config('trypost.platforms.telegram.bot_token');
$api = rtrim((string) config('trypost.platforms.telegram.api'), '/');
$response = $this->socialHttp()->post("{$api}/bot{$token}/{$method}", $payload);
$response = $this->socialHttp()->post(TelegramApi::endpoint($method), $payload);
if ($response->failed() || data_get($response->json(), 'ok') !== true) {
$this->handleApiError($response);

View file

@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
use App\Services\Social\TelegramApi;
beforeEach(function () {
config([
'trypost.platforms.telegram.bot_token' => 'TESTTOKEN',
'trypost.platforms.telegram.api' => 'https://api.telegram.org',
]);
});
it('builds a method endpoint from the token and host', function () {
expect(TelegramApi::endpoint('sendMessage'))
->toBe('https://api.telegram.org/botTESTTOKEN/sendMessage');
});
it('builds a file download url', function () {
expect(TelegramApi::fileUrl('photos/file_1.jpg'))
->toBe('https://api.telegram.org/file/botTESTTOKEN/photos/file_1.jpg');
});
it('trims a trailing slash from the configured host', function () {
config(['trypost.platforms.telegram.api' => 'https://api.telegram.org/']);
expect(TelegramApi::endpoint('getChat'))
->toBe('https://api.telegram.org/botTESTTOKEN/getChat');
});