Tasks 26.400.0–26.500.100: CRM в задачах, события спринта, ревизии чек-листа и закрытые дыры в правах
Обновление безопасности
Закрыта уязвимость или ослабленная проверка прав. Ставить в первую очередь.
В коробочный Битрикс24 пришли сразу три версии задач: 26.400.0, 26.500.0 и 26.500.100. Разработчику достались события старта и завершения спринта, связи Ганта в REST 3.0 и привязка CRM к задачам, которая пока спрятана за опцией. Перед обновлением проверьте вызовы SocialNetwork::getMemberList(), одноимённые пользовательские поля у задач и шаблонов и шаблоны БП с вложениями. Администраторам лучше не откладывать обновление, в двух версиях закрыто девять уязвимостей, восемь из них в проверке прав.
Новое
Включите CRM в задачах (26.400.0)
По умолчанию функция выключена, включает её Option::set('tasks', 'crm_in_tasks_enabled', 'Y'). После этого в фильтре списка появляется поле CRM_ITEM. Русской подписи для него в lang-файлах нет, есть только английская «CRM item». Можно выбрать конкретный элемент, весь тип, все смарт-процессы или «без привязки». В колонке CRM элементы показываются чипами. Клик по чипу фильтрует список, рядом есть кнопка «Привязать элемент CRM». Ещё добавилось групповое действие для выбранных задач. Для интеграций есть REST-метод tasks.task.bindCrmItem с параметрами taskId и crmItemId (D_15, C_7 и так далее). Он добавляет один элемент к уже привязанным и проверяет право на редактирование задачи и доступ к элементу CRM. Тип целиком и «без привязки» метод не принимает. Пока опция выключена, метод отвечает ACCESS_DENIED.
Подпишитесь на старт и завершение спринта (26.400.0)
Скрам теперь бросает события старого ядра tasks:OnAfterSprintStart и tasks:OnAfterSprintFinish. В обработчик приходит массив: sprintId, groupId, sprintName, даты в timestamp, actorId и tasks[] с taskId и responsibleId. При завершении у каждой задачи есть флаг finished, а если незакрытые задачи переехали в другой спринт, приходит ещё targetSprintId. Исключение в обработчике модуль запишет в лог, спринт всё равно стартует или закроется.
Например, так можно собрать хвосты спринта по ответственным:
<?php declare(strict_types=1);
use Bitrix\Main\Diag\Logger;
use Bitrix\Main\EventManager;
EventManager::getInstance()->addEventHandlerCompatible(
'tasks',
'OnAfterSprintFinish',
static function (array $sprint): void {
$carriedOver = [];
foreach ($sprint['tasks'] as $task) {
if (!$task['finished']) {
$carriedOver[$task['responsibleId']][] = $task['taskId'];
}
}
if ($carriedOver !== []) {
Logger::create('vendor.sprints')?->info('Спринт {name}: не закрыто {tasks}', [
'name' => $sprint['sprintName'],
'tasks' => $carriedOver,
]);
}
},
);
Логгер vendor.sprints настраивается в секции loggers в .settings.php.
Забирайте связи Ганта через REST 3.0 (26.400.0)
tasks.task.gantt.link.list отдаёт связи задачи: taskId, dependentId, type, creatorId. filter.taskId обязателен, нужен доступ на чтение задачи, есть пагинация limit/offset. Метод работает только при включённой новой карточке задачи, иначе вернёт отказ в доступе.
Передавайте baseRevision при сохранении чек-листа (26.500.0)
У чек-листа появились ревизии. Если двое правят его одновременно, второй увидит попап «Другой участник внёс изменения в чек-лист» и сам выберет, какую версию сохранить.
Под капотом оптимистическая блокировка. AJAX tasks.V2.CheckList.save принимает baseRevision, сервер увеличивает ревизию, только если она не изменилась, иначе отвечает status: 'conflict' с актуальной версией. Остальные участники получают свежий чек-лист через pull-событие.
При завершении задачи с невыполненными пунктами появляется диалог «Похоже, ещё не всё». Из него можно завершить задачу, и пункты отметятся сами. В скрам-канбане так же работает перенос в «Готово». За это отвечает параметр completeWithChecklist у tasks.V2.Task.Status.complete и действий канбана.
Запускайте БП на создание задачи (26.500.0)
Для нового конструктора бизнес-процессов появился триггер «Создана задача». Он отдаёт ID, название, дату постановки, ответственного и ссылку на задачу. Включается опцией tasks bizproc_create_trigger_available = Y. Модуль объявляет его через TasksModuleSettings::getCreateDocumentTrigger(). Как ModuleSettings обновляет устаревшие триггеры, мы разбирали в bizproc 26.1400.0.
Что заметят пользователи
- Сообщение из чата задачи можно добавить в результат одной кнопкой (26.400.0).
- Пункты чек-листа можно создать из выделенного текста, дубли пропускаются (26.400.0).
- Таймер учёта времени стартует у ответственного, когда задачу переводят в «Выполняется», и останавливается при любом выходе из этого статуса, в том числе у бывших ответственного и соисполнителей (26.500.0).
Что сломается
Передайте userId в getMemberList и getTasksWithSubTaskIds (26.500.0)
Bitrix\Tasks\Integration\SocialNetwork::getMemberList($groupId) стал getMemberList(int $groupId, int $userId): ?array. Вызов с одним аргументом упадёт. Если пользователь не может смотреть группу, метод вернёт null.
То же с Bitrix\Tasks\V2\Public\Provider\Relation\AbstractRelationTaskProvider::getTasksWithSubTaskIds() и его наследниками (SubTaskProvider, RelatedTaskProvider и другие): теперь (array $ids, int $userId), задачи и подзадачи без права чтения у этого пользователя отбрасываются.
Не держите одноимённые поля у задач и шаблонов (26.500.0)
Если удалить пользовательское поле у TASKS_TASK, модуль удалит и поле с тем же FIELD_NAME у TASKS_TASK_TEMPLATE. В обратную сторону работает так же. Если у вас было два независимых UF_PRIORITY, второе пропадёт вместе с данными.
Переименуйте одно из полей до обновления.
Перепишите свой JS вокруг чек-листа и гридов (26.500.0)
tasks.V2.CheckList.getиsaveвозвращают{status, revision, checklist}вместо объекта чек-листа,completeиrenewвозвращают{status: 'success'}вместоtrue.- Ячейки грида задач и проектов (оценка, проект, стадия, дедлайн, участники, роль и другие) стали
<button type="button" class="... tasks-grid-control">вместо<a href="javascript:void(0)">и<div onclick>. Вtasks.departments_overviewкнопка отдела теперь несётdata-department-idвместоdata-id. Селекторы в своих стилях и скриптах проверьте.
Проверьте шаблоны БП с файлами (26.400.0)
Действие «Задача» загружает вложения от имени пользователя шаблона, а не постановщика. Файлы Диска оно берёт только из его хранилища и только те, что он может читать. Строки принимает только как http/https/ftp/ftps-ссылки или относительные пути портала, всё остальное молча отбрасывает.
Учтите новые правила доступа
- Право управления доступом (
TASK_ACCESS_MANAGE) больше не отключает фильтр доступа в списках задач наTaskQuery, обход остался только у администратора (26.400.0). - В новой карточке и при переносе в «Готово» завершить задачу может и тот, у кого есть только право приёмки. Обязательный результат по-прежнему проверяется, а повторное завершение уже закрытой задачи возвращает успех (26.500.0).
- Без права завершения задача в скраме не уедет в «Готово», канбан вернёт её обратно (26.500.0).
- Менять соисполнителей теперь могут и пользователи с правами на редактирование задач своего и чужих отделов (26.500.0).
Что закрыли
- 26.400.0: БП-действие «Задача» могло приложить к задаче локальный файл сервера или чужой файл Диска; через канбан можно было стать наблюдателем чужой задачи; комментарий и запись затрат времени читались по id из другой задачи;
task.commentitem.addв новой карточке публиковал комментарий от имени сотрудника без доступа к задаче, теперь такойAUTHOR_IDотклоняется; фильтрSCRUM_ENTITY_IDSвCTasks::GetListпопадал в SQL без приведения к числу. - 26.500.0:
tasks_extended.meta.setAnyStatusменял статус любой задачи от имени администратора, теперь работает от имени вызывающего и проверяет его права;getMemberListотдавал состав любой группы; в списке проектов можно было закрепить чужую группу и посмотреть её участников; провайдер связанных задач отдавал подзадачи без проверки чтения.
БД
Таблица b_tasks_checklist_revision создана в 26.400.0, ORM-класс к ней появился в 26.500.0. Если фильтруете задачи по множественному пользовательскому полю напрямую через b_utm_tasks_task, учтите новый индекс ix_utm_tasks_task_field_value: на MySQL он покрывает (FIELD_ID, VALUE(50)), на PostgreSQL (field_id, value text_pattern_ops).
Мелочи и находки
- В комментариях к фильтру CRM разработчики пишут, что
whereExpr()прогоняет выражение черезsprintf(), поэтому%вLIKE 'D_%'надо удваивать, а позиционные%1$sне трогать. - В catch-блоке
getMemberListдо 26.500.0 стоял отладочныйdd($e). - Шаблон «для нового сотрудника» с
BASE_TEMPLATE_IDтеперь вызывает ошибку валидации, раньше поле молча сбрасывалось (26.400.0). - crm начал вызывать
TaskStateProviderраньше, чем этот класс появился в задачах, и проверял его черезclass_exists(crm 26.1400.0). - В 26.500.100 у действия БП «Получить информацию о задаче» появился
getAiPassthroughSettingNames(), чтобы параметрTaskActivityDaysне терялся при обратном преобразовании настроек. Кода, который его вызывает, в bizproc пока нет.