453 lines
18 KiB
PHP
453 lines
18 KiB
PHP
<?php
|
||
|
||
class Project extends BaseEntity {
|
||
|
||
protected $db_name = 'project';
|
||
|
||
// Получение всех проектов (только те, где пользователь участник)
|
||
public function getAll() {
|
||
$current_user_id = RestApi::getCurrentUserId();
|
||
|
||
if (!$current_user_id) {
|
||
return [];
|
||
}
|
||
|
||
// Получаем ID проектов где пользователь участник
|
||
$projectIds = ProjectAccess::getUserProjectIds($current_user_id);
|
||
|
||
if (empty($projectIds)) {
|
||
return [];
|
||
}
|
||
|
||
$projects = Database::select($this->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 = (int)(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' => 'Ошибка создания проекта']];
|
||
}
|
||
|
||
return [
|
||
'success' => true,
|
||
'id' => $projectId,
|
||
'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 = (int)(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];
|
||
}
|
||
}
|
||
|
||
?>
|