This commit is contained in:
2026-03-20 17:13:38 +01:00
parent 4c84735b75
commit c043ee9a52
1152 changed files with 317560 additions and 0 deletions
+134
View File
@@ -0,0 +1,134 @@
<?php
//Since this page writes to a session, initialise it here
session_start();
if ($_SERVER["REQUEST_METHOD"] == "POST" && $_POST["action"] == "PDF anzeigen") {
// Weiterleitung zur createPDF.php mit den Parametern
$userId = $_POST["user"];
$selectedMonth = $_POST["month"];
$monthYear = explode("/", $selectedMonth);
$month = $monthYear[0];
$year = $monthYear[1];
// Weiterleitung zur createPDF.php mit den Parametern
# echo "Location: createPDF.php?id=$userId&month=$month&year=$year";
header("Location: createPDF.php?id=$userId&month=$month&year=$year");
exit();
}
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");
//Überprüfe, dass der User eingeloggt ist
//Der Aufruf von check_user() muss in alle internen Seiten eingebaut sein
$user = check_user();
?>
<?php include 'header.php'; ?>
<div class="container">
<div class="row">
<div class="col-md-12">
<?php
// Überprüfen, ob eine Benutzer-ID in der Session vorhanden ist
if (!isset($_SESSION['userid'])) {
die("Kein Benutzer angemeldet.");
}
$user_id = $_SESSION['userid'];
// Monate für den Dropdown-Menü erhalten
try {
$months_stmt = $pdo->prepare("SELECT DISTINCT MONTH(timestamp_datetime) as month, YEAR(timestamp_datetime) as year FROM timestamps WHERE employee_id = ? ORDER BY timestamp_datetime DESC");
$months_stmt->bindParam(1, $user_id);
$months_stmt->execute();
$months = $months_stmt->fetchAll(PDO::FETCH_ASSOC);
} catch(PDOException $e) {
echo "Datenbankfehler: " . $e->getMessage();
}
$selectedMonth = $_POST['month'] ?? '';
#$selectedYear = $_POST['year'] ?? '';
// Zeiten für den ausgewählten Monat erhalten
if ($selectedMonth ) {
try {
$selectedYear = explode('/',$selectedMonth)[1];
$times_stmt = $pdo->prepare("SELECT timestamp_datetime, timestamp_type FROM timestamps WHERE employee_id = ? AND MONTH(timestamp_datetime) = ? AND YEAR(timestamp_datetime) = ? ORDER BY timestamp_datetime ASC");
$times_stmt->bindParam(1, $user_id);
$times_stmt->bindParam(2, $selectedMonth);
$times_stmt->bindParam(3, $selectedYear);
$times_stmt->execute();
$times = $times_stmt->fetchAll(PDO::FETCH_ASSOC);
} catch(PDOException $e) {
echo "Datenbankfehler: " . $e->getMessage();
}
// Gruppieren der Zeiten nach Tagen
$groupedTimes = [];
foreach ($times as $time) {
$date = date('Y-m-d', strtotime($time['timestamp_datetime']));
$groupedTimes[$date][] = $time;
}
}
?>
<h2>Zeitenübersicht</h2>
<form method="post" action="<?php echo $_SERVER['PHP_SELF'];?>">
<div class="form-group">
<label for="month">Monat auswählen:</label>
<select name="month" id="month" class="form-control">
<?php foreach ($months as $month): ?>
<option value="<?php echo $month['month'] . '/' . $month['year']; ?>" <?php if ($month['month'] == $selectedMonth && $month['year'] == $selectedYear) echo 'selected'; ?>>
<?php echo $month['month'] . '/' . $month['year']; ?>
</option>
<?php endforeach; ?>
</select>
<br><br>
<input type="submit" value="Zeiten anzeigen" class="btn btn-primary btn-lg">
<!-- Button zum Anzeigen der PDF -->
<input type="submit" name="action" value="PDF anzeigen" class="btn btn-primary btn-lg" formtarget="_blank">
</div>
</form>
<?php if ($selectedMonth): ?>
<table class="table table-striped table-hover">
<tr>
<th>Datum</th>
<th>Typ</th>
<th>Aktionen</th>
</tr>
<?php foreach ($groupedTimes as $date => $times): ?>
<tr>
<td><?php echo date('d.m.Y', strtotime($date)); ?></td>
<td>
<?php foreach ($times as $time): ?>
<div><?php echo date('H:i:s', strtotime($time['timestamp_datetime'])) . ' - ' . $time['timestamp_type']; ?></div>
<?php endforeach; ?>
</td>
<td>
<!-- Hier können Sie Aktionen für jeden Tag hinzufügen, z.B. Bearbeiten/Löschen des gesamten Tages -->
<a href="editDayEntries.php?employee_id=<?php echo $user_id; ?>&datum=<?php echo date('Y-m-d', strtotime($time['timestamp_datetime'])); ?>" class="btn btn-primary">Anpassen</a>
</td>
</tr>
<?php endforeach; ?>
</table>
<?php endif; ?>
</div>
</div>
</div>
<?php include 'footer.php'; ?>
+153
View File
@@ -0,0 +1,153 @@
<?php
//Since this page writes to a session, initialise it here
session_start();
if ($_SERVER["REQUEST_METHOD"] == "POST") {
// Überprüfen, welcher Button geklickt wurde
if ($_POST["action"] == "PDF anzeigen") {
// Weiterleitung zur createPDF.php mit den Parametern
$userId = $_POST["user"];
$selectedMonth = $_POST["month"];
$monthYear = explode("/", $selectedMonth);
$month = $monthYear[0];
$year = $monthYear[1];
// Weiterleitung zur createPDF.php mit den Parametern
# echo "Location: createPDF.php?id=$userId&month=$month&year=$year";
header("Location: createPDF.php?id=$userId&month=$month&year=$year");
exit();
}
}
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");
//Überprüfe, dass der User eingeloggt ist
//Der Aufruf von check_user() muss in alle internen Seiten eingebaut sein
$user = check_user();
?>
<?php include 'header.php'; ?>
<div class="container">
<div class="row">
<div class="col-md-12">
<?php
// Starten der Session, falls noch nicht geschehen
if(session_status() === PHP_SESSION_NONE) session_start();
// Überprüfen, ob eine Benutzer-ID in der Session vorhanden ist
if (!isset($_SESSION['userid'])) {
die("Kein Benutzer angemeldet.");
}
$user_id = $_SESSION['userid'];
// Benutzer aus der Datenbank erhalten
try {
$users_stmt = $pdo->prepare("SELECT id,vorname, nachname FROM users WHERE zeiterfassung='1' ORDER BY nachname ASC");
$users_stmt->execute();
$users = $users_stmt->fetchAll(PDO::FETCH_ASSOC);
} catch(PDOException $e) {
echo "Datenbankfehler: " . $e->getMessage();
}
// Monate für den Dropdown-Menü erhalten
try {
// Hier sollte die Abfrage angepasst werden, um auf den ausgewählten Benutzer zu filtern
$months_stmt = $pdo->prepare("SELECT DISTINCT MONTH(timestamp_datetime) as month, YEAR(timestamp_datetime) as year FROM timestamps ORDER BY timestamp_datetime DESC");
#$months_stmt->bindParam(1, $user_id);
$months_stmt->execute();
$months = $months_stmt->fetchAll(PDO::FETCH_ASSOC);
} catch(PDOException $e) {
echo "Datenbankfehler: " . $e->getMessage();
}
$selectedUser = $_POST['user'] ?? $user_id; // Standardmäßig der angemeldete Benutzer
$selectedMonth = $_POST['month'] ?? '';
// Zeiten für den ausgewählten Monat und Benutzer erhalten
if ($selectedMonth && $selectedUser) {
try {
$selectedYear = explode('/',$selectedMonth)[1];
$times_stmt = $pdo->prepare("SELECT timestamp_datetime, timestamp_type FROM timestamps WHERE employee_id = ? AND MONTH(timestamp_datetime) = ? AND YEAR(timestamp_datetime) = ? ORDER BY timestamp_datetime ASC");
$times_stmt->bindParam(1, $selectedUser);
$times_stmt->bindParam(2, explode('/', $selectedMonth)[0]); // Monat extrahieren
$times_stmt->bindParam(3, $selectedYear);
$times_stmt->execute();
$times = $times_stmt->fetchAll(PDO::FETCH_ASSOC);
} catch(PDOException $e) {
echo "Datenbankfehler: " . $e->getMessage();
}
// Gruppieren der Zeiten nach Tagen
$groupedTimes = [];
foreach ($times as $time) {
$date = date('Y-m-d', strtotime($time['timestamp_datetime']));
$groupedTimes[$date][] = $time;
}
}
?>
<h2>Zeitenübersicht</h2>
<form method="post" action="<?php echo $_SERVER['PHP_SELF'];?>">
<div class="form-group">
<label for="user">Benutzer auswählen:</label>
<select name="user" id="user" class="form-control">
<?php foreach ($users as $user): ?>
<option value="<?php echo $user['id']; ?>" <?php if ($user['id'] == $selectedUser) echo 'selected'; ?>>
<?php echo htmlspecialchars($user['vorname']); ?> <?php echo htmlspecialchars($user['nachname']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group">
<label for="month">Monat auswählen:</label>
<select name="month" id="month" class="form-control">
<?php foreach ($months as $month): ?>
<option value="<?php echo $month['month'] . '/' . $month['year']; ?>" <?php if ($month['month'] . '/' . $month['year'] == $selectedMonth) echo 'selected'; ?>>
<?php echo $month['month'] . '/' . $month['year']; ?>
</option>
<?php endforeach; ?>
</select>
</div>
<br>
<input type="submit" value="Zeiten anzeigen" class="btn btn-primary btn-lg">
<!-- Button zum Anzeigen der PDF -->
<input type="submit" name="action" value="PDF anzeigen" class="btn btn-primary btn-lg" formtarget="_blank">
</form>
<?php if ($selectedMonth && $selectedUser): ?>
<table class="table table-striped table-hover">
<tr>
<th>Datum</th>
<th>Typ</th>
<th>Aktionen</th>
</tr>
<?php foreach ($groupedTimes as $date => $times): ?>
<tr>
<td><?php echo date('d.m.Y', strtotime($date)); ?></td>
<td>
<?php foreach ($times as $time): ?>
<div><?php echo date('H:i:s', strtotime($time['timestamp_datetime'])) . ' - ' . $time['timestamp_type']; ?></div>
<?php endforeach; ?>
</td>
<td>
<a href="editDayEntries.php?employee_id=<?php echo $selectedUser; ?>&datum=<?php echo date('Y-m-d', strtotime($time['timestamp_datetime'])); ?>" class="btn btn-primary">Anpassen</a>
</td>
</tr>
<?php endforeach; ?>
</table>
<?php endif; ?>
</div>
</div>
</div>
<?php include 'footer.php'; ?>
+170
View File
@@ -0,0 +1,170 @@
<?php
session_start();
require_once('./../admin/tcpdf/tcpdf.php');
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");
// Überprüfen, ob eine Benutzer-ID in der Session vorhanden ist
if (!isset($_SESSION['userid'])) {
die("Kein Benutzer angemeldet.");
}
$user_id = $_SESSION['userid'];
$user = check_user();
?>
<?php include 'header.php'; ?>
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="container">
<h2 class="mb-4">Zeitbuchungsfehler Auswertung</h2>
<?php
// Benutzer aus der Datenbank erhalten
try {
$users_stmt = $pdo->prepare("SELECT id,vorname, nachname FROM users WHERE zeiterfassung='1' ORDER BY nachname ASC");
$users_stmt->execute();
$users = $users_stmt->fetchAll(PDO::FETCH_ASSOC);
} catch(PDOException $e) {
echo "Datenbankfehler: " . $e->getMessage();
}
foreach($users AS $user){
try {
// Holen Sie die fehlerhaften Zeitbuchungen des Mitarbeiters aus der Datenbank
$query = "
SELECT
DATE(timestamp_datetime) as datum,
SUM(CASE WHEN timestamp_type = 'KOMMEN' THEN 1 ELSE 0 END) as kommen_count,
SUM(CASE WHEN timestamp_type = 'GEHEN' THEN 1 ELSE 0 END) as gehen_count
FROM
timestamps
WHERE
employee_id = :employee_id
GROUP BY
DATE(timestamp_datetime)
HAVING
kommen_count != gehen_count";
$stmt = $pdo->prepare($query);
$stmt->bindParam(':employee_id', $user["id"], PDO::PARAM_INT);
$stmt->execute();
$fehlerhafteTage = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch(PDOException $e) {
echo "Datenbankfehler: " . $e->getMessage();
}
try {
$query2 = "
SELECT
DATE(timestamp_datetime) AS datum,
GROUP_CONCAT(timestamp_type ORDER BY timestamp_datetime) AS day_sequence
FROM
timestamps
WHERE
employee_id = :employee_id
GROUP BY
DATE(timestamp_datetime);";
$stmt = $pdo->prepare($query2);
$stmt->bindParam(':employee_id', $user["id"], PDO::PARAM_INT);
$stmt->execute();
$result = $stmt->fetchAll();
$invalidDates = [];
} catch(PDOException $e) {
echo "Datenbankfehler: " . $e->getMessage();
}
try {
$query1 = "
SELECT
vorname,
nachname
FROM
users
WHERE
id = :employee_id
ORDER BY
nachname
";
$stmt = $pdo->prepare($query1);
$stmt->bindParam(':employee_id', $user["id"], PDO::PARAM_INT);
$stmt->execute();
$userdaten = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch(PDOException $e) {
echo "Datenbankfehler: " . $e->getMessage();
}
foreach ($userdaten as $usertag){
echo "<h5>" . $usertag["vorname"] . " " . $usertag["nachname"] . "</h5>";
}
foreach ($result as $row) {
if (!isValidSequence($row["day_sequence"])) {
$invalidDates[] = $row["datum"];
}
}
?>
<?php if (!empty($invalidDates)): ?>
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th>Datum</th>
<th>Fehler</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
<?php foreach ($invalidDates as $date): ?>
<tr>
<td><?php echo date('d.m.Y', strtotime($date)); ?></td>
<td>Fehlerhafte Daten</td>
<td>
<a href="editDayEntries.php?employee_id=<?php echo $user['id']; ?>&datum=<?php echo $date; ?>" class="btn btn-warning">Anpassen</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php else: ?>
<div class="alert alert-info" role="alert">
Keine Zeitbuchungsfehler gefunden.
</div>
<?php endif; ?>
<?php
}
?>
</div>
</div>
</div>
</div>
<?php include 'footer.php'; ?>
+197
View File
@@ -0,0 +1,197 @@
<?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);
}
?>
+105
View File
@@ -0,0 +1,105 @@
<?php
session_start();
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");
$user = check_user();
if (!is_admin_user()) {
die('Zugriff verweigert. Nur Chefs dürfen Anträge genehmigen.');
}
// Handle approve/reject actions
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['id']) && isset($_POST['action'])) {
$id = (int)$_POST['id'];
$action = $_POST['action'];
if ($action === 'approve') {
$stmt = $pdo->prepare("UPDATE vacations SET status = 'genehmigt', approved_by = ?, approved_at = NOW() WHERE id = ?");
$stmt->execute([$_SESSION['userid'], $id]);
} elseif ($action === 'reject') {
$stmt = $pdo->prepare("UPDATE vacations SET status = 'abgelehnt', approved_by = ?, approved_at = NOW() WHERE id = ?");
$stmt->execute([$_SESSION['userid'], $id]);
} elseif ($action === 'delete' && is_admin_user()) {
$del = $pdo->prepare("DELETE FROM vacations WHERE id = ?");
$del->execute([$id]);
}
header('Location: approveVacation.php');
exit();
}
include 'header.php';
// List pending and recent requests
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname, u.email FROM vacations v JOIN users u ON v.user_id = u.id ORDER BY v.created_at DESC");
$stmt->execute();
$requests = $stmt->fetchAll();
?>
<div class="container">
<h2>Urlaubsanträge - Genehmigung</h2>
<table class="table table-bordered">
<thead>
<tr>
<th>Mitarbeiter</th>
<th>Von</th>
<th>Bis</th>
<th>Tage</th>
<th>Kommentar</th>
<th>Status</th>
<th>Aktion</th>
</tr>
</thead>
<tbody>
<?php foreach ($requests as $r): ?>
<tr>
<td><?php echo htmlspecialchars($r['vorname'] . ' ' . $r['nachname']); ?></td>
<td><?php echo $r['start_date']; ?></td>
<td><?php echo $r['end_date']; ?></td>
<td><?php echo $r['days']; ?></td>
<td><?php echo htmlspecialchars($r['comment_user']); ?></td>
<td>
<?php
if ($r['status'] === 'beantragt' || $r['status'] === null) {
echo '<span class="badge badge-warning">Beantragt</span>';
} elseif ($r['status'] === 'genehmigt') {
echo '<span class="badge badge-success">Genehmigt</span>';
} else {
echo '<span class="badge badge-danger">Abgelehnt</span>';
}
?>
</td>
<td>
<?php if ($r['status'] !== 'genehmigt'): ?>
<form method="post" style="display:inline-block; margin-right:6px;">
<input type="hidden" name="id" value="<?php echo $r['id']; ?>">
<input type="hidden" name="action" value="approve">
<button class="btn btn-sm btn-success" type="submit">Genehmigen</button>
</form>
<?php endif; ?>
<?php if ($r['status'] !== 'abgelehnt'): ?>
<form method="post" style="display:inline-block;">
<input type="hidden" name="id" value="<?php echo $r['id']; ?>">
<input type="hidden" name="action" value="reject">
<button class="btn btn-sm btn-danger" type="submit">Ablehnen</button>
</form>
<?php endif; ?>
<form method="post" style="display:inline-block; margin-left:6px;" onsubmit="return confirm('Wirklich löschen?');">
<input type="hidden" name="id" value="<?php echo $r['id']; ?>">
<input type="hidden" name="action" value="delete">
<button class="btn btn-sm btn-outline-danger" type="submit">Löschen</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php include 'footer.php';
?>
+98
View File
@@ -0,0 +1,98 @@
<?php
session_start();
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");
//Überprüfe, dass der User eingeloggt ist
//Der Aufruf von check_user() muss in alle internen Seiten eingebaut sein
$user = check_user();
?>
<?php include 'header.php'; ?>
<div class="container">
<div class="row">
<div class="col-md-12">
<h2>Stempelkarten-System</h2>
<?php
// Überprüfen, ob eine Benutzer-ID in der Session vorhanden ist
if (!isset($_SESSION['userid'])) {
die("Kein Benutzer angemeldet.");
}
#$mitarbeiterId = $_GET['employee_id'] ?? null;
#$gewaehlterTag = $_GET['datum'] ?? null;
$mitarbeiterId = $_SESSION['userid']; // Angenommen, die Mitarbeiter-ID kommt aus der Session
$gewaehlterMonat = '2024-01'; // Format: YYYY-MM
$tageImMonat = date('t', strtotime($gewaehlterMonat . '-01'));
$zeitenProTag = [];
for($tag = 1; $tag <= $tageImMonat; $tag++) {
$datum = $gewaehlterMonat . '-' . str_pad($tag, 2, '0', STR_PAD_LEFT);
echo $datum . "<br>";
// Abfrage für alle Zeitstempel des Tages
$query = "
SELECT timestamp_type, timestamp_datetime
FROM timestamps
WHERE employee_id = :employee_id AND DATE(timestamp_datetime) = :datum
ORDER BY timestamp_datetime
";
try {
$stmt = $pdo->prepare($query);
$stmt->bindParam(':employee_id', $mitarbeiterId, PDO::PARAM_INT);
$stmt->bindParam(':datum', $datum);
$stmt->execute();
$zeitstempel = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo $zeitstempel;
} catch(PDOException $e) {
$pdo->rollBack();
echo "Datenbankfehler: " . $e->getMessage();
}
$fruehesteKommenZeit = null;
$spaetesteGehenZeit = null;
$gesamtarbeitszeit = new DateInterval('PT0S');
$gesamtpausenzeit = new DateInterval('PT0S');
$letzterGehenZeitstempel = null;
echo "test";
foreach ($zeitstempel as $index => $eintrag) {
$zeit = new DateTime($eintrag['timestamp_datetime']);
echo "test2";
if ($eintrag['timestamp_type'] === 'KOMMEN') {
echo "test3";
if ($fruehesteKommenZeit === null || $zeit < $fruehesteKommenZeit) {
$fruehesteKommenZeit = $zeit;
}
if ($letzterGehenZeitstempel) {
$pause = $letzterGehenZeitstempel->diff($zeit);
$gesamtpausenzeit = $gesamtpausenzeit->add($pause);
}
} else if ($eintrag['timestamp_type'] === 'GEHEN') {
if ($spaetesteGehenZeit === null || $zeit > $spaetesteGehenZeit) {
$spaetesteGehenZeit = $zeit;
}
$letzterGehenZeitstempel = $zeit;
}
}
if ($fruehesteKommenZeit && $spaetesteGehenZeit) {
$gesamtarbeitszeit = $fruehesteKommenZeit->diff($spaetesteGehenZeit)->subtract($gesamtpausenzeit);
}
#echo $gesamtarbeitszeit;
$zeitenProTag[$datum] = [
'fruehesteKommenZeit' => $fruehesteKommenZeit ? $fruehesteKommenZeit->format('H:i:s') : '',
'spaetesteGehenZeit' => $spaetesteGehenZeit ? $spaetesteGehenZeit->format('H:i:s') : '',
'gesamtarbeitszeit' => $gesamtarbeitszeit->format('%H:%I:%S'),
'gesamtpausenzeit' => $gesamtpausenzeit->format('%H:%I:%S')
];
}
// Ausgabe der Ergebnisse für Testzwecke
echo '<pre>';
print_r($zeitenProTag);
echo '</pre>';
?>
</div>
</div>
</div>
<?php include 'footer.php'; ?>
+90
View File
@@ -0,0 +1,90 @@
<?php
session_start();
require_once('inc/config.inc.php');
require_once('inc/functions.inc.php');
$user = check_user();
if (!is_admin_user()) {
die('Zugriff verweigert. Nur Chefs dürfen Betriebsurlaub verwalten.');
}
// Create table if not exists (optional helper)
// Administrators can also run the SQL directly in DB. This is just a convenience.
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['start_date']) && isset($_POST['end_date'])) {
$start = $_POST['start_date'];
$end = $_POST['end_date'];
$desc = trim($_POST['description'] ?? 'Betriebsurlaub');
$stmt = $pdo->prepare("INSERT INTO company_holidays (start_date, end_date, description, created_by) VALUES (?, ?, ?, ?)");
$stmt->execute([$start, $end, $desc, $_SESSION['userid']]);
header('Location: company_holidays.php');
exit();
}
include 'header.php';
$stmt = $pdo->prepare("SELECT * FROM company_holidays ORDER BY start_date DESC");
$stmt->execute();
$holidays = $stmt->fetchAll();
?>
<div class="container">
<h2>Betriebsurlaub verwalten</h2>
<form method="post" class="form-inline mb-3">
<div class="form-group mr-2">
<label>Von:</label>
<input type="date" name="start_date" class="form-control" required>
</div>
<div class="form-group mr-2">
<label>Bis:</label>
<input type="date" name="end_date" class="form-control" required>
</div>
<div class="form-group mr-2">
<label>Beschreibung:</label>
<input type="text" name="description" class="form-control" placeholder="z. B. Betriebsurlaub Weihnachten">
</div>
<button class="btn btn-primary">Hinzufügen</button>
</form>
<table class="table table-bordered">
<thead>
<tr>
<th>Von</th>
<th>Bis</th>
<th>Beschreibung</th>
<th>Erstellt von</th>
<th>Aktion</th>
</tr>
</thead>
<tbody>
<?php foreach ($holidays as $h): ?>
<tr>
<td><?php echo $h['start_date']; ?></td>
<td><?php echo $h['end_date']; ?></td>
<td><?php echo htmlspecialchars($h['description']); ?></td>
<td><?php
$s = $pdo->prepare("SELECT vorname, nachname FROM users WHERE id = ?");
$s->execute([$h['created_by']]);
$u = $s->fetch();
echo htmlspecialchars($u['vorname'] . ' ' . $u['nachname']);
?></td>
<td>
<form method="post" action="deleteCompanyHoliday.php" onsubmit="return confirm('Betriebsurlaub wirklich löschen?');">
<input type="hidden" name="id" value="<?php echo intval($h['id']); ?>">
<button class="btn btn-sm btn-danger">Löschen</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php include 'footer.php';
?>
+241
View File
@@ -0,0 +1,241 @@
<?php
session_start();
require_once('./../admin/tcpdf/tcpdf.php');
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");
// Überprüfen, ob eine Benutzer-ID in der Session vorhanden ist
if (!isset($_SESSION['userid'])) {
die("Kein Benutzer angemeldet.");
}
$user = check_user();
if($_GET['id'] && $user["admin"] == 1){
$user_id = $_GET['id'];
}else{
$user_id = $_SESSION['userid'];
}
$mitarbeiterName = ""; // Holen Sie den Namen des Mitarbeiters aus der Datenbank
$firmaName = "Praxis Creutzburg"; // Setzen Sie den Firmennamen
$selectedMonth = $_GET['month'] ?? date('m'); // Monat vom Benutzer oder aktueller Monat
$selectedYear = $_GET['year'] ?? date('Y'); // Jahr vom Benutzer oder aktuelles Jahr
$selectedMonthSQL = str_pad($selectedMonth, 2, '0', STR_PAD_LEFT);
#echo $selectedMonthSQL;
try {
$query2 = "
SELECT
DATE(timestamp_datetime) AS datum,
GROUP_CONCAT(timestamp_type ORDER BY timestamp_datetime) AS day_sequence
FROM
timestamps
WHERE
employee_id = :employee_id AND
MONTH(timestamp_datetime) = :selectedMonth AND
YEAR(timestamp_datetime) = :selectedYear
GROUP BY
DATE(timestamp_datetime);";
$stmt = $pdo->prepare($query2);
$stmt->bindParam(':employee_id', $user_id, PDO::PARAM_INT);
$stmt->bindParam(':selectedMonth', $selectedMonth, PDO::PARAM_INT);
$stmt->bindParam(':selectedYear', $selectedYear, PDO::PARAM_INT);
$stmt->execute();
$result = $stmt->fetchAll();
#$invalidDates = [];
} catch(PDOException $e) {
echo "Datenbankfehler: " . $e->getMessage();
}
foreach ($result as $row) {
if (!isValidSequence($row["day_sequence"])) {
$fehlerhafteTage[] = $row["datum"];
}
}
if ($fehlerhafteTage){
include 'header.php'; ?>
<div class="container">
<div class="row">
<div class="col-md-12">
<h2>Stempelkarten-System</h2>
<?php
echo "<h1>Fehlzeiten erkannt</h1><br><h4>Bitte erst beheben.</h4><br>";
?>
<a href="index.php" class="btn btn-info btn-lg btn-block">Zurück</a>
</div>
</div>
</div>
<?php include 'footer.php';
exit;
}
try {
// Holen Sie den Namen des Mitarbeiters aus der Datenbank
$user_stmt = $pdo->prepare("SELECT vorname, nachname FROM users WHERE id = ?");
$user_stmt->bindParam(1, $user_id);
$user_stmt->execute();
$user = $user_stmt->fetch(PDO::FETCH_ASSOC);
if ($user) {
$mitarbeiterName = $user['vorname'] . ' ' . $user['nachname'];
} else {
die("Mitarbeiter nicht gefunden.");
}
// Holen Sie die Zeiten des Mitarbeiters aus der Datenbank
$times_stmt = $pdo->prepare("SELECT
DATE(timestamp_datetime) AS day,
MIN(CASE WHEN timestamp_type = 'KOMMEN' THEN timestamp_datetime END) AS first_come,
MAX(CASE WHEN timestamp_type = 'GEHEN' THEN timestamp_datetime END) AS last_go,
SEC_TO_TIME(SUM(
CASE
WHEN timestamp_type = 'GEHEN' THEN UNIX_TIMESTAMP(timestamp_datetime)
WHEN timestamp_type = 'KOMMEN' THEN -UNIX_TIMESTAMP(timestamp_datetime)
ELSE 0
END
)) AS total_time,
SEC_TO_TIME(
TIME_TO_SEC(
SEC_TO_TIME(
UNIX_TIMESTAMP(
MAX(CASE WHEN timestamp_type = 'GEHEN' THEN timestamp_datetime END)
) - UNIX_TIMESTAMP(
MIN(CASE WHEN timestamp_type = 'KOMMEN' THEN timestamp_datetime END)
)
)
) - TIME_TO_SEC(SEC_TO_TIME(SUM(
CASE
WHEN timestamp_type = 'GEHEN' THEN UNIX_TIMESTAMP(timestamp_datetime)
WHEN timestamp_type = 'KOMMEN' THEN -UNIX_TIMESTAMP(timestamp_datetime)
ELSE 0
END
)))
) AS difference_between_total_time_and_pause_time
FROM
timestamps
WHERE
employee_id = :employee_id AND
MONTH(timestamp_datetime) = :month AND
YEAR(timestamp_datetime) = :year
GROUP BY
DATE(timestamp_datetime)");
$times_stmt->bindParam(':employee_id', $user_id, PDO::PARAM_INT);
$times_stmt->bindParam(':month', $selectedMonth, PDO::PARAM_INT);
$times_stmt->bindParam(':year', $selectedYear, PDO::PARAM_INT);
$times_stmt->execute();
// Ergebnisse abrufen
#$result = $times_stmt->fetchAll();
#if (count($result) > 0) {
// Erstellen eines leeren Arrays, um die gesammelten Daten zu speichern
$times_data = [];
// Schleife durch die Ergebnisse der Abfrage und Speichern der Daten in einem assoziativen Array mit dem Tag als Schlüssel
while ($row = $times_stmt->fetch(PDO::FETCH_ASSOC)) {
$day = date('d', strtotime($row['day']));
$times_data[$day] = $row;
}
// Erstellen des PDF-Dokuments
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor($mitarbeiterName);
$pdf->SetTitle('Arbeitszeiten');
$pdf->SetSubject('Arbeitszeiten von ' . $mitarbeiterName);
$pdf->AddPage();
$stempdate = $selectedYear . "-" . $selectedMonth . "-1" ;
$date = new DateTime($stempdate);
// the international date formater object
$formatter = new IntlDateFormatter(
"de-DE",
IntlDateFormatter::LONG,
IntlDateFormatter::NONE,
"Europe/Berlin",
IntlDateFormatter::GREGORIAN,
"MMMM"
);
// Konvertieren Sie die Monatsnummer in einen Monatsnamen
#$dateObj = DateTime::createFromFormat('!m', $selectedMonth);
$monthName = $formatter->format($date); // z.B. March
$html = '<h1>Arbeitszeiten - ' . $firmaName . '</h1>';
$html .= '<h2>Mitarbeiter: ' . $mitarbeiterName . '</h2>';
$html .= '<h3>Monat: ' . $monthName . ' ' . $selectedYear . '</h3>';
$html .= '<table border="1" style="font-size:14px;" width=100%>';
$html .= '<tr><th style="width: 7%;">Tag</th><th style="width: 12%;">Start</th><th style="width: 12%;">Pause</th><th style="width: 12%;">Ende</th><th>Gesamtzeit</th><th style="width: 20%;font-size:12px;">aufgezeichnet am:</th><th style="width: 23%;">Bemerkung</th></tr>';
// Schleife durch die Tage 1-31
for ($day = 1; $day <= 31; $day++) {
$daytwo = str_pad($day, 2, '0', STR_PAD_LEFT);
// Überprüfen, ob Daten für diesen Tag vorhanden sind
if (isset($times_data[$daytwo])) {
// Daten für diesen Tag aus dem Array abrufen
$row = $times_data[$daytwo];
$html .= '<tr><td>' . $day . '</td><td>' . date('H:i:s', strtotime($row['first_come'])) . '</td><td>' . $row['difference_between_total_time_and_pause_time'] . '</td><td>' . date('H:i:s', strtotime($row['last_go'])) . '</td><td>' . $row['total_time'] . '</td><td>' . date('d.m.Y', strtotime($row['day'])) . '</td><td></td></tr>';
list($hours, $minutes, $seconds) = explode(':', $row["total_time"]);
$totalSeconds += $hours * 3600 + $minutes * 60 + $seconds;
} else {
// Wenn keine Daten für diesen Tag vorhanden sind, eine leere Zeile ausgeben
$html .= '<tr><td>' . $day . '</td><td></td><td></td><td></td><td></td><td></td><td></td></tr>';
}
}
// Umwandeln der gesamten Sekunden zurück in Stunden, Minuten, Sekunden
$hours = floor($totalSeconds / 3600);
$mins = floor($totalSeconds / 60 % 60);
$secs = floor($totalSeconds % 60);
$totalTime = sprintf('%02d:%02d:%02d', $hours, $mins, $secs);
#echo "Gesamtzeit über alle Tage: " . $totalTime;
$html .= '<tr><td></td><td></td><td></td><td><b>Gesamt</b></td><td><b>' . $totalTime .'</b></td><td></td><td></td></tr>';
$html .= '</table>';
$pdf->writeHTML($html, true, false, true, false, '');
$pdf->Output('Arbeitszeiten_' . $user['nachname'] . '_' . $selectedYear . '_' . $selectedMonth . '.pdf', 'I');
#} else {
# echo "Keine Ergebnisse gefunden";
#}
} catch(PDOException $e) {
echo "Datenbankfehler: " . $e->getMessage();
}
?>
+26
View File
@@ -0,0 +1,26 @@
<?php
session_start();
require_once('inc/config.inc.php');
require_once('inc/functions.inc.php');
$user = check_user();
if (!is_admin_user()) {
http_response_code(403);
echo 'Zugriff verweigert.';
exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['id'])) {
http_response_code(400);
echo 'Ungültige Anfrage.';
exit;
}
$id = intval($_POST['id']);
$stmt = $pdo->prepare("DELETE FROM company_holidays WHERE id = ?");
$stmt->execute([$id]);
header('Location: company_holidays.php');
exit;
?>
+51
View File
@@ -0,0 +1,51 @@
<?php
session_start();
require_once("inc/config.inc.php"); // Stellen Sie sicher, dass die Datenbankkonfiguration korrekt ist
require_once("inc/functions.inc.php"); // Enthält Funktionen für die Benutzerauthentifizierung und mehr
// Überprüfen, ob der Benutzer angemeldet ist
$user = check_user();
include 'header.php'; ?>
<div class="container">
<div class="row">
<div class="col-md-12">
<?php
try {
// Überprüfen, ob die erforderlichen POST-Daten vorhanden sind
if (isset($_GET['timestamp_id'])) {
// Die timestamp_id aus dem POST-Array holen
$timestamp_id = $_GET['timestamp_id'];
// SQL-Abfrage zum Löschen der Buchung
$sql = "DELETE FROM timestamps WHERE timestamp_id = :timestamp_id";
// Vorbereiten der SQL-Abfrage
$stmt = $pdo->prepare($sql);
// Binden von Parametern
$stmt->bindParam(':timestamp_id', $timestamp_id, PDO::PARAM_INT);
// Ausführen der vorbereiteten Abfrage
$stmt->execute();
// Erfolgreich gelöscht
echo "Buchung erfolgreich gelöscht";
} else {
// Fehler, wenn timestamp_id nicht im POST-Array gefunden wurde
echo "Fehler: timestamp_id nicht gefunden";
}
} catch(PDOException $e) {
// Fehler beim Verbindungsaufbau oder bei der Abfrage
echo "Fehler: " . $e->getMessage();
}
?>
</div>
</div>
</div>
<?php include 'footer.php'; ?>
+39
View File
@@ -0,0 +1,39 @@
<?php
session_start();
require_once("inc/config.inc.php"); // Stellen Sie sicher, dass die Datenbankkonfiguration korrekt ist
require_once("inc/functions.inc.php"); // Enthält Funktionen für die Benutzerauthentifizierung und mehr
// Überprüfen, ob der Benutzer angemeldet ist
$user = check_user();
try {
// Überprüfen, ob die erforderlichen POST-Daten vorhanden sind
if (isset($_POST['timestamp_id'])) {
// Die timestamp_id aus dem POST-Array holen
$timestamp_id = $_POST['timestamp_id'];
// SQL-Abfrage zum Löschen der Buchung
$sql = "DELETE FROM buchungen WHERE timestamp_id = :timestamp_id";
// Vorbereiten der SQL-Abfrage
$stmt = $pdo->prepare($sql);
// Binden von Parametern
$stmt->bindParam(':timestamp_id', $timestamp_id, PDO::PARAM_INT);
// Ausführen der vorbereiteten Abfrage
$stmt->execute();
// Erfolgreich gelöscht
echo "Buchung erfolgreich gelöscht";
} else {
// Fehler, wenn timestamp_id nicht im POST-Array gefunden wurde
echo "Fehler: timestamp_id nicht gefunden";
}
} catch(PDOException $e) {
// Fehler beim Verbindungsaufbau oder bei der Abfrage
echo "Fehler: " . $e->getMessage();
}
?>
+38
View File
@@ -0,0 +1,38 @@
<?php
session_start();
require_once('inc/config.inc.php');
require_once('inc/functions.inc.php');
$user = check_user();
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['id'])) {
http_response_code(400);
die('Bad request');
}
$id = (int)$_POST['id'];
$referer = $_POST['referer'] ?? 'urlaubsantrag.php';
// Fetch vacation to verify ownership
$stmt = $pdo->prepare("SELECT user_id, status FROM vacations WHERE id = ?");
$stmt->execute([$id]);
$vac = $stmt->fetch();
if (!$vac) {
die('Urlaubseintrag nicht gefunden.');
}
$isAdmin = is_admin_user();
if (!$isAdmin && $vac['user_id'] != $_SESSION['userid']) {
die('Zugriff verweigert.');
}
// Allow deletion for admins or owner
$del = $pdo->prepare("DELETE FROM vacations WHERE id = ?");
$del->execute([$id]);
header('Location: ' . $referer);
exit();
?>
+116
View File
@@ -0,0 +1,116 @@
<?php
session_start();
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");
//Überprüfe, dass der User eingeloggt ist
//Der Aufruf von check_user() muss in alle internen Seiten eingebaut sein
$user = check_user();
?>
<?php include 'header.php'; ?>
<div class="container">
<div class="row">
<div class="col-md-12">
<h2>Stempelkarten-System</h2>
<?php
// Überprüfen, ob eine Benutzer-ID in der Session vorhanden ist
if (!isset($_SESSION['userid'])) {
die("Kein Benutzer angemeldet.");
}
#$user_id = $_SESSION['userid'];
$user_id = $_GET['employee_id'] ?? null;
$datum = $_GET['datum'] ?? null;
if ($user_id && $datum) {
try {
// Holen Sie alle Zeitbuchungen des Tages für den Mitarbeiter
$query = "SELECT * FROM timestamps WHERE employee_id = :employee_id AND DATE(timestamp_datetime) = :datum ORDER BY timestamp_datetime ASC";
$stmt = $pdo->prepare($query);
$stmt->bindParam(':employee_id', $user_id, PDO::PARAM_INT);
$stmt->bindParam(':datum', $datum);
$stmt->execute();
$buchungen = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch(PDOException $e) {
echo "Datenbankfehler: " . $e->getMessage();
}
} else {
die("Fehler: Mitarbeiter-ID oder Datum fehlt.");
}
// ... [Hier könnten Sie PHP-Code für die Bearbeitung der Buchungen hinzufügen]
?>
<!DOCTYPE html>
<html>
<head>
<title>Tageseinträge bearbeiten</title>
<!-- ... [Bootstrap-CSS und optional JavaScript] -->
</head>
<body>
<div class="container">
<h3>Tageseinträge bearbeiten - <?php echo date('d.m.Y', strtotime($datum)); ?></h3>
<!-- Formular zum Bearbeiten der Zeitbuchungen -->
<form id="mainForm" action="saveDayEntries.php" method="post">
<input type="hidden" name="employee_id" value="<?php echo $user_id; ?>">
<input type="hidden" name="datum" value="<?php echo $datum; ?>">
<?php foreach ($buchungen as $index => $buchung): ?>
<div class="form-group" id="entry_<?php echo $buchung['timestamp_id']; ?>">
<label>Zeitbuchung <?php echo $index + 1; ?>:</label>
<input type="datetime-local" class="form-control" name="buchungen[<?php echo $buchung['timestamp_id']; ?>][timestamp_datetime]" value="<?php echo $buchung['timestamp_datetime']; ?>">
<select class="form-control" name="buchungen[<?php echo $buchung['timestamp_id']; ?>][timestamp_type]">
<option value="KOMMEN" <?php if ($buchung['timestamp_type'] == 'KOMMEN') echo 'selected'; ?>>KOMMEN</option>
<option value="GEHEN" <?php if ($buchung['timestamp_type'] == 'GEHEN') echo 'selected'; ?>>GEHEN</option>
</select>
<a href="deleteDayEntry.php?timestamp_id=<?php echo $buchung['timestamp_id']; ?>" class="btn btn-danger">Löschen</a>
</div>
<?php endforeach; ?>
<div id="newEnty"></div>
<button type="submit" class="btn btn-primary">Speichern</button>
</form>
<br>
<button onclick="addEntry()" class="btn btn-success">Neue Buchung hinzufügen</button>
<br><br>
<button type="button" class="btn btn-secondary" onclick="history.back();">Zurück</button>
</div>
<script>
let entryIndex = <?php echo count($buchungen); ?>;
function addEntry() {
entryIndex++;
const container = document.createElement('div');
container.className = 'form-group';
container.innerHTML = `
<label>Zeitbuchung ${entryIndex}:</label>
<input type="datetime-local" class="form-control" name="buchungen[new_${entryIndex}][timestamp_datetime]" placeholder="YYYY-MM-DD HH:MM:SS">
<select class="form-control" name="buchungen[new_${entryIndex}][timestamp_type]">
<option value="KOMMEN">KOMMEN</option>
<option value="GEHEN">GEHEN</option>
</select>
`;
document.getElementById('newEnty').appendChild(container);
}
</script>
</div>
</div>
</div>
</div>
<?php include 'footer.php'; ?>
+26
View File
@@ -0,0 +1,26 @@
<?php
session_start();
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");
//Überprüfe, dass der User eingeloggt ist
//Der Aufruf von check_user() muss in alle internen Seiten eingebaut sein
$user = check_user();
if (!isset($_SESSION['userid'])) {
die("Kein Benutzer angemeldet.");
}
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$employee_id = $_POST['employee_id'];
$datum = $_POST['datum'];
$kommen_count = $_POST['kommen_count'];
$gehen_count = $_POST['gehen_count'];
// Hier sollte die Logik implementiert werden, um die Anzahl der 'KOMMEN' und 'GEHEN' Buchungen anzupassen
// Beachten Sie, dass dies komplex sein kann, da Sie eventuell existierende Buchungen entfernen oder neue hinzufügen müssen
// Nach der Bearbeitung, leiten Sie den Benutzer zurück zur 'zeitfehlerAuswertung.php'
header("Location: zeitfehlerAuswertung.php");
exit();
}
?>
+122
View File
@@ -0,0 +1,122 @@
<?php
session_start();
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");
//Überprüfe, dass der User eingeloggt ist
//Der Aufruf von check_user() muss in alle internen Seiten eingebaut sein
$user = check_user();
?>
<?php include 'header.php'; ?>
<div class="container">
<div class="row">
<div class="col-md-12">
<?php
if (isset($_GET['id']) && is_numeric($_GET['id'])) {
$id = $_GET['id'];
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);
$mitarbeiter = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$mitarbeiter) {
die('Mitarbeiter nicht gefunden!');
}
} else {
die('Ungültige Anfrage!');
}
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$email = $_POST['email'];
$vorname = $_POST['vorname'];
$nachname = $_POST['nachname'];
$card_id = $_POST['card_id'] ?? '';
$card2_id = $_POST['card2_id'] ?? '';
$worker = $_POST['worker'] ?? 0;
$sql = "UPDATE users SET email=?, vorname=?, nachname=?, worker=?, admin=?, zeiterfassung=?, card_id=?, card2_id=? WHERE id=?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$email, $vorname, $nachname, $_POST['worker'], $_POST['admin'], $_POST['zeiterfassung'], $card_id, $card2_id, $id]);
// Zusatzaktion für users_worker
if ($worker == 1) {
// Prüfen, ob der Eintrag schon existiert
$checkSql = "SELECT COUNT(*) FROM users_worker WHERE userid = ?";
$checkStmt = $pdo->prepare($checkSql);
$checkStmt->execute([$id]);
$exists = $checkStmt->fetchColumn();
if ($exists == 0) {
// Eintrag hinzufügen
$insertSql = "INSERT INTO users_worker (workerid, userid) VALUES (?, ?)";
$insertStmt = $pdo->prepare($insertSql);
$insertStmt->execute([$id, $id]);
}
} else {
// Eintrag löschen
$deleteSql = "DELETE FROM users_worker WHERE userid = ?";
$deleteStmt = $pdo->prepare($deleteSql);
$deleteStmt->execute([$id]);
}
echo "<br><div class='alert alert-success' role='alert'>Mitarbeiter erfolgreich aktualisiert.</div>";
// Optional: Umleitung
// header('Location: index.php');
}else{
?>
<div class="container mt-5">
<h2>Mitarbeiter bearbeiten</h2>
<form action="" method="post" class="mt-3">
<div class="form-group">
<label for="email">Email</label>
<input type="text" class="form-control" name="email" id="email" value="<?php echo htmlspecialchars($mitarbeiter['email']); ?>" required>
</div>
<div class="form-group">
<label for="vorname">Vorname</label>
<input type="text" class="form-control" name="vorname" id="vorname" value="<?php echo htmlspecialchars($mitarbeiter['vorname']); ?>" required>
</div>
<div class="form-group">
<label for="nachname">Nachname</label>
<input type="text" class="form-control" name="nachname" id="nachname" value="<?php echo htmlspecialchars($mitarbeiter['nachname']); ?>" required>
</div>
<div class="form-group form-check">
<input type="checkbox" class="form-check-input" name="zeiterfassung" id="zeiterfassung" value="1" <?php if($mitarbeiter['zeiterfassung']== "1") echo 'checked'; ?>>
<label class="form-check-label" for="zeiterfassung">Zeiterfassung</label>
</div>
<div class="form-group form-check">
<input type="checkbox" class="form-check-input" name="worker" id="worker" value="1" <?php if($mitarbeiter['worker'] == "1") echo 'checked'; ?>>
<label class="form-check-label" for="worker">Worker</label>
</div>
<div class="form-group form-check">
<input type="checkbox" class="form-check-input" name="admin" id="admin" value="1" <?php if($mitarbeiter['admin']== "1") echo 'checked'; ?>>
<label class="form-check-label" for="admin">Admin</label>
</div>
<div class="form-group">
<label for="card_id">Card ID</label>
<input type="text" class="form-control" name="card_id" id="card_id" value="<?php echo htmlspecialchars($mitarbeiter['card_id']); ?>">
</div>
<div class="form-group">
<label for="card2_id">Card2 ID</label>
<input type="text" class="form-control" name="card2_id" id="card2_id" value="<?php echo htmlspecialchars($mitarbeiter['card2_id']); ?>">
</div>
<button type="submit" class="btn btn-primary">Aktualisieren</button>
</form>
</div>
<div class="container mt-5">
<?php
echo "<td><a class='btn btn-primary btn-sm' href='editworkerpassword.php?id=" . $mitarbeiter['id'] . "'>Passwort des Mitarbeiters ändern</a></td>";
?>
</div>
<?php
}
?>
<div class="container mt-5">
<button type="button" class="btn btn-secondary" onclick="window.location.href='showworker.php';">Zurück</button>
</div>
</div>
</div>
<?php include 'footer.php'; ?>
+78
View File
@@ -0,0 +1,78 @@
<?php
session_start();
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");
//Überprüfe, dass der User eingeloggt ist
//Der Aufruf von check_user() muss in alle internen Seiten eingebaut sein
$user = check_user();
?>
<?php include 'header.php'; ?>
<div class="container">
<div class="row">
<div class="col-md-12">
<?php
if (isset($_GET['id']) && is_numeric($_GET['id'])) {
$id = $_GET['id'];
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);
$mitarbeiter = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$mitarbeiter) {
die('Mitarbeiter nicht gefunden!');
}
} else {
die('Ungültige Anfrage!');
}
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if(isset($_GET['send'])) {
$passwort = $_POST['passwort'];
$passwort2 = $_POST['passwort2'];
if($passwort != $passwort2) {
$msg = "Bitte identische Passwörter eingeben";
} else { //Speichere neues Passwort und lösche den Code
$passworthash = password_hash($passwort, PASSWORD_DEFAULT);
$statement = $pdo->prepare("UPDATE users SET passwort = :passworthash, passwortcode = NULL, passwortcode_time = NULL WHERE id = :userid");
$result = $statement->execute(array('passworthash' => $passworthash, 'userid'=> $id ));
if($result) {
echo "<br><div class='alert alert-success' role='alert'>Das Passwort des Mitarbeiters wurde erfolgreich aktualisiert.</div>";
}
}
}
// Optional: Umleitung
// header('Location: index.php');
}else{
?>
<div class="container small-container-500">
<h1>Neues Passwort vergeben</h1>
<?php echo "<h3>Passwort von Mitarbeiter: " . htmlspecialchars($mitarbeiter['vorname']) . " " . htmlspecialchars($mitarbeiter['nachname']) . " ändern.</h3>" ?>
<form action="?send=1&amp;id=<?php echo htmlentities($_GET['id']); ?>" method="post">
<label for="passwort">Bitte gib ein neues Passwort ein:</label><br>
<input type="password" id="passwort" name="passwort" class="form-control" required><br>
<label for="passwort2">Passwort erneut eingeben:</label><br>
<input type="password" id="passwort2" name="passwort2" class="form-control" required><br>
<input type="submit" value="Passwort speichern" class="btn btn-lg btn-primary btn-block">
</form>
<?php
}
?>
<br>
<button type="button" class="btn btn-secondary" onclick="history.back();">Zurück</button>
</div>
</div>
</div>
<?php include 'footer.php'; ?>
+100
View File
@@ -0,0 +1,100 @@
<?php
session_start();
require_once('./../admin/tcpdf/tcpdf.php');
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");
// Überprüfen, ob eine Benutzer-ID in der Session vorhanden ist
if (!isset($_SESSION['userid'])) {
die("Kein Benutzer angemeldet.");
}
$user = check_user();
$user_id = $_SESSION['userid'];
try {
$query2 = "
SELECT
DATE(timestamp_datetime) AS datum,
GROUP_CONCAT(timestamp_type ORDER BY timestamp_datetime) AS day_sequence
FROM
timestamps
WHERE
employee_id = :employee_id
GROUP BY
DATE(timestamp_datetime);";
$stmt = $pdo->prepare($query2);
$stmt->bindParam(':employee_id', $user["id"], PDO::PARAM_INT);
$stmt->execute();
$result = $stmt->fetchAll();
$invalidDates = [];
} catch(PDOException $e) {
echo "Datenbankfehler: " . $e->getMessage();
}
?>
<?php include 'header.php'; ?>
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="container">
<h2 class="mb-4">Zeitbuchungsfehler Auswertung</h2>
<?php
foreach ($result as $row) {
if (!isValidSequence($row["day_sequence"])) {
$invalidDates[] = $row["datum"];
}
}
?>
<?php if (!empty($invalidDates)): ?>
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th>Datum</th>
<th>Fehler</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
<?php foreach ($invalidDates as $date): ?>
<tr>
<td><?php echo date('d.m.Y', strtotime($date)); ?></td>
<td>Fehlerhafte KOMMEN/GEHEN Buchung</td>
<td>
<a href="editDayEntries.php?employee_id=<?php echo $user['id']; ?>&datum=<?php echo $date; ?>" class="btn btn-warning">Anpassen</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php else: ?>
<div class="alert alert-info" role="alert">
Keine Zeitbuchungsfehler gefunden.
</div>
<?php endif; ?>
</div>
</div>
</div>
<?php include 'footer.php'; ?>
+7
View File
@@ -0,0 +1,7 @@
<!-- Optional JavaScript -->
<!-- jQuery, Popper.js, Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.4.2/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>
</html>
+93
View File
@@ -0,0 +1,93 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ihre Webseite</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="css/custom.css">
</head>
<body>
<?php
// Ensure $user is available without changing authentication behavior elsewhere
if (!isset($user)) {
if (isset($_SESSION['userid']) && isset($pdo)) {
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_SESSION['userid']]);
$user = $stmt->fetch();
} else {
// Minimal default to avoid notices when not logged in
$user = ['admin' => 0, 'zeiterfassung' => 0];
}
}
?>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="#">Zeiterfassung</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="index.php">Startseite</a>
</li>
<li class="nav-item">
<a class="nav-link" href="ZeitenAnzeige.php">Zeitübersicht</a>
</li>
<li class="nav-item">
<a class="nav-link" href="fehlbuchungen.php">Fehlbuchungen</a>
</li>
<!-- Urlaub Dropdown -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="urlaubDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Urlaub
</a>
<div class="dropdown-menu" aria-labelledby="urlaubDropdown">
<a class="dropdown-item" href="urlaubsantrag.php">Urlaubsantrag</a>
<a class="dropdown-item" href="my_vacations_calendar.php">Mein Urlaubskalender</a>
<a class="dropdown-item" href="vacations_calendar_all.php">Team Urlaubskalender</a>
<?php if (is_admin_user()) : ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="vacations_overview.php">Urlaubsübersicht</a>
<a class="dropdown-item" href="approveVacation.php">Urlaubsanträge genehmigen</a>
<a class="dropdown-item" href="company_holidays.php">Betriebsurlaub</a>
<?php endif; ?>
</div>
</li>
<!-- Verwaltung Dropdown (Admin only) -->
<?php if (is_admin_user()) : ?>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="adminDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Verwaltung
</a>
<div class="dropdown-menu" aria-labelledby="adminDropdown">
<a class="dropdown-item" href="alleZeitenanzeige.php">Alle Zeitbuchungen</a>
<a class="dropdown-item" href="allefehlbuchungen.php">Alle Fehlbuchungen</a>
<a class="dropdown-item" href="showworker.php">Mitarbeiterverwaltung</a>
</div>
</li>
<?php endif; ?>
</ul>
<!-- optional right-side user area -->
<ul class="navbar-nav">
<?php if (isset($user['vorname'])): ?>
<li class="nav-item"><span class="navbar-text text-light mr-3"><?php echo htmlspecialchars($user['vorname']); ?></span></li>
<li class="nav-item"><a class="nav-link" href="logout.php">Abmelden</a></li>
<?php else: ?>
<li class="nav-item"><a class="nav-link" href="login.php">Anmelden</a></li>
<?php endif; ?>
</ul>
</div>
</nav>
<?php
// Enforce zeiterfassung permission if present on pages that expect it
if (isset($user['zeiterfassung']) && $user['zeiterfassung'] != 1) {
die("Keine Rechte für die Zeiterfassung");
}
+27
View File
@@ -0,0 +1,27 @@
<?php
//Datenbankverbindung
$dbhost = "mysql2fda.netcup.net";
$dbuser = "k25330_pracreutz";
$dbpassword = "be4K8DSASDA2y";
$dbname = "k25330_pracreutz";
// SQL Datum festlegen
$sqltoday = date("Y-m-d");
#$sqlyesterday = date("Y-m-d", strtotime("-1 day", $sqltoday ));
#$yesterday = Date('Y-m-d', strtotime('-1 day'));
#$yesteryesterday = Date('Y-m-d', strtotime('-2 days'));
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpassword, $options);
#$conn = new mysqli($dbhost,$dbuser,$dbpassword,$dbname);
?>
+190
View File
@@ -0,0 +1,190 @@
<?php
include_once("password.inc.php");
/**
* Checks that the user is logged in.
* @return Returns the row of the logged in user
*/
function check_user() {
global $pdo;
if(!isset($_SESSION['userid']) && isset($_COOKIE['identifier']) && isset($_COOKIE['securitytoken'])) {
$identifier = $_COOKIE['identifier'];
$securitytoken = $_COOKIE['securitytoken'];
$statement = $pdo->prepare("SELECT * FROM securitytokens WHERE identifier = :identifier");
$result = $statement->execute(array('identifier' => $identifier));
$securitytoken_row = $statement->fetch();
//echo $securitytoken;
if(sha1($securitytoken) !== $securitytoken_row['securitytoken']) {
//Vermutlich wurde der Security Token gestohlen
//Hier ggf. eine Warnung o.ä. anzeigen
echo 'In der letzte Sitzung nicht abgemeldet oder neuer/anderen Browser genutzt.<br><br><br>';
} else { //Token war korrekt
//Setze neuen Token
$neuer_securitytoken = random_string();
$insert = $pdo->prepare("UPDATE securitytokens SET securitytoken = :securitytoken WHERE identifier = :identifier");
$insert->execute(array('securitytoken' => sha1($neuer_securitytoken), 'identifier' => $identifier));
setcookie("identifier",$identifier,time()+(3600*24*365)); //1 Jahr Gültigkeit
setcookie("securitytoken",$neuer_securitytoken,time()+(3600*24*365)); //1 Jahr Gültigkeit
//Logge den Benutzer ein
$_SESSION['userid'] = $securitytoken_row['user_id'];
}
}
if(!isset($_SESSION['userid'])) {
die('Bitte zuerst <a href="login.php" >einloggen</a>');
}
$statement = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$result = $statement->execute(array('id' => $_SESSION['userid']));
$user = $statement->fetch();
return $user;
}
/**
* Returns true when the user is checked in, else false
*/
function is_checked_in() {
return isset($_SESSION['userid']);
}
function is_checked_in_index() {
if( isset($_SESSION['userid']) || isset($_COOKIE['identifier'])){
return true;
}else{
return false;
}
}
/**
* Returns a random string
*/
function random_string() {
if(function_exists('openssl_random_pseudo_bytes')) {
$bytes = openssl_random_pseudo_bytes(16);
$str = bin2hex($bytes);
} else if(function_exists('mcrypt_create_iv')) {
$bytes = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
$str = bin2hex($bytes);
} else {
//Replace your_secret_string with a string of your choice (>12 characters)
$str = md5(uniqid('your_secret_string', true));
}
return $str;
}
/**
* Returns the URL to the site without the script name
*/
function getSiteURL() {
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
return $protocol.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']).'/';
}
/**
* Outputs an error message and stops the further exectution of the script.
*/
function error($error_msg) {
include("templates/header.inc.php");
include("templates/error.inc.php");
include("templates/footer.inc.php");
exit();
}
/**
* Prüft, ob der Benutzer administrator ist
*/
function check_admin() {
global $pdo;
if(isset($_SESSION['userid'])) {
$statement = $pdo->prepare("SELECT userid FROM users_admin WHERE userid = :id");
$statement->execute(array('id' => $_SESSION['userid']));
$count = $statement->rowCount();
if($count == 1){
return true;
}else{
return false;
}
}else{
return false;
}
}
/**
* Non-invasive admin check that prefers the `users.admin` flag but
* falls back to the legacy `users_admin` table. Does not modify
* `check_user()` behavior.
*/
function is_admin_user() {
global $pdo;
if (!isset($_SESSION['userid'])) {
return false;
}
// Prefer the admin flag in users table (supports BIT(1) or TINYINT)
$stmt = $pdo->prepare("SELECT admin FROM users WHERE id = ?");
$stmt->execute([$_SESSION['userid']]);
$row = $stmt->fetch();
if ($row && !empty($row['admin'])) {
return true;
}
// Fallback to legacy users_admin table
$statement = $pdo->prepare("SELECT userid FROM users_admin WHERE userid = :id");
$statement->execute(array('id' => $_SESSION['userid']));
return ($statement->rowCount() == 1);
}
/**
* Prüft, ob der Benutzer Bearbeiter ist
*/
function check_worker() {
global $pdo;
if(isset($_SESSION['userid'])) {
$statement = $pdo->prepare("SELECT userid FROM users_worker WHERE userid = :id");
$statement->execute(array('id' => $_SESSION['userid']));
$count = $statement->rowCount();
if($count == 1){
return true;
}else{
return false;
}
}else{
return false;
}
}
function isValidSequence($sequence) {
$events = explode(',', $sequence);
$previousType = null;
foreach ($events as $type) {
if ($previousType === $type) {
// Ein Fehler, wenn zwei gleiche Typen aufeinanderfolgen
return false;
}
$previousType = $type;
}
// Überprüfen Sie, ob die Sequenz mit einem KOMMEN beginnt und einem GEHEN endet
return $events[0] === 'KOMMEN' && end($events) === 'GEHEN';
}
?>
+317
View File
@@ -0,0 +1,317 @@
<?php
/**
* A Compatibility library with PHP 5.5's simplified password hashing API.
*
* @author Anthony Ferrara <ircmaxell@php.net>
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @copyright 2012 The Authors
*/
namespace {
if (!defined('PASSWORD_BCRYPT')) {
/**
* PHPUnit Process isolation caches constants, but not function declarations.
* So we need to check if the constants are defined separately from
* the functions to enable supporting process isolation in userland
* code.
*/
define('PASSWORD_BCRYPT', 1);
define('PASSWORD_DEFAULT', PASSWORD_BCRYPT);
define('PASSWORD_BCRYPT_DEFAULT_COST', 10);
}
if (!function_exists('password_hash')) {
/**
* Hash the password using the specified algorithm
*
* @param string $password The password to hash
* @param int $algo The algorithm to use (Defined by PASSWORD_* constants)
* @param array $options The options for the algorithm to use
*
* @return string|false The hashed password, or false on error.
*/
function password_hash($password, $algo, array $options = array()) {
if (!function_exists('crypt')) {
trigger_error("Crypt must be loaded for password_hash to function", E_USER_WARNING);
return null;
}
if (is_null($password) || is_int($password)) {
$password = (string) $password;
}
if (!is_string($password)) {
trigger_error("password_hash(): Password must be a string", E_USER_WARNING);
return null;
}
if (!is_int($algo)) {
trigger_error("password_hash() expects parameter 2 to be long, " . gettype($algo) . " given", E_USER_WARNING);
return null;
}
$resultLength = 0;
switch ($algo) {
case PASSWORD_BCRYPT:
$cost = PASSWORD_BCRYPT_DEFAULT_COST;
if (isset($options['cost'])) {
$cost = (int) $options['cost'];
if ($cost < 4 || $cost > 31) {
trigger_error(sprintf("password_hash(): Invalid bcrypt cost parameter specified: %d", $cost), E_USER_WARNING);
return null;
}
}
// The length of salt to generate
$raw_salt_len = 16;
// The length required in the final serialization
$required_salt_len = 22;
$hash_format = sprintf("$2y$%02d$", $cost);
// The expected length of the final crypt() output
$resultLength = 60;
break;
default:
trigger_error(sprintf("password_hash(): Unknown password hashing algorithm: %s", $algo), E_USER_WARNING);
return null;
}
$salt_req_encoding = false;
if (isset($options['salt'])) {
switch (gettype($options['salt'])) {
case 'NULL':
case 'boolean':
case 'integer':
case 'double':
case 'string':
$salt = (string) $options['salt'];
break;
case 'object':
if (method_exists($options['salt'], '__tostring')) {
$salt = (string) $options['salt'];
break;
}
case 'array':
case 'resource':
default:
trigger_error('password_hash(): Non-string salt parameter supplied', E_USER_WARNING);
return null;
}
if (PasswordCompat\binary\_strlen($salt) < $required_salt_len) {
trigger_error(sprintf("password_hash(): Provided salt is too short: %d expecting %d", PasswordCompat\binary\_strlen($salt), $required_salt_len), E_USER_WARNING);
return null;
} elseif (0 == preg_match('#^[a-zA-Z0-9./]+$#D', $salt)) {
$salt_req_encoding = true;
}
} else {
$buffer = '';
$buffer_valid = false;
if (function_exists('mcrypt_create_iv') && !defined('PHALANGER')) {
$buffer = mcrypt_create_iv($raw_salt_len, MCRYPT_DEV_URANDOM);
if ($buffer) {
$buffer_valid = true;
}
}
if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) {
$strong = false;
$buffer = openssl_random_pseudo_bytes($raw_salt_len, $strong);
if ($buffer && $strong) {
$buffer_valid = true;
}
}
if (!$buffer_valid && @is_readable('/dev/urandom')) {
$file = fopen('/dev/urandom', 'r');
$read = 0;
$local_buffer = '';
while ($read < $raw_salt_len) {
$local_buffer .= fread($file, $raw_salt_len - $read);
$read = PasswordCompat\binary\_strlen($local_buffer);
}
fclose($file);
if ($read >= $raw_salt_len) {
$buffer_valid = true;
}
$buffer = str_pad($buffer, $raw_salt_len, "\0") ^ str_pad($local_buffer, $raw_salt_len, "\0");
}
if (!$buffer_valid || PasswordCompat\binary\_strlen($buffer) < $raw_salt_len) {
$buffer_length = PasswordCompat\binary\_strlen($buffer);
for ($i = 0; $i < $raw_salt_len; $i++) {
if ($i < $buffer_length) {
$buffer[$i] = $buffer[$i] ^ chr(mt_rand(0, 255));
} else {
$buffer .= chr(mt_rand(0, 255));
}
}
}
$salt = $buffer;
$salt_req_encoding = true;
}
if ($salt_req_encoding) {
// encode string with the Base64 variant used by crypt
$base64_digits =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
$bcrypt64_digits =
'./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$base64_string = base64_encode($salt);
$salt = strtr(rtrim($base64_string, '='), $base64_digits, $bcrypt64_digits);
}
$salt = PasswordCompat\binary\_substr($salt, 0, $required_salt_len);
$hash = $hash_format . $salt;
$ret = crypt($password, $hash);
if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != $resultLength) {
return false;
}
return $ret;
}
/**
* Get information about the password hash. Returns an array of the information
* that was used to generate the password hash.
*
* array(
* 'algo' => 1,
* 'algoName' => 'bcrypt',
* 'options' => array(
* 'cost' => PASSWORD_BCRYPT_DEFAULT_COST,
* ),
* )
*
* @param string $hash The password hash to extract info from
*
* @return array The array of information about the hash.
*/
function password_get_info($hash) {
$return = array(
'algo' => 0,
'algoName' => 'unknown',
'options' => array(),
);
if (PasswordCompat\binary\_substr($hash, 0, 4) == '$2y$' && PasswordCompat\binary\_strlen($hash) == 60) {
$return['algo'] = PASSWORD_BCRYPT;
$return['algoName'] = 'bcrypt';
list($cost) = sscanf($hash, "$2y$%d$");
$return['options']['cost'] = $cost;
}
return $return;
}
/**
* Determine if the password hash needs to be rehashed according to the options provided
*
* If the answer is true, after validating the password using password_verify, rehash it.
*
* @param string $hash The hash to test
* @param int $algo The algorithm used for new password hashes
* @param array $options The options array passed to password_hash
*
* @return boolean True if the password needs to be rehashed.
*/
function password_needs_rehash($hash, $algo, array $options = array()) {
$info = password_get_info($hash);
if ($info['algo'] !== (int) $algo) {
return true;
}
switch ($algo) {
case PASSWORD_BCRYPT:
$cost = isset($options['cost']) ? (int) $options['cost'] : PASSWORD_BCRYPT_DEFAULT_COST;
if ($cost !== $info['options']['cost']) {
return true;
}
break;
}
return false;
}
/**
* Verify a password against a hash using a timing attack resistant approach
*
* @param string $password The password to verify
* @param string $hash The hash to verify against
*
* @return boolean If the password matches the hash
*/
function password_verify($password, $hash) {
if (!function_exists('crypt')) {
trigger_error("Crypt must be loaded for password_verify to function", E_USER_WARNING);
return false;
}
$ret = crypt($password, $hash);
if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != PasswordCompat\binary\_strlen($hash) || PasswordCompat\binary\_strlen($ret) <= 13) {
return false;
}
$status = 0;
for ($i = 0; $i < PasswordCompat\binary\_strlen($ret); $i++) {
$status |= (ord($ret[$i]) ^ ord($hash[$i]));
}
return $status === 0;
}
}
}
namespace PasswordCompat\binary {
if (!function_exists('PasswordCompat\\binary\\_strlen')) {
/**
* Count the number of bytes in a string
*
* We cannot simply use strlen() for this, because it might be overwritten by the mbstring extension.
* In this case, strlen() will count the number of *characters* based on the internal encoding. A
* sequence of bytes might be regarded as a single multibyte character.
*
* @param string $binary_string The input string
*
* @internal
* @return int The number of bytes
*/
function _strlen($binary_string) {
if (function_exists('mb_strlen')) {
return mb_strlen($binary_string, '8bit');
}
return strlen($binary_string);
}
/**
* Get a substring based on byte limits
*
* @see _strlen()
*
* @param string $binary_string The input string
* @param int $start
* @param int $length
*
* @internal
* @return string The substring
*/
function _substr($binary_string, $start, $length) {
if (function_exists('mb_substr')) {
return mb_substr($binary_string, $start, $length, '8bit');
}
return substr($binary_string, $start, $length);
}
/**
* Check if current PHP version is compatible with the library
*
* @return boolean the check result
*/
function check() {
static $pass = NULL;
if (is_null($pass)) {
if (function_exists('crypt')) {
$hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG';
$test = crypt("password", $hash);
$pass = $test == $hash;
} else {
$pass = false;
}
}
return $pass;
}
}
}
+156
View File
@@ -0,0 +1,156 @@
<?php
session_start();
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");
//Überprüfe, dass der User eingeloggt ist
//Der Aufruf von check_user() muss in alle internen Seiten eingebaut sein
$user = check_user();
?>
<?php include 'header.php'; ?>
<div class="container">
<div class="row">
<div class="col-md-12">
<h2>Stempelkarten-System</h2>
<?php
// Überprüfen, ob eine Benutzer-ID in der Session vorhanden ist
if (!isset($_SESSION['userid'])) {
die("Kein Benutzer angemeldet.");
}
$user_id = $_SESSION['userid'];
if ($_SERVER["REQUEST_METHOD"] == "POST") {
try {
// Benutzerinformationen basierend auf der gespeicherten Benutzer-ID abrufen
$stmt = $pdo->prepare("SELECT vorname FROM users WHERE id = ?");
$stmt->bindParam(1, $user_id);
$stmt->execute();
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if ($user) {
// Logik für das Setzen des Zeitstempels
$stmt = $pdo->prepare("SELECT COUNT(CASE WHEN timestamp_type = 'KOMMEN' THEN 1 ELSE NULL END) AS AnzahlKommen, COUNT(CASE WHEN timestamp_type = 'GEHEN' THEN 1 ELSE NULL END) AS AnzahlGehen FROM timestamps WHERE employee_id = ? AND DATE(timestamp_datetime) = CURDATE()");
$stmt->bindParam(1, $user_id);
$stmt->execute();
$timestamp_data = $stmt->fetch(PDO::FETCH_ASSOC);
$timestamp_type = $timestamp_data['AnzahlKommen'] > $timestamp_data['AnzahlGehen'] ? "GEHEN" : "KOMMEN";
// Zeitstempel hinzufügen
$insert_stmt = $pdo->prepare("INSERT INTO timestamps (employee_id, timestamp_type, timestamp_datetime, timestamp_endpoint) VALUES (?, ?, NOW(), 1)");
$insert_stmt->bindParam(1, $user_id);
$insert_stmt->bindParam(2, $timestamp_type);
$insert_stmt->execute();
if ($insert_stmt->rowCount() > 0) {
echo '<div class="text-center p-3 my-3 border border-success rounded bg-light text-success font-weight-bold">Zeitstempel für ' . $user['vorname'] . " erfolgreich gesetzt: " . $timestamp_type . "</div>";
} else {
echo "Fehler beim Speichern des Zeitstempels.";
}
} else {
echo "Benutzer nicht gefunden.";
}
} catch(PDOException $e) {
echo "Datenbankfehler: " . $e->getMessage();
}
}
$aktueller_status = "Unbekannt";
$letzte_aktion_zeit = "N/A";
try {
// Abfragen des letzten Status und der Zeit des Mitarbeiters
$status_stmt = $pdo->prepare("SELECT timestamp_type, timestamp_datetime FROM timestamps WHERE employee_id = ? ORDER BY timestamp_datetime DESC LIMIT 1");
$status_stmt->bindParam(1, $user_id);
$status_stmt->execute();
$status_data = $status_stmt->fetch(PDO::FETCH_ASSOC);
if ($status_data) {
$aktueller_status = $status_data['timestamp_type'];
$letzte_aktion_zeit = $status_data['timestamp_datetime'];
}
} catch(PDOException $e) {
echo "Datenbankfehler: " . $e->getMessage();
}
try {
$query2 = "
SELECT
DATE(timestamp_datetime) AS datum,
GROUP_CONCAT(timestamp_type ORDER BY timestamp_datetime) AS day_sequence
FROM
timestamps
WHERE
employee_id = :employee_id AND
DATE(timestamp_datetime) != CURDATE()
GROUP BY
DATE(timestamp_datetime);";
$stmt = $pdo->prepare($query2);
$stmt->bindParam(':employee_id', $user["id"], PDO::PARAM_INT);
$stmt->execute();
$result = $stmt->fetchAll();
#$invalidDates = [];
} catch(PDOException $e) {
echo "Datenbankfehler: " . $e->getMessage();
}
foreach ($result as $row) {
if (!isValidSequence($row["day_sequence"])) {
$fehlerhafteTage[] = $row["datum"];
}
}
#print_r($fehlerhafteTage);
?>
<br>
<?php if ($fehlerhafteTage): ?>
<div class="text-center p-3 my-3 border border-danger rounded bg-light text-danger font-weight-bold">
<p class="mb-0">Es gibt ein Buchungsproblem! <a href="fehlbuchungen.php">Zur Anpassung</a></p>
</div>
<?php endif;
?>
<p class="mb-0">Aktueller Status: <?php
if ($aktueller_status == "GEHEN") {
echo '<div class="text-center p-3 my-3 border border-warning rounded bg-light text-warning font-weight-bold">ABWESEND</div>';
} elseif ($aktueller_status == 'KOMMEN') {
echo '<div class="text-center p-3 my-3 border border-success rounded bg-light text-success font-weight-bold">ANWESEND</div>';
} else {
// Wenn weder "GEHEN" noch "KOMMEN" ist, handle es entsprechend
echo '<div class="text-center p-3 my-3 border border-danger rounded bg-light text-danger font-weight-bold">Unbekannter Status</div>';
}
?></p>
<div class="text-center p-3 my-3 border border-info rounded ">
<p class="mb-0">Letzte Stempelzeit: <?php echo $letzte_aktion_zeit; ?></p>
</div>
<br><br>
<form method="post" action="<?php echo $_SERVER['PHP_SELF'];?>">
<input type="submit" value="Stempeln" class="btn btn-info btn-lg btn-block">
</form>
</div>
</div>
</div>
<?php include 'footer.php'; ?>
+77
View File
@@ -0,0 +1,77 @@
<?php
session_start();
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");
$error_msg = "";
if(isset($_POST['email']) && isset($_POST['passwort'])) {
$email = $_POST['email'];
$passwort = $_POST['passwort'];
$statement = $pdo->prepare("SELECT * FROM users WHERE email = :email");
$result = $statement->execute(array('email' => $email));
$user = $statement->fetch();
//Überprüfung des Passworts
if ($user !== false && password_verify($passwort, $user['passwort'])) {
$_SESSION['userid'] = $user['id'];
//Möchte der Nutzer angemeldet beleiben?
if(isset($_POST['angemeldet_bleiben'])) {
$identifier = random_string();
$securitytoken = random_string();
$insert = $pdo->prepare("INSERT INTO securitytokens (user_id, identifier, securitytoken) VALUES (:user_id, :identifier, :securitytoken)");
$insert->execute(array('user_id' => $user['id'], 'identifier' => $identifier, 'securitytoken' => sha1($securitytoken)));
setcookie("identifier",$identifier,time()+(3600*24*365)); //Valid for 1 year
#$_COOKIE['identifier'] = $identifier;
setcookie("securitytoken",$securitytoken,time()+(3600*24*365)); //Valid for 1 year
#$_COOKIE['securitytoken'] = $securitytoken;
}
echo "<script>window.location.href='index.php';</script>";
//header("location: index.php");
exit;
} else {
$error_msg = "E-Mail oder Passwort war ungültig<br><br>";
}
}
$email_value = "";
if(isset($_POST['email']))
$email_value = htmlentities($_POST['email']);
include("templates/header.inc.php");
?>
<div class="container small-container-330 form-signin">
<form action="login.php" method="post">
<h2 class="form-signin-heading">Login</h2>
<?php
if(isset($error_msg) && !empty($error_msg)) {
echo $error_msg;
}
?>
<label for="inputEmail" class="sr-only">E-Mail</label>
<input type="email" name="email" id="inputEmail" class="form-control" placeholder="E-Mail" value="<?php echo $email_value; ?>" required autofocus>
<label for="inputPassword" class="sr-only">Passwort</label>
<input type="password" name="passwort" id="inputPassword" class="form-control" placeholder="Passwort" required>
<div class="checkbox">
<label>
<input type="checkbox" value="remember-me" name="angemeldet_bleiben" value="1" checked> Angemeldet bleiben
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Login</button>
<br>
<a href="passwortvergessen.php">Passwort vergessen</a>
</form>
</div> <!-- /container -->
<?php
include("templates/footer.inc.php")
?>
+21
View File
@@ -0,0 +1,21 @@
<?php
session_start();
session_destroy();
unset($_SESSION['userid']);
//Remove Cookies
setcookie("identifier","",time()-(3600*24*365));
setcookie("securitytoken","",time()-(3600*24*365));
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");
include("templates/header.inc.php");
?>
<div class="container main-container">
Der Logout war erfolgreich. <a href="login.php">Zurück zum Login</a>.
</div>
<?php
include("templates/footer.inc.php")
?>
+61
View File
@@ -0,0 +1,61 @@
<?php
session_start();
require_once('inc/config.inc.php');
require_once('inc/functions.inc.php');
$user = check_user();
// personal calendar available to any logged-in user
include 'header.php';
?>
<div class="container">
<h2>Mein Urlaubskalender</h2>
<div id="calendar"></div>
<br>
<div>
<span class="badge badge-success">genehmigt</span>
<span class="badge badge-warning">beantragt</span>
<span class="badge badge-primary">Betriebsurlaub</span>
</div>
<br>
<div id="eventDetails" style="display:none;">
<h4>Details</h4>
<div id="detailsContent"></div>
</div>
</div>
<link href='https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.css' rel='stylesheet' />
<script src='https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.js'></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'dayGridMonth',
firstDay: 1,
height: 650,
events: function(info, successCallback, failureCallback) {
var url = 'api/vacations.php?start=' + info.startStr + '&end=' + info.endStr + '&only_personal=1';
fetch(url).then(function(res){ return res.json(); }).then(function(data){ successCallback(data); }).catch(function(err){ failureCallback(err); });
},
eventClick: function(info) {
var ev = info.event;
var props = ev.extendedProps;
var html = '<strong>' + ev.title + '</strong><br>' + ev.start.toLocaleDateString() + ' - ' + (new Date(ev.end).toLocaleDateString()) + '<br>';
if (props.type === 'user') {
html += 'Status: ' + (props.status || '') + '<br>';
html += 'Kommentar: ' + (props.comment || '') + '<br>';
} else if (props.type === 'company') {
html += 'Beschreibung: ' + (props.description || '') + '<br>';
}
document.getElementById('detailsContent').innerHTML = html;
document.getElementById('eventDetails').style.display = 'block';
}
});
calendar.render();
});
</script>
<?php include 'footer.php'; ?>
+80
View File
@@ -0,0 +1,80 @@
<?php
session_start();
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");
//Überprüfe, dass der User eingeloggt ist
//Der Aufruf von check_user() muss in alle internen Seiten eingebaut sein
$user = check_user();
?>
<?php include 'header.php'; ?>
<div class="container">
<div class="row">
<div class="col-md-12">
<h2>Stempelkarten-System</h2>
<?php
// Überprüfen, ob eine Benutzer-ID in der Session vorhanden ist
if (!isset($_SESSION['userid'])) {
die("Kein Benutzer angemeldet.");
}
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$employee_id = $_POST['employee_id'];
$datum = $_POST['datum'];
$buchungen = $_POST['buchungen'];
$deleted_entries = $_POST['deleted_entries']; // IDs der zu löschenden Einträge
// Überprüfen, ob alle Termineinträge für denselben Tag sind
foreach ($buchungen as $timestamp_id => $buchung) {
if (date('Y-m-d', strtotime($buchung['timestamp_datetime'])) !== $datum) {
die("Fehler: Nicht alle Termineinträge sind für denselben Tag.");
}
}
try {
$pdo->beginTransaction();
// Löschvorgänge durchführen
foreach ($deleted_entries as $deleted_id) {
$delete_query = "DELETE FROM timestamps WHERE timestamp_id = :timestamp_id AND employee_id = :employee_id";
$stmt = $pdo->prepare($delete_query);
$stmt->bindParam(':timestamp_id', $deleted_id, PDO::PARAM_INT);
$stmt->bindParam(':employee_id', $employee_id, PDO::PARAM_INT);
$stmt->execute();
}
// Speichern oder Aktualisieren der Buchungen
foreach ($buchungen as $timestamp_id => $buchung) {
if (strpos($timestamp_id, 'new_') !== false) {
// Neue Buchung hinzufügen
$insert_query = "INSERT INTO timestamps (employee_id, timestamp_type, timestamp_datetime) VALUES (:employee_id, :timestamp_type, :timestamp_datetime)";
$stmt = $pdo->prepare($insert_query);
} else {
// Bestehende Buchung aktualisieren
$update_query = "UPDATE timestamps SET timestamp_type = :timestamp_type, timestamp_datetime = :timestamp_datetime WHERE timestamp_id = :timestamp_id AND employee_id = :employee_id";
$stmt = $pdo->prepare($update_query);
$stmt->bindParam(':timestamp_id', $timestamp_id, PDO::PARAM_INT);
}
$stmt->bindParam(':employee_id', $employee_id, PDO::PARAM_INT);
$stmt->bindParam(':timestamp_type', $buchung['timestamp_type']);
$stmt->bindParam(':timestamp_datetime', $buchung['timestamp_datetime']);
$stmt->execute();
}
$pdo->commit();
echo "Änderungen erfolgreich gespeichert.";
} catch(PDOException $e) {
$pdo->rollBack();
echo "Datenbankfehler: " . $e->getMessage();
}
} else {
die("Ungültige Anfrage.");
}
?>
</div>
</div>
</div>
<?php include 'footer.php'; ?>
+114
View File
@@ -0,0 +1,114 @@
<?php
session_start();
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");
//Überprüfe, dass der User eingeloggt ist
//Der Aufruf von check_user() muss in alle internen Seiten eingebaut sein
$user = check_user();
?>
<?php include 'header.php'; ?>
<div class="container">
<div class="row">
<div class="col-md-12">
<?php
// Überprüfen, ob eine Benutzer-ID in der Session vorhanden ist
if (!isset($_SESSION['userid'])) {
die("Kein Benutzer angemeldet.");
}
if($user["admin"] != 1){
die("Kein Admin-Rechte.");
}
// Bearbeitungslogik
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['email'])) {
$email = $_POST['email'];
$vorname = $_POST['vorname'];
$nachname = $_POST['nachname'];
// Füge neuen Mitarbeiter hinzu
$sql = "INSERT INTO users (email, vorname, nachname) VALUES (?, ?, ?)";
$stmt = $pdo->prepare($sql);
$stmt->execute([$email, $vorname, $nachname]);
echo "<br><div class='alert alert-success' role='alert'>Vorgang erfolgreich ausgeführt.</div>";
}
// Abfrage der Mitarbeiterdaten
$sql = "SELECT id, email, vorname, nachname, zeiterfassung, worker, admin, card_id, card2_id FROM users";
$stmt = $pdo->query($sql);
?>
<div class="container mt-5">
<h2>Mitarbeiterliste</h2>
<div class="table-responsive">
<table class="table table-bordered">
<thead class="thead-light">
<tr>
<th>ID</th>
<th>Email</th>
<th>Vorname</th>
<th>Nachname</th>
<th>Zeiterfassung</th>
<th>worker</th>
<th>Admin</th>
<th>Card ID</th>
<th>Card2 ID</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
<?php
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo "<tr>";
echo "<td>" . htmlspecialchars($row['id']) . "</td>";
echo "<td>" . htmlspecialchars($row['email']) . "</td>";
echo "<td>" . htmlspecialchars($row['vorname']) . "</td>";
echo "<td>" . htmlspecialchars($row['nachname']) . "</td>";
echo "<td>" ;
if($row['zeiterfassung'] == "1"){echo "Ja";}
echo "</td>";
echo "<td>" ;
if($row['worker'] == "1"){echo "Ja";}
echo "</td>";
echo "<td>" ;
if($row['admin'] == "1"){echo "Ja";}
echo "</td>";
echo "<td>" . htmlspecialchars($row['card_id']) . "</td>";
echo "<td>" . htmlspecialchars($row['card2_id']) . "</td>";
echo "<td><a class='btn btn-primary btn-sm' href='editworker.php?id=" . $row["id"] . "'>Bearbeiten</a></td>";
echo "</tr>";
}
?>
</tbody>
</table>
</div>
<h2>Neuen Mitarbeiter hinzufügen</h2>
<form action="" method="post" >
<div class="form-group">
<label for="email">Email</label>
<input type="text" class="form-control" id="email" name="email" required>
</div>
<div class="form-group">
<label for="vorname">Vorname</label>
<input type="text" class="form-control" id="vorname" name="vorname" required>
</div>
<div class="form-group">
<label for="nachname">Nachname</label>
<input type="text" class="form-control" id="nachname" name="nachname" required>
</div>
<button type="submit" class="btn btn-success">Hinzufügen</button>
</form>
<br>
<button type="button" class="btn btn-secondary" onclick="history.back();">Zurück</button>
</div>
</div>
</div>
</div>
<?php include 'footer.php'; ?>
+121
View File
@@ -0,0 +1,121 @@
<?php
session_start();
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");
$user = check_user();
if (!isset($_SESSION['userid'])) {
die("Kein Benutzer angemeldet.");
}
if ($_SESSION['admin'] != 1) {
die("Kein Zugriff.");
}
$admin_id = $_SESSION['userid'];
$message = "";
/* ===== Antrag bearbeiten ===== */
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['vacation_id'])) {
$vacation_id = (int)$_POST['vacation_id'];
$action = $_POST['action'];
$comment_admin = trim($_POST['comment_admin']);
if ($action == "genehmigen") {
$status = "genehmigt";
} elseif ($action == "ablehnen") {
$status = "abgelehnt";
} else {
die("Ungültige Aktion.");
}
$stmt = $pdo->prepare("
UPDATE vacations
SET status = ?,
approved_by = ?,
approved_at = NOW()
WHERE id = ?
");
$stmt->execute([$status, $admin_id, $vacation_id]);
$message = "Antrag erfolgreich aktualisiert.";
}
/* ===== Offene Anträge laden ===== */
$stmt = $pdo->prepare("
SELECT v.*, u.vorname, u.nachname
FROM vacations v
JOIN users u ON u.id = v.user_id
WHERE v.status = 'beantragt'
ORDER BY v.start_date ASC
");
$stmt->execute();
$antraege = $stmt->fetchAll();
?>
<?php include 'header.php'; ?>
<div class="container">
<div class="row">
<div class="col-md-12">
<h2>Urlaubsanträge genehmigen</h2>
<?php if ($message): ?>
<div class="alert alert-success"><?php echo $message; ?></div>
<?php endif; ?>
<?php if (count($antraege) == 0): ?>
<div class="alert alert-info">Keine offenen Anträge.</div>
<?php else: ?>
<table class="table table-bordered table-striped">
<tr>
<th>Mitarbeiter</th>
<th>Von</th>
<th>Bis</th>
<th>Tage</th>
<th>Kommentar</th>
<th>Aktion</th>
</tr>
<?php foreach ($antraege as $a): ?>
<tr>
<td><?php echo htmlspecialchars($a['vorname'] . " " . $a['nachname']); ?></td>
<td><?php echo $a['start_date']; ?></td>
<td><?php echo $a['end_date']; ?></td>
<td><?php echo $a['days']; ?></td>
<td><?php echo htmlspecialchars($a['comment_user']); ?></td>
<td>
<form method="post" style="display:inline;">
<input type="hidden" name="vacation_id" value="<?php echo $a['id']; ?>">
<input type="hidden" name="action" value="genehmigen">
<button type="submit" class="btn btn-success btn-sm">
Genehmigen
</button>
</form>
<form method="post" style="display:inline;">
<input type="hidden" name="vacation_id" value="<?php echo $a['id']; ?>">
<input type="hidden" name="action" value="ablehnen">
<button type="submit" class="btn btn-danger btn-sm">
Ablehnen
</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</table>
<?php endif; ?>
</div>
</div>
</div>
<?php include 'footer.php'; ?>
+178
View File
@@ -0,0 +1,178 @@
<?php
session_start();
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");
$user = check_user();
if (!isset($_SESSION['userid'])) {
die("Kein Benutzer angemeldet.");
}
$user_id = $_SESSION['userid'];
$message = "";
$error = "";
function calculateWorkingDays($start, $end) {
$start = new DateTime($start);
$end = new DateTime($end);
$end->modify('+1 day');
$interval = new DateInterval('P1D');
$period = new DatePeriod($start, $interval, $end);
$workingDays = 0;
foreach ($period as $day) {
if ($day->format('N') < 6) { // 1 (Mo) - 5 (Fr)
$workingDays++;
}
}
return $workingDays;
}
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$start_date = $_POST['start_date'];
$end_date = $_POST['end_date'];
$comment = trim($_POST['comment']);
if (empty($start_date) || empty($end_date)) {
$error = "Bitte beide Datumsfelder ausfüllen.";
} elseif ($start_date > $end_date) {
$error = "Enddatum liegt vor dem Startdatum.";
} elseif ($start_date < date("Y-m-d")) {
$error = "Urlaub kann nicht in der Vergangenheit beantragt werden.";
} else {
// Überschneidung prüfen
$stmt = $pdo->prepare("
SELECT COUNT(*) FROM vacations
WHERE user_id = ?
AND status != 'abgelehnt'
AND (
(start_date BETWEEN ? AND ?)
OR (end_date BETWEEN ? AND ?)
OR (? BETWEEN start_date AND end_date)
)
");
$stmt->execute([$user_id, $start_date, $end_date, $start_date, $end_date, $start_date]);
$exists = $stmt->fetchColumn();
if ($exists > 0) {
$error = "Der Zeitraum überschneidet sich mit einem bestehenden Antrag.";
} else {
$days = calculateWorkingDays($start_date, $end_date);
$insert = $pdo->prepare("
INSERT INTO vacations (user_id, start_date, end_date, days, comment_user)
VALUES (?, ?, ?, ?, ?)
");
$insert->execute([$user_id, $start_date, $end_date, $days, $comment]);
$message = "Urlaubsantrag erfolgreich eingereicht ($days Werktage).";
}
}
}
?>
<?php include 'header.php'; ?>
<div class="container">
<div class="row">
<div class="col-md-8 offset-md-2">
<h2>Urlaubsantrag</h2>
<?php if ($error): ?>
<div class="alert alert-danger"><?php echo $error; ?></div>
<?php endif; ?>
<?php if ($message): ?>
<div class="alert alert-success"><?php echo $message; ?></div>
<?php endif; ?>
<form method="post">
<div class="form-group">
<label>Von:</label>
<input type="date" name="start_date" class="form-control" required>
</div>
<div class="form-group">
<label>Bis:</label>
<input type="date" name="end_date" class="form-control" required>
</div>
<div class="form-group">
<label>Kommentar (optional):</label>
<textarea name="comment" class="form-control"></textarea>
</div>
<br>
<button type="submit" class="btn btn-primary btn-block">
Urlaub beantragen
</button>
</form>
<hr>
<h4>Meine Anträge</h4>
<?php
$stmt = $pdo->prepare("
SELECT * FROM vacations
WHERE user_id = ?
ORDER BY created_at DESC
");
$stmt->execute([$user_id]);
$antraege = $stmt->fetchAll();
?>
<table class="table table-bordered">
<tr>
<th>Von</th>
<th>Bis</th>
<th>Tage</th>
<th>Status</th>
<th>Aktion</th>
</tr>
<?php foreach ($antraege as $a): ?>
<tr>
<td><?php echo $a['start_date']; ?></td>
<td><?php echo $a['end_date']; ?></td>
<td><?php echo $a['days']; ?></td>
<td>
<?php
if ($a['status'] == 'beantragt') {
echo '<span class="badge badge-warning">Beantragt</span>';
} elseif ($a['status'] == 'genehmigt') {
echo '<span class="badge badge-success">Genehmigt</span>';
} else {
echo '<span class="badge badge-danger">Abgelehnt</span>';
}
?>
</td>
<td>
<form method="post" action="deleteVacation.php" onsubmit="return confirm('Wirklich löschen?');">
<input type="hidden" name="id" value="<?php echo $a['id']; ?>">
<input type="hidden" name="referer" value="urlaubsantrag.php">
<button type="submit" class="btn btn-sm btn-danger">Löschen</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</table>
</div>
</div>
</div>
<?php include 'footer.php'; ?>
+63
View File
@@ -0,0 +1,63 @@
<?php
session_start();
require_once('inc/config.inc.php');
require_once('inc/functions.inc.php');
$user = check_user();
if (!is_admin_user()) {
die('Zugriff verweigert. Nur Chefs dürfen den Kalender sehen.');
}
include 'header.php';
?>
<div class="container">
<h2>Team Urlaubskalender</h2>
<div id="calendar"></div>
<br>
<div>
<span class="badge badge-success">genehmigt</span>
<span class="badge badge-warning">beantragt</span>
<span class="badge badge-primary">Betriebsurlaub</span>
</div>
<br>
<div id="eventDetails" style="display:none;">
<h4>Details</h4>
<div id="detailsContent"></div>
</div>
</div>
<link href='https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.css' rel='stylesheet' />
<script src='https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.js'></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'dayGridMonth',
firstDay: 1,
height: 650,
events: function(info, successCallback, failureCallback) {
var url = 'api/vacations.php?start=' + info.startStr + '&end=' + info.endStr;
fetch(url).then(function(res){ return res.json(); }).then(function(data){ successCallback(data); }).catch(function(err){ failureCallback(err); });
},
eventClick: function(info) {
var ev = info.event;
var props = ev.extendedProps;
var html = '<strong>' + ev.title + '</strong><br>' + ev.start.toLocaleDateString() + ' - ' + (new Date(ev.end).toLocaleDateString()) + '<br>';
if (props.type === 'user') {
html += 'Status: ' + (props.status || '') + '<br>';
html += 'Kommentar: ' + (props.comment || '') + '<br>';
} else if (props.type === 'company') {
html += 'Beschreibung: ' + (props.description || '') + '<br>';
}
document.getElementById('detailsContent').innerHTML = html;
document.getElementById('eventDetails').style.display = 'block';
}
});
calendar.render();
});
</script>
<?php include 'footer.php'; ?>
+59
View File
@@ -0,0 +1,59 @@
<?php
session_start();
require_once('inc/config.inc.php');
require_once('inc/functions.inc.php');
// allow any logged-in user to view the team calendar (read-only)
$user = check_user();
include 'header.php';
?>
<div class="container">
<h2>Team Urlaubskalender</h2>
<div id="calendar"></div>
<br>
<div>
<span class="badge badge-success">genehmigt</span>
<span class="badge badge-primary">Betriebsurlaub</span>
</div>
<br>
<div id="eventDetails" style="display:none;">
<h4>Details</h4>
<div id="detailsContent"></div>
</div>
</div>
<link href='https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.css' rel='stylesheet' />
<script src='https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.js'></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'dayGridMonth',
firstDay: 1,
height: 650,
events: function(info, successCallback, failureCallback) {
var url = 'api/vacations.php?start=' + info.startStr + '&end=' + info.endStr + '&public=1&public_all=1';
fetch(url).then(function(res){ return res.json(); }).then(function(data){ successCallback(data); }).catch(function(err){ failureCallback(err); });
},
eventClick: function(info) {
var ev = info.event;
var props = ev.extendedProps;
var html = '<strong>' + ev.title + '</strong><br>' + ev.start.toLocaleDateString() + ' - ' + (new Date(ev.end).toLocaleDateString()) + '<br>';
if (props.type === 'user') {
html += 'Mitarbeiter-ID: ' + (props.user_id || '') + '<br>';
} else if (props.type === 'company') {
html += 'Beschreibung: ' + (props.description || '') + '<br>';
}
document.getElementById('detailsContent').innerHTML = html;
document.getElementById('eventDetails').style.display = 'block';
}
});
calendar.render();
});
</script>
<?php include 'footer.php'; ?>
+84
View File
@@ -0,0 +1,84 @@
<?php
session_start();
require_once('inc/config.inc.php');
require_once('inc/functions.inc.php');
$user = check_user();
if (!is_admin_user()) {
die('Zugriff verweigert. Nur Chefs dürfen die Urlaubsübersicht sehen.');
}
include 'header.php';
// Jahr für Auswertung
$year = date('Y');
// Lade alle Mitarbeiter
$stmt = $pdo->prepare("SELECT id, vorname, nachname, email, urlaubstage FROM users ORDER BY nachname, vorname");
$stmt->execute();
$users = $stmt->fetchAll();
?>
<div class="container">
<h2>Urlaubsübersicht (<?php echo $year; ?>)</h2>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Mitarbeiter</th>
<th>Email</th>
<th>Anspruch</th>
<th>Genutzt (<?php echo $year; ?>)</th>
<th>Verbleibend</th>
<th>Ausstehend</th>
<th>Bevorstehende Urlaube</th>
</tr>
</thead>
<tbody>
<?php foreach ($users as $u):
$uid = $u['id'];
// Genutzte Tage (genehmigt) im Jahr
$s = $pdo->prepare("SELECT IFNULL(SUM(days),0) AS used FROM vacations WHERE user_id = ? AND status = 'genehmigt' AND YEAR(start_date) = ?");
$s->execute([$uid, $year]);
$used = (int)$s->fetchColumn();
// Ausstehende Anträge
$p = $pdo->prepare("SELECT COUNT(*) FROM vacations WHERE user_id = ? AND status = 'beantragt'");
$p->execute([$uid]);
$pending = (int)$p->fetchColumn();
// Bevorstehende Urlaube (nächste 5)
$n = $pdo->prepare("SELECT start_date, end_date, days, status FROM vacations WHERE user_id = ? AND end_date >= CURDATE() ORDER BY start_date LIMIT 5");
$n->execute([$uid]);
$upcoming = $n->fetchAll();
$entitlement = isset($u['urlaubstage']) ? (int)$u['urlaubstage'] : 0;
$remaining = $entitlement - $used;
?>
<tr>
<td><?php echo htmlspecialchars($u['vorname'] . ' ' . $u['nachname']); ?></td>
<td><?php echo htmlspecialchars($u['email']); ?></td>
<td><?php echo $entitlement; ?></td>
<td><?php echo $used; ?></td>
<td><?php echo $remaining; ?></td>
<td><?php echo $pending; ?></td>
<td>
<?php if (count($upcoming) == 0) { echo '-'; } else {
foreach ($upcoming as $up) {
echo htmlspecialchars($up['start_date'] . ' → ' . $up['end_date'] . ' (' . $up['days'] . 'd) ' . ' [' . $up['status'] . ']');
echo '<br>';
}
} ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<p>Hinweis: Ansprüche werden aus dem Feld <strong>users.urlaubstage</strong> gelesen. Falls dieses Feld leer ist, bitte in der Nutzerverwaltung pflegen.</p>
</div>
<?php include 'footer.php'; ?>