3namespace Bitrix\Im\V2\Message\Send;
5use Bitrix\Im\V2\Bot\BotService;
6use Bitrix\Im\V2\Entity\User\User;
7use Bitrix\Im\V2\Message\Param\ParamError;
8use Bitrix\Im\V2\MessageCollection;
9use Bitrix\Main\Localization\Loc;
10use Bitrix\Im\Message\Uuid;
11use Bitrix\Im\V2\Message;
12use Bitrix\Im\V2\Result;
14use Bitrix\Im\V2\Chat\ChatError;
15use Bitrix\Im\V2\Message\MessageError;
16use Bitrix\Im\V2\Common\ContextCustomer;
17use CIMMessageParamAttach;
40 if ($sendingConfig ===
null)
44 $this->sendingConfig = $sendingConfig;
49 return $this->sendingConfig;
68 $alreadyExists = !$this->uuidService->add();
74 $messageIdByUuid = $this->uuidService->getMessageId();
76 if (!is_null($messageIdByUuid))
78 return $result->setResult([
'messageId' => $messageIdByUuid]);
83 if (!$this->uuidService->updateIfExpired())
102 if (isset($this->uuidService))
104 $this->uuidService->updateMessageId(
$message->getMessageId());
130 if ($eventResult ===
false || (isset($eventResult[
'result']) && $eventResult[
'result'] ===
false))
132 $reason = $this->detectReasonSendError($chat->
getType(), $eventResult[
'reason'] ??
'');
136 if (isset($eventResult[
'fields']) && is_array($eventResult[
'fields']))
139 $eventResult[
'fields'][
'MESSAGE_ID'],
140 $eventResult[
'fields'][
'CHAT_ID'],
141 $eventResult[
'fields'][
'AUTHOR_ID'],
142 $eventResult[
'fields'][
'FROM_USER_ID']
144 $message->fill($eventResult[
'fields']);
145 $this->sendingConfig->fill($eventResult[
'fields']);
164 $compatibleFields = array_merge(
167 $this->sendingConfig->toArray(),
175 (
new BotService($this->sendingConfig))->setContext($this->context)->runMessageCommand(
$message->getId(), $compatibleFields);
182 if (!$this->sendingConfig->isSkipFireEventBeforeMessageNotifySend())
212 $compatibleFields = array_merge(
214 $this->sendingConfig->toArray(),
216 $compatibleFieldsCopy = $compatibleFields;
218 foreach (\
GetModuleEvents(
'im', self::EVENT_BEFORE_NOTIFY_ADD,
true) as $arEvent)
221 if ($eventResult ===
false || (isset($eventResult[
'result']) && $eventResult[
'result'] ===
false))
223 $reason = $this->detectReasonSendError($chat->
getType(), $eventResult[
'reason'] ??
'');
226 if ($compatibleFields !== $compatibleFieldsCopy)
229 $this->sendingConfig->fillByLegacy($compatibleFields);
248 $compatibleFields = array_merge(
251 $this->sendingConfig->toArray(),
265 'MESSAGE' =>
$message->getMessage(),
266 'TEMPLATE_ID' =>
$message->getUuid(),
267 'MESSAGE_TYPE' =>
$message->getChat()->getType(),
268 'FROM_USER_ID' =>
$message->getAuthorId(),
269 'DIALOG_ID' =>
$message->getChat()->getDialogId(),
270 'TO_CHAT_ID' =>
$message->getChatId(),
271 'MESSAGE_OUT' =>
$message->getMessageOut() ??
'',
272 'PARAMS' =>
$message->getEnrichedParams()->toArray(),
273 'EXTRA_PARAMS' =>
$message->getPushParams() ?? [],
274 'NOTIFY_MODULE' =>
$message->getNotifyModule(),
275 'NOTIFY_EVENT' =>
$message->getNotifyEvent(),
276 'URL_ATTACH' =>
$message->getUrl()?->getUrlAttach()?->GetArray() ?? [],
277 'AUTHOR_ID' =>
$message->getAuthorId(),
278 'SYSTEM' =>
$message->isSystem() ?
'Y' :
'N',
289 foreach (
$message->getFiles() as $file)
291 $res[
'FILES'][$file->getId()] = $file->toRestFormat();
297 $res[
'TO_USER_ID'] =
$message->getChat()->getDialogId();
300 $res = array_merge(
$res, $this->sendingConfig->toArray());
312 $authorRelation = $chat->getRelationByUserId(
$message->getAuthorId());
315 'CHAT_ID' => $chat->getId(),
316 'CHAT_PARENT_ID' => $chat->getParentChatId() ?? 0,
317 'CHAT_PARENT_MID' => $chat->getParentMessageId() ?? 0,
318 'CHAT_TITLE' => $chat->getTitle() ??
'',
319 'CHAT_AUTHOR_ID' => $chat->getAuthorId(),
320 'CHAT_TYPE' => $chat->getType(),
321 'CHAT_AVATAR' => $chat->getAvatarId(),
322 'CHAT_COLOR' => $chat->getColor(),
323 'CHAT_ENTITY_TYPE' => $chat->getEntityType(),
324 'CHAT_ENTITY_ID' => $chat->getEntityId(),
325 'CHAT_ENTITY_DATA_1' => $chat->getEntityData1(),
326 'CHAT_ENTITY_DATA_2' => $chat->getEntityData2(),
327 'CHAT_ENTITY_DATA_3' => $chat->getEntityData3(),
328 'CHAT_EXTRANET' => ($chat->getExtranet() ??
false) ?
'Y' :
'N',
329 'CHAT_PREV_MESSAGE_ID' => $chat->getPrevMessageId() ?? 0,
330 'CHAT_CAN_POST' => $chat->getManageMessages(),
331 'RID' => $authorRelation?->getUserId() ?? 1,
332 'IS_MANAGER' => ($authorRelation?->getManager() ??
false) ?
'Y' :
'N',
337 $res[
'BOT_IN_CHAT'] = $chat->getBotInChat();
343 private function detectReasonSendError(
$type, $reason =
''): string
347 $sanitizer = new \CBXSanitizer;
348 $sanitizer->addTags([
349 'a' => [
'href',
'style',
'target'],
356 $reason = $sanitizer->sanitizeHtml($reason);
360 if (
$type == Chat::IM_TYPE_PRIVATE)
362 $reason = Loc::getMessage(
'IM_ERROR_MESSAGE_CANCELED');
364 else if (
$type == Chat::IM_TYPE_SYSTEM)
366 $reason = Loc::getMessage(
'IM_ERROR_NOTIFY_CANCELED');
370 $reason = Loc::getMessage(
'IM_ERROR_GROUP_CANCELED');
385 if (isset($forwardMessages))
387 if (!isset($fieldsToSend[
'MESSAGE']) && !isset($fieldsToSend[
'ATTACH']))
389 return (
new Result())->setResult([]);
393 $result = $this->checkMessage($fieldsToSend);
398 $fieldsToSend =
$result->getResult();
400 $chatData = $this->getChatData($chat, $fieldsToSend, $server);
401 $fieldsToSend = array_merge($fieldsToSend, $chatData);
403 if (isset($fieldsToSend[
'ATTACH']))
405 $result = $this->checkAttach($fieldsToSend);
411 $fieldsToSend =
$result->getResult();
414 if (!empty($fieldsToSend[
'KEYBOARD']))
416 $result = $this->checkKeyboard($fieldsToSend);
422 $fieldsToSend =
$result->getResult();
425 if (!empty($fieldsToSend[
'MENU']))
427 $result = $this->checkMenu($fieldsToSend);
433 $fieldsToSend =
$result->getResult();
436 if (isset($fieldsToSend[
'REPLY_ID']) && (
int)$fieldsToSend[
'REPLY_ID'] > 0)
438 $result = $this->checkReply($fieldsToSend, $chat);
444 $fieldsToSend =
$result->getResult();
447 $fieldsToSend = $this->checkParams($fieldsToSend, $server);
448 $fieldsToSend = isset($fieldsToSend[
'COPILOT']) ?$this->checkCopilotParams($fieldsToSend) : $fieldsToSend;
450 if (isset($fieldsToSend[
'COPILOT']))
455 return $result->setResult($fieldsToSend);
458 private function checkCopilotParams(
array $fieldsToSend):
array
462 if (isset($fieldsToSend[
'COPILOT']) && is_array($fieldsToSend[
'COPILOT']))
464 foreach ($fieldsToSend[
'COPILOT'] as
$key => $item)
466 if (
$key ===
'promptCode' && is_string($item))
473 $fieldsToSend[
'COPILOT'] = $copilotData;
475 return $fieldsToSend;
478 private function checkMessage(
array $fieldsToSend): Result
481 if(isset($fieldsToSend[
'MESSAGE']))
483 if (!is_string($fieldsToSend[
'MESSAGE']))
488 $fieldsToSend[
'MESSAGE'] = trim($fieldsToSend[
'MESSAGE']);
490 if ($fieldsToSend[
'MESSAGE'] ===
'' && empty($arguments[
'ATTACH']))
492 return $result->addError(
new MessageError(
494 "Message can't be empty"
498 elseif (!isset($fieldsToSend[
'ATTACH']))
503 return $result->setResult($fieldsToSend);
506 private function getChatData(Chat $chat,
array $fieldsToSend, ?\CRestServer $server): ?
array
508 $userId = $chat->getContext()->getUserId();
510 if ($chat->getType() === Chat::IM_TYPE_PRIVATE)
515 "DIALOG_ID" => $chat->getDialogId(),
519 if (isset($fieldsToSend[
'SYSTEM'], $server) && $fieldsToSend[
'SYSTEM'] ===
'Y')
521 $fieldsToSend[
'MESSAGE'] = $this->prepareSystemMessage($server, $fieldsToSend[
'MESSAGE']);
525 'MESSAGE' => $fieldsToSend[
'MESSAGE'],
528 "DIALOG_ID" => $chat->getDialogId(),
532 private function prepareSystemMessage(\CRestServer $server,
string $message): string
541 $result = \Bitrix\Rest\AppTable::getList(
549 'APP_NAME_DEFAULT' =>
'LANG_DEFAULT.MENU_NAME',
554 $moduleName = !empty(
$result[
'APP_NAME'])
556 : (!empty(
$result[
'APP_NAME_DEFAULT'])
562 return "[b]" . $moduleName .
"[/b]\n" .
$message;
565 private function checkAttach(
array $fieldsToSend): Result
572 if ($attach->IsAllowSize())
574 $fieldsToSend[
'ATTACH'] = $attach;
576 return $result->setResult($fieldsToSend);
579 return $result->addError(
new ParamError(
581 'You have exceeded the maximum allowable size of attach'
588 private function checkKeyboard(
array $fieldsToSend): Result
593 $keyboardField = $fieldsToSend[
'KEYBOARD'];
595 if (is_string($keyboardField))
597 $keyboardField = \CUtil::JsObjectToPhp($keyboardField);
599 if (!isset($keyboardField[
'BUTTONS']))
601 $keyboard[
'BUTTONS'] = $keyboardField;
605 $keyboard = $keyboardField;
608 $keyboard[
'BOT_ID'] = $fieldsToSend[
'BOT_ID'];
609 $keyboard = \Bitrix\Im\Bot\Keyboard::getKeyboardByJson($keyboard);
613 $fieldsToSend[
'KEYBOARD'] = $keyboard;
615 return $result->setResult($fieldsToSend);
621 private function checkMenu(
array $fieldsToSend): Result
626 $menuField = $fieldsToSend[
'MENU'];
628 if (is_string($menuField))
630 $menuField = \CUtil::JsObjectToPhp($menuField);
633 if (!isset($menuField[
'ITEMS']))
635 $menu[
'ITEMS'] = $menuField;
642 $menu[
'BOT_ID'] = $fieldsToSend[
'BOT_ID'];
643 $menu = \Bitrix\Im\Bot\ContextMenu::getByJson($menu);
647 $fieldsToSend[
'MENU'] = $menu;
649 return $result->setResult($fieldsToSend);
655 private function checkReply(
array $fieldsToSend, Chat $chat): Result
659 $message = new \Bitrix\Im\V2\Message((
int)$fieldsToSend[
'REPLY_ID']);
660 $messageAccess =
$message->checkAccess();
661 if (!$messageAccess->isSuccess())
663 return $result->addErrors($messageAccess->getErrors());
666 if (
$message->getChat()->getId() !== $chat->getId())
668 return $result->addError(
new MessageError(
670 'You can only reply to a message within the same chat')
674 $fieldsToSend[
'PARAMS'][
'REPLY_ID'] =
$message->getId();
676 return $result->setResult($fieldsToSend);
679 private function checkParams(
array $fieldsToSend, ?\CRestServer $server):
array
681 $checkAuth = isset($server) ? $server->
getAuthType() !== \Bitrix\Rest\SessionAuth\Auth::AUTH_TYPE :
true;
684 isset($fieldsToSend[
'SYSTEM']) && $fieldsToSend[
'SYSTEM'] ===
'Y'
685 && (!$checkAuth || User::getCurrent()->isExtranet())
688 $fieldsToSend[
'SYSTEM'] =
'N';
691 if (isset($fieldsToSend[
'URL_PREVIEW']) && $fieldsToSend[
'URL_PREVIEW'] ===
'N')
693 $fieldsToSend[
'URL_PREVIEW'] =
'N';
696 if (isset($fieldsToSend[
'SKIP_CONNECTOR']) && mb_strtoupper($fieldsToSend[
'SKIP_CONNECTOR']) ===
'Y')
698 $fieldsToSend[
'SKIP_CONNECTOR'] =
'Y';
699 $fieldsToSend[
'SILENT_CONNECTOR'] =
'Y';
702 if (!empty($fieldsToSend[
'TEMPLATE_ID']))
704 $fieldsToSend[
'TEMPLATE_ID'] = mb_substr((
string)$fieldsToSend[
'TEMPLATE_ID'], 0, 255);
707 return $fieldsToSend;
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
static getType($chatData, bool $camelCase=true)
static validate(string $uuid)
const MESSAGE_DUPLICATED_BY_UUID
const COPILOT_PROMPT_CODE
const EVENT_BEFORE_MESSAGE_ADD
const EVENT_AFTER_MESSAGE_ADD
prepareFields(Chat $chat, array $fieldsToSend, ?MessageCollection $forwardMessages, ?\CRestServer $server)
needToCheckDuplicate(Message $message)
const EVENT_AFTER_NOTIFY_ADD
const EVENT_BEFORE_NOTIFY_ADD
getChatForEvent(Message $message, bool $withBot=false)
checkDuplicateByUuid(Message $message)
fireEventAfterMessageSend(Chat $chat, Message $message)
fireEventBeforeSend(Chat $chat, Message $message)
updateMessageUuid(Message $message)
__construct(?SendingConfig $sendingConfig=null)
const EVENT_BEFORE_CHAT_MESSAGE_ADD
fireEventBeforeMessageNotifySend(Chat $chat, Message $message)
fireEventAfterNotifySend(Chat $chat, Message $message)
getMessageForEvent(Message $message, bool $onlyIdFiles=true)
fireEventBeforeMessageSend(Chat $chat, Message $message)
static GetAttachByJson($array)
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
ExecuteModuleEventEx($arEvent, $arParams=[])
GetModuleEvents($MODULE_ID, $MESSAGE_ID, $bReturnArray=false)
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
if(empty($signedUserToken)) $key