198 lines
9.4 KiB
PHP
198 lines
9.4 KiB
PHP
<?php
|
|
// API: returns JSON events for FullCalendar
|
|
session_start();
|
|
require_once(__DIR__ . '/../inc/config.inc.php');
|
|
require_once(__DIR__ . '/../inc/functions.inc.php');
|
|
|
|
// Enable full error reporting for API debugging
|
|
ini_set('display_errors', '1');
|
|
ini_set('display_startup_errors', '1');
|
|
error_reporting(E_ALL);
|
|
|
|
$user = check_user();
|
|
$isAdmin = is_admin_user();
|
|
|
|
$start = $_GET['start'] ?? null; // expected ISO date
|
|
$end = $_GET['end'] ?? null;
|
|
$onlyApproved = isset($_GET['only_approved']) && ($_GET['only_approved'] == '1' || $_GET['only_approved'] === 'true');
|
|
// public allows non-admin users to request all *approved* vacations (team view)
|
|
$public = isset($_GET['public']) && ($_GET['public'] == '1' || $_GET['public'] === 'true');
|
|
// include_rejected if set to 1 will return rejected entries; default behavior: do not return rejected for regular users
|
|
$includeRejected = isset($_GET['include_rejected']) && ($_GET['include_rejected'] == '1' || $_GET['include_rejected'] === 'true');
|
|
// only_personal forces the API to return only the current user's vacations (useful even if the user is admin)
|
|
$onlyPersonal = isset($_GET['only_personal']) && ($_GET['only_personal'] == '1' || $_GET['only_personal'] === 'true');
|
|
// public_all when used with public=1 returns all non-rejected team vacations (approved + beantragt)
|
|
$publicAll = isset($_GET['public_all']) && ($_GET['public_all'] == '1' || $_GET['public_all'] === 'true');
|
|
|
|
if (!$start || !$end) {
|
|
http_response_code(400);
|
|
echo json_encode(['error' => 'start and end required']);
|
|
exit;
|
|
}
|
|
|
|
$events = [];
|
|
try {
|
|
$branch = 'unknown';
|
|
$debugMode = isset($_GET['debug']) && ($_GET['debug'] == '1' || $_GET['debug'] === 'true');
|
|
|
|
// Vacations: support a personal-only mode, admin mode, and public/team mode
|
|
if ($onlyPersonal) {
|
|
$branch = 'onlyPersonal';
|
|
if ($onlyApproved) {
|
|
$branch = 'onlyPersonal_onlyApproved';
|
|
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? AND LOWER(TRIM(v.status)) = 'genehmigt' ORDER BY v.start_date");
|
|
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
|
} else {
|
|
if ($includeRejected) {
|
|
$branch = 'onlyPersonal_includeRejected';
|
|
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? ORDER BY v.start_date");
|
|
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
|
} else {
|
|
$branch = 'onlyPersonal_excludeRejected';
|
|
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? AND (v.status IS NULL OR LOWER(TRIM(v.status)) != 'abgelehnt') ORDER BY v.start_date");
|
|
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
|
}
|
|
}
|
|
} elseif ($isAdmin) {
|
|
$branch = 'admin';
|
|
if ($onlyApproved) {
|
|
$branch = 'admin_onlyApproved';
|
|
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? AND LOWER(TRIM(v.status)) = 'genehmigt' ORDER BY v.start_date");
|
|
$stmt->execute([$end, $start]);
|
|
} else {
|
|
// By default admins see genehmigt + beantragt; include_rejected=1 can override
|
|
if ($includeRejected) {
|
|
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? ORDER BY v.start_date");
|
|
$stmt->execute([$end, $start]);
|
|
} else {
|
|
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? AND (v.status IS NULL OR LOWER(TRIM(v.status)) IN ('genehmigt','beantragt')) ORDER BY v.start_date");
|
|
$stmt->execute([$end, $start]);
|
|
}
|
|
}
|
|
} else {
|
|
$branch = 'public_or_regular';
|
|
if ($public && $onlyApproved) {
|
|
$branch = 'public_onlyApproved';
|
|
// public team view: show all approved vacations (read-only)
|
|
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? AND LOWER(TRIM(v.status)) = 'genehmigt' ORDER BY v.start_date");
|
|
$stmt->execute([$end, $start]);
|
|
} elseif ($public && $publicAll) {
|
|
$branch = 'public_publicAll';
|
|
// public team view: explicitly show only approved (genehmigt) and pending (beantragt) vacations
|
|
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? AND (v.status IS NULL OR LOWER(TRIM(v.status)) IN ('genehmigt','beantragt')) ORDER BY v.start_date");
|
|
$stmt->execute([$end, $start]);
|
|
} else {
|
|
if ($onlyApproved) {
|
|
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? AND LOWER(TRIM(v.status)) = 'genehmigt' ORDER BY v.start_date");
|
|
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
|
} else {
|
|
// By default exclude rejected ('abgelehnt') for regular users; include if include_rejected=1
|
|
if ($includeRejected) {
|
|
$branch = 'regular_includeRejected';
|
|
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? ORDER BY v.start_date");
|
|
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
|
} else {
|
|
$branch = 'regular_excludeRejected';
|
|
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? AND (v.status IS NULL OR LOWER(TRIM(v.status)) != 'abgelehnt') ORDER BY v.start_date");
|
|
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
try {
|
|
$vacations = $stmt->fetchAll();
|
|
|
|
// If debug mode is enabled, prepare meta information
|
|
if ($debugMode) {
|
|
$rawStatuses = array_map(function($r){ return $r['status'] ?? null; }, $vacations);
|
|
$meta = [
|
|
'branch' => $branch,
|
|
'count' => count($vacations),
|
|
'raw_statuses' => $rawStatuses
|
|
];
|
|
}
|
|
|
|
foreach ($vacations as $v) {
|
|
// Normalize status: collapse whitespace (including NBSP), trim, lowercase
|
|
if (isset($v['status'])) {
|
|
$normalized = preg_replace('/\s+/u', ' ', $v['status']);
|
|
$status = mb_strtolower(trim($normalized));
|
|
} else {
|
|
$status = '';
|
|
}
|
|
// Defensive filter: do not expose rejected ('abgelehnt') entries to non-admins
|
|
if (!$isAdmin && !$includeRejected && mb_stripos($status, 'abgelehnt') !== false) {
|
|
continue;
|
|
}
|
|
$isApproved = (mb_stripos($status, 'genehmigt') !== false);
|
|
if ($isAdmin) {
|
|
$title = $v['vorname'] . ' ' . $v['nachname'] . ' (' . ($v['status'] ?? 'beantragt') . ')';
|
|
} else {
|
|
$title = $isApproved ? 'Urlaub' : 'Urlaubsantrag';
|
|
}
|
|
// Safely compute end date; fallback to start_date if invalid
|
|
try {
|
|
$endInclusive = (new DateTime($v['end_date']))->modify('+1 day')->format('Y-m-d');
|
|
} catch (Exception $e) {
|
|
$endInclusive = $v['start_date'];
|
|
}
|
|
$events[] = [
|
|
'id' => 'vac_' . $v['id'],
|
|
'title' => $title,
|
|
'start' => $v['start_date'],
|
|
'end' => $endInclusive,
|
|
'allDay' => true,
|
|
'color' => ($isApproved) ? '#28a745' : '#ffc107',
|
|
'extendedProps' => [
|
|
'type' => 'user',
|
|
'user_id' => $v['user_id'],
|
|
'status' => $v['status'],
|
|
'comment' => $v['comment_user'] ?? ''
|
|
]
|
|
];
|
|
}
|
|
} catch (Exception $ex) {
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
$payload = ['error' => $ex->getMessage(), 'branch' => $branch, 'trace' => $ex->getTraceAsString()];
|
|
echo json_encode($payload);
|
|
exit;
|
|
}
|
|
|
|
} catch (Exception $ex) {
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
$payload = ['error' => $ex->getMessage(), 'branch' => $branch, 'trace' => $ex->getTraceAsString()];
|
|
echo json_encode($payload);
|
|
exit;
|
|
}
|
|
|
|
// Company holidays (visible to all)
|
|
$stmt = $pdo->prepare("SELECT * FROM company_holidays WHERE start_date <= ? AND end_date >= ? ORDER BY start_date");
|
|
$stmt->execute([$end, $start]);
|
|
$holidays = $stmt->fetchAll();
|
|
|
|
foreach ($holidays as $h) {
|
|
$endInclusive = (new DateTime($h['end_date']))->modify('+1 day')->format('Y-m-d');
|
|
$events[] = [
|
|
'id' => 'com_' . $h['id'],
|
|
'title' => $h['description'] ?: 'Betriebsurlaub',
|
|
'start' => $h['start_date'],
|
|
'end' => $endInclusive,
|
|
'allDay' => true,
|
|
'color' => '#007bff',
|
|
'extendedProps' => [
|
|
'type' => 'company',
|
|
'description' => $h['description']
|
|
]
|
|
];
|
|
}
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
if ($debugMode) {
|
|
echo json_encode(['events' => $events, 'meta' => $meta]);
|
|
} else {
|
|
echo json_encode($events);
|
|
}
|
|
|
|
?>
|