fix(admin): correctly resolve and check assigned modules and admin permissions in user_form

This commit is contained in:
Philipp Urbschat 2026-09-12 23:58:42 +02:00
parent dc4b8e3993
commit 50b4a70045
Signed by: Phili
SSH key fingerprint: SHA256:ZSQWnldzrYiABzOV6vTICPe0h19pTpus7sCbm2S0po0
2 changed files with 71 additions and 17 deletions

View file

@ -5,25 +5,76 @@ class User {
$this->db = new Database(); $this->db = new Database();
} }
public static function parseProjects($projects): array { public static function parseProjects($projects): array {
if (is_array($projects)) { if (empty($projects)) {
$list = $projects;
} elseif (is_string($projects) && !empty($projects)) {
$decoded = json_decode($projects, true);
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
$list = $decoded;
} else {
$list = explode(',', $projects);
}
} else {
return []; 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';
$clean = []; $clean = [];
foreach ($list as $item) { foreach ($projects as $key => $val) {
if (is_string($item)) { $candidates = [];
$val = trim($item, " \t\n\r\0\x0B[]\"'"); if (is_string($key) && !is_numeric($key)) {
if (!empty($val)) { if ($val === true || $val === 1 || $val === '1' || $val === 'on' || $val === 'true' || is_array($val)) {
$clean[] = $val; $candidates[] = $key;
}
} else {
if (is_string($val)) {
$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)) $candidates[] = $sub;
}
}
}
}
foreach ($candidates as $cand) {
$sanitized = trim($cand, " \t\n\r\0\x0B[]\"'/");
if (empty($sanitized)) continue;
$lower = strtolower($sanitized);
$normalized = str_replace([' ', '-', '_'], '', $lower);
if (isset($slugMap[$lower])) {
$clean[] = $slugMap[$lower];
} elseif (isset($slugMap[$normalized])) {
$clean[] = $slugMap[$normalized];
} else {
$clean[] = $sanitized;
} }
} }
} }

View file

@ -2,6 +2,7 @@
<?php <?php
$baseUrl = rtrim(Config::get('BASE_URL', 'https://philippurbschat.de/'), '/'); $baseUrl = rtrim(Config::get('BASE_URL', 'https://philippurbschat.de/'), '/');
$userProjects = User::parseProjects($user['projects'] ?? []); $userProjects = User::parseProjects($user['projects'] ?? []);
$isAdmin = !empty($user['is_admin']);
$modules = $allModules ?? ModuleService::getAll(); $modules = $allModules ?? ModuleService::getAll();
?> ?>
<div class="max-w-4xl w-full mx-auto mt-6 px-4 sm:px-6"> <div class="max-w-4xl w-full mx-auto mt-6 px-4 sm:px-6">
@ -79,7 +80,7 @@ $modules = $allModules ?? ModuleService::getAll();
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-3"> <div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-3">
<?php foreach ($modules as $slug => $mod): <?php foreach ($modules as $slug => $mod):
$isChecked = in_array(strtolower($slug), array_map('strtolower', $userProjects), true); $isChecked = $isAdmin || in_array(strtolower($slug), array_map('strtolower', $userProjects), true);
?> ?>
<label class="flex items-start gap-3 p-3.5 bg-slate-950/70 border border-slate-800 hover:border-emerald-500/50 rounded-xl cursor-pointer transition-all group"> <label class="flex items-start gap-3 p-3.5 bg-slate-950/70 border border-slate-800 hover:border-emerald-500/50 rounded-xl cursor-pointer transition-all group">
<input type="checkbox" name="projects[]" value="<?= htmlspecialchars($slug) ?>" <?= $isChecked ? 'checked' : '' ?> class="module-checkbox mt-1 w-4 h-4 accent-emerald-500"> <input type="checkbox" name="projects[]" value="<?= htmlspecialchars($slug) ?>" <?= $isChecked ? 'checked' : '' ?> class="module-checkbox mt-1 w-4 h-4 accent-emerald-500">
@ -119,7 +120,9 @@ function selectAllModules(check) {
}); });
} }
function toggleAdminNotice(adminCheckbox) { function toggleAdminNotice(adminCheckbox) {
// If admin is checked, all checkboxes are accessible anyway if (adminCheckbox.checked) {
selectAllModules(true);
}
} }
</script> </script>