prepare intranet for first Dokploy deployment

This commit is contained in:
2026-08-26 12:59:51 +02:00
parent 5cfe688bdc
commit 29dfb85fef
1321 changed files with 227234 additions and 0 deletions
@@ -0,0 +1,26 @@
<?php /* Name: button_edit.php
Beschreibung: Button-Ausgabe für die Umschaltung auf den Bearbeitungsmodus
GET-Parameter: action=edit
id=[$edit_id] */
?>
<div class="right">
<?php
if (isset($_GET['action']) && $_GET['action'] == 'edit') {
display_button('edit','Bearbeiten','right');
} else {
if (isset($edit_id)) {
echo "<a href='".$g_httpCurrentCleanUrl."?action=edit&id=$edit_id' style='display:table-cell;'>";
} else {
echo "<a href='".$g_httpCurrentCleanUrl."?action=edit' style='display:table-cell;'>";
}
display_button('edit','Bearbeiten','right');
echo "</a>";
}
?>
</div>
@@ -0,0 +1,119 @@
<?php /* Name: contact_modal.php
Beschreibung: Globales Kontaktformular-Modal
- Wird überall eingebunden wo technik@-Link war
- Sendet per AJAX an process_contact.php */
?>
<!-- Kontaktformular Modal -->
<div class="standard_overlay" id="contactModal" onclick="closeContactModalOnBackdrop(event)">
<div style="position:relative;width:min(520px,calc(100vw - 24px));max-height:min(700px,calc(100vh - 24px));overflow:auto;background:#FFF;border-radius:0;box-shadow:0 24px 70px rgba(0,0,0,0.36);">
<button type="button" onclick="closeContactModal()" style="position:absolute;top:14px;right:14px;width:34px;height:34px;border-radius:0;border:1px solid rgba(255,255,255,0.25);background:rgba(255,255,255,0.16);color:#FFF;font-size:1.35em;cursor:pointer;z-index:1;">×</button>
<div style="padding:24px;color:#FFF;background:radial-gradient(circle at 10% 0%,rgba(255,255,255,0.24),transparent 32%),linear-gradient(135deg,var(--theme-color),var(--theme-hover));border-radius:0;">
<div style="font-size:1.3em;font-weight:850;">Admin kontaktieren</div>
<div style="margin-top:6px;color:rgba(255,255,255,0.8);font-weight:600;">Ihr Anliegen wird an den Administrator weitergeleitet.</div>
</div>
<div style="padding:22px 24px 24px 24px;">
<form id="contactForm" onsubmit="submitContactForm(event)">
<?php
$isLoggedIn = isset($user) && !empty($user['first_name']) && !empty($user['mail']);
$prefillName = $isLoggedIn ? htmlspecialchars($user['first_name'] . ' ' . $user['last_name']) : '';
$prefillMail = $isLoggedIn ? htmlspecialchars($user['mail']) : '';
$readonlyAttr = $isLoggedIn ? 'readonly' : '';
$readonlyStyle = $isLoggedIn ? 'cursor:not-allowed;opacity:0.7;' : '';
?>
<label style="display:block;margin-bottom:4px;font-weight:750;font-size:0.88em;color:hsl(210,18%,36%);text-transform:uppercase;letter-spacing:0.04em;">Name</label>
<input type="text" name="contact_name" id="contact_name" required <?= $readonlyAttr ?>
value="<?= $prefillName ?>"
style="width:100%;padding:12px 14px;border:1px solid hsl(210,18%,84%);border-radius:0;background:hsl(210,12%,98%);font-size:1em;font-weight:650;outline:none;margin-bottom:12px;box-sizing:border-box;<?= $readonlyStyle ?>">
<label style="display:block;margin-bottom:4px;font-weight:750;font-size:0.88em;color:hsl(210,18%,36%);text-transform:uppercase;letter-spacing:0.04em;">E-Mail</label>
<input type="email" name="contact_email" id="contact_email" required <?= $readonlyAttr ?>
value="<?= $prefillMail ?>"
style="width:100%;padding:12px 14px;border:1px solid hsl(210,18%,84%);border-radius:0;background:hsl(210,12%,98%);font-size:1em;font-weight:650;outline:none;margin-bottom:12px;box-sizing:border-box;<?= $readonlyStyle ?>">
<?php if ($isLoggedIn): ?>
<div style="margin:-8px 0 12px 0;font-size:0.82em;color:hsl(210,14%,50%);font-weight:600;">Ihre Kontaktdaten werden automatisch aus Ihrem Profil übernommen.</div>
<?php endif; ?>
<label style="display:block;margin-bottom:4px;font-weight:750;font-size:0.88em;color:hsl(210,18%,36%);text-transform:uppercase;letter-spacing:0.04em;">Betreff</label>
<input type="text" name="contact_subject" id="contact_subject" required
style="width:100%;padding:12px 14px;border:1px solid hsl(210,18%,84%);border-radius:0;background:hsl(210,12%,98%);font-size:1em;font-weight:650;outline:none;margin-bottom:12px;box-sizing:border-box;">
<label style="display:block;margin-bottom:4px;font-weight:750;font-size:0.88em;color:hsl(210,18%,36%);text-transform:uppercase;letter-spacing:0.04em;">Nachricht</label>
<textarea name="contact_message" id="contact_message" rows="5" required
style="width:100%;padding:12px 14px;border:1px solid hsl(210,18%,84%);border-radius:0;background:hsl(210,12%,98%);font-size:1em;font-weight:650;outline:none;margin-bottom:16px;resize:vertical;box-sizing:border-box;font-family:inherit;"></textarea>
<div style="display:flex;justify-content:flex-end;gap:8px;">
<button type="button" onclick="closeContactModal()" style="padding:8px 16px;border:1px solid hsl(210,18%,84%);border-radius:0;background:#FFF;font-weight:850;font-size:0.86em;cursor:pointer;">Abbrechen</button>
<button type="submit" id="contactSubmitBtn" style="padding:8px 16px;border:1px solid var(--theme-color);border-radius:0;background:linear-gradient(135deg,var(--theme-color),var(--theme-hover));color:#FFF;font-weight:850;font-size:0.86em;cursor:pointer;">Nachricht senden</button>
</div>
</form>
<div id="contactFormResult" style="display:none;margin-top:12px;padding:10px 14px;border-radius:0;font-weight:700;text-align:center;"></div>
</div>
</div>
</div>
<script>
function openContactModal() {
document.getElementById('contactModal').style.display = 'flex';
}
function closeContactModal() {
document.getElementById('contactModal').style.display = 'none';
document.getElementById('contactFormResult').style.display = 'none';
document.getElementById('contactSubmitBtn').disabled = false;
document.getElementById('contactSubmitBtn').textContent = 'Nachricht senden';
}
function closeContactModalOnBackdrop(event) {
if (event.target.id === 'contactModal') closeContactModal();
}
function submitContactForm(event) {
event.preventDefault();
const form = document.getElementById('contactForm');
const resultDiv = document.getElementById('contactFormResult');
const submitBtn = document.getElementById('contactSubmitBtn');
submitBtn.disabled = true;
submitBtn.textContent = 'Wird gesendet...';
const formData = new FormData(form);
fetch('/intranet_repo/projects/adminpanel/process_contact.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
resultDiv.style.display = 'block';
if (data.success) {
resultDiv.style.background = 'hsl(145, 50%, 93%)';
resultDiv.style.color = 'hsl(145, 50%, 28%)';
resultDiv.textContent = 'Nachricht erfolgreich gesendet!';
form.reset();
setTimeout(() => closeContactModal(), 2000);
} else {
resultDiv.style.background = 'hsl(0, 78%, 95%)';
resultDiv.style.color = 'hsl(0, 78%, 40%)';
resultDiv.textContent = data.error || 'Ein Fehler ist aufgetreten.';
submitBtn.disabled = false;
submitBtn.textContent = 'Nachricht senden';
}
})
.catch(() => {
resultDiv.style.display = 'block';
resultDiv.style.background = 'hsl(0, 78%, 95%)';
resultDiv.style.color = 'hsl(0, 78%, 40%)';
resultDiv.textContent = 'Verbindungsfehler. Bitte erneut versuchen.';
submitBtn.disabled = false;
submitBtn.textContent = 'Nachricht senden';
});
}
document.addEventListener('keydown', function(event) {
if (event.key === 'Escape' && document.getElementById('contactModal').style.display === 'flex') {
closeContactModal();
}
});
</script>
@@ -0,0 +1,30 @@
<?php
/*
Name: countdown.php
Beschreibung: Reload der aktuellen Seite mit Countdown
*/
?>
<div class="countdown"><span id="countdown">120</span></div>
<script>
var countdown = document.getElementById("countdown").textContent;
let pauseCountdown = false; //Von außen kann der Countdown angehalten werden: pauseCountdown = true
var countdownTimer = setInterval(function() {
if (!pauseCountdown) {
countdown--;
document.getElementById('countdown').textContent = countdown;
if ((countdown <= 0)) {
clearInterval(countdownTimer);
window.location.reload();
}
}
}, 1000);
</script>
@@ -0,0 +1,21 @@
<?php /* Name: overlay_addNewUser.php
Beschreibung: Neuen Nutzer anlegen in einem Overlay
- wird in admin.php aufgerufen */
// Neuen Nutzer anlegen im Overlay (Formular) ?>
<div class="standard_overlay" id="addNewUser">
<div class="bg_blur"></div>
<form method="post" action="">
<div class="eventbox_mini center">
<div class="exit" onclick="openCloseOverlay('addNewUser')">
<?php display_button('cancel','','center'); ?>
</div>
<h3 style="margin-top:15px;margin-left:5px;margin-bottom:15px">Neuen Nutzer anlegen</h3>
<div class="item">
<input class="field" placeholder="E-Mailadresse" type="text" name="newMail"required>
<input class="button" type="submit" name="addRecord" value="Hinzufügen">
</div>
</div>
</form>
</div>
@@ -0,0 +1,73 @@
<?php /* Name: overlay_message.php
Beschreibung: Ausgabe einer Message als Toast-Notification
Anforderung: Ausgabe möglichst zum <body>-Beginn. */
// Mapping aller Intranet-Messageboxen mit Typ und Ausgabetext
function getMessageInfo($message) {
return match ($message) {
1 => ['type' => 'success', 'text' => "Passwort zurückgesetzt."],
2 => ['type' => 'success', 'text' => "Nutzer entfernt."],
3 => ['type' => 'success', 'text' => "Nutzer angelegt."],
4 => ['type' => 'error', 'text' => "Nutzer existiert bereits."],
5 => ['type' => 'success', 'text' => "Speicherung erfolgt."],
6 => ['type' => 'success', 'text' => "Einladungsmail gesendet."],
7 => ['type' => 'error', 'text' => "Bitte Name und E-Mail ausfüllen."],
8 => ['type' => 'success', 'text' => "Brandschutzschulung abgeschlossen. Vielen Dank für deine Teilnahme!"],
default => ['type' => 'error', 'text' => "Unbekannter Fehler."],
};
}
// Laden der Message
if (isset($_GET["message"])) {
$message = intval($_GET["message"]);
$messageInfo = getMessageInfo($message);
$toastType = $messageInfo['type'];
$toastText = $messageInfo['text'];
?>
<div class="nak-toast nak-toast--<?= $toastType ?>" id="nakToast">
<div class="nak-toast__icon">
<?php if ($toastType === 'success'): ?>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="square" stroke-linejoin="miter"><path d="M20 6L9 17l-5-5"/></svg>
<?php else: ?>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="square" stroke-linejoin="miter"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
<?php endif; ?>
</div>
<span class="nak-toast__text"><?= htmlspecialchars($toastText) ?></span>
<button class="nak-toast__close" onclick="dismissNakToast()" aria-label="Schließen">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="square" stroke-linejoin="miter"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
</button>
</div>
<script>
(function() {
var toast = document.getElementById('nakToast');
if (!toast) return;
// Slide in
requestAnimationFrame(function() {
toast.classList.add('nak-toast--visible');
});
// Auto-dismiss after 4s
var timer = setTimeout(function() { dismissNakToast(); }, 4000);
toast._timer = timer;
// Clean URL
if (window.history && window.history.replaceState) {
var url = new URL(window.location);
url.searchParams.delete('message');
window.history.replaceState({}, '', url);
}
})();
function dismissNakToast() {
var toast = document.getElementById('nakToast');
if (!toast || toast.classList.contains('nak-toast--hiding')) return;
clearTimeout(toast._timer);
toast.classList.add('nak-toast--hiding');
toast.classList.remove('nak-toast--visible');
setTimeout(function() { toast.remove(); }, 350);
}
</script>
<?php } ?>
@@ -0,0 +1,81 @@
<?php /* Name: overlay_profile.php
Beschreibung: Profil eines ausgewählten Nutzers im Overlay */
?>
<?php
if (isset($_SESSION["profile_id"])) {
$pdo = require($_SERVER['DOCUMENT_ROOT']."/intranet_repo/general_files/ini/database.php");
$sql = "SELECT * FROM user_general_information
WHERE user_id = {$_SESSION["profile_id"]}";
$result = $pdo->query($sql);
$partner = $result->fetch(PDO::FETCH_ASSOC);
if (isset($partner["mail"])) {
$sql_groups = "SELECT * FROM user_permissions WHERE user_id = ?";
$stmt = $pdo->prepare($sql_groups);
$stmt->execute([$_SESSION["profile_id"]]);
$groups = $stmt->fetch(PDO::FETCH_ASSOC);
}
}
else {
header("Location:{$g_httpLoginPath}");
exit();
}
// Profile image
$profileImg = glob($_SERVER['DOCUMENT_ROOT']."/intranet_repo/general_files/profile_pictures/{$_SESSION["profile_id"]}-*.jpg");
if (!empty($profileImg)) {
usort($profileImg, function($a, $b) { return filemtime($b) - filemtime($a); });
$profileImgUrl = str_replace($_SERVER['DOCUMENT_ROOT'], '', $profileImg[0]);
} else {
$profileImgUrl = "/intranet_repo/general_files/profile_pictures/default.jpg";
}
$fullName = trim(($partner["first_name"] ?? '') . ' ' . ($partner["last_name"] ?? ''));
$isRegistered = !empty($partner["first_name"]);
?>
<div class="profile-modal-card">
<button type="button" class="exit" aria-label="Schließen" onclick="openCloseProfile(0, '<?= $profile_container_name ?>', '<?= $profile_overlay_id ?>');">×</button>
<div class="profile-modal-hero">
<img class="profile-modal-img" src="<?= htmlspecialchars($profileImgUrl) ?>" alt="Profilbild">
<div>
<?php if ($isRegistered): ?>
<div class="profile-modal-title"><?= htmlspecialchars($fullName) ?></div>
<?php else: ?>
<div class="profile-modal-title" style="color:rgba(255,255,255,0.7);">Nicht registriert</div>
<?php endif; ?>
<div class="profile-modal-subtitle">
<span><?= htmlspecialchars($partner["mail"]) ?></span>
</div>
</div>
</div>
<div class="profile-modal-body">
<?php if ($partner["phone"] != null): ?>
<div class="profile-modal-field">
<div class="profile-modal-field-label">Telefon</div>
<div class="profile-modal-field-value">
<a href="tel:0<?= htmlspecialchars($partner["phone"]) ?>">0<?= htmlspecialchars($partner["phone"]) ?></a>
</div>
</div>
<?php endif; ?>
<?php if (isset($groups)): ?>
<div class="profile-modal-field">
<div class="profile-modal-field-label">Gruppen</div>
<div class="profile-modal-chips">
<?php
foreach ($groups as $key => $value) {
if ($value == 1) {
echo '<span class="profile-modal-chip">' . htmlspecialchars($key) . '</span>';
}
}
?>
</div>
</div>
<?php endif; ?>
</div>
</div>