From b7e50042b56b899ad1cb8ff32163474a09f1eb7e Mon Sep 17 00:00:00 2001 From: Jukka Lampikoski Date: Tue, 10 Mar 2026 20:26:53 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20admin=20n=C3=A4kee=20oman=20yrityksen?= =?UTF-8?q?=20k=C3=A4ytt=C3=A4j=C3=A4t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Käyttäjät-nappi näkyy nyt myös admin-roolille - Admin näkee/hallitsee vain oman yrityksensä käyttäjiä - Admin voi luoda admin/user-rooleja (ei superadmin) - Admin ei voi poistaa/muokata superadmineja - Superadmin-vaihtoehto piilotettu rooli-dropdownista adminilta - Yritysoikeudet-osio piilotettu adminilta (lisätään automaattisesti) Co-Authored-By: Claude Opus 4.6 --- api.php | 51 ++++++++++++++++++++++++++++++++++++++++++++------- script.js | 8 +++++++- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/api.php b/api.php index 3d21331..e1053a4 100644 --- a/api.php +++ b/api.php @@ -1068,8 +1068,16 @@ switch ($action) { // ---------- USERS ---------- case 'users': - requireSuperAdmin(); + requireAdmin(); $users = dbLoadUsers(); + // Admin näkee vain oman yrityksensä käyttäjät, superadmin näkee kaikki + $role = $_SESSION['role'] ?? ''; + $companyId = $_SESSION['company_id'] ?? ''; + if ($role !== 'superadmin') { + $users = array_filter($users, function($u) use ($companyId) { + return in_array($companyId, $u['companies'] ?? []); + }); + } $safe = array_map(function($u) { unset($u['password_hash']); return $u; @@ -1078,14 +1086,15 @@ switch ($action) { break; case 'user_create': - requireSuperAdmin(); + requireAdmin(); if ($method !== 'POST') break; $input = json_decode(file_get_contents('php://input'), true); $username = trim($input['username'] ?? ''); $password = $input['password'] ?? ''; $nimi = trim($input['nimi'] ?? ''); $email = trim($input['email'] ?? ''); - $validRoles = ['superadmin', 'admin', 'user']; + $isSA = ($_SESSION['role'] ?? '') === 'superadmin'; + $validRoles = $isSA ? ['superadmin', 'admin', 'user'] : ['admin', 'user']; $role = in_array($input['role'] ?? '', $validRoles) ? $input['role'] : 'user'; if (empty($username) || empty($password)) { http_response_code(400); @@ -1104,6 +1113,11 @@ switch ($action) { break; } $companies = $input['companies'] ?? []; + // Admin voi lisätä käyttäjiä vain omaan yritykseensä + if (!$isSA) { + $myCompanyId = $_SESSION['company_id'] ?? ''; + $companies = [$myCompanyId]; + } // Validoi yritys-IDt $allCompanies = dbLoadCompanies(); $validIds = array_column($allCompanies, 'id'); @@ -1133,7 +1147,7 @@ switch ($action) { break; case 'user_update': - requireSuperAdmin(); + requireAdmin(); if ($method !== 'POST') break; $input = json_decode(file_get_contents('php://input'), true); $id = $input['id'] ?? ''; @@ -1143,11 +1157,24 @@ switch ($action) { echo json_encode(['error' => 'Käyttäjää ei löydy']); break; } + $isSA = ($_SESSION['role'] ?? '') === 'superadmin'; + $myCompanyId = $_SESSION['company_id'] ?? ''; + // Admin voi muokata vain oman yrityksensä käyttäjiä + if (!$isSA && !in_array($myCompanyId, $u['companies'] ?? [])) { + http_response_code(403); + echo json_encode(['error' => 'Ei oikeutta muokata tätä käyttäjää']); + break; + } if (isset($input['nimi'])) $u['nimi'] = trim($input['nimi']); if (isset($input['email'])) $u['email'] = trim($input['email']); if (isset($input['role'])) { - $validRoles = ['superadmin', 'admin', 'user']; - $u['role'] = in_array($input['role'], $validRoles) ? $input['role'] : 'user'; + $validRoles = $isSA ? ['superadmin', 'admin', 'user'] : ['admin', 'user']; + // Admin ei voi muuttaa superadminia + if (!$isSA && ($u['role'] === 'superadmin')) { + // Älä muuta roolia + } else { + $u['role'] = in_array($input['role'], $validRoles) ? $input['role'] : 'user'; + } } if (isset($input['companies'])) { $allCompanies = dbLoadCompanies(); @@ -1183,7 +1210,7 @@ switch ($action) { break; case 'user_delete': - requireSuperAdmin(); + requireAdmin(); if ($method !== 'POST') break; $input = json_decode(file_get_contents('php://input'), true); $id = $input['id'] ?? ''; @@ -1193,6 +1220,16 @@ switch ($action) { break; } $deleted = dbGetUser($id); + $isSA = ($_SESSION['role'] ?? '') === 'superadmin'; + $myCompanyId = $_SESSION['company_id'] ?? ''; + // Admin ei voi poistaa superadmineja eikä toisen yrityksen käyttäjiä + if (!$isSA) { + if ($deleted && ($deleted['role'] === 'superadmin' || !in_array($myCompanyId, $deleted['companies'] ?? []))) { + http_response_code(403); + echo json_encode(['error' => 'Ei oikeutta poistaa tätä käyttäjää']); + break; + } + } dbDeleteUser($id); $companyId = $_SESSION['company_id'] ?? ''; if ($deleted) dbAddLog($companyId, currentUser(), 'user_delete', '', '', "Poisti käyttäjän: {$deleted['username']}"); diff --git a/script.js b/script.js index 9f5c6fa..72bfeda 100644 --- a/script.js +++ b/script.js @@ -187,7 +187,7 @@ async function showDashboard() { const isSuperAdmin = currentUser.role === 'superadmin'; const isAdmin = currentUser.role === 'admin' || isSuperAdmin; // Näytä admin-toiminnot roolin mukaan - document.getElementById('btn-users').style.display = isSuperAdmin ? '' : 'none'; + document.getElementById('btn-users').style.display = isAdmin ? '' : 'none'; document.getElementById('tab-settings').style.display = isAdmin ? '' : 'none'; document.getElementById('btn-companies').style.display = isAdmin ? '' : 'none'; // Yritysvalitsin @@ -1012,6 +1012,12 @@ function openUserForm(user = null) { document.getElementById('user-form-password').value = ''; document.getElementById('user-pw-hint').textContent = user ? '(jätä tyhjäksi jos ei muuteta)' : '*'; document.getElementById('user-form-role').value = user ? user.role : 'user'; + // Piilota superadmin-vaihtoehto ellei ole superadmin + const saOption = document.querySelector('#user-form-role option[value="superadmin"]'); + if (saOption) saOption.style.display = currentUser?.role === 'superadmin' ? '' : 'none'; + // Piilota yrityscheckboxit adminilta (näkee vain oman yrityksen) + const compSection = document.getElementById('user-company-checkboxes')?.closest('.form-group'); + if (compSection) compSection.style.display = currentUser?.role === 'superadmin' ? '' : 'none'; // Yrityscheckboxit const allComps = availableCompanies.length > 0 ? availableCompanies : []; const userComps = user ? (user.companies || []) : [];