db_name, [ 'id', 'id_order', 'name', 'id_ready' ], [ 'id' => $projectIds, 'ORDER' => ['id_order' => 'ASC'] ]); // Добавляем флаг is_admin для каждого проекта return array_map(function($project) use ($current_user_id) { $project['is_admin'] = ProjectAccess::isAdmin($project['id'], $current_user_id); return $project; }, $projects); } // Получение одного проекта public static function get($id, $current_user_id = null) { $project = Database::get('project', [ 'id', 'id_order', 'name', 'id_ready' ], ['id' => $id]); if ($project && $current_user_id) { $project['is_admin'] = ProjectAccess::isAdmin($id, $current_user_id); } return $project; } // Получение id_ready (ID колонки "Готово") по ID проекта public static function getReadyColumnId($project_id) { $project = Database::get('project', ['id_ready'], ['id' => $project_id]); return $project ? (int)$project['id_ready'] : null; } // Получение колонок проекта public static function getColumns($project_id) { return Database::select('columns', [ 'id', 'name_columns', 'color', 'id_order' ], [ 'id_project' => $project_id, 'ORDER' => ['id_order' => 'ASC'] ]); } // Получение отделов проекта public static function getDepartments($project_id) { return Database::select('departments', [ 'id', 'name_departments', 'color', 'order_id' ], [ 'id_project' => $project_id, 'ORDER' => ['order_id' => 'ASC'] ]); } // Получение всех данных проекта (проект + колонки + отделы + метки) public static function getProjectData($project_id) { // Получаем ID текущего пользователя для проверки админства $current_user_id = RestApi::getCurrentUserId(); $project = self::get($project_id, $current_user_id); if (!$project) { return null; } // Получаем метки (глобальные) $labels = Database::select('labels', [ 'id', 'name_labels', 'icon', 'color' ]); return [ 'project' => $project, 'columns' => self::getColumns($project_id), 'departments' => self::getDepartments($project_id), 'labels' => $labels ]; } // ==================== CRUD ПРОЕКТОВ ==================== // Создание проекта с дефолтными колонками public static function create($name, $user_id) { // Получаем максимальный id_order $maxOrder = Database::max('project', 'id_order') ?? 0; // Создаём проект с создателем как владельцем (id_admin) Database::insert('project', [ 'name' => $name, 'id_order' => $maxOrder + 1, 'id_admin' => json_encode([$user_id]) ]); $projectId = Database::id(); if (!$projectId) { return ['success' => false, 'errors' => ['project' => 'Ошибка создания проекта']]; } // Создаём дефолтные колонки Database::insert('columns', [ 'name_columns' => 'К выполнению', 'color' => '#6366f1', 'id_project' => $projectId, 'id_order' => 1 ]); $firstColumnId = Database::id(); Database::insert('columns', [ 'name_columns' => 'Готово', 'color' => '#22c55e', 'id_project' => $projectId, 'id_order' => 2 ]); $readyColumnId = Database::id(); // Устанавливаем id_ready Database::update('project', ['id_ready' => $readyColumnId], ['id' => $projectId]); return [ 'success' => true, 'id' => $projectId, 'columns' => [ ['id' => $firstColumnId, 'name_columns' => 'К выполнению', 'color' => '#6366f1', 'id_order' => 1], ['id' => $readyColumnId, 'name_columns' => 'Готово', 'color' => '#22c55e', 'id_order' => 2] ], 'id_ready' => $readyColumnId, 'is_admin' => true ]; } // Обновление проекта public static function update($id, $name, $user_id) { if (!ProjectAccess::isAdmin($id, $user_id)) { return ['success' => false, 'errors' => ['access' => 'Нет прав на редактирование']]; } Database::update('project', ['name' => $name], ['id' => $id]); return ['success' => true]; } // Удаление проекта (каскадно: колонки, задачи, комментарии, файлы) public static function delete($id, $user_id) { if (!ProjectAccess::isAdmin($id, $user_id)) { return ['success' => false, 'errors' => ['access' => 'Нет прав на удаление']]; } // Получаем все задачи проекта $tasks = Database::select('cards_task', ['id'], ['id_project' => $id]); $taskIds = array_column($tasks, 'id'); if (!empty($taskIds)) { // Получаем все комментарии к задачам $comments = Database::select('comments', ['id'], ['id_task' => $taskIds]); // Удаляем файлы комментариев с диска foreach ($comments as $comment) { FileUpload::deleteFolder('comment', $comment['id']); } // Удаляем комментарии из БД Database::delete('comments', ['id_task' => $taskIds]); } // Удаляем файлы задач с диска foreach ($tasks as $task) { FileUpload::deleteFolder('task', $task['id']); } // Удаляем задачи из БД Database::delete('cards_task', ['id_project' => $id]); // Удаляем колонки Database::delete('columns', ['id_project' => $id]); // Удаляем отделы проекта Database::delete('departments', ['id_project' => $id]); // Удаляем участников проекта Database::delete('project_members', ['id_project' => $id]); // Удаляем приглашения в проект Database::delete('project_invites', ['id_project' => $id]); // Удаляем проект Database::delete('project', ['id' => $id]); return ['success' => true]; } // Обновление порядка проектов public static function updateOrder($ids, $user_id) { foreach ($ids as $order => $id) { Database::update('project', ['id_order' => $order + 1], ['id' => $id]); } return ['success' => true]; } // ==================== CRUD КОЛОНОК ==================== // Добавление колонки public static function addColumn($project_id, $name, $color, $user_id) { if (!ProjectAccess::can($project_id, $user_id, 'create_column')) { return ['success' => false, 'errors' => ['access' => 'Нет прав на создание колонок']]; } // Получаем максимальный id_order для проекта $maxOrder = Database::max('columns', 'id_order', ['id_project' => $project_id]) ?? 0; Database::insert('columns', [ 'name_columns' => $name, 'color' => $color ?: '#6366f1', 'id_project' => $project_id, 'id_order' => $maxOrder + 1 ]); $columnId = Database::id(); return [ 'success' => true, 'id' => $columnId, 'column' => [ 'id' => $columnId, 'name_columns' => $name, 'color' => $color ?: '#6366f1', 'id_order' => $maxOrder + 1 ] ]; } // Обновление колонки public static function updateColumn($id, $name, $color, $user_id) { // Получаем колонку для проверки проекта $column = Database::get('columns', ['id_project'], ['id' => $id]); if (!$column) { return ['success' => false, 'errors' => ['column' => 'Колонка не найдена']]; } if (!ProjectAccess::can($column['id_project'], $user_id, 'edit_column')) { return ['success' => false, 'errors' => ['access' => 'Нет прав на редактирование колонок']]; } $updateData = []; if ($name !== null) $updateData['name_columns'] = $name; if ($color !== null) $updateData['color'] = $color; if (!empty($updateData)) { Database::update('columns', $updateData, ['id' => $id]); } return ['success' => true]; } // Удаление колонки (возвращает количество задач для подтверждения) public static function getColumnTasksCount($column_id) { return Database::count('cards_task', ['column_id' => $column_id]); } // Удаление колонки с задачами public static function deleteColumn($id, $user_id) { // Получаем колонку для проверки проекта $column = Database::get('columns', ['id_project', 'id_order'], ['id' => $id]); if (!$column) { return ['success' => false, 'errors' => ['column' => 'Колонка не найдена']]; } if (!ProjectAccess::can($column['id_project'], $user_id, 'delete_column')) { return ['success' => false, 'errors' => ['access' => 'Нет прав на удаление колонок']]; } // Проверяем, не является ли это последней колонкой перед "Готово" // Минимум должно быть 3 колонки (2 обычные + готово), чтобы можно было удалить $columnsCount = Database::count('columns', ['id_project' => $column['id_project']]); if ($columnsCount <= 2) { return ['success' => false, 'errors' => ['column' => 'Нельзя удалить последнюю колонку перед финальной']]; } // Проверяем, не является ли это последней (финальной) колонкой $lastColumn = Database::get('columns', ['id'], [ 'id_project' => $column['id_project'], 'ORDER' => ['id_order' => 'DESC'], 'LIMIT' => 1 ]); if ($lastColumn && (int)$lastColumn['id'] === (int)$id) { return ['success' => false, 'errors' => ['column' => 'Нельзя удалить финальную колонку (последнюю)']]; } // Получаем задачи колонки $tasks = Database::select('cards_task', ['id'], ['column_id' => $id]); $taskIds = array_column($tasks, 'id'); // Удаляем комментарии к задачам if (!empty($taskIds)) { Database::delete('comments', ['id_task' => $taskIds]); } // Удаляем задачи Database::delete('cards_task', ['column_id' => $id]); // Удаляем колонку Database::delete('columns', ['id' => $id]); // Обновляем id_ready на новую последнюю колонку $newLastColumn = Database::get('columns', ['id'], [ 'id_project' => $column['id_project'], 'ORDER' => ['id_order' => 'DESC'], 'LIMIT' => 1 ]); if ($newLastColumn) { Database::update('project', ['id_ready' => $newLastColumn['id']], ['id' => $column['id_project']]); } return ['success' => true, 'deleted_tasks' => count($taskIds)]; } // Обновление порядка колонок public static function updateColumnsOrder($project_id, $ids, $user_id) { if (!ProjectAccess::can($project_id, $user_id, 'edit_column')) { return ['success' => false, 'errors' => ['access' => 'Нет прав на редактирование колонок']]; } foreach ($ids as $order => $id) { Database::update('columns', ['id_order' => $order + 1], ['id' => $id, 'id_project' => $project_id]); } // Автоматически устанавливаем id_ready на последнюю колонку $lastColumnId = end($ids); if ($lastColumnId) { Database::update('project', ['id_ready' => $lastColumnId], ['id' => $project_id]); } return ['success' => true]; } // Установка финальной колонки (id_ready) - ЗАБЛОКИРОВАНО // Финальная колонка всегда последняя, изменение запрещено public static function setReadyColumn($project_id, $column_id, $user_id) { return ['success' => false, 'errors' => ['column' => 'Изменение финальной колонки запрещено. Финальная колонка всегда последняя.']]; } // ==================== CRUD ОТДЕЛОВ ==================== // Добавление отдела public static function addDepartment($project_id, $name, $color, $user_id) { if (!ProjectAccess::can($project_id, $user_id, 'manage_departments')) { return ['success' => false, 'errors' => ['access' => 'Нет прав на управление отделами']]; } // Валидация имени if (!$name || trim($name) === '') { return ['success' => false, 'errors' => ['name' => 'Укажите название отдела']]; } // Получаем максимальный order_id для проекта $maxOrder = (int)(Database::max('departments', 'order_id', ['id_project' => $project_id]) ?? 0); $newOrderId = $maxOrder + 1; Database::insert('departments', [ 'name_departments' => $name, 'color' => $color ?: '#6366f1', 'id_project' => $project_id, 'order_id' => $newOrderId ]); $departmentId = Database::id(); return [ 'success' => true, 'id' => $departmentId, 'department' => [ 'id' => $departmentId, 'name_departments' => $name, 'color' => $color ?: '#6366f1', 'order_id' => $newOrderId ] ]; } // Обновление отдела public static function updateDepartment($id, $name, $color, $user_id) { // Получаем отдел для проверки проекта $department = Database::get('departments', ['id_project'], ['id' => $id]); if (!$department) { return ['success' => false, 'errors' => ['department' => 'Отдел не найден']]; } if (!ProjectAccess::can($department['id_project'], $user_id, 'manage_departments')) { return ['success' => false, 'errors' => ['access' => 'Нет прав на управление отделами']]; } // Валидация имени (если передано) if ($name !== null && trim($name) === '') { return ['success' => false, 'errors' => ['name' => 'Укажите название отдела']]; } $updateData = []; if ($name !== null) $updateData['name_departments'] = $name; if ($color !== null) $updateData['color'] = $color; if (!empty($updateData)) { Database::update('departments', $updateData, ['id' => $id]); } return ['success' => true]; } // Получение количества задач в отделе public static function getDepartmentTasksCount($department_id) { return Database::count('cards_task', ['id_department' => $department_id]); } // Удаление отдела (обнуляет id_department у задач) public static function deleteDepartment($id, $user_id) { // Получаем отдел для проверки проекта $department = Database::get('departments', ['id_project'], ['id' => $id]); if (!$department) { return ['success' => false, 'errors' => ['department' => 'Отдел не найден']]; } if (!ProjectAccess::can($department['id_project'], $user_id, 'manage_departments')) { return ['success' => false, 'errors' => ['access' => 'Нет прав на управление отделами']]; } // Обнуляем id_department у задач (не удаляем сами задачи) Database::update('cards_task', ['id_department' => null], ['id_department' => $id]); // Удаляем отдел Database::delete('departments', ['id' => $id]); return ['success' => true]; } // Обновление порядка отделов public static function updateDepartmentsOrder($project_id, $ids, $user_id) { if (!ProjectAccess::can($project_id, $user_id, 'manage_departments')) { return ['success' => false, 'errors' => ['access' => 'Нет прав на управление отделами']]; } foreach ($ids as $order => $id) { Database::update('departments', ['order_id' => $order + 1], ['id' => $id, 'id_project' => $project_id]); } return ['success' => true]; } } ?>