true, // создание задач 'edit_task' => false, // редактирование любых задач 'edit_own_task_only' => true, // редактирование только назначенных на себя 'delete_task' => false, // удаление задач 'move_task' => false, // перемещение любых задач между колонками 'move_own_task_only' => true, // перемещение только назначенных на себя 'archive_task' => true, // архивирование задач 'create_column' => false, // создание колонок 'edit_column' => false, // редактирование колонок 'delete_column' => false, // удаление колонок 'manage_departments' => false, // управление отделами 'remove_members' => false, // удаление участников 'create_comment' => false, // создание комментариев в любых задачах 'create_comment_own_task_only' => true, // создание комментариев только в назначенных на себя 'delete_own_comments' => true, // удаление своих комментариев 'delete_all_comments' => false, // удаление любых комментариев 'upload_files' => true, // загрузка файлов 'upload_images' => true // загрузка картинок ]; // ==================== ПРОВЕРКИ ДОСТУПА ==================== // Проверить, является ли пользователь владельцем проекта (в id_admin таблицы projects) public static function isOwner(int $project_id, int $user_id): bool { $project = Database::get('project', ['id_admin'], ['id' => $project_id]); if (!$project || !$project['id_admin']) { return false; } $owners = json_decode($project['id_admin'], true); return is_array($owners) && in_array($user_id, $owners); } // Проверить, является ли пользователь участником проекта public static function isMember(int $project_id, int $user_id): bool { // Владелец всегда имеет доступ if (self::isOwner($project_id, $user_id)) { return true; } return Database::has('project_members', [ 'id_project' => $project_id, 'id_user' => $user_id ]); } // Проверить, является ли пользователь админом проекта public static function isAdmin(int $project_id, int $user_id): bool { // Владелец = безоговорочный админ if (self::isOwner($project_id, $user_id)) { return true; } return Database::has('project_members', [ 'id_project' => $project_id, 'id_user' => $user_id, 'is_admin' => 1 ]); } // Проверить конкретное право (владелец/админ имеет все права) public static function can(int $project_id, int $user_id, string $permission): bool { // Владелец может всё if (self::isOwner($project_id, $user_id)) { return true; } $member = Database::get('project_members', ['is_admin', 'permissions'], [ 'id_project' => $project_id, 'id_user' => $user_id ]); if (!$member) { return false; } // Админ может всё if ((int)$member['is_admin'] === 1) { return true; } $permissions = $member['permissions'] ? json_decode($member['permissions'], true) : []; return isset($permissions[$permission]) && $permissions[$permission] === true; } // Проверить право на редактирование задачи (с учётом edit_own_task_only) // "Своя задача" = назначен на пользователя ИЛИ создана пользователем public static function canEditTask(int $project_id, int $user_id, ?int $task_assignee_id, ?int $task_creator_id = null): bool { if (self::isAdmin($project_id, $user_id)) { return true; } if (self::can($project_id, $user_id, 'edit_task')) { return true; } // Создатель + право создания → может редактировать свои созданные if ($task_creator_id === $user_id && self::can($project_id, $user_id, 'create_task')) { return true; } // Назначена на себя + право edit_own_task_only if ($task_assignee_id === $user_id && self::can($project_id, $user_id, 'edit_own_task_only')) { return true; } return false; } // Проверить право на перемещение задачи (с учётом move_own_task_only) // "Своя задача" = назначен на пользователя ИЛИ создана пользователем public static function canMoveTask(int $project_id, int $user_id, ?int $task_assignee_id, ?int $task_creator_id = null): bool { if (self::isAdmin($project_id, $user_id)) { return true; } if (self::can($project_id, $user_id, 'move_task')) { return true; } // Создатель + право создания → может перемещать свои созданные if ($task_creator_id === $user_id && self::can($project_id, $user_id, 'create_task')) { return true; } // Назначена на себя + право move_own_task_only if ($task_assignee_id === $user_id && self::can($project_id, $user_id, 'move_own_task_only')) { return true; } return false; } // Проверить право на создание комментария в задаче public static function canCreateComment(int $project_id, int $user_id, ?int $task_assignee_id, ?int $task_creator_id = null): bool { if (self::isAdmin($project_id, $user_id)) { return true; } // Полное право — комментировать любые задачи if (self::can($project_id, $user_id, 'create_comment')) { return true; } // Создатель + право создания → может комментировать свои созданные if ($task_creator_id === $user_id && self::can($project_id, $user_id, 'create_task')) { return true; } // Назначена на себя + право create_comment_own_task_only if ($task_assignee_id === $user_id && self::can($project_id, $user_id, 'create_comment_own_task_only')) { return true; } return false; } // ==================== ПРОВЕРКИ С EXIT ==================== // Требовать доступ к проекту (при отказе — 403 и exit) public static function requireAccess(int $project_id, ?int $user_id): void { if (!$user_id) { RestApi::response(['success' => false, 'errors' => ['auth' => 'Требуется авторизация']], 401); } if (!self::isMember($project_id, $user_id)) { RestApi::response(['success' => false, 'errors' => ['access' => 'Нет доступа к проекту']], 403); } } // Требовать права админа public static function requireAdmin(int $project_id, ?int $user_id): void { if (!$user_id) { RestApi::response(['success' => false, 'errors' => ['auth' => 'Требуется авторизация']], 401); } if (!self::isAdmin($project_id, $user_id)) { RestApi::response(['success' => false, 'errors' => ['access' => 'Требуются права администратора']], 403); } } // Требовать конкретное право public static function requirePermission(int $project_id, ?int $user_id, string $permission): void { if (!$user_id) { RestApi::response(['success' => false, 'errors' => ['auth' => 'Требуется авторизация']], 401); } if (!self::can($project_id, $user_id, $permission)) { RestApi::response(['success' => false, 'errors' => ['access' => 'Недостаточно прав']], 403); } } // Требовать право на редактирование задачи public static function requireEditTask(int $project_id, ?int $user_id, ?int $task_assignee_id, ?int $task_creator_id = null): void { if (!$user_id) { RestApi::response(['success' => false, 'errors' => ['auth' => 'Требуется авторизация']], 401); } if (!self::canEditTask($project_id, $user_id, $task_assignee_id, $task_creator_id)) { RestApi::response(['success' => false, 'errors' => ['access' => 'Нет прав на редактирование задачи']], 403); } } // Требовать право на перемещение задачи public static function requireMoveTask(int $project_id, ?int $user_id, ?int $task_assignee_id, ?int $task_creator_id = null): void { if (!$user_id) { RestApi::response(['success' => false, 'errors' => ['auth' => 'Требуется авторизация']], 401); } if (!self::canMoveTask($project_id, $user_id, $task_assignee_id, $task_creator_id)) { RestApi::response(['success' => false, 'errors' => ['access' => 'Нет прав на перемещение задачи']], 403); } } // ==================== УПРАВЛЕНИЕ УЧАСТНИКАМИ ==================== // Добавить участника в проект public static function addMember(int $project_id, int $user_id, int $current_user_id, bool $is_admin = false, ?array $permissions = null): array { // Нельзя пригласить себя if ($user_id === $current_user_id) { return ['success' => false, 'errors' => ['member' => 'Нельзя пригласить себя в проект']]; } if (self::isMember($project_id, $user_id)) { return ['success' => false, 'errors' => ['member' => 'Пользователь уже участник проекта']]; } $perms = $permissions ?? self::DEFAULT_PERMISSIONS; Database::insert('project_members', [ 'id_project' => $project_id, 'id_user' => $user_id, 'is_admin' => $is_admin ? 1 : 0, 'permissions' => json_encode($perms), 'created_at' => date('Y-m-d H:i:s') ]); return ['success' => true, 'id' => Database::id()]; } // Удалить участника из проекта (владельца удалить нельзя, админ не может удалить себя) public static function removeMember(int $project_id, int $user_id, int $current_user_id): array { // Владельца удалить нельзя if (self::isOwner($project_id, $user_id)) { return ['success' => false, 'errors' => ['member' => 'Нельзя удалить владельца проекта']]; } $member = Database::get('project_members', ['is_admin'], [ 'id_project' => $project_id, 'id_user' => $user_id ]); if (!$member) { return ['success' => false, 'errors' => ['member' => 'Участник не найден']]; } // Админ может выйти сам, если есть другие админы или владелец // (владелец всегда есть в id_admin проекта, так что это безопасно) Database::delete('project_members', [ 'id_project' => $project_id, 'id_user' => $user_id ]); return ['success' => true]; } // Получить всех участников проекта (включая владельцев из id_admin) public static function getMembers(int $project_id): array { $result = []; $addedUserIds = []; // Получаем владельцев из id_admin проекта $project = Database::get('project', ['id_admin'], ['id' => $project_id]); if ($project && $project['id_admin']) { $ownerIds = json_decode($project['id_admin'], true); if (is_array($ownerIds) && count($ownerIds) > 0) { $owners = Database::select('accounts', ['id', 'name', 'username', 'avatar_url', 'telegram'], ['id' => $ownerIds]); foreach ($owners as $owner) { $result[] = [ 'id' => null, 'id_user' => (int)$owner['id'], 'is_admin' => true, 'is_owner' => true, 'permissions' => [], 'created_at' => null, 'name' => $owner['name'], 'username' => $owner['username'], 'avatar_url' => $owner['avatar_url'], 'telegram' => $owner['telegram'] ]; $addedUserIds[] = (int)$owner['id']; } } } // Получаем участников из project_members $members = Database::select('project_members', [ '[>]accounts' => ['id_user' => 'id'] ], [ 'project_members.id', 'project_members.id_user', 'project_members.is_admin', 'project_members.permissions', 'project_members.created_at', 'accounts.name', 'accounts.username', 'accounts.avatar_url', 'accounts.telegram' ], [ 'project_members.id_project' => $project_id ]); foreach ($members as $member) { $userId = (int)$member['id_user']; // Пропускаем если уже добавлен как владелец if (in_array($userId, $addedUserIds)) { continue; } $result[] = [ 'id' => $member['id'], 'id_user' => $userId, 'is_admin' => (int)$member['is_admin'] === 1, 'is_owner' => false, 'permissions' => $member['permissions'] ? json_decode($member['permissions'], true) : [], 'created_at' => $member['created_at'], 'name' => $member['name'], 'username' => $member['username'], 'avatar_url' => $member['avatar_url'], 'telegram' => $member['telegram'] ]; } return $result; } // Получить ID всех проектов пользователя (включая где он владелец) public static function getUserProjectIds(int $user_id): array { $projectIds = []; // Проекты из project_members $rows = Database::select('project_members', ['id_project'], [ 'id_user' => $user_id ]); foreach ($rows as $row) { $projectIds[] = (int)$row['id_project']; } // Проекты где пользователь в id_admin $allProjects = Database::select('project', ['id', 'id_admin']); foreach ($allProjects as $project) { if ($project['id_admin']) { $owners = json_decode($project['id_admin'], true); if (is_array($owners) && in_array($user_id, $owners)) { $pid = (int)$project['id']; if (!in_array($pid, $projectIds)) { $projectIds[] = $pid; } } } } return $projectIds; } // ==================== УПРАВЛЕНИЕ ПРАВАМИ ==================== // Установить конкретное право public static function setPermission(int $project_id, int $user_id, string $permission, bool $value, int $current_user_id): array { // Нельзя редактировать свои права if ($user_id === $current_user_id) { return ['success' => false, 'errors' => ['member' => 'Нельзя изменять свои права']]; } if (!in_array($permission, self::PERMISSIONS)) { return ['success' => false, 'errors' => ['permission' => 'Неизвестное право: ' . $permission]]; } $member = Database::get('project_members', ['permissions'], [ 'id_project' => $project_id, 'id_user' => $user_id ]); if (!$member) { return ['success' => false, 'errors' => ['member' => 'Участник не найден']]; } $permissions = $member['permissions'] ? json_decode($member['permissions'], true) : []; $permissions[$permission] = $value; Database::update('project_members', [ 'permissions' => json_encode($permissions) ], [ 'id_project' => $project_id, 'id_user' => $user_id ]); return ['success' => true, 'permissions' => $permissions]; } // Установить несколько прав сразу public static function setPermissions(int $project_id, int $user_id, array $permissions, int $current_user_id): array { // Нельзя редактировать свои права if ($user_id === $current_user_id) { return ['success' => false, 'errors' => ['member' => 'Нельзя изменять свои права']]; } // Нельзя редактировать права владельца if (self::isOwner($project_id, $user_id)) { return ['success' => false, 'errors' => ['member' => 'Нельзя изменять права владельца проекта']]; } foreach (array_keys($permissions) as $perm) { if (!in_array($perm, self::PERMISSIONS)) { return ['success' => false, 'errors' => ['permission' => 'Неизвестное право: ' . $perm]]; } } $member = Database::get('project_members', ['permissions'], [ 'id_project' => $project_id, 'id_user' => $user_id ]); if (!$member) { return ['success' => false, 'errors' => ['member' => 'Участник не найден']]; } $currentPerms = $member['permissions'] ? json_decode($member['permissions'], true) : []; $mergedPerms = array_merge($currentPerms, $permissions); Database::update('project_members', [ 'permissions' => json_encode($mergedPerms) ], [ 'id_project' => $project_id, 'id_user' => $user_id ]); return ['success' => true, 'permissions' => $mergedPerms]; } // Получить права участника public static function getPermissions(int $project_id, int $user_id): ?array { // Владелец имеет все права if (self::isOwner($project_id, $user_id)) { $allPerms = []; foreach (self::PERMISSIONS as $perm) { $allPerms[$perm] = true; } return $allPerms; } $member = Database::get('project_members', ['is_admin', 'permissions'], [ 'id_project' => $project_id, 'id_user' => $user_id ]); if (!$member) { return null; } // Админ имеет все права if ((int)$member['is_admin'] === 1) { $allPerms = []; foreach (self::PERMISSIONS as $perm) { $allPerms[$perm] = true; } return $allPerms; } return $member['permissions'] ? json_decode($member['permissions'], true) : []; } // Назначить/снять админа public static function setAdmin(int $project_id, int $user_id, bool $is_admin, int $current_user_id): array { // Нельзя редактировать свои права if ($user_id === $current_user_id) { return ['success' => false, 'errors' => ['member' => 'Нельзя изменять свои права']]; } // Нельзя изменять статус владельца if (self::isOwner($project_id, $user_id)) { return ['success' => false, 'errors' => ['member' => 'Нельзя изменять статус владельца проекта']]; } $member = Database::get('project_members', ['id'], [ 'id_project' => $project_id, 'id_user' => $user_id ]); if (!$member) { return ['success' => false, 'errors' => ['member' => 'Участник не найден']]; } Database::update('project_members', [ 'is_admin' => $is_admin ? 1 : 0 ], [ 'id_project' => $project_id, 'id_user' => $user_id ]); return ['success' => true]; } // Получить список всех доступных прав (для UI) public static function getAvailablePermissions(): array { return self::PERMISSIONS; } // Получить дефолтные права (для UI) public static function getDefaultPermissions(): array { return self::DEFAULT_PERMISSIONS; } } ?>