1
0

Комментарии, файлы и права проекта

- Система комментариев к задачам с вложенными ответами
- Редактирование и удаление комментариев
- Прикрепление файлов к задачам и комментариям (картинки, архивы до 10 МБ)
- Система прав проекта: админ проекта может удалять чужие комментарии и файлы
- Универсальный класс FileUpload для загрузки файлов
- Защита загрузки: только автор комментария может добавлять файлы
- Каскадное удаление: задача → комментарии → файлы
- Автообновление комментариев в реальном времени
This commit is contained in:
2026-01-15 06:40:47 +07:00
parent 8ac497df63
commit 3bfa1e9e1b
25 changed files with 3353 additions and 904 deletions

View File

@@ -84,7 +84,7 @@ class Task extends BaseEntity {
$uploaded_files = [];
if (!empty($files)) {
foreach ($files as $file) {
$result = TaskImage::upload($this->id, $file['data'], $file['name']);
$result = FileUpload::upload('task', $this->id, $file['data'], $file['name']);
if ($result['success']) {
$uploaded_files[] = $result['file'];
}
@@ -154,24 +154,40 @@ class Task extends BaseEntity {
// Проверка что задача существует
self::check_task($id);
// Удаляем папку с файлами если есть
$upload_dir = __DIR__ . '/../../../public/task/' . $id;
if (is_dir($upload_dir)) {
$files = glob($upload_dir . '/*');
foreach ($files as $file) {
if (is_file($file)) {
unlink($file);
}
// Удаляем папку с файлами задачи
FileUpload::deleteFolder('task', $id);
// Удаляем все комментарии задачи и их файлы
$comments = Database::select('comments', ['id'], ['id_task' => $id]);
if ($comments) {
foreach ($comments as $comment) {
FileUpload::deleteFolder('comment', $comment['id']);
}
rmdir($upload_dir);
Database::delete('comments', ['id_task' => $id]);
}
// Удаляем из базы
// Удаляем задачу из базы
Database::delete('cards_task', ['id' => $id]);
return ['success' => true];
}
// === МЕТОДЫ ДЛЯ РАБОТЫ С ФАЙЛАМИ ===
// Загрузка файла к задаче
public static function uploadFile($task_id, $file_base64, $file_name) {
// Проверка что задача существует
self::check_task($task_id);
return FileUpload::upload('task', $task_id, $file_base64, $file_name);
}
// Удаление файлов задачи
public static function deleteFile($task_id, $file_names) {
// Проверка что задача существует
self::check_task($task_id);
return FileUpload::delete('task', $task_id, $file_names);
}
// Изменение порядка и колонки задачи (с пересчётом order)
public static function updateOrder($id, $column_id, $to_index) {
@@ -251,8 +267,20 @@ class Task extends BaseEntity {
'archive'
], $where);
// Получаем количество комментариев для всех задач одним запросом
$task_ids = array_column($tasks, 'id');
$comments_counts = [];
if (!empty($task_ids)) {
$counts = Database::query(
"SELECT id_task, COUNT(*) as cnt FROM comments WHERE id_task IN (" . implode(',', $task_ids) . ") GROUP BY id_task"
)->fetchAll(\PDO::FETCH_ASSOC);
foreach ($counts as $row) {
$comments_counts[$row['id_task']] = (int)$row['cnt'];
}
}
// Декодируем JSON и получаем avatar_url из accounts
return array_map(function($task) {
return array_map(function($task) use ($comments_counts) {
$task['file_img'] = $task['file_img'] ? json_decode($task['file_img'], true) : [];
// Получаем avatar_url из accounts по id_account
@@ -263,6 +291,9 @@ class Task extends BaseEntity {
$task['avatar_img'] = null;
}
// Количество комментариев
$task['comments_count'] = $comments_counts[$task['id']] ?? 0;
return $task;
}, $tasks);
}