fix(admin): correctly parse and preselect assigned modules in user edit form

This commit is contained in:
Philipp Urbschat 2026-09-12 23:51:44 +02:00
parent 98cf8e6fda
commit dc4b8e3993
Signed by: Phili
SSH key fingerprint: SHA256:ZSQWnldzrYiABzOV6vTICPe0h19pTpus7sCbm2S0po0
3 changed files with 34 additions and 13 deletions

View file

@ -109,7 +109,7 @@ class RegisterController extends Controller {
'name' => $name, 'name' => $name,
'email' => $email, 'email' => $email,
'password' => $password, 'password' => $password,
'projects' => implode(',', $invitation['assigned_projects'] ?? []), 'projects' => $invitation['assigned_projects'] ?? [],
'is_admin' => 0, 'is_admin' => 0,
'status' => 'Active' 'status' => 'Active'
]; ];

View file

@ -4,13 +4,39 @@ class User {
public function __construct() { public function __construct() {
$this->db = new Database(); $this->db = new Database();
} }
public static function parseProjects($projects): array {
if (is_array($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 [];
}
$clean = [];
foreach ($list as $item) {
if (is_string($item)) {
$val = trim($item, " \t\n\r\0\x0B[]\"'");
if (!empty($val)) {
$clean[] = $val;
}
}
}
return array_values(array_unique($clean));
}
// Auth-Logic // Auth-Logic
public function authenticate($email, $password) { public function authenticate($email, $password) {
$this->db->query("SELECT * FROM home_users WHERE email = :email AND status = 'Active'"); $this->db->query("SELECT * FROM home_users WHERE email = :email AND status = 'Active'");
$this->db->bind(':email', $email); $this->db->bind(':email', $email);
$user = $this->db->single(); $user = $this->db->single();
if ($user && password_verify($password, $user['password'])) { if ($user && password_verify($password, $user['password'])) {
$user['projects'] = json_decode($user['projects'], true) ?? []; $user['projects'] = self::parseProjects($user['projects'] ?? []);
if (in_array(strtolower($user['email']), ['philipp.urbschat@gmail.com', 'hi@philippurbschat.de'])) { if (in_array(strtolower($user['email']), ['philipp.urbschat@gmail.com', 'hi@philippurbschat.de'])) {
$user['is_admin'] = true; $user['is_admin'] = true;
} else { } else {
@ -25,7 +51,7 @@ class User {
$this->db->query("SELECT id, name, email, is_admin, status, projects FROM home_users ORDER BY id DESC"); $this->db->query("SELECT id, name, email, is_admin, status, projects FROM home_users ORDER BY id DESC");
$users = $this->db->resultSet(); $users = $this->db->resultSet();
foreach ($users as &$user) { foreach ($users as &$user) {
$user['projects'] = json_decode($user['projects'], true) ?? []; $user['projects'] = self::parseProjects($user['projects'] ?? []);
} }
return $users; return $users;
} }
@ -34,18 +60,13 @@ class User {
$this->db->bind(':id', $id); $this->db->bind(':id', $id);
$user = $this->db->single(); $user = $this->db->single();
if ($user) { if ($user) {
$user['projects'] = json_decode($user['projects'], true) ?? []; $user['projects'] = self::parseProjects($user['projects'] ?? []);
} }
return $user; return $user;
} }
// Persistence // Persistence
public function save($data, $id = null) { public function save($data, $id = null) {
if (is_array($data['projects'] ?? null)) { $projectsList = self::parseProjects($data['projects'] ?? []);
$projectsList = array_values(array_filter($data['projects']));
} else {
$projectsStr = $data['projects'] ?? '';
$projectsList = !empty($projectsStr) ? array_values(array_filter(array_map('trim', explode(',', $projectsStr)))) : [];
}
$projectsJson = json_encode($projectsList); $projectsJson = json_encode($projectsList);
if ($id) { if ($id) {
$sql = "UPDATE home_users SET name = :name, email = :email, projects = :projects, is_admin = :is_admin, status = :status "; $sql = "UPDATE home_users SET name = :name, email = :email, projects = :projects, is_admin = :is_admin, status = :status ";
@ -80,7 +101,7 @@ class User {
$this->db->bind(':email', trim($email)); $this->db->bind(':email', trim($email));
$user = $this->db->single(); $user = $this->db->single();
if ($user) { if ($user) {
$user['projects'] = json_decode($user['projects'], true) ?? []; $user['projects'] = self::parseProjects($user['projects'] ?? []);
} }
return $user ?: null; return $user ?: null;
} }

View file

@ -1,7 +1,7 @@
<?php require_once __DIR__ . '/../inc/admin_header.php'; ?> <?php require_once __DIR__ . '/../inc/admin_header.php'; ?>
<?php <?php
$baseUrl = rtrim(Config::get('BASE_URL', 'https://philippurbschat.de/'), '/'); $baseUrl = rtrim(Config::get('BASE_URL', 'https://philippurbschat.de/'), '/');
$userProjects = $user['projects'] ?? []; $userProjects = User::parseProjects($user['projects'] ?? []);
$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 +79,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($slug, $userProjects, true); $isChecked = 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">