Skip to content

Commit 5ff450d

Browse files
author
root
committed
Support two-way message replies and quotes for Telegram forum topics and webhooks
1 parent e746281 commit 5ff450d

4 files changed

Lines changed: 166 additions & 13 deletions

File tree

bootstrap/bootstrap.php

Lines changed: 120 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,67 @@ private function isMeaningfulTelegramUploadName($file)
441441
return true;
442442
}
443443

444-
private function sendTelegramChatFile($tchat, $fileData, $caption, $disableNotification = false)
444+
public function saveTopicMsgId($msg, $topicMsgId)
445+
{
446+
if (!($msg instanceof erLhcoreClassModelmsg) || !(int)$topicMsgId || $msg->id <= 0) {
447+
return;
448+
}
449+
450+
$meta = is_array($msg->meta_msg_array) ? $msg->meta_msg_array : [];
451+
$meta['tg_topic_msg_id'] = (int)$topicMsgId;
452+
$msg->meta_msg_array = $meta;
453+
$msg->meta_msg = json_encode($meta);
454+
455+
$stmt = ezcDbInstance::get()->prepare("UPDATE lh_msg SET meta_msg = :meta_msg WHERE id = :id");
456+
$stmt->bindValue(':meta_msg', $msg->meta_msg);
457+
$stmt->bindValue(':id', (int)$msg->id, PDO::PARAM_INT);
458+
$stmt->execute();
459+
}
460+
461+
public function getTopicReplyId($msg, $chatId)
462+
{
463+
if (!($msg instanceof erLhcoreClassModelmsg)) {
464+
return null;
465+
}
466+
467+
$meta = $msg->meta_msg_array;
468+
469+
if (isset($meta['content']['reply_to']['db_msg_id']) && (int)$meta['content']['reply_to']['db_msg_id'] > 0) {
470+
$targetMsg = erLhcoreClassModelmsg::fetch((int)$meta['content']['reply_to']['db_msg_id']);
471+
if ($targetMsg instanceof erLhcoreClassModelmsg && isset($targetMsg->meta_msg_array['tg_topic_msg_id']) && (int)$targetMsg->meta_msg_array['tg_topic_msg_id'] > 0) {
472+
return (int)$targetMsg->meta_msg_array['tg_topic_msg_id'];
473+
}
474+
}
475+
476+
if (isset($meta['content']['reply_to']['iwh_msg_id']) && $meta['content']['reply_to']['iwh_msg_id'] != '') {
477+
$iwhId = (string)$meta['content']['reply_to']['iwh_msg_id'];
478+
$targetMsg = erLhcoreClassModelmsg::findOne([
479+
'filter' => ['chat_id' => $chatId],
480+
'customfilter' => ['`meta_msg` != \'\' AND JSON_VALID(`meta_msg`) AND (JSON_UNQUOTE(JSON_EXTRACT(meta_msg,\'$.iwh_msg_id\')) = ' . ezcDbInstance::get()->quote($iwhId) . ' OR JSON_EXTRACT(meta_msg,\'$.iwh_msg_id\') = ' . (is_numeric($iwhId) ? (int)$iwhId : ezcDbInstance::get()->quote($iwhId)) . ')']
481+
]);
482+
if ($targetMsg instanceof erLhcoreClassModelmsg && isset($targetMsg->meta_msg_array['tg_topic_msg_id']) && (int)$targetMsg->meta_msg_array['tg_topic_msg_id'] > 0) {
483+
return (int)$targetMsg->meta_msg_array['tg_topic_msg_id'];
484+
}
485+
}
486+
487+
if (isset($meta['content']['quote']['id']) && (int)$meta['content']['quote']['id'] > 0) {
488+
$targetMsg = erLhcoreClassModelmsg::fetch((int)$meta['content']['quote']['id']);
489+
if ($targetMsg instanceof erLhcoreClassModelmsg && isset($targetMsg->meta_msg_array['tg_topic_msg_id']) && (int)$targetMsg->meta_msg_array['tg_topic_msg_id'] > 0) {
490+
return (int)$targetMsg->meta_msg_array['tg_topic_msg_id'];
491+
}
492+
}
493+
494+
if (preg_match('#\[quote="?([0-9]+)"?\]#is', (string)$msg->msg, $m)) {
495+
$targetMsg = erLhcoreClassModelmsg::fetch((int)$m[1]);
496+
if ($targetMsg instanceof erLhcoreClassModelmsg && isset($targetMsg->meta_msg_array['tg_topic_msg_id']) && (int)$targetMsg->meta_msg_array['tg_topic_msg_id'] > 0) {
497+
return (int)$targetMsg->meta_msg_array['tg_topic_msg_id'];
498+
}
499+
}
500+
501+
return null;
502+
}
503+
504+
private function sendTelegramChatFile($tchat, $fileData, $caption, $disableNotification = false, $params = array())
445505
{
446506
$file = $fileData['file'];
447507

@@ -475,6 +535,10 @@ private function sendTelegramChatFile($tchat, $fileData, $caption, $disableNotif
475535
$field => $this->getTelegramChatFileUrl($file)
476536
);
477537

538+
if (isset($params['reply_to_message_id']) && $params['reply_to_message_id'] > 0) {
539+
$data['reply_to_message_id'] = $params['reply_to_message_id'];
540+
}
541+
478542
if ($caption !== '') {
479543
$data['caption'] = $caption;
480544
}
@@ -515,7 +579,7 @@ private function sendTelegramChatFile($tchat, $fileData, $caption, $disableNotif
515579
return false;
516580
}
517581

518-
return true;
582+
return $sendData->getResult()->getMessageId();
519583
}
520584

521585
private function getTelegramChatFileUrl($file)
@@ -580,8 +644,17 @@ public function messageAdded($params)
580644
$data['disable_notification'] = true;
581645
}
582646

647+
$replyTopicMsgId = $this->getTopicReplyId($params['msg'], $chat->id);
648+
if ($replyTopicMsgId > 0) {
649+
$data['reply_to_message_id'] = $replyTopicMsgId;
650+
}
651+
583652
$sendData = Longman\TelegramBot\Request::sendMessage($data);
584653

654+
if ($sendData->isOk()) {
655+
$this->saveTopicMsgId($params['msg'], $sendData->getResult()->getMessageId());
656+
}
657+
585658
if (!$sendData->isOk() && $sendData->getErrorCode() == 400 && str_contains( $sendData->getDescription(), 'TOPIC_DELETED') === true) {
586659
// Reset telegram chat
587660
$tchat->tchat_id = 0;
@@ -610,9 +683,13 @@ public function messageAdded($params)
610683
$failedEmbedCodes = array();
611684
$fileIndex = 0;
612685

686+
$replyTopicMsgId = $this->getTopicReplyId($params['msg'], $chat->id);
613687
foreach ($telegramFiles as $telegramFile) {
614-
if ($this->sendTelegramChatFile($tchat, $telegramFile, $this->getTelegramFileCaption($params['msg'], $chat, $telegramFile['file'], $fileIndex === 0 ? $messageText : ''), $chat->status == erLhcoreClassModelChat::STATUS_BOT_CHAT) === false) {
688+
$sentFileMsgId = $this->sendTelegramChatFile($tchat, $telegramFile, $this->getTelegramFileCaption($params['msg'], $chat, $telegramFile['file'], $fileIndex === 0 ? $messageText : ''), $chat->status == erLhcoreClassModelChat::STATUS_BOT_CHAT, ['reply_to_message_id' => $replyTopicMsgId]);
689+
if ($sentFileMsgId === false) {
615690
$failedEmbedCodes[] = $telegramFile['embed'];
691+
} else {
692+
$this->saveTopicMsgId($params['msg'], $sentFileMsgId);
616693
}
617694
$fileIndex++;
618695
}
@@ -671,7 +748,9 @@ public function messageAdded($params)
671748
}
672749
$sendData = Longman\TelegramBot\Request::sendMessage($data);
673750

674-
if (!$sendData->isOk()) {
751+
if ($sendData->isOk()) {
752+
$this->saveTopicMsgId($botMessage, $sendData->getResult()->getMessageId());
753+
} else {
675754
erLhcoreClassLog::write('SendMessage BOT ['.$sendData->getErrorCode().']'. $sendData->getDescription(),
676755
ezcLog::SUCCESS_AUDIT,
677756
array(
@@ -690,8 +769,11 @@ public function messageAdded($params)
690769
$fileIndex = 0;
691770

692771
foreach ($telegramFiles as $telegramFile) {
693-
if ($this->sendTelegramChatFile($tchat, $telegramFile, $this->getTelegramFileCaption($botMessage, $chat, $telegramFile['file'], $fileIndex === 0 ? $messageText : ''), $chat->status == erLhcoreClassModelChat::STATUS_BOT_CHAT) === false) {
772+
$sentFileMsgId = $this->sendTelegramChatFile($tchat, $telegramFile, $this->getTelegramFileCaption($botMessage, $chat, $telegramFile['file'], $fileIndex === 0 ? $messageText : ''), $chat->status == erLhcoreClassModelChat::STATUS_BOT_CHAT);
773+
if ($sentFileMsgId === false) {
694774
$failedEmbedCodes[] = $telegramFile['embed'];
775+
} else {
776+
$this->saveTopicMsgId($botMessage, $sentFileMsgId);
695777
}
696778
$fileIndex++;
697779
}
@@ -767,7 +849,9 @@ public function triggerClicked($params)
767849
}
768850
$sendData = Longman\TelegramBot\Request::sendMessage($data);
769851

770-
if (!$sendData->isOk()) {
852+
if ($sendData->isOk()) {
853+
$this->saveTopicMsgId($botMessage, $sendData->getResult()->getMessageId());
854+
} else {
771855
erLhcoreClassLog::write('['.$sendData->getErrorCode().']'. $sendData->getDescription(),
772856
ezcLog::SUCCESS_AUDIT,
773857
array(
@@ -786,8 +870,11 @@ public function triggerClicked($params)
786870
$fileIndex = 0;
787871

788872
foreach ($telegramFiles as $telegramFile) {
789-
if ($this->sendTelegramChatFile($tchat, $telegramFile, $this->getTelegramFileCaption($botMessage, $chat, $telegramFile['file'], $fileIndex === 0 ? $messageText : ''), $chat->status == erLhcoreClassModelChat::STATUS_BOT_CHAT) === false) {
873+
$sentFileMsgId = $this->sendTelegramChatFile($tchat, $telegramFile, $this->getTelegramFileCaption($botMessage, $chat, $telegramFile['file'], $fileIndex === 0 ? $messageText : ''), $chat->status == erLhcoreClassModelChat::STATUS_BOT_CHAT);
874+
if ($sentFileMsgId === false) {
790875
$failedEmbedCodes[] = $telegramFile['embed'];
876+
} else {
877+
$this->saveTopicMsgId($botMessage, $sentFileMsgId);
791878
}
792879
$fileIndex++;
793880
}
@@ -926,7 +1013,17 @@ public function chatStarted($params)
9261013

9271014
$sendData = Longman\TelegramBot\Request::sendMessage($data);
9281015

929-
if (!$sendData->isOk()) {
1016+
if ($sendData->isOk()) {
1017+
$firstVisitorMsg = erLhcoreClassModelmsg::findOne(['filter' => ['chat_id' => $params['chat']->id, 'user_id' => 0], 'sort' => 'id ASC']);
1018+
if ($firstVisitorMsg instanceof erLhcoreClassModelmsg) {
1019+
$this->saveTopicMsgId($firstVisitorMsg, $sendData->getResult()->getMessageId());
1020+
} else {
1021+
$firstMsg = erLhcoreClassModelmsg::findOne(['filter' => ['chat_id' => $params['chat']->id], 'sort' => 'id ASC']);
1022+
if ($firstMsg instanceof erLhcoreClassModelmsg) {
1023+
$this->saveTopicMsgId($firstMsg, $sendData->getResult()->getMessageId());
1024+
}
1025+
}
1026+
} else {
9301027

9311028
// Try first time to create a topic if old one is gone
9321029
if ($sendData->getErrorCode() == 400 && (str_contains($sendData->getDescription(), 'message thread not found') || str_contains($sendData->getDescription(), 'TOPIC_DELETED'))) {
@@ -946,7 +1043,17 @@ public function chatStarted($params)
9461043
$data['message_thread_id'] = $tChat->tchat_id;
9471044
$sendData = Longman\TelegramBot\Request::sendMessage($data);
9481045

949-
if (!$sendData->isOk()) {
1046+
if ($sendData->isOk()) {
1047+
$firstVisitorMsg = erLhcoreClassModelmsg::findOne(['filter' => ['chat_id' => $params['chat']->id, 'user_id' => 0], 'sort' => 'id ASC']);
1048+
if ($firstVisitorMsg instanceof erLhcoreClassModelmsg) {
1049+
$this->saveTopicMsgId($firstVisitorMsg, $sendData->getResult()->getMessageId());
1050+
} else {
1051+
$firstMsg = erLhcoreClassModelmsg::findOne(['filter' => ['chat_id' => $params['chat']->id], 'sort' => 'id ASC']);
1052+
if ($firstMsg instanceof erLhcoreClassModelmsg) {
1053+
$this->saveTopicMsgId($firstMsg, $sendData->getResult()->getMessageId());
1054+
}
1055+
}
1056+
} else {
9501057
erLhcoreClassLog::write('['.$sendData->getErrorCode().']'. $sendData->getDescription(),
9511058
ezcLog::SUCCESS_AUDIT,
9521059
array(
@@ -964,8 +1071,11 @@ public function chatStarted($params)
9641071
$failedEmbedCodes = array();
9651072

9661073
foreach ($initialTelegramFiles as $initialTelegramFile) {
967-
if ($this->sendTelegramChatFile($tChat, $initialTelegramFile['file'], $this->getTelegramFileCaption($initialTelegramFile['msg'], $params['chat'], $initialTelegramFile['file']['file'], $initialTelegramFile['text']), $params['chat']->status == erLhcoreClassModelChat::STATUS_BOT_CHAT) === false) {
1074+
$sentFileMsgId = $this->sendTelegramChatFile($tChat, $initialTelegramFile['file'], $this->getTelegramFileCaption($initialTelegramFile['msg'], $params['chat'], $initialTelegramFile['file']['file'], $initialTelegramFile['text']), $params['chat']->status == erLhcoreClassModelChat::STATUS_BOT_CHAT);
1075+
if ($sentFileMsgId === false) {
9681076
$failedEmbedCodes[] = $initialTelegramFile['file']['embed'];
1077+
} else if (isset($initialTelegramFile['msg']) && $initialTelegramFile['msg'] instanceof erLhcoreClassModelmsg) {
1078+
$this->saveTopicMsgId($initialTelegramFile['msg'], $sentFileMsgId);
9691079
}
9701080
}
9711081

classes/Commands/GenericmessageCommand.php

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,50 @@ public function execute(): ServerResponse
341341

342342
if ($ignoreMessage == false) {
343343
$msg = new \erLhcoreClassModelmsg();
344-
$msg->msg = $text;
344+
$msgText = $text;
345+
$metaMsg = [];
346+
347+
$replyTo = $message->getReplyToMessage();
348+
$isExplicitReply = ($replyTo && (int)$replyTo->getMessageId() !== (int)$message->getMessageThreadId() && !$replyTo->getForumTopicCreated());
349+
350+
if ($isExplicitReply) {
351+
$replyTopicMsgId = (int)$replyTo->getMessageId();
352+
$metaMsg['tg_topic_msg_id'] = (int)$message->getMessageId();
353+
354+
$replyMsg = \erLhcoreClassModelmsg::findOne([
355+
'filter' => ['chat_id' => $chat->id],
356+
'customfilter' => ['`meta_msg` != \'\' AND JSON_VALID(`meta_msg`) AND JSON_EXTRACT(meta_msg, \'$.tg_topic_msg_id\') = ' . $replyTopicMsgId]
357+
]);
358+
359+
if ($replyMsg instanceof \erLhcoreClassModelmsg) {
360+
$quoteText = $message->getQuote() ? trim($message->getQuote()->getText()) : $replyMsg->msg;
361+
$replyNick = $replyMsg->name_support != '' ? $replyMsg->name_support : $chat->nick;
362+
$msgText = '[quote=' . $replyMsg->id . ']' . $quoteText . '[/quote]' . $msgText;
363+
364+
$metaMsg['content'] = [
365+
'quote' => [
366+
'id' => $replyMsg->id,
367+
'text' => $quoteText,
368+
'nick' => $replyNick
369+
],
370+
'reply_to' => [
371+
'db_msg_id' => $replyMsg->id
372+
]
373+
];
374+
375+
if (isset($replyMsg->meta_msg_array['iwh_msg_id']) && $replyMsg->meta_msg_array['iwh_msg_id'] != '') {
376+
$metaMsg['content']['reply_to']['iwh_msg_id'] = $replyMsg->meta_msg_array['iwh_msg_id'];
377+
}
378+
}
379+
} else {
380+
$metaMsg['tg_topic_msg_id'] = (int)$message->getMessageId();
381+
}
382+
383+
$msg->msg = $msgText;
384+
if (!empty($metaMsg)) {
385+
$msg->meta_msg = json_encode($metaMsg);
386+
$msg->meta_msg_array = $metaMsg;
387+
}
345388
$msg->chat_id = $chat->id;
346389
$msg->user_id = $messageUserId;
347390
$msg->time = time();

0 commit comments

Comments
 (0)