Refactor code structure for improved readability and maintainability

This commit is contained in:
2026-09-10 11:27:31 +02:00
parent a7aad57e0b
commit 130a43eabc
42 changed files with 2545 additions and 122 deletions
+341 -96
View File
@@ -142,17 +142,17 @@ function jira_test_connection(string $domain, string $email, string $apiToken):
/**
* Haalt alle actieve issues op die zijn toegewezen aan de ingelogde Jira gebruiker
*/
function jira_fetch_assigned_issues(string $domain, string $email, string $apiToken, int $maxResults = 50): array {
/**
* Haalt issues op via een flexibele JQL query via Atlassian REST API
*/
function jira_fetch_issues(string $domain, string $email, string $apiToken, string $jql, int $maxResults = 50): array {
$cleanDomain = jira_normalize_domain($domain);
$authHeader = jira_get_auth_header($email, $apiToken);
// JQL: Alle openstaande taken toegewezen aan mij, gesorteerd op recent bijgewerkt
$jql = 'assignee = currentUser() AND statusCategory != Done ORDER BY updated DESC';
$params = [
'jql' => $jql,
'maxResults' => min($maxResults, 100),
'fields' => 'summary,status,priority,issuetype,parent,project,duedate,updated',
'fields' => 'summary,status,priority,issuetype,parent,project,assignee,reporter,duedate,updated',
];
$url = $cleanDomain . '/rest/api/3/search?' . http_build_query($params);
@@ -195,21 +195,34 @@ function jira_fetch_assigned_issues(string $domain, string $email, string $apiTo
$key = $item['key'] ?? '';
$summary = $fields['summary'] ?? '(Geen titel)';
$statusName = $fields['status']['name'] ?? 'To Do';
$statusCategory = $fields['status']['statusCategory']['key'] ?? 'indeterminate';
$priorityName = $fields['priority']['name'] ?? 'Medium';
$issueTypeName = $fields['issuetype']['name'] ?? 'Taak';
$issueTypeIcon = $fields['issuetype']['iconUrl'] ?? '';
$projectName = $fields['project']['name'] ?? 'Project';
$projectKey = $fields['project']['key'] ?? '';
$dueDate = $fields['duedate'] ?? null;
$updated = $fields['updated'] ?? null;
$assigneeName = $fields['assignee']['displayName'] ?? 'Niet toegewezen';
$assigneeAvatar = $fields['assignee']['avatarUrls']['48x48'] ?? ($fields['assignee']['avatarUrls']['32x32'] ?? '');
$issues[] = [
'key' => $key,
'summary' => $summary,
'status' => $statusName,
'priority' => $priorityName,
'issue_type' => $issueTypeName,
'project' => $projectName,
'due_date' => $dueDate,
'url' => "{$cleanDomain}/browse/{$key}",
'source' => 'JIRA_LIVE',
'key' => $key,
'summary' => $summary,
'status' => $statusName,
'status_category' => $statusCategory,
'priority' => $priorityName,
'issue_type' => $issueTypeName,
'issue_type_icon' => $issueTypeIcon,
'project' => $projectName,
'project_key' => $projectKey,
'assignee_name' => $assigneeName,
'assignee_avatar' => $assigneeAvatar,
'due_date' => $dueDate,
'updated' => $updated,
'url' => "{$cleanDomain}/browse/{$key}",
'source' => 'JIRA_LIVE',
];
}
@@ -221,66 +234,271 @@ function jira_fetch_assigned_issues(string $domain, string $email, string $apiTo
}
/**
* Haalt de Jira tickets op voor een Fociz gebruiker
* Schakelt naadloos tussen live Jira tickets en sandbox demotickets
* Haalt alle actieve issues op die zijn toegewezen aan de ingelogde Jira gebruiker
*/
function jira_get_user_issues(int $userId, bool $forceRefresh = false): array {
function jira_fetch_assigned_issues(string $domain, string $email, string $apiToken, int $maxResults = 50): array {
$jql = 'assignee = currentUser() ORDER BY updated DESC';
return jira_fetch_issues($domain, $email, $apiToken, $jql, $maxResults);
}
/**
* Haalt openstaande team issues op die horen bij de projecten van de gebruiker
*/
function jira_fetch_team_issues(string $domain, string $email, string $apiToken, int $maxResults = 50): array {
$jql = 'assignee != currentUser() AND statusCategory != Done ORDER BY updated DESC';
return jira_fetch_issues($domain, $email, $apiToken, $jql, $maxResults);
}
/**
* Haalt de complete dashboard data op (persoonlijk + team) inclusief statistieken
*/
function jira_get_dashboard_data(int $userId, bool $forceRefresh = false): array {
$db = get_db_connection();
$stmt = $db->prepare("SELECT * FROM integrations WHERE user_id = ? AND provider = 'JIRA' AND is_enabled = 1");
$stmt->execute([$userId]);
$integration = $stmt->fetch();
// Als de integratie niet is ingesteld of in demo mode staat, geef interactieve fallback issues terug
// Sandbox / Demo dataset indien niet gekoppeld of expliciet in demomodus
if (!$integration || !empty($integration['is_demo_mode'])) {
return [
'is_demo' => true,
'success' => true,
'issues' => [
[
'key' => 'FOC-101',
'summary' => 'Tweestapsverificatie (2FA TOTP) flow implementeren',
'status' => 'In Progress',
'priority' => 'High',
'issue_type' => 'Story',
'project' => 'Fociz Platform',
'due_date' => date('Y-m-d', strtotime('+2 days')),
'url' => '#',
'source' => 'SANDBOX',
],
[
'key' => 'FOC-102',
'summary' => 'Interactief whiteboard canvas voor brainstormsessies',
'status' => 'To Do',
'priority' => 'High',
'issue_type' => 'Feature',
'project' => 'Fociz Platform',
'due_date' => date('Y-m-d', strtotime('+4 days')),
'url' => '#',
'source' => 'SANDBOX',
],
[
'key' => 'FOC-103',
'summary' => 'Koppeling met Microsoft Outlook Calendar & Teams Graph API',
'status' => 'In Review',
'priority' => 'Medium',
'issue_type' => 'Task',
'project' => 'Integrations Hub',
'due_date' => date('Y-m-d'),
'url' => '#',
'source' => 'SANDBOX',
],
[
'key' => 'FOC-104',
'summary' => 'Roadmap kwartaalweergave en voortgangsindicatoren',
'status' => 'To Do',
'priority' => 'Medium',
'issue_type' => 'Story',
'project' => 'Roadmap Module',
'due_date' => date('Y-m-d', strtotime('+7 days')),
'url' => '#',
'source' => 'SANDBOX',
],
$assigned = [
[
'key' => 'FOC-101',
'summary' => 'Tweestapsverificatie (2FA TOTP) flow implementeren',
'status' => 'In Progress',
'status_category' => 'indeterminate',
'priority' => 'High',
'issue_type' => 'Story',
'project' => 'Fociz Platform',
'project_key' => 'FOC',
'assignee_name' => 'Mijzelf',
'assignee_avatar' => '',
'due_date' => date('Y-m-d', strtotime('+2 days')),
'updated' => date('Y-m-d H:i:s', strtotime('-2 hours')),
'url' => 'https://jira.atlassian.net/browse/FOC-101',
'source' => 'SANDBOX',
],
[
'key' => 'FOC-102',
'summary' => 'Interactief whiteboard canvas voor brainstormsessies',
'status' => 'To Do',
'status_category' => 'new',
'priority' => 'High',
'issue_type' => 'Feature',
'project' => 'Fociz Platform',
'project_key' => 'FOC',
'assignee_name' => 'Mijzelf',
'assignee_avatar' => '',
'due_date' => date('Y-m-d', strtotime('+4 days')),
'updated' => date('Y-m-d H:i:s', strtotime('-1 day')),
'url' => 'https://jira.atlassian.net/browse/FOC-102',
'source' => 'SANDBOX',
],
[
'key' => 'FOC-103',
'summary' => 'Koppeling met Microsoft Outlook Calendar & Teams Graph API',
'status' => 'In Review',
'status_category' => 'indeterminate',
'priority' => 'Medium',
'issue_type' => 'Task',
'project' => 'Integrations Hub',
'project_key' => 'INT',
'assignee_name' => 'Mijzelf',
'assignee_avatar' => '',
'due_date' => date('Y-m-d'),
'updated' => date('Y-m-d H:i:s', strtotime('-4 hours')),
'url' => 'https://jira.atlassian.net/browse/FOC-103',
'source' => 'SANDBOX',
],
[
'key' => 'FOC-104',
'summary' => 'Roadmap kwartaalweergave en voortgangsindicatoren',
'status' => 'To Do',
'status_category' => 'new',
'priority' => 'Medium',
'issue_type' => 'Story',
'project' => 'Roadmap Module',
'project_key' => 'ROAD',
'assignee_name' => 'Mijzelf',
'assignee_avatar' => '',
'due_date' => date('Y-m-d', strtotime('+7 days')),
'updated' => date('Y-m-d H:i:s', strtotime('-3 days')),
'url' => 'https://jira.atlassian.net/browse/FOC-104',
'source' => 'SANDBOX',
],
[
'key' => 'FOC-108',
'summary' => 'CSS scrollbar glitch oplossen in Kanban lane op Firefox',
'status' => 'In Progress',
'status_category' => 'indeterminate',
'priority' => 'Highest',
'issue_type' => 'Bug',
'project' => 'UI/UX Redesign',
'project_key' => 'UI',
'assignee_name' => 'Mijzelf',
'assignee_avatar' => '',
'due_date' => date('Y-m-d', strtotime('+1 day')),
'updated' => date('Y-m-d H:i:s', strtotime('-30 minutes')),
'url' => 'https://jira.atlassian.net/browse/FOC-108',
'source' => 'SANDBOX',
],
[
'key' => 'FOC-112',
'summary' => 'Avatar upload beveiliging en compressie optimalisatie',
'status' => 'Done',
'status_category' => 'done',
'priority' => 'Medium',
'issue_type' => 'Task',
'project' => 'Security',
'project_key' => 'SEC',
'assignee_name' => 'Mijzelf',
'assignee_avatar' => '',
'due_date' => date('Y-m-d', strtotime('-1 day')),
'updated' => date('Y-m-d H:i:s', strtotime('-5 hours')),
'url' => 'https://jira.atlassian.net/browse/FOC-112',
'source' => 'SANDBOX',
],
];
$team = [
[
'key' => 'FOC-95',
'summary' => 'Sessie timeout notificatie verschijnt niet tijdig bij inactieve tab',
'status' => 'In Progress',
'status_category' => 'indeterminate',
'priority' => 'Highest',
'issue_type' => 'Bug',
'project' => 'Fociz Platform',
'project_key' => 'FOC',
'assignee_name' => 'Lisa Bakker',
'assignee_avatar' => '',
'due_date' => date('Y-m-d', strtotime('+1 day')),
'updated' => date('Y-m-d H:i:s', strtotime('-1 hour')),
'url' => 'https://jira.atlassian.net/browse/FOC-95',
'source' => 'SANDBOX',
],
[
'key' => 'FOC-98',
'summary' => 'Automatische e-mail triggers voor taakdeadlines en uitnodigingen',
'status' => 'To Do',
'status_category' => 'new',
'priority' => 'High',
'issue_type' => 'Story',
'project' => 'Notifications',
'project_key' => 'NOTIF',
'assignee_name' => 'Daan van Dijk',
'assignee_avatar' => '',
'due_date' => date('Y-m-d', strtotime('+3 days')),
'updated' => date('Y-m-d H:i:s', strtotime('-2 days')),
'url' => 'https://jira.atlassian.net/browse/FOC-98',
'source' => 'SANDBOX',
],
[
'key' => 'FOC-105',
'summary' => 'Database indexering optimaliseren voor grote audit logs',
'status' => 'In Review',
'status_category' => 'indeterminate',
'priority' => 'Medium',
'issue_type' => 'Task',
'project' => 'Database & Core',
'project_key' => 'CORE',
'assignee_name' => 'Sophie de Vries',
'assignee_avatar' => '',
'due_date' => date('Y-m-d', strtotime('+5 days')),
'updated' => date('Y-m-d H:i:s', strtotime('-1 day')),
'url' => 'https://jira.atlassian.net/browse/FOC-105',
'source' => 'SANDBOX',
],
[
'key' => 'FOC-107',
'summary' => 'Exporteer wekelijkse team rapportage naar PDF en Excel spreadsheet',
'status' => 'To Do',
'status_category' => 'new',
'priority' => 'Low',
'issue_type' => 'Feature',
'project' => 'Reporting',
'project_key' => 'REP',
'assignee_name' => 'Thomas Jansen',
'assignee_avatar' => '',
'due_date' => date('Y-m-d', strtotime('+10 days')),
'updated' => date('Y-m-d H:i:s', strtotime('-4 days')),
'url' => 'https://jira.atlassian.net/browse/FOC-107',
'source' => 'SANDBOX',
],
[
'key' => 'FOC-110',
'summary' => 'Real-time websocket synchronisatie voor gelijktijdig bewerken van borden',
'status' => 'To Do',
'status_category' => 'new',
'priority' => 'High',
'issue_type' => 'Story',
'project' => 'Realtime Engine',
'project_key' => 'RT',
'assignee_name' => 'Bram Meijer',
'assignee_avatar' => '',
'due_date' => date('Y-m-d', strtotime('+6 days')),
'updated' => date('Y-m-d H:i:s', strtotime('-6 hours')),
'url' => 'https://jira.atlassian.net/browse/FOC-110',
'source' => 'SANDBOX',
],
[
'key' => 'FOC-114',
'summary' => 'Datum picker springt terug naar 1970 bij lege invoer',
'status' => 'To Do',
'status_category' => 'new',
'priority' => 'Medium',
'issue_type' => 'Bug',
'project' => 'UI/UX Redesign',
'project_key' => 'UI',
'assignee_name' => 'Niet toegewezen',
'assignee_avatar' => '',
'due_date' => null,
'updated' => date('Y-m-d H:i:s', strtotime('-2 days')),
'url' => 'https://jira.atlassian.net/browse/FOC-114',
'source' => 'SANDBOX',
],
[
'key' => 'FOC-89',
'summary' => 'GDPR / AVG compliancy en geautomatiseerd data retentiebeleid',
'status' => 'In Progress',
'status_category' => 'indeterminate',
'priority' => 'Medium',
'issue_type' => 'Epic',
'project' => 'Security',
'project_key' => 'SEC',
'assignee_name' => 'Lisa Bakker',
'assignee_avatar' => '',
'due_date' => date('Y-m-d', strtotime('+14 days')),
'updated' => date('Y-m-d H:i:s', strtotime('-3 hours')),
'url' => 'https://jira.atlassian.net/browse/FOC-89',
'source' => 'SANDBOX',
],
[
'key' => 'FOC-82',
'summary' => 'Performance optimalisatie van vector avatar rendering in navigatiebalk',
'status' => 'Done',
'status_category' => 'done',
'priority' => 'Low',
'issue_type' => 'Task',
'project' => 'UI/UX Redesign',
'project_key' => 'UI',
'assignee_name' => 'Sophie de Vries',
'assignee_avatar' => '',
'due_date' => date('Y-m-d', strtotime('-3 days')),
'updated' => date('Y-m-d H:i:s', strtotime('-2 days')),
'url' => 'https://jira.atlassian.net/browse/FOC-82',
'source' => 'SANDBOX',
],
];
return [
'is_demo' => true,
'success' => true,
'domain' => 'sandbox.atlassian.net',
'email' => 'demo@fociz.nl',
'account_name' => 'Demo Account',
'last_sync_at' => date('Y-m-d H:i:s'),
'assigned_issues' => $assigned,
'team_issues' => $team,
];
}
@@ -288,56 +506,81 @@ function jira_get_user_issues(int $userId, bool $forceRefresh = false): array {
$domain = !empty($settings['jira_domain']) ? $settings['jira_domain'] : jira_get_company_domain();
$email = $settings['jira_email'] ?? fociz_env('JIRA_EMAIL', '');
$apiToken = $settings['jira_api_token'] ?? fociz_env('JIRA_API_TOKEN', '');
$accName = $settings['account_name'] ?? 'Atlassian Gebruiker';
if (empty($domain) || empty($email) || empty($apiToken)) {
return [
'is_demo' => false,
'success' => false,
'error' => 'Jira configuratie is onvolledig.',
'issues' => [],
'is_demo' => false,
'success' => false,
'error' => 'Jira configuratie is onvolledig. Controleer je instellingen.',
'assigned_issues' => [],
'team_issues' => [],
];
}
// Sessiecache voor 90 seconden om onnodige Jira API calls bij snelle pagina refreshes te beperken
// Sessiecache voor 60 seconden
if (session_status() === PHP_SESSION_NONE) {
@session_start();
}
$cacheKey = "jira_issues_user_{$userId}";
$cacheKey = "jira_dashboard_user_{$userId}";
$cached = $_SESSION[$cacheKey] ?? null;
if (!$forceRefresh && $cached && is_array($cached) && ($cached['timestamp'] ?? 0) > (time() - 90)) {
if (!$forceRefresh && $cached && is_array($cached) && ($cached['timestamp'] ?? 0) > (time() - 60)) {
return array_merge($cached['data'], ['from_cache' => true]);
}
// Ophalen van toegewezen taken
$assignedRes = jira_fetch_assigned_issues($domain, $email, $apiToken, 50);
// Ophalen van teamtaken
$teamRes = jira_fetch_team_issues($domain, $email, $apiToken, 50);
if (!$assignedRes['success'] && !$teamRes['success']) {
return [
'is_demo' => false,
'success' => true,
'issues' => $cached['issues'],
'from_cache' => true,
'is_demo' => false,
'success' => false,
'error' => $assignedRes['error'] ?? 'Kan Jira tickets niet ophalen.',
'assigned_issues' => [],
'team_issues' => [],
];
}
$result = jira_fetch_assigned_issues($domain, $email, $apiToken, 50);
$assignedIssues = $assignedRes['success'] ? $assignedRes['issues'] : [];
$teamIssues = $teamRes['success'] ? $teamRes['issues'] : [];
if ($result['success']) {
$_SESSION[$cacheKey] = [
'timestamp' => time(),
'issues' => $result['issues'],
];
$data = [
'is_demo' => false,
'success' => true,
'domain' => $domain,
'email' => $email,
'account_name' => $accName,
'last_sync_at' => date('Y-m-d H:i:s'),
'assigned_issues' => $assignedIssues,
'team_issues' => $teamIssues,
];
// Werk last_sync_at bij
$stmtUpdate = $db->prepare("UPDATE integrations SET last_sync_at = NOW() WHERE id = ?");
$stmtUpdate->execute([$integration['id']]);
$_SESSION[$cacheKey] = [
'timestamp' => time(),
'data' => $data,
];
return [
'is_demo' => false,
'success' => true,
'issues' => $result['issues'],
];
}
// Werk last_sync_at bij in database
$stmtUpdate = $db->prepare("UPDATE integrations SET last_sync_at = NOW() WHERE id = ?");
$stmtUpdate->execute([$integration['id']]);
return $data;
}
/**
* Haalt de Jira tickets op voor een Fociz gebruiker (backwards compatibility)
*/
function jira_get_user_issues(int $userId, bool $forceRefresh = false): array {
$data = jira_get_dashboard_data($userId, $forceRefresh);
return [
'is_demo' => false,
'success' => false,
'error' => $result['error'],
'issues' => [],
'is_demo' => $data['is_demo'] ?? false,
'success' => $data['success'] ?? false,
'error' => $data['error'] ?? null,
'issues' => $data['assigned_issues'] ?? [],
'from_cache' => $data['from_cache'] ?? false,
];
}
@@ -351,6 +594,8 @@ function jira_disconnect(int $userId): bool {
@session_start();
}
unset($_SESSION["jira_issues_user_{$userId}"]);
unset($_SESSION["jira_dashboard_user_{$userId}"]);
return $stmt->execute([$userId]);
}