diff --git a/account.php b/account.php index eabe441..5eab9cf 100644 --- a/account.php +++ b/account.php @@ -229,7 +229,13 @@ include 'header.php'; if (!empty($_SESSION['user_roles']) && in_array('ADMIN', $_SESSION['user_roles'], true)): ?> - Produkt hinzufügen + Produkt verwalten + + + Angebot verwalten + + + Shop verwalten Benutzerverwaltung diff --git a/info/DB_Design.mwb b/info/DB_Design.mwb index f598298..071d5e8 100644 Binary files a/info/DB_Design.mwb and b/info/DB_Design.mwb differ diff --git a/info/MySQL_Dump_Workbench.sql b/info/MySQL_Dump_Workbench.sql new file mode 100644 index 0000000..cfd9e5e --- /dev/null +++ b/info/MySQL_Dump_Workbench.sql @@ -0,0 +1,350 @@ +-- MySQL Script generated by MySQL Workbench +-- Mon Apr 6 01:50:45 2026 +-- Model: New Model Version: 1.0 +-- MySQL Workbench Forward Engineering + +SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0; +SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0; +SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; + +-- ----------------------------------------------------- +-- Schema mydb +-- ----------------------------------------------------- +-- ----------------------------------------------------- +-- Schema FSST +-- ----------------------------------------------------- + +-- ----------------------------------------------------- +-- Schema FSST +-- ----------------------------------------------------- +CREATE SCHEMA IF NOT EXISTS `FSST` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci ; +USE `FSST` ; + +-- ----------------------------------------------------- +-- Table `FSST`.`attributes` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `FSST`.`attributes` ( + `attributeID` INT NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + `unit` VARCHAR(50) NULL DEFAULT NULL, + `dataType` VARCHAR(20) NULL DEFAULT NULL, + PRIMARY KEY (`attributeID`)) +ENGINE = InnoDB +AUTO_INCREMENT = 70 +DEFAULT CHARACTER SET = utf8mb4 +COLLATE = utf8mb4_0900_ai_ci; + + +-- ----------------------------------------------------- +-- Table `FSST`.`brands` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `FSST`.`brands` ( + `brandID` INT NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + PRIMARY KEY (`brandID`)) +ENGINE = InnoDB +AUTO_INCREMENT = 8 +DEFAULT CHARACTER SET = utf8mb4 +COLLATE = utf8mb4_0900_ai_ci; + + +-- ----------------------------------------------------- +-- Table `FSST`.`categories` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `FSST`.`categories` ( + `categoryID` INT NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + `parentCategoryID` INT NULL DEFAULT NULL, + PRIMARY KEY (`categoryID`), + INDEX `categories_ibfk_1` (`parentCategoryID` ASC) VISIBLE, + CONSTRAINT `categories_ibfk_1` + FOREIGN KEY (`parentCategoryID`) + REFERENCES `FSST`.`categories` (`categoryID`) + ON DELETE CASCADE) +ENGINE = InnoDB +AUTO_INCREMENT = 26 +DEFAULT CHARACTER SET = utf8mb4 +COLLATE = utf8mb4_0900_ai_ci; + + +-- ----------------------------------------------------- +-- Table `FSST`.`categoryAttributes` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `FSST`.`categoryAttributes` ( + `categoryID` INT NOT NULL, + `attributeID` INT NOT NULL, + PRIMARY KEY (`categoryID`, `attributeID`), + INDEX `attributeID` (`attributeID` ASC) VISIBLE, + CONSTRAINT `categoryAttributes_ibfk_1` + FOREIGN KEY (`categoryID`) + REFERENCES `FSST`.`categories` (`categoryID`), + CONSTRAINT `categoryAttributes_ibfk_2` + FOREIGN KEY (`attributeID`) + REFERENCES `FSST`.`attributes` (`attributeID`)) +ENGINE = InnoDB +DEFAULT CHARACTER SET = utf8mb4 +COLLATE = utf8mb4_0900_ai_ci; + + +-- ----------------------------------------------------- +-- Table `FSST`.`users` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `FSST`.`users` ( + `userID` INT NOT NULL AUTO_INCREMENT, + `email` VARCHAR(255) NOT NULL, + `passwordHash` VARCHAR(255) NOT NULL, + `displayName` VARCHAR(255) NULL DEFAULT NULL, + `isActive` TINYINT(1) NOT NULL DEFAULT '1', + `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `profilePicture` VARCHAR(255) NULL DEFAULT NULL, + PRIMARY KEY (`userID`), + UNIQUE INDEX `email` (`email` ASC) VISIBLE) +ENGINE = InnoDB +AUTO_INCREMENT = 45 +DEFAULT CHARACTER SET = utf8mb4 +COLLATE = utf8mb4_0900_ai_ci; + + +-- ----------------------------------------------------- +-- Table `FSST`.`notifications` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `FSST`.`notifications` ( + `notificationID` INT NOT NULL AUTO_INCREMENT, + `userID` INT NOT NULL, + `title` VARCHAR(255) NOT NULL, + `message` TEXT NOT NULL, + `isRead` TINYINT(1) NOT NULL DEFAULT '0', + `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`notificationID`), + INDEX `fk_notifications_user` (`userID` ASC) VISIBLE, + CONSTRAINT `fk_notifications_user` + FOREIGN KEY (`userID`) + REFERENCES `FSST`.`users` (`userID`) + ON DELETE CASCADE) +ENGINE = InnoDB +AUTO_INCREMENT = 4 +DEFAULT CHARACTER SET = utf8mb4 +COLLATE = utf8mb4_0900_ai_ci; + + +-- ----------------------------------------------------- +-- Table `FSST`.`products` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `FSST`.`products` ( + `productID` INT NOT NULL AUTO_INCREMENT, + `categoryID` INT NOT NULL, + `brandID` INT NOT NULL, + `model` VARCHAR(255) NOT NULL, + `description` TEXT NULL DEFAULT NULL, + `imagePath` VARCHAR(255) NULL DEFAULT NULL, + PRIMARY KEY (`productID`), + INDEX `categoryID` (`categoryID` ASC) VISIBLE, + INDEX `brandID` (`brandID` ASC) VISIBLE, + CONSTRAINT `products_ibfk_1` + FOREIGN KEY (`categoryID`) + REFERENCES `FSST`.`categories` (`categoryID`), + CONSTRAINT `products_ibfk_2` + FOREIGN KEY (`brandID`) + REFERENCES `FSST`.`brands` (`brandID`)) +ENGINE = InnoDB +AUTO_INCREMENT = 1347 +DEFAULT CHARACTER SET = utf8mb4 +COLLATE = utf8mb4_0900_ai_ci; + + +-- ----------------------------------------------------- +-- Table `FSST`.`shops` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `FSST`.`shops` ( + `shopID` INT NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + `website` VARCHAR(255) NULL DEFAULT NULL, + `logoPath` VARCHAR(255) NULL DEFAULT NULL, + `shippingTime` VARCHAR(255) NULL DEFAULT NULL, + PRIMARY KEY (`shopID`)) +ENGINE = InnoDB +AUTO_INCREMENT = 7 +DEFAULT CHARACTER SET = utf8mb4 +COLLATE = utf8mb4_0900_ai_ci; + + +-- ----------------------------------------------------- +-- Table `FSST`.`offers` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `FSST`.`offers` ( + `offerID` INT NOT NULL AUTO_INCREMENT, + `productID` INT NOT NULL, + `shopID` INT NOT NULL, + `price` DECIMAL(10,2) NOT NULL, + `shippingCost` DECIMAL(10,2) NULL DEFAULT NULL, + `inStock` TINYINT(1) NULL DEFAULT NULL, + `offerURL` VARCHAR(255) NULL DEFAULT NULL, + PRIMARY KEY (`offerID`), + INDEX `productID` (`productID` ASC) VISIBLE, + INDEX `shopID` (`shopID` ASC) VISIBLE, + CONSTRAINT `offers_ibfk_1` + FOREIGN KEY (`productID`) + REFERENCES `FSST`.`products` (`productID`), + CONSTRAINT `offers_ibfk_2` + FOREIGN KEY (`shopID`) + REFERENCES `FSST`.`shops` (`shopID`)) +ENGINE = InnoDB +AUTO_INCREMENT = 10 +DEFAULT CHARACTER SET = utf8mb4 +COLLATE = utf8mb4_0900_ai_ci; + + +-- ----------------------------------------------------- +-- Table `FSST`.`priceAlerts` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `FSST`.`priceAlerts` ( + `alertID` INT NOT NULL AUTO_INCREMENT, + `userID` INT NOT NULL, + `productID` INT NOT NULL, + `targetPrice` DECIMAL(10,2) NOT NULL, + `isActive` TINYINT(1) NOT NULL DEFAULT '1', + `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`alertID`), + INDEX `fk_pricealerts_user` (`userID` ASC) VISIBLE, + INDEX `fk_pricealerts_product` (`productID` ASC) VISIBLE, + CONSTRAINT `fk_pricealerts_product` + FOREIGN KEY (`productID`) + REFERENCES `FSST`.`products` (`productID`) + ON DELETE CASCADE, + CONSTRAINT `fk_pricealerts_user` + FOREIGN KEY (`userID`) + REFERENCES `FSST`.`users` (`userID`) + ON DELETE CASCADE) +ENGINE = InnoDB +AUTO_INCREMENT = 4 +DEFAULT CHARACTER SET = utf8mb4 +COLLATE = utf8mb4_0900_ai_ci; + + +-- ----------------------------------------------------- +-- Table `FSST`.`productAttributes` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `FSST`.`productAttributes` ( + `productID` INT NOT NULL, + `attributeID` INT NOT NULL, + `valueString` VARCHAR(255) NULL DEFAULT NULL, + `valueNumber` DECIMAL(10,2) NULL DEFAULT NULL, + `valueBool` TINYINT(1) NULL DEFAULT NULL, + PRIMARY KEY (`productID`, `attributeID`), + INDEX `attributeID` (`attributeID` ASC) VISIBLE, + CONSTRAINT `productAttributes_ibfk_1` + FOREIGN KEY (`productID`) + REFERENCES `FSST`.`products` (`productID`), + CONSTRAINT `productAttributes_ibfk_2` + FOREIGN KEY (`attributeID`) + REFERENCES `FSST`.`attributes` (`attributeID`)) +ENGINE = InnoDB +DEFAULT CHARACTER SET = utf8mb4 +COLLATE = utf8mb4_0900_ai_ci; + + +-- ----------------------------------------------------- +-- Table `FSST`.`reviews` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `FSST`.`reviews` ( + `reviewID` INT NOT NULL AUTO_INCREMENT, + `userID` INT NOT NULL, + `productID` INT NOT NULL, + `rating` INT NOT NULL, + `comment` TEXT NULL DEFAULT NULL, + `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`reviewID`), + INDEX `fk_reviews_user` (`userID` ASC) VISIBLE, + INDEX `fk_reviews_product` (`productID` ASC) VISIBLE, + CONSTRAINT `fk_reviews_product` + FOREIGN KEY (`productID`) + REFERENCES `FSST`.`products` (`productID`) + ON DELETE CASCADE, + CONSTRAINT `fk_reviews_user` + FOREIGN KEY (`userID`) + REFERENCES `FSST`.`users` (`userID`) + ON DELETE CASCADE) +ENGINE = InnoDB +AUTO_INCREMENT = 42 +DEFAULT CHARACTER SET = utf8mb4 +COLLATE = utf8mb4_0900_ai_ci; + + +-- ----------------------------------------------------- +-- Table `FSST`.`roles` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `FSST`.`roles` ( + `roleID` INT NOT NULL AUTO_INCREMENT, + `name` VARCHAR(50) NOT NULL, + PRIMARY KEY (`roleID`), + UNIQUE INDEX `name` (`name` ASC) VISIBLE) +ENGINE = InnoDB +AUTO_INCREMENT = 4 +DEFAULT CHARACTER SET = utf8mb4 +COLLATE = utf8mb4_0900_ai_ci; + + +-- ----------------------------------------------------- +-- Table `FSST`.`userFavorites` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `FSST`.`userFavorites` ( + `userID` INT NOT NULL, + `productID` INT NOT NULL, + `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`userID`, `productID`), + INDEX `fk_favorites_product` (`productID` ASC) VISIBLE, + CONSTRAINT `fk_favorites_product` + FOREIGN KEY (`productID`) + REFERENCES `FSST`.`products` (`productID`) + ON DELETE CASCADE, + CONSTRAINT `fk_favorites_user` + FOREIGN KEY (`userID`) + REFERENCES `FSST`.`users` (`userID`) + ON DELETE CASCADE) +ENGINE = InnoDB +DEFAULT CHARACTER SET = utf8mb4 +COLLATE = utf8mb4_0900_ai_ci; + + +-- ----------------------------------------------------- +-- Table `FSST`.`userRoles` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `FSST`.`userRoles` ( + `userID` INT NOT NULL, + `roleID` INT NOT NULL, + PRIMARY KEY (`userID`, `roleID`), + INDEX `fk_userroles_role` (`roleID` ASC) VISIBLE, + CONSTRAINT `fk_userroles_role` + FOREIGN KEY (`roleID`) + REFERENCES `FSST`.`roles` (`roleID`) + ON DELETE CASCADE, + CONSTRAINT `fk_userroles_user` + FOREIGN KEY (`userID`) + REFERENCES `FSST`.`users` (`userID`) + ON DELETE CASCADE) +ENGINE = InnoDB +DEFAULT CHARACTER SET = utf8mb4 +COLLATE = utf8mb4_0900_ai_ci; + + +-- ----------------------------------------------------- +-- Table `FSST`.`userSessions` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `FSST`.`userSessions` ( + `sessionID` VARCHAR(128) NOT NULL, + `userID` INT NOT NULL, + `expiresAt` TIMESTAMP NOT NULL, + PRIMARY KEY (`sessionID`), + INDEX `fk_sessions_user` (`userID` ASC) VISIBLE, + CONSTRAINT `fk_sessions_user` + FOREIGN KEY (`userID`) + REFERENCES `FSST`.`users` (`userID`) + ON DELETE CASCADE) +ENGINE = InnoDB +DEFAULT CHARACTER SET = utf8mb4 +COLLATE = utf8mb4_0900_ai_ci; + + +SET SQL_MODE=@OLD_SQL_MODE; +SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; +SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS; diff --git a/offerAdder.php b/offerAdder.php new file mode 100644 index 0000000..b30cf21 --- /dev/null +++ b/offerAdder.php @@ -0,0 +1,332 @@ +
'; + echo '

Zugriff verweigert

'; + echo '

Du hast keine Berechtigung, Angebote hinzuzufügen.

'; + echo '
'; + include 'footer.php'; + exit; +} + +/** + * @brief Datenbankverbindung herstellen und Initialisierung von Statusvariablen. + * + * @var mysqli $conn Die aktive Datenbankverbindung. + * @var string $message Eine Nachricht an den Benutzer (Erfolg oder Fehler). + * @var string $messageType Der Typ der Nachricht ('success' oder 'error'). + */ +$conn = db_connect(); +$message = ''; +$messageType = ''; + +/** + * @brief Verarbeitung von POST-Anfragen zur Angebotsverwaltung. + * + * Überprüft, ob das Formular abgesendet wurde und eine spezifische 'action' gesetzt ist. + * Unterstützte Aktionen sind 'add_offer' (Angebot hinzufügen) und 'delete_offer' (Angebot löschen). + */ +if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { + /** + * @brief Aktion: Neues Angebot hinzufügen. + * + * Liest die übermittelten Formulardaten aus, validiert diese (Produkt-ID, Shop-ID und + * gültiger Preis) und fügt sie durch ein Prepared Statement in die Tabelle `offers` ein. + */ + if ($_POST['action'] === 'add_offer') { + $productID = (int)$_POST['product_id']; + $shopID = (int)$_POST['shop_id']; + $price = (float)$_POST['price']; + $shippingCost = isset($_POST['shipping_cost']) && $_POST['shipping_cost'] !== '' ? (float)$_POST['shipping_cost'] : 0.00; + $inStock = isset($_POST['in_stock']) ? 1 : 0; + $offerURL = trim($_POST['offer_url']); + + if ($productID > 0 && $shopID > 0 && $price >= 0) { + /** + * @brief Einfügen in die Datenbank. + * Bereitet das SQL-Statement vor und bindet die Parameter sicher, um SQL-Injection zu verhindern. + */ + $stmt = $conn->prepare("INSERT INTO offers (productID, shopID, price, shippingCost, inStock, offerURL) VALUES (?, ?, ?, ?, ?, ?)"); + $stmt->bind_param("iiddis", $productID, $shopID, $price, $shippingCost, $inStock, $offerURL); + if ($stmt->execute()) { + $message = 'Angebot erfolgreich hinzugefügt!'; + $messageType = 'success'; + } else { + $message = 'Fehler beim Hinzufügen des Angebots.'; + $messageType = 'error'; + } + $stmt->close(); + } else { + /** + * @brief Fehlerbehandlung bei ungültigen Eingaben. + */ + $message = 'Bitte alle Pflichtfelder korrekt ausfüllen.'; + $messageType = 'error'; + } + } elseif ($_POST['action'] === 'delete_offer') { + /** + * @brief Aktion: Existierendes Angebot löschen. + * + * Überprüft die übermittelte Angebot-ID und löscht den entsprechenden Eintrag + * sicher per Prepared Statement aus der Datenbank. + */ + $offerID = (int)$_POST['offer_id']; + if ($offerID > 0) { + $stmt = $conn->prepare("DELETE FROM offers WHERE offerID = ?"); + $stmt->bind_param("i", $offerID); + if ($stmt->execute()) { + $message = 'Angebot erfolgreich gelöscht!'; + $messageType = 'success'; + } else { + $message = 'Fehler beim Löschen des Angebots.'; + $messageType = 'error'; + } + $stmt->close(); + } + } +} + +/** + * @brief Abrufen aller Produkte für das Dropdown-Feld. + * + * Führt eine Query aus, um alle verfügbaren Produkte (IDs und Modelle) + * alphabetisch geordnet aus der Datenbank zu laden. + * + * @var array $products Enthält die geladenen Produkte. + */ +// Get all products for dropdown +$productsResult = $conn->query("SELECT productID, model FROM products ORDER BY model ASC"); +$products = []; +if ($productsResult) { + while ($row = $productsResult->fetch_assoc()) { + $products[] = $row; + } +} + +/** + * @brief Abrufen aller Shops für das Dropdown-Feld. + * + * Führt eine Query aus, um alle verfügbaren Shops (IDs und Namen) + * alphabetisch geordnet aus der Datenbank zu laden. + * + * @var array $shops Enthält die geladenen Shops. + */ +// Get all shops for dropdown +$shopsResult = $conn->query("SELECT shopID, name FROM shops ORDER BY name ASC"); +$shops = []; +if ($shopsResult) { + while ($row = $shopsResult->fetch_assoc()) { + $shops[] = $row; + } +} + +/** + * @brief Filterlogik für die Anzeige existierender Angebote. + * + * Überprüft, ob über GET ein Filter für eine bestimmte Produkt-ID gesetzt wurde. + * Ist dies der Fall, werden nur Angebote für dieses Produkt angezeigt. + * + * @var int $filterProductID Die ID des zu filternden Produkts (0, wenn kein Filter gesetzt ist). + * @var string $offersQuery Die dynamisch generierte SQL-Abfrage für die Angebote. + */ +$filterProductID = isset($_GET['filter_product_id']) ? (int)$_GET['filter_product_id'] : 0; + +$offersQuery = " + SELECT o.offerID, p.model AS productName, s.name AS shopName, o.price + FROM offers o + JOIN products p ON o.productID = p.productID + JOIN shops s ON o.shopID = s.shopID +"; + +if ($filterProductID > 0) { + /** + * @brief Anwenden des Filters auf die SQL-Query, falls notwendig. + */ + $offersQuery .= " WHERE o.productID = " . $filterProductID; +} + +$offersQuery .= " ORDER BY o.offerID DESC"; + +/** + * @brief Ausführen der Angebot-Abfrage und Speichern in ein Array. + * + * @var array $existingOffers Enthält die geladenen Angebote inkl. Shop- und Produkt-Namen, + * die zur Anzeige in der Tabelle verwendet werden. + */ +// Get existing offers to manage +$offersResult = $conn->query($offersQuery); +$existingOffers = []; +if ($offersResult) { + while ($row = $offersResult->fetch_assoc()) { + $existingOffers[] = $row; + } +} + +/** + * @brief Einbinden des HTML-Headers, der Navigation und Stile. + */ +include 'header.php'; +?> +
+
Filter zurücksetzen + +
+ + 0): ?> +
+ + + + + + + + + + + + + + + + + + + +
ProduktShopPreisAktion
+
+ + + + +
+
+
+ +

Keine Angebote vorhanden.

+ +
+
+
+ diff --git a/productAdder.php b/productAdder.php index 1fa71cd..e862fa2 100644 --- a/productAdder.php +++ b/productAdder.php @@ -68,6 +68,28 @@ if (isset($_GET['categoryID']) && ctype_digit($_GET['categoryID'])) { ======================= */ $conn = db_connect(); +/* ======================= + 2b) Produkt löschen + ======================= */ +$deleteMessage = ''; +$deleteMessageType = ''; +if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'delete_product') { + $delProductID = (int)$_POST['product_id']; + $catIDFromForm = (int)$_POST['categoryID']; // to redirect back + if ($delProductID > 0) { + $delStmt = $conn->prepare("DELETE FROM products WHERE productID = ?"); + $delStmt->bind_param("i", $delProductID); + if ($delStmt->execute()) { + $deleteMessage = 'Produkt erfolgreich gelöscht!'; + $deleteMessageType = 'success'; + } else { + $deleteMessage = 'Fehler beim Löschen des Produkts (möglicherweise sind noch Angebote oder Attribute verknüpft?).'; + $deleteMessageType = 'error'; + } + $delStmt->close(); + } +} + /** * @section Kategorien-Laden * @brief Abrufen aller verfügbaren Kategorien. @@ -419,7 +441,7 @@ include 'header.php'; 0): ?>
-

Produkt hinzufügen

+

Produkt verwalten

@@ -484,6 +506,52 @@ include 'header.php';
+ +
+
+

Produkt löschen

+
+ + +
+ +
+ + + + + +
+ + +
+ +
+ +
+ +
+ diff --git a/shopAdder.php b/shopAdder.php new file mode 100644 index 0000000..71b6f15 --- /dev/null +++ b/shopAdder.php @@ -0,0 +1,355 @@ +
'; + echo '

Zugriff verweigert

'; + echo '

Du hast keine Berechtigung, Shops hinzuzufügen.

'; + echo '
'; + include 'footer.php'; + exit; +} + +/** + * @brief Datenbankverbindung herstellen + * @var mysqli $conn Die aktive Datenbankverbindung + */ +$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 = ''; +$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 ($_POST['action'] === 'add_shop') { + /** + * @brief Extrahieren der Formulardaten für einen neuen Shop + */ + $name = trim($_POST['name']); + $website = trim($_POST['website']); + $shippingTime = trim($_POST['shipping_time']); + $logoPath = null; + + /** + * @brief Verarbeitung des Logo-Uploads + * + * Prüft zunächst, ob eine Datei hochgeladen wurde und kein Fehler aufgetreten ist. + */ + // Handle logo upload + 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']; + $fileInfo = finfo_open(FILEINFO_MIME_TYPE); + $mimeType = finfo_file($fileInfo, $_FILES['logo']['tmp_name']); + finfo_close($fileInfo); + + if (in_array($mimeType, $allowedTypes)) { + /** + * @brief Verzeichnisstruktur für Logos sicherstellen + */ + $uploadDir = __DIR__ . '/assets/images/shopLogo/'; + if (!is_dir($uploadDir)) { + mkdir($uploadDir, 0777, true); + } + + /** + * @brief Generierung eines eindeutigen Dateinamens + */ + $extension = pathinfo($_FILES['logo']['name'], PATHINFO_EXTENSION); + $fileName = preg_replace('/[^a-zA-Z0-9_-]/', '_', $name) . '_' . time() . '.' . $extension; + $targetFile = $uploadDir . $fileName; + + /** + * @brief Speichern der hochgeladenen Datei + */ + if (move_uploaded_file($_FILES['logo']['tmp_name'], $targetFile)) { + $logoPath = 'assets/images/shopLogo/' . $fileName; + } else { + $message = 'Fehler beim Hochladen des Logos.'; + $messageType = 'error'; + } + } else { + $message = 'Ungültiges Dateiformat für das Logo. Erlaubt sind JPG, PNG, GIF und WEBP.'; + $messageType = 'error'; + } + } 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']); + } + + /** + * @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 !== '') { + $stmt = $conn->prepare("INSERT INTO shops (name, website, logoPath, shippingTime) VALUES (?, ?, ?, ?)"); + $stmt->bind_param("ssss", $name, $website, $logoPath, $shippingTime); + if ($stmt->execute()) { + $message = 'Shop erfolgreich hinzugefügt!'; + $messageType = 'success'; + } else { + $message = 'Fehler beim Hinzufügen des Shops.'; + $messageType = 'error'; + } + $stmt->close(); + } elseif (empty($message)) { + $message = 'Bitte mindestens den Shop-Namen angeben.'; + $messageType = 'error'; + } + } elseif ($_POST['action'] === 'delete_shop') { + /** + * @brief Löschen eines bestehenden Shops + */ + $shopID = (int)$_POST['shop_id']; + 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 + $checkStmt = $conn->prepare("SELECT COUNT(*) AS offerCount FROM offers WHERE shopID = ?"); + $checkStmt->bind_param("i", $shopID); + $checkStmt->execute(); + $result = $checkStmt->get_result(); + $row = $result->fetch_assoc(); + $offerCount = (int)$row['offerCount']; + $checkStmt->close(); + + 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."; + $messageType = 'error'; + } else { + /** + * @brief Führt das Löschen des Shops aus der Datenbank durch + */ + $stmt = $conn->prepare("DELETE FROM shops WHERE shopID = ?"); + $stmt->bind_param("i", $shopID); + if ($stmt->execute()) { + $message = 'Shop erfolgreich gelöscht!'; + $messageType = 'success'; + } else { + $message = 'Fehler beim Löschen des Shops.'; + $messageType = 'error'; + } + $stmt->close(); + } + } + } +} + +/** + * @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 +$shopsResult = $conn->query(" + SELECT s.shopID, s.name, s.website, s.logoPath, s.shippingTime, COUNT(o.offerID) AS offerCount + FROM shops s + LEFT JOIN offers o ON s.shopID = o.shopID + GROUP BY s.shopID, s.name, s.website, s.logoPath, s.shippingTime + ORDER BY s.name ASC +"); +/** + * @var array $existingShops Speichert die aus der Datenbank abgerufenen Shops + */ +$existingShops = []; +if ($shopsResult) { + while ($row = $shopsResult->fetch_assoc()) { + $existingShops[] = $row; + } +} + +/** + * @brief Einbinden des globalen Headers + */ +include 'header.php'; +?> + +
+
+
+
+ +

Shop verwalten

+
+ + + +

+ +

+ + + +
+ + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ + +
+
- ODER -
+
+ + +
+
+
+ +
+ + +
+
+
+ +
+
+ +

Bestehende Shops verwalten

+
+ + 0): ?> + +
+ + + + + + + + + + + + + + + + + + + + + + +
LogoNameWebsiteAngeboteAktion
+ + Logo + + Kein Logo + + + + Link ↗ + + + + + + + 0): ?> + + + + +
+ + + +
+ +
+
+ + +

Keine Shops vorhanden.

+ +
+
+
+