Jira fix
This commit is contained in:
+70
-6
@@ -129,6 +129,12 @@ function fociz_log_audit(?int $userId, string $action, string $resourceType = ''
|
||||
$statusNormalized,
|
||||
$createdAt
|
||||
]);
|
||||
|
||||
// Bewaartermijn audit logs: 3 maanden (90 dagen)
|
||||
// Voer periodiek (1 op de 20 log-acties) een automatische opschoning uit
|
||||
if (mt_rand(1, 20) === 1) {
|
||||
$db->exec("DELETE FROM audit_logs WHERE created_at < NOW() - INTERVAL 90 DAY");
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
// Audit log mag NOOIT de applicatiewerking breken
|
||||
error_log("fociz_log_audit failure: " . $e->getMessage());
|
||||
@@ -419,6 +425,36 @@ function fociz_get_device_name(?string $userAgent): string {
|
||||
return "{$browser} op {$platform}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Ruimt verlopen sessies op en beperkt het aantal sessies per gebruiker tot maximaal 20 (FIFO / oldest out)
|
||||
*/
|
||||
function fociz_cleanup_user_sessions(PDO $db, int $userId): void {
|
||||
try {
|
||||
// 1. Markeer sessies waarvan de geldigheidsduur is verstreken direct als inactief
|
||||
$stmtExp = $db->prepare("UPDATE user_sessions SET is_active = 0 WHERE user_id = ? AND is_active = 1 AND expires_at < NOW()");
|
||||
$stmtExp->execute([$userId]);
|
||||
|
||||
// 2. Beperk tot maximaal 20 sessies per gebruiker (FIFO: behoud de 20 meest recente, ruim oudere op)
|
||||
$stmtLimit = $db->prepare("
|
||||
SELECT id FROM user_sessions
|
||||
WHERE user_id = ?
|
||||
ORDER BY last_activity_at DESC, id DESC
|
||||
LIMIT 20, 200
|
||||
");
|
||||
$stmtLimit->execute([$userId]);
|
||||
$excessIds = $stmtLimit->fetchAll(PDO::FETCH_COLUMN);
|
||||
if (!empty($excessIds)) {
|
||||
$inClause = implode(',', array_map('intval', $excessIds));
|
||||
$db->exec("DELETE FROM user_sessions WHERE id IN ($inClause)");
|
||||
}
|
||||
|
||||
// 3. Verwijder inactieve/verlopen sessies ouder dan 7 dagen over de gehele tabel
|
||||
$db->exec("DELETE FROM user_sessions WHERE is_active = 0 AND (expires_at < NOW() - INTERVAL 7 DAY OR last_activity_at < NOW() - INTERVAL 7 DAY)");
|
||||
} catch (Throwable $e) {
|
||||
error_log("fociz_cleanup_user_sessions error: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registreert of vernieuwt een actieve sessie in user_sessions (SOC 2 CC6.1 / ISO 27001 A.9.4.2)
|
||||
*/
|
||||
@@ -447,8 +483,8 @@ function fociz_register_active_session(int $userId, string $sessionId, int $maxI
|
||||
");
|
||||
$stmt->execute([$userId, $hash, $ip, $ua, $deviceName, $expiresAt]);
|
||||
|
||||
// Verwijder oude verlopen sessies (> 7 dagen geleden verlopen)
|
||||
$db->exec("DELETE FROM user_sessions WHERE expires_at < NOW() - INTERVAL 7 DAY");
|
||||
// Ruim verlopen sessies op en handhaaf max 20 sessies
|
||||
fociz_cleanup_user_sessions($db, $userId);
|
||||
} catch (Throwable $e) {
|
||||
error_log("fociz_register_active_session error: " . $e->getMessage());
|
||||
}
|
||||
@@ -505,7 +541,14 @@ function fociz_is_session_active(string $sessionId, int $userId): bool {
|
||||
fociz_register_active_session($userId, $sessionId, $maxIdleSeconds);
|
||||
return true;
|
||||
}
|
||||
return (!empty($row['is_active']));
|
||||
if (empty($row['is_active'])) {
|
||||
return false;
|
||||
}
|
||||
if (!empty($row['expires_at']) && strtotime($row['expires_at']) < time()) {
|
||||
$db->prepare("UPDATE user_sessions SET is_active = 0 WHERE session_id_hash = ?")->execute([$hash]);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (Throwable $e) {
|
||||
return true; // Fallback op toegestaan bij databaseverstoring
|
||||
}
|
||||
@@ -567,7 +610,7 @@ function fociz_revoke_session_by_id(int $userId, int $sessionDbId): bool {
|
||||
}
|
||||
|
||||
/**
|
||||
* Haalt alle actieve sessies van een gebruiker op voor de profielpagina
|
||||
* Haalt alle actieve sessies van een gebruiker op voor de profielpagina (maximaal 20, actieve expiratiedatum)
|
||||
*/
|
||||
function fociz_get_user_active_sessions(int $userId, string $currentSessionId): array {
|
||||
try {
|
||||
@@ -575,14 +618,35 @@ function fociz_get_user_active_sessions(int $userId, string $currentSessionId):
|
||||
ensure_sessions_table($db);
|
||||
$currentHash = hash('sha256', $currentSessionId);
|
||||
|
||||
// Voer direct opschoning uit: deactiveer verlopen sessies en handhaaf limiet van max 20
|
||||
fociz_cleanup_user_sessions($db, $userId);
|
||||
|
||||
$stmt = $db->prepare("
|
||||
SELECT id, ip_address, user_agent, device_name, last_activity_at, created_at, (session_id_hash = ?) AS is_current
|
||||
FROM user_sessions
|
||||
WHERE user_id = ? AND is_active = 1
|
||||
WHERE user_id = ? AND is_active = 1 AND expires_at >= NOW()
|
||||
ORDER BY is_current DESC, last_activity_at DESC
|
||||
LIMIT 20
|
||||
");
|
||||
$stmt->execute([$currentHash, $userId]);
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
|
||||
$sessions = $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
|
||||
|
||||
// Zorg dat het huidige apparaat altijd geregistreerd staat als actief
|
||||
$hasCurrent = false;
|
||||
foreach ($sessions as $s) {
|
||||
if (!empty($s['is_current'])) {
|
||||
$hasCurrent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$hasCurrent && !empty($currentSessionId)) {
|
||||
$maxIdleSeconds = function_exists('get_session_idle_timeout') ? get_session_idle_timeout() : 1800;
|
||||
fociz_register_active_session($userId, $currentSessionId, $maxIdleSeconds);
|
||||
$stmt->execute([$currentHash, $userId]);
|
||||
$sessions = $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
|
||||
}
|
||||
|
||||
return $sessions;
|
||||
} catch (Throwable $e) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -331,6 +331,82 @@ function jira_fetch_statuses(string $domain, string $email, string $apiToken): a
|
||||
return $statuses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Haalt project-specifieke statussen op uit Jira Cloud voor een specifiek project
|
||||
*/
|
||||
function jira_fetch_project_statuses(string $domain, string $email, string $apiToken, string $projectKey): array {
|
||||
$cleanDomain = jira_normalize_domain($domain);
|
||||
$pKey = strtoupper(trim($projectKey));
|
||||
if (empty($cleanDomain) || empty($email) || empty($apiToken) || empty($pKey)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$cacheKey = "jira_proj_statuses_" . $pKey . "_" . md5($cleanDomain);
|
||||
$cached = fociz_cache_get($cacheKey);
|
||||
if (is_array($cached) && !empty($cached)) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
$authHeader = jira_get_auth_header($email, $apiToken);
|
||||
$url = $cleanDomain . '/rest/api/3/project/' . rawurlencode($pKey) . '/statuses';
|
||||
|
||||
$response = fociz_http_request($url, [
|
||||
'method' => 'GET',
|
||||
'headers' => [
|
||||
'Authorization' => $authHeader,
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
'timeout' => 8,
|
||||
]);
|
||||
|
||||
if ($response['status'] === 404 || $response['status'] === 405) {
|
||||
$urlV2 = $cleanDomain . '/rest/api/2/project/' . rawurlencode($pKey) . '/statuses';
|
||||
$response = fociz_http_request($urlV2, [
|
||||
'method' => 'GET',
|
||||
'headers' => [
|
||||
'Authorization' => $authHeader,
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
'timeout' => 8,
|
||||
]);
|
||||
}
|
||||
|
||||
$statuses = [];
|
||||
if ($response['status'] === 200 && is_array($response['json'])) {
|
||||
foreach ($response['json'] as $issueType) {
|
||||
if (!empty($issueType['statuses']) && is_array($issueType['statuses'])) {
|
||||
foreach ($issueType['statuses'] as $st) {
|
||||
$sName = trim($st['name'] ?? '');
|
||||
if (empty($sName)) continue;
|
||||
$sKey = strtolower($sName);
|
||||
$catKey = strtolower($st['statusCategory']['key'] ?? 'indeterminate');
|
||||
$catName = $st['statusCategory']['name'] ?? 'In uitvoering';
|
||||
$statuses[$sKey] = [
|
||||
'id' => (string)($st['id'] ?? ''),
|
||||
'name' => $sName,
|
||||
'description' => $st['description'] ?? '',
|
||||
'status_category' => $catKey,
|
||||
'category_name' => $catName,
|
||||
'color' => $st['statusCategory']['colorName'] ?? '',
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
$statuses = array_values($statuses);
|
||||
usort($statuses, function($a, $b) {
|
||||
$order = ['new' => 1, 'indeterminate' => 2, 'done' => 3];
|
||||
$oa = $order[$a['status_category']] ?? 2;
|
||||
$ob = $order[$b['status_category']] ?? 2;
|
||||
if ($oa !== $ob) return $oa - $ob;
|
||||
return strcasecmp($a['name'], $b['name']);
|
||||
});
|
||||
|
||||
fociz_cache_set($cacheKey, $statuses, 3600);
|
||||
}
|
||||
|
||||
return $statuses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Haalt issues op via een flexibele JQL query via Atlassian REST API
|
||||
*/
|
||||
@@ -974,6 +1050,34 @@ function jira_get_dashboard_data(int $userId, bool $forceRefresh = false): array
|
||||
],
|
||||
];
|
||||
|
||||
$demoProjectStatuses = [
|
||||
'SD' => [
|
||||
['id' => '1', 'name' => 'To Do', 'status_category' => 'new', 'category_name' => 'Nieuw'],
|
||||
['id' => '2', 'name' => 'In behandeling', 'status_category' => 'indeterminate', 'category_name' => 'In uitvoering'],
|
||||
['id' => '3', 'name' => 'Wachten op klant', 'status_category' => 'indeterminate', 'category_name' => 'In uitvoering'],
|
||||
['id' => '4', 'name' => 'Gesloten', 'status_category' => 'done', 'category_name' => 'Gereed'],
|
||||
],
|
||||
'IN' => [
|
||||
['id' => '10', 'name' => 'Nieuw', 'status_category' => 'new', 'category_name' => 'Nieuw'],
|
||||
['id' => '11', 'name' => 'In behandeling', 'status_category' => 'indeterminate', 'category_name' => 'In uitvoering'],
|
||||
['id' => '12', 'name' => 'In Review', 'status_category' => 'indeterminate', 'category_name' => 'In uitvoering'],
|
||||
['id' => '13', 'name' => 'Gereed', 'status_category' => 'done', 'category_name' => 'Gereed'],
|
||||
['id' => '14', 'name' => 'Gesloten', 'status_category' => 'done', 'category_name' => 'Gereed'],
|
||||
],
|
||||
'AAN' => [
|
||||
['id' => '20', 'name' => 'Nieuw', 'status_category' => 'new', 'category_name' => 'Nieuw'],
|
||||
['id' => '21', 'name' => 'In behandeling', 'status_category' => 'indeterminate', 'category_name' => 'In uitvoering'],
|
||||
['id' => '22', 'name' => 'Goedgekeurd', 'status_category' => 'indeterminate', 'category_name' => 'In uitvoering'],
|
||||
['id' => '23', 'name' => 'Afgewezen', 'status_category' => 'done', 'category_name' => 'Gereed'],
|
||||
['id' => '24', 'name' => 'Gesloten', 'status_category' => 'done', 'category_name' => 'Gereed'],
|
||||
],
|
||||
'GEN' => [
|
||||
['id' => '30', 'name' => 'To Do', 'status_category' => 'new', 'category_name' => 'Nieuw'],
|
||||
['id' => '31', 'name' => 'In Progress', 'status_category' => 'indeterminate', 'category_name' => 'In uitvoering'],
|
||||
['id' => '32', 'name' => 'Done', 'status_category' => 'done', 'category_name' => 'Gereed'],
|
||||
],
|
||||
];
|
||||
|
||||
return [
|
||||
'is_demo' => true,
|
||||
'success' => true,
|
||||
@@ -987,6 +1091,7 @@ function jira_get_dashboard_data(int $userId, bool $forceRefresh = false): array
|
||||
'default_queue_filter' => $userQueuePref,
|
||||
'user_queue_filters' => $userQueuePrefs,
|
||||
'available_statuses' => $demoStatuses,
|
||||
'project_statuses' => $demoProjectStatuses,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1041,6 +1146,23 @@ function jira_get_dashboard_data(int $userId, bool $forceRefresh = false): array
|
||||
$assignedIssues = $assignedRes['success'] ? $assignedRes['issues'] : [];
|
||||
$teamIssues = $teamRes['success'] ? $teamRes['issues'] : [];
|
||||
|
||||
// Project-specifieke statussen ophalen voor gebruikte projecten
|
||||
$activeProjKeys = ['SD', 'IN', 'AAN', 'GEN'];
|
||||
$allLoaded = array_merge($assignedIssues, $teamIssues);
|
||||
foreach ($allLoaded as $iss) {
|
||||
$pk = strtoupper(trim($iss['project_key'] ?? ''));
|
||||
if (!empty($pk) && !in_array($pk, $activeProjKeys, true)) {
|
||||
$activeProjKeys[] = $pk;
|
||||
}
|
||||
}
|
||||
$projectStatusesMap = [];
|
||||
foreach ($activeProjKeys as $pk) {
|
||||
$pStats = jira_fetch_project_statuses($domain, $email, $apiToken, $pk);
|
||||
if (!empty($pStats)) {
|
||||
$projectStatusesMap[$pk] = $pStats;
|
||||
}
|
||||
}
|
||||
|
||||
$data = [
|
||||
'is_demo' => false,
|
||||
'success' => true,
|
||||
@@ -1054,6 +1176,7 @@ function jira_get_dashboard_data(int $userId, bool $forceRefresh = false): array
|
||||
'default_queue_filter' => $userQueuePref,
|
||||
'user_queue_filters' => $userQueuePrefs,
|
||||
'available_statuses' => $availableStatuses,
|
||||
'project_statuses' => $projectStatusesMap,
|
||||
];
|
||||
|
||||
fociz_cache_set($cacheKey, $data, 60);
|
||||
|
||||
Reference in New Issue
Block a user