Rpa 26.300.0: права на перемещение элементов наконец проверяются
Обновление безопасности
Закрыта уязвимость или ослабленная проверка прав. Ставить в первую очередь.
До RPA 26.300.0 UserPermissions::canMoveItem() сразу отвечал true, и любой сотрудник, кроме экстранет-пользователей, мог перетащить любой элемент на любую стадию, а права стадии на перемещение не учитывались. Теперь права проверяются, а тем, кто может только смотреть, rpa.item.get и rpa.item.list отдают элементы без значений пользовательских полей (название остаётся в name). Проверьте интеграции, которые двигают элементы, свои шаблоны формы задания и роботов согласования с очередью.
Новое
F5 больше не закрывает карточку элемента, открытую над списком или канбаном. BX.Rpa.Manager запоминает адреса карточки и списка в history.state и добавляет в URL маркер __rpa_slider_restore=1. В браузерах с Navigation API менеджер сам перехватывает перезагрузку, в остальных страницу с маркером обрабатывает компонент rpa.router. Если ваш код вызывает BX.Rpa.Manager.Instance.setUrlTemplates() напрямую, учтите, что при RPA-состоянии в history.state или маркере в URL этот вызов теперь может перезагрузить страницу, открыть слайдер или сделать location.replace.
В карточке появились подсказки полей. Components\ItemDetail передаёт в редактор HELP_MESSAGE пользовательского поля, и ui.entity-editor берёт оттуда текст хинта.
Что сломается
Проверьте, кто у вас двигает элементы
canMoveItem() и canMoveFromStage() раньше возвращали true через canMoveAnywhere(), а он всегда true. Теперь администратора canMoveItem() пускает всегда, остальных — только при одном из трёх условий (canMoveFromStage() проверяет первое и третье):
- право
ITEMS_CREATEна процесс (canAddItemsToType()); - быть автором элемента и переносить его с первой стадии;
- право
MOVEна исходную стадию.
canMoveItem() вызывается в Command\Update, поэтому смена stageId через rpa.item.update без этих прав заканчивается ошибкой RPA_ITEM_MOVE_ACCESS_DENIED. В интерфейсе такой пользователь стадию не сменит: карточки в канбане у него серые и не перетаскиваются, шкала стадий в карточке элемента неактивна. На стандартных настройках ничего не меняется, потому что процессу, созданному в интерфейсе, Scenario\DraftType выдаёт ITEMS_CREATE всем сотрудникам (код доступа UA). Процесс, созданный через rpa.type.add без permissions, этого права не получает. Отказы начнутся на порталах, где в настройках процесса сужен круг тех, кто добавляет элементы, и у вебхуков таких пользователей. Повтор запроса не поможет, нужно выдать право на стадию или перевести интеграцию на вебхук пользователя с правами.
Команда и сама вернёт ошибку, но если перед переносом вы пишете что-то во внешнюю систему, право лучше спросить заранее:
<?php
declare(strict_types=1);
namespace Vendor\Module\Application\Service;
use Bitrix\Main\Error;
use Bitrix\Main\Loader;
use Bitrix\Main\Result;
use Bitrix\Rpa\Driver;
final class RpaStageMover
{
public function move(int $typeId, int $itemId, int $toStageId, int $userId): Result
{
$result = new Result();
if (!Loader::includeModule('rpa')) {
return $result->addError(new Error('Модуль rpa не установлен'));
}
$driver = Driver::getInstance();
$item = $driver->getType($typeId)?->getItem($itemId);
if ($item === null) {
return $result->addError(new Error('Элемент не найден'));
}
$permissions = $driver->getUserPermissions($userId);
if (!$permissions->canMoveItem($item, $item->getStageId(), $toStageId)) {
return $result->addError(new Error('Нет права переносить элемент с текущей стадии', 'MOVE_DENIED'));
}
$item->setStageId($toStageId);
return $driver->getFactory()->getUpdateCommand($item)->setUserId($userId)->run();
}
}
Если пользователь последним перемещал элемент, канбан по-прежнему даёт ему схватить карточку (permissions.draggable остаётся true), но сервер перенос не примет.
Значения полей пропадут у тех, кто только смотрит
Controller\Item::prepareItemData() кладёт значения пользовательских полей в ответ, только если пользователь может менять элементы на стадии, переносить их с неё или сам последним переместил элемент. Второе условие раньше выполнялось всегда. Теперь пользователь без ITEMS_CREATE на процесс и без MOVE на стадию, если не он последним переместил элемент, получает в rpa.item.get, rpa.item.list и канбане элементы без значений полей, а permissions.draggable у него false. Название карточки при этом не пропадёт. Если поля названия нет в данных, канбан берёт name из ответа, а Item::getName() кладёт туда то же название или «Название процесса #ID», если оно пустое. В 26.200.0 нули и «Нет» перестали превращаться в null при сохранении, а теперь у части пользователей этих полей нет в ответе вовсе.
Форма задания сохраняет только поля из задания
Раньше компонент rpa.task.fields отправлял в CBPDocument::PostTaskForm() все пользовательские поля процесса из запроса, и робот записывал их в элемент. Теперь RpaAutomationTaskFieldsComponent::saveAction() фильтрует данные по FIELDS_TO_SET задания, это список «Поля, которые заполнить» робота «Запросить информацию». Лишние поля отбрасываются без ошибки. У файлового поля из списка проходит и флаг удаления <поле>_del. Если ваш шаблон формы или скрипт дописывал через задание другие поля, добавьте их в «Поля, которые заполнить», но учтите, что форма сделает их обязательными.
Очередь согласования иначе обходит отсутствующих
Если у робота «Утвердить или отклонить» включены режим «Все по очереди» и флаг «Пропускать тех, кто в отпуске», задания начнут приходить другим людям. Вместо отсутствующего участника задание получает следующий в очереди, кто на месте, а заместитель из поля «Назначить заместителя» назначается, только когда отсутствуют все оставшиеся. До обновления задание отсутствующего сразу уходило заместителю, а если заместителя не задали, очередь считалась пройденной.
Читайте права наследника через getPermissions()
Конструктор UserPermissions больше не вызывает loadUserPermissions(), права грузятся лениво в новом getPermissions(). Наследник, подменённый через событие rpa:onDriverCollectClasses, при прямом чтении $this->permissions до первого вызова получит null. Если же canMoveAnywhere() в наследнике возвращает false, canMoveFromStage() больше не вызывает isSimplePermissionsForTheFirstStage() и isAlwaysCanMoveToTheNextStage(): с любой стадии пускает ITEMS_CREATE на процесс, иначе нужен MOVE на стадию, а в canMoveItem() переход между стадиями теперь проверяется на всех путях. Для переопределения появились protected-методы fetchPermissionRows(array $accessCodes): iterable (выборка из PermissionTable, в select только ENTITY, ENTITY_ID, ACTION, PERMISSION) и isMovingBackAvailable().