false, 'errors' => ['invite' => 'Нельзя пригласить себя в проект']]; } // Проверяем, что пользователь существует $user = Database::get('accounts', ['id'], ['id' => $to_user_id]); if (!$user) { return ['success' => false, 'errors' => ['invite' => 'Пользователь не найден']]; } // Проверяем, что пользователь ещё не участник проекта if (ProjectAccess::isMember($project_id, $to_user_id)) { return ['success' => false, 'errors' => ['invite' => 'Пользователь уже участник проекта']]; } // Проверяем, нет ли уже pending-приглашения if (self::hasPending($project_id, $to_user_id)) { return ['success' => false, 'errors' => ['invite' => 'Пользователь уже приглашён, ожидается ответ']]; } // Права по умолчанию $perms = $permissions ?? ProjectAccess::DEFAULT_PERMISSIONS; // Сохраняем is_admin в permissions для передачи при accept $inviteData = [ 'is_admin' => $is_admin, 'permissions' => $perms ]; Database::insert('project_invites', [ 'id_project' => $project_id, 'id_from_user' => $from_user_id, 'id_to_user' => $to_user_id, 'status' => self::STATUS_PENDING, 'permissions' => json_encode($inviteData), 'created_at' => date('Y-m-d H:i:s') ]); return ['success' => true, 'id' => Database::id()]; } // ==================== ПРОВЕРКИ ==================== /** * Есть ли pending-приглашение для пользователя в проект */ public static function hasPending(int $project_id, int $to_user_id): bool { return Database::has('project_invites', [ 'id_project' => $project_id, 'id_to_user' => $to_user_id, 'status' => self::STATUS_PENDING ]); } /** * Получить количество pending-приглашений для пользователя */ public static function getPendingCount(int $user_id): int { return Database::count('project_invites', [ 'id_to_user' => $user_id, 'status' => self::STATUS_PENDING ]); } // ==================== ПОЛУЧЕНИЕ ПРИГЛАШЕНИЙ ==================== /** * Получить все pending-приглашения для пользователя (входящие) */ public static function getMyPending(int $user_id): array { $invites = Database::select('project_invites', [ '[>]project' => ['id_project' => 'id'], '[>]accounts' => ['id_from_user' => 'id'] ], [ 'project_invites.id', 'project_invites.id_project', 'project_invites.created_at', 'project_invites.permissions', 'project.name(project_name)', 'accounts.name(from_user_name)', 'accounts.username(from_user_username)', 'accounts.avatar_url(from_user_avatar)' ], [ 'project_invites.id_to_user' => $user_id, 'project_invites.status' => self::STATUS_PENDING, 'ORDER' => ['project_invites.created_at' => 'DESC'] ]); return array_map(function($invite) { $permData = $invite['permissions'] ? json_decode($invite['permissions'], true) : []; return [ 'id' => (int)$invite['id'], 'project_id' => (int)$invite['id_project'], 'project_name' => $invite['project_name'], 'from_user' => [ 'name' => $invite['from_user_name'], 'username' => $invite['from_user_username'], 'avatar_url' => $invite['from_user_avatar'] ], 'is_admin' => $permData['is_admin'] ?? false, 'created_at' => $invite['created_at'] ]; }, $invites); } /** * Получить pending-приглашения для проекта (для админа) */ public static function getProjectPending(int $project_id): array { $invites = Database::select('project_invites', [ '[>]accounts' => ['id_to_user' => 'id'] ], [ 'project_invites.id', 'project_invites.id_to_user', 'project_invites.created_at', 'project_invites.permissions', 'accounts.name', 'accounts.username', 'accounts.avatar_url' ], [ 'project_invites.id_project' => $project_id, 'project_invites.status' => self::STATUS_PENDING, 'ORDER' => ['project_invites.created_at' => 'DESC'] ]); return array_map(function($invite) { $permData = $invite['permissions'] ? json_decode($invite['permissions'], true) : []; return [ 'id' => (int)$invite['id'], 'id_user' => (int)$invite['id_to_user'], 'name' => $invite['name'], 'username' => $invite['username'], 'avatar_url' => $invite['avatar_url'], 'is_admin' => $permData['is_admin'] ?? false, 'created_at' => $invite['created_at'], 'status' => 'pending' ]; }, $invites); } // ==================== ОТВЕТ НА ПРИГЛАШЕНИЕ ==================== /** * Принять приглашение */ public static function accept(int $invite_id, int $user_id): array { $invite = Database::get('project_invites', '*', [ 'id' => $invite_id, 'id_to_user' => $user_id, 'status' => self::STATUS_PENDING ]); if (!$invite) { return ['success' => false, 'errors' => ['invite' => 'Приглашение не найдено или уже обработано']]; } $project_id = (int)$invite['id_project']; $permData = $invite['permissions'] ? json_decode($invite['permissions'], true) : []; $is_admin = $permData['is_admin'] ?? false; $permissions = $permData['permissions'] ?? ProjectAccess::DEFAULT_PERMISSIONS; // Добавляем в project_members Database::insert('project_members', [ 'id_project' => $project_id, 'id_user' => $user_id, 'is_admin' => $is_admin ? 1 : 0, 'permissions' => json_encode($permissions), 'created_at' => date('Y-m-d H:i:s') ]); // Обновляем статус приглашения Database::update('project_invites', [ 'status' => self::STATUS_ACCEPTED, 'responded_at' => date('Y-m-d H:i:s') ], ['id' => $invite_id]); return ['success' => true, 'project_id' => $project_id]; } /** * Отклонить приглашение */ public static function decline(int $invite_id, int $user_id): array { $invite = Database::get('project_invites', ['id'], [ 'id' => $invite_id, 'id_to_user' => $user_id, 'status' => self::STATUS_PENDING ]); if (!$invite) { return ['success' => false, 'errors' => ['invite' => 'Приглашение не найдено или уже обработано']]; } Database::update('project_invites', [ 'status' => self::STATUS_DECLINED, 'responded_at' => date('Y-m-d H:i:s') ], ['id' => $invite_id]); return ['success' => true]; } /** * Отменить приглашение (для админа) */ public static function cancel(int $invite_id, int $project_id): array { $invite = Database::get('project_invites', ['id'], [ 'id' => $invite_id, 'id_project' => $project_id, 'status' => self::STATUS_PENDING ]); if (!$invite) { return ['success' => false, 'errors' => ['invite' => 'Приглашение не найдено']]; } Database::delete('project_invites', ['id' => $invite_id]); return ['success' => true]; } } ?>