opnform-host-nginx/api/app/Integrations/Handlers/TelegramIntegration.php

170 lines
6.2 KiB
PHP

<?php
namespace App\Integrations\Handlers;
use App\Models\Forms\Form;
use App\Open\MentionParser;
use App\Service\Forms\FormSubmissionFormatter;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Arr;
use Vinkla\Hashids\Facades\Hashids;
class TelegramIntegration extends AbstractIntegrationHandler
{
protected const TELEGRAM_API_BASE = 'https://api.telegram.org/bot';
public static function getValidationRules(?Form $form): array
{
return [
'include_submission_data' => 'boolean',
'include_hidden_fields_submission_data' => ['nullable', 'boolean'],
'link_open_form' => 'boolean',
'link_edit_form' => 'boolean',
'views_submissions_count' => 'boolean',
'link_edit_submission' => 'boolean'
];
}
protected function getChatId(): ?string
{
return $this->provider?->provider_user_id;
}
protected function getWebhookUrl(): ?string
{
$token = config('services.telegram.bot_token');
if (!$token) {
return null;
}
return self::TELEGRAM_API_BASE . $token . '/sendMessage';
}
protected function shouldRun(): bool
{
$hasValidProvider = $this->formIntegration->oauth_id && $this->provider;
$shouldRun = !is_null($this->getWebhookUrl()) && $hasValidProvider && $this->form->is_pro && parent::shouldRun();
return $shouldRun;
}
protected function getWebhookData(): array
{
$settings = (array) $this->integrationData ?? [];
$messageParts = [];
$formatter = (new FormSubmissionFormatter($this->form, $this->submissionData))->outputStringsOnly();
if (Arr::get($settings, 'include_hidden_fields_submission_data', false)) {
$formatter->showHiddenFields();
}
$formattedData = $formatter->getFieldsWithValue();
$mentionMessage = Arr::get($settings, 'message', 'New form submission');
$parsedMentionMessage = (new MentionParser($mentionMessage, $formattedData))->parse();
$messageParts[] = $this->escapeMarkdownV2($parsedMentionMessage);
if (Arr::get($settings, 'include_submission_data', true)) {
$messageParts[] = "\n\n📝 *Submission Details:*";
foreach ($formattedData as $field) {
$fieldName = ucfirst($field['name']);
$fieldValue = is_array($field['value']) ? implode(', ', $field['value']) : $field['value'];
$messageParts[] = "*" . $this->escapeMarkdownV2($fieldName) . "*: " . $this->escapeMarkdownV2($fieldValue ?? '');
}
}
if (Arr::get($settings, 'views_submissions_count', true)) {
$messageParts[] = "\n📊 *Form Statistics:*";
$messageParts[] = "👀 *Views*: " . (string) $this->form->views_count;
$messageParts[] = "🖊️ *Submissions*: " . (string) $this->form->submissions_count;
}
$links = [];
if (Arr::get($settings, 'link_open_form', true)) {
$url = $this->escapeMarkdownV2($this->form->share_url);
$links[] = "[🔗 Open Form](" . $url . ")";
}
if (Arr::get($settings, 'link_edit_form', true)) {
$url = $this->escapeMarkdownV2(front_url('forms/' . $this->form->slug . '/show'));
$links[] = "[✍️ Edit Form](" . $url . ")";
}
if (Arr::get($settings, 'link_edit_submission', true) && $this->form->editable_submissions) {
$submissionId = Hashids::encode($this->submissionData['submission_id']);
$buttonText = $this->escapeMarkdownV2($this->form->editable_submissions_button_text);
$url = $this->escapeMarkdownV2($this->form->share_url . "?submission_id=" . $submissionId);
$links[] = "[✍️ " . $buttonText . "](" . $url . ")";
}
if (count($links) > 0) {
$messageParts[] = "\n" . implode("\n", $links);
}
$finalMessageText = implode("\n", $messageParts);
$payload = [
'chat_id' => $this->getChatId(),
'text' => $finalMessageText,
'parse_mode' => 'MarkdownV2'
];
return $payload;
}
/**
* Escape special characters for Telegram MarkdownV2 format
* @see https://core.telegram.org/bots/api#markdownv2-style
*/
protected function escapeMarkdownV2(string $text): string
{
$specialChars = ['_', '*', '[', ']', '(', ')', '~', '`', '>', '#', '+', '-', '=', '|', '{', '}', '.', '!'];
$text = str_replace('\\', '\\\\', $text);
return str_replace($specialChars, array_map(fn ($char) => '\\' . $char, $specialChars), $text);
}
public static function isOAuthRequired(): bool
{
return true;
}
public function handle(): void
{
if (!$this->shouldRun()) {
return;
}
$url = $this->getWebhookUrl();
if (!$url) {
logger()->error('TelegramIntegration failed: Missing bot token.', [
'form_id' => $this->form?->id,
'integration_id' => $this->formIntegration?->id,
]);
return;
}
$data = $this->getWebhookData();
if (empty($data['chat_id'])) {
logger()->error('TelegramIntegration failed: Missing chat_id.', [
'form_id' => $this->form?->id,
'integration_id' => $this->formIntegration?->id,
'provider_id' => $this->provider?->id
]);
return;
}
try {
$response = Http::post($url, $data);
if ($response->failed()) {
logger()->warning('TelegramIntegration request failed', [
'form_id' => $this->form->id,
'integration_id' => $this->formIntegration->id,
'status' => $response->status(),
'response' => $response->json() ?? $response->body()
]);
}
} catch (\Exception $e) {
logger()->error('TelegramIntegration failed during API call', [
'form_id' => $this->form->id,
'integration_id' => $this->formIntegration->id,
'message' => $e->getMessage(),
'exception' => $e
]);
}
}
}