Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
PrivateChat.php
1<?php
2
3namespace Bitrix\Im\V2\Chat;
4
31
32class PrivateChat extends Chat implements PopupDataAggregatable
33{
34 protected const EXTRANET_CAN_SEE_HISTORY = true;
35
36 protected function getDefaultType(): string
37 {
38 return self::IM_TYPE_PRIVATE;
39 }
40
41 protected function checkAccessWithoutCaching(int $userId): bool
42 {
43 return $this->getCompanion($userId)->hasAccess($userId);
44 }
45
50 public function allowMention(): bool
51 {
52 return false;
53 }
54
55 public function setManageSettings(string $manageSettings): Chat
56 {
57 return $this;
58 }
59
60 public function setManageUsersAdd(string $manageUsersAdd): Chat
61 {
62 return $this;
63 }
64
65 public function setManageUsersDelete(string $manageUsersDelete): Chat
66 {
67 return $this;
68 }
69
70 public function setManageUI(string $manageUI): Chat
71 {
72 return $this;
73 }
74
75 public function setCanPost(string $canPost): Chat
76 {
77 return $this;
78 }
79
80 public function getDialogId(): ?string
81 {
82 if ($this->dialogId || !$this->getChatId())
83 {
84 return $this->dialogId;
85 }
86
87 $this->dialogId = $this->getCompanion()->getId();
88
89 return $this->dialogId;
90 }
91
92 public function getDialogContextId(): ?string
93 {
94 return $this->getDialogId() . ':' .$this->getContext()->getUserId();
95 }
96
97 public function getStartId(?int $userId = null): int
98 {
99 return 0;
100 }
101
105 public function getOpponentId(): int
106 {
108 $opponentUserId = 0;
109 foreach ($this->getRelations() as $relation)
110 {
111 if (
112 User::getInstance($relation->getUserId())->isActive()
113 && $this->getAuthorId() != $relation->getUserId()
114 )
115 {
116 $opponentUserId = $relation->getUserId();
117 break;
118 }
119 }
120
121 return $opponentUserId;
122 }
123
128 public function riseInRecent(Message $message): void
129 {
131 $opponentUserId = 0;
132 foreach ($this->getRelations() as $relation)
133 {
134 if (
135 User::getInstance($relation->getUserId())->isActive()
136 && $message->getAuthorId() != $relation->getUserId()
137 )
138 {
139 $opponentUserId = $relation->getUserId();
140 break;
141 }
142 }
143
144 foreach ($this->getRelations() as $relation)
145 {
146 if (!User::getInstance($relation->getUserId())->isActive())
147 {
148 continue;
149 }
150
151 \CIMContactList::SetRecent([
152 'ENTITY_ID' => $relation->getUserId() == $opponentUserId ? $message->getAuthorId() : $opponentUserId,
153 'MESSAGE_ID' => $message->getMessageId(),
154 'CHAT_TYPE' => self::IM_TYPE_PRIVATE,
155 'CHAT_ID' => $relation->getChatId(),
156 'RELATION_ID' => $relation->getId(),
157 'USER_ID' => $relation->getUserId(),
158 ]);
159 }
160 }
161
162 public function getCompanion(?int $userId = null): \Bitrix\Im\V2\Entity\User\User
163 {
164 $userId = $userId ?? $this->getContext()->getUserId();
165
166 $relations = $this->getRelations(['LIMIT' => 2]);
167
168 if (!$relations->hasUser($userId, $this->getChatId()))
169 {
170 return new NullUser();
171 }
172
173 foreach ($relations as $relation)
174 {
175 if ($relation->getUserId() !== $userId)
176 {
177 return $relation->getUser();
178 }
179 }
180
181 return new NullUser();
182 }
183
184 public function getDisplayedTitle(): ?string
185 {
186 return Loc::getMessage(
187 'IM_PRIVATE_CHAT_TITLE',
188 [
189 //todo: replace to $this->getContext()->getUser() when ->getUser will return V2 User
190 '#CHAT_MEMBER_NAME_1#' => \Bitrix\Im\V2\Entity\User\User::getInstance($this->getContext()->getUserId())->getName(),
191 '#CHAT_MEMBER_NAME_2#' => $this->getCompanion()->getName(),
192 ]
193 );
194 }
195
196 public function addUsers(array $userIds, array $managerIds = [], ?bool $hideHistory = null, bool $withMessage = true, bool $skipRecent = false): Chat
197 {
198 return $this;
199 }
200
201 public function sendPushUpdateMessage(Message $message): void
202 {
203 $pushFormat = new Message\PushFormat();
204 $push = $pushFormat->formatMessageUpdate($message);
205 $authorId = $message->getAuthorId();
206 $opponentId = $this->getCompanion($authorId)->getId();
207
208 $push['params']['dialogId'] = $authorId;
209 $push['params']['fromUserId'] = $authorId;
210 $push['params']['toUserId'] = $opponentId;
211 Event::add($opponentId, $push);
212
213 $push['params']['dialogId'] = $opponentId;
214 $push['params']['fromUserId'] = $opponentId;
215 $push['params']['toUserId'] = $authorId;
216 Event::add($authorId, $push);
217 }
218
219 protected function sendPushReadSelf(MessageCollection $messages, int $lastId, int $counter): void
220 {
221 $companionId = $this->getDialogId();
222 \Bitrix\Pull\Event::add($this->getContext()->getUserId(), [
223 'module_id' => 'im',
224 'command' => 'readMessage',
225 'params' => [
226 'dialogId' => $companionId,
227 'chatId' => $this->getChatId(),
228 'senderId' => $this->getContext()->getUserId(),
229 'id' => (int)$companionId,
230 'userId' => (int)$companionId,
231 'lastId' => $lastId,
232 'counter' => $counter,
233 'muted' => false,
234 'unread' => Recent::isUnread($this->getContext()->getUserId(), $this->getType(), $this->getDialogId() ?? ''),
235 'viewedMessages' => $messages->getIds(),
236 ],
237 'extra' => \Bitrix\Im\Common::getPullExtra()
238 ]);
239 }
240
241 protected function sendPushReadOpponent(MessageCollection $messages, int $lastId): array
242 {
243 $companionId = $this->getDialogId();
244 $pushMessage = [
245 'module_id' => 'im',
246 'command' => 'readMessageOpponent',
247 'expiry' => 3600,
248 'params' => [
249 'dialogId' => $this->getContext()->getUserId(),
250 'chatId' => $this->getChatId(),
251 'userId' => $this->getContext()->getUserId(),
252 'userName' => User::getInstance($this->getContext()->getUserId())->getFullName(false),
253 'lastId' => $lastId,
254 'date' => (new DateTime())->format('c'),
255 'chatMessageStatus' => $this->getReadService()->getChatMessageStatus($this->getChatId()),
256 'viewedMessages' => $messages->getIds(),
257 ],
258 'extra' => \Bitrix\Im\Common::getPullExtra()
259 ];
260 \Bitrix\Pull\Event::add($companionId, $pushMessage);
261
262 return $pushMessage;
263 }
264
265 protected function sendPushUnreadSelf(int $unreadToId, int $lastId, int $counter, ?array $lastMessageStatuses = null): void
266 {
267 \Bitrix\Pull\Event::add($this->getContext()->getUserId(), [
268 'module_id' => 'im',
269 'command' => 'unreadMessage',
270 'expiry' => 3600,
271 'params' => [
272 'dialogId' => $this->getDialogId(),
273 'chatId' => $this->chatId,
274 'userId' => (int)$this->getDialogId(),
275 'date' => new \Bitrix\Main\Type\DateTime(),
276 'counter' => $counter,
277 'muted' => false,
278 'unread' => Recent::isUnread($this->getContext()->getUserId(), $this->getType(), $this->getDialogId()),
279 'unreadToId' => $unreadToId,
280 ],
281 'push' => ['badge' => 'Y'],
282 'extra' => \Bitrix\Im\Common::getPullExtra()
283 ]);
284 }
285
286 protected function sendEventRead(int $startId, int $endId, int $counter, bool $byEvent): void
287 {
288 foreach(GetModuleEvents("im", "OnAfterUserRead", true) as $arEvent)
289 {
290 ExecuteModuleEventEx($arEvent, array(Array(
291 'DIALOG_ID' => $this->getDialogId(),
292 'CHAT_ID' => $this->getChatId(),
293 'CHAT_ENTITY_TYPE' => 'USER',
294 'CHAT_ENTITY_ID' => '',
295 'START_ID' => $startId,
296 'END_ID' => $endId,
297 'COUNT' => $counter,
298 'USER_ID' => $this->getContext()->getUserId(),
299 'BY_EVENT' => $byEvent
300 )));
301 }
302 }
303
311 public function sendMessage($message, $sendingConfig = null): Result
312 {
313 $result = new Result;
314
315 if (!$this->getChatId())
316 {
317 return $result->addError(new ChatError(ChatError::WRONG_TARGET_CHAT));
318 }
319
320 if (is_string($message))
321 {
322 $message = (new Message)->setMessage($message);
323 }
324 elseif (!$message instanceof Message)
325 {
326 $message = new Message($message);
327 }
328
329 $message
330 ->setRegistry($this->messageRegistry)
331 ->setContext($this->context)
332 ->setChatId($this->getChatId())
333 ;
334
335 if (!$message->getNotifyModule())
336 {
337 $message->setNotifyModule('im');
338 }
339 if ($message->isSystem())
340 {
341 $message->setNotifyEvent(Notify::EVENT_PRIVATE_SYSTEM);
342 }
343 else
344 {
345 $message->setNotifyEvent(Notify::EVENT_PRIVATE);
346 }
347
348 // config for sending process
349 if ($sendingConfig instanceof SendingConfig)
350 {
351 $sendingServiceConfig = $sendingConfig;
352 }
353 else
354 {
355 $sendingServiceConfig = new SendingConfig();
356 if (is_array($sendingConfig))
357 {
358 $sendingServiceConfig->fill($sendingConfig);
359 }
360 }
361 // sending process
362 $sendService = new SendingService($sendingServiceConfig);
363 $sendService->setContext($this->context);
364
365 // check duplication by UUID
366 if (
367 !$message->isSystem()
368 && $message->getUuid()
369 )
370 {
371 $checkUuidResult = $sendService->checkDuplicateByUuid($message);
372 if (!$checkUuidResult->isSuccess())
373 {
374 return $result->addErrors($checkUuidResult->getErrors());
375 }
376 $data = $checkUuidResult->getResult();
377 if (!empty($data['messageId']))
378 {
379 return $result->setResult($checkUuidResult->getResult());
380 }
381 }
382
383 // author from current context
384 if (
385 !$message->getAuthorId()
386 && !$message->isSystem()
387 )
388 {
389 $message->setAuthorId($this->getContext()->getUserId());
390 if (!$message->getAuthorId())
391 {
392 return $result->addError(new ChatError(ChatError::WRONG_SENDER));
393 }
394 }
395
396 // Extranet cannot send system
397 if (
398 $message->isSystem()
399 && $message->getAuthorId()
400 && User::getInstance($message->getAuthorId())->isExtranet()
401 )
402 {
403 $message->markAsSystem(false);
404 }
405
406 // permissions
407 if (
408 !$sendingServiceConfig->skipUserCheck()
409 && !$sendingServiceConfig->convertMode()
410 && !$message->isSystem()
411 )
412 {
413 if (!$this->hasAccess($message->getAuthorId()))
414 {
415 return $result->addError(new ChatError(ChatError::ACCESS_DENIED));
416 }
417 }
418
419 // fire event `im:OnBeforeChatMessageAdd` before message send
420 $eventResult = $sendService->fireEventBeforeMessageSend($this, $message);
421 if (!$eventResult->isSuccess())
422 {
423 // cancel sending by event
424 return $result->addErrors($eventResult->getErrors());
425 }
426
427 // check for empty message
428 if (
429 !$message->getMessage()
430 && !$message->hasFiles()
431 && !$message->getParams()->isSet(Params::ATTACH)
432 )
433 {
434 return $result->addError(new MessageError(MessageError::EMPTY_MESSAGE));
435 }
436
437 // Replacements / DateLink
438 if ($sendingServiceConfig->generateUrlPreview())
439 {
440 $message->parseDates();
441 }
442
443 // Emoji
444 $message->checkEmoji();
445
446
447 // BB codes with disk files
448 $message->uploadFileFromText();
449
450 // Format attached files
451 $message->formatFilesMessageOut();
452
453 // Save + Save Params
454 $saveResult = $message->save();
455 if (!$saveResult->isSuccess())
456 {
457 return $result->addErrors($saveResult->getErrors());
458 }
459
460 // Unread
461 $readService = new ReadService($message->getAuthorId());
462 $readService->markMessageUnread($message, $this->getRelations());
463
464 // Chat message counter
465 $this
466 ->setLastMessageId($message->getMessageId())
467 ->incrementMessageCount()
468 ->save()
469 ;
470
471 // Recent
472 if ($sendingServiceConfig->addRecent())
473 {
474 $readService->markRecentUnread($message);
475 }
476
477 // Counters
478 $counters = [];
479 if ($sendingServiceConfig->sendPush())
480 {
481 $counters = $readService->getCountersForUsers($message, $this->getRelations());
482 }
483
484 // fire event `im:OnAfterMessagesAdd`
485 $sendService->fireEventAfterMessageSend($this, $message);
486
487 // Recent
488 if (
489 $sendingServiceConfig->addRecent()
490 && !$sendingServiceConfig->skipAuthorAddRecent()// Do not add author into recent list in case of self message chat.
491 )
492 {
493 $this->riseInRecent($message);
494 }
495
496 // Rich
497 if ($sendingServiceConfig->generateUrlPreview())
498 {
499 // generate preview or set bg job
500 $message->generateUrlPreview();
501 }
502
503 if ($this->getParentMessageId())
504 {
505 $this->updateParentMessageCount();
506 }
507
508 // send Push
509 if ($sendingServiceConfig->sendPush())
510 {
511 $pushService = new PushService($sendingServiceConfig);
512 $pushService->sendPushPrivateChat($this, $message, $counters);
513 }
514
515 // Mentions
516 if (!$message->isSystem())
517 {
518 $mentionService = new MentionService($sendingServiceConfig);
519 $mentionService->setContext($this->context);
520 $mentionService->sendMentions($this, $message);
521 }
522
523 // Run message command
524 $botService = new BotService($sendingServiceConfig);
525 $botService->setContext($this->context);
526 $botService->runMessageCommand($this, $message);
527
528 // Links
529 (new UrlService())->saveUrlsFromMessage($message);
530
531 // search
532 $message->updateSearchIndex();
533
534 $result->setResult(['messageId' => $message->getMessageId()]);
535
536 return $result;
537 }
538
553 public static function find(array $params, ?Context $context = null): Result
554 {
555 $result = new Result;
556
557 if (isset($params['CHAT_ID']))
558 {
559 $chatId = (int)$params['CHAT_ID'];
560 $relations = \CIMChat::getRelationById($chatId, false, true, false);
561
562 $params['TO_USER_ID'] = (int)$params['FROM_USER_ID'];//check for self-personal chat
563 foreach ($relations as $rel)
564 {
565 if (
566 $params['TO_USER_ID']
567 && $rel['USER_ID'] == $params['FROM_USER_ID']
568 )
569 {
570 continue;
571 }
572
573 $params['TO_USER_ID'] = (int)$rel['USER_ID'];
574 }
575 }
576
577 if (empty($params['FROM_USER_ID']))
578 {
579 $context = $context ?? Locator::getContext();
580 $params['FROM_USER_ID'] = $context->getUserId();
581 }
582
583 $params['FROM_USER_ID'] = (int)$params['FROM_USER_ID'];
584 $params['TO_USER_ID'] = (int)$params['TO_USER_ID'];
585
586 if ($params['FROM_USER_ID'] <= 0)
587 {
588 return $result->addError(new ChatError(ChatError::WRONG_SENDER));
589 }
590 if ($params['TO_USER_ID'] <= 0)
591 {
592 return $result->addError(new ChatError(ChatError::WRONG_RECIPIENT));
593 }
594
595 $connection = \Bitrix\Main\Application::getConnection();
596
597 $res = $connection->query("
598 SELECT
599 C.*
600 FROM
601 b_im_chat C,
602 b_im_relation RF,
603 b_im_relation RT
604 WHERE
605 C.ID = RT.CHAT_ID
606 AND RF.CHAT_ID = RT.CHAT_ID
607 AND C.TYPE = '" . self::IM_TYPE_PRIVATE . "'
608 AND RF.USER_ID = " . $params['FROM_USER_ID'] . "
609 AND RT.USER_ID = " . $params['TO_USER_ID'] . "
610 AND RF.MESSAGE_TYPE = '" . self::IM_TYPE_PRIVATE . "'
611 AND RT.MESSAGE_TYPE = '" . self::IM_TYPE_PRIVATE . "'
612 ");
613 if ($row = $res->fetch())
614 {
615 $result->setResult([
616 'ID' => (int)$row['ID'],
617 'TYPE' => $row['TYPE'],
618 'ENTITY_TYPE' => $row['ENTITY_TYPE'],
619 'ENTITY_ID' => $row['ENTITY_ID'],
620 ]);
621 }
622
623 return $result;
624 }
625
626 public function add(array $params, ?Context $context = null): Result
627 {
628 $result = new Result;
629
630 $paramsResult = $this->prepareParams($params);
631 if (!$paramsResult->isSuccess())
632 {
633 return $result->addErrors($paramsResult->getErrors());
634 }
635
636 $params = $paramsResult->getResult();
637
638 if (!\Bitrix\Im\Dialog::hasAccess($params['FROM_USER_ID'], $params['TO_USER_ID']))
639 {
640 return $result->addError(new ChatError(ChatError::ACCESS_DENIED));
641 }
642
643 if ($params['FROM_USER_ID'] == $params['TO_USER_ID'])
644 {
645 return (new FavoriteChat($params))->add($params);
646 }
647
648 $chatResult = self::find($params);
649 if ($chatResult->isSuccess() && $chatResult->hasResult())
650 {
651 $chatParams = $chatResult->getResult();
652
653 return $result->setResult([
654 'CHAT_ID' => (int)$chatParams['ID'],
655 'CHAT' => self::load($chatParams),
656 ]);
657 }
658
659 $chat = new static($params);
660 $chat->save();
661
662 if ($chat->getChatId() <= 0)
663 {
664 return $result->addError(new ChatError(ChatError::CREATION_ERROR));
665 }
666
667 \Bitrix\Im\Model\RelationTable::add([
668 'CHAT_ID' => $chat->getChatId(),
669 'MESSAGE_TYPE' => \IM_MESSAGE_PRIVATE,
670 'USER_ID' => $params['FROM_USER_ID'],
671 'STATUS' => \IM_STATUS_READ,
672 ]);
673 \Bitrix\Im\Model\RelationTable::add([
674 'CHAT_ID' => $chat->getChatId(),
675 'MESSAGE_TYPE' => \IM_MESSAGE_PRIVATE,
676 'USER_ID' => $params['TO_USER_ID'],
677 'STATUS' => \IM_STATUS_READ,
678 ]);
679
680 $botJoinFields = [
681 'CHAT_TYPE' => \IM_MESSAGE_PRIVATE,
682 'MESSAGE_TYPE' => \IM_MESSAGE_PRIVATE
683 ];
684 if (
685 User::getInstance($params['FROM_USER_ID'])->isExists()
686 && !User::getInstance($params['FROM_USER_ID'])->isBot()
687 )
688 {
689 $botJoinFields['BOT_ID'] = $params['TO_USER_ID'];
690 $botJoinFields['USER_ID'] = $params['FROM_USER_ID'];
691 $botJoinFields['TO_USER_ID'] = $params['TO_USER_ID'];
692 $botJoinFields['FROM_USER_ID'] = $params['FROM_USER_ID'];
693 \Bitrix\Im\Bot::onJoinChat($params['FROM_USER_ID'], $botJoinFields);
694 }
695 elseif (
696 User::getInstance($params['TO_USER_ID'])->isExists()
697 && !User::getInstance($params['TO_USER_ID'])->isBot()
698 )
699 {
700 $botJoinFields['BOT_ID'] = $params['FROM_USER_ID'];
701 $botJoinFields['USER_ID'] = $params['TO_USER_ID'];
702 $botJoinFields['TO_USER_ID'] = $params['TO_USER_ID'];
703 $botJoinFields['FROM_USER_ID'] = $params['FROM_USER_ID'];
704 \Bitrix\Im\Bot::onJoinChat($params['TO_USER_ID'], $botJoinFields);
705 }
706
707 return $result->setResult([
708 'CHAT_ID' => $chat->getChatId(),
709 'CHAT' => $chat,
710 ]);
711 }
712
713 protected function prepareParams(array $params = []): Result
714 {
715 $result = new Result();
716
717 if (isset($params['FROM_USER_ID']))
718 {
719 $params['AUTHOR_ID'] = $params['FROM_USER_ID'] = (int)$params['FROM_USER_ID'];
720 }
721 if ($params['FROM_USER_ID'] <= 0)
722 {
723 return $result->addError(new ChatError(ChatError::WRONG_SENDER));
724 }
725
726 if (isset($params['TO_USER_ID']))
727 {
728 $params['TO_USER_ID'] = (int)$params['TO_USER_ID'];
729 }
730 else
731 {
732 $params['TO_USER_ID'] = 0;
733 }
734
735 if ($params['TO_USER_ID'] <= 0)
736 {
737 return $result->addError(new ChatError(ChatError::WRONG_RECIPIENT));
738 }
739
740 $result->setResult($params);
741
742 return $result;
743 }
744
745 protected function addIndex(): Chat
746 {
747 return $this;
748 }
749
750 protected function updateIndex(): Chat
751 {
752 return $this;
753 }
754
755 public function getPopupData(array $excludedList = []): PopupData
756 {
757 $userIds = [$this->getContext()->getUserId(), $this->getCompanion()->getId()];
758
759 return new PopupData([new UserPopupItem($userIds)], $excludedList);
760 }
761}
static hasAccess($chatId)
Definition chat.php:445
static getType($chatData)
Definition chat.php:41
static getPullExtra()
Definition common.php:128
static hasAccess($dialogId, $userId=null)
Definition dialog.php:143
const EVENT_PRIVATE_SYSTEM
Definition notify.php:15
const EVENT_PRIVATE
Definition notify.php:14
static isUnread(int $userId, string $itemType, string $dialogId)
Definition recent.php:1425
sendPushUpdateMessage(Message $message)
setManageUsersDelete(string $manageUsersDelete)
sendPushReadSelf(MessageCollection $messages, int $lastId, int $counter)
add(array $params, ?Context $context=null)
getPopupData(array $excludedList=[])
sendMessage($message, $sendingConfig=null)
sendEventRead(int $startId, int $endId, int $counter, bool $byEvent)
addUsers(array $userIds, array $managerIds=[], ?bool $hideHistory=null, bool $withMessage=true, bool $skipRecent=false)
sendPushReadOpponent(MessageCollection $messages, int $lastId)
setManageUI(string $manageUI)
setManageSettings(string $manageSettings)
getStartId(?int $userId=null)
prepareParams(array $params=[])
setManageUsersAdd(string $manageUsersAdd)
sendPushUnreadSelf(int $unreadToId, int $lastId, int $counter, ?array $lastMessageStatuses=null)
static find(array $params, ?Context $context=null)
checkAccessWithoutCaching(int $userId)
getCompanion(?int $userId=null)
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29
addError(Error $error)
Definition result.php:50