prepare("SELECT * FROM integrations WHERE user_id = ? AND provider = 'OUTLOOK'"); $stmtExisting->execute([$userId]); $existing = $stmtExisting->fetch(); $existingSettings = json_decode($existing['settings'] ?? '{}', true) ?: []; if (($clientSecret === '' || $clientSecret === '••••••••••••••••') && !empty($existingSettings['client_secret']) && $existingSettings['client_secret'] !== '••••••••••••••••') { $clientSecret = $existingSettings['client_secret']; } $newSettings = array_merge($existingSettings, [ 'client_id' => $clientId, 'client_secret' => $clientSecret, 'tenant_id' => $tenantId, ]); $stmt = $db->prepare(" INSERT INTO integrations (user_id, provider, is_enabled, is_demo_mode, settings, last_sync_at) VALUES (?, 'OUTLOOK', 1, ?, ?, NOW()) ON DUPLICATE KEY UPDATE is_demo_mode = VALUES(is_demo_mode), settings = VALUES(settings), last_sync_at = NOW() "); $stmt->execute([$userId, $isDemo, json_encode($newSettings)]); if (empty($clientId)) { $message = "Vul eerst de Application (Client) ID in van uw Azure App Registratie."; $messageType = 'error'; } elseif (empty($clientSecret)) { $message = "Vul eerst het Client Secret in van uw Azure App Registratie."; $messageType = 'error'; } else { header("Location: /auth/oauth_microsoft.php"); exit; } } else { // Collega of Beheerder zonder inline velden if (!$appConfig['is_configured']) { $message = "Microsoft 365 is nog niet geconfigureerd door de beheerder. Vraag een beheerder om de Application ID en Client Secret in te stellen."; $messageType = 'error'; } else { header("Location: /auth/oauth_microsoft.php"); exit; } } } // B. Alleen Beheerders mogen de centrale Azure instellingen opslaan elseif ($action === 'save') { if (!$isAdmin) { $message = "Alleen beheerders kunnen centrale integratie-instellingen wijzigen."; $messageType = 'error'; } else { $clientId = trim($_POST['client_id'] ?? ''); $clientSecret = trim($_POST['client_secret'] ?? ''); $tenantId = trim($_POST['tenant_id'] ?? 'common'); if (empty($tenantId)) $tenantId = 'common'; $isDemo = isset($_POST['is_demo_mode']) ? 1 : 0; $stmtExisting = $db->prepare("SELECT * FROM integrations WHERE user_id = ? AND provider = 'OUTLOOK'"); $stmtExisting->execute([$userId]); $existing = $stmtExisting->fetch(); $existingSettings = json_decode($existing['settings'] ?? '{}', true) ?: []; if (($clientSecret === '' || $clientSecret === '••••••••••••••••') && !empty($existingSettings['client_secret']) && $existingSettings['client_secret'] !== '••••••••••••••••') { $clientSecret = $existingSettings['client_secret']; } $newSettings = array_merge($existingSettings, [ 'client_id' => $clientId, 'client_secret' => $clientSecret, 'tenant_id' => $tenantId, ]); $stmt = $db->prepare(" INSERT INTO integrations (user_id, provider, is_enabled, is_demo_mode, settings, last_sync_at) VALUES (?, 'OUTLOOK', 1, ?, ?, NOW()) ON DUPLICATE KEY UPDATE is_demo_mode = VALUES(is_demo_mode), settings = VALUES(settings), last_sync_at = NOW() "); $stmt->execute([$userId, $isDemo, json_encode($newSettings)]); $message = "Centrale instellingen voor Microsoft Outlook zijn succesvol opgeslagen."; $messageType = 'success'; } } } // 3. Teams Opslaan elseif ($provider === 'TEAMS') { $isDemo = isset($_POST['is_demo_mode']) ? 1 : 0; $stmt = $db->prepare(" INSERT INTO integrations (user_id, provider, is_enabled, is_demo_mode, last_sync_at) VALUES (?, 'TEAMS', 1, ?, NOW()) ON DUPLICATE KEY UPDATE is_demo_mode = VALUES(is_demo_mode), last_sync_at = NOW() "); $stmt->execute([$userId, $isDemo]); $message = "Instellingen voor Microsoft Teams zijn bijgewerkt."; } // 4. Jira Opslaan & Testen elseif ($provider === 'JIRA') { $jiraDomain = jira_normalize_domain($_POST['jira_domain'] ?? ''); $jiraEmail = trim($_POST['jira_email'] ?? ''); $jiraToken = trim($_POST['jira_api_token'] ?? ''); $isDemo = isset($_POST['is_demo_mode']) ? 1 : 0; // Haal bestaande instellingen op $stmtExisting = $db->prepare("SELECT * FROM integrations WHERE user_id = ? AND provider = 'JIRA'"); $stmtExisting->execute([$userId]); $existing = $stmtExisting->fetch(); $existingSettings = json_decode($existing['settings'] ?? '{}', true) ?: []; if (($jiraToken === '' || $jiraToken === '••••••••••••••••') && !empty($existingSettings['jira_api_token']) && $existingSettings['jira_api_token'] !== '••••••••••••••••') { $jiraToken = $existingSettings['jira_api_token']; } // Als niet in demo mode, test verbinding $accountName = $existingSettings['account_name'] ?? ''; $accountId = $existingSettings['account_id'] ?? ''; if (!$isDemo && !empty($jiraDomain) && !empty($jiraEmail) && !empty($jiraToken)) { $testRes = jira_test_connection($jiraDomain, $jiraEmail, $jiraToken); if (!$testRes['success']) { $message = "Jira Verbindingsfout: " . $testRes['error']; $messageType = 'error'; } else { $accountName = $testRes['user']['displayName'] ?? 'Jira Gebruiker'; $accountId = $testRes['user']['accountId'] ?? ''; $message = "Verbinding met Jira geslaagd! Ingelogd als: {$accountName}"; $messageType = 'success'; } } else { $message = "Jira instellingen opgeslagen."; $messageType = 'success'; } $newSettings = [ 'jira_domain' => $jiraDomain, 'jira_email' => $jiraEmail, 'jira_api_token' => $jiraToken, 'account_name' => $accountName, 'account_id' => $accountId, ]; $stmt = $db->prepare(" INSERT INTO integrations (user_id, provider, is_enabled, is_demo_mode, settings, last_sync_at) VALUES (?, 'JIRA', 1, ?, ?, NOW()) ON DUPLICATE KEY UPDATE is_demo_mode = VALUES(is_demo_mode), settings = VALUES(settings), last_sync_at = NOW() "); $stmt->execute([$userId, $isDemo, json_encode($newSettings)]); // Wis cache unset($_SESSION["jira_issues_user_{$userId}"]); } } // Laad nu pas de HTML header in require_once __DIR__ . '/includes/header.php'; // Haal huidige configuraties op $stmtConfigs = $db->prepare("SELECT * FROM integrations WHERE user_id = ?"); $stmtConfigs->execute([$userId]); $configsRaw = $stmtConfigs->fetchAll(); $configs = []; foreach ($configsRaw as $c) { $configs[$c['provider']] = $c; $configs[$c['provider']]['settings_parsed'] = json_decode($c['settings'] ?? '{}', true) ?: []; } // Bepaal statussen $isOutlookConnected = !empty($configs['OUTLOOK']['access_token']) && empty($configs['OUTLOOK']['is_demo_mode']); $outlookSettings = $configs['OUTLOOK']['settings_parsed'] ?? []; $isJiraConnected = !empty($configs['JIRA']) && empty($configs['JIRA']['is_demo_mode']) && !empty($configs['JIRA']['settings_parsed']['jira_api_token']); $jiraSettings = $configs['JIRA']['settings_parsed'] ?? []; // Haal actuele Jira issues op $forceRefresh = isset($_GET['refresh_jira']); $jiraData = jira_get_user_issues($userId, $forceRefresh); $jiraIssues = $jiraData['issues'] ?? []; $jiraIsDemo = !empty($jiraData['is_demo']); // Callback redirect URI $redirectUri = rtrim(APP_URL, '/') . '/auth/callback_microsoft.php'; $appConfig = microsoft_get_app_config(); $isAdmin = ($user['role'] === 'ADMIN'); // Voor beheerders tonen we eventueel centraal opgeslagen waarden als fallback in de inputvelden if ($isAdmin) { if (empty($outlookSettings['client_id']) && !empty($appConfig['client_id'])) { $outlookSettings['client_id'] = $appConfig['client_id']; } if (empty($outlookSettings['client_secret']) && !empty($appConfig['client_secret'])) { $outlookSettings['client_secret'] = $appConfig['client_secret']; } if (empty($outlookSettings['tenant_id']) && !empty($appConfig['tenant_id'])) { $outlookSettings['tenant_id'] = $appConfig['tenant_id']; } } ?>
Live Koppelingen & Data Synchronisatie

Integraties Hub

Outlook:
Jira:
Live Verbonden Sandbox Modus Niet Gekoppeld

Microsoft Outlook (365)

Synchroniseert automatisch uw zakelijke agenda-afspraken en meetings naar de dagplanner tijdlijn.

Account:
Naam:
Laatste Sync:
Centrale Beheerdersinstellingen Deze Azure App gegevens gelden voor alle collega's in de organisatie. Gewone gebruikers zien deze technische details niet en hoeven alleen op 'Koppelen' te klikken.
Azure App Registratie Instructies

1. Open Azure App Registraties en maak een nieuwe registratie.

2. Kies Accounts in elke organisatiemap (...) en persoonlijke Microsoft-accounts.

3. Voeg een Web Omleidings-URI toe:

4. Maak een geheim aan onder Certificaten en geheimen.

5. Voeg API-machtigingen toe: Calendars.ReadWrite, User.Read, offline_access.

6. Cruciaal voor organisaties: Klik direct boven de tabel met machtigingen op de knop "Beheerdersgoedkeuring verlenen voor [Organisatie]" (Grant admin consent) en bevestig met 'Ja'. Hiermee voorkomt u de melding "Beheerdersgoedkeuring vereist".

Configuratie vereist door beheerder Uw beheerder heeft de Microsoft 365 integratie nog niet geconfigureerd voor uw organisatie. Vraag uw beheerder om de Azure App gegevens in te stellen.
Gereed voor Koppeling Uw beheerder heeft Microsoft 365 klaargezet voor uw organisatie. Koppel uw persoonlijke werkagenda om al uw meetings en Teams-afspraken automatisch in uw dagplanning te laden.

Te vinden op de Overzichtspagina (Overview) van uw Azure App Registratie.

Aangemaakt onder Certificaten en geheimen > Nieuw clientgeheim (kopieer de Waarde / Value).

Standaard: common

💡 Wat moet hier staan?

• Voor uw organisatie: vul uw domein in (bijv. planningsagenda.nl) of uw Tenant GUID.

• Voor multi-tenant apps: vul organizations of common in.

Krijgt u "Beheerdersgoedkeuring vereist"? Stuur deze officiële Microsoft goedkeuringslink naar uw IT-beheerder om Fociz met 1 klik goed te keuren voor :
Inbegrepen bij Outlook

Microsoft Teams

Detecteert Teams vergaderingen automatisch vanuit uw Outlook agenda en toont directe 'Deelnemen' knoppen.

Direct Deelnemen: Ondersteund
Meeting detectie: Via Graph API
Status:

Teams vergaderingen worden automatisch uitgelezen zodra Microsoft Outlook is gekoppeld. U hoeft voor Teams geen aparte koppeling te configureren!

Live Verbonden Sandbox Modus Niet Gekoppeld

Atlassian Jira Cloud

Koppelt uw Jira tickets rechtstreeks aan de Fociz dagplanning en roadmap.

Ingelogd als:
Domein:
Tickets Toegewezen: open taken
Atlassian API Token nodig? Genereer Token

Jira Issues Toegewezen aan U

Sandbox Live Jira
Geen openstaande tickets gevonden die aan u zijn toegewezen in Jira.
'text-red-400 bg-red-500/10 border-red-500/20', 'medium', 'gemiddeld' => 'text-amber-400 bg-amber-500/10 border-amber-500/20', default => 'text-slate-400 bg-slate-800/60 border-slate-700', }; ?>

Type: Vervaldatum: