1
0
Files
TaskBoard/backend/app/class/enity/class_comment.php
Falknat 3bfa1e9e1b Комментарии, файлы и права проекта
- Система комментариев к задачам с вложенными ответами
- Редактирование и удаление комментариев
- Прикрепление файлов к задачам и комментариям (картинки, архивы до 10 МБ)
- Система прав проекта: админ проекта может удалять чужие комментарии и файлы
- Универсальный класс FileUpload для загрузки файлов
- Защита загрузки: только автор комментария может добавлять файлы
- Каскадное удаление: задача → комментарии → файлы
- Автообновление комментариев в реальном времени
2026-01-15 06:40:47 +07:00

247 lines
9.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
class Comment extends BaseEntity {
protected $db_name = 'comments';
// Свойства комментария
public $id;
public $id_task;
public $id_accounts;
public $id_answer; // ID родительского комментария (ответ на)
public $text;
public $date_create;
// Создание комментария
public function create() {
static::$error_message = [];
// Валидация
if (!$this->id_task) {
$this->addError('id_task', 'Задача не указана');
}
if (!$this->id_accounts) {
$this->addError('id_accounts', 'Пользователь не указан');
}
if (!$this->text || trim($this->text) === '') {
$this->addError('text', 'Текст комментария не может быть пустым');
}
if ($errors = $this->getErrors()) {
return $errors;
}
// Проверяем что задача существует
Task::check_task($this->id_task);
// Если это ответ — проверяем что родительский комментарий существует
if ($this->id_answer) {
self::checkComment($this->id_answer);
}
// Вставляем в базу
Database::insert($this->db_name, [
'id_task' => $this->id_task,
'id_accounts' => $this->id_accounts,
'id_answer' => $this->id_answer ?: null,
'text' => $this->text,
'date_create' => date('Y-m-d H:i:s'),
'file_img' => '[]'
]);
$this->id = Database::id();
// Возвращаем созданный комментарий с данными пользователя
return [
'success' => true,
'comment' => $this->getById($this->id)
];
}
// Обновление комментария
public function update() {
static::$error_message = [];
// Валидация
if (!$this->id) {
$this->addError('id', 'ID комментария не указан');
}
if (!$this->text || trim($this->text) === '') {
$this->addError('text', 'Текст комментария не может быть пустым');
}
if ($errors = $this->getErrors()) {
return $errors;
}
// Проверяем что комментарий существует
$comment = self::checkComment($this->id);
// Проверяем что пользователь — автор комментария
if ((int)$comment['id_accounts'] !== (int)$this->id_accounts) {
$this->addError('access', 'Вы можете редактировать только свои комментарии');
return $this->getErrors();
}
// Обновляем в БД
Database::update($this->db_name, [
'text' => $this->text
], [
'id' => $this->id
]);
return [
'success' => true,
'comment' => $this->getById($this->id)
];
}
// Удаление комментария (с дочерними)
public static function delete($id, $id_accounts) {
// Проверяем что комментарий существует
$comment = self::checkComment($id);
// Получаем задачу для проверки админа проекта
$task = Database::get('cards_task', ['id_project'], ['id' => $comment['id_task']]);
// Проверяем права: автор комментария ИЛИ админ проекта
$isAuthor = (int)$comment['id_accounts'] === (int)$id_accounts;
$isProjectAdmin = $task && Project::isAdmin($task['id_project'], $id_accounts);
if (!$isAuthor && !$isProjectAdmin) {
RestApi::response([
'success' => false,
'errors' => ['access' => 'Нет прав на удаление комментария']
], 403);
}
// Рекурсивно удаляем все дочерние комментарии
self::deleteWithChildren($id);
return ['success' => true];
}
// Рекурсивное удаление комментария и всех его дочерних
private static function deleteWithChildren($id) {
// Находим все дочерние комментарии
$children = Database::select('comments', ['id'], ['id_answer' => $id]);
// Рекурсивно удаляем дочерние
if ($children) {
foreach ($children as $child) {
self::deleteWithChildren($child['id']);
}
}
// Удаляем папку с файлами комментария
FileUpload::deleteFolder('comment', $id);
// Удаляем сам комментарий
Database::delete('comments', ['id' => $id]);
}
// === МЕТОДЫ ДЛЯ РАБОТЫ С ФАЙЛАМИ ===
// Загрузка файла к комментарию (только автор может загружать)
public static function uploadFile($comment_id, $file_base64, $file_name, $user_id) {
// Проверка что комментарий существует
$comment = self::checkComment($comment_id);
// Проверка что пользователь — автор комментария
if ((int)$comment['id_accounts'] !== (int)$user_id) {
RestApi::response([
'success' => false,
'errors' => ['access' => 'Вы можете загружать файлы только к своим комментариям']
], 403);
}
return FileUpload::upload('comment', $comment_id, $file_base64, $file_name);
}
// Удаление файлов комментария (автор или админ проекта)
public static function deleteFile($comment_id, $file_names, $user_id) {
// Проверка что комментарий существует
$comment = self::checkComment($comment_id);
// Получаем задачу для проверки админа проекта
$task = Database::get('cards_task', ['id_project'], ['id' => $comment['id_task']]);
// Проверка прав: автор комментария ИЛИ админ проекта
$isAuthor = (int)$comment['id_accounts'] === (int)$user_id;
$isProjectAdmin = $task && Project::isAdmin($task['id_project'], $user_id);
if (!$isAuthor && !$isProjectAdmin) {
RestApi::response([
'success' => false,
'errors' => ['access' => 'Нет прав на удаление файлов']
], 403);
}
return FileUpload::delete('comment', $comment_id, $file_names);
}
// Получение комментария по ID (с данными пользователя)
public function getById($id) {
$comment = Database::get($this->db_name, [
'[>]accounts' => ['id_accounts' => 'id']
], [
'comments.id',
'comments.id_task',
'comments.id_accounts',
'comments.id_answer',
'comments.text',
'comments.date_create',
'comments.file_img',
'accounts.name(author_name)',
'accounts.avatar_url(author_avatar)'
], [
'comments.id' => $id
]);
// Декодируем JSON файлов
if ($comment) {
$comment['file_img'] = $comment['file_img'] ? json_decode($comment['file_img'], true) : [];
}
return $comment;
}
// Получение всех комментариев задачи
public function getByTask($id_task) {
// Проверяем что задача существует
Task::check_task($id_task);
$comments = Database::select($this->db_name, [
'[>]accounts' => ['id_accounts' => 'id']
], [
'comments.id',
'comments.id_task',
'comments.id_accounts',
'comments.id_answer',
'comments.text',
'comments.date_create',
'comments.file_img',
'accounts.name(author_name)',
'accounts.avatar_url(author_avatar)'
], [
'comments.id_task' => $id_task,
'ORDER' => ['comments.date_create' => 'ASC']
]);
// Декодируем JSON файлов для каждого комментария
return array_map(function($comment) {
$comment['file_img'] = $comment['file_img'] ? json_decode($comment['file_img'], true) : [];
return $comment;
}, $comments ?: []);
}
// Проверка и получение комментария (при ошибке — сразу ответ и exit)
public static function checkComment($id) {
$comment = Database::get('comments', '*', ['id' => $id]);
if (!$id || !$comment) {
RestApi::response(['success' => false, 'errors' => ['comment' => 'Комментарий не найден']], 404);
}
return $comment;
}
}
?>