shopAdder.php aktualisiert
This commit is contained in:
parent
77ced928b0
commit
9f2dbb29d0
111
shopAdder.php
111
shopAdder.php
@ -1,11 +1,25 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* @file shopAdder.php
|
* @file shopAdder.php
|
||||||
* @brief Shop hinzufügen
|
* @brief Shop-Verwaltungssystem (Hinzufügen und Löschen von Shops)
|
||||||
|
*
|
||||||
|
* Dieses Skript ermöglicht Administratoren das Hinzufügen neuer Shops sowie das Löschen
|
||||||
|
* bestehender Shops, sofern diese keine verknüpften Angebote (Offers) haben.
|
||||||
|
* Es enthält Funktionen für den Upload oder die Verlinkung von Shop-Logos.
|
||||||
|
*
|
||||||
|
* @author GitHub Copilot
|
||||||
|
* @version 1.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once __DIR__ . '/lib/bootstrap.php';
|
require_once __DIR__ . '/lib/bootstrap.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Überprüfung der Zugriffsberechtigungen
|
||||||
|
*
|
||||||
|
* Es wird geprüft, ob eine aktive Benutzersession existiert und ob der Benutzer
|
||||||
|
* die Rolle 'ADMIN' besitzt. Wenn nicht, wird der Zugriff verweigert (Status 403)
|
||||||
|
* und eine entsprechende Fehlermeldung ausgegeben.
|
||||||
|
*/
|
||||||
// Only ADMIN
|
// Only ADMIN
|
||||||
if (empty($_SESSION['user_id']) || empty($_SESSION['user_roles']) || !in_array('ADMIN', $_SESSION['user_roles'], true)) {
|
if (empty($_SESSION['user_id']) || empty($_SESSION['user_roles']) || !in_array('ADMIN', $_SESSION['user_roles'], true)) {
|
||||||
http_response_code(403);
|
http_response_code(403);
|
||||||
@ -18,34 +32,69 @@ if (empty($_SESSION['user_id']) || empty($_SESSION['user_roles']) || !in_array('
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Datenbankverbindung herstellen
|
||||||
|
* @var mysqli $conn Die aktive Datenbankverbindung
|
||||||
|
*/
|
||||||
$conn = db_connect();
|
$conn = db_connect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string $message Speichert Erfolgs- oder Fehlermeldungen für den Benutzer
|
||||||
|
* @var string $messageType Definiert den Typ der Nachricht ('success' oder 'error')
|
||||||
|
*/
|
||||||
$message = '';
|
$message = '';
|
||||||
$messageType = '';
|
$messageType = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Verarbeitung von POST-Anfragen (Formular-Übermittlungen)
|
||||||
|
*
|
||||||
|
* Prüft, ob ein Formular abgesendet wurde und welche Aktion ('add_shop' oder 'delete_shop')
|
||||||
|
* ausgeführt werden soll.
|
||||||
|
*/
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
||||||
if ($_POST['action'] === 'add_shop') {
|
if ($_POST['action'] === 'add_shop') {
|
||||||
|
/**
|
||||||
|
* @brief Extrahieren der Formulardaten für einen neuen Shop
|
||||||
|
*/
|
||||||
$name = trim($_POST['name']);
|
$name = trim($_POST['name']);
|
||||||
$website = trim($_POST['website']);
|
$website = trim($_POST['website']);
|
||||||
$shippingTime = trim($_POST['shipping_time']);
|
$shippingTime = trim($_POST['shipping_time']);
|
||||||
$logoPath = null;
|
$logoPath = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Verarbeitung des Logo-Uploads
|
||||||
|
*
|
||||||
|
* Prüft zunächst, ob eine Datei hochgeladen wurde und kein Fehler aufgetreten ist.
|
||||||
|
*/
|
||||||
// Handle logo upload
|
// Handle logo upload
|
||||||
if (isset($_FILES['logo']) && $_FILES['logo']['error'] === UPLOAD_ERR_OK) {
|
if (isset($_FILES['logo']) && $_FILES['logo']['error'] === UPLOAD_ERR_OK) {
|
||||||
|
/**
|
||||||
|
* @brief Validierung des MIME-Types der hochgeladenen Datei
|
||||||
|
*/
|
||||||
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
||||||
$fileInfo = finfo_open(FILEINFO_MIME_TYPE);
|
$fileInfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||||
$mimeType = finfo_file($fileInfo, $_FILES['logo']['tmp_name']);
|
$mimeType = finfo_file($fileInfo, $_FILES['logo']['tmp_name']);
|
||||||
finfo_close($fileInfo);
|
finfo_close($fileInfo);
|
||||||
|
|
||||||
if (in_array($mimeType, $allowedTypes)) {
|
if (in_array($mimeType, $allowedTypes)) {
|
||||||
|
/**
|
||||||
|
* @brief Verzeichnisstruktur für Logos sicherstellen
|
||||||
|
*/
|
||||||
$uploadDir = __DIR__ . '/assets/images/shopLogo/';
|
$uploadDir = __DIR__ . '/assets/images/shopLogo/';
|
||||||
if (!is_dir($uploadDir)) {
|
if (!is_dir($uploadDir)) {
|
||||||
mkdir($uploadDir, 0777, true);
|
mkdir($uploadDir, 0777, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generierung eines eindeutigen Dateinamens
|
||||||
|
*/
|
||||||
$extension = pathinfo($_FILES['logo']['name'], PATHINFO_EXTENSION);
|
$extension = pathinfo($_FILES['logo']['name'], PATHINFO_EXTENSION);
|
||||||
$fileName = preg_replace('/[^a-zA-Z0-9_-]/', '_', $name) . '_' . time() . '.' . $extension;
|
$fileName = preg_replace('/[^a-zA-Z0-9_-]/', '_', $name) . '_' . time() . '.' . $extension;
|
||||||
$targetFile = $uploadDir . $fileName;
|
$targetFile = $uploadDir . $fileName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Speichern der hochgeladenen Datei
|
||||||
|
*/
|
||||||
if (move_uploaded_file($_FILES['logo']['tmp_name'], $targetFile)) {
|
if (move_uploaded_file($_FILES['logo']['tmp_name'], $targetFile)) {
|
||||||
$logoPath = 'assets/images/shopLogo/' . $fileName;
|
$logoPath = 'assets/images/shopLogo/' . $fileName;
|
||||||
} else {
|
} else {
|
||||||
@ -57,9 +106,18 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
$messageType = 'error';
|
$messageType = 'error';
|
||||||
}
|
}
|
||||||
} elseif (isset($_POST['logo_url']) && trim($_POST['logo_url']) !== '') {
|
} elseif (isset($_POST['logo_url']) && trim($_POST['logo_url']) !== '') {
|
||||||
|
/**
|
||||||
|
* @brief Fallback auf eine angegebene Bild-URL, falls keine Datei hochgeladen wurde
|
||||||
|
*/
|
||||||
$logoPath = trim($_POST['logo_url']);
|
$logoPath = trim($_POST['logo_url']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Speichern des neuen Shops in der Datenbank
|
||||||
|
*
|
||||||
|
* Wenn keine Fehler aufgetreten sind und ein Name angegeben wurde,
|
||||||
|
* wird der Shop über ein Prepared Statement in die Datenbank eingefügt.
|
||||||
|
*/
|
||||||
if (empty($message) && $name !== '') {
|
if (empty($message) && $name !== '') {
|
||||||
$stmt = $conn->prepare("INSERT INTO shops (name, website, logoPath, shippingTime) VALUES (?, ?, ?, ?)");
|
$stmt = $conn->prepare("INSERT INTO shops (name, website, logoPath, shippingTime) VALUES (?, ?, ?, ?)");
|
||||||
$stmt->bind_param("ssss", $name, $website, $logoPath, $shippingTime);
|
$stmt->bind_param("ssss", $name, $website, $logoPath, $shippingTime);
|
||||||
@ -76,8 +134,18 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
$messageType = 'error';
|
$messageType = 'error';
|
||||||
}
|
}
|
||||||
} elseif ($_POST['action'] === 'delete_shop') {
|
} elseif ($_POST['action'] === 'delete_shop') {
|
||||||
|
/**
|
||||||
|
* @brief Löschen eines bestehenden Shops
|
||||||
|
*/
|
||||||
$shopID = (int)$_POST['shop_id'];
|
$shopID = (int)$_POST['shop_id'];
|
||||||
if ($shopID > 0) {
|
if ($shopID > 0) {
|
||||||
|
/**
|
||||||
|
* @brief Überprüfung auf verknüpfte Angebote
|
||||||
|
*
|
||||||
|
* Bevor ein Shop gelöscht wird, muss sichergestellt werden, dass
|
||||||
|
* keine Angebote (Offers) mehr mit diesem verknüpft sind, um die
|
||||||
|
* referenzielle Integrität zu wahren.
|
||||||
|
*/
|
||||||
// First check if the shop has associated offers
|
// First check if the shop has associated offers
|
||||||
$checkStmt = $conn->prepare("SELECT COUNT(*) AS offerCount FROM offers WHERE shopID = ?");
|
$checkStmt = $conn->prepare("SELECT COUNT(*) AS offerCount FROM offers WHERE shopID = ?");
|
||||||
$checkStmt->bind_param("i", $shopID);
|
$checkStmt->bind_param("i", $shopID);
|
||||||
@ -88,9 +156,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
$checkStmt->close();
|
$checkStmt->close();
|
||||||
|
|
||||||
if ($offerCount > 0) {
|
if ($offerCount > 0) {
|
||||||
|
/**
|
||||||
|
* @brief Löschen verhindern, wenn Angebote existieren
|
||||||
|
*/
|
||||||
$message = "Der Shop kann nicht gelöscht werden, da er noch $offerCount verknüpfte Angebote hat.";
|
$message = "Der Shop kann nicht gelöscht werden, da er noch $offerCount verknüpfte Angebote hat.";
|
||||||
$messageType = 'error';
|
$messageType = 'error';
|
||||||
} else {
|
} else {
|
||||||
|
/**
|
||||||
|
* @brief Führt das Löschen des Shops aus der Datenbank durch
|
||||||
|
*/
|
||||||
$stmt = $conn->prepare("DELETE FROM shops WHERE shopID = ?");
|
$stmt = $conn->prepare("DELETE FROM shops WHERE shopID = ?");
|
||||||
$stmt->bind_param("i", $shopID);
|
$stmt->bind_param("i", $shopID);
|
||||||
if ($stmt->execute()) {
|
if ($stmt->execute()) {
|
||||||
@ -106,6 +180,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Abrufen aller bestehenden Shops zur Verwaltung
|
||||||
|
*
|
||||||
|
* Es wird eine Liste aller Shops inklusive der Anzahl ihrer zugeordneten Angebote
|
||||||
|
* (über einen LEFT JOIN mit der Tabelle offers) abgerufen, um diese in der Tabelle
|
||||||
|
* im Frontend anzuzeigen.
|
||||||
|
*/
|
||||||
// Get existing shops to manage
|
// Get existing shops to manage
|
||||||
$shopsResult = $conn->query("
|
$shopsResult = $conn->query("
|
||||||
SELECT s.shopID, s.name, s.website, s.logoPath, s.shippingTime, COUNT(o.offerID) AS offerCount
|
SELECT s.shopID, s.name, s.website, s.logoPath, s.shippingTime, COUNT(o.offerID) AS offerCount
|
||||||
@ -114,6 +195,9 @@ $shopsResult = $conn->query("
|
|||||||
GROUP BY s.shopID, s.name, s.website, s.logoPath, s.shippingTime
|
GROUP BY s.shopID, s.name, s.website, s.logoPath, s.shippingTime
|
||||||
ORDER BY s.name ASC
|
ORDER BY s.name ASC
|
||||||
");
|
");
|
||||||
|
/**
|
||||||
|
* @var array $existingShops Speichert die aus der Datenbank abgerufenen Shops
|
||||||
|
*/
|
||||||
$existingShops = [];
|
$existingShops = [];
|
||||||
if ($shopsResult) {
|
if ($shopsResult) {
|
||||||
while ($row = $shopsResult->fetch_assoc()) {
|
while ($row = $shopsResult->fetch_assoc()) {
|
||||||
@ -121,21 +205,31 @@ if ($shopsResult) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Einbinden des globalen Headers
|
||||||
|
*/
|
||||||
include 'header.php';
|
include 'header.php';
|
||||||
?>
|
?>
|
||||||
|
<!--
|
||||||
|
@brief Hauptbereich für die Shop-Verwaltung
|
||||||
|
Hier wird die GUI zum Anlegen und Löschen von Shops aufgebaut.
|
||||||
|
-->
|
||||||
<main class="auth">
|
<main class="auth">
|
||||||
<section class="auth__grid" style="grid-template-columns: 1fr;">
|
<section class="auth__grid" style="grid-template-columns: 1fr;">
|
||||||
<div class="auth__card">
|
<div class="auth__card">
|
||||||
<header class="auth__header">
|
<header class="auth__header">
|
||||||
|
<!-- @brief Überschrift für das Hinzufügen-Formular -->
|
||||||
<h2 class="auth__title">Shop verwalten</h2>
|
<h2 class="auth__title">Shop verwalten</h2>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<?php if ($message): ?>
|
<?php if ($message): ?>
|
||||||
|
<!-- @brief Ausgabe von Systemnachrichten (Erfolg / Fehler) -->
|
||||||
<p class="<?php echo $messageType === 'success' ? 'auth__alert__sucess' : 'auth__alert__error'; ?>" style="margin-bottom: 1rem;">
|
<p class="<?php echo $messageType === 'success' ? 'auth__alert__sucess' : 'auth__alert__error'; ?>" style="margin-bottom: 1rem;">
|
||||||
<?php echo htmlspecialchars($message); ?>
|
<?php echo htmlspecialchars($message); ?>
|
||||||
</p>
|
</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<!-- @brief Formular zum Hinzufügen eines neuen Shops -->
|
||||||
<form method="POST" action="shopAdder.php" class="auth__form" enctype="multipart/form-data">
|
<form method="POST" action="shopAdder.php" class="auth__form" enctype="multipart/form-data">
|
||||||
<input type="hidden" name="action" value="add_shop">
|
<input type="hidden" name="action" value="add_shop">
|
||||||
|
|
||||||
@ -155,6 +249,7 @@ include 'header.php';
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="margin-top: 1rem;">
|
<div style="margin-top: 1rem;">
|
||||||
|
<!-- @brief Upload-Bereich für das Shop-Logo oder URL-Eingabe -->
|
||||||
<label style="display: block; margin-bottom: 0.5rem; font-weight: 500; color: var(--text-muted);">Shop Logo</label>
|
<label style="display: block; margin-bottom: 0.5rem; font-weight: 500; color: var(--text-muted);">Shop Logo</label>
|
||||||
<div style="display: flex; flex-direction: column; gap: 0.8rem; background: var(--bg-alt); padding: 1rem; border-radius: 6px; border: 1px solid var(--border-light);">
|
<div style="display: flex; flex-direction: column; gap: 0.8rem; background: var(--bg-alt); padding: 1rem; border-radius: 6px; border: 1px solid var(--border-light);">
|
||||||
<div>
|
<div>
|
||||||
@ -170,6 +265,7 @@ include 'header.php';
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="auth__actions" style="margin-top: 1.5rem;">
|
<div class="auth__actions" style="margin-top: 1.5rem;">
|
||||||
|
<!-- @brief Absende-Button -->
|
||||||
<button type="submit" class="auth__submit">Shop hinzufügen</button>
|
<button type="submit" class="auth__submit">Shop hinzufügen</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@ -177,10 +273,12 @@ include 'header.php';
|
|||||||
|
|
||||||
<div class="auth__card" style="margin-top: 2rem;">
|
<div class="auth__card" style="margin-top: 2rem;">
|
||||||
<header class="auth__header">
|
<header class="auth__header">
|
||||||
|
<!-- @brief Überschrift für die Liste der bestehenden Shops -->
|
||||||
<h2 class="auth__title">Bestehende Shops verwalten</h2>
|
<h2 class="auth__title">Bestehende Shops verwalten</h2>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<?php if (count($existingShops) > 0): ?>
|
<?php if (count($existingShops) > 0): ?>
|
||||||
|
<!-- @brief Tabelle mit den vorhandenen Shops -->
|
||||||
<div style="overflow-x: auto; margin-top: 1rem;">
|
<div style="overflow-x: auto; margin-top: 1rem;">
|
||||||
<table style="width: 100%; border-collapse: collapse; min-width: 600px;">
|
<table style="width: 100%; border-collapse: collapse; min-width: 600px;">
|
||||||
<thead>
|
<thead>
|
||||||
@ -194,6 +292,7 @@ include 'header.php';
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach ($existingShops as $shop): ?>
|
<?php foreach ($existingShops as $shop): ?>
|
||||||
|
<!-- @brief Tabellenzeile für jeden einzelnen Shop -->
|
||||||
<tr style="border-bottom: 1px solid var(--border-light);">
|
<tr style="border-bottom: 1px solid var(--border-light);">
|
||||||
<td style="padding: 1rem 0.5rem; vertical-align: middle;">
|
<td style="padding: 1rem 0.5rem; vertical-align: middle;">
|
||||||
<?php if ($shop['logoPath']): ?>
|
<?php if ($shop['logoPath']): ?>
|
||||||
@ -215,6 +314,7 @@ include 'header.php';
|
|||||||
</td>
|
</td>
|
||||||
<td style="padding: 1rem 0.5rem; text-align: right; vertical-align: middle;">
|
<td style="padding: 1rem 0.5rem; text-align: right; vertical-align: middle;">
|
||||||
<?php if ($shop['offerCount'] > 0): ?>
|
<?php if ($shop['offerCount'] > 0): ?>
|
||||||
|
<!-- @brief Deaktivierter Löschen-Button, falls Angebote existieren -->
|
||||||
<button disabled style="background: none; border: none; color: #ccc; cursor: not-allowed; display: inline-flex; align-items: center; justify-content: flex-end; padding: 0.5rem;" title="Shop kann nicht gelöscht werden, da er noch Angebote hat">
|
<button disabled style="background: none; border: none; color: #ccc; cursor: not-allowed; display: inline-flex; align-items: center; justify-content: flex-end; padding: 0.5rem;" title="Shop kann nicht gelöscht werden, da er noch Angebote hat">
|
||||||
<svg width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24">
|
<svg width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24">
|
||||||
<polyline points="3 6 5 6 21 6"></polyline>
|
<polyline points="3 6 5 6 21 6"></polyline>
|
||||||
@ -222,6 +322,7 @@ include 'header.php';
|
|||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
|
<!-- @brief Aktives Formular mit Lösch-Button, wenn keine Angebote verknüpft sind -->
|
||||||
<form method="POST" action="shopAdder.php" onsubmit="return confirm('Möchtest du diesen Shop wirklich löschen?');" style="display: inline-block; margin: 0;">
|
<form method="POST" action="shopAdder.php" onsubmit="return confirm('Möchtest du diesen Shop wirklich löschen?');" style="display: inline-block; margin: 0;">
|
||||||
<input type="hidden" name="action" value="delete_shop">
|
<input type="hidden" name="action" value="delete_shop">
|
||||||
<input type="hidden" name="shop_id" value="<?php echo $shop['shopID']; ?>">
|
<input type="hidden" name="shop_id" value="<?php echo $shop['shopID']; ?>">
|
||||||
@ -240,9 +341,15 @@ include 'header.php';
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
|
<!-- @brief Hinweis, wenn noch keine Shops in der Datenbank vorhanden sind -->
|
||||||
<p style="margin-top: 1rem; color: var(--text-muted); text-align: center; padding: 2rem 0;">Keine Shops vorhanden.</p>
|
<p style="margin-top: 1rem; color: var(--text-muted); text-align: center; padding: 2rem 0;">Keine Shops vorhanden.</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
<?php include 'footer.php'; ?>
|
<?php
|
||||||
|
/**
|
||||||
|
* @brief Einbinden des globalen Footers
|
||||||
|
*/
|
||||||
|
include 'footer.php';
|
||||||
|
?>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user