1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
Chat.php
См. документацию.
1<?php
2
3namespace Bitrix\Im\V2;
4
5use Bitrix\Disk\Folder;
6use Bitrix\Im\Alias;
7use Bitrix\Im\V2\Analytics\MessageAnalytics;
8use Bitrix\Im\V2\Chat\Background\Background;
9use Bitrix\Im\V2\Chat\TextField\TextFieldEnabled;
10use Bitrix\Im\V2\Chat\Member\Provider\MemberProvider;
11use Bitrix\Im\V2\Entity\User\UserCollection;
12use Bitrix\Im\V2\Entity\User\UserError;
13use Bitrix\Im\V2\Async\Promise\BackgroundJobPromise;
14use Bitrix\Im\V2\Entity\User\UserType;
15use Bitrix\Im\V2\Integration\AI\AIHelper;
16use Bitrix\Im\Recent;
17use Bitrix\Im\V2\Integration\Socialnetwork\Group;
18use Bitrix\Im\V2\Message\Counter\CounterType;
19use Bitrix\Im\V2\Message\ReadService;
20use Bitrix\Im\V2\Message\Send\MentionService;
21use Bitrix\Im\V2\Message\Send\PushService;
22use Bitrix\Im\V2\Message\Send\SendingService;
23use Bitrix\Im\V2\Message\Send\SendResult;
24use Bitrix\Im\V2\Permission\Action;
25use Bitrix\Im\V2\Recent\Config\ChatRecentConfig;
26use Bitrix\Im\V2\Recent\Config\RecentConfigManager;
27use Bitrix\Im\V2\Relation\AddUsersConfig;
28use Bitrix\Im\V2\Relation\DeleteUserConfig;
29use Bitrix\Im\V2\Relation\Provider\RelationProvider;
30use Bitrix\Im\V2\Relation\Reason;
31use Bitrix\Im\V2\Relation\RelationChangeSet;
32use Bitrix\Im\V2\Rest\PopupData;
33use Bitrix\Im\V2\Rest\PopupDataAggregatable;
34use Bitrix\Im\V2\Rest\RestEntity;
35use Bitrix\Main;
36use Bitrix\Main\Application;
37use Bitrix\Main\Config\Option;
38use Bitrix\Main\Engine\Response\Converter;
39use Bitrix\Main\Localization\Loc;
40use Bitrix\Main\ORM\Data\DataManager;
41use Bitrix\Main\ORM\Fields\Relations\Reference;
42use Bitrix\Main\ORM\Query\Join;
43use Bitrix\Main\Type\DateTime;
44use Bitrix\Im;
45use Bitrix\Im\User;
46use Bitrix\Im\Color;
47use Bitrix\Im\Model\ChatTable;
48use Bitrix\Im\Model\EO_Chat;
49use Bitrix\Im\Model\RelationTable;
50use Bitrix\Im\V2\Service\Locator;
51use Bitrix\Im\V2\Service\Context;
52use Bitrix\Im\V2\Chat\ChatFactory;
53use Bitrix\Im\V2\Chat\ChatError;
54use Bitrix\Im\V2\Common\ContextCustomer;
55use Bitrix\Im\V2\Common\ActiveRecordImplementation;
56use Bitrix\Im\V2\Common\RegistryEntryImplementation;
57use Bitrix\Im\V2\Message\MessageError;
58use Bitrix\Im\V2\Message\Send\SendingConfig;
59use Bitrix\Im\V2\Chat\Param\Params;
60use Bitrix\Pull\Event;
61use CGlobalCounter;
62use CIMContactList;
63use CIMNotify;
64use CPushManager;
65
70{
71 use ContextCustomer
72 {
73 setContext as private defaultSaveContext;
74 }
75 use RegistryEntryImplementation;
76 use ActiveRecordImplementation
77 {
78 save as defaultSave;
79 }
80
81 public const
95 ;
96
97 public const IM_TYPES = [
98 self::IM_TYPE_PRIVATE,
99 self::IM_TYPE_CHAT,
100 self::IM_TYPE_COMMENT,
101 self::IM_TYPE_OPEN_LINE,
102 self::IM_TYPE_SYSTEM,
103 self::IM_TYPE_CHANNEL,
104 self::IM_TYPE_OPEN_CHANNEL,
105 self::IM_TYPE_OPEN,
106 self::IM_TYPE_COPILOT,
107 self::IM_TYPE_COLLAB,
108 self::IM_TYPE_EXTERNAL,
109 self::IM_TYPE_AI_ASSISTANT,
110 self::IM_TYPE_AI_ASSISTANT_ENTITY,
111 ];
112
113 public const IM_TYPES_TRANSLATE = [
114 'PRIVATE' => self::IM_TYPE_PRIVATE,
115 'CHAT' => self::IM_TYPE_CHAT,
116 'COMMENT' => self::IM_TYPE_COMMENT,
117 'OPENLINE' => self::IM_TYPE_OPEN_LINE,
118 'SYSTEM' => self::IM_TYPE_SYSTEM,
119 'NOTIFY' => self::IM_TYPE_SYSTEM,
120 'CHANNEL' => self::IM_TYPE_CHANNEL,
121 'OPEN_CHANNEL' => self::IM_TYPE_OPEN_CHANNEL,
122 'OPEN' => self::IM_TYPE_OPEN,
123 'COPILOT' => self::IM_TYPE_COPILOT,
124 'COLLAB' => self::IM_TYPE_COLLAB,
125 'EXTERNAL' => self::IM_TYPE_EXTERNAL
126 ];
127
128 // Default entity types
129 public const
133 ENTITY_TYPE_GENERAL_CHANNEL = 'GENERAL_CHANNEL',
134 ENTITY_TYPE_PRIVATE_AI_ASSISTANT = 'AI_ASSISTANT_PRIVATE'
135 ;
136
137 //OPENLINES
138 public const
139 ENTITY_TYPE_LINE = 'LINES', //OPERATOR
140 ENTITY_TYPE_LIVECHAT = 'LIVECHAT'; //USER
141
142 protected const ENTITY_TYPES = [
143 self::ENTITY_TYPE_LINE,
144 self::ENTITY_TYPE_LIVECHAT,
145 self::ENTITY_TYPE_FAVORITE,
146 self::ENTITY_TYPE_VIDEOCONF,
147 ];
148
149 public const AVAILABLE_PARAMS = [
150 'type',
151 'entityType',
152 'entityId',
153 'entityData1',
154 'entityData2',
155 'entityData3',
156 'title',
157 'description',
158 'searchable',
159 'color',
160 'ownerId',
161 'users',
162 'managers',
163 'manageUsersAdd',
164 'manageUsersDelete',
165 'manageUi',
166 'manageSettings',
167 'messagesAutoDeleteDelay',
168 'manageMessages',
169 'avatar',
170 'conferencePassword',
171 'memberEntities',
172 ];
173
174 public const
179 ;
180
181 public const ROLE_OWNER = 'OWNER';
182 public const ROLE_MANAGER = 'MANAGER';
183 public const ROLE_MEMBER = 'MEMBER';
184 public const ROLE_GUEST = 'GUEST';
185 public const ROLE_NONE = 'NONE';
186
187 private const CHUNK_SIZE = 1000;
188 protected const EXTRANET_CAN_SEE_HISTORY = true;
190
194 protected static array $chatStaticCache = [];
195
196 protected array $accessCache = [];
197
198 protected ?int $chatId = null;
199
207 protected ?string $dialogId = null;
208
217 protected ?string $type = null;
218
219 protected ?int $authorId = null;
220
221 protected ?string $title = null;
222
223 protected ?string $description = null;
224
225 protected ?string $color = null;
226
227 protected int $parentChatId = 0;
228
229 protected int $parentMessageId = 0;
230
231 protected ?bool $extranet = null;
232
233 protected ?int $avatarId = null;
234
235 protected ?int $pinMessageId = null;
236
237 protected ?int $callType = null;
238
239 protected ?string $callNumber = null;
240
241 protected ?string $entityType = null;
242
243 protected ?string $entityId = null;
244
245 protected ?string $entityData1 = null;
246
247 protected ?string $entityData2 = null;
248
250 protected ?string $entityData3 = null;
251
252 protected ?int $diskFolderId = null;
253
254 protected ?Folder $diskFolder = null;
255
256 protected ?int $messageCount = null;
257
258 protected ?int $userCount = null;
259 protected ?int $userCounter = null;
260
261 protected ?int $prevMessageId = null;
262
263 protected ?int $lastMessageId = null;
264 protected ?int $lastFileId = null;
265 protected ?DateTime $dateMessage = null;
266
267 protected ?int $markedId = null;
268 protected ?string $role = null;
269
270 protected ?string $aliasName = null;
271
272 protected ?string $lastMessageStatus = null;
273
274 protected ?DateTime $dateCreate = null;
275
276 protected ?string $manageUsersAdd = null;
277 protected ?string $manageUsersDelete = null;
278
279 protected ?string $manageUI = null;
280
281 protected ?string $manageSettings = null;
282
283 protected ?string $manageMessages = null;
284
285 protected ?array $usersIds = null;
286
287 protected ?int $messagesAutoDeleteDelay = null;
288
289 protected ?Params $chatParams = null;
290
293
295
298
299 protected ?ReadService $readService = null;
300
302
304
305 protected bool $isFilledNonCachedData = false;
306 protected bool $isDiskFolderFilled = false;
308
312 public function __construct($source = null)
313 {
314 $this->initByDefault();
315
316 if (!empty($source))
317 {
318 $this->load($source);
319 }
320
321 $this->messageRegistry = new Registry;
322 $this->recentConfigManager = RecentConfigManager::getInstance();
323 }
324
325 //region Users
326 //endregion
327
328 //region Relations
329 //endregion
330
335 public static function getInstance(?int $chatId): self
336 {
337 if (!isset($chatId))
338 {
339 return new Im\V2\Chat\NullChat();
340 }
341
342 if (isset(self::$chatStaticCache[$chatId]))
343 {
344 return self::$chatStaticCache[$chatId];
345 }
346
347 $chat = ChatFactory::getInstance()->getChatById($chatId);
348
349 if ($chat instanceof Im\V2\Chat\NullChat)
350 {
351 return $chat;
352 }
353
354 self::$chatStaticCache[$chatId] = $chat;
355
356 return self::$chatStaticCache[$chatId];
357 }
358
359 public static function cleanCache(int $id, bool $cleanStaticCache = true): void
360 {
361 if ($cleanStaticCache)
362 {
363 unset(self::$chatStaticCache[$id]);
364 }
365
366 ChatFactory::getInstance()->cleanCache($id);
367 Im\V2\Chat\EntityLink::cleanCache($id);
368 }
369
370 public static function cleanAccessCache(int $chatId): void
371 {
372 if (isset(self::$chatStaticCache[$chatId]))
373 {
374 self::$chatStaticCache[$chatId]->accessCache = [];
375 }
376 }
377
378 public function save(): Result
379 {
380 $id = $this->getChatId();
381 $result = $this->defaultSave();
382
383 if (!$result->isSuccess())
384 {
385 return $result;
386 }
387
388 if ($id !== null && ($result->getResult()['IS_CHANGES'] ?? true) === true)
389 {
390 self::cleanCache($id);
391 }
392
393 if ($this->getChatParams()->isCreated())
394 {
395 $this->getChatParams()->saveWithNewChatId($this->getChatId());
396 }
397 else
398 {
399 $this->getChatParams()->save();
400 }
401
402 return $result;
403 }
404
405 public function getStartId(?int $userId = null): int
406 {
407 return RelationCollection::getStartId($userId ?? $this->getContext()->getUserId(), $this->getChatId());
408 }
409
410 public function isExist(): bool
411 {
412 return isset($this->chatId);
413 }
414
415 public function isCounterIncrementAllowed(): bool
416 {
417 return !empty($this->getRecentSections());
418 }
419
420 public function shouldAddToRecent(): bool
421 {
422 return !empty($this->getRecentSections());
423 }
424
425 public function getRecentSections(): array
426 {
427 return $this->recentConfigManager->getRecentSectionsByChat($this);
428 }
429
431 {
432 return $this->getRecentSections();
433 }
434
435 public function add(array $params): Result
436 {
437 return new Result();
438 }
439
440 public function containsCollaber(): bool
441 {
442 return (bool)$this->getChatParams()->get(Params::CONTAINS_COLLABER)?->getValue();
443 }
444
445 public function containsCopilot(): bool
446 {
447 return false;
448 }
449
450 protected function setUserIds(?array $userIds): self
451 {
452 $this->usersIds = $this->getValidUsersToAdd($userIds ?? []);
453
454 return $this;
455 }
456
457 public function getUserIds(): ?array
458 {
459 return $this->usersIds;
460 }
461
462 public function getAliasName(): ?string
463 {
464 return $this->aliasName;
465 }
466
467 public function setAliasName(string $aliasName): self
468 {
469 $this->aliasName = $aliasName;
470
471 return $this;
472 }
473
474 public function prepareAliasToLoad($alias): ?string
475 {
476 if (is_string($alias))
477 {
478 return $alias;
479 }
480
481 if ($alias === null)
482 {
483 return null;
484 }
485
486 return $alias['ALIAS'] ?? null;
487 }
488
489 public function getMarkedId(): int
490 {
491 if (!isset($this->markedId))
492 {
493 $this->markedId = Im\Recent::getMarkedId($this->getContext()->getUserId(), $this->getType(), $this->getDialogId());
494 }
495
496 return $this->markedId;
497 }
498
499 public function setMarkedId(?int $markedId): self
500 {
501 $this->markedId = $markedId;
502 return $this;
503 }
504
506 {
507 $this->isFilledNonCachedData = $isFilledNonCachedData;
508
509 return $this;
510 }
511
512
513
514 public function getRole(): string
515 {
516 if (isset($this->role))
517 {
518 return $this->role;
519 }
520
521 $selfRelation = $this->getSelfRelation();
522
523 if ($selfRelation === null)
524 {
525 $this->role = self::ROLE_GUEST;
526
527 return $this->role;
528 }
529
530 if ($this->getContext()->getUserId() === (int)$this->getAuthorId())
531 {
532 $this->role = self::ROLE_OWNER;
533
534 return $this->role;
535 }
536
537 elseif ($selfRelation->getManager())
538 {
539 $this->role = self::ROLE_MANAGER;
540 }
541 else
542 {
543 $this->role = self::ROLE_MEMBER;
544 }
545
546 return $this->role;
547 }
548
549 public function checkColor(): Result
550 {
551 if (!Color::isSafeColor($this->color))
552 {
553 CGlobalCounter::Increment('im_chat_color_id', CGlobalCounter::ALL_SITES, false);
554 $chatColorId = CGlobalCounter::GetValue('im_chat_color_id', CGlobalCounter::ALL_SITES);
555 $this->color = Color::getCodeByNumber($chatColorId);
556 }
557
558 return new Result();
559 }
560
561 public function setChatParams(array $chatParams = []): self
562 {
564
565 return $this;
566 }
567
568 public function getChatParams(): Params
569 {
570 $this->chatParams ??= $this->getId() !== null
571 ? Params::getInstance($this->getId())
572 : Params::loadWithoutChat([])
573 ;
574
575 return $this->chatParams;
576 }
577
578 //region Access & Permissions
579
580 final public function checkAccess(int|User|null $user = null): Result
581 {
582 $userId = $this->getUserId($user);
583
584 if (isset($this->accessCache[$userId]))
585 {
586 return $this->accessCache[$userId];
587 }
588
589 if (!$userId || !$this->getChatId())
590 {
591 $this->accessCache[$userId] = (new Result())->addError(new ChatError(ChatError::NOT_FOUND));
592
593 return $this->accessCache[$userId];
594 }
595
596 $this->accessCache[$userId] = $this->checkAccessInternal($userId);
597
598 return $this->accessCache[$userId];
599 }
600
601 protected function checkAccessInternal(int $userId): Result
602 {
603 return (new Result())->addError(new ChatError(ChatError::ACCESS_DENIED));
604 }
605
606 protected function getUserId($user): int
607 {
608 $userId = 0;
609 if ($user === null)
610 {
611 $userId = $this->getContext()->getUserId();
612 }
613 elseif (is_numeric($user))
614 {
615 $userId = (int)$user;
616 }
617 elseif ($user instanceof User)
618 {
619 $userId = $user->getId();
620 }
621
622 return $userId;
623 }
624
625
626 //endregion
627
628 //region Message
629
633 public function getMessageRegistry(): Registry
634 {
635 return $this->messageRegistry;
636 }
637
642 public function getMessage(int $messageId): ?Message
643 {
644 if (isset($this->messageRegistry[$messageId]))
645 {
646 return $this->messageRegistry[$messageId];
647 }
648
649 $message = new Message;
650 $message->setRegistry($this->messageRegistry);
651
652 $loadResult = $message->load($messageId);
653 if ($loadResult->isSuccess())
654 {
655 return $message;
656 }
657
658 return null;
659 }
660
661 public function sendMessage(Message $message, ?SendingConfig $sendingConfig = null): SendResult
662 {
663 $result = new SendResult();
664
665 $this->prepareMessage($message);
666 $sendingConfig ??= new SendingConfig();
667
668 $sendService = (new SendingService($sendingConfig))->setContext($message->getContext());
669 $onBeforeResult = $this->onBeforeMessageSend($message, $sendingConfig);
670 if (!$onBeforeResult->isSuccess())
671 {
672 return $result->addErrors($onBeforeResult->getErrors());
673 }
674
675 $checkUuidResult = $sendService->checkDuplicateByUuid($message);
676 if (!$checkUuidResult->isSuccess())
677 {
678 return $result->addErrors($checkUuidResult->getErrors());
679 }
680
681 $data = $checkUuidResult->getResult();
682 if (!empty($data['messageId']))
683 {
684 return $result->setMessageId((int)$data['messageId']);
685 }
686
687 $message->autocompleteParams($sendingConfig);
688
689 $eventResult = $sendService->fireEventBeforeSend($this, $message);
690 if (!$eventResult->isSuccess())
691 {
692 return $result->addErrors($eventResult->getErrors());
693 }
694
695 if ($message->getChatId() !== $this->getId()) // The target chat was changed in the event handler
696 {
697 return $this->processSendToOtherChat($message, $sendingConfig);
698 }
699
700 if ($message->isCompletelyEmpty())
701 {
702 return $result->addError(new MessageError(MessageError::EMPTY_MESSAGE));
703 }
704
705 $message->uploadFileFromText();
706
707 $saveResult = $message->save();
708 if (!$saveResult->isSuccess())
709 {
710 return $result->addErrors($saveResult->getErrors());
711 }
712
713 $promise = BackgroundJobPromise::deferJob(fn () => $this->onAfterMessageSend($message, $sendService));
714
715 return $result->setMessageId($message->getId())->setPromise($promise);
716 }
717
719 {
720 return new Result();
721 }
722
724 {
725 if (
726 !$message->isSystem()
727 && !$this->getContext()->getUser()->isBot()
728 && !$message->getChat()->getTextFieldEnabled()->get()
729 )
730 {
731 return (new Result())->addError(new ChatError(ChatError::TEXT_FIELD_DISABLED));
732 }
733
734 return new Result();
735 }
736
738 {
739 return $this->getRelations()->filterActive();
740 }
741
742 protected function onAfterMessageSend(Message $message, SendingService $sendingService): void
743 {
744 $authorContext = $message->getContext();
745 $sendingConfig = $sendingService->getConfig();
746
747 $sendingService->updateMessageUuid($message);
748 (new MessageAnalytics($message))->addSendMessage();
749
750 if ($sendingConfig->convertMode())
751 {
752 return;
753 }
754
755 $updateStateResult = $this->updateStateAfterMessageSend($message, $sendingConfig);
756 $counters = $updateStateResult->getResult()['COUNTERS'] ?? [];
757
758 $this->getMentionService($sendingConfig)->setContext($authorContext)->processMentions($message);
759 $this->getPushService($message, $sendingConfig)->setContext($authorContext)->sendPush($counters);
760 $sendingService->fireEventAfterMessageSend($this, $message);
761 (new Im\V2\Link\LinkFacade($sendingConfig))->setContext($authorContext)->saveLinksFromMessage($message);
762 }
763
765 {
766 $newConfig = clone $config;
767 $newConfig->skipFireEventBeforeMessageNotifySend();
768
769 return $message->getChat()->sendMessage($message, $config);
770 }
771
772 protected function prepareMessage(Message $message): void
773 {
775 ->setRegistry($this->messageRegistry)
776 ->setContextUser($message->getAuthorId() ?: $this->getContext()->getUserId())
777 ->setChatId($this->getId())
778 ->setChat($this)
779 ->filterMessageText()
780 ;
781 }
782
784 {
785 $result = new Result();
788
789 if (!$sendingConfig->addRecent())
790 {
791 return $result;
792 }
793
794 $this->updateRecentAfterMessageSend($message, $sendingConfig);
796
797 return $this->updateCountersAfterMessageSend($message, $sendingConfig);
798 }
799
801 {
802 $countMessageBeforeUpdate = $this->getMessageCount();
803 \Bitrix\Im\Model\ChatTable::update($this->getId(), [
804 'MESSAGE_COUNT' => new \Bitrix\Main\DB\SqlExpression('?# + 1', 'MESSAGE_COUNT'),
805 'LAST_MESSAGE_ID' => $message->getId(),
806 ]);
807 $this->messageCount = $countMessageBeforeUpdate + 1;
808 $this->lastMessageId = $message->getId();
809
810 return new Result();
811 }
812
814 {
815 if (!$this->shouldAddToRecent())
816 {
817 return new Result();
818 }
819
820 $usersToAddToRecent = $this->getUsersToAddToRecent();
822
823 if ($config->skipAuthorAddRecent())
824 {
825 unset($usersToAddToRecent[$message->getAuthorId()]);
826 }
827
828 $this->addToRecent($usersToAddToRecent, $message);
829
830 return new Result();
831 }
832
833 protected function getUsersToAddToRecent(): array
834 {
835 return Recent::getUsersOutOfRecent($this);
836 }
837
838 protected function updateRecentItems(Message $message): void
839 {
840 Im\Model\RecentTable::updateByFilter(
841 ['=ITEM_CID' => $this->getId()],
843 );
844 }
845
846 protected function addToRecent(array $users, Message $message): Result
847 {
848 if (empty($users))
849 {
850 return new Result();
851 }
852
853 $fields = [];
854
855 foreach ($users as $userId)
856 {
857 $field = $this->getFieldsForRecent($userId, $message);
858 if (!empty($field))
859 {
860 $fields[] = $field;
861 }
862 }
863
864 $this->insertRecent($fields);
865
866 return new Result();
867 }
868
869 protected function insertRecent(array $fields): void
870 {
871 Im\Model\RecentTable::multiplyInsertWithoutDuplicate(
872 $fields,
873 ['DEADLOCK_SAFE' => true, 'UNIQUE_FIELDS' => ['USER_ID', 'ITEM_TYPE', 'ITEM_ID']]
874 );
875 }
876
877 protected function getFieldsForRecent(int $userId, Message $message): array // todo: refactor
878 {
879 $relationId = $this->getRelations()->getByUserId($userId, $this->getId())?->getId();
880
881 if ($relationId === null)
882 {
883 return [];
884 }
885
886 return [
887 'USER_ID' => $userId,
888 'ITEM_TYPE' => $this->getType(),
889 'ITEM_ID' => $this->getId(),
890 'ITEM_MID' => $message->getId(),
891 'ITEM_CID' => $this->getId(),
892 'ITEM_RID' => $relationId,
893 'DATE_MESSAGE' => $message->getDateCreate(),
894 'DATE_LAST_ACTIVITY' => $message->getDateCreate(),
895 'DATE_UPDATE' => $message->getDateCreate(),
896 ];
897 }
898
900 {
901 return [
902 'ITEM_MID' => $message->getId(),
903 'DATE_MESSAGE' => $message->getDateCreate(),
904 'DATE_UPDATE' => $message->getDateCreate(),
905 'DATE_LAST_ACTIVITY' => $message->getDateCreate(),
906 ];
907 }
908
910 {
911 $this->getRelations()
912 ->getByUserId($message->getActionContextUserId(), $this->getId())
913 ?->setLastId($message->getId())
914 ?->setLastSendMessageId($message->getId())
915 ?->save()
916 ;
917
918 return new Result();
919 }
920
922 {
923 $skipCounterIncrement = !$this->isCounterIncrementAllowed() || $sendingConfig->skipCounterIncrements();
924
925 return $this
926 ->getReadService()
927 ->withContextUser($message->getContext()->getUserId())
928 ->onAfterMessageSend($message, $this->getRelationsForSendMessage(), $skipCounterIncrement)
929 ;
930 }
931
933 {
934 if (!$this->shouldAddToRecent())
935 {
936 return new Result();
937 }
938
940 new Sync\Event(Sync\Event::ADD_EVENT, Sync\Event::MESSAGE_ENTITY, $message->getId()),
941 $this->getRelations()->getUserIds(),
942 $this
943 );
945 new Sync\Event(Sync\Event::ADD_EVENT, Sync\Event::CHAT_ENTITY, $this->getId()),
946 $this->getRelations()->getUserIds(),
947 $this
948 );
949
950 return new Result();
951 }
952
954 {
955 return new MentionService($config);
956 }
957
963 {
964 $message->setRegistry($this->messageRegistry);
965
966 $result = new Result;
967
968 //todo: updating process here
969
970 return $result;
971 }
972
978 {
979 //todo: drop process here
980 $result = new Result;
981
982 return $result;
983 }
984
990 public static function fillSelfRelations(array $chats, ?int $userId = null): void
991 {
993 $chatIds = [];
994 foreach ($chats as $chat)
995 {
996 $chatIds[] = $chat->getId();
997 }
998
999 if (empty($chatIds))
1000 {
1001 return;
1002 }
1003
1004 $relationEntities = RelationTable::query()
1006 ->where('USER_ID', $userId)
1007 ->whereIn('CHAT_ID', $chatIds)
1008 ->fetchAll()
1009 ;
1010 $relations = new RelationCollection($relationEntities);
1011
1012 foreach ($chats as $chat)
1013 {
1014 $chat->getRelationFacade()?->preloadUserRelation($userId, $relations->getByUserId($userId, $chat->getId()));
1015 }
1016 }
1017
1018 public static function readAllChats(int $userId): Result
1019 {
1021 $readService->readAll();
1022
1024
1026 ->getReadService()
1027 ->withContextUser($userId)
1028 ->readAll();
1029
1030 if (Main\Loader::includeModule('pull'))
1031 {
1033 'module_id' => 'im',
1034 'command' => 'readAllChats',
1035 'extra' => Im\Common::getPullExtra()
1036 ]);
1037 }
1038
1039 return new Result();
1040 }
1041
1042 public function read(bool $onlyRecent = false, bool $byEvent = false): Result
1043 {
1044 Im\Recent::unread($this->getDialogId(), false, $this->getContext()->getUserId());
1045
1046 if ($onlyRecent)
1047 {
1048 $lastId = $this->getReadService()->getLastMessageIdInChat($this->chatId);
1049
1050 return (new Result())->setResult([
1051 'CHAT_ID' => $this->chatId,
1052 'LAST_ID' => $lastId,
1053 'COUNTER' => $this->getReadService()->getCounterService()->getByChat($this->chatId),
1054 'VIEWED_MESSAGES' => [],
1055 ]);
1056 }
1057
1058 return $this->readAllMessages($byEvent);
1059 }
1060
1061 public function readAllMessages(bool $byEvent = false): Result
1062 {
1063 return $this->readMessages(null, $byEvent);
1064 }
1065
1066 public function readMessages(?MessageCollection $messages, bool $byEvent = false): Result
1067 {
1068 $result = new Result();
1069
1070 if (isset($messages))
1071 {
1072 $messages = $messages->filterByChatId($this->chatId);
1073
1074 if ($messages->count() === 0)
1075 {
1076 return $result->addError(new MessageError(MessageError::MESSAGE_NOT_FOUND));
1077 }
1078 }
1079
1080 $readService = $this->getReadService();
1081 $startId = $readService->getLastIdByChatId($this->chatId);
1082 $readResult = isset($messages) ? $readService->read($messages, $this) : $readService->readAllInChat($this->chatId);
1083 $counter = $readResult->getResult()['COUNTER'] ?? 0;
1084 $viewedMessages = $readResult->getResult()['VIEWED_MESSAGES'] ?? new MessageCollection();
1085
1086 $lastId = $readService->getLastIdByChatId($this->chatId);
1087
1088 $notOwnMessages = $viewedMessages->filter(fn (Message $message) => $message->getAuthorId() !== $this->getContext()->getUserId());
1089
1090 if (Main\Loader::includeModule('pull'))
1091 {
1092 CIMNotify::DeleteBySubTag("IM_MESS_{$this->getChatId()}_{$this->getContext()->getUserId()}", false, false);
1093 CPushManager::DeleteFromQueueBySubTag($this->getContext()->getUserId(), 'IM_MESS');
1094 $this->sendPushRead($notOwnMessages, $lastId, $counter);
1095 }
1096
1097 $this->sendEventRead($startId, $lastId, $counter, $byEvent);
1098
1099 return $result->setResult([
1100 'CHAT_ID' => $this->chatId,
1101 'LAST_ID' => $lastId,
1102 'COUNTER' => $counter,
1103 'VIEWED_MESSAGES' => $notOwnMessages->getIds(),
1104 ]);
1105 }
1106
1107 public function readTo(Message $message, bool $byEvent = false): Result
1108 {
1109 $readService = $this->getReadService();
1110 $startId = $message->getMessageId();
1111 $readResult = $readService->readTo($message);
1112 $counter = $readResult->getResult()['COUNTER'] ?? 0;
1113
1114 $viewedMessages = $readResult->getResult()['VIEWED_MESSAGES'];
1115 $messageCollection = new MessageCollection();
1116 foreach ($viewedMessages as $messageId)
1117 {
1118 $viewedMessage = new Message();
1119 $viewedMessage->setMessageId((int)$messageId);
1120 $messageCollection->add($viewedMessage);
1121 }
1122
1123 $lastId = $readService->getLastIdByChatId($this->chatId);
1124
1125 if (Main\Loader::includeModule('pull'))
1126 {
1127 CIMNotify::DeleteBySubTag("IM_MESS_{$this->getChatId()}_{$this->getContext()->getUserId()}", false, false);
1128 CPushManager::DeleteFromQueueBySubTag($this->getContext()->getUserId(), 'IM_MESS');
1129 $this->sendPushRead($messageCollection, $lastId, $counter);
1130 }
1131
1132 $this->sendEventRead($startId, $lastId, $counter, $byEvent);
1133
1134 $result = new Result();
1135 return $result->setResult([
1136 'CHAT_ID' => $this->chatId,
1137 'LAST_ID' => $lastId,
1138 'COUNTER' => $counter,
1139 'VIEWED_MESSAGES' => $viewedMessages,
1140 ]);
1141 }
1142
1144 {
1145 return;
1146 }
1147
1148 protected function sendPushRead(MessageCollection $messages, int $lastId, int $counter): void
1149 {
1150 if ($this->getType() === self::ENTITY_TYPE_LIVECHAT || !$this->getContext()->getUser()->isConnector())
1151 {
1153 }
1155 }
1156
1157 public function startRecordVoice(): void
1158 {
1159 if (!Main\Loader::includeModule('pull'))
1160 {
1161 return;
1162 }
1163
1165 if ($this->getType() === self::IM_TYPE_COMMENT)
1166 {
1167 \CPullWatch::AddToStack('IM_PUBLIC_COMMENT_'.$this->getParentChatId(), $push);
1168 }
1169 else
1170 {
1171 Event::add($this->getUsersForPush(), $push);
1172 }
1173 if ($this->needToSendPublicPull())
1174 {
1175 \CPullWatch::AddToStack('IM_PUBLIC_'.$this->getId(), $push);
1176 }
1177 if ($this->getType() === self::IM_TYPE_OPEN_CHANNEL)
1178 {
1180 }
1181 }
1182
1184
1186 {
1187 $selfRelation = $this->getSelfRelation();
1188
1189 $muted = isset($selfRelation) ? $selfRelation->getNotifyBlock() : false;
1190 \Bitrix\Pull\Event::add($this->getContext()->getUserId(), [
1191 'module_id' => 'im',
1192 'command' => 'readMessageChat',
1193 'params' => [
1194 'dialogId' => $this->getDialogId(),
1195 'chatId' => $this->getChatId(),
1196 'parentChatId' => $this->getParentChatId(),
1197 'type' => $this->getExtendedType(),
1198 'lastId' => $lastId,
1199 'counter' => $counter,
1200 'muted' => $muted ?? false,
1201 'unread' => Im\Recent::isUnread($this->getContext()->getUserId(), $this->getType(), $this->getDialogId()),
1202 'lines' => $this->getType() === IM_MESSAGE_OPEN_LINE,
1203 'viewedMessages' => $messages->getIds(),
1204 'counterType' => $this->getCounterType()->value,
1205 'recentConfig' => $this->getRecentConfig()->toPullFormat(),
1206 ],
1207 'extra' => \Bitrix\Im\Common::getPullExtra()
1208 ]);
1209 }
1210
1212 {
1213 $viewedMessageIds = $messages->getIds();
1214 $pushMessage = [
1215 'module_id' => 'im',
1216 'command' => 'readMessageChatOpponent',
1217 'expiry' => 600,
1218 'params' => [
1219 'dialogId' => $this->getDialogId(),
1220 'chatId' => $this->chatId,
1221 'userId' => $this->getContext()->getUserId(),
1222 'userName' => $this->getContext()->getUser()->getName(),
1223 'lastId' => $lastId,
1224 'date' => (new DateTime())->format('c'),
1225 'viewedMessages' => $viewedMessageIds,
1226 'chatMessageStatus' => $this->getReadService()->getChatMessageStatus($this->chatId),
1227 ],
1229 ];
1230 if ($this->getType() === Chat::IM_TYPE_COMMENT)
1231 {
1232 \CPullWatch::AddToStack('IM_PUBLIC_COMMENT_' . $this->getParentChatId(), $pushMessage);
1233 }
1234 else
1235 {
1236 \Bitrix\Pull\Event::add($this->getUsersForPush(), $pushMessage);
1237 }
1238 $lastMessageId = $this->getReadService()->getLastMessageIdInChat($this->chatId);
1239 $maxViewedMessageId = !empty($viewedMessageIds) ? max($viewedMessageIds) : 0;
1240
1241 if ($this->needToSendPublicPull())
1242 {
1243 \CPullWatch::AddToStack("IM_PUBLIC_{$this->chatId}", $pushMessage);
1244 }
1245 if ($this->getType() === Chat::IM_TYPE_OPEN_CHANNEL && $maxViewedMessageId === $lastMessageId)
1246 {
1248 }
1249
1250 return $pushMessage;
1251 }
1252
1253 protected function sendEventRead(int $startId, int $endId, int $counter, bool $byEvent): void
1254 {
1255 foreach (\GetModuleEvents("im", "OnAfterChatRead", true) as $arEvent)
1256 {
1257 \ExecuteModuleEventEx($arEvent, array(Array(
1258 'CHAT_ID' => $this->chatId,
1259 'CHAT_ENTITY_TYPE' => $this->getEntityType(),
1260 'CHAT_ENTITY_ID' => $this->getEntityId(),
1261 'START_ID' => $startId,
1262 'END_ID' => $endId,
1263 'COUNT' => $counter,
1264 'USER_ID' => $this->getContext()->getUserId(),
1265 'BY_EVENT' => $byEvent
1266 )));
1267 }
1268 }
1269
1270 public function getLastMessageViews(): array
1271 {
1272 $lastMessageViewsByGroups = $this->getLastMessageViewsByGroups();
1273
1274 if (isset($lastMessageViewsByGroups['USERS'][$this->getContext()->getUserId()]))
1275 {
1276 return $lastMessageViewsByGroups['FOR_VIEWERS'];
1277 }
1278
1279 return $lastMessageViewsByGroups['FOR_NOT_VIEWERS'];
1280 }
1281
1283 {
1284 $defaultViewInfo = [
1285 'MESSAGE_ID' => 0,
1286 'FIRST_VIEWERS' => [],
1287 'COUNT_OF_VIEWERS' => 0,
1288 ];
1289 $defaultValue = [
1290 'USERS' => [],
1291 'FOR_VIEWERS' => $defaultViewInfo,
1292 'FOR_NOT_VIEWERS' => $defaultViewInfo,
1293 ];
1294
1295 $readService = $this->getReadService();
1296
1297 $lastMessageInChat = $this->getLastMessageId() ?? 0;
1298
1299 if ($lastMessageInChat === 0)
1300 {
1301 return $defaultValue;
1302 }
1303
1304 $messageViewers = $readService->getViewedService()->getMessageViewersIds($lastMessageInChat);
1305 $countOfView = count($messageViewers);
1306
1307 $firstViewers = [];
1308
1309 foreach ($messageViewers as $messageViewer)
1310 {
1311 if (count($firstViewers) >= 2)
1312 {
1313 break;
1314 }
1315
1316 $firstViewers[$messageViewer] = $messageViewer;
1317 }
1318
1319 $datesOfViews = $readService->getViewedService()->getDateViewedByMessageIdForEachUser($lastMessageInChat, $firstViewers);
1320
1321 $firstViewersWithDate = [];
1322
1323 foreach ($firstViewers as $viewer)
1324 {
1325 $firstViewersWithDate[] = [
1326 'USER_ID' => $viewer,
1327 'USER_NAME' => Im\V2\Entity\User\User::getInstance($viewer)->getName(),
1328 'DATE' => $datesOfViews[$viewer] ?? null
1329 ];
1330 }
1331
1332 $viewsInfoByGroups = ['USERS' => $messageViewers];
1333 $viewInfoForViewers = [
1334 'MESSAGE_ID' => $lastMessageInChat,
1335 'FIRST_VIEWERS' => $firstViewersWithDate,
1336 'COUNT_OF_VIEWERS' => $countOfView - 1,
1337 ];
1338 $viewInfoForNotViewers = $viewInfoForViewers;
1339 ++$viewInfoForNotViewers['COUNT_OF_VIEWERS'];
1340 $viewsInfoByGroups['FOR_VIEWERS'] = $viewInfoForViewers;
1341 $viewsInfoByGroups['FOR_NOT_VIEWERS'] = $viewInfoForNotViewers;
1342
1343 return $viewsInfoByGroups;
1344 }
1345
1346 protected function getUsersForPush(bool $skipBot = false, bool $skipSelf = true): array
1347 {
1348 $userId = $this->getContext()->getUserId();
1349 $isLineChat = $this->getEntityType() === self::ENTITY_TYPE_LINE;
1350 $relations = $this->getRelations();
1351 $userIds = [];
1352 foreach ($relations as $relation)
1353 {
1354 if ($skipSelf && $relation->getUserId() === $userId)
1355 {
1356 continue;
1357 }
1358 if ($skipBot && $relation->getUser()->isBot())
1359 {
1360 continue;
1361 }
1362 if ($isLineChat && $relation->getUser()->isConnector())
1363 {
1364 continue;
1365 }
1366 $userIds[] = $relation->getUserId();
1367 }
1368
1369 return $userIds;
1370 }
1371
1372 //endregion
1373
1374 //region Data storage
1375
1379 protected static function mirrorDataEntityFields(): array
1380 {
1381 return [
1382 'ID' => [
1383 'primary' => true,
1384 'field' => 'chatId',
1385 'set' => 'setChatId',
1386 'get' => 'getChatId',
1387 ],
1388 'CHAT_ID' => [
1389 'alias' => 'ID',
1390 ],
1391 'TYPE' => [
1392 'field' => 'type',
1393 'set' => 'setType',
1394 'get' => 'getType',
1395 'default' => 'getDefaultType',
1396 'beforeSave' => 'beforeSaveType',
1397 ],
1398 'AUTHOR_ID' => [
1399 'field' => 'authorId',
1400 'set' => 'setAuthorId',
1401 'get' => 'getAuthorId',
1402 ],
1403 'CHAT_AUTHOR_ID' => [
1404 'alias' => 'AUTHOR_ID',
1405 ],
1406 'COLOR' => [
1407 'field' => 'color',
1408 'get' => 'getColor',
1409 'set' => 'setColor',
1410 'beforeSave' => 'checkColor',
1411 // 'beforeSave' => 'validateColor', /** @see Chat::validateColor */
1412 //'default' => 'getDefaultColor', /** @see Chat::getDefaultColor */
1413 ],
1414 'TITLE' => [
1415 'field' => 'title',
1416 'set' => 'setTitle',
1417 'get' => 'getTitle',
1418 'beforeSave' => 'checkTitle',
1419 //'default' => 'getDefaultTitle', /** @see Chat::getDefaultTitle */
1420 ],
1421 'DESCRIPTION' => [
1422 'field' => 'description',
1423 'get' => 'getDescription',
1424 'set' => 'setDescription',
1425 'nullable' => true,
1426 ],
1427 'PARENT_ID' => [
1428 'field' => 'parentChatId',
1429 'get' => 'getParentId',
1430 'set' => 'setParentId',
1431 ],
1432 'PARENT_MID' => [
1433 'field' => 'parentMessageId',
1434 'get' => 'getParentMessageId',
1435 'set' => 'setParentMessageId',
1436 ],
1437 'EXTRANET' => [
1438 'field' => 'extranet',
1439 'get' => 'getExtranet',
1440 'set' => 'setExtranet',
1441 'default' => 'getDefaultExtranet',
1442 ],
1443 'AVATAR' => [
1444 'field' => 'avatarId',
1445 'get' => 'getAvatarId',
1446 'set' => 'setAvatarId',
1447 ],
1448 'PIN_MESSAGE_ID' => [
1449 'field' => 'pinMessageId',
1450 'get' => 'getPinMessageId',
1451 'set' => 'setPinMessageId',
1452 ],
1453 'CALL_TYPE' => [
1454 'field' => 'callType',
1455 'get' => 'getCallType',
1456 'set' => 'setCallType',
1457 ],
1458 'CALL_NUMBER' => [
1459 'field' => 'callNumber',
1460 'get' => 'getCallNumber',
1461 'set' => 'setCallNumber',
1462 ],
1463 'ENTITY_TYPE' => [
1464 'field' => 'entityType',
1465 'get' => 'getEntityType',
1466 'set' => 'setEntityType',
1467 'default' => 'getDefaultEntityType',
1468 ],
1469 'ENTITY_ID' => [
1470 'field' => 'entityId',
1471 'get' => 'getEntityId',
1472 'set' => 'setEntityId',
1473 ],
1474 'ENTITY_DATA_1' => [
1475 'field' => 'entityData1',
1476 'get' => 'getEntityData1',
1477 'set' => 'setEntityData1',
1478 ],
1479 'ENTITY_DATA_2' => [
1480 'field' => 'entityData2',
1481 'get' => 'getEntityData2',
1482 'set' => 'setEntityData2',
1483 ],
1484 'ENTITY_DATA_3' => [
1485 'field' => 'entityData3',
1486 'get' => 'getEntityData3',
1487 'set' => 'setEntityData3',
1488 ],
1489 'DISK_FOLDER_ID' => [
1490 'field' => 'diskFolderId',
1491 'get' => 'getDiskFolderId',
1492 'set' => 'setDiskFolderId',
1493 ],
1494 'MESSAGE_COUNT' => [
1495 'field' => 'messageCount',
1496 'get' => 'getMessageCount',
1497 'set' => 'setMessageCount',
1498 ],
1499 'USER_COUNT' => [
1500 'field' => 'userCount',
1501 'get' => 'getUserCount',
1502 'set' => 'setUserCount',
1503 ],
1504 'PREV_MESSAGE_ID' => [
1505 'field' => 'prevMessageId',
1506 'get' => 'getPrevMessageId',
1507 'set' => 'setPrevMessageId',
1508 ],
1509 'LAST_MESSAGE_ID' => [
1510 'field' => 'lastMessageId',
1511 'get' => 'getLastMessageId',
1512 'set' => 'setLastMessageId',
1513 ],
1514 'LAST_MESSAGE_STATUS' => [
1515 'field' => 'lastMessageStatus',
1516 'get' => 'getLastMessageStatus',
1517 'set' => 'setLastMessageStatus',
1518 'default' => 'getDefaultLastMessageStatus',
1519 ],
1520 'DATE_CREATE' => [
1521 'field' => 'dateCreate',
1522 'get' => 'getDateCreate',
1523 'set' => 'setDateCreate',
1524 'default' => 'getDefaultDateCreate',
1525 ],
1526 'MANAGE_USERS_ADD' => [
1527 'field' => 'manageUsersAdd',
1528 'get' => 'getManageUsersAdd',
1529 'set' => 'setManageUsersAdd',
1530 'default' => 'getDefaultManageUsersAdd',
1531 ],
1532 'MANAGE_USERS_DELETE' => [
1533 'field' => 'manageUsersDelete',
1534 'get' => 'getManageUsersDelete',
1535 'set' => 'setManageUsersDelete',
1536 'default' => 'getDefaultManageUsersDelete',
1537 ],
1538 'MANAGE_UI' => [
1539 'field' => 'manageUI',
1540 'get' => 'getManageUI',
1541 'set' => 'setManageUI',
1542 'default' => 'getDefaultManageUI',
1543 ],
1544 'MANAGE_SETTINGS' => [
1545 'field' => 'manageSettings',
1546 'get' => 'getManageSettings',
1547 'set' => 'setManageSettings',
1548 'default' => 'getDefaultManageSettings',
1549 ],
1550 'MANAGE_MESSAGES_AUTO_DELETE' => [
1551 'get' => 'getManageMessagesAutoDelete',
1552 'set' => 'setManageMessagesAutoDelete',
1553 'default' => 'getDefaultManageMessagesAutoDelete',
1554 'skipSave' => true,
1555 ],
1556 'DISAPPEARING_TIME' => [
1557 'field' => 'messagesAutoDeleteDelay',
1558 'get' => 'getMessagesAutoDeleteDelay',
1559 'set' => 'setMessagesAutoDeleteDelay',
1560 'default' => 'getDefaultMessagesAutoDeleteDelay',
1561 ],
1562 'MESSAGES_AUTO_DELETE_DELAY' => [
1563 'alias' => 'DISAPPEARING_TIME',
1564 ],
1565 'CAN_POST' => [
1566 'field' => 'manageMessages',
1567 'get' => 'getManageMessages',
1568 'set' => 'setManageMessages',
1569 'default' => 'getDefaultManageMessages',
1570 ],
1571 'MANAGE_MESSAGES' => [
1572 'alias' => 'CAN_POST'
1573 ],
1574 'USERS' => [
1575 'get' => 'getUserIds',
1576 'set' => 'setUserIds',
1577 ],
1578 'ALIAS' => [
1579 'field' => 'aliasName',
1580 'get' => 'getAliasName',
1581 'set' => 'setAliasName',
1582 'loadFilter' => 'prepareAliasToLoad',
1583 'skipSave' => true,
1584 ],
1585 'RELATIONS' => [
1586 'set' => 'setRelations',
1587 'skipSave' => true,
1588 ],
1589 'CHAT_PARAMS' => [
1590 'set' => 'setChatParams',
1591 'skipSave' => true,
1592 ],
1593 ];
1594 }
1595
1599 public static function getDataClass(): string
1600 {
1601 return ChatTable::class;
1602 }
1603
1607 public function getPrimaryId(): ?int
1608 {
1609 return $this->getChatId();
1610 }
1611
1616 public function setPrimaryId(int $primaryId): self
1617 {
1618 return $this->setChatId($primaryId);
1619 }
1620
1621 //endregion
1622
1623 //region Search
1624
1632 public static function find(array $params, ?Context $context = null): Result
1633 {
1634 $result = new Result;
1635
1636 if ($params['CHAT_ID'] <= 0)
1637 {
1638 return $result->addError(new ChatError(ChatError::WRONG_PARAMETER));
1639 }
1640
1642
1643 $context = $context ?? Locator::getContext();
1644
1645 if ($context->getUserId() == 0)
1646 {
1647 $res = $connection->query("
1648 SELECT
1649 C.ID as CHAT_ID,
1650 C.PARENT_ID as CHAT_PARENT_ID,
1651 C.PARENT_MID as CHAT_PARENT_MID,
1652 C.TITLE as CHAT_TITLE,
1653 C.AUTHOR_ID as CHAT_AUTHOR_ID,
1654 C.TYPE as CHAT_TYPE,
1655 C.AVATAR as CHAT_AVATAR,
1656 C.COLOR as CHAT_COLOR,
1657 C.ENTITY_TYPE as CHAT_ENTITY_TYPE,
1658 C.ENTITY_ID as CHAT_ENTITY_ID,
1659 C.ENTITY_DATA_1 as CHAT_ENTITY_DATA_1,
1660 C.ENTITY_DATA_2 as CHAT_ENTITY_DATA_2,
1661 C.ENTITY_DATA_3 as CHAT_ENTITY_DATA_3,
1662 C.EXTRANET as CHAT_EXTRANET,
1663 C.PREV_MESSAGE_ID as CHAT_PREV_MESSAGE_ID,
1664 '1' as RID,
1665 'Y' as IS_MANAGER
1666 FROM b_im_chat C
1667 WHERE C.ID = ".(int)$params['CHAT_ID']."
1668 ");
1669 }
1670 else
1671 {
1672 if (empty($params['FROM_USER_ID']))
1673 {
1674 $params['FROM_USER_ID'] = $context->getUserId();
1675 }
1676
1677 $params['FROM_USER_ID'] = (int)$params['FROM_USER_ID'];
1678 if ($params['FROM_USER_ID'] <= 0)
1679 {
1680 return $result->addError(new ChatError(ChatError::WRONG_SENDER));
1681 }
1682
1683 $res = $connection->query("
1684 SELECT
1685 C.ID as CHAT_ID,
1686 C.PARENT_ID as CHAT_PARENT_ID,
1687 C.PARENT_MID as CHAT_PARENT_MID,
1688 C.TITLE as CHAT_TITLE,
1689 C.AUTHOR_ID as CHAT_AUTHOR_ID,
1690 C.TYPE as CHAT_TYPE,
1691 C.AVATAR as CHAT_AVATAR,
1692 C.COLOR as CHAT_COLOR,
1693 C.ENTITY_TYPE as CHAT_ENTITY_TYPE,
1694 C.ENTITY_ID as CHAT_ENTITY_ID,
1695 C.ENTITY_DATA_1 as CHAT_ENTITY_DATA_1,
1696 C.ENTITY_DATA_2 as CHAT_ENTITY_DATA_2,
1697 C.ENTITY_DATA_3 as CHAT_ENTITY_DATA_3,
1698 C.EXTRANET as CHAT_EXTRANET,
1699 C.PREV_MESSAGE_ID as CHAT_PREV_MESSAGE_ID,
1700 R.USER_ID as RID,
1701 R.MANAGER as IS_MANAGER
1702 FROM b_im_chat C
1703 LEFT JOIN b_im_relation R
1704 ON R.CHAT_ID = C.ID
1705 AND R.USER_ID = ".$params['FROM_USER_ID']."
1706 WHERE C.ID = ".(int)$params['CHAT_ID']."
1707 ");
1708 }
1709
1710 if ($row = $res->fetch())
1711 {
1712 $result->setResult([
1713 'ID' => (int)$row['CHAT_ID'],
1714 'TYPE' => $row['CHAT_TYPE'],
1715 'ENTITY_TYPE' => $row['CHAT_ENTITY_TYPE'],
1716 'ENTITY_ID' => $row['CHAT_ENTITY_ID'],
1717 /*'RELATIONS' => [
1718 (int)$row['RID'] => [
1719 'CHAT_ID' => (int)$row['CHAT_ID'],
1720 'USER_ID' => (int)$row['RID'],
1721 'IS_MANAGER' => $row['IS_MANAGER'],
1722 ]
1723 ]*/
1724 ]);
1725 }
1726
1727 return $result;
1728 }
1729
1737 public static function getSharedChatsWithUser(int $userId, int $limit = 50, int $offset = 0, ?int $currentUserId = null): array
1738 {
1739 $currentUserId ??= Im\V2\Entity\User\User::getCurrent()->getId();
1740 //todo: change with ChatCollection
1741 $chats = [];
1742 $types = [
1743 self::IM_TYPE_CHAT,
1744 self::IM_TYPE_OPEN,
1745 self::IM_TYPE_CHANNEL,
1746 self::IM_TYPE_OPEN_CHANNEL,
1747 self::IM_TYPE_COLLAB,
1748 ];
1749
1750 $recentCollection = Im\Model\RecentTable::query()
1751 ->setSelect(['ITEM_ID', 'DATE_MESSAGE'])
1752 ->registerRuntimeField(
1753 new Reference(
1754 'RELATION',
1755 RelationTable::class,
1756 Join::on('this.ITEM_ID', 'ref.CHAT_ID')
1757 ->where('this.USER_ID', $currentUserId)
1758 ->where('ref.USER_ID', $userId)
1759 ->whereIn('this.ITEM_TYPE', $types),
1760 ['join_type' => Join::TYPE_INNER]
1761 )
1762 )
1763 ->setOrder(['DATE_MESSAGE' => 'DESC'])
1764 ->setLimit($limit)
1765 ->setOffset($offset)
1766 ->fetchCollection()
1767 ;
1768
1769 foreach ($recentCollection as $recentItem)
1770 {
1771 $chat = self::getInstance($recentItem->getItemId());
1772 if ($chat instanceof Im\V2\Chat\NullChat)
1773 {
1774 continue;
1775 }
1776 $chat->dateMessage = $recentItem->getDateMessage();
1777 $chats[$chat->getId()] = $chat;
1778 }
1779
1780 return $chats;
1781 }
1782
1783 //endregion
1784
1785
1786 //region Setters & Getters
1787
1788 protected function setChatId(int $chatId): self
1789 {
1790 if (!$this->chatId)
1791 {
1792 $this->chatId = $chatId;
1793 }
1794 return $this;
1795 }
1796
1797 public function getChatId(): ?int
1798 {
1799 return $this->chatId;
1800 }
1801
1802 public function getId(): ?int
1803 {
1804 return $this->getChatId();
1805 }
1806
1811 public function setDialogId(string $dialogId): self
1812 {
1813 $this->dialogId = $dialogId;
1814
1816 {
1818 if (!$this->getType())
1819 {
1820 $this->setType(self::IM_TYPE_CHAT);
1821 }
1822 }
1823 else
1824 {
1825 if (!$this->getType())
1826 {
1827 $this->setType(self::IM_TYPE_PRIVATE);
1828 }
1829 }
1830
1831 return $this;
1832 }
1833
1838 abstract public function allowMention(): bool;
1839
1840 public function filterUsersToMention(array $userIds): array
1841 {
1842 $result = [];
1843 $relations = $this->getRelationsByUserIds($userIds);
1844
1845 foreach ($userIds as $userId)
1846 {
1847 $relation = $relations->getByUserId($userId, $this->getChatId());
1848 if (
1849 $relation !== null
1850 && $relation->getNotifyBlock()
1852 )
1853 {
1855 }
1856 }
1857
1858 return $result;
1859 }
1860
1861 public function filterUsersToMentionAnchor(array $userIds): array
1862 {
1863 $result = [];
1864 $relations = $this->getRelationsByUserIds($userIds);
1865
1866 foreach ($userIds as $userId)
1867 {
1868 $relation = $relations->getByUserId($userId, $this->getChatId());
1869 if ($relation !== null)
1870 {
1872 }
1873 }
1874
1875 return $result;
1876 }
1877
1878 public function getDialogId(?int $contextUserId = null): ?string
1879 {
1880 if ($this->dialogId || !$this->getChatId())
1881 {
1882 return $this->dialogId;
1883 }
1884
1885 $this->dialogId = 'chat'. $this->getChatId();
1886
1887 return $this->dialogId;
1888 }
1889
1890 public function getDialogContextId(): ?string
1891 {
1892 return $this->getDialogId();
1893 }
1894
1901 public static function getDialogIdByContextId(string $contextId, ?int $userId = null): string
1902 {
1903 $userId ??= Locator::getContext()->getUserId();
1904
1905 [$dialogContextId] = explode('/', $contextId);
1906 if (str_starts_with($dialogContextId, 'chat'))
1907 {
1908 return $dialogContextId;
1909 }
1910
1911 $userIds = explode(':', $dialogContextId);
1912
1913 foreach ($userIds as $contextUserId)
1914 {
1915 if ((int)$contextUserId !== $userId)
1916 {
1917 return $contextUserId;
1918 }
1919 }
1920
1921 return '0';
1922 }
1923
1928 public function setType(string $type): self
1929 {
1930 if (!in_array($type, self::IM_TYPES))
1931 {
1932 if (in_array($type, array_keys(self::IM_TYPES_TRANSLATE), true))
1933 {
1934 $type = self::IM_TYPES_TRANSLATE[$type];
1935 }
1936 else
1937 {
1938 $type = $this->getDefaultType();
1939 }
1940 }
1941
1942 $this->type = $type;
1943 return $this;
1944 }
1945
1946 public function getType(): string
1947 {
1948 if (!$this->type)
1949 {
1950 $this->type = $this->getDefaultType();
1951 }
1952
1953 return $this->type;
1954 }
1955
1956 abstract protected function getDefaultType(): string;
1957
1958 public function getCounterType(): CounterType
1959 {
1960 return CounterType::tryFromChat($this);
1961 }
1962
1963 protected function beforeSaveType(): Result
1964 {
1965 $check = new Result;
1966
1967 if (!in_array($this->type, self::IM_TYPES, true))
1968 {
1969 $check->addError(new ChatError(ChatError::WRONG_TYPE,'Wrong chat type'));
1970 }
1971
1972 return $check;
1973 }
1974
1975 // Author
1976 public function setAuthorId(int $authorId): self
1977 {
1978 $this->authorId = $authorId;
1979 return $this;
1980 }
1981
1982 public function getAuthorId(): ?int
1983 {
1984 return $this->authorId;
1985 }
1986
1987 public function getAuthor(): Entity\User\User
1988 {
1990 }
1991
1992 // Chat title
1993 public function setTitle(?string $title): self
1994 {
1995 $this->title = $title ? mb_substr(trim($title), 0, 255) : null;
1996 return $this;
1997 }
1998
1999 public function getTitle(): ?string
2000 {
2001 return $this->title;
2002 }
2003
2004 public function getDisplayedTitle(): ?string
2005 {
2006 return $this->title;
2007 }
2008
2009 // Chat description
2010 public function setDescription(?string $description): self
2011 {
2012 $this->description = $description ? trim($description) : null;
2013 return $this;
2014 }
2015
2016 public function getDescription(): ?string
2017 {
2018 return $this->description;
2019 }
2020
2021 // Chat color
2022 public function setColor(?string $color): self
2023 {
2024 $this->color = $color ? trim($color) : null;
2025 return $this;
2026 }
2027
2028 public function getColor(bool $forRest = false): ?string
2029 {
2030 if ($forRest)
2031 {
2032 $color = $this->color ?? '';
2033 return $color !== '' ? Color::getColor($color) : Color::getColorByNumber($this->getId());
2034 }
2035
2036 return $this->color;
2037 }
2038
2039 public function validateColor(): Result
2040 {
2041 $check = new Result;
2042 if (!Color::isSafeColor($this->color))
2043 {
2044 $check->addError(new ChatError(ChatError::WRONG_COLOR,'Wrong chat color'));
2045 }
2046 return $check;
2047 }
2048
2049 public function getDefaultColor(): string
2050 {
2051 $color = '';
2052
2053 return $color;
2054 }
2055
2056 // parent chat
2057 public function setParentChatId(int $parentChatId): self
2058 {
2059 $this->parentChatId = $parentChatId > 0 ? $parentChatId : 0;
2060 return $this;
2061 }
2062
2063 public function getParentChatId(): ?int
2064 {
2065 return $this->parentChatId;
2066 }
2067
2068 // parent message
2069 public function setParentMessageId(int $messageId): self
2070 {
2071 $this->parentMessageId = $messageId > 0 ? $messageId : 0;
2072 return $this;
2073 }
2074
2075 public function getParentMessageId(): int
2076 {
2077 return $this->parentMessageId;
2078 }
2079
2080 // extranet
2081 public function setExtranet(?bool $extranet): self
2082 {
2083 $this->extranet = is_bool($extranet) ? $extranet : null;
2084 return $this;
2085 }
2086
2087 public function getExtranet(): ?bool
2088 {
2089 return $this->extranet;
2090 }
2091
2092 public function getDefaultExtranet(): bool
2093 {
2094 return false;
2095 }
2096
2097 // avatar's file Id
2098 public function setAvatarId(?int $avatarId): self
2099 {
2100 $this->avatarId = is_integer($avatarId) ? $avatarId : null;
2101 return $this;
2102 }
2103
2104 public function getAvatarId(): ?int
2105 {
2106 return $this->avatarId;
2107 }
2108
2109 public function getAvatar(bool $addBlankPicture = false, bool $withDomain = false): string
2110 {
2111 return (new Im\V2\Entity\File\ChatAvatar($this))->get($addBlankPicture, $withDomain);
2112 }
2113
2114 // pined message Id
2115 public function setPinMessageId(?int $pinMessageId): self
2116 {
2117 $this->pinMessageId = is_integer($pinMessageId) ? $pinMessageId : null;
2118 return $this;
2119 }
2120
2121 public function getPinMessageId(): ?int
2122 {
2123 return $this->pinMessageId;
2124 }
2125
2126 // callType
2127 public function setCallType(?int $callType): self
2128 {
2129 $this->callType = is_integer($callType) ? $callType : null;
2130 return $this;
2131 }
2132
2133 public function getCallType(): ?int
2134 {
2135 return $this->callType;
2136 }
2137
2138 // callNumber
2139 public function setCallNumber(?string $callNumber): self
2140 {
2141 $this->callNumber = $callNumber ? trim($callNumber) : null;
2142 return $this;
2143 }
2144
2145 public function getCallNumber(): ?string
2146 {
2147 return $this->callNumber;
2148 }
2149
2150 // entity Type
2151 public function setEntityType(?string $entityType): self
2152 {
2153 $this->entityType = $entityType ? trim($entityType) : null;
2154 return $this;
2155 }
2156
2157 public function getEntityType(): ?string
2158 {
2159 if ($this->entityType)
2160 {
2161 return $this->entityType;
2162 }
2163
2164 return $this->getDefaultEntityType();
2165 }
2166
2167 protected function getDefaultEntityType(): ?string
2168 {
2169 return null;
2170 }
2171
2172 // entity Id
2173 public function setEntityId(?string $entityId): self
2174 {
2175 $this->entityId = $entityId ? trim($entityId) : null;
2176 return $this;
2177 }
2178
2179 public function getEntityId(): ?string
2180 {
2181 return $this->entityId;
2182 }
2183
2184 // entity Data1
2185 public function setEntityData1(?string $entityData1): self
2186 {
2187 $this->entityData1 = $entityData1 ? trim($entityData1) : null;
2188 return $this;
2189 }
2190
2191 public function getEntityData1(): ?string
2192 {
2193 return $this->entityData1;
2194 }
2195
2196 // entity Data2
2197 public function setEntityData2(?string $entityData2): self
2198 {
2199 $this->entityData2 = $entityData2 ? trim($entityData2) : null;
2200 return $this;
2201 }
2202
2203 public function getEntityData2(): ?string
2204 {
2205 return $this->entityData2;
2206 }
2207
2208 // entityData3
2209 public function setEntityData3(?string $entityData3): self
2210 {
2211 $this->entityData3 = $entityData3 ? trim($entityData3) : null;
2212 return $this;
2213 }
2214
2215 public function getEntityData3(): ?string
2216 {
2217 return $this->entityData3;
2218 }
2219
2220 // disk Folder Id
2221 public function setDiskFolderId(?int $diskFolderId): self
2222 {
2223 $this->diskFolderId = is_integer($diskFolderId) ? $diskFolderId : null;
2224 return $this;
2225 }
2226
2227 public function getDiskFolderId(): ?int
2228 {
2229 return $this->diskFolderId;
2230 }
2231
2232 protected function setDiskFolder(?Folder $folder): void
2233 {
2234 $this->isDiskFolderFilled = true;
2235 $this->diskFolder = $folder;
2236 }
2237
2238 public function getOrCreateDiskFolder(): ?Folder
2239 {
2240 $folder = $this->getDiskFolder();
2241
2242 if ($folder === null)
2243 {
2244 $folder = $this->createDiskFolder();
2245 $this->setDiskFolder($folder);
2246 }
2247
2248 return $folder;
2249 }
2250
2251 public function getStorageId(): int
2252 {
2253 return (int)Option::get('im', 'disk_storage_id', 0);
2254 }
2255
2256 public function getDiskFolder(): ?Folder
2257 {
2258 if (!Main\Loader::includeModule('disk'))
2259 {
2260 return null;
2261 }
2262
2263 if ($this->isDiskFolderFilled)
2264 {
2265 return $this->diskFolder;
2266 }
2267
2268 $diskFolderId = $this->getDiskFolderId();
2269 $folder = null;
2270
2271 if ($diskFolderId !== null && $diskFolderId !== 0)
2272 {
2273 $folder = \Bitrix\Disk\Folder::getById($diskFolderId);
2274 if (!($folder instanceof Folder) || (int)$folder->getStorageId() !== \CIMDisk::GetStorageId($this->chatId))
2275 {
2276 $folder = null;
2277 }
2278 }
2279
2280 $this->setDiskFolder($folder);
2281
2282 return $folder;
2283 }
2284
2285 protected function createDiskFolder(): ?Folder
2286 {
2287 $storage = \CIMDisk::GetStorage($this->chatId);
2288
2289 if (!$storage)
2290 {
2291 return null;
2292 }
2293
2294 $folderModel = $storage->addFolder(
2295 [
2296 'NAME' => "chat{$this->getId()}",
2297 'CREATED_BY' => $this->getContext()->getUserId(),
2298 ],
2300 true
2301 );
2302
2303 if ($folderModel)
2304 {
2305 $this->setDiskFolderId($folderModel->getId())->save();
2306 $accessProvider = new \Bitrix\Im\Access\ChatAuthProvider;
2307 $accessProvider->updateChatCodesByRelations($this->getId());
2308 }
2309
2310 return $folderModel;
2311 }
2312
2314 {
2315 $accessProvider = new \Bitrix\Im\Access\ChatAuthProvider;
2316 $driver = \Bitrix\Disk\Driver::getInstance();
2317 $rightsManager = $driver->getRightsManager();
2318 $accessCodes = [];
2319 // allow for access code `CHATxxx`
2320 $accessCodes[] = [
2321 'ACCESS_CODE' => $accessProvider->generateAccessCode($this->getId()),
2322 'TASK_ID' => $rightsManager->getTaskIdByName($rightsManager::TASK_EDIT)
2323 ];
2324
2325 return $accessCodes;
2326 }
2327
2328 // message Count
2329 public function setMessageCount(int $messageCount): self
2330 {
2331 $this->messageCount = $messageCount > 0 ? $messageCount : 0;
2332 return $this;
2333 }
2334
2335 public function getMessageCount(): int
2336 {
2337 $this->fillNonCachedData();
2338
2339 return $this->messageCount ?? 0;
2340 }
2341
2342 // user Count
2343 public function setUserCount(int $userCount): self
2344 {
2345 $this->userCount = $userCount > 0 ? $userCount : 0;
2346 return $this;
2347 }
2348
2349 public function getUserCount(): int
2350 {
2351 $this->fillNonCachedData();
2352
2353 return $this->userCount;
2354 }
2355
2356 public function setUserCounter(?int $userCounter): self
2357 {
2358 $this->userCounter = $userCounter;
2359 return $this;
2360 }
2361
2362 public function getUserCounter(): ?int
2363 {
2364 if ($this->userCounter === null)
2365 {
2366 $this->userCounter = $this->getReadService()->getCounterService()->getByChat($this->getChatId());
2367 }
2368
2369 return $this->userCounter;
2370 }
2371
2372 // prev Message Id
2373 public function setPrevMessageId(int $prevMessageId): self
2374 {
2375 $this->prevMessageId = $prevMessageId > 0 ? $prevMessageId : 0;
2376 return $this;
2377 }
2378
2379 public function getPrevMessageId(): int
2380 {
2381 return $this->prevMessageId;
2382 }
2383
2384 // last Message Id
2385 public function setLastMessageId(int $lastMessageId): self
2386 {
2387 $this->lastMessageId = $lastMessageId > 0 ? $lastMessageId : 0;
2388 return $this;
2389 }
2390
2391 public function getLastMessageId(): ?int
2392 {
2393 $this->fillNonCachedData();
2394
2395 return $this->lastMessageId;
2396 }
2397
2398 public function getLastFileId(): int
2399 {
2400 $this->lastFileId ??= \CIMDisk::GetMaxFileId($this->getId());
2401
2402 return $this->lastFileId;
2403 }
2404
2405 // last Message Status
2406 public function setLastMessageStatus(?string $lastMessageStatus): self
2407 {
2408 $this->lastMessageStatus = $lastMessageStatus ? trim($lastMessageStatus) : null;
2409 return $this;
2410 }
2411
2412 public function getLastMessageStatus(): ?string
2413 {
2414 return $this->lastMessageStatus;
2415 }
2416
2417 public function getDefaultLastMessageStatus(): string
2418 {
2419 return \IM_MESSAGE_STATUS_RECEIVED;
2420 }
2421
2422 // Create date
2423 public function setDateCreate(?DateTime $dateCreate): self
2424 {
2425 $this->dateCreate = $dateCreate ? $dateCreate : null;
2426 return $this;
2427 }
2428
2429 public function getDateCreate(): ?DateTime
2430 {
2431 return $this->dateCreate;
2432 }
2433
2435 {
2436 return new DateTime;
2437 }
2438
2439 protected function getReadService(): ReadService
2440 {
2441 if ($this->readService === null)
2442 {
2443 $this->readService = new ReadService();
2444 $this->readService->setContext($this->context);
2445 }
2446
2447 return $this->readService;
2448 }
2449
2455 {
2456 return $this->getRelationFacade()?->get() ?? new RelationCollection();
2457 }
2458
2460 {
2461 return $this->getRelationFacade()?->getRawFullRelations() ?? new RelationCollection();
2462 }
2463
2465 {
2466 if ($this->getId())
2467 {
2468 $this->chatRelations ??= Im\V2\Relation\ChatRelations::getInstance($this->getId());
2469 }
2470
2471 return $this->chatRelations;
2472 }
2473
2475 {
2476 return $this->getRelationFacade()?->getByUserIds($userIds) ?? new RelationCollection();
2477 }
2478
2479 public function getRelationByReason(Reason $reason): RelationCollection
2480 {
2481 return $this->getRelationFacade()?->getByReason($reason) ?? new RelationCollection();
2482 }
2483
2484 public function setRelations(RelationCollection $relations): self
2485 {
2486 $this->getRelationFacade()?->forceRelations($relations);
2487
2488 return $this;
2489 }
2490
2491 public function getSelfRelation(): ?Relation
2492 {
2493 return $this->getRelationFacade()?->getByUserId($this->getContext()->getUserId());
2494 }
2495
2496 public function getRelationByUserId(int $userId): ?Relation
2497 {
2498 return $this->getRelationFacade()?->getByUserId($userId);
2499 }
2500
2502 {
2503 $this->relationProvider ??= new RelationProvider($this->getId() ?? 0);
2504
2505 return $this->relationProvider;
2506 }
2507
2508 public function getBackground(): Background
2509 {
2510 $this->background ??= new Background((int)$this->getId());
2511
2512 return $this->background;
2513 }
2514
2516 {
2517 $this->textFieldEnabled ??= new TextFieldEnabled((int)$this->getId());
2518
2519 return $this->textFieldEnabled;
2520 }
2521
2522 public function getBotInChat(): array
2523 {
2524 $botInChat = [];
2525 $relations = $this->getRelations();
2526 foreach ($relations as $relation)
2527 {
2528 if ($relation->getUser()->getExternalAuthId() === Im\Bot::EXTERNAL_AUTH_ID)
2529 {
2530 $botInChat[$relation->getUserId()] = $relation->getUserId();
2531 }
2532 }
2533
2534 return $botInChat;
2535 }
2536
2537 public function isNew(): bool
2538 {
2539 return false;
2540 }
2541
2542 public function checkTitle(): Result
2543 {
2544 return new Result;
2545 }
2546
2551 public function setManageUsersAdd(string $manageUsersAdd): self
2552 {
2553 $manageUsersAdd = mb_strtoupper($manageUsersAdd);
2554 if (!in_array(
2556 [self::MANAGE_RIGHTS_MEMBER, self::MANAGE_RIGHTS_OWNER, self::MANAGE_RIGHTS_MANAGERS],
2557 true
2558 ))
2559 {
2561 }
2562 $this->manageUsersAdd = $manageUsersAdd ;
2563
2564 return $this;
2565 }
2566
2567 public function getManageUsersAdd(): ?string
2568 {
2569 return $this->manageUsersAdd;
2570 }
2571
2572
2573 public function getDefaultManageUsersAdd(): string
2574 {
2575 return self::MANAGE_RIGHTS_MEMBER;
2576 }
2577
2582 public function setManageUsersDelete(string $manageUsersDelete): self
2583 {
2584 $manageUsersDelete = mb_strtoupper($manageUsersDelete);
2585 if (!in_array(
2587 [self::MANAGE_RIGHTS_MEMBER, self::MANAGE_RIGHTS_OWNER, self::MANAGE_RIGHTS_MANAGERS],
2588 true
2589 ))
2590 {
2592 }
2593 $this->manageUsersDelete = $manageUsersDelete ;
2594
2595 return $this;
2596 }
2597
2598 public function getManageUsersDelete(): ?string
2599 {
2600 return $this->manageUsersDelete;
2601 }
2602
2603
2604 public function getDefaultManageUsersDelete(): string
2605 {
2606 return self::MANAGE_RIGHTS_MANAGERS;
2607 }
2608
2613 public function setManageUI(string $manageUI): self
2614 {
2615 $manageUI = mb_strtoupper($manageUI);
2616 if (!in_array(
2617 $manageUI,
2618 [self::MANAGE_RIGHTS_MEMBER, self::MANAGE_RIGHTS_OWNER, self::MANAGE_RIGHTS_MANAGERS],
2619 true
2620 ))
2621 {
2622 $manageUI = $this->getDefaultManageUI();
2623 }
2624 $this->manageUI = $manageUI;
2625
2626 return $this;
2627 }
2628
2629 public function getManageUI(): ?string
2630 {
2631 return $this->manageUI;
2632 }
2633
2634 public function getDefaultManageUI(): string
2635 {
2636 return self::MANAGE_RIGHTS_MEMBER;
2637 }
2638
2643 public function setManageSettings(string $manageSettings): self
2644 {
2645 $manageSettings = mb_strtoupper($manageSettings);
2646 if (!in_array($manageSettings, [self::MANAGE_RIGHTS_OWNER, self::MANAGE_RIGHTS_MANAGERS], true))
2647 {
2649 }
2650 $this->manageSettings = $manageSettings ;
2651
2652 return $this;
2653 }
2654
2655 public function getManageSettings(): ?string
2656 {
2657 return $this->manageSettings;
2658 }
2659
2660 public function getDefaultManageSettings(): string
2661 {
2662 return self::MANAGE_RIGHTS_OWNER;
2663 }
2664
2666 {
2667 if (!in_array($messagesAutoDeleteDelay, Im\V2\Message\Delete\DisappearService::TIME_WHITELIST))
2668 {
2670 }
2671 $this->messagesAutoDeleteDelay = $messagesAutoDeleteDelay;
2672
2673 return $this;
2674 }
2675
2676 public function getMessagesAutoDeleteDelay(): int
2677 {
2678 return $this->messagesAutoDeleteDelay ?? $this->getDefaultMessagesAutoDeleteDelay();
2679 }
2680
2682 {
2683 return 0;
2684 }
2685
2692 public function setCanPost(string $canPost): self
2693 {
2694 return $this->setManageMessages($canPost);
2695 }
2696
2701 public function setManageMessages(string $manageMessages): self
2702 {
2703 $manageMessages = mb_strtoupper($manageMessages);
2704 if (!in_array(
2706 [
2707 self::MANAGE_RIGHTS_NONE,
2708 self::MANAGE_RIGHTS_MEMBER,
2709 self::MANAGE_RIGHTS_OWNER,
2710 self::MANAGE_RIGHTS_MANAGERS
2711 ],
2712 true
2713 ))
2714 {
2716 }
2717 $this->manageMessages = $manageMessages;
2718
2719 return $this;
2720 }
2721
2722 public function getManageMessages(): ?string
2723 {
2724 return $this->manageMessages;
2725 }
2726
2727 public function getDefaultManageMessages(): string
2728 {
2729 return self::MANAGE_RIGHTS_MEMBER;
2730 }
2731
2732 public function setManageMessagesAutoDelete(string $manageMessagesAutoDelete): self
2733 {
2734 $manageMessagesAutoDelete = mb_strtoupper($manageMessagesAutoDelete);
2735
2736 if (!in_array(
2737 $manageMessagesAutoDelete,
2738 [
2739 self::MANAGE_RIGHTS_NONE,
2740 self::MANAGE_RIGHTS_MEMBER,
2741 self::MANAGE_RIGHTS_OWNER,
2742 self::MANAGE_RIGHTS_MANAGERS,
2743 ],
2744 true
2745 ))
2746 {
2747 return $this;
2748 }
2749
2750 if ($manageMessagesAutoDelete === $this->getDefaultManageMessagesAutoDelete())
2751 {
2752 $this
2753 ->getChatParams()
2754 ?->deleteParam(
2755 Params::MANAGE_MESSAGES_AUTO_DELETE,
2756 false
2757 )
2758 ;
2759 }
2760 else
2761 {
2762 $this
2763 ->getChatParams()
2764 ?->addParamByName(
2765 Params::MANAGE_MESSAGES_AUTO_DELETE,
2766 $manageMessagesAutoDelete,
2767 false
2768 )
2769 ;
2770 }
2771
2772 return $this;
2773 }
2774
2775 public function getManageMessagesAutoDelete(): ?string
2776 {
2777 $manageMessagesAutoDelete = $this->getChatParams()?->get(Params::MANAGE_MESSAGES_AUTO_DELETE);
2778
2779 return
2780 isset($manageMessagesAutoDelete)
2781 ? (string)$manageMessagesAutoDelete->getValue()
2783 ;
2784 }
2785
2786 public function getDefaultManageMessagesAutoDelete(): string
2787 {
2788 return self::MANAGE_RIGHTS_MANAGERS;
2789 }
2790
2791 public static function getCanPostList(): array
2792 {
2793 return [
2794 self::MANAGE_RIGHTS_NONE => Loc::getMessage('IM_CHAT_CAN_POST_NONE'),
2795 self::MANAGE_RIGHTS_MEMBER => Loc::getMessage('IM_CHAT_CAN_POST_ALL_MSGVER_1'),
2796 self::MANAGE_RIGHTS_OWNER => Loc::getMessage('IM_CHAT_CAN_POST_OWNER_MSGVER_1'),
2797 self::MANAGE_RIGHTS_MANAGERS => Loc::getMessage('IM_CHAT_CAN_POST_MANAGERS_MSGVER_1')
2798 ];
2799 }
2800
2801 public function getCallToken(): Im\V2\Call\CallToken
2802 {
2803 if (!isset($this->callToken))
2804 {
2805 $this->callToken = new Im\V2\Call\CallToken($this->getId(), $this->getContext()->getUserId());
2806 }
2807
2808 return $this->callToken;
2809 }
2810 //endregion
2811
2812 public function isAutoJoinEnabled(): bool
2813 {
2814 return false;
2815 }
2816
2817 public function canUserAutoJoin(?int $userId = null): bool
2818 {
2819 $userId ??= $this->getContext()->getUserId();
2820
2821 return $this->isAutoJoinEnabled() && $this->checkAccess($userId)->isSuccess();
2822 }
2823
2824 public function join(bool $withMessage = true): self
2825 {
2826 $config = new AddUsersConfig(hideHistory: false, withMessage: $withMessage);
2827
2828 return $this->addUsers([$this->getContext()->getUserId()], $config);
2829 }
2830
2835 public function addUsers(array $userIds, AddUsersConfig $config = new AddUsersConfig()): self
2836 {
2837 if (empty($userIds) || !$this->getChatId())
2838 {
2839 return $this;
2840 }
2841
2842 $validUsers = $this->getValidUsersToAdd($userIds);
2843 $changes = $this->resolveRelationConflicts($validUsers, $config);
2844
2845 if ($changes->isEmpty())
2846 {
2847 return $this;
2848 }
2849
2850 $relations = $this->getRelations();
2851 if (!$config->isFakeAdd)
2852 {
2853 $this->addUsersToRelation($changes->getNewRelations(), $config);
2854 $this->updateStateAfterRelationsAdd($changes->getNewRelations());
2855 $this->updateStateAfterMembersAdd($changes->getNewMembers());
2856 $this->save();
2857 }
2858 $this->sendPushUsersAdd($changes->getAll(), $relations);
2859 if ($config->withMessage)
2860 {
2861 $this->sendMessageUsersAdd($changes->getNewMembers(), $config);
2862 }
2863 $this->disableUserDeleteMessage($config->skipRecent);
2864 $this->sendEventUsersAdd($changes->getNewRelations());
2865
2866 return $this;
2867 }
2868
2870 {
2871 $changes = new RelationChangeSet();
2872 if (empty($userIds))
2873 {
2874 return $changes;
2875 }
2876
2877 $usersAlreadyInChat = $this->getRawRelations();
2878
2879 foreach ($userIds as $userId)
2880 {
2881 $relation = $usersAlreadyInChat->getByUserId($userId, $this->getId() ?? 0);
2882 if (!$relation)
2883 {
2884 $changes->addNewRelation($userId, $config->isHidden($userId));
2885
2886 continue;
2887 }
2888
2889 if ($relation->isHidden() && !$config->isHidden($userId))
2890 {
2891 $changes->addNewMembers($userId);
2892 $relation->markAsHidden(false);
2893 }
2894 if ($config->reason !== Reason::DEFAULT)
2895 {
2896 $relation->setReason($config->reason);
2897 }
2898 }
2899
2900 $usersAlreadyInChat->save(true);
2901
2902 return $changes;
2903 }
2904
2905 protected function sendMessageUsersAdd(array $usersToAdd, AddUsersConfig $config): void
2906 {
2907 if (empty($usersToAdd))
2908 {
2909 return;
2910 }
2911
2912 $currentUserId = $this->getContext()->getUserId();
2913 $userCodes = [];
2914 foreach ($usersToAdd as $userId)
2915 {
2916 $userCodes[] = "[USER={$userId}][/USER]";
2917 }
2918 $userCodesString = implode(', ', $userCodes);
2919
2920 $addsOnlyHimself = count($usersToAdd) === 1 && (isset($usersToAdd[$currentUserId]) || $currentUserId === 0);
2921 if ($addsOnlyHimself)
2922 {
2923 $userIdToAdd = current($usersToAdd);
2924 $userToAdd = Im\V2\Entity\User\User::getInstance($userIdToAdd);
2925 $messageText = Loc::getMessage("IM_CHAT_SELF_JOIN_{$userToAdd->getGender()}", ['#USER_NAME#' => $userCodesString]);
2926 }
2927 elseif ($currentUserId === 0 && count($usersToAdd) > 1)
2928 {
2929 $messageText = Loc::getMessage('IM_CHAT_SELF_JOIN', ['#USERS_NAME#' => $userCodesString]);
2930 }
2931 else
2932 {
2933 $currentUser = Im\V2\Entity\User\User::getInstance($currentUserId);
2934 $type = $this instanceof Im\V2\Chat\ChannelChat ? 'CHANNEL' : 'CHAT';
2935 $code = "IM_{$type}_JOIN_{$currentUser->getGender()}";
2936 $messageText = Loc::getMessage(
2937 $code,
2938 [
2939 '#USER_1_NAME#' => "[USER={$currentUserId}][/USER]",
2940 '#USER_2_NAME#' => $userCodesString
2941 ]
2942 );
2943 }
2944
2945 $params = [
2946 "CODE" => 'CHAT_JOIN',
2947 "NOTIFY" => $this->getEntityType() === self::ENTITY_TYPE_LINE? 'Y': 'N',
2948 ];
2949
2950 if ($config->isFakeAdd)
2951 {
2952 $params['FAKE_RELATION'] = (int)array_shift($usersToAdd);
2953 }
2954
2955 \CIMChat::AddMessage([
2956 'TO_CHAT_ID' => $this->getId(),
2957 'MESSAGE' => $messageText,
2958 'FROM_USER_ID' => $currentUserId,
2959 'SYSTEM' => 'Y',
2960 'RECENT_ADD' => $config->skipRecent ? 'N' : 'Y',
2961 'PARAMS' => $params,
2962 'PUSH' => 'N',
2963 'SKIP_USER_CHECK' => 'Y',
2964 'SKIP_COUNTER_INCREMENTS' => $this->getEntityType() === self::ENTITY_TYPE_LINE ? 'N' : 'Y',
2965 ]);
2966 }
2967
2968 protected function sendPushUsersAdd(array $usersToAdd, RelationCollection $oldRelations): void
2969 {
2970 if (empty($usersToAdd) || !\Bitrix\Main\Loader::includeModule('pull'))
2971 {
2972 return;
2973 }
2974
2975 (new Im\V2\Pull\Event\ChatUserAdd($this, $usersToAdd))->send();
2976 }
2977
2978 protected function updateStateAfterRelationsAdd(array $usersToAdd): self
2979 {
2980 if (empty($usersToAdd))
2981 {
2982 return $this;
2983 }
2984
2985 foreach ($usersToAdd as $userId)
2986 {
2987 $this->clearLegacyCache((int)$userId);
2988 }
2989
2990 \CIMDisk::ChangeFolderMembers($this->getId(), $usersToAdd);
2991 self::cleanAccessCache($this->getId());
2992
2993 return $this;
2994 }
2995
2996 protected function updateStateAfterMembersAdd(array $newMembers): static
2997 {
2998 if (empty($newMembers))
2999 {
3000 return $this;
3001 }
3002
3003 if (!$this->getExtranet() && UserCollection::hasUserByType($newMembers, UserType::EXTRANET))
3004 {
3005 $this->setExtranet(true);
3006 }
3007 if (!$this->containsCollaber() && UserCollection::hasUserByType($newMembers, UserType::COLLABER))
3008 {
3009 $this->getChatParams()->addParamByName(Params::CONTAINS_COLLABER, true);
3010 }
3011 if (!$this->containsCopilot() && AIHelper::containsCopilotBot($newMembers))
3012 {
3013 $this->getChatParams()->addParamByName(Chat\Param\Params::IS_COPILOT, true);
3014 }
3015
3016 $userCount = $this->getRelationFacade()?->getUserCount();
3017 $this->setUserCount($userCount);
3018 $this->updateIndex();
3019
3020 return $this;
3021 }
3022
3023 protected function addUsersToRelation(array $usersToAdd, AddUsersConfig $config): void
3024 {
3025 $usersToAdd = array_filter($usersToAdd);
3026
3027 if (empty($usersToAdd))
3028 {
3029 return;
3030 }
3031
3032 $relations = $this->getRelations();
3033 foreach ($usersToAdd as $userId)
3034 {
3035 $relation = $this->createRelation($userId, $config);
3036 $relations->add($relation);
3037 }
3038 $relations->save(true);
3039 $this->getRelationFacade()?->onAfterRelationAdd($usersToAdd);
3040
3041 $chatAnalytics = new Im\V2\Analytics\ChatAnalytics($this);
3042
3043 foreach ($usersToAdd as $userId)
3044 {
3045 $chatAnalytics->addAddUser();
3046 }
3047 }
3048
3050 {
3051 $hideHistory = $config->hideHistory ?? false;
3052 $hideHistory = (!static::EXTRANET_CAN_SEE_HISTORY && Im\V2\Entity\User\User::getInstance($userId)->isExtranet()) ? true : $hideHistory;
3053
3054 $relation = new Relation();
3055 $relation
3056 ->setChatId($this->getId())
3057 ->setMessageType($this->getType())
3058 ->setUserId($userId)
3059 ->setLastId($this->getLastMessageId())
3060 ->setStatus(\IM_STATUS_READ)
3061 ->setReason($config->reason)
3062 ->markAsHidden($config->isHidden($userId))
3063 ->fillRestriction($hideHistory, $this)
3064 ;
3065 if ($config->isManager($userId))
3066 {
3067 $relation->setManager(true);
3068 }
3069
3070 return $relation;
3071 }
3072
3073 protected function getValidUsersToAdd(array $userIds): array
3074 {
3075 $userIds = Group::filterAddedUsersToChatBySonetRestriction($userIds, $this->getContext()->getUserId());
3076
3077 if ($this->getContext()->getUser()->isExtranet())
3078 {
3080 }
3081
3082 $usersToAdd = [];
3083
3084 foreach ($userIds as $userId)
3085 {
3086 $userId = (int)$userId;
3087 if ($this->isValidToAdd($userId))
3088 {
3089 $usersToAdd[$userId] = $userId;
3090 }
3091 }
3092
3093 return $usersToAdd;
3094 }
3095
3096 protected function isValidToAdd(int $userId): bool
3097 {
3098 if ($userId <= 0)
3099 {
3100 return false;
3101 }
3102
3104
3105 return $user->isExist() && $user->isActive();
3106 }
3107
3108 protected function sendEventUsersAdd(array $usersToAdd): void
3109 {
3110 if (empty($usersToAdd))
3111 {
3112 return;
3113 }
3114
3115 foreach ($usersToAdd as $userId)
3116 {
3117 $relation = $this->getRelations()->getByUserId($userId, $this->getId());
3118 if ($relation === null)
3119 {
3120 continue;
3121 }
3122 if ($relation->getUser()->isBot())
3123 {
3124 IM\Bot::onJoinChat('chat'.$this->getId(), [
3125 'CHAT_TYPE' => $this->getType(),
3126 'MESSAGE_TYPE' => $this->getType(),
3127 'BOT_ID' => $userId,
3128 'USER_ID' => $this->getContext()->getUserId(),
3129 'CHAT_ID' => $this->getId(),
3130 "CHAT_AUTHOR_ID" => $this->getAuthorId(),
3131 "CHAT_ENTITY_TYPE" => $this->getEntityType(),
3132 "CHAT_ENTITY_ID" => $this->getEntityId(),
3133 "ACCESS_HISTORY" => (int)$relation->getStartCounter() === 0,
3134 ]);
3135 }
3136 }
3137
3138 if (!empty($this->getEntityType()))
3139 {
3140 $converter = new Converter(Converter::TO_CAMEL | Converter::UC_FIRST);
3141 $eventCode = $converter->process($this->getEntityType());
3142 //$eventCode = str_replace('_', '', ucfirst(ucwords(mb_strtolower($chatEntityType), '_')));
3143 foreach(GetModuleEvents("im", "OnChatUserAddEntityType".$eventCode, true) as $arEvent)
3144 {
3145 ExecuteModuleEventEx($arEvent, array([
3146 'CHAT_ID' => $this->getId(),
3147 'NEW_USERS' => $usersToAdd,
3148 ]));
3149 }
3150 }
3151 }
3152
3154 {
3155 $relations = clone $this->getRelations();
3156 $userRelation = $this->getRawRelations()->getByUserId($userId, $this->getId());
3157 if ($userRelation && !$relations->hasUser($userId, $this->getId()))
3158 {
3159 $relations[] = $userRelation;
3160 }
3161
3162 if ($userRelation === null)
3163 {
3164 return (new Result())->addError(new UserError(UserError::NOT_FOUND));
3165 }
3166
3167 if (!$config->skipCheckReason && $userRelation->getReason() !== Reason::DEFAULT)
3168 {
3169 return (new Result())->addError(new UserError(UserError::DELETE_FROM_STRUCTURE_SYNC));
3170 }
3171
3172 if ($this->getAuthorId() === $userId)
3173 {
3174 $this->changeAuthor();
3175 }
3176
3177 $userRelation->delete();
3178 $this->getRelationFacade()?->onAfterRelationDelete($userId);
3179
3181 $this->sendPushUserDelete($userId, $relations);
3183 $this->disableUserDeleteMessage($config->skipRecent);
3186
3187 (new Im\V2\Analytics\ChatAnalytics($this))->addDeleteUser();
3188
3189 return new Result();
3190 }
3191
3192 public function hideUser(int $userId): Result
3193 {
3194 $relations = $this->getRelations();
3195 $relation = $relations->getByUserId($userId, $this->getId());
3196 if ($relation === null)
3197 {
3198 return new Result();
3199 }
3200
3201 $relation->markAsHidden(true)->save();
3203 $this->sendPushUserDelete($userId, $relations);
3204
3205 return new Result();
3206 }
3207
3208 protected function needToSendMessageUserDelete(): bool
3209 {
3210 return false;
3211 }
3212
3214 {
3215 if (
3216 !$config->withMessage
3217 || !$this->needToSendMessageUserDelete()
3218 || $this->getChatParams()->get(Params::USER_DELETE_MESSAGE_DISABLED)?->getValue() ?? false
3219 || $this->getEntityType() === 'ANNOUNCEMENT'
3220 )
3221 {
3222 return;
3223 }
3224
3226 if ($message === '')
3227 {
3228 return;
3229 }
3230
3231 \CIMChat::AddMessage($this->prepareMessageParamsFromUserDelete($message, $config->skipRecent));
3232 }
3233
3234 protected function prepareMessageParamsFromUserDelete(string $message, bool $skipRecent): array
3235 {
3236 return [
3237 'TO_CHAT_ID' => $this->getId(),
3238 'MESSAGE' => $message,
3239 'FROM_USER_ID' => $this->getContext()->getUserId(),
3240 'SYSTEM' => 'Y',
3241 'RECENT_ADD' => $skipRecent ? 'N' : 'Y',
3242 'PARAMS' => ['CODE' => 'CHAT_LEAVE', 'NOTIFY' => 'N'],
3243 'PUSH' => 'N',
3244 'SKIP_USER_CHECK' => 'Y',
3245 'SKIP_COUNTER_INCREMENTS' => 'Y',
3246 ];
3247 }
3248
3250 {
3251 if (!$config->withNotification)
3252 {
3253 return;
3254 }
3255
3256 if ($userId === $this->getContext()->getUserId() || $this->getContext()->getUserId() === 0)
3257 {
3258 return;
3259 }
3260
3261 $gender = $this->getContext()->getUser()->getGender();
3262 $userName = $this->getContext()->getUser()->getName();
3263 $userName = "[USER={$this->getContext()->getUserId()}]{$userName}[/USER]";
3264
3265 $notificationCallback = fn (?string $languageId = null) => Loc::getMessage(
3266 'IM_CHAT_KICK_NOTIFICATION_'. $gender,
3267 ["#USER_NAME#" => $userName],
3268 $languageId
3269 );
3270
3271 $notificationFields = [
3272 'TO_USER_ID' => $userId,
3273 'FROM_USER_ID' => 0,
3274 'NOTIFY_TYPE' => IM_NOTIFY_SYSTEM,
3275 'NOTIFY_MODULE' => 'im',
3276 'NOTIFY_TITLE' => htmlspecialcharsback(\Bitrix\Main\Text\Emoji::decode($this->getTitle())),
3277 'NOTIFY_MESSAGE' => $notificationCallback,
3278 ];
3279 CIMNotify::Add($notificationFields);
3280 }
3281
3282 public function getUserDeleteMessageText(int $deletedUserId): string
3283 {
3284 $currentUser = $this->getContext()->getUser();
3285 $currentUserId = $this->getContext()->getUserId();
3286
3287 if (!$currentUser->isExist())
3288 {
3289 return '';
3290 }
3291
3292 if ($currentUserId === $deletedUserId)
3293 {
3294 return Loc::getMessage(
3295 "IM_CHAT_LEAVE_{$currentUser->getGender()}_MSGVER_1",
3296 ['#USER_ID#' => $currentUserId]
3297 );
3298 }
3299
3300 return Loc::getMessage(
3301 "IM_CHAT_KICK_{$currentUser->getGender()}_MSGVER_1",
3302 ['#CURRENT_USER_ID#' => $currentUserId, '#DELETED_USER_ID#' => $deletedUserId]
3303 );
3304 }
3305
3306 protected function updateStateAfterUserDelete(int $deletedUserId, DeleteUserConfig $config): self
3307 {
3308 \CIMContactList::DeleteRecent($this->getId(), true, $deletedUserId, $config->withoutRead);
3309 \Bitrix\Im\LastSearch::delete($this->getDialogId(), $deletedUserId);
3310 $deletedUser = Im\V2\Entity\User\User::getInstance($deletedUserId);
3311 $userIds = $this->getRelations()->getUserIds();
3312
3313 if (
3314 $deletedUser->getType() === UserType::EXTRANET
3315 && $this->getExtranet()
3316 && !UserCollection::hasUserByType($userIds, UserType::EXTRANET)
3317 )
3318 {
3319 $this->setExtranet(false);
3320 }
3321
3322 if (
3323 $deletedUser->getType() === UserType::COLLABER
3324 && $this->containsCollaber()
3325 && !UserCollection::hasUserByType($userIds, UserType::COLLABER)
3326 )
3327 {
3328 $this->getChatParams()->deleteParam(Params::CONTAINS_COLLABER);
3329 }
3330
3331 if (AIHelper::containsCopilotBot([$deletedUserId]) && $this->containsCopilot())
3332 {
3333 $this->getChatParams()->deleteParam(Chat\Param\Params::IS_COPILOT);
3334 }
3335
3336 $userCount = $this->getRelationFacade()?->getUserCount();
3337 $this->setUserCount($userCount);
3338
3339 \CIMDisk::ChangeFolderMembers($this->getId(), $deletedUserId, false);
3340 self::cleanAccessCache($this->getId());
3341 $this->updateIndex();
3342
3343 $this->clearLegacyCache($deletedUserId);
3344
3345 return $this;
3346 }
3347
3348 protected function clearLegacyCache(int $userId): void
3349 {
3350 CIMContactList::CleanChatCache($userId);
3351 }
3352
3353 protected function sendEventUserDelete(int $userId): void
3354 {
3356 if ($user->isBot())
3357 {
3358 IM\Bot::onLeaveChat('chat'.$this->getId(), [
3359 'CHAT_TYPE' => $this->getType(),
3360 'MESSAGE_TYPE' => $this->getType(),
3361 'BOT_ID' => $userId,
3362 'USER_ID' => $this->getContext()->getUserId(),
3363 "CHAT_AUTHOR_ID" => $this->getAuthorId(),
3364 "CHAT_ENTITY_TYPE" => $this->getEntityType(),
3365 "CHAT_ENTITY_ID" => $this->getEntityId(),
3366 ]);
3367 }
3368
3369 if (!empty($this->getEntityType()))
3370 {
3371 $converter = new Converter(Converter::TO_CAMEL | Converter::UC_FIRST);
3372 $eventCode = $converter->process($this->getEntityType());
3373 foreach(GetModuleEvents("im", "OnChatUserDeleteEntityType".$eventCode, true) as $arEvent)
3374 {
3375 ExecuteModuleEventEx($arEvent, array([
3376 'CHAT_ID' => $this->getId(),
3377 'USER_ID' => $userId,
3378 ]));
3379 }
3380 }
3381
3382 $eventParams = ['chatId' => $this->getId(), 'userIds' => [$userId]];
3383 $event = new Main\Event('im', 'OnChatUserDelete', $eventParams);
3384 $event->send();
3385 }
3386
3387 protected function sendPushUserDelete(int $userId, RelationCollection $oldRelations): void
3388 {
3389 if (!\Bitrix\Main\Loader::includeModule('pull'))
3390 {
3391 return;
3392 }
3393
3394 (new Im\V2\Pull\Event\ChatUserLeave($this, $userId, $oldRelations))->send();
3395 }
3396
3397 public function changeAuthor(): void
3398 {
3399 $currentAuthorId = $this->getAuthorId();
3400 $relations = $this->getRelations();
3401 $authorRelation = $relations->getByUserId($currentAuthorId, $this->getId());
3402 if ($authorRelation !== null)
3403 {
3404 $authorRelation->setManager(false);
3405 }
3406 $otherRealUserRelation = $relations->filter(static function (Relation $relation) use ($currentAuthorId) {
3407 $user = $relation->getUser();
3408
3409 return $user->getId() !== $currentAuthorId
3410 && $user->isActive()
3411 && !$user->isBot()
3412 && !$user->isExtranet()
3413 && !$user->isConnector()
3414 ;
3415 })->getAny();
3416
3417 if (!$otherRealUserRelation instanceof Relation)
3418 {
3419 return;
3420 }
3421
3422 $this->setAuthorId($otherRealUserRelation->getUserId());
3423 $otherRealUserRelation->setManager(true);
3424 $relations->save(true);
3425 }
3426
3427 public function setManagers(array $managerIds): self
3428 {
3429 if (!$this->getChatId() || empty($managerIds) || !count($managerIds))
3430 {
3431 return $this;
3432 }
3433
3434 $managerIds = filter_var(
3435 $managerIds,
3436 FILTER_VALIDATE_INT,
3437 [
3438 'flags' => FILTER_REQUIRE_ARRAY,
3439 'options' => ['min_range' => 1],
3440 ]
3441 );
3442
3443 foreach ($managerIds as $key => $managerId)
3444 {
3445 if (!is_int($managerId))
3446 {
3447 unset($managerIds[$key]);
3448 }
3449 }
3450
3451 $relations = $this->getRelations();
3452
3453 $relationIds = [];
3454 $unsetManagerIds = [];
3456 foreach ($relations as $relation)
3457 {
3458 if (in_array($relation->getUserId(), $managerIds, true))
3459 {
3460 $relationIds[] = $relation->getPrimaryId();
3461 }
3462 elseif ($relation->getManager())
3463 {
3464 $unsetManagerIds[] = $relation->getPrimaryId();
3465 }
3466
3467 }
3468
3469 if ($unsetManagerIds)
3470 {
3471 RelationTable::updateMulti(
3472 $unsetManagerIds,
3473 [
3474 'MANAGER' => 'N',
3475 ]
3476 );
3477 }
3478
3479 RelationTable::updateMulti(
3480 $relationIds,
3481 [
3482 'MANAGER' => 'Y',
3483 ]
3484 );
3485
3486 return $this;
3487 }
3488
3493 public static function loadPhrases(): void
3494 {
3495 Loc::loadMessages(__FILE__);
3496 }
3497
3498 public function setContext(?Context $context): self
3499 {
3500 $this->defaultSaveContext($context);
3501 $this->getReadService()->setContext($context);
3502 $this->role = null;
3503
3504 return $this;
3505 }
3506
3507 public function getLoadContextMessage(bool $ignoreMark = false): Message
3508 {
3509 if (!$ignoreMark)
3510 {
3511 $startMessageId = $this->getMarkedId() ?: $this->getLastId();
3512 }
3513 else
3514 {
3515 $startMessageId = $this->getLastId();
3516 }
3517
3518 return (new \Bitrix\Im\V2\Message($startMessageId))->setChatId($this->getId())->setMessageId($startMessageId);
3519 }
3520
3521 public function fillNonCachedData(): self
3522 {
3523 if ($this->isFilledNonCachedData)
3524 {
3525 return $this;
3526 }
3527
3528 $this->fillActual(ChatFactory::NON_CACHED_FIELDS);
3529 $this->isFilledNonCachedData = true;
3530
3531 return $this;
3532 }
3533
3534 public static function getRestEntityName(): string
3535 {
3536 return 'chat';
3537 }
3538
3539 public function getEntityLink(): Im\V2\Chat\EntityLink
3540 {
3541 return Im\V2\Chat\EntityLink::getInstance($this);
3542 }
3543
3548
3550 {
3551 return new ChatRecentConfig($this);
3552 }
3553
3554 public function getPermissions(): array
3555 {
3556 return [
3557 'manageUsersAdd' => mb_strtolower($this->getManageUsersAdd()),
3558 'manageUsersDelete' => mb_strtolower($this->getManageUsersDelete()),
3559 'manageUi' => mb_strtolower($this->getManageUI()),
3560 'manageSettings' => mb_strtolower($this->getManageSettings()),
3561 'manageMessages' => mb_strtolower($this->getManageMessages()),
3562 'manageMessagesAutoDelete' => mb_strtolower($this->getManageMessagesAutoDelete()),
3563 'canPost' => mb_strtolower($this->getManageMessages()),
3564 ];
3565 }
3566
3567 public function getPopupData(array $excludedList = []): PopupData
3568 {
3569 return new PopupData([$this->getRecentConfig()], $excludedList);
3570 }
3571
3572 public function toRestFormat(array $option = []): array
3573 {
3574 $commonFields = [
3575 'avatar' => $this->getAvatar(),
3576 'color' => $this->getColor(true),
3577 'description' => $this->getDescription() ?? '',
3578 'dialogId' => $this->getDialogId(),
3579 'diskFolderId' => $this->getDiskFolderId(),
3580 'entityData1' => $this->getEntityData1() ?? '',
3581 'entityData2' => $this->getEntityData2() ?? '',
3582 'entityData3' => $this->getEntityData3() ?? '',
3583 'entityId' => $this->getEntityId() ?? '',
3584 'entityType' => $this->getEntityType() ?? '',
3585 'extranet' => $this->getExtranet() ?? false,
3586 'containsCollaber' => (bool)$this->getChatParams()->get(Params::CONTAINS_COLLABER)?->getValue(),
3587 'id' => $this->getId(),
3588 'parentChatId' => $this->getParentChatId(),
3589 'parentMessageId' => $this->getParentMessageId(),
3590 'name' => $this->getTitle(),
3591 'owner' => (int)$this->getAuthorId(),
3592 'messageType' => $this->getType(),
3593 'role' => mb_strtolower($this->getRole()),
3594 'muteList' => $this->getMuteList(),
3595 'type' => $this->getExtendedType(),
3596 'entityLink' => $this->getEntityLink()->toRestFormat($option),
3597 'permissions' => $this->getPermissions(),
3598 'isNew' => $this->isNew(),
3599 'textFieldEnabled' => $this->getTextFieldEnabled()->get(),
3600 'backgroundId' => $this->getBackground()->get(),
3601 ];
3602
3603 if ($option['CHAT_WITH_DATE_MESSAGE'] ?? false)
3604 {
3605 $commonFields['dateMessage'] = $this->dateMessage;
3606 }
3607 if ($option['CHAT_SHORT_FORMAT'] ?? false)
3608 {
3609 return $commonFields;
3610 }
3611
3612 $additionalFields = [
3613 'counter' => $this->getUserCounter(),
3614 'dateCreate' => $this->getDateCreate()?->format('c'),
3615 'lastMessageId' => $this->getLastMessageId(),
3616 'lastMessageViews' => Im\Common::toJson($this->getLastMessageViews()),
3617 'lastId' => $this->getLastId(),
3618 'managerList' => $this->getManagerList(),
3619 'markedId' => $this->getMarkedId(),
3620 'messageCount' => $this->getMessageCount(),
3621 'public' => $this->getPublicOption() ?? '',
3622 'unreadId' => $this->getUnreadId(),
3623 'userCounter' => $this->getUserCount(),
3624 ];
3625
3626 return array_merge($commonFields, $additionalFields);
3627 }
3628
3629 public function toPullFormat(): array
3630 {
3631 return [
3632 'id' => $this->getId(),
3633 'dialogId' => $this->getDialogId(),
3634 'parent_chat_id' => $this->getParentChatId(),
3635 'parent_message_id' => $this->getParentMessageId(),
3636 'name' => \Bitrix\Im\Text::decodeEmoji($this->getTitle()),
3637 'owner' => $this->getAuthorId(),
3638 'color' => $this->getColor(true),
3639 'extranet' => $this->getExtranet() ?? false,
3640 'contains_collaber' => (bool)$this->getChatParams()->get(Params::CONTAINS_COLLABER)?->getValue(),
3641 'avatar' => $this->getAvatar(true),
3642 'message_count' => $this->getMessageCount(),
3643 'call' => $this->getCallType(),
3644 'call_number' => $this->getCallNumber(),
3645 'entity_type' => $this->getEntityType(),
3646 'entity_id' => $this->getEntityId(),
3647 'entity_data_1' => $this->getEntityData1(),
3648 'entity_data_2' => $this->getEntityData2(),
3649 'entity_data_3' => $this->getEntityData3(),
3650 'public' => $this->getPublicOption() ?? '',
3651 'mute_list' => $this->getMuteList(true),
3652 'manager_list' => $this->getManagerList(),
3653 'date_create' => $this->getDateCreate(),
3654 'type' => $this->getExtendedType(),
3655 'entity_link' => $this->getEntityLink()->toRestFormat(),
3656 'permissions' => $this->getPermissions(),
3657 'isNew' => $this->isNew(),
3658 'message_type' => $this->getType(),
3659 'ai_provider' => null,
3660 'description' => \Bitrix\Im\Text::decodeEmoji($this->getDescription() ?? ''),
3661 'textFieldEnabled' => $this->getTextFieldEnabled()->get(),
3662 'backgroundId' => $this->getBackground()->get(),
3663 ];
3664 }
3665
3666 public function getMultidialogData(): array
3667 {
3668 return [];
3669 }
3670
3671 public function getManagerList(bool $fullList = true): array
3672 {
3673 if ($fullList)
3674 {
3675 return array_values($this->getRelationFacade()?->getManagerOnly()->getUserIds() ?? []);
3676 }
3677
3678 if ($this->getSelfRelation()?->getManager() ?? false)
3679 {
3680 return [$this->getContext()->getUserId()];
3681 }
3682
3683 return [];
3684 }
3685
3686 protected function getMuteList(bool $fullList = false): array
3687 {
3688 if ($fullList)
3689 {
3690 $list = [];
3691 foreach ($this->getRelations() as $relation)
3692 {
3693 $list[$relation->getUserId()] = $relation->getNotifyBlock();
3694 }
3695
3696 return $list;
3697 }
3698
3699 $selfRelation = $this->getSelfRelation();
3700
3701 if ($selfRelation === null)
3702 {
3703 return [];
3704 }
3705
3706 if ($selfRelation->getNotifyBlock() ?? false)
3707 {
3708 return [$this->getContext()->getUserId()];
3709 }
3710
3711 return [];
3712 }
3713
3714 public function getPublicOption(): ?array
3715 {
3716 if ($this->getAliasName() === null)
3717 {
3718 return null;
3719 }
3720
3721 return [
3722 'code' => $this->getAliasName(),
3723 'link' => Alias::getPublicLink($this->getEntityType(), $this->getAliasName())
3724 ];
3725 }
3726
3727 public function getExtendedType(bool $forRest = true): string
3728 {
3729 return Im\Chat::getType(
3730 ['ID' => $this->getId(), 'TYPE' => $this->getType(), 'ENTITY_TYPE' => $this->getEntityType()],
3731 $forRest
3732 );
3733 }
3734
3735 public function getUnreadId(): int
3736 {
3737 $selfRelation = $this->getSelfRelation();
3738 if ($selfRelation === null)
3739 {
3740 return 0;
3741 }
3742
3743 return $selfRelation->getUnreadId() ?? 0;
3744 }
3745
3746 public function getLastId(): int
3747 {
3748 $selfRelation = $this->getSelfRelation();
3749 if ($selfRelation === null)
3750 {
3751 return $this->getLastMessageId();
3752 }
3753
3754 return $selfRelation->getLastId() ?? 0;
3755 }
3756
3757 protected function addIndex(): self
3758 {
3759 if (!$this->getChatId())
3760 {
3761 return $this;
3762 }
3763
3765 ->setChatId($this->getChatId())
3766 ->setTitle(mb_substr($this->getTitle() ?? '', 0, 255))
3767 ->setUserList($this->getUserNamesForIndex())
3768 ;
3770
3771 return $this;
3772 }
3773
3774 protected function updateIndex(): self
3775 {
3776 if (!$this->getChatId())
3777 {
3778 return $this;
3779 }
3780
3782 ->setChatId($this->getChatId())
3783 ->setUserList($this->getUserNamesForIndex())
3784 ;
3786
3787 return $this;
3788 }
3789
3790 private function getUserNamesForIndex(): array
3791 {
3792 $relations = RelationCollection::find(['CHAT_ID' => $this->getId()], limit: 100);
3793
3794 $users = [];
3795 foreach ($relations as $relation)
3796 {
3797 $users[] = $relation->getUser()->getName() ?? '';
3798 }
3799
3800 return $users;
3801 }
3802
3806 public function deleteChat(): Result
3807 {
3808 $result = new Result();
3809
3810 if (!$this->chatId)
3811 {
3812 return $result->addError(new ChatError(ChatError::NOT_FOUND));
3813 }
3814
3815 $currentUserId = Entity\User\User::getCurrent()->getId();
3816
3817 Application::getInstance()->addBackgroundJob(
3818 fn () => (new Im\V2\Chat\Cleanup\ChatContentCollector($this->chatId))
3819 ->deleteChat($currentUserId)
3820 );
3821
3822 return $result;
3823 }
3824
3825 private function hideChat(): Result
3826 {
3827 $result = new Result();
3828
3829 if (!$this->getChatId())
3830 {
3831 return $result->addError(new ChatError(ChatError::NOT_FOUND));
3832 }
3833
3834 $pushList = [];
3835 foreach($this->getRelations() as $relation)
3836 {
3837 \CIMContactList::DeleteRecent($this->getChatId(), true, $relation->getUserId());
3838
3839 if (!Im\User::getInstance($relation->getUserId())->isConnector())
3840 {
3841 $pushList[] = $relation->getUserId();
3842 }
3843 }
3844
3845 if (
3846 !empty($pushList)
3847 && \Bitrix\Main\Loader::includeModule("pull")
3848 )
3849 {
3850 \Bitrix\Pull\Event::add($pushList, [
3851 'module_id' => 'im',
3852 'command' => 'chatHide',
3853 'expiry' => 3600,
3854 'params' => [
3855 'dialogId' => 'chat' . $this->getChatId(),
3856 'chatId' => $this->getId(),
3857 'lines' => $this->getType() === self::IM_TYPE_OPEN_LINE,
3858 ],
3859 'extra' => \Bitrix\Im\Common::getPullExtra()
3860 ]);
3861 }
3862
3863 return $result;
3864 }
3865
3866 public function sendMessageUpdateAvatar(bool $skipRecent = false): void
3867 {
3868 $currentUser = $this->getContext()->getUser();
3869 $type = $this instanceof Im\V2\Chat\ChannelChat ? 'CHANNEL' : 'CHAT';
3870 $code = "IM_{$type}_AVATAR_CHANGE_{$currentUser->getGender()}";
3871
3872 $messageText = Loc::getMessage(
3873 $code,
3874 ['#USER_NAME#' => htmlspecialcharsback($currentUser->getName())]
3875 );
3876
3877 if ($messageText === '')
3878 {
3879 return;
3880 }
3881
3882 \CIMChat::AddMessage([
3883 "TO_CHAT_ID" => $this->getId(),
3884 "MESSAGE" => $messageText,
3885 "FROM_USER_ID" => $this->getContext()->getUserId(),
3886 "SYSTEM" => 'Y',
3887 "RECENT_ADD" => $skipRecent ? 'N' : 'Y',
3888 "PARAMS" => [
3889 "CODE" => 'CHAT_LEAVE',
3890 "NOTIFY" => $this->getEntityType() === 'LINES' ? 'Y': 'N',
3891 ],
3892 "PUSH" => 'N',
3893 "SKIP_USER_CHECK" => "Y",
3894 ]);
3895 }
3896
3897 protected function disableUserDeleteMessage(bool $skipRecent = false): void
3898 {
3899 if (
3901 && $this->needToSendMessageUserDelete()
3902 && $this->getChatParams()->get(Params::USER_DELETE_MESSAGE_DISABLED)?->getValue() !== true
3903 && $this->getRelationFacade()?->getUserCount() > self::MAX_USERS_TO_DISABLE_DELETE_MESSAGE
3904 )
3905 {
3906 $this->getChatParams()->addParamByName(Params::USER_DELETE_MESSAGE_DISABLED, true);
3907 $this->sendMessageOnUserDeleteMessageDisabled($skipRecent);
3908 }
3909 }
3910
3911 protected function canDisableUserDeleteMessage(): bool
3912 {
3913 return Option::get('im', 'chat_user_deletion_message_disabled', 'N') === 'Y';
3914 }
3915
3916 protected function sendMessageOnUserDeleteMessageDisabled(bool $skipRecent): void
3917 {
3918 $userCount = self::MAX_USERS_TO_DISABLE_DELETE_MESSAGE;
3919
3920 \CIMChat::AddMessage([
3921 'TO_CHAT_ID' => $this->getId(),
3922 'MESSAGE' => Loc::getMessage('IM_CHAT_OVERFLOW_DELETE_MESSAGE', ['#USER_COUNT#' => $userCount]),
3923 'SYSTEM' => 'Y',
3924 'RECENT_ADD' => $skipRecent ? 'N' : 'Y',
3925 'PUSH' => 'N',
3926 'SKIP_USER_CHECK' => 'Y',
3927 'SKIP_COUNTER_INCREMENTS' => 'Y',
3928 'PARAMS' => [
3929 Im\V2\Message\Params::NOTIFY => 'N',
3930 ],
3931 ]);
3932 }
3933
3934 public function needToSendPublicPull(): bool
3935 {
3936 return false;
3937 }
3938
3939 public function checkAllowedAction(string $action): bool
3940 {
3941 $options = \CIMChat::GetChatOptions();
3942 $entityType = $this->getEntityType();
3943
3944 $defaultAllowed = (bool)($chatOptions['DEFAULT'][$action] ?? true);
3945
3946 if (isset($entityType, $options[$entityType]))
3947 {
3948 return (bool)($chatOptions[$entityType][$action] ?? $defaultAllowed);
3949 }
3950
3951 return $defaultAllowed;
3952 }
3953
3954 public function canDo(Action $action, mixed $target = null): bool
3955 {
3956 $userRights = $this->getRole();
3957 $userId = $this->getContext()->getUserId();
3958 $action = Im\V2\Permission::specifyAction($action, $this, $target);
3959
3960 $rightByType = Im\V2\Permission::getRoleForActionByType($this->getExtendedType(false), $action);
3961 $actionGroup = Im\V2\Permission\ActionGroup::tryFromAction($action);
3962
3963 $manageRights = match ($actionGroup)
3964 {
3965 Permission\ActionGroup::ManageUi => $this->getManageUI(),
3966 Permission\ActionGroup::ManageUsersAdd => $this->getManageUsersAdd(),
3967 Permission\ActionGroup::ManageUsersDelete => $this->getManageUsersDelete(),
3968 Permission\ActionGroup::ManageSettings => $this->getManageSettings(),
3969 Permission\ActionGroup::ManageMessages => $this->getManageMessages(),
3970 Permission\ActionGroup::ManageMessagesAutoDelete => $this->getManageMessagesAutoDelete(),
3971 default => Chat::ROLE_GUEST,
3972 };
3973
3974 return Im\V2\Permission::compareRole($userRights, $manageRights)
3975 && Im\V2\Permission::compareRole($userRights, $rightByType)
3976 && Im\V2\Permission::canDoActionByUserType($userId, $action, $target)
3977 ;
3978 }
3979 public static function updateStateAfterOrmEvent(int $id, array $fields): void
3980 {
3981 $chat = self::$chatStaticCache[$id];
3982 $chat?->onAfterOrmUpdate($fields);
3983 }
3984}
$connection
Определения actionsdefinitions.php:38
$type
Определения options.php:106
if($_SERVER $defaultValue['REQUEST_METHOD']==="GET" &&!empty($RestoreDefaults) && $bizprocPerms==="W" &&check_bitrix_sessid())
Определения options.php:32
if(! $messageFields||!isset($messageFields['message_id'])||!isset($messageFields['status'])||!CModule::IncludeModule("messageservice")) $messageId
Определения callback_ismscenter.php:26
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
Определения check_mail.php:18
static getPublicLink($type, $alias)
Определения alias.php:226
static getType($chatData, bool $camelCase=true)
Определения chat.php:45
static getColorByNumber($number)
Определения color.php:144
static isSafeColor($code)
Определения color.php:186
static getColor($code)
Определения color.php:121
static getCodeByNumber($number)
Определения color.php:166
static toJson($array, $camelCase=true)
Определения common.php:89
static isChatId($id)
Определения common.php:58
static getPullExtra()
Определения common.php:127
static getChatId($dialogId, $userId=null)
Определения dialog.php:93
static filterUserList(array $userList, $currentUserId=null)
Определения extranet.php:141
static create()
Определения chatindex.php:20
static delete($dialogId, $userId=null)
Определения lastsearch.php:107
static updateIndexRecord(ChatIndex $index)
Определения chat.php:341
static addIndexRecord(ChatIndex $index)
Определения chat.php:323
static readAll(int $userId)
Определения recent.php:1805
static isUnread(int $userId, string $itemType, string $dialogId)
Определения recent.php:1819
static unread($dialogId, $unread, $userId=null, ?int $markedId=null, ?string $itemTypes=null)
Определения recent.php:1674
static getMarkedId(int $userId, string $itemType, string $dialogId)
Определения recent.php:1859
static getUsersOutOfRecent(\Bitrix\Im\V2\Chat $chat)
Определения recent.php:1655
static decodeEmoji($text)
Определения text.php:378
static getInstance($userId=null)
Определения user.php:45
const WRONG_COLOR
Определения ChatError.php:16
const WRONG_PARAMETER
Определения ChatError.php:12
const TEXT_FIELD_DISABLED
Определения ChatError.php:40
const ACCESS_DENIED
Определения ChatError.php:19
const WRONG_SENDER
Определения ChatError.php:13
const NOT_FOUND
Определения ChatError.php:20
const WRONG_TYPE
Определения ChatError.php:11
const NON_CACHED_FIELDS
Определения ChatFactory.php:22
static getInstance()
Определения ChatFactory.php:37
static sendSharedPull(array $pull)
Определения OpenChannelChat.php:124
static loadWithoutChat(array $source)
Определения Params.php:172
getEntityId()
Определения Chat.php:2179
getParentMessageId()
Определения Chat.php:2075
setLastMessageId(int $lastMessageId)
Определения Chat.php:2385
read(bool $onlyRecent=false, bool $byEvent=false)
Определения Chat.php:1042
getCallType()
Определения Chat.php:2133
int $markedId
Определения Chat.php:267
setChatParams(array $chatParams=[])
Определения Chat.php:561
getRelations()
Определения Chat.php:2454
updateCountersAfterMessageSend(Message $message, SendingConfig $sendingConfig)
Определения Chat.php:921
getChatId()
Определения Chat.php:1797
getDefaultEntityType()
Определения Chat.php:2167
static getRestEntityName()
Определения Chat.php:3534
sendNotificationUserDelete(int $userId, DeleteUserConfig $config)
Определения Chat.php:3249
getEntityData1()
Определения Chat.php:2191
int $diskFolderId
Определения Chat.php:252
getExtendedType(bool $forRest=true)
Определения Chat.php:3727
setPrimaryId(int $primaryId)
Определения Chat.php:1616
getBackground()
Определения Chat.php:2508
const ENTITY_TYPE_LIVECHAT
Определения Chat.php:140
getRole()
Определения Chat.php:514
setRelations(RelationCollection $relations)
Определения Chat.php:2484
string $aliasName
Определения Chat.php:270
getManageMessagesAutoDelete()
Определения Chat.php:2775
Registry $messageRegistry
Определения Chat.php:292
getId()
Определения Chat.php:1802
startRecordVoice()
Определения Chat.php:1157
const IM_TYPE_CHANNEL
Определения Chat.php:87
int $messagesAutoDeleteDelay
Определения Chat.php:287
isAutoJoinEnabled()
Определения Chat.php:2812
const AVAILABLE_PARAMS
Определения Chat.php:149
string $description
Определения Chat.php:223
getParentChatId()
Определения Chat.php:2063
setCanPost(string $canPost)
Определения Chat.php:2692
updateStateAfterMessageSend(Message $message, SendingConfig $sendingConfig)
Определения Chat.php:783
checkAccessInternal(int $userId)
Определения Chat.php:601
getBotInChat()
Определения Chat.php:2522
const IM_TYPE_PRIVATE
Определения Chat.php:82
getAvatarId()
Определения Chat.php:2104
getManageSettings()
Определения Chat.php:2655
getChatParams()
Определения Chat.php:568
const ROLE_GUEST
Определения Chat.php:184
const IM_TYPES_TRANSLATE
Определения Chat.php:113
getFieldsForRecent(int $userId, Message $message)
Определения Chat.php:877
sendMessageUsersAdd(array $usersToAdd, AddUsersConfig $config)
Определения Chat.php:2905
sendMessage(Message $message, ?SendingConfig $sendingConfig=null)
Определения Chat.php:661
getValidUsersToAdd(array $userIds)
Определения Chat.php:3073
getRecentSectionsForGuest()
Определения Chat.php:430
setDialogId(string $dialogId)
Определения Chat.php:1811
onAfterMessageUpdate(Message $message)
Определения Chat.php:718
toRestFormat(array $option=[])
Определения Chat.php:3572
prepareMessage(Message $message)
Определения Chat.php:772
bool $isDiskFolderFilled
Определения Chat.php:306
clearLegacyCache(int $userId)
Определения Chat.php:3348
getSelfRelation()
Определения Chat.php:2491
getDefaultExtranet()
Определения Chat.php:2092
const MANAGE_RIGHTS_MEMBER
Определения Chat.php:176
getDefaultLastMessageStatus()
Определения Chat.php:2417
setUserIds(?array $userIds)
Определения Chat.php:450
setAvatarId(?int $avatarId)
Определения Chat.php:2098
getRelationByReason(Reason $reason)
Определения Chat.php:2479
const ENTITY_TYPE_GENERAL
Определения Chat.php:131
getUpdatedFieldsForRecent(Message $message)
Определения Chat.php:899
setMarkedId(?int $markedId)
Определения Chat.php:499
updateMessage(Message $message)
Определения Chat.php:962
sendPushUserDelete(int $userId, RelationCollection $oldRelations)
Определения Chat.php:3387
getCallToken()
Определения Chat.php:2801
getDateCreate()
Определения Chat.php:2429
static cleanAccessCache(int $chatId)
Определения Chat.php:370
canDisableUserDeleteMessage()
Определения Chat.php:3911
getCallNumber()
Определения Chat.php:2145
getDescription()
Определения Chat.php:2016
setExtranet(?bool $extranet)
Определения Chat.php:2081
getMessageAutoDeleteConfigs()
Определения Chat.php:3544
sendPushUpdateMessage(Message $message)
Определения Chat.php:1143
setManageUsersDelete(string $manageUsersDelete)
Определения Chat.php:2582
getUserIds()
Определения Chat.php:457
int $messageCount
Определения Chat.php:256
getAvatar(bool $addBlankPicture=false, bool $withDomain=false)
Определения Chat.php:2109
getLastMessageStatus()
Определения Chat.php:2412
const IM_TYPE_OPEN_LINE
Определения Chat.php:85
deleteChat()
Определения Chat.php:3806
sendPushReadSelf(MessageCollection $messages, int $lastId, int $counter)
Определения Chat.php:1185
static array $chatStaticCache
Определения Chat.php:194
setEntityData3(?string $entityData3)
Определения Chat.php:2209
updateStateAfterRelationsAdd(array $usersToAdd)
Определения Chat.php:2978
needToSendMessageUserDelete()
Определения Chat.php:3208
getDiskFolder()
Определения Chat.php:2256
getExtranet()
Определения Chat.php:2087
static getSharedChatsWithUser(int $userId, int $limit=50, int $offset=0, ?int $currentUserId=null)
Определения Chat.php:1737
string $role
Определения Chat.php:268
getColor(bool $forRest=false)
Определения Chat.php:2028
getUsersForPush(bool $skipBot=false, bool $skipSelf=true)
Определения Chat.php:1346
setEntityData1(?string $entityData1)
Определения Chat.php:2185
getAuthorId()
Определения Chat.php:1982
getPublicOption()
Определения Chat.php:3714
getStorageId()
Определения Chat.php:2251
static getDialogIdByContextId(string $contextId, ?int $userId=null)
Определения Chat.php:1901
processSendToOtherChat(Message $message, SendingConfig $config)
Определения Chat.php:764
getUsersToAddToRecent()
Определения Chat.php:833
const ENTITY_TYPE_VIDEOCONF
Определения Chat.php:130
getPinMessageId()
Определения Chat.php:2121
toPullFormat()
Определения Chat.php:3629
beforeSaveType()
Определения Chat.php:1963
getUserCounter()
Определения Chat.php:2362
const IM_TYPE_AI_ASSISTANT
Определения Chat.php:93
Im V2 Relation ChatRelations $chatRelations
Определения Chat.php:294
getPopupData(array $excludedList=[])
Определения Chat.php:3567
__construct($source=null)
Определения Chat.php:312
getPrimaryId()
Определения Chat.php:1607
updateRecentItems(Message $message)
Определения Chat.php:838
getUnreadId()
Определения Chat.php:3735
const IM_TYPE_COMMENT
Определения Chat.php:84
getRecentConfig()
Определения Chat.php:3549
const IM_TYPE_OPEN
Определения Chat.php:89
int $authorId
Определения Chat.php:219
getDisplayedTitle()
Определения Chat.php:2004
checkAllowedAction(string $action)
Определения Chat.php:3939
getAuthor()
Определения Chat.php:1987
int $lastFileId
Определения Chat.php:264
setParentChatId(int $parentChatId)
Определения Chat.php:2057
string $entityData2
Определения Chat.php:247
getPushService(Message $message, SendingConfig $config)
getRelationByUserId(int $userId)
Определения Chat.php:2496
getUserDeleteMessageText(int $deletedUserId)
Определения Chat.php:3282
DateTime $dateMessage
Определения Chat.php:265
setPinMessageId(?int $pinMessageId)
Определения Chat.php:2115
addIndex()
Определения Chat.php:3757
getMultidialogData()
Определения Chat.php:3666
prepareAliasToLoad($alias)
Определения Chat.php:474
const MANAGE_RIGHTS_MANAGERS
Определения Chat.php:178
getCounterType()
Определения Chat.php:1958
string $entityId
Определения Chat.php:243
getEntityData2()
Определения Chat.php:2203
readTo(Message $message, bool $byEvent=false)
Определения Chat.php:1107
getRecentSections()
Определения Chat.php:425
const MANAGE_RIGHTS_NONE
Определения Chat.php:175
string $title
Определения Chat.php:221
string $manageUsersDelete
Определения Chat.php:277
getUserCount()
Определения Chat.php:2349
const ENTITY_TYPE_PRIVATE_AI_ASSISTANT
Определения Chat.php:134
addUsers(array $userIds, AddUsersConfig $config=new AddUsersConfig())
Определения Chat.php:2835
checkColor()
Определения Chat.php:549
setDateCreate(?DateTime $dateCreate)
Определения Chat.php:2423
static loadPhrases()
Определения Chat.php:3493
const IM_TYPE_SYSTEM
Определения Chat.php:86
checkTitle()
Определения Chat.php:2542
setPrevMessageId(int $prevMessageId)
Определения Chat.php:2373
const ROLE_MANAGER
Определения Chat.php:182
onBeforeMessageSend(Message $message, SendingConfig $config)
Определения Chat.php:723
getRawRelations()
Определения Chat.php:2459
setMessageCount(int $messageCount)
Определения Chat.php:2329
bool $isFilledNonCachedData
Определения Chat.php:305
containsCopilot()
Определения Chat.php:445
changeAuthor()
Определения Chat.php:3397
sendEventRead(int $startId, int $endId, int $counter, bool $byEvent)
Определения Chat.php:1253
getMuteList(bool $fullList=false)
Определения Chat.php:3686
getDefaultMessagesAutoDeleteDelay()
Определения Chat.php:2681
Im V2 Call CallToken $callToken
Определения Chat.php:307
int $callType
Определения Chat.php:237
array $accessCache
Определения Chat.php:196
isValidToAdd(int $userId)
Определения Chat.php:3096
sendEventUserDelete(int $userId)
Определения Chat.php:3353
readAllMessages(bool $byEvent=false)
Определения Chat.php:1061
const IM_TYPE_AI_ASSISTANT_ENTITY
Определения Chat.php:94
sendEventUsersAdd(array $usersToAdd)
Определения Chat.php:3108
setEntityData2(?string $entityData2)
Определения Chat.php:2197
static updateStateAfterOrmEvent(int $id, array $fields)
Определения Chat.php:3979
getManageUI()
Определения Chat.php:2629
string $dialogId
Определения Chat.php:207
getDefaultManageUI()
Определения Chat.php:2634
int $prevMessageId
Определения Chat.php:261
getLastMessageViewsByGroups()
Определения Chat.php:1282
sendPushReadOpponent(MessageCollection $messages, int $lastId)
Определения Chat.php:1211
static readAllChats(int $userId)
Определения Chat.php:1018
getDialogContextId()
Определения Chat.php:1890
const MANAGE_RIGHTS_OWNER
Определения Chat.php:177
getReadService()
Определения Chat.php:2439
string $manageUsersAdd
Определения Chat.php:276
int $chatId
Определения Chat.php:198
getOrCreateDiskFolder()
Определения Chat.php:2238
string $manageUI
Определения Chat.php:279
setDiskFolderId(?int $diskFolderId)
Определения Chat.php:2221
getType()
Определения Chat.php:1946
string $entityType
Определения Chat.php:241
int $userCounter
Определения Chat.php:259
getDefaultColor()
Определения Chat.php:2049
add(array $params)
Определения Chat.php:435
readMessages(?MessageCollection $messages, bool $byEvent=false)
Определения Chat.php:1066
getMessageCount()
Определения Chat.php:2335
string $lastMessageStatus
Определения Chat.php:272
getAccessCodesForDiskFolder()
Определения Chat.php:2313
setManageUI(string $manageUI)
Определения Chat.php:2613
const EXTRANET_CAN_SEE_HISTORY
Определения Chat.php:188
markFilledNonCachedData(bool $isFilledNonCachedData)
Определения Chat.php:505
sendPushRead(MessageCollection $messages, int $lastId, int $counter)
Определения Chat.php:1148
createDiskFolder()
Определения Chat.php:2285
const IM_TYPE_CHAT
Определения Chat.php:83
isExist()
Определения Chat.php:410
getEntityData3()
Определения Chat.php:2215
const ROLE_MEMBER
Определения Chat.php:183
const ENTITY_TYPE_GENERAL_CHANNEL
Определения Chat.php:133
setManageSettings(string $manageSettings)
Определения Chat.php:2643
string $color
Определения Chat.php:225
getDefaultManageSettings()
Определения Chat.php:2660
int $userCount
Определения Chat.php:258
setAliasName(string $aliasName)
Определения Chat.php:467
getTitle()
Определения Chat.php:1999
insertRecent(array $fields)
Определения Chat.php:869
setMessagesAutoDeleteDelay(int $messagesAutoDeleteDelay)
Определения Chat.php:2665
getMarkedId()
Определения Chat.php:489
Folder $diskFolder
Определения Chat.php:254
getManageMessages()
Определения Chat.php:2722
getPermissions()
Определения Chat.php:3554
setLastMessageStatus(?string $lastMessageStatus)
Определения Chat.php:2406
updateIndex()
Определения Chat.php:3774
getMessage(int $messageId)
Определения Chat.php:642
static getCanPostList()
Определения Chat.php:2791
int $pinMessageId
Определения Chat.php:235
getDefaultDateCreate()
Определения Chat.php:2434
setEntityType(?string $entityType)
Определения Chat.php:2151
getStartId(?int $userId=null)
Определения Chat.php:405
sendMessageOnUserDeleteMessageDisabled(bool $skipRecent)
Определения Chat.php:3916
containsCollaber()
Определения Chat.php:440
getDiskFolderId()
Определения Chat.php:2227
resolveRelationConflicts(array $userIds, AddUsersConfig $config)
Определения Chat.php:2869
string $type
Определения Chat.php:217
setCallType(?int $callType)
Определения Chat.php:2127
const ROLE_NONE
Определения Chat.php:185
const ENTITY_TYPES
Определения Chat.php:142
updateChatAfterMessageSend(Message $message)
Определения Chat.php:800
getAliasName()
Определения Chat.php:462
const IM_TYPE_COLLAB
Определения Chat.php:91
disableUserDeleteMessage(bool $skipRecent=false)
Определения Chat.php:3897
getManagerList(bool $fullList=true)
Определения Chat.php:3671
getLastMessageViews()
Определения Chat.php:1270
setParentMessageId(int $messageId)
Определения Chat.php:2069
string $entityData1
Определения Chat.php:245
setEntityId(?string $entityId)
Определения Chat.php:2173
getEntityLink()
Определения Chat.php:3539
RelationProvider $relationProvider
Определения Chat.php:303
DateTime $dateCreate
Определения Chat.php:274
deleteMessage(Message $message)
Определения Chat.php:977
static getInstance(?int $chatId)
Определения Chat.php:335
RecentConfigManager $recentConfigManager
Определения Chat.php:301
getTextFieldEnabled()
Определения Chat.php:2515
setManageUsersAdd(string $manageUsersAdd)
Определения Chat.php:2551
onAfterMessageSend(Message $message, SendingService $sendingService)
Определения Chat.php:742
setChatId(int $chatId)
Определения Chat.php:1788
string $manageMessages
Определения Chat.php:283
getRelationProvider()
Определения Chat.php:2501
setUserCounter(?int $userCounter)
Определения Chat.php:2356
bool $extranet
Определения Chat.php:231
const ENTITY_TYPE_LINE
Определения Chat.php:139
static fillSelfRelations(array $chats, ?int $userId=null)
Определения Chat.php:990
getMentionService(SendingConfig $config)
Определения Chat.php:953
updateRecentAfterMessageSend(Message $message, SendingConfig $config)
Определения Chat.php:813
getManageUsersAdd()
Определения Chat.php:2567
getDefaultManageMessagesAutoDelete()
Определения Chat.php:2786
prepareMessageParamsFromUserDelete(string $message, bool $skipRecent)
Определения Chat.php:3234
const IM_TYPE_EXTERNAL
Определения Chat.php:92
getManageUsersDelete()
Определения Chat.php:2598
validateColor()
Определения Chat.php:2039
getRelationsByUserIds(array $userIds)
Определения Chat.php:2474
const IM_TYPES
Определения Chat.php:97
static getDataClass()
Определения Chat.php:1599
getDefaultManageMessages()
Определения Chat.php:2727
setTitle(?string $title)
Определения Chat.php:1993
getRelationFacade()
Определения Chat.php:2464
sendPushUsersAdd(array $usersToAdd, RelationCollection $oldRelations)
Определения Chat.php:2968
sendMessageUserDelete(int $userId, DeleteUserConfig $config)
Определения Chat.php:3213
string $entityData3
Определения Chat.php:250
string $callNumber
Определения Chat.php:239
int $parentMessageId
Определения Chat.php:229
int $avatarId
Определения Chat.php:233
setManageMessages(string $manageMessages)
Определения Chat.php:2701
setDescription(?string $description)
Определения Chat.php:2010
getLastId()
Определения Chat.php:3746
getDefaultManageUsersAdd()
Определения Chat.php:2573
getUserId($user)
Определения Chat.php:606
setContext(?Context $context)
Определения Chat.php:3498
sendMessageUpdateAvatar(bool $skipRecent=false)
Определения Chat.php:3866
isNew()
Определения Chat.php:2537
getLastMessageId()
Определения Chat.php:2391
setCallNumber(?string $callNumber)
Определения Chat.php:2139
canUserAutoJoin(?int $userId=null)
Определения Chat.php:2817
getEntityType()
Определения Chat.php:2157
Background $background
Определения Chat.php:296
addUsersToRelation(array $usersToAdd, AddUsersConfig $config)
Определения Chat.php:3023
int $parentChatId
Определения Chat.php:227
getLoadContextMessage(bool $ignoreMark=false)
Определения Chat.php:3507
static cleanCache(int $id, bool $cleanStaticCache=true)
Определения Chat.php:359
deleteUser(int $userId, DeleteUserConfig $config=new DeleteUserConfig())
Определения Chat.php:3153
getDialogId(?int $contextUserId=null)
Определения Chat.php:1878
setDiskFolder(?Folder $folder)
Определения Chat.php:2232
filterUsersToMentionAnchor(array $userIds)
Определения Chat.php:1861
updateStateAfterMembersAdd(array $newMembers)
Определения Chat.php:2996
setUserCount(int $userCount)
Определения Chat.php:2343
needToSendPublicPull()
Определения Chat.php:3934
TextFieldEnabled $textFieldEnabled
Определения Chat.php:297
const IM_TYPE_COPILOT
Определения Chat.php:90
int $lastMessageId
Определения Chat.php:263
static find(array $params, ?Context $context=null)
Определения Chat.php:1632
getPrevMessageId()
Определения Chat.php:2379
createRelation(int $userId, AddUsersConfig $config)
Определения Chat.php:3049
updateStateAfterUserDelete(int $deletedUserId, DeleteUserConfig $config)
Определения Chat.php:3306
updateRelationsAfterMessageSend(Message $message)
Определения Chat.php:909
checkAccess(int|User|null $user=null)
Определения Chat.php:580
setManageMessagesAutoDelete(string $manageMessagesAutoDelete)
Определения Chat.php:2732
shouldAddToRecent()
Определения Chat.php:420
string $manageSettings
Определения Chat.php:281
getDefaultManageUsersDelete()
Определения Chat.php:2604
filterUsersToMention(array $userIds)
Определения Chat.php:1840
setColor(?string $color)
Определения Chat.php:2022
const ENTITY_TYPE_FAVORITE
Определения Chat.php:132
addToRecent(array $users, Message $message)
Определения Chat.php:846
array $usersIds
Определения Chat.php:285
setAuthorId(int $authorId)
Определения Chat.php:1976
const IM_TYPE_OPEN_CHANNEL
Определения Chat.php:88
const ROLE_OWNER
Определения Chat.php:181
fillNonCachedData()
Определения Chat.php:3521
getMessagesAutoDeleteDelay()
Определения Chat.php:2676
getRelationsForSendMessage()
Определения Chat.php:737
static mirrorDataEntityFields()
Определения Chat.php:1379
Params $chatParams
Определения Chat.php:289
getLastFileId()
Определения Chat.php:2398
const MAX_USERS_TO_DISABLE_DELETE_MESSAGE
Определения Chat.php:189
canDo(Action $action, mixed $target=null)
Определения Chat.php:3954
ReadService $readService
Определения Chat.php:299
setType(string $type)
Определения Chat.php:1928
save()
Определения Chat.php:378
getMessageRegistry()
Определения Chat.php:633
hideUser(int $userId)
Определения Chat.php:3192
logToSyncAfterMessageSend(Message $message)
Определения Chat.php:932
join(bool $withMessage=true)
Определения Chat.php:2824
isCounterIncrementAllowed()
Определения Chat.php:415
static getCurrent()
Определения User.php:89
static getInstance(?int $id)
Определения User.php:72
static formatStartRecordVoice(Chat $chat)
Определения PushFormat.php:196
fireEventAfterMessageSend(Chat $chat, Message $message)
Определения SendingService.php:160
updateMessageUuid(Message $message)
Определения SendingService.php:100
static getInstance(int $chatId)
Определения ChatRelations.php:35
static getStartId(int $userId, int $chatId)
Определения RelationCollection.php:112
static find(array $filter, array $order=[], ?int $limit=null, ?Context $context=null, array $select=self::COMMON_FIELDS)
Определения RelationCollection.php:50
static getInstance()
Определения Logger.php:37
static getConnection($name="")
Определения application.php:638
Определения result.php:20
static getInstance()
Определения servicelocator.php:33
Определения event.php:5
$code
Определения entity.php:53
$fields
Определения entity.php:45
static add($recipient, array $parameters, $channelType=\CPullChannel::TYPE_PRIVATE)
Определения event.php:22
static ChangeFolderMembers($chatId, $userId, $append=true)
Определения im_disk.php:1974
static GetStorage(?int $chatId=null)
Определения im_disk.php:30
static GetMaxFileId($chatId)
Определения im_disk.php:1555
static GetStorageId(?int $chatId=null)
Определения im_disk.php:2211
static GetNotifyAccess($userId, $moduleId, $eventId, $clientId)
Определения im_settings.php:255
const CLIENT_SITE
Определения im_settings.php:15
if(!\Bitrix\Main\Loader::includeModule('clouds')) $lastId
Определения sync.php:68
$options
Определения commerceml2.php:49
$data['IS_AVAILABLE']
Определения .description.php:13
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
background color
Определения file_new.php:745
$res
Определения filter_act.php:7
$result
Определения get_property_values.php:14
if(Loader::includeModule( 'bitrix24')) elseif(Loader::includeModule('intranet') &&CIntranetUtils::getPortalZone() !=='ru') $description
Определения .description.php:24
const IM_NOTIFY_SYSTEM
Определения include.php:38
const IM_STATUS_READ
Определения include.php:42
const IM_MESSAGE_OPEN_LINE
Определения include.php:26
Определения RegistryEntry.php:6
$context
Определения csv_new_setup.php:223
ExecuteModuleEventEx($arEvent, $arParams=[])
Определения tools.php:5214
htmlspecialcharsback($str)
Определения tools.php:2693
GetModuleEvents($MODULE_ID, $MESSAGE_ID, $bReturnArray=false)
Определения tools.php:5177
Определения auth.php:9
Определения Uuid.php:3
Определения ChatsSync.php:3
Определения ActionUuid.php:3
Определения culture.php:9
Определения arrayresult.php:2
Определения ufield.php:9
Определения Image.php:9
Определения base32.php:2
$user
Определения mysql_to_pgsql.php:33
$entityId
Определения payment.php:4
$message
Определения payment.php:8
$counter
Определения options.php:5
$event
Определения prolog_after.php:141
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
<? endif;?> window document title
Определения prolog_main_admin.php:76
$config
Определения quickway.php:69
if(empty($signedUserToken)) $key
Определения quickway.php:257
if(empty($decryptedData)) $storage
Определения quickway.php:270
else $userName
Определения order_form.php:75
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
Определения waybill.php:936
$background
Определения html.php:27
$messages
Определения template.php:8
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
Определения template.php:799
$title
Определения pdf.php:123
$option
Определения options.php:1711
$counters
Определения options.php:100
$action
Определения file_dialog.php:21
if( $fieldsExist) if($parametricFieldsExist) $commonFields
Определения yandex_run.php:551