403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/im/lib/V2/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/im/lib/V2/Message.php
<?php

namespace Bitrix\Im\V2;

use ArrayAccess;
use Bitrix\Im\V2\Integration\AI\RoleManager;
use Bitrix\Im\V2\Message\Delete\DeletionMode;
use Bitrix\Im\V2\Message\MessageError;
use Bitrix\Im\V2\Message\Reaction\ReactionMessage;
use Bitrix\Im\V2\TariffLimit\DateFilterable;
use Bitrix\Im\V2\TariffLimit\FilterResult;
use Bitrix\Im\V2\TariffLimit\Limit;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\ORM\Data\DataManager;
use Bitrix\Main\Type\DateTime;
use Bitrix\Main\ObjectException;
use Bitrix\Main\UrlPreview\UrlPreview;
use Bitrix\Im;
use Bitrix\Im\Text;
use Bitrix\Im\Notify;
use Bitrix\Im\Recent;
use Bitrix\Im\Model\EO_Message;
use Bitrix\Im\Model\MessageTable;
use Bitrix\Im\V2\Common\ContextCustomer;
use Bitrix\Im\V2\Common\FieldAccessImplementation;
use Bitrix\Im\V2\Common\ActiveRecordImplementation;
use Bitrix\Im\V2\Common\RegistryEntryImplementation;
use Bitrix\Im\V2\Entity\File\FileCollection;
use Bitrix\Im\V2\Entity\Url\UrlItem;
use Bitrix\Im\V2\Link\Pin\PinService;
use Bitrix\Im\V2\Link\Favorite\FavoriteService;
use Bitrix\Im\V2\Message\Param;
use Bitrix\Im\V2\Message\Params;
use Bitrix\Im\V2\Message\Param\Menu;
use Bitrix\Im\V2\Message\Param\Keyboard;
use Bitrix\Im\V2\Message\Param\AttachArray;
use Bitrix\Im\V2\Message\ReadService;
use Bitrix\Im\V2\Message\MessageParameter;
use Bitrix\Im\V2\Rest\PopupData;
use Bitrix\Im\V2\Rest\RestEntity;
use Bitrix\Im\V2\Rest\PopupDataAggregatable;

/**
 * Chat version #2
 */
class Message implements ArrayAccess, RegistryEntry, ActiveRecord, RestEntity, PopupDataAggregatable, DateFilterable
{
	use FieldAccessImplementation;
	use ActiveRecordImplementation
	{
		save as defaultSave;
	}
	use RegistryEntryImplementation;
	use ContextCustomer;

	public const MESSAGE_MAX_LENGTH = 20000;
	public const REST_FIELDS = ['ID', 'CHAT_ID', 'AUTHOR_ID', 'DATE_CREATE', 'MESSAGE', 'NOTIFY_EVENT', 'NOTIFY_READ'];

	protected ?int $messageId = null;

	protected ?int $chatId = null;

	protected ?Chat $chat = null;

	/** Created by Id */
	protected int $authorId = 0;
	protected array $userIdsFromMention;

	/** Message to send */
	protected ?string $message = null;

	protected ?string $parsedMessage = null;

	protected ?string $formattedMessage = null;

	/** Formatted rich message */
	protected ?string $messageOut = null;

	/** message creation date. */
	protected ?DateTime $dateCreate = null;

	/** E-mail template code. */
	protected ?string $emailTemplate = null;

	/**
	 *	Notification type:
	 * 	@see \IM_NOTIFY_MESSAGE = 0 - message,
	 * 	@see \IM_NOTIFY_CONFIRM = 1 - confirm,
	 * 	@see \IM_NOTIFY_FROM = 2 - notify single from,
	 * 	@see \IM_NOTIFY_SYSTEM = 4 - notify single.
	 */
	protected int $notifyType = \IM_NOTIFY_MESSAGE;

	/** Source module id (ex: xmpp, main, etc). */
	protected ?string $notifyModule = null;

	/** Source module event id for search (ex: IM_GROUP_INVITE). */
	protected ?string $notifyEvent = null;

	/** Field for group in JS notification and search in table. */
	protected ?string $notifyTag = null;

	/** Second TAG for search in table. */
	protected ?string $notifySubTag = null;

	/** Notify title for sending email. */
	protected ?string $notifyTitle = null;

	/** Url to dislplay in notification balloon. */
	protected ?string $notifyLink = null;

	/** Serialized button's data available with NOTIFY_TYPE = 1
	 * 	Array(
	 * 		Array('TITLE' => 'OK', 'VALUE' => 'Y', 'TYPE' => 'accept', 'URL' => '/test.php?CONFIRM=Y'),
	 * 		Array('TITLE' => 'Cancel', 'VALUE' => 'N', 'TYPE' => 'cancel', 'URL' => '/test.php?CONFIRM=N'),
	 * 	)
	 */
	protected ?array $notifyButtons = null;

	/** Message seen flag */
	protected ?bool $notifyRead = null;

	/** Allow answering right in notification balloon. */
	protected ?bool $notifyAnswer = null;

	/** Display only balloon without adding message into notification list. */
	protected ?bool $notifyFlash = null;

	/** The ID of the message to be imported. */
	protected ?int $importId = null;

	protected ?bool $isUnread = null;

	protected ?bool $isViewed = null;

	/** Message additional parameters. */
	protected Params $params;

	/**
	 * Message file attachments
	 * @var FileCollection|null
	 */
	protected ?FileCollection $files = null;

	protected ?Im\V2\Message\Reaction\ReactionMessage $reactions;

	/** Display message as a system notification. */
	protected bool $isSystem = false;

	protected ?UrlItem $url;

	protected int $botId = 0;

	/** Message UUID.*/
	protected ?string $uuid = null;

	protected ?string $forwardUuid = null;

	/** File UUID.*/
	protected ?string $fileUuid = null;

	protected bool $isUuidFilled = false;
	protected bool $isUrlFilled = false;
	protected bool $isMessageOutFilled = false;

	protected ?string $pushMessage = null;
	protected ?array $pushParams = null;
	protected ?string $pushAppId = null;

	protected ?bool $isImportant = false;

	protected ?array $importantFor = null;
	protected ?string $dialogId = null;
	protected ?int $prevId = null;

	/**
	 * @param int|array|EO_Message|null $source
	 */
	public function __construct($source = null)
	{
		$this->params = new Params;

		$this->initByDefault();

		if (!empty($source))
		{
			$this->load($source);
		}
	}

	public function save(): Result
	{
		$checkParamsIsValid = $this->getParams()->isValid();

		if (!$checkParamsIsValid->isSuccess())
		{
			return $checkParamsIsValid;
		}

		$result = $this->defaultSave();

		if ($result->isSuccess())
		{
			$this->params->setMessageId($this->getMessageId());

			$paramsSaveResult = $this->params->save();
			if (!$paramsSaveResult->isSuccess())
			{
				$result->addErrors($paramsSaveResult->getErrors());
			}

			$this->params = new Params();
		}

		return $result;
	}

	//region Setters & Getters

	public function getId(): ?int
	{
		return $this->getMessageId();
	}

	public function markAsSystem(bool $flag): self
	{
		$this->isSystem = $flag;

		return $this;
	}

	public function isSystem(): bool
	{
		return $this->isSystem;
	}

	public function isDisappearing(): bool
	{
		return (bool)$this->getDisappearingTime();
	}

	public function getDisappearingTime(): ?DateTime
	{
		if ($this->getMessageId())
		{
			$row = Im\Model\MessageDisappearingTable::getRowById($this->getMessageId());

			return $row['DATE_REMOVE'];
		}

		return null;
	}

	public function isImportant(): ?bool
	{
		return $this->isImportant;
	}

	public function markAsImportant(?bool $isImportant = true): self
	{
		$this->isImportant = $isImportant;

		return $this;
	}

	public function getImportantFor(): array
	{
		return $this->importantFor ?? array_values($this->getUserIdsFromMention());
	}

	public function setImportantFor(array $importantFor): self
	{
		$this->importantFor = $importantFor;

		return $this;
	}

	public function getForwardUuid(): ?string
	{
		return $this->forwardUuid;
	}

	public function setForwardUuid(?string $forwardUuid): self
	{
		if ($forwardUuid && Im\Message\Uuid::validate($forwardUuid))
		{
			$this->forwardUuid = $forwardUuid;
		}

		return $this;
	}

	/**
	 * @param array $params
	 * @return $this
	 */
	public function setParams($params): self
	{
		$this->getParams()->load($params);

		return $this;
	}

	/**
	 * @param array $params
	 * @return $this
	 */
	public function resetParams($params): self
	{
		$this->getParams()->delete();

		return $this->setParams($params);
	}

	/**
	 * @param bool $disallowLazyLoad
	 * @return Params
	 */
	public function getParams(bool $disallowLazyLoad = false): Params
	{
		if (
			$disallowLazyLoad != true
			&& !$this->params->isLoaded()
			&& $this->getMessageId()
		)
		{
			// lazyload
			$this->params->loadByMessageId($this->getMessageId());
		}

		return $this->params;
	}

	/**
	 * @param array|Param $attach
	 * @return $this
	 */
	public function setAttach($attach): self
	{
		$this->getParams()->get(Params::ATTACH)->setValue($attach);
		return $this;
	}

	/**
	 * @return AttachArray|MessageParameter
	 */
	public function getAttach(): AttachArray
	{
		return $this->getParams()->get(Params::ATTACH);
	}

	public function setUrl(?UrlItem $url): self
	{
		$this->url = $url;
		$this->isUrlFilled = true;

		return $this;
	}

	public function getUrl(): ?UrlItem
	{
		if (isset($this->url))
		{
			return $this->url;
		}

		$urlId = $this->getParams()->get(Params::URL_ID)->getValue()[0] ?? null;
		if (isset($urlId) && !$this->isUrlFilled)
		{
			return UrlItem::initByPreviewUrlId($urlId, false);
		}

		return null;
	}

	public function setUnread(bool $isUnread): self
	{
		$this->isUnread = $isUnread;

		return $this;
	}

	public function isUnread(): bool
	{
		if (isset($this->isUnread))
		{
			return $this->isUnread;
		}

		$messageIds = [$this->getMessageId()];
		$this->isUnread = !(new ReadService())->getReadStatusesByMessageIds($messageIds)[$this->getMessageId()];

		return $this->isUnread;
	}

	public function setViewed(bool $isViewed): self
	{
		$this->isViewed = $isViewed;

		return $this;
	}

	public function isViewed(): bool
	{
		if (isset($this->isViewed))
		{
			return $this->isViewed;
		}

		if ($this->authorId === $this->getContext()->getUserId())
		{
			$this->isViewed = true;

			return $this->isViewed;
		}

		$messageIds = [$this->getMessageId()];
		$this->isViewed = (new ReadService())->getViewStatusesByMessageIds($messageIds)[$this->getMessageId()];

		return $this->isViewed;
	}

	public function isViewedByOthers(): bool
	{
		return $this->isNotifyRead() ?? false;
	}

	public function setBotId(int $botId): self
	{
		$this->botId = $botId;

		return $this;
	}

	/**
	 * @param array|Param|Keyboard $keyboard
	 * @return $this
	 */
	public function setKeyboard($keyboard): self
	{
		if (is_array($keyboard))
		{
			$value = [];
			if (!isset($keyboard['BUTTONS']))
			{
				$value['BUTTONS'] = $keyboard;
			}
			else
			{
				$value = $keyboard;
			}
			if (!isset($value['BOT_ID']))
			{
				$value['BOT_ID'] = $this->botId;
			}
			$keyboard = $value;
		}

		$this->getParams()->get(Params::KEYBOARD)->setValue($keyboard);
		return $this;
	}

	/**
	 * @return Keyboard|MessageParameter
	 */
	public function getKeyboard(): Keyboard
	{
		return $this->getParams()->get(Params::KEYBOARD);
	}

	/*
	 * @param array|Parameter|Menu $menu
	 */
	public function setMenu($menu): self
	{
		if (is_array($menu))
		{
			$value = [];
			if (!isset($menu['ITEMS']))
			{
				$value['ITEMS'] = $menu;
			}
			else
			{
				$value = $menu;
			}
			if (!isset($value['BOT_ID']))
			{
				$value['BOT_ID'] = $this->botId;
			}
			$menu = $value;
		}

		$this->getParams()->get(Params::MENU)->setValue($menu);
		return $this;
	}

	/**
	 * @return Menu|MessageParameter
	 */
	public function getMenu(): Menu
	{
		return $this->getParams()->get(Params::MENU);
	}

	//region UUID

	/**
	 * @param string|null $uuid
	 * @return self
	 */
	public function setUuid(?string $uuid): self
	{
		$this->isUuidFilled = true;
		$this->uuid = $uuid;

		return $this;
	}

	public function getUuid(): ?string
	{
		if ($this->isUuidFilled)
		{
			return $this->uuid;
		}

		$this->isUuidFilled = true;
		$this->uuid = null;

		if ($this->getMessageId())
		{
			$row = Im\Model\MessageUuidTable::query()
				->setSelect(['UUID'])
				->where('MESSAGE_ID', $this->getMessageId())
				->fetch() ?: [];

			$this->uuid = $row['UUID'] ?? null;
		}

		return $this->uuid;
	}

	public function setFileUuid(?string $uuid): self
	{
		$this->fileUuid = $uuid;
		return $this;
	}

	public function getFileUuid(): ?string
	{
		return $this->fileUuid;
	}

	//endregion

	//region Files

	/**
	 * @return int[]
	 */
	public function getFileIds(): array
	{
		if ($this->getParams()->isSet(Params::FILE_ID))
		{
			return $this->getParams()->get(Params::FILE_ID)->getValue();
		}

		return [];
	}

	/**
	 * @return bool
	 */
	public function hasFiles(): bool
	{
		return
			$this->getParams()->isSet(Params::FILE_ID)
			&& ($this->getParams()->get(Params::FILE_ID)->count() > 0);
	}

	/**
	 * @param int[]|FileCollection $files
	 * @return static
	 */
	public function setFiles($files): self
	{
		$fileIds = [];
		if ($files instanceof FileCollection)
		{
			$this->files = $files;
			foreach ($this->files as $fileItem)
			{
				$fileIds[] = $fileItem->getDiskFileId();
			}
		}
		elseif (is_array($files))
		{
			$fileIds = array_filter(array_map('intval', array_values($files)));
		}

		$this->getParams()->get(Params::FILE_ID)->setValue($fileIds);

		return $this;
	}

	public function fillFiles(FileCollection $files): self
	{
		$this->files = $files;

		return $this;
	}

	public function addFile(Im\V2\Entity\File\FileItem $file): self
	{
		$this->getFiles()[] = $file;
		$this->getParams()->get(Params::FILE_ID)->addValue($file->getId());

		return $this;
	}

	/**
	 * @return FileCollection
	 */
	public function getFiles(): FileCollection
	{
		if (!$this->files instanceof FileCollection)
		{
			$fileIds = $this->getFileIds();
			if (!empty($fileIds))
			{
				$this->files = FileCollection::initByDiskFilesIds($fileIds, $this->getChatId());
			}
			else
			{
				$this->files = new FileCollection;
			}
		}

		return $this->files;
	}

	public function getPrevId(): int
	{
		if ($this->prevId !== null)
		{
			return $this->prevId;
		}

		$result = \Bitrix\Im\Model\MessageTable::query()
			->setSelect(['ID'])
			->where('CHAT_ID', $this->getChatId() ?? 0)
			->where('ID', '<', $this->getId() ?? 0)
			->setOrder(['DATE_CREATE' => 'DESC', 'ID' => 'DESC'])
			->setLimit(1)
			->fetch() ?: []
		;
		$this->prevId = (int)($result['ID'] ?? 0);

		return $this->prevId;
	}

	/**
	 * @param ReactionMessage $reactions
	 * @return $this
	 */
	public function setReactions(Im\V2\Message\Reaction\ReactionMessage $reactions): self
	{
		$this->reactions = $reactions;

		return $this;
	}

	/**
	 * @return ReactionMessage
	 */
	public function getReactions(): Im\V2\Message\Reaction\ReactionMessage
	{
		$this->reactions ??= Im\V2\Message\Reaction\ReactionMessage::getByMessageId($this->getMessageId());

		return $this->reactions;
	}

	/**
	 * Extracts and saves files from message text.
	 *
	 * @return array
	 */
	public function uploadFileFromText(): array
	{
		$files = [];
		$message = $this->getMessage();
		$chatId = $this->getChatId();

		if (!$message || !$chatId)
		{
			return $files;
		}

		$diskFileIds = Im\V2\Entity\File\FileItem::getDiskFileIdsFromBbCodesInText($message);

		foreach ($diskFileIds as $fileId)
		{
			$newFile = \CIMDisk::SaveFromLocalDisk($this->getChatId(), $fileId, false, $this->getContext()->getUserId());
			if (!$newFile)
			{
				continue;
			}
			$files[] = $newFile;
			$file = new Im\V2\Entity\File\FileItem($newFile, $this->getChatId());
			$this->addFile($file);
		}

		if (!empty($diskFileIds))
		{
			$this->setMessage(Im\V2\Entity\File\FileItem::removeDiskBbCodesFromText($message));
		}

		return $files;
	}

	/**
	 * @return array
	 */
	public function getFilesDiskData(): array
	{
		if ($this->hasFiles())
		{
			return $this->getFiles()->getFileDiskAttributes($this->getChatId());
		}

		return  [];
	}

	//endregion

	public function getReminder(): ?Link\Reminder\ReminderItem
	{
		return Link\Reminder\ReminderItem::getByMessageAndUserId($this, $this->getContext()->getUserId());
	}

	public function getAdditionalMessageIds(): array
	{
		$ids = [];

		if ($this->getParams()->isSet(Params::REPLY_ID))
		{
			$ids[] = $this->getParams()->get(Params::REPLY_ID)->getValue();
		}

		return $ids;
	}

	public function getPopupData(array $excludedList = []): PopupData
	{
		$data = new PopupData([
			new Im\V2\Entity\User\UserPopupItem($this->getUserIds()),
			new Im\V2\Entity\File\FilePopupItem(),
			new Im\V2\Link\Reminder\ReminderPopupItem(),
			new Im\V2\Message\Reaction\ReactionPopupItem($this->getReactions()),
		], $excludedList);

		if (!in_array(Im\V2\Entity\File\FilePopupItem::class, $excludedList, true))
		{
			$data->add(new Im\V2\Entity\File\FilePopupItem($this->getFiles()));
		}

		/*if (!in_array(Im\V2\Link\Reminder\ReminderPopupItem::class, $excludedList, true))
		{
			$data->add(new Im\V2\Link\Reminder\ReminderPopupItem($this->getReminder()));
		}*/

		return $data->mergeFromEntity($this->getReactions());
	}

	public function setMessageId(int $messageId): self
	{
		if (!$this->messageId)
		{
			$this->messageId = $messageId;
			$this->params->setMessageId($messageId);
		}
		return $this;
	}

	public function getMessageId(): ?int
	{
		return $this->messageId;
	}

	public function setAuthorId(int $authorId): self
	{
		$this->authorId = $authorId;

		$this->processChangeAuthorId($authorId);

		return $this;
	}

	public function processChangeAuthorId(int $authorId): int
	{
		if ($authorId === 0)
		{
			$this->markAsSystem(true);
		}

		if ($this->context && $authorId)
		{
			$this->context->setUserId($authorId);
		}

		return $authorId;
	}

	public function getAuthorId(): int
	{
		return $this->authorId;
	}

	public function getAuthor(): ?Entity\User\User
	{
		if ($this->getAuthorId())
		{
			return Im\V2\Entity\User\User::getInstance($this->getAuthorId());
		}

		return null;
	}

	public function setChatId(int $value): self
	{
		$this->chatId = $value;
		return $this;
	}

	public function setChat(Chat $chat): self
	{
		$this->chat = $chat;
		return $this;
	}

	public function getChatId(): ?int
	{
		return $this->chatId;
	}

	public function getChat(): Chat
	{
		if (!$this->chat)
		{
			if ($this->getChatId())
			{
				$this->chat = Chat::getInstance($this->getChatId());
			}
			if ($this->chat)
			{
				$this->setRegistry($this->chat->getMessageRegistry());
			}
			else
			{
				return new Im\V2\Chat\NullChat();
			}
		}

		return $this->chat;
	}

	// message
	public function setMessage(?string $value): self
	{
		if ($value)
		{
			$value = \trim(\str_replace(['[BR]', '[br]', '#BR#'], "\n", $value));

			if (\mb_strlen($value) > self::MESSAGE_MAX_LENGTH + 6)
			{
				$value = \mb_substr($value, 0, self::MESSAGE_MAX_LENGTH). ' (...)';
			}
		}

		$this->message = $value ?? '';
		unset($this->parsedMessage, $this->formattedMessage, $this->url);
		return $this;
	}

	public function getMessage(): ?string
	{
		return $this->message;
	}

	public function getParsedMessage(): string
	{
		$this->parsedMessage ??= Im\Text::parse($this->getMessage() ?? '');

		return $this->parsedMessage;
	}

	public function getFormattedMessage(): string
	{
		if (isset($this->formattedMessage))
		{
			return $this->formattedMessage;
		}

		$this->formattedMessage =
			$this->isCompletelyEmpty()
				? Loc::getMessage('IM_MESSAGE_DELETED')
				: $this->getParsedMessage()
		;

		return $this->formattedMessage;
	}

	public function getQuotedMessage(?int $messageSize = null): string
	{
		$user = $this->getAuthor();
		$userName = $user?->getName() ?? '';
		$date = FormatDate('X', $this->getDateCreate(), time() + \CTimeZone::GetOffset());
		$contextTag = $this->getContextTag();
		$quoteDelimiter = '------------------------------------------------------';
		$messageContent = $this->getPreviewMessage($messageSize);

		$quotedMessage =
			$quoteDelimiter
			. "\n"
			. "{$userName} [{$date}] $contextTag\n"
			. $messageContent
			. "\n"
			. $quoteDelimiter
		;

		return $quotedMessage;
	}

	public function getReplaceMap(): array
	{
		return Im\Text::getReplaceMap($this->getFormattedMessage());
	}

	// formatted rich message to output
	public function setMessageOut(?string $value): self
	{
		$this->messageOut = $value ? trim($value) : '';
		return $this;
	}

	public function getMessageOut(): ?string
	{
		if ($this->isMessageOutFilled)
		{
			return $this->messageOut;
		}

		$this->fillMessageOut();

		return $this->messageOut;
	}

	public function fillMessageOut(): ?string
	{
		if ($this->isMessageOutFilled)
		{
			return $this->messageOut;
		}

		if ($this->getChatId() && $this->hasFiles())
		{
			$messageFiles = $this->getFiles()->getMessageOut();
			if (!empty($messageFiles))
			{
				$messageOut = $this->messageOut ?: $this->message;
				$messageOut .= "\n";
				$messageOut .= implode("\n", $messageFiles);
				$this->setMessageOut($messageOut);
			}
		}

		$this->isMessageOutFilled = true;

		return $this->messageOut;
	}

	// date create

	/**
	 * @param DateTime|string|null $value
	 * @return static
	 */
	public function setDateCreate($value): self
	{
		if (!empty($value) && !($value instanceof DateTime))
		{
			try
			{
				$value = new DateTime($value);
			}
			catch (ObjectException $exception)
			{}
		}
		$this->dateCreate = $value ?: null;
		return $this;
	}

	public function getDateCreate(): ?DateTime
	{
		return $this->dateCreate;
	}

	public function getDefaultDateCreate(): DateTime
	{
		return new DateTime;
	}

	public function setEmailTemplate(?string $value): self
	{
		$this->emailTemplate = $value ?: '';
		return $this;
	}

	public function getEmailTemplate(): ?string
	{
		return $this->emailTemplate;
	}

	public function setNotifyType(?int $value): self
	{
		if (in_array($value, [\IM_NOTIFY_MESSAGE, \IM_NOTIFY_CONFIRM, \IM_NOTIFY_SYSTEM, \IM_NOTIFY_FROM], true))
		{
			$this->notifyType = $value;
		}
		return $this;
	}

	public function getNotifyType(): int
	{
		return $this->notifyType;
	}

	public function getDefaultNotifyType(): int
	{
		return \IM_NOTIFY_MESSAGE;
	}

	public function setNotifyModule(?string $value): self
	{
		$this->notifyModule = $value;
		return $this;
	}

	public function getNotifyModule(): ?string
	{
		return $this->notifyModule;
	}

	public function getDefaultNotifyModule(): ?string
	{
		return 'im';
	}

	/**
	 * Sets source module event id.
	 * @see \Bitrix\Im\Notify
	 * @return string|null
	 */
	public function setNotifyEvent(?string $notifyEvent): self
	{
		$this->notifyEvent = $notifyEvent;

		$this->processChangeNotifyEvent($notifyEvent);

		return $this;
	}

	public function processChangeNotifyEvent(?string $notifyEvent): ?string
	{
		if ($notifyEvent === Notify::EVENT_PRIVATE_SYSTEM)
		{
			$this->markAsSystem(true);
		}

		return $notifyEvent;
	}

	/**
	 * Returns source module event id.
	 * @see \Bitrix\Im\Notify
	 * @return string|null
	 */
	public function getNotifyEvent(): ?string
	{
		return $this->notifyEvent;
	}

	public function getDefaultNotifyEvent(): ?string
	{
		return Notify::EVENT_DEFAULT;
	}

	public function setNotifyTag(?string $value): self
	{
		$this->notifyTag = $value;
		return $this;
	}

	public function getNotifyTag(): ?string
	{
		return $this->notifyTag;
	}

	public function setNotifySubTag(?string $value): self
	{
		$this->notifySubTag = $value;
		return $this;
	}

	public function getNotifySubTag(): ?string
	{
		return $this->notifySubTag;
	}

	public function setNotifyTitle(?string $value): self
	{
		$this->notifyTitle = $value ? mb_substr(trim($value), 0, 255) : null;
		return $this;
	}

	public function getNotifyTitle(): ?string
	{
		return $this->notifyTitle;
	}

	public function setNotifyLink(?string $value): self
	{
		$this->notifyLink = $value;
		return $this;
	}

	public function getNotifyLink(): ?string
	{
		return $this->notifyLink;
	}

	public function setNotifyButtons($value): self
	{
		if (is_string($value))
		{
			$value = $this->unserializeNotifyButtons($value);
		}
		$this->notifyButtons = $value;
		return $this;
	}

	public function getNotifyButtons(): ?array
	{
		return $this->notifyButtons;
	}

	protected function serializeNotifyButtons($value)
	{
		return $value ? serialize($value) : null;
	}

	protected function unserializeNotifyButtons($value)
	{
		return $value ? unserialize($value, ['allowed_classes' => false]) : null;
	}

	public function markNotifyRead(?bool $value): self
	{
		$this->notifyRead = $value ?: false;
		return $this;
	}

	public function isNotifyRead(): ?bool
	{
		return $this->notifyRead;
	}

	public function getDefaultNotifyRead(): bool
	{
		return false;
	}

	public function markNotifyAnswer(?bool $value): self
	{
		$this->notifyAnswer = $value ?: false;
		return $this;
	}

	public function allowNotifyAnswer(): ?bool
	{
		return $this->notifyAnswer;
	}

	public function markNotifyFlash(?bool $value): self
	{
		$this->notifyFlash = $value;
		return $this;
	}

	public function isNotifyFlash(): ?bool
	{
		return $this->notifyFlash;
	}

	public function setImportId(?int $value): self
	{
		$this->importId = $value;
		return $this;
	}

	public function getImportId(): ?int
	{
		return $this->importId;
	}

	//endregion

	//region Push

	/**
	 * @todo Move it into special push message class.
	 * @param string|null $message
	 * @return self
	 */
	public function setPushMessage(?string $message): self
	{
		$this->pushMessage = $message;
		return $this;
	}

	public function getPushMessage(): ?string
	{
		return $this->pushMessage;
	}

	/**
	 * @todo Move it into special push message class.
	 * @param array|null $params
	 * @return self
	 */
	public function setPushParams(?array $params): self
	{
		$this->pushParams = $params;
		return $this;
	}

	public function getPushParams(): ?array
	{
		return $this->pushParams;
	}

	/**
	 * @todo Move it into special push message class.
	 * @param string|null $message
	 * @return self
	 */
	public function setPushAppId(?string $message): self
	{
		$this->pushAppId = $message;
		return $this;
	}

	public function getPushAppId(): ?string
	{
		return $this->pushAppId;
	}


	//endregion

	//region Data storage

	/**
	 * @return array
	 */
	protected static function mirrorDataEntityFields(): array
	{
		return [
			'ID' => [
				'primary' => true,
				'field' => 'messageId', /** @see Message::$messageId */
				'set' => 'setMessageId', /** @see Message::setMessageId */
				'get' => 'getMessageId', /** @see Message::getMessageId */
			],
			'CHAT_ID' => [
				'field' => 'chatId', /** @see Message::$chatId */
				'set' => 'setChatId', /** @see Message::setChatId */
				'get' => 'getChatId', /** @see Message::getChatId */
			],
			'AUTHOR_ID' => [
				'field' => 'authorId', /** @see Message::$authorId */
				'set' => 'setAuthorId', /** @see Message::setAuthorId */
				'get' => 'getAuthorId', /** @see Message::getAuthorId */
				'loadFilter' => 'processChangeAuthorId', /** @see Message::processChangeAuthorId */
			],
			'MESSAGE' => [
				'field' => 'message', /** @see Message::$message */
				'set' => 'setMessage', /** @see Message::setMessage */
				'get' => 'getMessage', /** @see Message::getMessage */
			],
			'MESSAGE_OUT' => [
				'field' => 'messageOut', /** @see Message::$messageOut */
				'set' => 'setMessageOut', /** @see Message::setMessageOut */
				'get' => 'getMessageOut', /** @see Message::getMessageOut */
				'saveFilter' => 'fillMessageOut', /** @see Message::fillMessageOut */
			],
			'DATE_CREATE' => [
				'field' => 'dateCreate', /** @see Message::$dateCreate */
				'set' => 'setDateCreate', /** @see Message::setDateCreate */
				'get' => 'getDateCreate', /** @see Message::getDateCreate */
				'default' => 'getDefaultDateCreate', /** @see Message::getDefaultDateCreate */
			],
			'MESSAGE_DATE' =>
				[
					'alias' => 'DATE_CREATE',
				],
			'EMAIL_TEMPLATE' => [
				'field' => 'emailTemplate', /** @see Message::$emailTemplate */
				'set' => 'setEmailTemplate', /** @see Message::setEmailTemplate */
				'get' => 'getEmailTemplate', /** @see Message::getEmailTemplate */
			],
			'NOTIFY_TYPE' => [
				'field' => 'notifyType', /** @see Message::$notifyType */
				'set' => 'setNotifyType', /** @see Message::setNotifyType */
				'get' => 'getNotifyType', /** @see Message::getNotifyType */
				'default' => 'getDefaultNotifyType',/** @see Message::getDefaultNotifyType */
			],
			'NOTIFY_MODULE' => [
				'field' => 'notifyModule', /** @see Message::$notifyModule */
				'set' => 'setNotifyModule', /** @see Message::setNotifyModule */
				'get' => 'getNotifyModule', /** @see Message::getNotifyModule */
				'default' => 'getDefaultNotifyModule',/** @see Message::getDefaultNotifyModule */
			],
			'NOTIFY_EVENT' => [
				'field' => 'notifyEvent', /** @see Message::$notifyEvent */
				'set' => 'setNotifyEvent', /** @see Message::setNotifyEvent */
				'get' => 'getNotifyEvent', /** @see Message::getNotifyEvent */
				'default' => 'getDefaultNotifyEvent', /** @see Message::getDefaultNotifyEvent */
				'loadFilter' => 'processChangeNotifyEvent', /** @see Message::processChangeNotifyEvent */
			],
			'NOTIFY_TAG' => [
				'field' => 'notifyTag', /** @see Message::$notifyTag */
				'set' => 'setNotifyTag', /** @see Message::setNotifyTag */
				'get' => 'getNotifyTag', /** @see Message::getNotifyTag */
			],
			'NOTIFY_SUB_TAG' => [
				'field' => 'notifySubTag', /** @see Message::$notifySubTag */
				'set' => 'setNotifySubTag', /** @see Message::setNotifySubTag */
				'get' => 'getNotifySubTag', /** @see Message::getNotifySubTag */
			],
			'NOTIFY_TITLE' => [
				'field' => 'notifyTitle', /** @see Message::$notifyTitle */
				'set' => 'setNotifyTitle', /** @see Message::setNotifyTitle */
				'get' => 'getNotifyTitle', /** @see Message::getNotifyTitle */
			],
			'NOTIFY_LINK' => [
				'set' => 'setNotifyLink', /** @see Message::setNotifyLink */
				'get' => 'getNotifyLink', /** @see Message::getNotifyLink */
			],
			'TITLE' => [
				'alias' => 'NOTIFY_TITLE',
			],
			'NOTIFY_MESSAGE' => [
				'alias' => 'MESSAGE',
			],
			'NOTIFY_MESSAGE_OUT' => [
				'alias' => 'MESSAGE_OUT',
			],
			'NOTIFY_BUTTONS' => [
				'field' => 'notifyButtons', /** @see Message::$notifyButtons */
				'set' => 'setNotifyButtons', /** @see Message::setNotifyButtons */
				'get' => 'getNotifyButtons', /** @see Message::getNotifyButtons */
				'saveFilter' => 'serializeNotifyButtons', /** @see Message::serializeNotifyButtons */
				'loadFilter' => 'unserializeNotifyButtons', /** @see Message::unserializeNotifyButtons */
			],
			'NOTIFY_READ' => [
				'field' => 'notifyRead', /** @see Message::$notifyRead */
				'set' => 'markNotifyRead', /** @see Message::markNotifyRead */
				'get' => 'isNotifyRead', /** @see Message::isNotifyRead */
				'default' => 'getDefaultNotifyRead',/** @see Message::getDefaultNotifyRead */
			],
			'NOTIFY_ANSWER' => [
				'set' => 'markNotifyAnswer', /** @see Message::markNotifyAnswer */
				'get' => 'allowNotifyAnswer', /** @see Message::allowNotifyAnswer */
			],
			'NOTIFY_FLASH' => [
				'set' => 'markNotifyFlash', /** @see Message::markNotifyFlash */
				'get' => 'isNotifyFlash', /** @see Message::isNotifyFlash */
			],
			'NOTIFY_ONLY_FLASH' => [
				'alias' => 'NOTIFY_FLASH',
			],
			'IMPORT_ID' => [
				'field' => 'importId', /** @see Message::$importId */
				'set' => 'setImportId', /** @see Message::setImportId */
				'get' => 'getImportId', /** @see Message::getImportId */
			],
			'SYSTEM' => [
				'set' => 'markAsSystem', /** @see Message::markAsSystem */
				'get' => 'isSystem', /** @see Message::isSystem */
			],
			'PARAMS' => [
				'set' => 'setParams', /** @see Message::setParams */
				'get' => 'getParams', /** @see Message::getParams */
			],
			'ATTACH' => [
				'set' => 'setAttach', /** @see Message::setAttach */
				'get' => 'getAttach', /** @see Message::getAttach */
			],
			'FILES' => [
				'set' => 'setFiles', /** @see Message::setFiles */
				'get' => 'getFiles', /** @see Message::getFiles */
			],
			'KEYBOARD' => [
				'set' => 'setKeyboard', /** @see Message::setKeyboard */
				'get' => 'getKeyboard', /** @see Message::getKeyboard */
			],
			'MENU' => [
				'set' => 'setMenu', /** @see Message::setMenu */
				'get' => 'getMenu', /** @see Message::getMenu */
			],
			'UUID' => [
				'set' => 'setUuid', /** @see Message::setUuid */
				'get' => 'getUuid', /** @see Message::getUuid */
			],
			'MESSAGE_UUID' => [
				'alias' => 'UUID',
			],
			'TEMPLATE_ID' => [
				'alias' => 'UUID',
			],
			'FILE_TEMPLATE_ID' => [
				'set' => 'setFileUuid', /** @see Message::setFileUuid */
				'get' => 'getFileUuid', /** @see Message::getFileUuid */
			],
			'PUSH_MESSAGE' => [
				'set' => 'setPushMessage', /** @see Message::setPushMessage */
				'get' => 'getPushMessage', /** @see Message::getPushMessage */
			],
			'MESSAGE_PUSH' => [
				'alias' => 'PUSH_MESSAGE'
			],
			'PUSH_PARAMS' => [
				'set' => 'setPushParams', /** @see Message::setPushParams */
				'get' => 'getPushParams', /** @see Message::getPushParams */
			],
			'EXTRA_PARAMS' => [
				'alias' => 'PUSH_PARAMS'
			],
			'PUSH_APP_ID' => [
				'set' => 'setPushAppId', /** @see Message::setPushAppId */
				'get' => 'getPushAppId', /** @see Message::getPushAppId */
			],
			'TO_CHAT_ID' => [
				'alias' => 'CHAT_ID',
			],
		];
	}

	/**
	 * @return string|DataManager;
	 */
	public static function getDataClass(): string
	{
		return MessageTable::class;
	}

	/**
	 * @return int|null
	 */
	public function getPrimaryId(): ?int
	{
		return $this->getMessageId();
	}

	/**
	 * @param int $primaryId
	 * @return self
	 */
	public function setPrimaryId(int $primaryId): self
	{
		return $this->setMessageId($primaryId);
	}

	//endregion

	public function markAsFavorite(): Result
	{
		$favoriteMessageService = new FavoriteService();
		$favoriteMessageService->setContext($this->context);

		return $favoriteMessageService->markMessageAsFavorite($this);
	}

	public function unmarkAsFavorite(): Result
	{
		$favoriteMessageService = new FavoriteService();
		$favoriteMessageService->setContext($this->context);

		return $favoriteMessageService->unmarkMessageAsFavorite($this);
	}

	public function pin(): Result
	{
		$pinService = new PinService();
		$pinService->setContext($this->context);

		return $pinService->pinMessage($this);
	}

	public function unpin(): Result
	{
		$pinService = new PinService();
		$pinService->setContext($this->context);

		return $pinService->unpinMessage($this);
	}

	public function mark(): Result
	{
		$result = new Result();

		$isSuccessMark = Recent::unread(
			$this->getChat()->getDialogId(),
			true,
			$this->getContext()->getUserId(),
			$this->getId()
		);

		if (!$isSuccessMark)
		{
			$result->addError(new MessageError(MessageError::MARK_FAILED));
		}

		return $result;
	}

	public function addToReminder(DateTime $dateRemind): Result
	{
		$reminderService = new Link\Reminder\ReminderService();
		$reminderService->setContext($this->context);

		return $reminderService->addMessageToReminders($this, $dateRemind);
	}

	public function getPreviewMessage(?int $messageSize = 200): string
	{
		$previewMessage = trim($this->getFormattedMessage());
		$hasFiles = $this->hasFiles();
		$hasAttach = mb_strpos($previewMessage, '[ATTACH=') !== false;

		if ($this->getRegistry() instanceof MessageCollection)
		{
			$this->getRegistry()->fillFiles();
		}

		if ($hasFiles)
		{
			$files = $this->getFiles();
			foreach ($files as $file)
			{
				$hasFiles = true;
				$previewMessage .= " [{$file->getDiskFile()->getName()}]";
			}
		}

		$previewMessage = preg_replace(
			"/\[ATTACH=([0-9]{1,})\]/i",
			" [".Loc::getMessage('IM_MESSAGE_ATTACH')."] ",
			$previewMessage
		);
		$previewMessage = preg_replace(
			'#\-{54}.+?\-{54}#s',
			" [".Loc::getMessage('IM_MESSAGE_QUOTE')."] ",
			str_replace(["#BR#"], [" "], $previewMessage)
		);
		$previewMessage = preg_replace(
			'/^(>>(.*)(\n)?)/mi',
			" [".Loc::getMessage('IM_MESSAGE_QUOTE')."] ",
			str_replace(["#BR#"], [" "], $previewMessage)
		);

		if (!$hasFiles && !$hasAttach)
		{
			if ($this->getParams()->isSet(Params::ATTACH))
			{
				$previewMessage .= " [".Loc::getMessage('IM_MESSAGE_ATTACH')."]";
			}
		}

		if ($messageSize !== null)
		{
			$dots = mb_strlen($previewMessage) >= $messageSize ? '...' : '';
			$previewMessage = mb_substr($previewMessage, 0, $messageSize - 1) . $dots;
		}

		return $previewMessage;
	}

	public function getForPush(?int $messageSize = 200): string
	{
		if ($this->getRegistry() instanceof MessageCollection)
		{
			$this->getRegistry()->fillFiles();
		}

		$files = [];

		foreach ($this->getFiles() as $file)
		{
			$files[] = ['name' => $file->getDiskFile()->getName()];
		}

		$message = ['MESSAGE' => $this->getMessage(), 'FILES' => $files];
		$text = \CIMMessenger::PrepareParamsForPush($message);

		if ($messageSize !== null)
		{
			$dots = mb_strlen($text) >= $messageSize ? '...' : '';
			$text = mb_substr($text, 0, $messageSize - 1) . $dots;
		}

		return $text;
	}

	public function checkAccess(?int $userId = null): Result
	{
		$userId ??= $this->getContext()->getUserId();
		$chat = $this->getChat();
		$result = new Result();

		if (!$this->getId())
		{
			return $result->addError(new MessageError(MessageError::NOT_FOUND));
		}

		$chatAccess = $chat->checkAccess($userId);
		if (!$chatAccess->isSuccess())
		{
			return $chatAccess;
		}

		if ($chat->getStartId($userId) > $this->getId())
		{
			return $result->addError(new MessageError(MessageError::ACCESS_DENIED));
		}

		if (!Limit::getInstance()->hasAccessByDate($this, $this->getDateCreate() ?? new DateTime()))
		{
			return $result->addError(new MessageError(MessageError::MESSAGE_ACCESS_DENIED_BY_TARIFF));
		}

		return $result;
	}

	public static function getRestEntityName(): string
	{
		return 'message';
	}

	public function getUserIds(): array
	{
		$userIds = $this->getUserIdsFromMention();

		if ($this->getAuthorId() !== 0)
		{
			$userIds[$this->getAuthorId()] = $this->getAuthorId();
		}

		if ($this->getParams()->isSet(Params::FORWARD_USER_ID))
		{
			$userId = (int)$this->getParams()->get(Params::FORWARD_USER_ID)->getValue();
			$userIds[$userId] = $userId;
		}

		return $userIds;
	}

	public function getUserIdsFromMention(): array
	{
		if (isset($this->userIdsFromMention))
		{
			return $this->userIdsFromMention;
		}

		$this->userIdsFromMention = [];
		if (preg_match_all("/\[USER=([0-9]+)( REPLACE)?](.*?)\[\/USER]/i", $this->getParsedMessage(), $matches))
		{
			foreach ($matches[1] as $userId)
			{
				$this->userIdsFromMention[(int)$userId] = (int)$userId;
			}
		}

		return $this->userIdsFromMention;
	}

	public function getUserIdsToSendMentions(): array
	{
		$mentionedUsers = $this->getUserIdsFromMention();

		return $this->getChat()->filterUsersToMention($mentionedUsers);
	}

	public function getUserIdsToSendMentionAnchors(): array
	{
		$mentionedUsers = $this->getUserIdsFromMention();

		return $this->getChat()->filterUsersToMentionAnchor($mentionedUsers);
	}

	public function getEnrichedParams(bool $withUrl = true): Params
	{
		$params = clone $this->getParams();

		if ($withUrl)
		{
			$url = $this->getUrl();
			if (isset($url))
			{
				$params->get(Params::ATTACH)->addValue($url->getUrlAttach());
			}
		}

		if ($this->isCompletelyEmpty())
		{
			$params->get(Params::IS_DELETED)->setValue(true);
		}

		return $params;
	}

	public function isCompletelyEmpty(): bool
	{
		return (
			$this->getParsedMessage() === ''
			&& !$this->getParams()->isSet(Params::FILE_ID)
			&& !$this->getParams()->isSet(Params::KEYBOARD)
			&& !$this->getParams()->isSet(Params::ATTACH)
		);
	}

	public function getContextId(): string
	{
		$chat = $this->getChat();

		if ($chat instanceof Im\V2\Chat\PrivateChat)
		{
			$userIds = $chat->getRelations()->getUserIds();
			$implodeUserIds = implode(':', $userIds);

			return "{$implodeUserIds}/{$this->getMessageId()}";
		}

		return "{$chat->getDialogId()}/{$this->getMessageId()}";
	}

	protected function getContextTag(): string
	{
		return "#{$this->getContextId()}";
	}

	public function isForward(): bool
	{
		return $this->getParams()->isSet(Params::FORWARD_ID)
			&& $this->getParams()->isSet(Params::FORWARD_CONTEXT_ID)
		;
	}

	public function getForwardInfo(): ?array
	{
		if (!$this->isForward())
		{
			return null;
		}

		$contextId = $this->getParams()->get(Params::FORWARD_CONTEXT_ID)->getValue();

		return [
			'id' => $contextId,
			'userId' => (int)$this->getParams()->get(Params::FORWARD_USER_ID)->getValue(),
			'chatTitle' => $this->getParams()->get(Params::FORWARD_CHAT_TITLE)->getValue() ?? null,
			'chatType' => Im\V2\Message\Forward\ForwardService::getChatTypeByContextId($contextId),
		];
	}

	/**
	 * @param array $option
	 * @return array
	 */
	public function toRestFormat(array $option = []): array
	{
		$dateCreate = $this->getDateCreate();
		$authorId = $this->getNotifyEvent() === Notify::EVENT_SYSTEM ? 0 : $this->getAuthorId();
		$messageShortInfo = $option['MESSAGE_SHORT_INFO'] ?? false;
		$onlyCommonRest = [
			'id' => $this->getId(),
			'chat_id' => $this->getChatId(),
			'author_id' => $authorId,
			'date' => isset($dateCreate) ? $dateCreate->format('c') : null,
			'text' => $this->getFormattedMessage(),
			'isSystem' => $this->isSystem(),
			'replaces' => $this->getReplaceMap(),
			'uuid' => $this->getUuid(),
			'forward' => $this->getForwardInfo(),
			'params' => $this->getEnrichedParams(!$messageShortInfo)->toRestFormat(),
			'viewedByOthers' => $this->isViewedByOthers(),
		];
		$rest = $onlyCommonRest;

		if (!isset($option['MESSAGE_ONLY_COMMON_FIELDS']) || $option['MESSAGE_ONLY_COMMON_FIELDS'] === false)
		{
			$rest = array_merge($onlyCommonRest, [
				'unread' => $this->isUnread(),
				'viewed' => $this->isViewed(),
			]);
		}

		return $rest;
	}

	/**
	 * Appends message with an url preview attachment.
	 * @return void
	 */
	public function generateUrlPreview(): void
	{
		if ($this->getMessage())
		{
			$urls = UrlItem::getUrlsFromText($this->getMessage());
			foreach ($urls as $url)
			{
				$metadata = UrlPreview::getMetadataByUrl($url, true, false);
				if ($metadata !== false)
				{
					$urlItem = UrlItem::initByMetadata($metadata);
					if ($urlItem->getId())
					{
						$this->getParams()->get(Params::URL_ID)->addValue($urlItem->getId());
						$this->getParams()->get(Params::ATTACH)->addValue($urlItem->getUrlAttach());

						// check if message contains only link
						if ($urlItem->isStaticUrl())
						{
							$staticUrl = [$url];
							if (mb_substr($url, -1) == '/')
							{
								$staticUrl[] = mb_substr($url, 0, -1);
							}
							$checkMessage = trim(str_replace($staticUrl, '', $this->getMessage()));

							if (empty($checkMessage))
							{
								$this->getParams()->get(Params::URL_ONLY)->setValue(true);
							}
						}
					}
				}
			}
		}
	}

	/**
	 * Parse dates from message.
	 * @return self
	 */
	public function parseDates(): self
	{
		if ($this->getMessage())
		{
			$dateConvertResult = Text::getDateConverterParams($this->getMessage());
			foreach ($dateConvertResult as $row)
			{
				$this->getParams()->get(Params::DATE_TEXT)->addValue($row->getText());
				$this->getParams()->get(Params::DATE_TS)->addValue($row->getDate()->getTimestamp());
			}
		}

		return $this;
	}

	/**
	 * Parse dates from message.
	 * @return self
	 */
	public function checkEmoji(): self
	{
		if ($this->getMessage())
		{
			if (Text::isOnlyEmoji($this->getMessage()))
			{
				$this->getParams()->get(Params::LARGE_FONT)->setValue(true);
			}
		}

		return $this;
	}

	public function autocompleteParams(Im\V2\Message\Send\SendingConfig $config): self
	{
		$this->getParams()->get(Params::LARGE_FONT)->setValue(Text::isOnlyEmoji($this->getMessage() ?? ''));
		$dateText = [];
		$dateTs = [];
		$urlIds = [];
		$isUrlOnly = false;
		if ($config->generateUrlPreview())
		{
			$results = Text::getDateConverterParams($this->getMessage() ?? '');
			foreach ($results as $result)
			{
				$dateText[] = $result->getText();
				$dateTs[] = $result->getDate()->getTimestamp();
			}

			$url = UrlItem::getByMessage($this);
			if (isset($url))
			{
				if ($url->getId() !== null)
				{
					$urlIds[] = $url->getId();
				}
				$this->setUrl($url);
				$isUrlOnly = $this->isUrlOnly($url);
			}
		}
		if ($config->keepConnectorSilence())
		{
			$this->getParams()->get(Params::STYLE_CLASS)->setValue('bx-messenger-content-item-system');
			if ($this->chat instanceof Im\V2\Chat\OpenLineChat)
			{
				$this->getParams()->get(Params::COMPONENT_ID)->setValue('HiddenMessage');
			}
		}
		$this->getParams()->get(Params::DATE_TEXT)->setValue($dateText);
		$this->getParams()->get(Params::DATE_TS)->setValue($dateTs);
		$this->getParams()->get(Params::URL_ID)->setValue($urlIds);
		$this->getParams()->get(Params::URL_ONLY)->setValue($isUrlOnly);

		return $this;
	}

	public function getCopilotData(): ?array
	{
		$chat = $this->getChat();
		$roleManager = (new RoleManager())->setContextUser($this->getAuthorId());

		if (
			!$this->getParams()->isSet(Params::COPILOT_ROLE)
			&& !$chat instanceof Im\V2\Chat\CopilotChat
		)
		{
			return null;
		}

		$roles = [];
		$messageRole = $this->getParams()->get(Params::COPILOT_ROLE)->getValue() ?? $this->getDefaultCopilotRole();
		$roles[] = $messageRole;
		$chatRoleInfo = null;

		if ($chat instanceof Im\V2\Chat\CopilotChat)
		{
			$chatRole = $roleManager->getMainRole($this->getChatId());
			$roles[] = $chatRole;
			$chatRoleInfo = [['dialogId' => $this->getChat()->getDialogId(), 'role' => $chatRole]];
		}

		return [
			'chats' => $chatRoleInfo,
			'messages' => $messageRole ? [['id' => $this->getId(), 'role' => $messageRole]] : null,
			'roles' => $roleManager->getRoles($roles),
		];
	}

	protected function getDefaultCopilotRole(): ?string
	{
		if (\Bitrix\Main\Loader::includeModule('imbot')
			&& $this->getAuthorId() === \Bitrix\Imbot\Bot\CopilotChatBot::getBotId()
		)
		{
			return RoleManager::getDefaultRoleCode();
		}

		return null;
	}

	private function isUrlOnly(?UrlItem $url): bool
	{
		if ($url === null)
		{
			return false;
		}

		if (!$url->isStaticUrl())
		{
			return false;
		}

		$messageWithoutUrl = str_replace($url->getUrl(), '', $this->getMessage() ?? '');

		return trim($messageWithoutUrl) === '';
	}

	/**
	 * Update search index record.
	 * @return void
	 */
	public function updateSearchIndex(): void
	{
		if ($this->getMessageId())
		{
			MessageTable::indexRecord($this->getMessageId());
		}
	}

	/**
	 * Lazy load message's context phrases.
	 * @return void
	 */
	public static function loadPhrases(): void
	{
		Loc::loadMessages(__FILE__);
	}

	public function deleteSoft(): Result
	{
		$service = Im\V2\Message\Delete\DeleteService::getInstanceByMessage($this);
		$service->setMode(DeletionMode::Soft);
		return $service->delete();
	}

	public function deleteComplete(): Result
	{
		$service = Im\V2\Message\Delete\DeleteService::getInstanceByMessage($this);
		$service->setMode(DeletionMode::Complete);
		return $service->delete();
	}

	public function filterByDate(DateTime $date): FilterResult
	{
		$result = new FilterResult();

		if ($this->getDateCreate()?->getTimestamp() > $date->getTimestamp())
		{
			return $result->setResult($this);
		}

		return $result->setResult(null)->setFiltered(true);
	}

	public function getRelatedChatId(): ?int
	{
		return $this->getChatId();
	}

	public function filterMessageText(): void
	{
		if (!$this->isSystem && $this->getMessage() !== null)
		{
			$this->setMessage(Text::filterUserBbCodes($this->getMessage(), $this->getContext()->getUserId()));
		}
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit