27 private const PINNED_CHATS_LIMIT = 25;
29 static private bool $limitError =
false;
31 public static function get($userId =
null, $options = [])
33 $onlyOpenlinesOption = $options[
'ONLY_OPENLINES'] ??
null;
34 $onlyCopilotOption = $options[
'ONLY_COPILOT'] ??
null;
35 $skipOpenlinesOption = $options[
'SKIP_OPENLINES'] ??
null;
36 $skipChat = $options[
'SKIP_CHAT'] ??
null;
37 $skipDialog = $options[
'SKIP_DIALOG'] ??
null;
39 if (isset($options[
'FORCE_OPENLINES']) && $options[
'FORCE_OPENLINES'] ===
'Y')
41 $forceOpenlines =
'Y';
45 $forceOpenlines =
'N';
48 $userId = \Bitrix\Im\Common::getUserId($userId);
55 \Bitrix\Main\Loader::includeModule(
'imopenlines')
56 && ($onlyOpenlinesOption ===
'Y' || $skipOpenlinesOption !==
'Y')
61 && $forceOpenlines !==
'Y'
62 && class_exists(
'\Bitrix\ImOpenLines\Recent')
65 return \Bitrix\ImOpenLines\Recent::getRecent($userId, $options);
68 $generalChatId = \CIMChat::GetGeneralChatId();
70 $ormParams = self::getOrmParams([
72 'SHOW_OPENLINES' => $showOpenlines,
73 'WITHOUT_COMMON_USERS' =>
true,
74 'CHAT_IDS' => $options[
'CHAT_IDS'] ??
null,
77 $lastSyncDateOption = $options[
'LAST_SYNC_DATE'] ??
null;
78 if ($lastSyncDateOption)
80 $maxLimit = (new \Bitrix\Main\Type\DateTime())->add(
'-7 days');
81 if ($maxLimit > $options[
'LAST_SYNC_DATE'])
83 $options[
'LAST_SYNC_DATE'] = $maxLimit;
85 $ormParams[
'filter'][
'>=DATE_UPDATE'] = $options[
'LAST_SYNC_DATE'];
87 else if ($options[
'ONLY_OPENLINES'] !==
'Y')
89 $ormParams[
'filter'][
'>=DATE_UPDATE'] = (new \Bitrix\Main\Type\DateTime())->add(
'-30 days');
93 if ($onlyCopilotOption ===
'Y')
95 $ormParams[
'filter'][] = [
96 '=ITEM_TYPE' => \Bitrix\Im\V2\Chat::IM_TYPE_COPILOT
99 elseif ($onlyOpenlinesOption ===
'Y')
101 $ormParams[
'filter'][] = [
102 '=ITEM_TYPE' => IM_MESSAGE_OPEN_LINE
107 $skipTypes[] = \Bitrix\Im\V2\Chat::IM_TYPE_COPILOT;
108 if ($options[
'SKIP_OPENLINES'] ===
'Y')
110 $skipTypes[] = IM_MESSAGE_OPEN_LINE;
112 if ($skipChat ===
'Y')
114 $skipTypes[] = IM_MESSAGE_OPEN;
115 $skipTypes[] = IM_MESSAGE_CHAT;
117 if ($skipDialog ===
'Y')
119 $skipTypes[] = IM_MESSAGE_PRIVATE;
121 if (!empty($skipTypes))
123 $ormParams[
'filter'][] = [
124 '!@ITEM_TYPE' => $skipTypes
129 if (!isset($options[
'LAST_SYNC_DATE']))
131 if (isset($options[
'OFFSET']))
133 $ormParams[
'offset'] = $options[
'OFFSET'];
135 if (isset($options[
'LIMIT']))
137 $ormParams[
'limit'] = $options[
'LIMIT'];
139 if (isset($options[
'ORDER']))
141 $ormParams[
'order'] = $options[
'ORDER'];
146 $orm = \Bitrix\Im\Model\RecentTable::getList($ormParams);
147 $rows = $orm->fetchAll();
149 foreach ($rows as $row)
151 $isUser = $row[
'ITEM_TYPE'] == IM_MESSAGE_PRIVATE;
152 $id = $isUser? (int)$row[
'ITEM_ID']:
'chat'.$row[
'ITEM_ID'];
156 if (isset($result[$id]) && !$row[
'ITEM_MID'])
161 else if (isset($result[$id]))
166 $item = self::formatRow($row, [
167 'GENERAL_CHAT_ID' => $generalChatId,
168 'GET_ORIGINAL_TEXT' => $options[
'GET_ORIGINAL_TEXT'] ??
null,
175 $result[$id] = $item;
177 $result = array_values($result);
181 && !$options[
'ONLY_OPENLINES']
182 && class_exists(
'\Bitrix\ImOpenLines\Recent')
185 $options[
'ONLY_IN_QUEUE'] =
true;
186 $chatsInQueue = \Bitrix\ImOpenLines\Recent::getRecent($userId, $options);
187 $result = array_merge($result, $chatsInQueue);
190 \Bitrix\Main\Type\Collection::sortByColumn(
192 [
'PINNED' => SORT_DESC,
'MESSAGE' => SORT_DESC,
'ID' => SORT_DESC],
194 'ID' =>
function($row) {
197 'MESSAGE' =>
function($row) {
198 return $row[
'DATE'] instanceof \Bitrix\Main\Type\DateTime ? $row[
'DATE']->getTimeStamp() : 0;
203 if ($options[
'JSON'])
205 foreach ($result as $index => $item)
207 $result[$index] = self::jsonRow($item);
214 public static function getList($userId =
null, $options = [])
216 $userId = \Bitrix\Im\Common::getUserId($userId);
222 $generalChatId = \CIMChat::GetGeneralChatId();
224 $viewCommonUsers = (bool)\CIMSettings::GetSetting(\CIMSettings::SETTINGS,
'viewCommonUsers');
226 $onlyOpenlinesOption = $options[
'ONLY_OPENLINES'] ??
null;
227 $onlyCopilotOption = $options[
'ONLY_COPILOT'] ??
null;
228 $skipChatOption = $options[
'SKIP_CHAT'] ??
null;
229 $skipDialogOption = $options[
'SKIP_DIALOG'] ??
null;
230 $lastMessageDateOption = $options[
'LAST_MESSAGE_DATE'] ??
null;
231 $withoutCommonUsers = !$viewCommonUsers || $onlyOpenlinesOption ===
'Y';
232 $unreadOnly = isset($options[
'UNREAD_ONLY']) && $options[
'UNREAD_ONLY'] ===
'Y';
233 $shortInfo = isset($options[
'SHORT_INFO']) && $options[
'SHORT_INFO'] ===
'Y';
236 \Bitrix\Main\Loader::includeModule(
'imopenlines')
238 $onlyOpenlinesOption ===
'Y'
239 || $options[
'SKIP_OPENLINES'] !==
'Y'
243 $ormParams = self::getOrmParams([
244 'USER_ID' => $userId,
245 'SHOW_OPENLINES' => $showOpenlines,
246 'WITHOUT_COMMON_USERS' => $withoutCommonUsers,
247 'UNREAD_ONLY' => $unreadOnly,
248 'SHORT_INFO' => $shortInfo,
251 if ($onlyCopilotOption ===
'Y')
253 $ormParams[
'filter'][] = [
254 '=ITEM_TYPE' => \Bitrix\Im\V2\Chat::IM_TYPE_COPILOT
257 elseif ($onlyOpenlinesOption ===
'Y')
259 $ormParams[
'filter'][] = [
260 '=ITEM_TYPE' => IM_MESSAGE_OPEN_LINE
266 $skipTypes[] = \Bitrix\Im\V2\Chat::IM_TYPE_COPILOT;
267 if ($options[
'SKIP_OPENLINES'] ===
'Y')
269 $skipTypes[] = IM_MESSAGE_OPEN_LINE;
271 if ($skipChatOption ===
'Y')
273 $skipTypes[] = IM_MESSAGE_OPEN;
274 $skipTypes[] = IM_MESSAGE_CHAT;
276 if ($skipDialogOption ===
'Y')
278 $skipTypes[] = IM_MESSAGE_PRIVATE;
280 if (!empty($skipTypes))
282 $ormParams[
'filter'][] = [
283 '!@ITEM_TYPE' => $skipTypes
290 $ormParams[
'filter'][
'<=DATE_MESSAGE'] = $lastMessageDateOption;
292 else if (isset($options[
'OFFSET']))
294 $ormParams[
'offset'] = $options[
'OFFSET'];
297 if (isset($options[
'LIMIT']))
299 $ormParams[
'limit'] = (int)$options[
'LIMIT'];
303 $ormParams[
'limit'] = 50;
306 $sortOption = (
new UserConfiguration((
int)$userId))->getGeneralSettings()[
'pinnedChatSort'];
307 if ($sortOption ===
'byCost')
309 $ormParams[
'order'] = [
312 'DATE_MESSAGE' =>
'DESC',
317 $ormParams[
'order'] = [
319 'DATE_MESSAGE' =>
'DESC',
323 $orm = \Bitrix\Im\Model\RecentTable::getList($ormParams);
329 $rows = $orm->fetchAll();
331 foreach ($rows as $row)
334 $isUser = $row[
'ITEM_TYPE'] == IM_MESSAGE_PRIVATE;
335 $id = $isUser? (int)$row[
'ITEM_ID']:
'chat'.$row[
'ITEM_ID'];
339 if (isset($result[$id]) && !$row[
'ITEM_MID'])
344 else if (isset($result[$id]))
349 $item = self::formatRow($row, [
350 'GENERAL_CHAT_ID' => $generalChatId,
351 'WITHOUT_COMMON_USERS' => $withoutCommonUsers,
352 'GET_ORIGINAL_TEXT' => $options[
'GET_ORIGINAL_TEXT'] ??
null,
353 'SHORT_INFO' => $shortInfo,
360 $result[$id] = $item;
362 if ($showOpenlines && !$onlyCopilotOption && Loader::includeModule(
'imopenlines'))
364 if (!isset($options[
'SKIP_UNDISTRIBUTED_OPENLINES']) || $options[
'SKIP_UNDISTRIBUTED_OPENLINES'] !==
'Y')
366 $recentOpenLines = \Bitrix\ImOpenLines\Recent::getRecent($userId, [
'ONLY_IN_QUEUE' =>
true]);
368 if (is_array($recentOpenLines))
370 $result = array_merge($result, $recentOpenLines);
375 $result = array_values($result);
377 if ($options[
'JSON'])
379 foreach ($result as $index => $item)
381 $result[$index] = self::jsonRow($item);
386 'hasMorePages' => $ormParams[
'limit'] == $counter,
387 'hasMore' => $ormParams[
'limit'] == $counter
390 if (!isset($options[
'LAST_MESSAGE_DATE']))
392 $objectToReturn[
'birthdayList'] = \Bitrix\Im\Integration\Intranet\User::getBirthdayForToday();
395 return $objectToReturn;
400 'HAS_MORE_PAGES' => $ormParams[
'limit'] == $counter,
401 'HAS_MORE' => $ormParams[
'limit'] == $counter
405 public static function getElement($itemType, $itemId, $userId =
null, $options = [])
407 $userId = \Bitrix\Im\Common::getUserId($userId);
413 $generalChatId = \CIMChat::GetGeneralChatId();
415 $ormParams = self::getOrmParams([
416 'USER_ID' => $userId,
417 'SHOW_OPENLINES' => $itemType === IM_MESSAGE_OPEN_LINE,
418 'WITHOUT_COMMON_USERS' =>
true,
421 $ormParams[
'filter'][
'=ITEM_TYPE'] = $itemType;
422 $ormParams[
'filter'][
'=ITEM_ID'] = $itemId;
424 $orm = \Bitrix\Im\Model\RecentTable::getList([
425 'select' => $ormParams[
'select'],
426 'filter' => $ormParams[
'filter'],
427 'runtime' => $ormParams[
'runtime'],
431 $rows = $orm->fetchAll();
433 foreach ($rows as $row)
435 $isUser = $row[
'ITEM_TYPE'] == IM_MESSAGE_PRIVATE;
438 if ($result && !$row[
'ITEM_MID'])
448 $item = self::formatRow($row, [
449 'GENERAL_CHAT_ID' => $generalChatId,
460 if ($options[
'JSON'])
462 $result = self::jsonRow($result);
468 private static function getOrmParams($params)
470 $userId = (int)$params[
'USER_ID'];
471 $showOpenlines = \Bitrix\Main\Loader::includeModule(
'imopenlines') && $params[
'SHOW_OPENLINES'] !==
false;
472 $isIntranet = \Bitrix\Main\Loader::includeModule(
'intranet') && \Bitrix\Intranet\Util::isIntranetUser($userId);
473 $withoutCommonUsers = $params[
'WITHOUT_COMMON_USERS'] ===
true || !$isIntranet;
474 $unreadOnly = isset($params[
'UNREAD_ONLY']) && $params[
'UNREAD_ONLY'] ===
true;
475 $shortInfo = isset($params[
'SHORT_INFO']) && $params[
'SHORT_INFO'] ===
true;
476 $chatIds = $params[
'CHAT_IDS'] ??
null;
480 'RELATION_USER_ID' =>
'RELATION.USER_ID',
481 'RELATION_NOTIFY_BLOCK' =>
'RELATION.NOTIFY_BLOCK',
482 'RELATION_IS_MANAGER' =>
'RELATION.MANAGER',
483 'CHAT_ID' =>
'CHAT.ID',
484 'CHAT_TITLE' =>
'CHAT.TITLE',
485 'CHAT_TYPE' =>
'CHAT.TYPE',
486 'CHAT_AVATAR' =>
'CHAT.AVATAR',
487 'CHAT_AUTHOR_ID' =>
'CHAT.AUTHOR_ID',
488 'CHAT_EXTRANET' =>
'CHAT.EXTRANET',
489 'CHAT_COLOR' =>
'CHAT.COLOR',
490 'CHAT_ENTITY_TYPE' =>
'CHAT.ENTITY_TYPE',
491 'CHAT_ENTITY_ID' =>
'CHAT.ENTITY_ID',
492 'CHAT_ENTITY_DATA_1' =>
'CHAT.ENTITY_DATA_1',
493 'CHAT_ENTITY_DATA_2' =>
'CHAT.ENTITY_DATA_2',
494 'CHAT_ENTITY_DATA_3' =>
'CHAT.ENTITY_DATA_3',
495 'CHAT_DATE_CREATE' =>
'CHAT.DATE_CREATE',
496 'CHAT_USER_COUNT' =>
'CHAT.USER_COUNT',
497 'MESSAGE_CODE' =>
'CODE.PARAM_VALUE',
498 'USER_LAST_ACTIVITY_DATE' =>
'USER.LAST_ACTIVITY_DATE',
499 'MESSAGE_DATE' =>
'MESSAGE.DATE_CREATE',
502 $additionalInfoFields = [
503 'MESSAGE_ID' =>
'MESSAGE.ID',
504 'MESSAGE_AUTHOR_ID' =>
'MESSAGE.AUTHOR_ID',
505 'MESSAGE_TEXT' =>
'MESSAGE.MESSAGE',
506 'MESSAGE_FILE' =>
'FILE.PARAM_VALUE',
507 'MESSAGE_ATTACH' =>
'ATTACH.PARAM_VALUE',
508 'MESSAGE_ATTACH_JSON' =>
'ATTACH.PARAM_JSON',
509 'MESSAGE_USER_LAST_ACTIVITY_DATE' =>
'MESSAGE.AUTHOR.LAST_ACTIVITY_DATE',
513 'USER_EMAIL' =>
'USER.EMAIL',
517 'MESSAGE_UUID_VALUE' =>
'MESSAGE_UUID.UUID',
518 'HAS_REMINDER' =>
'HAS_REMINDER',
519 'CHAT_MANAGE_USERS_ADD' =>
'CHAT.MANAGE_USERS_ADD',
520 'CHAT_MANAGE_USERS_DELETE' =>
'CHAT.MANAGE_USERS_DELETE',
521 'CHAT_MANAGE_UI' =>
'CHAT.MANAGE_UI',
522 'CHAT_MANAGE_SETTINGS' =>
'CHAT.MANAGE_SETTINGS',
523 'CHAT_CAN_POST' =>
'CHAT.CAN_POST',
527 new \Bitrix\Main\Entity\ReferenceField(
529 '\Bitrix\Im\Model\MessageParamTable',
531 "=ref.MESSAGE_ID" =>
"this.ITEM_MID",
534 [
"join_type" =>
"LEFT"]
536 new \Bitrix\Main\Entity\ReferenceField(
538 '\Bitrix\Main\UserTable',
539 array(
"=this.ITEM_TYPE" =>
new \
Bitrix\Main\DB\
SqlExpression(
"?s", IM_MESSAGE_PRIVATE),
"=ref.ID" =>
"this.ITEM_ID"),
540 array(
"join_type"=>
"LEFT")
547 $additionalRuntime = [
548 new \Bitrix\Main\Entity\ReferenceField(
550 '\Bitrix\Im\Model\MessageParamTable',
552 "=ref.MESSAGE_ID" =>
"this.ITEM_MID",
555 [
"join_type" =>
"LEFT"]
557 new \Bitrix\Main\Entity\ReferenceField(
559 '\Bitrix\Im\Model\MessageParamTable',
561 "=ref.MESSAGE_ID" =>
"this.ITEM_MID",
564 [
"join_type" =>
"LEFT"]
576 FROM {$reminderTable}
577 WHERE CHAT_ID = %s AND AUTHOR_ID = %s AND IS_REMINDED = 'Y'
578 ) THEN 'Y' ELSE 'N' END",
579 [
'ITEM_CID',
'USER_ID'],
580 [
'data_type' =>
'boolean',
'values' => [
'N',
'Y']]
583 'HAS_UNREAD_MESSAGE',
584 "EXISTS(SELECT 1 FROM {$unreadTable} WHERE CHAT_ID = %s AND USER_ID = %s)",
585 [
'ITEM_CID',
'USER_ID']
589 $select = $shortInfo ? $shortInfoFields : array_merge($shortInfoFields, $additionalInfoFields);
590 $runtime = $shortInfo ? $shortRuntime : array_merge($shortRuntime, $additionalRuntime);
592 if (!$withoutCommonUsers)
594 $select[
'INVITATION_ORIGINATOR_ID'] =
'INVITATION.ORIGINATOR_ID';
598 $select[
'LINES_ID'] =
'LINES.ID';
599 $select[
'LINES_STATUS'] =
'LINES.STATUS';
600 $select[
'LINES_DATE_CREATE'] =
'LINES.DATE_CREATE';
603 if (!$withoutCommonUsers)
605 $runtime[] = new \Bitrix\Main\Entity\ReferenceField(
607 '\Bitrix\Intranet\Internals\InvitationTable',
608 array(
"=this.ITEM_TYPE" =>
new \
Bitrix\Main\DB\SqlExpression(
"?s", IM_MESSAGE_PRIVATE),
"=ref.USER_ID" =>
"this.ITEM_ID"),
609 array(
"join_type"=>
"LEFT")
614 $runtime[] = new \Bitrix\Main\Entity\ReferenceField(
616 '\Bitrix\ImOpenlines\Model\SessionTable',
617 [
">this.ITEM_OLID" =>
new \
Bitrix\Main\DB\SqlExpression(
"?i", 0),
"=ref.ID" =>
"this.ITEM_OLID"],
618 [
"join_type" =>
"LEFT"]
622 if ($withoutCommonUsers)
624 $filter = [
'=USER_ID' =>
$userId];
628 $filter = [
'@USER_ID' => [
$userId, 0]];
635 [
'==HAS_UNREAD_MESSAGE' =>
true],
642 $filter[
'@ITEM_CID'] = $chatIds;
648 'runtime' => $runtime,
652 private static function formatRow($row, $options = []): ?array
654 $generalChatId = (int)$options[
'GENERAL_CHAT_ID'];
655 $withoutCommonUsers = isset($options[
'WITHOUT_COMMON_USERS']) && $options[
'WITHOUT_COMMON_USERS'] ===
true;
656 $shortInfo = isset($options[
'SHORT_INFO']) && $options[
'SHORT_INFO'];
658 $chatOwner = $row[
'CHAT_OWNER'] ??
null;
660 $isUser = $row[
'ITEM_TYPE'] == IM_MESSAGE_PRIVATE;
661 $id = $isUser? (int)$row[
'ITEM_ID']:
'chat'.$row[
'ITEM_ID'];
662 $row[
'MESSAGE_ID'] ??=
null;
664 if (!$isUser && ((!$row[
'MESSAGE_ID'] && !$shortInfo) || !$row[
'RELATION_USER_ID'] || !$row[
'CHAT_ID']))
669 if ($row[
'ITEM_MID'] > 0 && $row[
'MESSAGE_ID'] > 0)
672 if ($row[
'MESSAGE_ATTACH'] || $row[
"MESSAGE_ATTACH_JSON"])
674 if (preg_match(
'/^(\d+)$/', $row[
'MESSAGE_ATTACH']))
678 else if ($row[
'MESSAGE_ATTACH'] === \CIMMessageParamAttach::FIRST_MESSAGE)
682 $value = \Bitrix\Main\Web\Json::decode($row[
"MESSAGE_ATTACH_JSON"]);
683 $attachRestored = \CIMMessageParamAttach::PrepareAttach($value);
684 $attach = $attachRestored[
'DESCRIPTION'];
686 catch (\
Bitrix\Main\SystemException $e)
691 else if (!empty($row[
'MESSAGE_ATTACH']))
693 $attach = $row[
'MESSAGE_ATTACH'];
701 $text = $row[
'MESSAGE_TEXT'] ??
'';
703 $getOriginalTextOption = $options[
'GET_ORIGINAL_TEXT'] ??
null;
704 if ($getOriginalTextOption ===
'Y')
711 str_replace(
"\n",
" ", $text),
712 $row[
'MESSAGE_FILE'] > 0,
718 'ID' => (int)$row[
'ITEM_MID'],
720 'FILE' => $row[
'MESSAGE_FILE'],
721 'AUTHOR_ID' => (
int)$row[
'MESSAGE_AUTHOR_ID'],
723 'DATE' => $row[
'MESSAGE_DATE']?: $row[
'DATE_UPDATE'],
724 'STATUS' => $row[
'CHAT_LAST_MESSAGE_STATUS'],
725 'UUID' => $row[
'MESSAGE_UUID_VALUE'],
730 $row[
'MESSAGE_DATE'] ??=
null;
737 'DATE' => $row[
'MESSAGE_DATE']?: $row[
'DATE_UPDATE'],
738 'STATUS' => $row[
'CHAT_LAST_MESSAGE_STATUS'],
744 'CHAT_ID' => (int)$row[
'CHAT_ID'],
745 'TYPE' => $isUser ?
'user' :
'chat',
748 'MESSAGE' => $message,
749 'COUNTER' => (int)$row[
'COUNTER'],
750 'PINNED' => $row[
'PINNED'] ===
'Y',
751 'UNREAD' => $row[
'UNREAD'] ===
'Y',
752 'HAS_REMINDER' => isset($row[
'HAS_REMINDER']) && $row[
'HAS_REMINDER'] ===
'Y',
753 'DATE_UPDATE' => $row[
'DATE_UPDATE']
760 && ($row[
'USER_ID'] == 0 || $row[
'MESSAGE_CODE'] ===
'USER_JOIN')
766 $row[
'INVITATION_ORIGINATOR_ID'] ??=
null;
767 if (!$row[
'USER_LAST_ACTIVITY_DATE'] && $row[
'INVITATION_ORIGINATOR_ID'])
770 'ORIGINATOR_ID' => (int)$row[
'INVITATION_ORIGINATOR_ID'],
771 'CAN_RESEND' => !empty($row[
'USER_EMAIL'])
775 'ID' => (int)$row[
'ITEM_ID'],
780 $avatar = \CIMChat::GetAvatarImage($row[
'CHAT_AVATAR'], 200,
false);
781 $color = $row[
'CHAT_COLOR'] <>
''
783 : Color::getColorByNumber(
786 $chatType = \Bitrix\Im\Chat::getType($row);
788 if ($generalChatId == $row[
'ITEM_ID'])
790 $row[
"CHAT_ENTITY_TYPE"] =
'GENERAL';
794 if ($row[
'RELATION_NOTIFY_BLOCK'] ==
'Y')
796 $muteList = [$row[
'RELATION_USER_ID'] =>
true];
801 $chatOwner == $row[
'RELATION_USER_ID']
802 || $row[
'RELATION_IS_MANAGER'] ==
'Y'
805 $managerList = [(int)$row[
'RELATION_USER_ID']];
808 if ($row[
'RELATION_NOTIFY_BLOCK'] ==
'Y')
810 $muteList = [$row[
'RELATION_USER_ID'] =>
true];
813 $chatOptions = \CIMChat::GetChatOptions();
814 $restrictions = $chatOptions[
'DEFAULT'];
815 if ($row[
'CHAT_ENTITY_TYPE'] && array_key_exists($row[
'CHAT_ENTITY_TYPE'], $chatOptions))
817 $restrictions = $chatOptions[$row[
'CHAT_ENTITY_TYPE']];
824 $item[
'TITLE'] = $row[
'CHAT_TITLE'];
826 'ID' => (int)$row[
'ITEM_CID'],
827 'NAME' => $row[
'CHAT_TITLE'],
828 'OWNER' => (
int)$row[
'CHAT_AUTHOR_ID'],
829 'EXTRANET' => $row[
'CHAT_EXTRANET'] ==
'Y',
833 'ENTITY_TYPE' => (string)$row[
'CHAT_ENTITY_TYPE'],
834 'ENTITY_ID' => (
string)$row[
'CHAT_ENTITY_ID'],
835 'ENTITY_DATA_1' => (string)$row[
'CHAT_ENTITY_DATA_1'],
836 'ENTITY_DATA_2' => (
string)$row[
'CHAT_ENTITY_DATA_2'],
837 'ENTITY_DATA_3' => (string)$row[
'CHAT_ENTITY_DATA_3'],
838 'MUTE_LIST' => $muteList,
839 'MANAGER_LIST' => $managerList,
840 'DATE_CREATE' => $row[
'CHAT_DATE_CREATE'],
841 'MESSAGE_TYPE' => $row[
"CHAT_TYPE"],
842 'USER_COUNTER' => (
int)$row[
'CHAT_USER_COUNT'],
843 'RESTRICTIONS' => $restrictions,
846 'AI_PROVIDER' => $chatType ===
'copilot' ? AIHelper::getProviderName() : null,
848 'MANAGE_USERS_ADD' => mb_strtolower($row[
'CHAT_MANAGE_USERS_ADD'] ??
''),
849 'MANAGE_USERS_DELETE' => mb_strtolower($row[
'CHAT_MANAGE_USERS_DELETE'] ??
''),
850 'MANAGE_UI' => mb_strtolower($row[
'CHAT_MANAGE_UI'] ??
''),
851 'MANAGE_SETTINGS' => mb_strtolower($row[
'CHAT_MANAGE_SETTINGS'] ??
''),
852 'CAN_POST' => mb_strtolower($row[
'CHAT_CAN_POST'] ??
''),
855 if ($row[
"CHAT_ENTITY_TYPE"] ==
'LINES')
858 'ID' => (int)$row[
'LINES_ID'],
859 'STATUS' => (
int)$row[
'LINES_STATUS'],
860 'DATE_CREATE' => $row[
'LINES_DATE_CREATE'] ?? $row[
'DATE_UPDATE'],
864 'ID' => (int)($row[
'MESSAGE_AUTHOR_ID'] ?? 0),
868 if ($item[
'USER'][
'ID'] > 0)
870 $user = \Bitrix\Im\V2\Entity\User\User::getInstance($item[
'USER'][
'ID'])
871 ->getArray([
'WITHOUT_ONLINE' =>
true])
878 else if ($item[
'TYPE'] ==
'user')
881 !empty($user[
'BOT_DATA'])
882 && Loader::includeModule(
'imbot')
883 && $user[
'BOT_DATA'][
'code'] === CopilotChatBot::BOT_CODE
890 (!$user[
'ACTIVE'] && $item[
'COUNTER'] <= 0)
892 && !$user[
'CONNECTOR']
900 'URL' => $user[
'AVATAR'],
901 'COLOR' => $user[
'COLOR']
904 $item[
'TITLE'] = $user[
'NAME'];
906 $row[
'USER_LAST_ACTIVITY_DATE'] ??=
null;
907 $row[
'USER_DESKTOP_LAST_DATE'] ??=
null;
908 $row[
'USER_MOBILE_LAST_DATE'] ??=
null;
909 $row[
'USER_IDLE'] ??=
null;
911 $user[
'LAST_ACTIVITY_DATE'] = $row[
'USER_LAST_ACTIVITY_DATE']?:
false;
912 $user[
'DESKTOP_LAST_DATE'] = $row[
'USER_DESKTOP_LAST_DATE']?:
false;
913 $user[
'MOBILE_LAST_DATE'] = $row[
'USER_MOBILE_LAST_DATE']?:
false;
914 $user[
'IDLE'] = $row[
'USER_IDLE']?:
false;
918 $row[
'MESSAGE_USER_LAST_ACTIVITY_DATE'] ??=
null;
919 $row[
'MESSAGE_USER_DESKTOP_LAST_DATE'] ??=
null;
920 $row[
'MESSAGE_USER_MOBILE_LAST_DATE'] ??=
null;
921 $row[
'MESSAGE_USER_IDLE'] ??=
null;
923 $user[
'LAST_ACTIVITY_DATE'] = $row[
'MESSAGE_USER_LAST_ACTIVITY_DATE']?:
false;
924 $user[
'DESKTOP_LAST_DATE'] = $row[
'MESSAGE_USER_DESKTOP_LAST_DATE']?:
false;
925 $user[
'MOBILE_LAST_DATE'] = $row[
'MESSAGE_USER_MOBILE_LAST_DATE']?:
false;
926 $user[
'IDLE'] = $row[
'MESSAGE_USER_IDLE']?:
false;
929 $item[
'USER'] = $user;
932 $item[
'OPTIONS'] = [];
933 if ($row[
'USER_ID'] == 0 || $row[
'MESSAGE_CODE'] ===
'USER_JOIN')
935 $item[
'OPTIONS'][
'DEFAULT_USER_RECORD'] =
true;
941 private static function jsonRow($item)
943 if (!is_array($item))
948 foreach ($item as $key => $value)
950 if ($value instanceof \
Bitrix\Main\
Type\DateTime)
952 $item[$key] = date(
'c', $value->getTimestamp());
954 else if (is_array($value))
956 foreach ($value as $subKey => $subValue)
958 if ($subValue instanceof \
Bitrix\Main\
Type\DateTime)
960 $value[$subKey] = date(
'c', $subValue->getTimestamp());
965 && in_array($subKey, [
'URL',
'AVATAR'])
966 && mb_strpos($subValue,
'http') !== 0
969 $value[$subKey] = \Bitrix\Im\Common::getPublicDomain().$subValue;
971 else if (is_array($subValue))
973 $value[$subKey] = array_change_key_case($subValue, CASE_LOWER);
976 $item[$key] = array_change_key_case($value, CASE_LOWER);
980 return array_change_key_case($item, CASE_LOWER);
983 public static function pin($dialogId, $pin, $userId =
null)
985 $userId = \Bitrix\Im\Common::getUserId($userId);
991 $pinnedCount = \Bitrix\Im\Model\RecentTable::getCount([
'=USER_ID' => $userId,
'=PINNED' =>
'Y']);
993 self::$limitError =
false;
994 if ($pin && (
int)$pinnedCount >= self::PINNED_CHATS_LIMIT)
996 self::$limitError =
true;
1001 $pin = $pin ===
true?
'Y':
'N';
1005 if (mb_substr($dialogId, 0, 4) ==
'chat')
1007 $itemTypes = \Bitrix\Im\Chat::getTypes();
1008 $id = mb_substr($dialogId, 4);
1013 $itemTypes = IM_MESSAGE_PRIVATE;
1014 $chatId = \Bitrix\Im\Dialog::getChatId($dialogId);
1017 $element = \Bitrix\Im\Model\RecentTable::getList(
1019 'select' => [
'USER_ID',
'ITEM_TYPE',
'ITEM_ID',
'PINNED',
'PIN_SORT'],
1021 '=USER_ID' => $userId,
1022 '=ITEM_TYPE' => $itemTypes,
1048 $relationData = \Bitrix\Im\Model\RelationTable::getList(
1050 'select' => [
'ID',
'LAST_MESSAGE_ID' =>
'CHAT.LAST_MESSAGE_ID'],
1052 '=CHAT_ID' => $chatId,
1053 '=USER_ID' => $userId,
1058 $messageId = $relationData[
'LAST_MESSAGE_ID'];
1059 $relationId = $relationData[
'ID'];
1061 $addResult = \Bitrix\Im\Model\RecentTable::add(
1063 'USER_ID' => $userId,
1064 'ITEM_TYPE' => $itemTypes,
1066 'ITEM_MID' => $messageId,
1067 'ITEM_RID' => $relationId,
1068 'ITEM_CID' => $chatId,
1072 if (!$addResult->isSuccess())
1079 $element[
'USER_ID'] = $userId;
1080 $element[
'ITEM_TYPE'] = $itemTypes;
1081 $element[
'ITEM_ID'] = $id;
1084 if ($element[
'PINNED'] == $pin)
1090 $connection->lock(
"PIN_SORT_CHAT_{$userId}", 10);
1094 self::increasePinSortCost($userId);
1098 $pinSort = $element[
'PIN_SORT'] ? (int)$element[
'PIN_SORT'] :
null;
1099 self::decreasePinSortCost($userId, $pinSort);
1103 \Bitrix\Im\Model\RecentTable::update(
1105 'USER_ID' => $element[
'USER_ID'],
1106 'ITEM_TYPE' => $element[
'ITEM_TYPE'],
1107 'ITEM_ID' => $element[
'ITEM_ID'],
1112 'PIN_SORT' => ($pin ===
'Y') ? 1 :
null,
1116 $connection->unlock(
"PIN_SORT_CHAT_{$userId}");
1118 if ($element[
'ITEM_TYPE'] !== \
Bitrix\Im\V2\Chat::IM_TYPE_OPEN_LINE)
1120 Sync\Logger::getInstance()->add(
1121 new Sync\
Event(Sync\Event::ADD_EVENT, Sync\Event::CHAT_ENTITY, $chatId),
1128 $pullInclude = \Bitrix\Main\Loader::includeModule(
"pull");
1131 \Bitrix\Pull\Event::add(
1134 'module_id' =>
'im',
1135 'command' =>
'chatPin',
1138 'dialogId' => $dialogId,
1139 'active' => $pin ==
'Y'
1149 private static function increasePinSortCost(
int $userId): void
1153 RecentTable::updateByFilter(
1156 '=USER_ID' => $userId,
1159 [
'PIN_SORT' => $caseField]
1163 private static function decreasePinSortCost(
int $userId, ?
int $pinSort)
1165 if (!isset($pinSort))
1170 $caseField =
new SqlExpression(
'?# - 1',
'PIN_SORT');
1172 RecentTable::updateByFilter(
1175 '=USER_ID' => $userId,
1176 '>PIN_SORT' => $pinSort,
1178 [
'PIN_SORT' => $caseField]
1185 $connection->lock(
"PIN_SORT_CHAT_{$userId}", 10);
1187 $query = RecentTable::query()
1188 ->setSelect([
'PIN_SORT'])
1190 ->where(
'USER_ID', $userId)
1191 ->where(
'ITEM_CID', (
int)$chat->getChatId())
1192 ->where(
'PINNED',
'Y')
1198 $connection->unlock(
"PIN_SORT_CHAT_{$userId}");
1202 $currentCost = (int)$query[
'PIN_SORT'];
1204 $query = RecentTable::query()
1205 ->setSelect([
'PIN_SORT'])
1206 ->setOrder([
'PIN_SORT'])
1207 ->setOffset($newPosition - 1)
1209 ->where(
'PINNED',
'Y')
1210 ->where(
'USER_ID', $userId)
1216 $connection->unlock(
"PIN_SORT_CHAT_{$userId}");
1220 $newCost = (int)$query[
'PIN_SORT'];
1222 if ($currentCost === $newCost)
1224 $connection->unlock(
"PIN_SORT_CHAT_{$userId}");
1229 if ($currentCost < $newCost)
1232 "CASE WHEN ?# = ?i THEN ?i WHEN ?# > ?i AND ?# <= ?i THEN ?# - 1 END",
1245 '=USER_ID' => $userId,
1246 '>=PIN_SORT' => $currentCost,
1247 '<=PIN_SORT' => $newCost,
1253 "CASE WHEN ?# = ?i THEN ?i WHEN ?# >= ?i AND ?# < ?i THEN ?# + 1 END",
1266 '=USER_ID' => $userId,
1267 '>=PIN_SORT' => $newCost,
1268 '<=PIN_SORT' => $currentCost,
1272 RecentTable::updateByFilter(
1274 [
'PIN_SORT' => $caseField]
1277 $connection->unlock(
"PIN_SORT_CHAT_{$userId}");
1282 return self::PINNED_CHATS_LIMIT ?? 25;
1288 $connection->lock(
"PIN_SORT_CHAT_{$userId}", 10);
1292 RecentTable::updateByFilter(
1295 '=USER_ID' => $userId
1297 [
'PIN_SORT' => $caseField]
1300 $connection->unlock(
"PIN_SORT_CHAT_{$userId}");
1305 RecentTable::updateByFilter($filter, $fields);
1308 public static function unread($dialogId, $unread, $userId =
null, ?
int $markedId =
null)
1310 $userId = \Bitrix\Im\Common::getUserId($userId);
1316 $unread = $unread ===
true?
'Y':
'N';
1319 if (mb_substr($dialogId, 0, 4) ===
'chat')
1321 $itemTypes = \Bitrix\Im\Chat::getTypes();
1322 $id = mb_substr($dialogId, 4);
1326 $itemTypes = IM_MESSAGE_PRIVATE;
1329 $element = \Bitrix\Im\Model\RecentTable::getList([
1330 'select' => [
'USER_ID',
'ITEM_TYPE',
'ITEM_ID',
'UNREAD',
'MUTED' =>
'RELATION.NOTIFY_BLOCK',
'ITEM_CID',
'MARKED_ID'],
1332 '=USER_ID' => $userId,
1333 '=ITEM_TYPE' => $itemTypes,
1341 if ($element[
'UNREAD'] === $unread && !isset($markedId))
1347 'UNREAD' => $unread,
1348 'DATE_UPDATE' => new \Bitrix\Main\Type\DateTime(),
1351 if ($unread ===
'N')
1355 if (isset($markedId))
1357 $updatedFields[
'MARKED_ID'] = $markedId;
1360 \Bitrix\Im\Model\RecentTable::update(
1362 'USER_ID' => $element[
'USER_ID'],
1363 'ITEM_TYPE' => $element[
'ITEM_TYPE'],
1364 'ITEM_ID' => $element[
'ITEM_ID'],
1371 CounterService::clearCache((
int)$element[
'USER_ID']);
1372 $chatId = (int)$element[
'ITEM_CID'];
1373 if ($element[
'ITEM_TYPE'] !== \
Bitrix\Im\V2\Chat::IM_TYPE_OPEN_LINE)
1375 Sync\Logger::getInstance()->add(
1376 new Sync\
Event(Sync\Event::ADD_EVENT, Sync\Event::CHAT_ENTITY, $chatId),
1381 $pullInclude = \Bitrix\Main\Loader::includeModule(
"pull");
1385 $counter = $readService->getCounterService()->getByChat($chatId);
1388 \Bitrix\Pull\Event::add(
1391 'module_id' =>
'im',
1392 'command' =>
'chatUnread',
1395 'chatId' => $chatId,
1396 'dialogId' => $dialogId,
1397 'active' => $unread ===
'Y',
1398 'muted' => $element[
'MUTED'] ===
'Y',
1399 'counter' => $counter,
1400 'markedId' => $markedId ?? $element[
'MARKED_ID'],
1401 'lines' => $element[
'ITEM_TYPE'] === IM_MESSAGE_OPEN_LINE,
1413 \Bitrix\Im\Model\RecentTable::updateByFilter(
1416 '=USER_ID' => $userId,
1425 public static function isUnread(
int $userId,
string $itemType,
string $dialogId): bool
1427 $id = mb_strpos($dialogId,
'chat') === 0 ? mb_substr($dialogId, 4) : $dialogId;
1428 $element = \Bitrix\Im\Model\RecentTable::getList([
1429 'select' => [
'USER_ID',
'ITEM_TYPE',
'ITEM_ID',
'UNREAD',
'MUTED' =>
'RELATION.NOTIFY_BLOCK',
'ITEM_CID'],
1431 '=USER_ID' => $userId,
1432 '=ITEM_TYPE' => $itemType,
1441 return ($element[
'UNREAD'] ??
'N') ===
'Y';
1444 public static function getUnread(
string $itemType,
string $dialogId): array
1446 $id = mb_strpos($dialogId,
'chat') === 0 ? mb_substr($dialogId, 4) : $dialogId;
1447 $queryResult = \Bitrix\Im\Model\RecentTable::getList([
1448 'select' => [
'USER_ID',
'UNREAD',],
1450 '=ITEM_TYPE' => $itemType,
1457 foreach ($queryResult as $row)
1459 $result[(int)$row[
'USER_ID']] = ($row[
'UNREAD'] ??
'N') ===
'Y';
1465 public static function getMarkedId(
int $userId,
string $itemType,
string $dialogId): int
1467 $id = mb_strpos($dialogId,
'chat') === 0 ? mb_substr($dialogId, 4) : $dialogId;
1468 $element = \Bitrix\Im\Model\RecentTable::getList([
1469 'select' => [
'MARKED_ID'],
1471 '=USER_ID' => $userId,
1472 '=ITEM_TYPE' => $itemType,
1481 return (
int)($element[
'MARKED_ID'] ?? 0);
1486 if (empty($chatIds))
1491 $markedIdByChatIds = [];
1493 $result = RecentTable::query()
1494 ->setSelect([
'ITEM_CID',
'MARKED_ID'])
1495 ->where(
'USER_ID', $userId)
1496 ->whereIn(
'ITEM_CID', $chatIds)
1500 foreach ($result as $row)
1502 $markedIdByChatIds[(int)$row[
'ITEM_CID']] = (
int)$row[
'MARKED_ID'];
1505 return $markedIdByChatIds;
1508 public static function hide($dialogId, $userId =
null)
1510 return \CIMContactList::DialogHide($dialogId, $userId);
1513 public static function show($dialogId, $options = [], $userId =
null)
1524 $entityId = $chatId;
1528 $entityId = (int)$dialogId;
1531 $relation = \Bitrix\Im\Model\RelationTable::getList([
1534 'TYPE' =>
'CHAT.TYPE',
1535 'LAST_MESSAGE_ID' =>
'CHAT.LAST_MESSAGE_ID',
1536 'LAST_MESSAGE_DATE' =>
'MESSAGE.DATE_CREATE'
1539 '=CHAT_ID' => $chatId,
1540 '=USER_ID' => $userId
1545 '\Bitrix\Im\Model\MessageTable',
1546 [
"=ref.ID" =>
"this.CHAT.LAST_MESSAGE_ID"],
1547 [
"join_type" =>
"LEFT"]
1554 $relationId = $relation[
'ID'];
1555 $entityType = $relation[
'TYPE'];
1556 $messageId = $relation[
'LAST_MESSAGE_ID'];
1557 $messageDate = $relation[
'LAST_MESSAGE_DATE'];
1560 isset($options[
'CHAT_DATA'][
'TYPE'])
1561 && isset($options[
'CHAT_DATA'][
'LAST_MESSAGE_ID'])
1565 $entityType = $options[
'CHAT_DATA'][
'TYPE'];
1566 $messageId = $options[
'CHAT_DATA'][
'LAST_MESSAGE_ID'];
1567 $messageDate = $options[
'CHAT_DATA'][
'LAST_MESSAGE_DATE'];
1571 $chat = \Bitrix\Im\Model\ChatTable::getList([
1575 'LAST_MESSAGE_DATE' =>
'MESSAGE.DATE_CREATE'
1583 '\Bitrix\Im\Model\MessageTable',
1584 [
"=ref.ID" =>
"this.LAST_MESSAGE_ID"],
1585 [
"join_type" =>
"LEFT"]
1595 $entityType = $chat[
'TYPE'];
1596 $messageId = $chat[
'LAST_MESSAGE_ID'];
1597 $messageDate = $chat[
'LAST_MESSAGE_DATE'];
1601 if ($entityType == IM_MESSAGE_OPEN_LINE)
1603 if (isset($options[
'SESSION_ID']))
1605 $sessionId = (int)$options[
'SESSION_ID'];
1607 else if (\
Bitrix\Main\Loader::includeModule(
'imopenlines'))
1609 $session = \Bitrix\ImOpenLines\Model\SessionTable::getList([
1611 'filter' => [
'=CHAT_ID' => $chatId],
1612 'order' => [
'ID' =>
'DESC'],
1617 $sessionId = $session[
'ID'];
1622 \CIMContactList::SetRecent($temp = [
1623 'ENTITY_TYPE' => $entityType,
1624 'ENTITY_ID' => $entityId,
1625 'MESSAGE_ID' => $messageId,
1626 'MESSAGE_DATE' => $messageDate,
1627 'CHAT_ID' => $chatId,
1628 'RELATION_ID' => $relationId,
1629 'SESSION_ID' => $sessionId,
1630 'USER_ID' => $userId,
1633 if (!\
Bitrix\Main\Loader::includeModule(
"pull"))
1638 $data = \Bitrix\Im\Recent::getElement($entityType, $entityId, $userId, [
'JSON' =>
true]);
1642 !isset($data[
'message'])
1644 && class_exists(
'\Bitrix\ImOpenLines\Recent')
1647 $data = \Bitrix\ImOpenLines\Recent::getElement(
1656 \Bitrix\Pull\Event::add($userId, [
1657 'module_id' =>
'im',
1658 'command' =>
'chatShow',
1673 protected static function prepareRows(array $rows,
int $userId): array
1675 $rows = static::fillCounters($rows, $userId);
1676 $rows = static::fillFiles($rows);
1678 return static::fillLastMessageStatuses($rows, $userId);
1686 protected static function getRole(array $row): string
1688 if (!isset($row[
'RELATION_USER_ID']))
1690 return \Bitrix\Im\V2\Chat::ROLE_GUEST;
1692 if ((
int)$row[
'CHAT_AUTHOR_ID'] === (
int)$row[
'RELATION_USER_ID'])
1694 return \Bitrix\Im\V2\Chat::ROLE_OWNER;
1696 if ($row[
'RELATION_IS_MANAGER'] ===
'Y')
1698 return \Bitrix\Im\V2\Chat::ROLE_MANAGER;
1701 return \Bitrix\Im\V2\Chat::ROLE_MEMBER;
1708 foreach ($rows as $row)
1710 $chatIds[] = (int)$row[
'CHAT_ID'];
1713 $counters = (
new CounterService($userId))->getForEachChat($chatIds);
1715 foreach ($rows as $key => $row)
1717 $rows[$key][
'COUNTER'] = (int)($counters[(
int)$row[
'CHAT_ID']] ?? 0);
1727 foreach ($rows as $row)
1729 if (isset($row[
'MESSAGE_AUTHOR_ID']) && (
int)$row[
'MESSAGE_AUTHOR_ID'] === $userId)
1731 $messageIds[] = (int)$row[
'MESSAGE_ID'];
1735 $messageStatuses = (
new ViewedService($userId))->getMessageStatuses($messageIds);
1737 foreach ($rows as $key => $row)
1739 $rows[$key][
'CHAT_LAST_MESSAGE_STATUS'] = $messageStatuses[(int)($row[
'MESSAGE_ID'] ?? 0)] ?? \IM_MESSAGE_STATUS_RECEIVED;
1745 protected static function fillFiles(array $rows): array
1749 foreach ($rows as $key => $row)
1751 $rows[$key][
'MESSAGE_FILE'] = (bool)($row[
'MESSAGE_FILE'] ??
false);
1759 foreach ($rows as $row)
1761 if (isset($row[
'MESSAGE_FILE']) && $row[
'MESSAGE_FILE'] > 0)
1763 $fileIds[] = (int)$row[
'MESSAGE_FILE'];
1769 foreach ($rows as $key => $row)
1771 $fileId = $row[
'MESSAGE_FILE'] ??
null;
1772 $rows[$key][
'MESSAGE_FILE'] =
false;
1773 if (isset($fileId) && $fileId > 0)
1775 $file = $files->getById((
int)$fileId);
1779 $rows[$key][
'MESSAGE_FILE'] = [
1780 'ID' => $file->getId(),
1781 'TYPE' => $file->getContentType(),
1782 'NAME' => $file->getDiskFile()->getName(),
1793 return self::$limitError;
static populateUserBbCode(string $text)
static removeBbCodes($text, $withFile=false, $attachValue=false)