im · Веб-мессенджер 26.900.0 Ломающее

im 26.900.0 + socialnetwork 26.150.0: инициатор в событиях внешних чатов и установщик на миграциях

1 мин чтения Устаревших API: 12

Ломающее обновление

Удалены или изменены публичные API — прикладной код может перестать работать.

В im 26.900.0 папки чатов научились работать с dialogId, мобильная синхронизация узнаёт об уволенных сотрудниках, у чата появился бэкенд навигации по датам, а установщик модуля переехал с SQL-файлов на UpdateSystem\Migration. Ломаются конструкторы десяти событий внешних чатов, несколько флагов в Features и REST-формат папок. socialnetwork 26.150.0 едет в том же пакете ради одной строки, которая создаёт Copilot-чат проекта в системном контексте, и im к этому подготовили.

Что сломается

Передайте инициатора в события внешних чатов

В конструкторы десяти событий Bitrix\Im\V2\Chat\ExternalChat\Event\* вторым параметром, сразу после ExternalChat $chat, встал обязательный int $initiatorId. Это AfterDeleteMessagesEvent, AfterSendMessageEvent, AfterUpdateMessageEvent, AfterUsersAddEvent, AfterUsersDeleteEvent, AfterUsersHideEvent, BeforeMessageSendEvent, BeforeUsersAddEvent, BeforeUsersDeleteEvent и BeforeUsersHideEvent. Сам ExternalChat передаёт туда id пользователя из контекста чата.

Подписчиков правка не задевает. Сломается код, который создаёт такие события сам, например в тестах или в своей обёртке над внешним чатом:

        <?php declare(strict_types=1);

use Bitrix\Im\V2\Chat\ExternalChat\Event\BeforeUsersAddEvent;

// до 26.900.0 было: new BeforeUsersAddEvent($chat, $userIds, $config)
$event = new BeforeUsersAddEvent($chat, $initiatorId, $userIds, $config);

    

Все десять событий реализуют новый интерфейс InitiatedByUserInterface с единственным методом getInitiatorId(): int, поэтому инициатора можно достать, не перебирая классы:

        <?php declare(strict_types=1);

use Bitrix\Im\V2\Chat\ExternalChat\Event\InitiatedByUserInterface;

function externalChatInitiator(object $event): ?int
{
    return $event instanceof InitiatedByUserInterface ? $event->getInitiatorId() : null;
}

    

Проверьте флаги в Features

Из Bitrix\Im\V2\Application\Features удалены три static-метода. isCopilotSelectModelAvailable() и isCopilotReasoningAvailable() и так всегда возвращали true, так что проверки на них можно убрать. Параметр Copilot reasoning сервер теперь принимает без условий. Третий, isUnreadRecentModeAvailable(), читал опцию unread_recent_mode_available.

isChatFoldersAvailable() переименован в isChatFoldersWebAvailable() и смотрит на другую опцию модуля: chat_folders_web_available вместо chat_folders_available. Если вы включали папки старой опцией, после обновления они выключатся, пока не выставите новую:

        <?php declare(strict_types=1);

use Bitrix\Main\Config\Option;

Option::set('im', 'chat_folders_web_available', 'Y');

    

С включённым флагом левое меню мессенджера скрывает пункты «Чаты», задачи, Copilot, коллабы, каналы и открытые линии.

Конструктор Features перестроили. Из него убраны шесть свойств (isCopilotSelectModelAvailable, unreadRecentModeAvailable, isCopilotReasoningAvailable, isMessageBuilderAvailable, isAddingUserByMentionAvailable, isExternalChatMessageForwardingAvailable), одно переименовано, а перед isReplyWithMediaAvailable вставлено isMessageDateNavigationAvailable. Позиционная сборка объекта сломается. Static-методы isMessageBuilderAvailable(), isAddingUserByMentionAvailable() и isExternalChatMessageForwardingAvailable() остались, флаги читайте через них.

Уберите BuilderError::BLOCK_NOT_AVAILABLE

Конструктор блоков сообщений больше не выключается флагом. Проверки isMessageBuilderAvailable() убраны из BuilderService, из валидатора блоков и из экшенов append, delete и update контроллера Controller\Chat\Message\Block\Element. Вместе с ними удалён код ошибки BuilderError::BLOCK_NOT_AVAILABLE, и обращение к этой константе в вашем коде теперь упадёт.

Обновите клиентов папок чатов

В веб-интерфейсе папки чатов пока за флагом, но если вы уже работаете с их REST, формат поменялся:

  • у личной папки definition.chatIds (массив чисел) заменён на definition.chats, массив пар {chatId, dialogId};
  • у личных и системных папок появилось поле sort;
  • системная папка открытых линий отдаёт code: "lines", а в definition.recentSection вместо openlines теперь тоже lines (хранимый код остался openlines). Клиент, который сравнивает recentSection со строкой 'openlines', совпадения не получит;
  • im.v2.Folder.add принимает в fields не только chatIds, но и dialogIds;
  • im.v2.Folder.addChats и im.v2.Folder.deleteChats принимают dialogIds рядом с chatIds, оба параметра необязательные;
  • im.v2.Folder.update умеет менять состав папки через поля chatIds/dialogIds, а название стало необязательным. Строка 'N' вместо массива очищает папку.

В PHP сменились сигнатуры DTO. FolderFields::fromArray() и UpdateFields::fromArray() теперь требуют DialogChatIdResolver, id текущего пользователя идёт третьим необязательным параметром (int $currentUserId = 0). Конструктор UpdateFields принимает (?string $title, ?ChatIds $chatIds = null).

Проверьте наследников SyncService

SyncService выбирает события строго после курсора (ID > lastId, раньше было >=), а курсор следующей страницы берёт по последней строке среза. Лог читается двумя запросами, по текущему пользователю и по глобальным событиям с USER_ID = 0, и потом сливается. Если вы наследовались от SyncService, проверьте getNavigationData(), у него новая сигнатура (array $logEvents, DateTime $incomingLastDate, ?int $incomingLastId, bool $hasMore). Мобильная ревизия API Revision::MOBILE поднята с 25 до 26.

Что ещё ведёт себя иначе

  • PrivateChat::getDialogIds() теперь возвращает чат «заметок» (переписку с самим собой) с собственным userId. Раньше контекстный пользователь исключался из выборки. Если в чате есть собеседник, выигрывает он.
  • RecentItem для личного чата кладёт в dialogId id собеседника, а не chat<ID>. Комментарий // TODO: replace рядом с этой строкой удалили.
  • Из NotifyChat и Reading\Notification\Reader убраны вызовы \Bitrix\Pull\MobileCounter::send(). Куда переехала отправка мобильного счётчика, по диффу не видно.
  • В письме о непрочитанных сообщениях CIMMail строки больше не проходят через nl2br().

Новое

Навигация по датам, пока только бэкенд

Появились REST-методы im.v2.Chat.Message.DateNavigation.getCalendar и im.v2.Chat.Message.DateNavigation.resolveDate. Первый возвращает дни, в которые в чате есть видимые сообщения, и границы истории (firstAvailableDate, lastAvailableDate). Второй находит первое сообщение нужной даты, а если в этот день сообщений нет, переходит к ближайшему следующему дню с сообщениями. Учитываются startId пользователя в чате (его берут по контекстному пользователю объекта Chat) и тарифное ограничение истории.

Методы закрыты флагом Features::isMessageDateNavigationAvailable() (опция message_date_navigation_available, по умолчанию N), фронтенда в релизе нет. Флаг проверяет только контроллер, поэтому сервис DateNavigationService можно вызывать из своего кода уже сейчас. Доступ к чату сервис не проверяет, это остаётся за вами:

        <?php declare(strict_types=1);

namespace Vendor\Chat\Report;

use Bitrix\Im\V2\Chat;
use Bitrix\Im\V2\Message\DateNavigation\DateNavigationService;

final class ChatActivityCalendar
{
    /** @return string[] дни в формате Y-m-d */
    public function activeDays(Chat $chat, int $userId, string $from, string $to): array
    {
        // startId и границы истории сервис берёт по контекстному пользователю чата
        $chat = $chat->withContextUser($userId);

        if (!$chat->checkAccess($userId)->isSuccess()) {
            return [];
        }

        $fromDate = DateNavigationService::parseDate($from);
        $toDate = DateNavigationService::parseDate($to);
        if ($fromDate === null || $toDate === null) {
            return [];
        }

        $result = DateNavigationService::createForClientOffset($chat, null)
            ->getCalendar($fromDate, $toDate);

        return $result->isSuccess() ? $result->getResult()->getDays() : [];
    }
}

    

Диапазон не шире 62 дней, иначе вернётся ошибка DateNavigationError::WRONG_RANGE. null вместо смещения клиента означает смещение из \CTimeZone::GetOffset(). Даты ожидаются в формате Y-m-d, на кривой строке parseDate() вернёт null.

Папки понимают dialogId

Под это завели пару резолверов. DialogChatIdResolver превращает dialogId в id чатов: chat42 разбирается без запроса, числовые id пользователей уходят одним пакетным запросом, остальное (crm|…, sg…) идёт через Dialog::getChatId(). ChatDialogIdResolver делает обратное. Контроллер папок берёт резолвер из сервис-локатора, так же можно и в своём коде:

        <?php declare(strict_types=1);

use Bitrix\Im\V2\Chat\DialogChatIdResolver;
use Bitrix\Main\DI\ServiceLocator;
use Bitrix\Main\Loader;

Loader::requireModule('im');

$resolver = ServiceLocator::getInstance()->get(DialogChatIdResolver::class);
$chatIds = $resolver->resolve([], ['chat42', '17'], $currentUserId, createMissing: false);

// $chatIds->values: уникальные положительные id чатов

    

По умолчанию createMissing равен true, и для пользователя без личного чата резолвер этот чат создаст. Если нужно только найти существующие чаты, передавайте false, как это делает сам deleteChatsAction().

Лимиты папок собраны в FolderLimits: 20 папок на пользователя, 50 чатов в папке, 30 символов в названии. Размер запрошенного состава проверяется до резолва, чтобы длинный список dialogIds не наплодил личных чатов, которые в папку всё равно не влезут. Если при обновлении папки непустой состав не разрешился ни в один чат, запрос отклоняется с кодом FOLDER_CHAT_NOT_ELIGIBLE, и папка остаётся как была.

Когда корневой чат прикрепляют к родителю, он пропадает из личных папок всех пользователей (FolderCascadeHandler::onChatAttachedToParent()).

Мобильный клиент узнаёт об уволенных

Sync\UserLifecycleService пишет в лог синхронизации глобальные события: userFired, когда пользователя деактивируют, userRestored, когда возвращают, и событие полного удаления. Его вызывают CIMEvent::OnAfterUserUpdate и CIMEvent::OnUserDelete. Служебные и внешние учётки (боты, email, imconnector, гости и другие) он пропускает. Записи уходят в фоне через Logger::addGlobal() с USER_ID = 0.

В ответе синхронизации появился блок userSync с updatedUsers и deletedUsers. Список обновлённых фильтруется по видимости. Интранет-пользователь видит всех, экстранет и гости получают только доступных им, а без контекстного пользователя список пустой.

Для тех, кого уволили до обновления, есть одноразовый агент Sync\Agent\FiredUsersAgent. Он порциями по 500 проходит неактивных реальных пользователей с последней активностью начиная с 2023-01-01 (или без неё) и дописывает им userFired.

Участники по группам

im.v2.Chat.Member.tail принимает withGroupSort. С ним участники идут группами: владелец, менеджеры, коллаберы, остальные. Сайдбар включает этот режим для коллаб.

Остальное

  • MessageHistoryFilter получил последний параметр bool $includeSystem = false. С true провайдер истории отдаёт системные и приветственные сообщения; удалённые и сообщения об ошибках не попадают туда никогда.
  • GuestNetworkPortalRegistry::getShortLinkBaseUrl() выбирает базу гостевых ссылок: https://bitrix24.net/gi/, если сеть портала смотрит на bitrix24.net, иначе https://b24.to/gi/. Раньше b24.to был зашит константой в GuestChatLink.
  • Extranet::filterUserList() и соседние методы принимают bool $filterActiveUser = true.
  • DocumentSign::isAvailable() кеширует ответ модуля sign на сутки для каждого пользователя.
  • Два новых стикерпака: aiHelp (10 стикеров) и ladyBoss (44).

БД: схема та же, таблицы теперь создаёт UpdateSystem\Migration

InstallDB() вызывает installMigrations(), UnInstallDB() вызывает uninstallMigrations(), а файлы install/db/mysql/*.sql и install/db/pgsql/*.sql удалены. Вместо них:

  • install/migrations/tables.php описывает схему через UpdateSystem\Migration, один файл на MySQL и PostgreSQL. С удалённым MySQL-скриптом он совпадает по набору таблиц (69) и колонок в каждой, типы построчно не сверялись. Пять полнотекстовых индексов из бывшего install_ft.sql объявлены здесь же;
  • install/migrations/events.php регистрирует те же 42 обработчика, что раньше InstallDB();
  • install/migrations/agents.php содержит прежние агенты и новый FiredUsersAgent;
  • migration_config.json задаёт defaultTableName: b_im_chat и маппинг каталогов установки.

Самих installMigrations() и Migration в диффе нет, они живут в main.

Проверьте savedata в скриптах удаления

Раньше UnInstallDB() сохранял таблицы при любом истинном значении savedata. Условие стало таким:

        $needDropTables = !array_key_exists('savedata', $arParams) || $arParams['savedata'] != 'Y';

    

Теперь 'N' или 1 удаляют таблицы. Если у вас есть скрипты, которые переустанавливают im с сохранением данных, передавайте именно 'Y'.

Пять агентов старый InstallDB() регистрировал с ведущим \ (например, \Bitrix\Im\V2\Recent\Initializer::executeAgent();), а в agents.php те же имена записаны без него. Как uninstallMigrations() ищет агенты, по диффу не видно, так что после удаления модуля загляните в список агентов.

Мелочи и находки

  • Правка в socialnetwork одна. ProjectCopilotChatProvider создаёт Copilot-чат проекта через withContextUser(0) вместо контекста пользователя. По комментарию в коде, коллабер не видит бота Copilot, фильтры видимости выкинули бы бота из состава, и чат остался бы без того, кто в нём отвечает. В im под это доработали CopilotChat: sendBanner() без автора берёт автора чата, а номер в названии чата в системном контексте идёт из счётчика автора.
  • Имя агента Copilot для незападной зоны сменилось с BitrixGPT 5.5 Agent на BitrixGPT 5.6 Agent 1M.
  • В UIPromotionService почистили промо. Условия для промо видеозаметок и стикеров читали Features::get()->videoNoteAvailable и ->stickersAvailable, а таких свойств в Features нет. Теперь этих двух промо нет совсем, а промо смены движка и роли Copilot добавляется без условий и живёт до 30.04.2027.
  • UpdateFields делает частичное обновление через неинициализированное readonly-свойство. ValidationService проверяет только инициализированные свойства, поэтому непереданный title валидацию пропускает. Приём можно взять и в свои Request DTO.
  • DateNavigationService::parseDate() проверяет дату обратным форматированием, чтобы 2026-02-31 молча не превратилась в мартовскую дату.
  • Кеш Extranet раньше не различал выборку с неактивными пользователями и без, потому что ключ im_sonet_extranet_v3_<userId> не зависел от $filterActiveUser. Теперь к нему добавляется _active или _all.
  • В комментариях всплывают внутренние коды задач: ALG-01 в синхронизации и сортировке участников, RF-2 в фильтре видимости.
  • Комментарий в RecentItem обещает, что для открытых линий, каналов и коллаб вывод «byte-identical to master».

Что делать

Перед обновлением поищите в своём коде ExternalChat\Event\, isChatFoldersAvailable, isCopilotSelectModelAvailable, isCopilotReasoningAvailable, isUnreadRecentModeAvailable, BLOCK_NOT_AVAILABLE, definition.chatIds и 'openlines'. После обновления проверьте опцию chat_folders_web_available, если пользуетесь папками, и savedata в скриптах удаления.

Устаревшие и удалённые API в этой версии

Символ Статус Чем заменять
Bitrix\Im\V2\Application\Features::isChatFoldersAvailable() Удалено Bitrix\Im\V2\Application\Features::isChatFoldersWebAvailable()
Bitrix\Im\V2\Application\Features::isCopilotSelectModelAvailable() Удалено —
Bitrix\Im\V2\Application\Features::isCopilotReasoningAvailable() Удалено —
Bitrix\Im\V2\Application\Features::isUnreadRecentModeAvailable() Удалено —
Bitrix\Im\V2\Application\Features::$isChatFoldersAvailable Удалено Bitrix\Im\V2\Application\Features::$isChatFoldersWebAvailable
Bitrix\Im\V2\Application\Features::$isCopilotSelectModelAvailable Удалено —
Bitrix\Im\V2\Application\Features::$isCopilotReasoningAvailable Удалено —
Bitrix\Im\V2\Application\Features::$unreadRecentModeAvailable Удалено —
Bitrix\Im\V2\Application\Features::$isMessageBuilderAvailable Удалено Bitrix\Im\V2\Application\Features::isMessageBuilderAvailable()
Bitrix\Im\V2\Application\Features::$isAddingUserByMentionAvailable Удалено Bitrix\Im\V2\Application\Features::isAddingUserByMentionAvailable()
Bitrix\Im\V2\Application\Features::$isExternalChatMessageForwardingAvailable Удалено Bitrix\Im\V2\Application\Features::isExternalChatMessageForwardingAvailable()
Bitrix\Im\V2\Message\BlocksBuilder\BuilderError::BLOCK_NOT_AVAILABLE Удалено —

Читайте дальше

im 26.800.0 Заметное

im 26.800.0 + socialnetwork 26.100.0: чаты крепятся к проекту, markdown в сообщениях, учёт входов по ссылке

Большой парный релиз: `im` и `socialnetwork` едут одним батчем, потому что делают одну вещь — сращивают чаты с проектами. Чат теперь можно прикрепить к проекту как дочерний, лента знает о своих IM-сообщениях, а прочтение в одном месте гасит счётчик в другом. Плюс markdown и учёт участников шаринг-сс...

5 мин
im 26.700.0 Безопасность

im 26.700.0: гостевой доступ переписан с нуля — REST-метод joinByCode удалён

Вход гостя в чат по ссылке перестал быть «REST-методом плюс правилом в urlrewrite» и стал полноценной областью авторизации на уровне ядра. Заодно у гостевых ссылок появился срок жизни, а у неактивных гостей — агент очистки. Если вы что-то строили поверх гостевых чатов, этот релиз ломающий.

4 мин
voximplant 26.700.0 Ломающее Свежее

Voximplant 26.700.0: оценку качества связи убрали, у notifyAdmins() появился тип

Модуль телефонии voximplant 26.700.0 вышел в коробочный Битрикс24 11 сентября 2026 года, по данным официального канала «Битрикс24 changelog». Из карточки звонка убрали оценку качества связи вместе с её JS-событиями, у `Im::notifyAdmins()` появился тип параметра, а публичные константы `SipStatusInfor...

3 мин
ui 26.687.0 Рутинное Свежее

UI 26.687.0: триал VibePlus в облаке и дизайн чипа TintedBitrixGpt

`Bitrix\UI\Controller\InfoHelper` при активации демо сначала спрашивает у модуля bitrix24, включён ли старт VibePlus, и если да, запускает триал VibePlus вместо обычного демо тарифа. Ветка срабатывает только при подключённом модуле bitrix24 и определённой константе `BX24_HOST_NAME`. В `ui.system.chi...

1 мин
Мы используем файлы cookie для улучшения работы сайта. Продолжая использовать сайт, вы соглашаетесь с нашей политикой конфиденциальности.
AI Домовой

AI Домовой История

на связи

пишет…
Нет истории чатов
AI Домовой

Нужна авторизация

Войдите, чтобы задавать вопросы AI Домовому.

Войти