db = new Database(); } public static function parseProjects($projects): array { if (empty($projects)) { return []; } if (is_string($projects)) { $trimmed = trim($projects); while (is_string($trimmed) && (str_starts_with($trimmed, '[') || str_starts_with($trimmed, '{') || str_starts_with($trimmed, '"'))) { $decoded = json_decode($trimmed, true); if (json_last_error() === JSON_ERROR_NONE && $decoded !== null) { $trimmed = $decoded; } else { break; } } if (is_array($trimmed)) { $projects = $trimmed; } else { $projects = explode(',', (string)$trimmed); } } if (!is_array($projects)) { return []; } $allModules = ModuleService::getAll(); $slugMap = []; foreach ($allModules as $s => $m) { $slugMap[strtolower($s)] = $s; $slugMap[strtolower($m['name'])] = $s; $slugMap[strtolower(str_replace([' ', '-', '_'], '', $m['name']))] = $s; $slugMap[strtolower(ltrim($m['path'], '/'))] = $s; } $slugMap['web audio synth'] = 'test'; $slugMap['webaudiosynth'] = 'test'; $slugMap['synth'] = 'test'; $slugMap['geschichtenmaschine'] = 'storymachine'; $slugMap['geschichten-maschine'] = 'storymachine'; $slugMap['pflanzen'] = 'plants'; $slugMap['pflanzentracker'] = 'plants'; $ignore = ['on', 'off', 'true', 'false', '1', '0', 'null', 'undefined']; $clean = []; foreach ($projects as $key => $val) { $candidates = []; if (is_string($key) && !is_numeric($key)) { $candidates[] = $key; if (is_string($val) && !in_array(strtolower(trim($val)), $ignore, true)) { $candidates[] = $val; } } else { if (is_string($val) && !in_array(strtolower(trim($val)), $ignore, true)) { $candidates[] = $val; } elseif (is_array($val)) { if (!empty($val['slug'])) $candidates[] = $val['slug']; elseif (!empty($val['name'])) $candidates[] = $val['name']; elseif (!empty($val['id'])) $candidates[] = $val['id']; elseif (!empty($val['project'])) $candidates[] = $val['project']; else { foreach ($val as $sub) { if (is_string($sub) && !in_array(strtolower(trim($sub)), $ignore, true)) { $candidates[] = $sub; } } } } } foreach ($candidates as $cand) { $candSan = trim($cand, " \t\n\r\0\x0B[]\"'/"); if (empty($candSan)) continue; // Check if candidate contains colon or equals, e.g. "plants:plants" or "storymachine:geschichtenmaschine" $subParts = preg_split('/[:=]/', $candSan); $matched = false; foreach ($subParts as $part) { $pSan = trim($part, " \t\n\r\0\x0B[]\"'/"); if (empty($pSan)) continue; $pLower = strtolower($pSan); $pNorm = str_replace([' ', '-', '_'], '', $pLower); if (isset($slugMap[$pLower])) { $clean[] = $slugMap[$pLower]; $matched = true; break; } elseif (isset($slugMap[$pNorm])) { $clean[] = $slugMap[$pNorm]; $matched = true; break; } } if (!$matched) { $lower = strtolower($candSan); $normalized = str_replace([' ', '-', '_'], '', $lower); if (isset($slugMap[$lower])) { $clean[] = $slugMap[$lower]; } elseif (isset($slugMap[$normalized])) { $clean[] = $slugMap[$normalized]; } elseif (isset($allModules[$lower])) { $clean[] = $lower; } } } } return array_values(array_unique($clean)); } // Auth-Logic public function authenticate($email, $password) { $this->db->query("SELECT * FROM home_users WHERE email = :email AND status = 'Active'"); $this->db->bind(':email', $email); $user = $this->db->single(); if ($user && password_verify($password, $user['password'])) { $user['projects'] = self::parseProjects($user['projects'] ?? []); if (in_array(strtolower($user['email']), ['philipp.urbschat@gmail.com', 'hi@philippurbschat.de'])) { $user['is_admin'] = true; } else { $user['is_admin'] = (bool)$user['is_admin']; } return $user; } return false; } // Data-Retrieval public function getAll() { $this->db->query("SELECT id, name, email, is_admin, status, projects FROM home_users ORDER BY id DESC"); $users = $this->db->resultSet(); foreach ($users as &$user) { $user['projects'] = self::parseProjects($user['projects'] ?? []); } return $users; } public function getById($id) { $this->db->query("SELECT * FROM home_users WHERE id = :id"); $this->db->bind(':id', $id); $user = $this->db->single(); if ($user) { $user['projects'] = self::parseProjects($user['projects'] ?? []); } return $user; } // Persistence public function save($data, $id = null) { $projectsList = self::parseProjects($data['projects'] ?? []); $projectsJson = json_encode($projectsList); if ($id) { $sql = "UPDATE home_users SET name = :name, email = :email, projects = :projects, is_admin = :is_admin, status = :status "; if (!empty($data['password'])) { $sql .= ", password = :password "; } $sql .= "WHERE id = :id"; $this->db->query($sql); $this->db->bind(':id', $id); } else { $sql = "INSERT INTO home_users (name, email, password, projects, is_admin, status) VALUES (:name, :email, :password, :projects, :is_admin, :status)"; $this->db->query($sql); } $this->db->bind(':name', $data['name']); $this->db->bind(':email', $data['email']); $this->db->bind(':projects', $projectsJson); $this->db->bind(':is_admin', !empty($data['is_admin']) ? 1 : 0); $this->db->bind(':status', $data['status']); if (!$id || !empty($data['password'])) { $this->db->bind(':password', password_hash($data['password'], PASSWORD_DEFAULT)); } return $this->db->execute(); } public function delete($id) { $this->db->query("DELETE FROM home_users WHERE id = :id"); $this->db->bind(':id', $id); return $this->db->execute(); } public function findByEmail(string $email): ?array { $this->db->query("SELECT * FROM home_users WHERE LOWER(email) = LOWER(:email)"); $this->db->bind(':email', trim($email)); $user = $this->db->single(); if ($user) { $user['projects'] = self::parseProjects($user['projects'] ?? []); } return $user ?: null; } public function updatePassword(int $id, string $newPasswordHash): bool { $this->db->query("UPDATE home_users SET password = :password WHERE id = :id"); $this->db->bind(':password', $newPasswordHash); $this->db->bind(':id', $id); return $this->db->execute(); } }