From 45a883319a54634e146e328d4e083d9a86845d4c Mon Sep 17 00:00:00 2001 From: Niek Rabelink Date: Wed, 16 Sep 2026 00:32:29 +0200 Subject: [PATCH] Outlook changes --- api/mail.php | 17 +- includes/integrations/microsoft.php | 382 +++++++++++++++++++++++++++- mail.php | 359 +++++++++++++++++++------- 3 files changed, 654 insertions(+), 104 deletions(-) diff --git a/api/mail.php b/api/mail.php index 4708eca..0b7e526 100644 --- a/api/mail.php +++ b/api/mail.php @@ -22,13 +22,22 @@ header('Content-Type: application/json; charset=utf-8'); $action = $_GET['action'] ?? ($_POST['action'] ?? ''); try { - // 1. Inbox berichten ophalen - if ($action === 'get_inbox') { - $limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 25; + // 0. Mail mappen ophalen + if ($action === 'get_folders') { + $forceRefresh = !empty($_GET['refresh']) && $_GET['refresh'] === '1'; + $res = microsoft_fetch_mail_folders($userId, $forceRefresh); + echo json_encode($res); + exit; + } + + // 1. Inbox of specifieke map berichten ophalen + if ($action === 'get_folder_messages' || $action === 'get_inbox') { + $folderId = trim($_GET['folder_id'] ?? ($_POST['folder_id'] ?? 'inbox')); + $limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 30; $unreadOnly = !empty($_GET['unread_only']) && $_GET['unread_only'] === '1'; $forceRefresh = !empty($_GET['refresh']) && $_GET['refresh'] === '1'; - $res = microsoft_fetch_inbox_messages($userId, $limit, $unreadOnly, $forceRefresh); + $res = microsoft_fetch_folder_messages($userId, $folderId, $limit, $unreadOnly, $forceRefresh); echo json_encode($res); exit; } diff --git a/includes/integrations/microsoft.php b/includes/integrations/microsoft.php index 679789d..f02dee3 100644 --- a/includes/integrations/microsoft.php +++ b/includes/integrations/microsoft.php @@ -940,11 +940,156 @@ function microsoft_reconcile_tasks_with_outlook(int $userId, string $startDate, /** * Levert realistische demo e-mails voor accounts zonder actieve Outlook verbinding */ -function microsoft_get_mail_demo_data(): array { +function microsoft_get_mail_demo_data(?string $folderId = 'inbox'): array { $now = time(); + $fId = strtolower(trim($folderId ?: 'inbox')); + + if ($fId === 'demo-folder-dx') { + return [ + [ + 'id' => 'demo-mail-dx-1', + 'folder_id' => 'demo-folder-dx', + 'subject' => '⚡ Update: REST endpoint v2 specificatie voor UWV & Koppelingen', + 'body_preview' => 'Beste collega, hierbij de bijgewerkte documentatie voor de REST endpoints en de schema-wijzigingen voor de datadump...', + 'body_html' => '

Beste collega,

Hierbij de bijgewerkte documentatie voor de REST endpoints en de schema-wijzigingen voor de datadump.

Graag controleren of de data mapping aansluit bij onze migratiestappen.

Met vriendelijke groet,
Team Koppelingen & DX

', + 'from_name' => 'Koppelingen Team DX', + 'from_email' => 'dx-koppelingen@fociz.nl', + 'to_recipients' => [['name' => 'Collega', 'address' => 'collega@fociz.nl']], + 'cc_recipients' => [], + 'received_at' => date('Y-m-d H:i:s', $now - (25 * 60)), + 'received_human' => '25 min geleden', + 'is_read' => false, + 'has_attachments' => true, + 'importance' => 'high', + 'web_link' => 'https://outlook.office.com/mail/', + 'is_demo' => true, + ], + [ + 'id' => 'demo-mail-dx-2', + 'folder_id' => 'demo-folder-dx', + 'subject' => 'Migratie draaiboek koppelingen fase 3 gereed', + 'body_preview' => 'Het draaiboek voor de uitrol van de vernieuwde interfaces is goedgekeurd door de lead architect...', + 'body_html' => '

Het draaiboek voor de uitrol van de vernieuwde interfaces is goedgekeurd door de lead architect. Zie de bijlage voor de tijdsplanning.

', + 'from_name' => 'Lead Architect', + 'from_email' => 'architect@fociz.nl', + 'to_recipients' => [['name' => 'Collega', 'address' => 'collega@fociz.nl']], + 'cc_recipients' => [], + 'received_at' => date('Y-m-d H:i:s', $now - (4 * 3600)), + 'received_human' => '4 uur geleden', + 'is_read' => true, + 'has_attachments' => false, + 'importance' => 'normal', + 'web_link' => 'https://outlook.office.com/mail/', + 'is_demo' => true, + ], + [ + 'id' => 'demo-mail-dx-3', + 'folder_id' => 'demo-folder-dx', + 'subject' => 'SSO Certificaat verificatie voor staging omgeving', + 'body_preview' => 'Het SSL/TLS certificaat voor de authenticatiekoppeling verloopt over 30 dagen. Het nieuwe certificaat is klaargezet...', + 'body_html' => '

Het SSL/TLS certificaat voor de authenticatiekoppeling verloopt over 30 dagen. Het nieuwe certificaat is klaargezet op de staging server.

', + 'from_name' => 'Security & Certificaten', + 'from_email' => 'security@fociz.nl', + 'to_recipients' => [['name' => 'Collega', 'address' => 'collega@fociz.nl']], + 'cc_recipients' => [], + 'received_at' => date('Y-m-d H:i:s', $now - (26 * 3600)), + 'received_human' => 'Gisteren', + 'is_read' => true, + 'has_attachments' => false, + 'importance' => 'normal', + 'web_link' => 'https://outlook.office.com/mail/', + 'is_demo' => true, + ], + ]; + } + + if ($fId === 'demo-folder-klanten') { + return [ + [ + 'id' => 'demo-mail-klant-1', + 'folder_id' => 'demo-folder-klanten', + 'subject' => 'Project kick-off partnerportaal integratie', + 'body_preview' => 'Beste Fociz team, bedankt voor de toelichting gisteren. We kijken uit naar de gezamenlijke sprintstart volgende maand...', + 'body_html' => '

Beste Fociz team,

Bedankt voor de toelichting gisteren. We kijken uit naar de gezamenlijke sprintstart volgende maand.

Vriendelijke groet,
Partner Relatiemanager

', + 'from_name' => 'Partner Relaties', + 'from_email' => 'partners@klantportaal.nl', + 'to_recipients' => [['name' => 'Collega', 'address' => 'collega@fociz.nl']], + 'cc_recipients' => [], + 'received_at' => date('Y-m-d H:i:s', $now - (5 * 3600)), + 'received_human' => '5 uur geleden', + 'is_read' => true, + 'has_attachments' => false, + 'importance' => 'normal', + 'web_link' => 'https://outlook.office.com/mail/', + 'is_demo' => true, + ], + [ + 'id' => 'demo-mail-klant-2', + 'folder_id' => 'demo-folder-klanten', + 'subject' => 'Vraag over API sleutels en documentatie', + 'body_preview' => 'Hallo, kunnen we de sandbox tokens alvast ontvangen voor onze ontwikkelaars?...', + 'body_html' => '

Hallo, kunnen we de sandbox tokens alvast ontvangen voor onze ontwikkelaars? Alvast dank!

', + 'from_name' => 'IT Lead Klant', + 'from_email' => 'tech@partnerbedrijf.com', + 'to_recipients' => [['name' => 'Collega', 'address' => 'collega@fociz.nl']], + 'cc_recipients' => [], + 'received_at' => date('Y-m-d H:i:s', $now - (28 * 3600)), + 'received_human' => 'Gisteren', + 'is_read' => true, + 'has_attachments' => false, + 'importance' => 'normal', + 'web_link' => 'https://outlook.office.com/mail/', + 'is_demo' => true, + ], + ]; + } + + if ($fId === 'demo-folder-fin') { + return [ + [ + 'id' => 'demo-mail-fin-1', + 'folder_id' => 'demo-folder-fin', + 'subject' => 'Nieuwe factuur September licenties ter goedkeuring', + 'body_preview' => 'Beste directie, bijgaand de specificatie van de maandelijks cloud infrastructuur kosten ter akkoord...', + 'body_html' => '

Beste directie,

Bijgaand de specificatie van de maandelijkse cloud infrastructuur kosten ter akkoord. Graag uiterlijk vrijdag verwerken.

', + 'from_name' => 'Financiële Administratie', + 'from_email' => 'facturen@fociz.nl', + 'to_recipients' => [['name' => 'Collega', 'address' => 'collega@fociz.nl']], + 'cc_recipients' => [], + 'received_at' => date('Y-m-d H:i:s', $now - (40 * 60)), + 'received_human' => '40 min geleden', + 'is_read' => false, + 'has_attachments' => true, + 'importance' => 'high', + 'web_link' => 'https://outlook.office.com/mail/', + 'is_demo' => true, + ], + [ + 'id' => 'demo-mail-fin-2', + 'folder_id' => 'demo-folder-fin', + 'subject' => 'Betaalbevestiging software koppelingen', + 'body_preview' => 'Uw betaling voor de kwartaallicenties is succesvol verwerkt...', + 'body_html' => '

Uw betaling voor de kwartaallicenties is succesvol verwerkt. Factuurnummer INV-2026-09.

', + 'from_name' => 'Accounts Payable', + 'from_email' => 'billing@cloudvendor.com', + 'to_recipients' => [['name' => 'Collega', 'address' => 'collega@fociz.nl']], + 'cc_recipients' => [], + 'received_at' => date('Y-m-d H:i:s', $now - (48 * 3600)), + 'received_human' => '2 dagen geleden', + 'is_read' => true, + 'has_attachments' => false, + 'importance' => 'low', + 'web_link' => 'https://outlook.office.com/mail/', + 'is_demo' => true, + ], + ]; + } + + // Standaard Inbox demo berichten return [ [ 'id' => 'demo-mail-1', + 'folder_id' => 'inbox', 'subject' => '⚡ Urgent: UWV Koppeling REST-endpoints en Datamigratie timing', 'body_preview' => 'Beste collega, we hebben vanuit de overheidsspecificaties aanvullende eisen ontvangen omtrent de UWV REST-endpoints en de validatie van werknemersdossiers...', 'body_html' => '

Beste collega,

We hebben vanuit de overheidsspecificaties aanvullende eisen ontvangen omtrent de UWV REST-endpoints en de validatie van werknemersdossiers.

Zou je kunnen verifiëren of onze SSO-koppeling en de datadump export hier al op aansluiten? Het zou fijn zijn als we dit vanmiddag kort kunnen afstemmen in de planning.

Met vriendelijke groet,
Directie UWV Koppelingen & Integraties

', @@ -952,7 +1097,7 @@ function microsoft_get_mail_demo_data(): array { 'from_email' => 'koppelingen@uwv-overheid.nl', 'to_recipients' => [['name' => 'Collega', 'address' => 'collega@fociz.nl']], 'cc_recipients' => [], - 'received_at' => date('Y-m-d H:i:s', $now - (12 * 60)), // 12 minuten geleden + 'received_at' => date('Y-m-d H:i:s', $now - (12 * 60)), 'received_human' => '12 min geleden', 'is_read' => false, 'has_attachments' => true, @@ -962,6 +1107,7 @@ function microsoft_get_mail_demo_data(): array { ], [ 'id' => 'demo-mail-2', + 'folder_id' => 'inbox', 'subject' => 'Factuur & Urenverantwoording September — Goedkeuring vereist', 'body_preview' => 'Hallo team, bijgaand tref je de voorlopige urenstaat en factuurspecificatie aan voor de lopende sprint. Graag voor het einde van de week accorderen...', 'body_html' => '

Hallo team,

Bijgaand tref je de voorlopige urenstaat en factuurspecificatie aan voor de lopende sprint. Graag voor het einde van de werkweek accorderen in het systeem.

Laat het weten indien er correcties nodig zijn op de dagregistraties.

Hartelijke groet,
Financiële Administratie Fociz

', @@ -969,7 +1115,7 @@ function microsoft_get_mail_demo_data(): array { 'from_email' => 'facturatie@fociz.nl', 'to_recipients' => [['name' => 'Collega', 'address' => 'collega@fociz.nl']], 'cc_recipients' => [], - 'received_at' => date('Y-m-d H:i:s', $now - (65 * 60)), // 1 uur geleden + 'received_at' => date('Y-m-d H:i:s', $now - (65 * 60)), 'received_human' => '1 uur geleden', 'is_read' => false, 'has_attachments' => false, @@ -979,6 +1125,7 @@ function microsoft_get_mail_demo_data(): array { ], [ 'id' => 'demo-mail-3', + 'folder_id' => 'inbox', 'subject' => 'Jira SSO Migratie & Staging server testomgeving', 'body_preview' => 'Goedemiddag, de testomgeving voor de nieuwe Atlassian API migratie (CHANGE-2046) is succesvol klaargezet. We kunnen starten met de verificatietesten...', 'body_html' => '

Goedemiddag,

De testomgeving voor de nieuwe Atlassian API migratie (CHANGE-2046) is succesvol klaargezet. We kunnen starten met de verificatietesten op de Servicedesk wachtrijen en DX filters.

Alle endpoint logs zijn beschikbaar via het beheerpaneel.

Groeten,
Team DevOps & Infrastructuur

', @@ -986,7 +1133,7 @@ function microsoft_get_mail_demo_data(): array { 'from_email' => 'infra@fociz.nl', 'to_recipients' => [['name' => 'Collega', 'address' => 'collega@fociz.nl']], 'cc_recipients' => [], - 'received_at' => date('Y-m-d H:i:s', $now - (3 * 3600)), // 3 uur geleden + 'received_at' => date('Y-m-d H:i:s', $now - (3 * 3600)), 'received_human' => '3 uur geleden', 'is_read' => true, 'has_attachments' => true, @@ -996,6 +1143,7 @@ function microsoft_get_mail_demo_data(): array { ], [ 'id' => 'demo-mail-4', + 'folder_id' => 'inbox', 'subject' => 'Herinnering: Kwartaal Roadmap Review & Strategie sessie', 'body_preview' => 'Beste collega\'s, vergeet niet je prioriteiten en feature requests in te dienen in de Fociz Roadmap module voor de meeting van aanstaande donderdag...', 'body_html' => '

Beste collega\'s,

Vergeet niet je prioriteiten en feature requests in te dienen in de Fociz Roadmap module voor de meeting van aanstaande donderdag.

We behandelen dan tevens de nieuwe Kanban borden en de Outlook time-blocking ervaring.

Tot dan!
Product Management

', @@ -1003,7 +1151,7 @@ function microsoft_get_mail_demo_data(): array { 'from_email' => 'product@fociz.nl', 'to_recipients' => [['name' => 'Alle Medewerkers', 'address' => 'team@fociz.nl']], 'cc_recipients' => [], - 'received_at' => date('Y-m-d H:i:s', $now - (24 * 3600)), // Gisteren + 'received_at' => date('Y-m-d H:i:s', $now - (24 * 3600)), 'received_human' => 'Gisteren', 'is_read' => true, 'has_attachments' => false, @@ -1013,6 +1161,7 @@ function microsoft_get_mail_demo_data(): array { ], [ 'id' => 'demo-mail-5', + 'folder_id' => 'inbox', 'subject' => 'Welkom bij Fociz Live — Handige tips voor jouw dagplanning', 'body_preview' => 'Welkom bij Fociz! Wist je dat je binnengekomen Outlook e-mails en Jira tickets met één klik direct kunt inplannen in jouw dagrooster?...', 'body_html' => '

Welkom bij Fociz!

Wist je dat je binnengekomen Outlook e-mails en Jira tickets met één klik direct kunt inplannen in jouw persoonlijke dagplanning?

Hierdoor houd je maximale grip op je werkdag en behoud je de ultieme focus.

Veel productiviteit gewenst,
Het Fociz Team

', @@ -1020,7 +1169,7 @@ function microsoft_get_mail_demo_data(): array { 'from_email' => 'no-reply@fociz.nl', 'to_recipients' => [['name' => 'Collega', 'address' => 'collega@fociz.nl']], 'cc_recipients' => [], - 'received_at' => date('Y-m-d H:i:s', $now - (48 * 3600)), // 2 dagen geleden + 'received_at' => date('Y-m-d H:i:s', $now - (48 * 3600)), 'received_human' => '2 dagen geleden', 'is_read' => true, 'has_attachments' => false, @@ -1032,10 +1181,10 @@ function microsoft_get_mail_demo_data(): array { } /** - * Haalt inbox berichten op van Microsoft Graph API (of retourneert demo data) + * Haalt alle beschikbare mailmappen op van Microsoft Graph API (exclusief SPAM/Junk, Prullenbak/Deleted, Outbox en Concepten) */ -function microsoft_fetch_inbox_messages(int $userId, int $limit = 25, bool $unreadOnly = false, bool $forceRefresh = false): array { - $cacheKey = "ms_inbox_{$userId}_{$limit}_" . ($unreadOnly ? '1' : '0'); +function microsoft_fetch_mail_folders(int $userId, bool $forceRefresh = false): array { + $cacheKey = "ms_folders_{$userId}"; if (!$forceRefresh) { $cached = fociz_cache_get($cacheKey); if ($cached !== null && is_array($cached)) { @@ -1050,13 +1199,208 @@ function microsoft_fetch_inbox_messages(int $userId, int $limit = 25, bool $unre $isLive = !empty($integration['access_token']) && empty($integration['is_demo_mode']); if (!$isLive) { - $demo = microsoft_get_mail_demo_data(); + $demoFolders = [ + [ + 'id' => 'inbox', + 'name' => 'Postvak IN', + 'unread_count' => 2, + 'total_count' => 5, + 'is_inbox' => true, + ], + [ + 'id' => 'demo-folder-dx', + 'name' => 'Projecten & DX Koppelingen', + 'unread_count' => 1, + 'total_count' => 3, + 'is_inbox' => false, + ], + [ + 'id' => 'demo-folder-klanten', + 'name' => 'Klanten & Partners', + 'unread_count' => 0, + 'total_count' => 2, + 'is_inbox' => false, + ], + [ + 'id' => 'demo-folder-fin', + 'name' => 'Financiën & Facturatie', + 'unread_count' => 1, + 'total_count' => 2, + 'is_inbox' => false, + ], + ]; + $totalUnread = array_sum(array_column($demoFolders, 'unread_count')); + return [ + 'success' => true, + 'is_demo' => true, + 'folders' => $demoFolders, + 'total_unread' => $totalUnread, + ]; + } + + $token = microsoft_get_valid_token($userId); + if (!$token) { + return [ + 'success' => false, + 'error' => 'Geen geldig Microsoft 365 token beschikbaar.', + 'folders' => [], + 'total_unread' => 0, + ]; + } + + $url = MS_GRAPH_BASE_URL . '/me/mailFolders?$top=100&$select=id,displayName,parentFolderId,childFolderCount,unreadItemCount,totalItemCount,wellKnownName'; + $res = fociz_http_request($url, [ + 'method' => 'GET', + 'headers' => [ + 'Authorization' => "Bearer {$token}", + 'Accept' => 'application/json', + ], + 'timeout' => 15, + ]); + + if ($res['status'] !== 200 || !isset($res['json']['value'])) { + $graphError = $res['json']['error']['message'] ?? ($res['error'] ?? 'HTTP ' . $res['status']); + error_log("Microsoft fetch folders error: HTTP {$res['status']} - {$graphError}"); + return [ + 'success' => false, + 'error' => $graphError, + 'folders' => [ + [ + 'id' => 'inbox', + 'name' => 'Postvak IN', + 'unread_count' => 0, + 'total_count' => 0, + 'is_inbox' => true, + ] + ], + 'total_unread' => 0, + ]; + } + + $rawFolders = $res['json']['value']; + + // Haal eventuele submappen op voor mappen met childFolderCount > 0 + foreach ($res['json']['value'] as $f) { + if (!empty($f['childFolderCount']) && (int)$f['childFolderCount'] > 0 && !empty($f['id'])) { + $childUrl = MS_GRAPH_BASE_URL . '/me/mailFolders/' . urlencode($f['id']) . '/childFolders?$top=50&$select=id,displayName,parentFolderId,childFolderCount,unreadItemCount,totalItemCount,wellKnownName'; + $cRes = fociz_http_request($childUrl, [ + 'method' => 'GET', + 'headers' => [ + 'Authorization' => "Bearer {$token}", + 'Accept' => 'application/json', + ], + 'timeout' => 10, + ]); + if ($cRes['status'] === 200 && !empty($cRes['json']['value'])) { + foreach ($cRes['json']['value'] as $child) { + $rawFolders[] = $child; + } + } + } + } + + // Uitsluitingen conform gebruikerswens: SPAM / Ongewenst, Prullenbak / Deleted, Outbox en Drafts + $excludedWellKnown = ['junkemail', 'deleteditems', 'outbox', 'drafts', 'conflicts', 'localfailures', 'serverfailures', 'syncissues']; + $excludedTerms = ['junk', 'spam', 'ongewenst', 'ongewenste e-mail', 'ongewenste email', 'deleted items', 'verwijderde items', 'prullenbak', 'trash', 'verwijderd', 'outbox', 'postvak uit', 'drafts', 'concepten']; + + $folders = []; + $seenIds = []; + + foreach ($rawFolders as $rf) { + $fId = $rf['id'] ?? ''; + if (empty($fId) || isset($seenIds[$fId])) continue; + $seenIds[$fId] = true; + + $wk = strtolower(trim($rf['wellKnownName'] ?? '')); + if (in_array($wk, $excludedWellKnown, true)) continue; + + $dName = trim($rf['displayName'] ?? ''); + $dNameLower = strtolower($dName); + + $skip = false; + foreach ($excludedTerms as $term) { + if ($dNameLower === $term || strpos($dNameLower, $term) !== false) { + $skip = true; + break; + } + } + if ($skip) continue; + + $isInbox = ($wk === 'inbox' || $dNameLower === 'inbox' || $dNameLower === 'postvak in'); + + $folders[] = [ + 'id' => $isInbox ? 'inbox' : $fId, + 'name' => $dName ?: 'Map', + 'unread_count' => (int)($rf['unreadItemCount'] ?? 0), + 'total_count' => (int)($rf['totalItemCount'] ?? 0), + 'is_inbox' => $isInbox, + ]; + } + + // Zorg dat Inbox altijd vooraan staat + $hasInbox = false; + foreach ($folders as $f) { + if (!empty($f['is_inbox'])) { + $hasInbox = true; + break; + } + } + if (!$hasInbox) { + array_unshift($folders, [ + 'id' => 'inbox', + 'name' => 'Postvak IN', + 'unread_count' => 0, + 'total_count' => 0, + 'is_inbox' => true, + ]); + } + + usort($folders, function($a, $b) { + if (!empty($a['is_inbox'])) return -1; + if (!empty($b['is_inbox'])) return 1; + return strcasecmp($a['name'], $b['name']); + }); + + $totalUnread = array_sum(array_column($folders, 'unread_count')); + + $result = [ + 'success' => true, + 'is_demo' => false, + 'folders' => $folders, + 'total_unread' => $totalUnread, + ]; + fociz_cache_set($cacheKey, $result, 60); // 60 seconden cache + return $result; +} + +/** + * Haalt berichten op voor een specifieke map van Microsoft Graph API (of retourneert demo data) + */ +function microsoft_fetch_folder_messages(int $userId, string $folderId = 'inbox', int $limit = 30, bool $unreadOnly = false, bool $forceRefresh = false): array { + $cleanFolderId = trim($folderId ?: 'inbox'); + $cacheKey = "ms_folder_{$userId}_" . md5($cleanFolderId) . "_{$limit}_" . ($unreadOnly ? '1' : '0'); + if (!$forceRefresh) { + $cached = fociz_cache_get($cacheKey); + if ($cached !== null && is_array($cached)) { + return $cached; + } + } + + $db = get_db_connection(); + $stmt = $db->prepare("SELECT * FROM integrations WHERE user_id = ? AND provider = 'OUTLOOK' AND is_enabled = 1"); + $stmt->execute([$userId]); + $integration = $stmt->fetch(); + + $isLive = !empty($integration['access_token']) && empty($integration['is_demo_mode']); + if (!$isLive) { + $demo = microsoft_get_mail_demo_data($cleanFolderId); if ($unreadOnly) { $demo = array_values(array_filter($demo, function($m) { return empty($m['is_read']); })); } return [ 'success' => true, 'is_demo' => true, + 'folder_id' => $cleanFolderId, 'messages' => array_slice($demo, 0, $limit), 'unread_count' => count(array_filter($demo, function($m) { return empty($m['is_read']); })), 'total_count' => count($demo), @@ -1068,6 +1412,7 @@ function microsoft_fetch_inbox_messages(int $userId, int $limit = 25, bool $unre return [ 'success' => false, 'error' => 'Geen geldig Microsoft 365 token beschikbaar.', + 'folder_id' => $cleanFolderId, 'messages' => [], 'unread_count' => 0, ]; @@ -1083,7 +1428,8 @@ function microsoft_fetch_inbox_messages(int $userId, int $limit = 25, bool $unre $queryParams['$filter'] = 'isRead eq false'; } - $url = MS_GRAPH_BASE_URL . '/me/mailFolders/inbox/messages?' . http_build_query($queryParams); + $folderEndpoint = ($cleanFolderId === 'inbox') ? 'inbox' : urlencode($cleanFolderId); + $url = MS_GRAPH_BASE_URL . '/me/mailFolders/' . $folderEndpoint . '/messages?' . http_build_query($queryParams); $res = fociz_http_request($url, [ 'method' => 'GET', 'headers' => [ @@ -1097,14 +1443,15 @@ function microsoft_fetch_inbox_messages(int $userId, int $limit = 25, bool $unre if ($res['status'] !== 200 || !isset($res['json']['value'])) { $graphError = $res['json']['error']['message'] ?? ($res['error'] ?? 'HTTP ' . $res['status']); $graphCode = $res['json']['error']['code'] ?? ''; - error_log("Microsoft fetch inbox error: HTTP {$res['status']} [{$graphCode}] - {$graphError}"); + error_log("Microsoft fetch folder messages error for {$cleanFolderId}: HTTP {$res['status']} [{$graphCode}] - {$graphError}"); - $demo = microsoft_get_mail_demo_data(); + $demo = microsoft_get_mail_demo_data($cleanFolderId); $needsReconsent = ($res['status'] === 403 || stripos($graphError, 'access') !== false || stripos($graphError, 'privilege') !== false || stripos($graphError, 'denied') !== false || stripos($graphError, 'consent') !== false); return [ 'success' => true, 'is_demo' => true, + 'folder_id' => $cleanFolderId, 'messages' => array_slice($demo, 0, $limit), 'unread_count' => count(array_filter($demo, function($m) { return empty($m['is_read']); })), 'total_count' => count($demo), @@ -1153,6 +1500,7 @@ function microsoft_fetch_inbox_messages(int $userId, int $limit = 25, bool $unre $messages[] = [ 'id' => $msg['id'] ?? '', + 'folder_id' => $cleanFolderId, 'subject' => $msg['subject'] ?: '(Geen onderwerp)', 'body_preview' => $msg['bodyPreview'] ?? '', 'from_name' => $fromName, @@ -1178,6 +1526,7 @@ function microsoft_fetch_inbox_messages(int $userId, int $limit = 25, bool $unre $result = [ 'success' => true, 'is_demo' => false, + 'folder_id' => $cleanFolderId, 'messages' => $messages, 'unread_count' => $unreadCount, 'total_count' => count($messages), @@ -1186,6 +1535,13 @@ function microsoft_fetch_inbox_messages(int $userId, int $limit = 25, bool $unre return $result; } +/** + * Haalt inbox berichten op van Microsoft Graph API (of retourneert demo data) + */ +function microsoft_fetch_inbox_messages(int $userId, int $limit = 30, bool $unreadOnly = false, bool $forceRefresh = false): array { + return microsoft_fetch_folder_messages($userId, 'inbox', $limit, $unreadOnly, $forceRefresh); +} + /** * Haalt de volledige inhoud en details van een enkel e-mailbericht op */ diff --git a/mail.php b/mail.php index 58c390d..e445207 100644 --- a/mail.php +++ b/mail.php @@ -14,15 +14,22 @@ $isAdmin = (($currentUser['role'] ?? '') === 'ADMIN'); $db = get_db_connection(); $userBoards = fociz_get_user_boards_with_lanes($db, $userId, $isAdmin); -// Haal initiële inbox data op (met 45s cache, tenzij ?refresh=1) +// Haal alle beschikbare mailmappen op (exclusief SPAM/Junk, Prullenbak/Deleted, Outbox, Drafts) $forceRefresh = !empty($_GET['refresh']) && $_GET['refresh'] === '1'; +$foldersData = microsoft_fetch_mail_folders($userId, $forceRefresh); +$mailFolders = $foldersData['folders'] ?? []; +$totalUnreadCount = (int)($foldersData['total_unread'] ?? 0); + +// Haal initiële inbox data op (met 45s cache, tenzij ?refresh=1) $inboxData = microsoft_fetch_inbox_messages($userId, 30, false, $forceRefresh); $messages = $inboxData['messages'] ?? []; -$isDemo = !empty($inboxData['is_demo']); -$unreadCount = (int)($inboxData['unread_count'] ?? 0); -$warning = $inboxData['warning'] ?? ''; +$isDemo = !empty($inboxData['is_demo']) || !empty($foldersData['is_demo']); +$warning = $inboxData['warning'] ?? ($foldersData['warning'] ?? ''); $needsReconsent = !empty($inboxData['needs_reconsent']); +// Bereken actuele ongelezen aantal: neem het hoogste van total_unread over mappen en inbox unread_count +$unreadCount = max($totalUnreadCount, (int)($inboxData['unread_count'] ?? 0)); + // Controleer status $stmtInt = $db->prepare("SELECT * FROM integrations WHERE user_id = ? AND provider = 'OUTLOOK' AND is_enabled = 1"); $stmtInt->execute([$userId]); @@ -31,6 +38,7 @@ $isOutlookConfigured = !empty($outlookInt['access_token']) && empty($outlookInt[ $isLiveMail = $isOutlookConfigured && !$isDemo; $jsonMessages = json_encode($messages, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP); +$jsonFolders = json_encode($mailFolders, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP); ?>
@@ -143,15 +151,15 @@ $jsonMessages = json_encode($messages, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_Q
- +
- Inbox Berichten () + Inbox & Mappen () Sorteer: Nieuwste eerst
-
- +
+
@@ -527,7 +535,12 @@ $jsonMessages = json_encode($messages, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_Q