feat: moduulijärjestelmä + käyttäjäroolit + suhteellinen aika
- Moduulijärjestelmä: yrityskohtaiset tabit (customers, support, leads, archive, changelog, settings) valittavissa checkboxeina yrityksen asetuksissa - Käyttäjäroolit: superadmin (pääkäyttäjä), admin (yritysadmin), user (käyttäjä) - Superadmin: kaikki oikeudet kuten ennen - Yritysadmin: muokkaa oman yrityksen asetuksia, moduuleita, postilaatikoita - Käyttäjä: peruskäyttö ilman hallintaoikeuksia - Päivitetty-kenttä näyttää suhteellista aikaa (15min sitten, 2h sitten, 3pv sitten) - DB: enabled_modules sarake companies-tauluun, role ENUM laajennettu - Automaattinen migraatio: vanhat admin → superadmin Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
75
api.php
75
api.php
@@ -38,13 +38,32 @@ function requireAuth() {
|
||||
|
||||
function requireAdmin() {
|
||||
requireAuth();
|
||||
if (($_SESSION['role'] ?? '') !== 'admin') {
|
||||
$role = $_SESSION['role'] ?? '';
|
||||
if ($role !== 'admin' && $role !== 'superadmin') {
|
||||
http_response_code(403);
|
||||
echo json_encode(['error' => 'Vain ylläpitäjä voi tehdä tämän']);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
function requireSuperAdmin() {
|
||||
requireAuth();
|
||||
if (($_SESSION['role'] ?? '') !== 'superadmin') {
|
||||
http_response_code(403);
|
||||
echo json_encode(['error' => 'Vain pääkäyttäjä voi tehdä tämän']);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
function isSuperAdmin(): bool {
|
||||
return ($_SESSION['role'] ?? '') === 'superadmin';
|
||||
}
|
||||
|
||||
function isCompanyAdmin(): bool {
|
||||
$role = $_SESSION['role'] ?? '';
|
||||
return $role === 'admin' || $role === 'superadmin';
|
||||
}
|
||||
|
||||
function currentUser(): string {
|
||||
return $_SESSION['username'] ?? 'tuntematon';
|
||||
}
|
||||
@@ -884,7 +903,7 @@ switch ($action) {
|
||||
$domainCompany = dbGetCompanyByDomain($host);
|
||||
$domainCompanyId = $domainCompany ? $domainCompany['id'] : '';
|
||||
// Jos domain kuuluu tietylle yritykselle, vain sen yrityksen käyttäjät + adminit pääsevät sisään
|
||||
if ($domainCompanyId && $u['role'] !== 'admin' && !in_array($domainCompanyId, $userCompanies)) {
|
||||
if ($domainCompanyId && $u['role'] !== 'superadmin' && !in_array($domainCompanyId, $userCompanies)) {
|
||||
dbRecordLoginAttempt($ip);
|
||||
http_response_code(403);
|
||||
echo json_encode(['error' => 'Sinulla ei ole oikeutta kirjautua tälle sivustolle.']);
|
||||
@@ -956,6 +975,15 @@ switch ($action) {
|
||||
// Brändäystiedot domain-pohjaisesti (sama kuin branding-endpoint)
|
||||
$host = strtolower(explode(':', $_SERVER['HTTP_HOST'] ?? '')[0]);
|
||||
$branding = dbGetBranding($host);
|
||||
// Aktiivisen yrityksen enabled_modules
|
||||
$activeCompanyId = $_SESSION['company_id'] ?? '';
|
||||
$enabledModules = [];
|
||||
foreach ($allCompanies as $comp) {
|
||||
if ($comp['id'] === $activeCompanyId) {
|
||||
$enabledModules = $comp['enabled_modules'] ?? [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
echo json_encode([
|
||||
'authenticated' => true,
|
||||
'user_id' => $_SESSION['user_id'],
|
||||
@@ -966,6 +994,7 @@ switch ($action) {
|
||||
'company_id' => $_SESSION['company_id'] ?? '',
|
||||
'signatures' => $userSignatures,
|
||||
'branding' => $branding,
|
||||
'enabled_modules' => $enabledModules,
|
||||
]);
|
||||
} else {
|
||||
echo json_encode(['authenticated' => false]);
|
||||
@@ -1035,7 +1064,7 @@ switch ($action) {
|
||||
|
||||
// ---------- USERS ----------
|
||||
case 'users':
|
||||
requireAdmin();
|
||||
requireSuperAdmin();
|
||||
$users = dbLoadUsers();
|
||||
$safe = array_map(function($u) {
|
||||
unset($u['password_hash']);
|
||||
@@ -1045,14 +1074,15 @@ switch ($action) {
|
||||
break;
|
||||
|
||||
case 'user_create':
|
||||
requireAdmin();
|
||||
requireSuperAdmin();
|
||||
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'] ?? '');
|
||||
$role = ($input['role'] ?? 'user') === 'admin' ? 'admin' : 'user';
|
||||
$validRoles = ['superadmin', 'admin', 'user'];
|
||||
$role = in_array($input['role'] ?? '', $validRoles) ? $input['role'] : 'user';
|
||||
if (empty($username) || empty($password)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Käyttäjätunnus ja salasana vaaditaan']);
|
||||
@@ -1099,7 +1129,7 @@ switch ($action) {
|
||||
break;
|
||||
|
||||
case 'user_update':
|
||||
requireAdmin();
|
||||
requireSuperAdmin();
|
||||
if ($method !== 'POST') break;
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$id = $input['id'] ?? '';
|
||||
@@ -1111,7 +1141,10 @@ switch ($action) {
|
||||
}
|
||||
if (isset($input['nimi'])) $u['nimi'] = trim($input['nimi']);
|
||||
if (isset($input['email'])) $u['email'] = trim($input['email']);
|
||||
if (isset($input['role'])) $u['role'] = $input['role'] === 'admin' ? 'admin' : 'user';
|
||||
if (isset($input['role'])) {
|
||||
$validRoles = ['superadmin', 'admin', 'user'];
|
||||
$u['role'] = in_array($input['role'], $validRoles) ? $input['role'] : 'user';
|
||||
}
|
||||
if (isset($input['companies'])) {
|
||||
$allCompanies = dbLoadCompanies();
|
||||
$validIds = array_column($allCompanies, 'id');
|
||||
@@ -1146,7 +1179,7 @@ switch ($action) {
|
||||
break;
|
||||
|
||||
case 'user_delete':
|
||||
requireAdmin();
|
||||
requireSuperAdmin();
|
||||
if ($method !== 'POST') break;
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$id = $input['id'] ?? '';
|
||||
@@ -2297,7 +2330,15 @@ switch ($action) {
|
||||
|
||||
case 'companies_all':
|
||||
requireAdmin();
|
||||
echo json_encode(dbLoadCompanies());
|
||||
$all = dbLoadCompanies();
|
||||
if (isSuperAdmin()) {
|
||||
echo json_encode($all);
|
||||
} else {
|
||||
// Yritysadmin näkee vain omat yrityksensä
|
||||
$userCompanyIds = $_SESSION['companies'] ?? [];
|
||||
$filtered = array_values(array_filter($all, fn($c) => in_array($c['id'], $userCompanyIds)));
|
||||
echo json_encode($filtered);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'all_mailboxes':
|
||||
@@ -2322,7 +2363,7 @@ switch ($action) {
|
||||
break;
|
||||
|
||||
case 'company_create':
|
||||
requireAdmin();
|
||||
requireSuperAdmin();
|
||||
if ($method !== 'POST') break;
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$id = preg_replace('/[^a-z0-9-]/', '', strtolower(trim($input['id'] ?? '')));
|
||||
@@ -2374,6 +2415,15 @@ switch ($action) {
|
||||
if ($method !== 'POST') break;
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$id = $input['id'] ?? '';
|
||||
// Yritysadmin saa muokata vain omia yrityksiään
|
||||
if (!isSuperAdmin()) {
|
||||
$userCompanyIds = $_SESSION['companies'] ?? [];
|
||||
if (!in_array($id, $userCompanyIds)) {
|
||||
http_response_code(403);
|
||||
echo json_encode(['error' => 'Ei oikeuksia muokata tätä yritystä']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$companies = dbLoadCompanies();
|
||||
$found = false;
|
||||
foreach ($companies as $c) {
|
||||
@@ -2385,6 +2435,9 @@ switch ($action) {
|
||||
}
|
||||
if (isset($input['primary_color'])) $c['primary_color'] = trim($input['primary_color']);
|
||||
if (isset($input['subtitle'])) $c['subtitle'] = trim($input['subtitle']);
|
||||
if (isset($input['enabled_modules']) && is_array($input['enabled_modules'])) {
|
||||
$c['enabled_modules'] = array_values($input['enabled_modules']);
|
||||
}
|
||||
dbSaveCompany($c);
|
||||
$found = true;
|
||||
echo json_encode($c);
|
||||
@@ -2398,7 +2451,7 @@ switch ($action) {
|
||||
break;
|
||||
|
||||
case 'company_delete':
|
||||
requireAdmin();
|
||||
requireSuperAdmin();
|
||||
if ($method !== 'POST') break;
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$id = $input['id'] ?? '';
|
||||
|
||||
Reference in New Issue
Block a user