263 lines
10 KiB
PHP
263 lines
10 KiB
PHP
<?php
|
|
/**
|
|
* Centrale Systeeminstellingen Helper voor Fociz
|
|
* Beheert organisatie-brede werkdagstandaarden (v1.4) en AI configuratie (v1.5).
|
|
*/
|
|
|
|
require_once __DIR__ . '/../config/database.php';
|
|
|
|
/**
|
|
* Zorgt ervoor dat de system_settings tabel bestaat in MariaDB
|
|
*/
|
|
function ensure_system_settings_table(?PDO $db = null): void {
|
|
static $ensured = false;
|
|
if ($ensured) return;
|
|
|
|
try {
|
|
$pdo = $db ?: get_db_connection();
|
|
$pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS `system_settings` (
|
|
`setting_key` VARCHAR(64) PRIMARY KEY,
|
|
`setting_value` TEXT NULL,
|
|
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
");
|
|
$ensured = true;
|
|
} catch (Throwable $e) {
|
|
error_log("ensure_system_settings_table error: " . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Haalt alle systeeminstellingen in 1 geoptimaliseerde query op en bewaart deze in het static runtime geheugen
|
|
*/
|
|
function get_all_system_settings(bool $forceRefresh = false): array {
|
|
static $settingsCache = null;
|
|
if ($settingsCache !== null && !$forceRefresh) {
|
|
return $settingsCache;
|
|
}
|
|
|
|
$settingsCache = [];
|
|
try {
|
|
$db = get_db_connection();
|
|
ensure_system_settings_table($db);
|
|
|
|
$stmt = $db->query("SELECT setting_key, setting_value FROM system_settings");
|
|
while ($row = $stmt->fetch()) {
|
|
$val = $row['setting_value'];
|
|
if ($val === null) {
|
|
$settingsCache[$row['setting_key']] = null;
|
|
continue;
|
|
}
|
|
$trimmed = trim((string)$val);
|
|
if (str_starts_with($trimmed, '{') || str_starts_with($trimmed, '[')) {
|
|
$decoded = json_decode($val, true);
|
|
$settingsCache[$row['setting_key']] = (json_last_error() === JSON_ERROR_NONE) ? $decoded : $val;
|
|
} else {
|
|
$settingsCache[$row['setting_key']] = $val;
|
|
}
|
|
}
|
|
} catch (Throwable $e) {
|
|
error_log("get_all_system_settings error: " . $e->getMessage());
|
|
}
|
|
|
|
return $settingsCache;
|
|
}
|
|
|
|
/**
|
|
* Haalt een enkele instelling op uit het geheugen (of fallback default)
|
|
*/
|
|
function get_system_setting(string $key, $default = null) {
|
|
$all = get_all_system_settings();
|
|
if (array_key_exists($key, $all) && $all[$key] !== null && $all[$key] !== '') {
|
|
return $all[$key];
|
|
}
|
|
return $default;
|
|
}
|
|
|
|
/**
|
|
* Slaat een instelling op in MariaDB en ververst direct het cachegeheugen
|
|
*/
|
|
function set_system_setting(string $key, $value): bool {
|
|
try {
|
|
$db = get_db_connection();
|
|
ensure_system_settings_table($db);
|
|
|
|
$valToStore = is_array($value) || is_object($value) ? json_encode($value) : (string)$value;
|
|
|
|
$stmt = $db->prepare("
|
|
INSERT INTO system_settings (setting_key, setting_value)
|
|
VALUES (?, ?)
|
|
ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value), updated_at = NOW()
|
|
");
|
|
$ok = $stmt->execute([$key, $valToStore]);
|
|
if ($ok) {
|
|
get_all_system_settings(true);
|
|
}
|
|
return $ok;
|
|
} catch (Throwable $e) {
|
|
error_log("set_system_setting error for {$key}: " . $e->getMessage());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Haalt alle organisatie werkdag standaarden op (Release v1.4)
|
|
*/
|
|
function get_workday_settings(): array {
|
|
$rawDays = get_system_setting('workdays', '1,2,3,4,5');
|
|
$workdays = array_values(array_filter(array_map('intval', explode(',', $rawDays)), fn($d) => $d >= 1 && $d <= 7));
|
|
if (empty($workdays)) {
|
|
$workdays = [1, 2, 3, 4, 5];
|
|
}
|
|
return [
|
|
'workday_start' => get_system_setting('workday_start', '08:30'),
|
|
'workday_end' => get_system_setting('workday_end', '17:00'),
|
|
'lunch_start' => get_system_setting('lunch_start', '12:30'),
|
|
'lunch_end' => get_system_setting('lunch_end', '13:00'),
|
|
'pomodoro_focus' => (int)get_system_setting('pomodoro_focus', 25),
|
|
'pomodoro_deep' => (int)get_system_setting('pomodoro_deep', 50),
|
|
'pomodoro_break' => (int)get_system_setting('pomodoro_break', 5),
|
|
'default_task_duration' => (int)get_system_setting('default_task_duration', 30),
|
|
'workdays' => $workdays,
|
|
'workdays_str' => implode(',', $workdays),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Haalt AI configuratie-instellingen op (Release v2.0 - Google Gemini Pro & OpenAI)
|
|
* Ondersteunt organisatiebrede en optioneel persoonlijke sleutels.
|
|
*/
|
|
function get_ai_settings(?int $userId = null): array {
|
|
if (!function_exists('fociz_decrypt')) {
|
|
require_once __DIR__ . '/auth.php';
|
|
}
|
|
|
|
$apiKey = '';
|
|
$isPersonal = false;
|
|
$personalProvider = null;
|
|
$personalModel = null;
|
|
|
|
// 1. Controleer persoonlijke sleutel van de ingelogde gebruiker
|
|
if ($userId !== null && $userId > 0) {
|
|
try {
|
|
$db = get_db_connection();
|
|
$stmt = $db->prepare("SELECT access_token, settings, is_enabled FROM integrations WHERE user_id = ? AND provider IN ('GEMINI', 'AI') AND is_enabled = 1 ORDER BY id DESC LIMIT 1");
|
|
$stmt->execute([$userId]);
|
|
$row = $stmt->fetch();
|
|
if ($row) {
|
|
// Sleutel kan in access_token staan of in settings['api_key']
|
|
if (!empty($row['access_token'])) {
|
|
$apiKey = fociz_decrypt((string)$row['access_token']);
|
|
$isPersonal = true;
|
|
} elseif (!empty($row['settings'])) {
|
|
$userSettings = json_decode($row['settings'], true) ?: [];
|
|
if (!empty($userSettings['api_key'])) {
|
|
$apiKey = fociz_decrypt((string)$userSettings['api_key']);
|
|
$isPersonal = true;
|
|
}
|
|
}
|
|
|
|
if (!empty($row['settings'])) {
|
|
$userSettings = json_decode($row['settings'], true) ?: [];
|
|
if (!empty($userSettings['provider'])) {
|
|
$personalProvider = (string)$userSettings['provider'];
|
|
}
|
|
if (!empty($userSettings['model'])) {
|
|
$personalModel = (string)$userSettings['model'];
|
|
}
|
|
}
|
|
}
|
|
} catch (Throwable $e) {
|
|
error_log("Fout bij ophalen persoonlijke AI sleutel: " . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
// 2. Fallback naar organisatiebrede instellingen
|
|
if (empty($apiKey)) {
|
|
$savedKeyRaw = get_system_setting('ai_api_key', '');
|
|
if (!empty($savedKeyRaw)) {
|
|
$apiKey = fociz_decrypt((string)$savedKeyRaw);
|
|
}
|
|
}
|
|
|
|
// 3. Fallback naar .env variabelen (GEMINI_API_KEY of OPENAI_API_KEY)
|
|
if (empty($apiKey)) {
|
|
$apiKey = (string)(fociz_env('GEMINI_API_KEY', '') ?: fociz_env('OPENAI_API_KEY', ''));
|
|
}
|
|
|
|
$provider = !empty($personalProvider) ? $personalProvider : get_system_setting('ai_provider', 'gemini');
|
|
if (empty($provider)) {
|
|
$provider = 'gemini';
|
|
}
|
|
|
|
$model = !empty($personalModel) ? $personalModel : get_system_setting('ai_model', 'gemini-1.5-pro');
|
|
if (empty($model)) {
|
|
$model = (strpos((string)$provider, 'openai') !== false) ? 'gpt-4o-mini' : 'gemini-1.5-pro';
|
|
}
|
|
|
|
$apiKey = trim((string)$apiKey);
|
|
$hasKey = ($apiKey !== '');
|
|
|
|
return [
|
|
'ai_enabled' => (bool)get_system_setting('ai_enabled', $hasKey),
|
|
'ai_provider' => (string)$provider,
|
|
'ai_api_key' => $apiKey,
|
|
'ai_model' => (string)$model,
|
|
'has_key' => $hasKey,
|
|
'is_personal_key'=> $isPersonal,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Haalt geconfigureerde sessie idle timeout in seconden op conform NIST SP 800-63B / ISO 27001
|
|
* Toegestane waarden: 900 (15m), 1800 (30m - default), 3600 (60m), 7200 (120m)
|
|
*/
|
|
function get_session_idle_timeout(): int {
|
|
$timeout = (int)get_system_setting('session_idle_timeout', 1800);
|
|
$validTimeouts = [900, 1800, 3600, 7200];
|
|
return in_array($timeout, $validTimeouts, true) ? $timeout : 1800;
|
|
}
|
|
|
|
/**
|
|
* Haalt de beheerbare dagblokkade-redenen op (bijv. Vakantie, Verlof, Ziek, Focusdag, ADV).
|
|
* Standaard voorzien van een duidelijke titel, emoji-icoon en actief-status.
|
|
*/
|
|
function get_calendar_block_reasons(): array {
|
|
$defaultReasons = [
|
|
['code' => 'VACATION', 'title' => 'Vakantie', 'icon' => '🏖️', 'is_active' => 1],
|
|
['code' => 'LEAVE', 'title' => 'Verlof / Vrij', 'icon' => '✈️', 'is_active' => 1],
|
|
['code' => 'SICK', 'title' => 'Ziek / Afwezig', 'icon' => '🤒', 'is_active' => 1],
|
|
['code' => 'FOCUS', 'title' => 'Focusdag', 'icon' => '🎯', 'is_active' => 1],
|
|
['code' => 'ADV', 'title' => 'ADV Dag', 'icon' => '📋', 'is_active' => 1],
|
|
];
|
|
|
|
$saved = get_system_setting('calendar_block_reasons', null);
|
|
if (is_array($saved) && !empty($saved)) {
|
|
return $saved;
|
|
}
|
|
return $defaultReasons;
|
|
}
|
|
|
|
/**
|
|
* Haalt de beheerbare brainstorm categorieën op.
|
|
* Standaard voorzien van een duidelijke categorienaam, beschrijving en actief-status.
|
|
*/
|
|
function get_brainstorm_categories(): array {
|
|
$defaultCategories = [
|
|
['name' => 'Product & Strategie', 'description' => 'Strategische richting, nieuwe producten en visie', 'is_active' => 1],
|
|
['name' => 'Procesverbetering', 'description' => 'Optimalisatie van werkprocessen en efficiëntie', 'is_active' => 1],
|
|
['name' => 'Klant & Service', 'description' => 'Klanttevredenheid, support en klantervaring', 'is_active' => 1],
|
|
['name' => 'Technologie & IT', 'description' => 'Architectuur, tooling, infrastructuur en tech stack','is_active' => 1],
|
|
['name' => 'Marketing & Groei', 'description' => 'Leadgeneratie, branding en marktpositie', 'is_active' => 1],
|
|
];
|
|
|
|
$saved = get_system_setting('brainstorm_categories', null);
|
|
if (is_array($saved) && !empty($saved)) {
|
|
return $saved;
|
|
}
|
|
return $defaultCategories;
|
|
}
|
|
|
|
|