Add Telegram connection flow (controller + webhook)
Connect a channel by issuing a one-time code the user posts as /connect <code>
in their channel. A secret-token-guarded webhook matches the code, links the
channel as a SocialAccount (chat_id in meta), and records it on the request so
the connect endpoint can poll for completion. Adds the TelegramConnectRequest
model + migration, the connect/status endpoints, the public webhook route (CSRF
exempt), a ConnectionVerifier branch (getChat liveness), and a telegram:set-webhook
command. Tests cover the code issue, webhook link, secret rejection, expired/
unknown codes, status polling, and the command.
2026-06-14 00:39:03 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace App\Http\Controllers\Webhooks;
|
|
|
|
|
|
2026-06-14 13:18:44 +00:00
|
|
|
use App\Actions\SocialAccount\ConnectTelegramChannel;
|
2026-06-14 14:18:40 +00:00
|
|
|
use App\Actions\SocialAccount\StoreTelegramReactions;
|
Add Telegram connection flow (controller + webhook)
Connect a channel by issuing a one-time code the user posts as /connect <code>
in their channel. A secret-token-guarded webhook matches the code, links the
channel as a SocialAccount (chat_id in meta), and records it on the request so
the connect endpoint can poll for completion. Adds the TelegramConnectRequest
model + migration, the connect/status endpoints, the public webhook route (CSRF
exempt), a ConnectionVerifier branch (getChat liveness), and a telegram:set-webhook
command. Tests cover the code issue, webhook link, secret rejection, expired/
unknown codes, status polling, and the command.
2026-06-14 00:39:03 +00:00
|
|
|
use App\Http\Controllers\Controller;
|
2026-06-14 01:48:21 +00:00
|
|
|
use App\Models\Workspace;
|
2026-06-14 16:32:03 +00:00
|
|
|
use App\Services\Social\Telegram\TelegramConnectCode;
|
Add Telegram connection flow (controller + webhook)
Connect a channel by issuing a one-time code the user posts as /connect <code>
in their channel. A secret-token-guarded webhook matches the code, links the
channel as a SocialAccount (chat_id in meta), and records it on the request so
the connect endpoint can poll for completion. Adds the TelegramConnectRequest
model + migration, the connect/status endpoints, the public webhook route (CSRF
exempt), a ConnectionVerifier branch (getChat liveness), and a telegram:set-webhook
command. Tests cover the code issue, webhook link, secret rejection, expired/
unknown codes, status polling, and the command.
2026-06-14 00:39:03 +00:00
|
|
|
use Illuminate\Http\Request;
|
|
|
|
|
use Illuminate\Http\Response;
|
|
|
|
|
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
|
|
|
|
|
|
|
|
|
|
class TelegramWebhookController extends Controller
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* Receives Bot API updates. The only update we act on is a `/connect <code>`
|
2026-06-14 11:57:38 +00:00
|
|
|
* message/channel_post: the signed code carries the workspace, so we link the
|
|
|
|
|
* originating channel to it. Everything else is acknowledged and ignored.
|
Add Telegram connection flow (controller + webhook)
Connect a channel by issuing a one-time code the user posts as /connect <code>
in their channel. A secret-token-guarded webhook matches the code, links the
channel as a SocialAccount (chat_id in meta), and records it on the request so
the connect endpoint can poll for completion. Adds the TelegramConnectRequest
model + migration, the connect/status endpoints, the public webhook route (CSRF
exempt), a ConnectionVerifier branch (getChat liveness), and a telegram:set-webhook
command. Tests cover the code issue, webhook link, secret rejection, expired/
unknown codes, status polling, and the command.
2026-06-14 00:39:03 +00:00
|
|
|
*/
|
|
|
|
|
public function handle(Request $request): Response
|
|
|
|
|
{
|
|
|
|
|
$secret = (string) config('trypost.platforms.telegram.webhook_secret');
|
|
|
|
|
|
|
|
|
|
abort_if(
|
|
|
|
|
$secret === '' || ! hash_equals($secret, (string) $request->header('X-Telegram-Bot-Api-Secret-Token')),
|
|
|
|
|
SymfonyResponse::HTTP_FORBIDDEN,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$update = $request->all();
|
2026-06-14 14:18:40 +00:00
|
|
|
|
|
|
|
|
if (is_array($reactionUpdate = data_get($update, 'message_reaction_count'))) {
|
|
|
|
|
StoreTelegramReactions::execute($reactionUpdate);
|
|
|
|
|
|
|
|
|
|
return response()->noContent();
|
|
|
|
|
}
|
|
|
|
|
|
Add Telegram connection flow (controller + webhook)
Connect a channel by issuing a one-time code the user posts as /connect <code>
in their channel. A secret-token-guarded webhook matches the code, links the
channel as a SocialAccount (chat_id in meta), and records it on the request so
the connect endpoint can poll for completion. Adds the TelegramConnectRequest
model + migration, the connect/status endpoints, the public webhook route (CSRF
exempt), a ConnectionVerifier branch (getChat liveness), and a telegram:set-webhook
command. Tests cover the code issue, webhook link, secret rejection, expired/
unknown codes, status polling, and the command.
2026-06-14 00:39:03 +00:00
|
|
|
$chat = data_get($update, 'message.chat') ?? data_get($update, 'channel_post.chat');
|
|
|
|
|
$text = data_get($update, 'message.text') ?? data_get($update, 'channel_post.text');
|
|
|
|
|
|
|
|
|
|
if (! is_array($chat) || ! is_string($text) || ! preg_match('/^\/connect(?:@\S+)?\s+(\S+)/', $text, $matches)) {
|
|
|
|
|
return response()->noContent();
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-14 11:57:38 +00:00
|
|
|
$payload = TelegramConnectCode::decode($matches[1]);
|
|
|
|
|
$workspace = $payload === null ? null : Workspace::find(data_get($payload, 'workspace_id'));
|
Add Telegram connection flow (controller + webhook)
Connect a channel by issuing a one-time code the user posts as /connect <code>
in their channel. A secret-token-guarded webhook matches the code, links the
channel as a SocialAccount (chat_id in meta), and records it on the request so
the connect endpoint can poll for completion. Adds the TelegramConnectRequest
model + migration, the connect/status endpoints, the public webhook route (CSRF
exempt), a ConnectionVerifier branch (getChat liveness), and a telegram:set-webhook
command. Tests cover the code issue, webhook link, secret rejection, expired/
unknown codes, status polling, and the command.
2026-06-14 00:39:03 +00:00
|
|
|
|
2026-06-14 13:18:44 +00:00
|
|
|
if ($workspace !== null) {
|
|
|
|
|
ConnectTelegramChannel::execute($workspace, $chat, data_get($payload, 'nonce'));
|
2026-06-14 12:18:24 +00:00
|
|
|
}
|
|
|
|
|
|
Add Telegram connection flow (controller + webhook)
Connect a channel by issuing a one-time code the user posts as /connect <code>
in their channel. A secret-token-guarded webhook matches the code, links the
channel as a SocialAccount (chat_id in meta), and records it on the request so
the connect endpoint can poll for completion. Adds the TelegramConnectRequest
model + migration, the connect/status endpoints, the public webhook route (CSRF
exempt), a ConnectionVerifier branch (getChat liveness), and a telegram:set-webhook
command. Tests cover the code issue, webhook link, secret rejection, expired/
unknown codes, status polling, and the command.
2026-06-14 00:39:03 +00:00
|
|
|
return response()->noContent();
|
|
|
|
|
}
|
|
|
|
|
}
|