Files
Fociz/api/integrations.php
T

382 lines
15 KiB
PHP

<?php
/**
* AJAX API voor Integraties (Outlook, Teams, Jira)
*/
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/integrations/microsoft.php';
require_once __DIR__ . '/../includes/integrations/jira.php';
$user = require_auth();
$db = get_db_connection();
header('Content-Type: application/json');
$action = $_GET['action'] ?? ($_POST['action'] ?? '');
try {
// 1. Jira Verbinding Testen & Optioneel Opslaan
if ($action === 'test_jira') {
$input = json_decode(file_get_contents('php://input'), true) ?: $_POST;
$domain = trim($input['jira_domain'] ?? '');
$email = trim($input['jira_email'] ?? '');
$apiToken = trim($input['jira_api_token'] ?? '');
$save = !empty($input['save']);
// Als er geen nieuw token is meegegeven, kijk of er een opgeslagen token is
if (empty($apiToken)) {
$stmt = $db->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()]);
}