prepare("SELECT settings FROM integrations WHERE user_id = ? AND provider = 'JIRA'"); $stmt->execute([$user['id']]); $saved = json_decode($stmt->fetchColumn() ?: '{}', true); $apiToken = fociz_decrypt($saved['jira_api_token'] ?? ''); if (empty($domain)) $domain = $saved['jira_domain'] ?? ''; if (empty($email)) $email = $saved['jira_email'] ?? ''; } $res = jira_test_connection($domain, $email, $apiToken); if ($res['success'] && $save) { $jiraUser = $res['user']; $settings = json_encode([ 'jira_domain' => jira_normalize_domain($domain), 'jira_email' => $email, 'jira_api_token' => fociz_encrypt($apiToken), 'account_name' => $jiraUser['displayName'] ?? '', 'account_id' => $jiraUser['accountId'] ?? '', ]); $stmt = $db->prepare(" INSERT INTO integrations (user_id, provider, is_enabled, is_demo_mode, settings, last_sync_at) VALUES (?, 'JIRA', 1, 0, ?, NOW()) ON DUPLICATE KEY UPDATE is_enabled = 1, is_demo_mode = 0, settings = VALUES(settings), last_sync_at = NOW() "); $stmt->execute([$user['id'], $settings]); // Wis eventuele oude sessie cache unset($_SESSION["jira_issues_user_{$user['id']}"]); unset($_SESSION["jira_dashboard_user_{$user['id']}"]); } echo json_encode($res); exit; } // 2. Jira Issues Ophalen (Toegewezen aan de gebruiker) if ($action === 'get_jira_issues') { $force = !empty($_GET['force']) || !empty($_POST['force']); $res = jira_get_user_issues($user['id'], $force); echo json_encode($res); exit; } // 2b. Jira Dashboard Data Ophalen (Toegewezen + Team issues + Stats) if ($action === 'get_jira_dashboard') { $force = !empty($_GET['force']) || !empty($_POST['force']); $res = jira_get_dashboard_data($user['id'], $force); echo json_encode($res); exit; } // 2c. Jira Issue inplannen in Dagplanner if ($action === 'plan_jira_task') { $input = json_decode(file_get_contents('php://input'), true) ?: $_POST; $key = trim($input['key'] ?? ''); $summary = trim($input['summary'] ?? ''); $url = trim($input['url'] ?? ''); $planDate = !empty($input['plan_date']) ? trim($input['plan_date']) : date('Y-m-d'); $priority = in_array($input['priority'] ?? '', ['P1', 'P2', 'P3']) ? $input['priority'] : 'P2'; $timeBlockStart = !empty($input['time_block_start']) ? trim($input['time_block_start']) : null; $timeBlockEnd = !empty($input['time_block_end']) ? trim($input['time_block_end']) : null; $durationMinutes = !empty($input['duration_minutes']) ? (int)$input['duration_minutes'] : 45; if (empty($key) || empty($summary)) { echo json_encode(['error' => 'Ticket key en titel zijn verplicht']); exit; } $title = "[{$key}] {$summary}"; // Zoek of maak daily plan aan voor deze datum $stmtPlan = $db->prepare("SELECT id FROM daily_plans WHERE user_id = ? AND plan_date = ?"); $stmtPlan->execute([$user['id'], $planDate]); $planId = $stmtPlan->fetchColumn(); if (!$planId) { $stmtCreatePlan = $db->prepare("INSERT INTO daily_plans (user_id, plan_date) VALUES (?, ?)"); $stmtCreatePlan->execute([$user['id'], $planDate]); $planId = (int)$db->lastInsertId(); } // Voeg taak toe $stmt = $db->prepare(" INSERT INTO tasks (user_id, daily_plan_id, title, priority, time_block_start, time_block_end, duration_minutes, status, source, external_id, external_url) VALUES (?, ?, ?, ?, ?, ?, ?, 'TODO', 'JIRA', ?, ?) "); $stmt->execute([ $user['id'], $planId, $title, $priority, $timeBlockStart, $timeBlockEnd, $durationMinutes, $key, $url ]); $taskId = (int)$db->lastInsertId(); echo json_encode([ 'success' => true, 'task_id' => $taskId, 'message' => "Ticket {$key} is succesvol ingepland voor " . date('d-m-Y', strtotime($planDate)) . "!", ]); exit; } // 2d. Jira Issue toevoegen aan een Kanban Bord kolom if ($action === 'board_jira_card') { $input = json_decode(file_get_contents('php://input'), true) ?: $_POST; $boardId = (int)($input['board_id'] ?? 0); $laneId = (int)($input['lane_id'] ?? 0); $key = trim($input['key'] ?? ''); $summary = trim($input['summary'] ?? ''); $description = trim($input['description'] ?? ''); $url = trim($input['url'] ?? ''); $priority = in_array($input['priority'] ?? '', ['P1', 'P2', 'P3']) ? $input['priority'] : 'P2'; $color = in_array($input['color'] ?? '', ['yellow', 'blue', 'green', 'purple', 'red', 'pink', 'indigo', 'orange']) ? $input['color'] : 'blue'; if (empty($boardId) || empty($laneId) || empty($key) || empty($summary)) { echo json_encode(['error' => 'Bord, kolom, ticket key en titel zijn verplicht']); exit; } // Controleer toegang tot bord $isAdmin = ($user['role'] ?? '') === 'ADMIN'; if (!$isAdmin) { $stmtCheck = $db->prepare("SELECT role FROM board_members WHERE board_id = ? AND user_id = ?"); $stmtCheck->execute([$boardId, $user['id']]); if (!$stmtCheck->fetchColumn()) { echo json_encode(['error' => 'Geen toegang tot dit bord']); exit; } } // Controleer of lane bij bord hoort $stmtLane = $db->prepare("SELECT id FROM board_lanes WHERE id = ? AND board_id = ?"); $stmtLane->execute([$laneId, $boardId]); if (!$stmtLane->fetchColumn()) { echo json_encode(['error' => 'Kolom hoort niet bij dit bord']); exit; } $title = "[{$key}] {$summary}"; $descFull = trim(($url ? "🔗 Jira: {$url}\n\n" : "") . $description); $maxPos = (int)$db->query("SELECT COALESCE(MAX(position), -1) FROM board_cards WHERE lane_id = {$laneId}")->fetchColumn(); $stmt = $db->prepare(" INSERT INTO board_cards (board_id, lane_id, title, description, assignee_id, priority, color, position, created_by_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) "); $stmt->execute([ $boardId, $laneId, $title, $descFull, $user['id'], $priority, $color, $maxPos + 1, $user['id'] ]); $cardId = (int)$db->lastInsertId(); echo json_encode([ 'success' => true, 'card_id' => $cardId, 'message' => "Ticket {$key} is succesvol als kaart op het bord geplaatst!", ]); exit; } // 2e. Beschikbare borden en kolommen ophalen voor selectiedialoog if ($action === 'get_boards_and_lanes') { $isAdmin = ($user['role'] ?? '') === 'ADMIN'; if ($isAdmin) { $boards = $db->query("SELECT id, title FROM boards WHERE is_archived = 0 ORDER BY id ASC")->fetchAll(); } else { $stmt = $db->prepare(" SELECT b.id, b.title FROM boards b JOIN board_members bm ON b.id = bm.board_id WHERE bm.user_id = ? AND b.is_archived = 0 ORDER BY b.id ASC "); $stmt->execute([$user['id']]); $boards = $stmt->fetchAll(); } $boardIds = array_column($boards, 'id'); $lanesByBoard = []; if (!empty($boardIds)) { $inClause = implode(',', array_map('intval', $boardIds)); $lanes = $db->query("SELECT id, board_id, title, color FROM board_lanes WHERE board_id IN ({$inClause}) ORDER BY position ASC")->fetchAll(); foreach ($lanes as $lane) { $lanesByBoard[$lane['board_id']][] = $lane; } } foreach ($boards as &$b) { $b['lanes'] = $lanesByBoard[$b['id']] ?? []; } echo json_encode(['success' => true, 'boards' => $boards]); exit; } // 3. Outlook Agenda Afspraken Ophalen if ($action === 'get_outlook_events') { $date = $_GET['date'] ?? date('Y-m-d'); $events = microsoft_fetch_today_events($user['id'], $date); echo json_encode([ 'success' => true, 'date' => $date, 'events' => $events, 'count' => count($events), ]); exit; } // 4. Integratie Ontkoppelen if ($action === 'disconnect') { $input = json_decode(file_get_contents('php://input'), true) ?: $_POST; $provider = strtoupper(trim($input['provider'] ?? '')); if ($provider === 'OUTLOOK') { microsoft_disconnect($user['id']); echo json_encode(['success' => true, 'message' => 'Microsoft Outlook ontkoppeld']); exit; } if ($provider === 'JIRA') { jira_disconnect($user['id']); echo json_encode(['success' => true, 'message' => 'Atlassian Jira ontkoppeld']); exit; } echo json_encode(['error' => 'Onbekende provider']); exit; } // 5a. Jira Wachtrijfilters Ophalen if ($action === 'get_jira_queue_filters') { $onlyActive = !isset($_GET['all']) && !isset($_POST['all']); $filters = jira_get_queue_filters($onlyActive); echo json_encode(['success' => true, 'filters' => $filters]); exit; } // 5b. Jira Wachtrijfilter Opslaan / Wijzigen (Alleen Beheerders) if ($action === 'save_jira_queue_filter') { if (($user['role'] ?? '') !== 'ADMIN') { echo json_encode(['error' => 'Alleen beheerders mogen wachtrijfilters aanpassen.']); exit; } $input = json_decode(file_get_contents('php://input'), true) ?: $_POST; $id = (int)($input['id'] ?? 0); $filterCode = strtoupper(trim($input['filter_code'] ?? '')); $filterName = trim($input['filter_name'] ?? ''); $projectKey = strtoupper(trim($input['project_key'] ?? '')); $jqlClause = trim($input['jql_clause'] ?? ''); $description = trim($input['description'] ?? ''); $isActive = isset($input['is_active']) ? (int)$input['is_active'] : 1; $sortOrder = (int)($input['sort_order'] ?? 0); if (empty($filterCode) || empty($filterName) || empty($jqlClause)) { echo json_encode(['error' => 'Code, naam en JQL-clausule zijn verplicht.']); exit; } if ($id > 0) { $stmt = $db->prepare(" UPDATE jira_queue_filters SET filter_code = ?, filter_name = ?, project_key = ?, jql_clause = ?, description = ?, is_active = ?, sort_order = ?, updated_at = NOW() WHERE id = ? "); $stmt->execute([$filterCode, $filterName, $projectKey ?: null, $jqlClause, $description, $isActive, $sortOrder, $id]); } else { $stmt = $db->prepare(" INSERT INTO jira_queue_filters (filter_code, filter_name, project_key, jql_clause, description, is_active, sort_order) VALUES (?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE filter_name = VALUES(filter_name), project_key = VALUES(project_key), jql_clause = VALUES(jql_clause), description = VALUES(description), is_active = VALUES(is_active), sort_order = VALUES(sort_order), updated_at = NOW() "); $stmt->execute([$filterCode, $filterName, $projectKey ?: null, $jqlClause, $description, $isActive, $sortOrder]); } echo json_encode(['success' => true, 'message' => "Wachtrijfilter '{$filterName}' is succesvol opgeslagen."]); exit; } // 5c. Jira Wachtrijfilter Verwijderen (Alleen Beheerders) if ($action === 'delete_jira_queue_filter') { if (($user['role'] ?? '') !== 'ADMIN') { echo json_encode(['error' => 'Alleen beheerders mogen wachtrijfilters verwijderen.']); exit; } $input = json_decode(file_get_contents('php://input'), true) ?: $_POST; $id = (int)($input['id'] ?? 0); $filterCode = trim($input['filter_code'] ?? ''); if ($id > 0) { $stmt = $db->prepare("DELETE FROM jira_queue_filters WHERE id = ?"); $stmt->execute([$id]); } elseif (!empty($filterCode)) { $stmt = $db->prepare("DELETE FROM jira_queue_filters WHERE filter_code = ?"); $stmt->execute([$filterCode]); } else { echo json_encode(['error' => 'Filter ID of code ontbreekt.']); exit; } echo json_encode(['success' => true, 'message' => 'Wachtrijfilter is verwijderd.']); exit; } // 5d. Standaard Wachtrijfilter Toewijzen aan Gebruiker (Beheerders of Gebruiker zelf) if ($action === 'set_user_jira_filter') { $input = json_decode(file_get_contents('php://input'), true) ?: $_POST; $targetUserId = (int)($input['user_id'] ?? $user['id']); $filterCode = trim($input['filter_code'] ?? ''); if ($targetUserId !== (int)$user['id'] && ($user['role'] ?? '') !== 'ADMIN') { echo json_encode(['error' => 'Geen toestemming om instellingen van andere gebruikers te wijzigen.']); exit; } $stmt = $db->prepare("UPDATE users SET default_jira_filter_code = ? WHERE id = ?"); $stmt->execute([$filterCode ?: null, $targetUserId]); echo json_encode(['success' => true, 'message' => 'Wachtrijvoorkeur is succesvol bijgewerkt.']); exit; } echo json_encode(['error' => 'Onbekende actie']); } catch (Exception $e) { http_response_code(500); echo json_encode(['error' => $e->getMessage()]); }