Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c2b7462307 | |||
| cdbf81878b | |||
| 68ec6dedd7 | |||
| 12782463d7 | |||
| 21a935edf3 | |||
| 3d65f79d2c | |||
| ed31210e3a | |||
| 5030caa029 | |||
| 4a87152531 | |||
| 1401c3afe7 | |||
| d5a3f4298f | |||
| b4a5c9c020 | |||
| 6d6f1f31b0 | |||
| cafffba921 | |||
| 8fa758d825 | |||
| 01fc8537cf | |||
| 4a6a3cf708 | |||
| cb44c3f5a8 | |||
| eb0a34e959 | |||
| 8d683cc1a0 | |||
| ee41dd4cfe | |||
| 3d50e6e3b3 | |||
| 4f8d11881d | |||
| 5c924d3277 | |||
| 7f703a8386 | |||
| f063ea4741 | |||
| ca643dd298 | |||
| e19225e49e | |||
| 9ffbca679e | |||
| d90a10e462 | |||
| b6f25d041b | |||
| d1b3641754 |
Generated
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="dataSourceStorageLocal" created-in="IU-261.25134.95">
|
<component name="dataSourceStorageLocal" created-in="IU-261.24374.151">
|
||||||
<data-source name="articles" uuid="315cb5c9-2b0f-435b-b602-59823b160908">
|
<data-source name="articles" uuid="315cb5c9-2b0f-435b-b602-59823b160908">
|
||||||
<database-info product="SQLite" version="3.51.1" jdbc-version="4.2" driver-name="SQLite JDBC" driver-version="3.51.1.0" dbms="SQLITE" exact-version="3.51.1" exact-driver-version="3.51">
|
<database-info product="SQLite" version="3.51.1" jdbc-version="4.2" driver-name="SQLite JDBC" driver-version="3.51.1.0" dbms="SQLITE" exact-version="3.51.1" exact-driver-version="3.51">
|
||||||
<identifier-quote-string>"</identifier-quote-string>
|
<identifier-quote-string>"</identifier-quote-string>
|
||||||
|
|||||||
@@ -16,16 +16,21 @@
|
|||||||
|
|
||||||
## Bekannte Fehler und Mängel
|
## Bekannte Fehler und Mängel
|
||||||
- Bitte auf die gesetzten TODO's achten. Wenn Inhalte fehlen, sind sie i.d.R. als TODO kommentiert.
|
- Bitte auf die gesetzten TODO's achten. Wenn Inhalte fehlen, sind sie i.d.R. als TODO kommentiert.
|
||||||
- Die Suchseite und Kategorieseite packen momentan alle passenden Beiträge untereinander. Später sollen zunächst 10
|
- Die Kategorieseite listet momentan alle passenden Beiträge untereinander. Später sollen mit einem Paginator die neusten
|
||||||
Ergebnisse auf einer Seite angezeigt werden.
|
Beiträge nacheinander aufgelistet werden (ähnlich wie bei der Suche, wenn nach Fach gefiltert wird).
|
||||||
- Wenn ein Bild aus einem Beitrag entfernt wird, dann wird noch nicht die Datei im Pfad /uploads gelöscht.
|
- Wenn ein Bild aus einem Beitrag entfernt wird, dann wird noch nicht die Datei im Pfad /uploads gelöscht.
|
||||||
|
- id in showArticle-controller.php und updateArticle-controller.php wird nicht als gültige numerische ID geprüft.
|
||||||
|
- Bilder im Beitragseditor sollen zukünftig eine Bildunterschrift bekommen und größenverstellbar sein.
|
||||||
|
- Die Elemente eines Contents im Beitrag werden momentan stumpf untereinander aufgelistet. Soll später
|
||||||
|
sich responisve auch nebeneinander orientieren usw.
|
||||||
|
|
||||||
## Besonderheiten des Projektes
|
## Besonderheiten des Projektes
|
||||||
- Es wurde ein einfacher Beitrags-Editor erstellt. Mit diesem können Beiträge erstellt oder bearbeitet werden.
|
- Es wurde AJAX verwendet, um asynchrone Erstellung von Kommentaren zu implementieren. Es ermöglicht dem Nutzer, einen
|
||||||
Es handelt es sich um eine einfache Version. Später sollen z.B. Bilder und die Positionierung der Elemente folgen.
|
Kommentar abzusenden, ohne dass die gesamte Webseite neu geladen werden muss.
|
||||||
- Es sind drei Dummy-Beiträge für den Nutzer max.mustermann hinterlegt.
|
- Mit JavaScript werden auch clientseitig die Kommentare visuell hinzugefügt und die Kommentarbäume aufgebaut.
|
||||||
- Die Such-Seite umfasst eine Such- und Sortierfunktion. Jedoch fehlt noch eine
|
- JavaScript wird verwendet, um im erweitertem Beitragseditor clientseitig einzelne Content-Boxen erstellen und löschen
|
||||||
Filterfunktion (z.B. nur Mathe anzeigen).
|
zu können.
|
||||||
|
- JavaScript wird ebenfalls verwendet, um in die Suchergebnisse clientseitig zu sortieren.
|
||||||
|
|
||||||
## Sonstiges
|
## Sonstiges
|
||||||
- Das Datenschema befindet sich unter /planung/Datenschema.pdf
|
- Das Datenschema befindet sich unter /planung/Datenschema.pdf
|
||||||
+4
-9
@@ -7,8 +7,8 @@ $isEditMode = (isset($_GET["edit"]) && $_GET["edit"] === "1") || !empty($error);
|
|||||||
|
|
||||||
<main class="form-page">
|
<main class="form-page">
|
||||||
<div class="flexbox">
|
<div class="flexbox">
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<?php include_once "includes/alertMessages.php" ?>
|
||||||
|
|
||||||
<?php if (!empty($error)): ?>
|
<?php if (!empty($error)): ?>
|
||||||
<p class="alert-message is-error">
|
<p class="alert-message is-error">
|
||||||
@@ -93,8 +93,6 @@ $isEditMode = (isset($_GET["edit"]) && $_GET["edit"] === "1") || !empty($error);
|
|||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
||||||
<?php include_once "includes/alertMessages.php" ?>
|
|
||||||
|
|
||||||
<h2 class="section-title">Meine Beiträge</h2>
|
<h2 class="section-title">Meine Beiträge</h2>
|
||||||
|
|
||||||
<div class="articles-list">
|
<div class="articles-list">
|
||||||
@@ -182,10 +180,9 @@ $isEditMode = (isset($_GET["edit"]) && $_GET["edit"] === "1") || !empty($error);
|
|||||||
|
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<br>
|
<div class="container">
|
||||||
|
|
||||||
<!-- Eigener Bereich für die Kommentare des Nutzers -->
|
|
||||||
<div class="comments-section">
|
<div class="comments-section">
|
||||||
|
|
||||||
<h2 class="section-title">Meine Kommentare</h2>
|
<h2 class="section-title">Meine Kommentare</h2>
|
||||||
@@ -228,10 +225,8 @@ $isEditMode = (isset($_GET["edit"]) && $_GET["edit"] === "1") || !empty($error);
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<?php unset($_SESSION["message"]); ?>
|
<?php unset($_SESSION["message"]); ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
@@ -65,8 +65,8 @@ $resultCount = count($results);
|
|||||||
</label>
|
</label>
|
||||||
<!-- Noch disabled, da likes noch nicht implementiert-->
|
<!-- Noch disabled, da likes noch nicht implementiert-->
|
||||||
<label class="s-res-filter-option">
|
<label class="s-res-filter-option">
|
||||||
<input type="radio" name="sort" value="likes" <?php echo $currentSort === 'likes' ? 'checked' : ''; ?> disabled>
|
<input type="radio" name="sort" value="likes" <?php echo $currentSort === 'likes' ? 'checked' : ''; ?> onchange="this.form.submit()">
|
||||||
<span style="color: #94a3b8;">Beliebtheit (Likes)</span>
|
<span>Beliebtheit (Likes)</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="s-res-filter-option">
|
<label class="s-res-filter-option">
|
||||||
<input type="radio" name="sort" value="newest" <?php echo $currentSort === 'newest' ? 'checked' : ''; ?> onchange="this.form.submit()">
|
<input type="radio" name="sort" value="newest" <?php echo $currentSort === 'newest' ? 'checked' : ''; ?> onchange="this.form.submit()">
|
||||||
@@ -103,7 +103,14 @@ $resultCount = count($results);
|
|||||||
<?php echo htmlspecialchars($item['title']); ?>
|
<?php echo htmlspecialchars($item['title']); ?>
|
||||||
</a>
|
</a>
|
||||||
</h2>
|
</h2>
|
||||||
|
<div class="s-res-meta-row">
|
||||||
<p class="s-res-author">Von: <span class="s-res-author-name"><?php echo htmlspecialchars($item['author']); ?></span></p>
|
<p class="s-res-author">Von: <span class="s-res-author-name"><?php echo htmlspecialchars($item['author']); ?></span></p>
|
||||||
|
|
||||||
|
<span class="s-res-likes">
|
||||||
|
❤️ <?php echo isset($item['likes']) && is_array($item['likes']) ? count($item['likes']) : 0; ?>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="s-res-arrow">→</div>
|
<div class="s-res-arrow">→</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+21
-20
@@ -1,28 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
include_once 'php/controller/showArticle-controller.php';
|
|
||||||
require_once 'php/model/CommentManager.php';
|
|
||||||
|
|
||||||
$comments = [];
|
$comments = [];
|
||||||
$mainComments = [];
|
$mainComments = [];
|
||||||
$repliesByParent = [];
|
$repliesByParent = [];
|
||||||
|
$articleObj = null;
|
||||||
|
|
||||||
if (isset($_GET["id"])) {
|
include_once 'php/controller/showArticle-controller.php';
|
||||||
try {
|
|
||||||
$commentManager = CommentManager::getInstance();
|
|
||||||
$comments = $commentManager->getCommentsByArticle($_GET["id"]);
|
|
||||||
|
|
||||||
foreach ($comments as $comment) {
|
|
||||||
if ($comment->isReply()) {
|
|
||||||
$parentId = $comment->getParentCommentId();
|
|
||||||
$repliesByParent[$parentId][] = $comment;
|
|
||||||
} else {
|
|
||||||
$mainComments[] = $comment;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$_SESSION["message"] = "internal_error";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
?>
|
||||||
<!--
|
<!--
|
||||||
Seite: Anzeige für Beiträge
|
Seite: Anzeige für Beiträge
|
||||||
@@ -35,10 +17,29 @@ if (isset($_GET["id"])) {
|
|||||||
<!-- Metadaten & Titel -->
|
<!-- Metadaten & Titel -->
|
||||||
<div class="article-view-top-section">
|
<div class="article-view-top-section">
|
||||||
|
|
||||||
|
<div class="article-view-top-section">
|
||||||
|
|
||||||
|
<div class="category-and-likes-row">
|
||||||
<?php if (isset($category) && !empty($category)): ?>
|
<?php if (isset($category) && !empty($category)): ?>
|
||||||
<span class="article-view-category"><?php echo htmlspecialchars($category); ?></span>
|
<span class="article-view-category"><?php echo htmlspecialchars($category); ?></span>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<!-- Like-Anzeige und dynamischer Like-Button -->
|
||||||
|
<?php if (isset($articleObj) && $articleObj !== null): ?>
|
||||||
|
<div class="article-view-likes">
|
||||||
|
<span>❤️ <span class="like-count"><?php echo $articleObj->getLikeCount(); ?></span></span>
|
||||||
|
|
||||||
|
<?php if (isset($_SESSION["user_email"])): ?>
|
||||||
|
<a href="php/controller/like-controller.php?id=<?php echo $articleObj->getId(); ?>" class="like-toggle-btn">
|
||||||
|
<?php echo $articleObj->hasLiked($_SESSION["user_email"]) ? '👎 Gefällt mir nicht mehr' : '👍 Gefällt mir'; ?>
|
||||||
|
</a>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="login-hint">(Anmelden zum Liken)</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h1 class="article-view-title">
|
<h1 class="article-view-title">
|
||||||
<?php if (isset($title)) { echo htmlspecialchars($title); } ?>
|
<?php if (isset($title)) { echo htmlspecialchars($title); } ?>
|
||||||
</h1>
|
</h1>
|
||||||
|
|||||||
@@ -247,6 +247,17 @@ CSS für die Suchergebnis-Seite
|
|||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.s-res-meta-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 15px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.s-res-likes {
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: #475569;
|
||||||
|
}
|
||||||
|
|
||||||
/* Responsive Anpassungen unter 760px (für z.B. Smartphones) */
|
/* Responsive Anpassungen unter 760px (für z.B. Smartphones) */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.s-res-layout-grid {
|
.s-res-layout-grid {
|
||||||
|
|||||||
@@ -240,3 +240,47 @@
|
|||||||
.comment-login-hint p {
|
.comment-login-hint p {
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Like-Button etc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.category-and-likes-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-view-likes {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
font-size: 0.95em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-view-likes .like-count {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-view-likes .login-hint {
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interaktiver Like/Unlike-Button */
|
||||||
|
.like-toggle-btn {
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 4px 10px;
|
||||||
|
border: 1px solid #bbb;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: background-color 0.2s ease, border-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.like-toggle-btn:hover {
|
||||||
|
background-color: #eaeaea;
|
||||||
|
border-color: #999;
|
||||||
|
}
|
||||||
@@ -63,11 +63,26 @@
|
|||||||
Dein Beitrag wurde erfolgreich veröffentlicht!
|
Dein Beitrag wurde erfolgreich veröffentlicht!
|
||||||
</p>
|
</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
<?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "article_updated"): ?>
|
||||||
|
<p class="alert-message is-success">
|
||||||
|
Der Beitrag wurde erfolgreich bearbeitet und gespeichert.
|
||||||
|
</p>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "profile_updated"): ?>
|
||||||
|
<p class="alert-message is-success">
|
||||||
|
Das Profil wurde erfolgreich bearbeitet.
|
||||||
|
</p>
|
||||||
|
<?php endif; ?>
|
||||||
<?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "image_upload_error"): ?>
|
<?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "image_upload_error"): ?>
|
||||||
<p class="alert-message is-error">
|
<p class="alert-message is-error">
|
||||||
Das Bild konnte nicht hochgeladen werden. Bitte versuche es erneut oder verwende ein anderes Bildformat.
|
Das Bild konnte nicht hochgeladen werden. Bitte versuche es erneut oder verwende ein anderes Bildformat.
|
||||||
</p>
|
</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
<?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "database_error"): ?>
|
||||||
|
<p class="alert-message is-error">
|
||||||
|
Es ist ein Datenbankfehler aufgetreten. Bitte versuche es erneut.
|
||||||
|
</p>
|
||||||
|
<?php endif; ?>
|
||||||
<?php
|
<?php
|
||||||
unset($_SESSION["message"]);
|
unset($_SESSION["message"]);
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ if (session_status() === PHP_SESSION_NONE) {
|
|||||||
session_start();
|
session_start();
|
||||||
}
|
}
|
||||||
ob_start();
|
ob_start();
|
||||||
|
include_once("php/controller/index.php");
|
||||||
|
|
||||||
$pfad = $_GET["pfad"] ?? "home";
|
$pfad = $_GET["pfad"] ?? "home";
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ require_once '../model/LocalArticleManager.php';
|
|||||||
require_once '../model/ArticleManager.php';
|
require_once '../model/ArticleManager.php';
|
||||||
require_once '../validator/article-validator.php';
|
require_once '../validator/article-validator.php';
|
||||||
|
|
||||||
|
if (!isset($_SESSION["user"])) {
|
||||||
|
header("Location: index.php?pfad=login");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||||
$_SESSION["old_title"] = $_POST["title"] ?? '';
|
$_SESSION["old_title"] = $_POST["title"] ?? '';
|
||||||
$_SESSION["old_content"] = $_POST["content"] ?? '';
|
$_SESSION["old_content"] = $_POST["content"] ?? '';
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ if (session_status() === PHP_SESSION_NONE) {
|
|||||||
require_once __DIR__ . "/../model/UserManager.php";
|
require_once __DIR__ . "/../model/UserManager.php";
|
||||||
require_once __DIR__ . "/../model/ArticleManager.php";
|
require_once __DIR__ . "/../model/ArticleManager.php";
|
||||||
|
|
||||||
|
if (!isset($_SESSION["user"])) {
|
||||||
|
header("Location: index.php?pfad=login");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Deregistrierung
|
Deregistrierung
|
||||||
Funktion: Entfernt User aus der Datenbank und beendet die Session
|
Funktion: Entfernt User aus der Datenbank und beendet die Session
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ if (session_status() === PHP_SESSION_NONE) {
|
|||||||
|
|
||||||
require_once __DIR__ . "/../model/ArticleManager.php";
|
require_once __DIR__ . "/../model/ArticleManager.php";
|
||||||
|
|
||||||
|
if (!isset($_SESSION["user"])) {
|
||||||
|
header("Location: index.php?pfad=login");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||||
|
|
||||||
if (isset($_SESSION["user_email"])) {
|
if (isset($_SESSION["user_email"])) {
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
if (session_status() === PHP_SESSION_NONE) {
|
||||||
|
session_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../model/Article.php';
|
||||||
|
require_once __DIR__ . '/../model/ArticleManager.php';
|
||||||
|
|
||||||
|
// 2. Prüfen, ob eine gültige Artikel-ID übergeben wurde
|
||||||
|
if (isset($_GET["id"]) && !empty($_GET["id"])) {
|
||||||
|
$articleId = intval($_GET["id"]);
|
||||||
|
$userEmail = $_SESSION["user_email"];
|
||||||
|
|
||||||
|
if (!isset($_SESSION["user_email"]) || empty($_SESSION["user_email"])) {
|
||||||
|
$_SESSION["message"] = "unauthorized_access";
|
||||||
|
header("Location: ../../index.php?pfad=showArticle&id=" . $articleId);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$articleManager = ArticleManager::getInstance();
|
||||||
|
$articleManager->toggleLike($articleId, $userEmail);
|
||||||
|
|
||||||
|
header("Location: ../../index.php?pfad=showArticle&id=" . $articleId);
|
||||||
|
exit();
|
||||||
|
|
||||||
|
} catch (NotFoundException $e) {
|
||||||
|
$_SESSION["message"] = "missing_id";
|
||||||
|
header("Location: ../../index.php");
|
||||||
|
exit();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$_SESSION["message"] = "internal_error";
|
||||||
|
header("Location: ../../index.php");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$_SESSION["message"] = "missing_id";
|
||||||
|
header("Location: ../../index.php");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
@@ -63,6 +63,7 @@ try {
|
|||||||
$_SESSION["user"] = $vorname . " " . $nachname;
|
$_SESSION["user"] = $vorname . " " . $nachname;
|
||||||
$_SESSION["user_email"] = $newEmail;
|
$_SESSION["user_email"] = $newEmail;
|
||||||
|
|
||||||
|
$_SESSION["message"] = "profile_updated";
|
||||||
header("Location: index.php?pfad=profile");
|
header("Location: index.php?pfad=profile");
|
||||||
exit();
|
exit();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -25,18 +25,22 @@ if ($_SERVER["REQUEST_METHOD"] === "GET" && isset($_GET["q"])) {
|
|||||||
|
|
||||||
if ($sortStyle === 'alphabet') {
|
if ($sortStyle === 'alphabet') {
|
||||||
// Titel aufsteigend alphabetiisch sortiert
|
// Titel aufsteigend alphabetiisch sortiert
|
||||||
|
usort($results, function ($a, $b) {
|
||||||
|
return strcasecmp($a->getTitle(), $b->getTitle());
|
||||||
|
});
|
||||||
|
} elseif ($sortStyle === 'likes') {
|
||||||
usort($results, function($a, $b) {
|
usort($results, function($a, $b) {
|
||||||
return strcasecmp($a->title, $b->title);
|
return $b->getLikeCount() <=> $a->getLikeCount();
|
||||||
});
|
});
|
||||||
} elseif ($sortStyle === 'newest') {
|
} elseif ($sortStyle === 'newest') {
|
||||||
// Datum neu zu alt sortiert
|
// Datum neu zu alt sortiert
|
||||||
usort($results, function($a, $b) {
|
usort($results, function($a, $b) {
|
||||||
return strcmp($b->creationDate, $a->creationDate);
|
return strcmp($b->getCreationDate(), $a->getCreationDate());
|
||||||
});
|
});
|
||||||
} elseif ($sortStyle === 'oldest') {
|
} elseif ($sortStyle === 'oldest') {
|
||||||
// Datum alt zu neu sortiert
|
// Datum alt zu neu sortiert
|
||||||
usort($results, function($a, $b) {
|
usort($results, function($a, $b) {
|
||||||
return strcmp($a->creationDate, $b->creationDate);
|
return strcmp($a->getCreationDate(), $b->getCreationDate());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,13 +48,14 @@ if ($_SERVER["REQUEST_METHOD"] === "GET" && isset($_GET["q"])) {
|
|||||||
$safeArrayResults = [];
|
$safeArrayResults = [];
|
||||||
foreach ($results as $obj) {
|
foreach ($results as $obj) {
|
||||||
$safeArrayResults[] = [
|
$safeArrayResults[] = [
|
||||||
"id" => $obj->id,
|
"id" => $obj->getId(),
|
||||||
"title" => $obj->title,
|
"title" => $obj->getTitle(),
|
||||||
"content" => $obj->content,
|
"content" => $obj->getContent(),
|
||||||
"author" => $obj->author,
|
"author" => $obj->getAuthor(),
|
||||||
"category" => $obj->category,
|
"category" => $obj->getCategory(),
|
||||||
"tags" => $obj->tags,
|
"tags" => $obj->getTags(),
|
||||||
"creationDate" => $obj->creationDate
|
"creationDate" => $obj->getCreationDate(),
|
||||||
|
"likes" => $obj->getLikes(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ if (session_status() === PHP_SESSION_NONE) {
|
|||||||
|
|
||||||
require_once 'php/model/Article.php';
|
require_once 'php/model/Article.php';
|
||||||
require_once 'php/model/ArticleManager.php';
|
require_once 'php/model/ArticleManager.php';
|
||||||
|
require_once 'php/model/CommentManager.php';
|
||||||
|
|
||||||
if (isset($_GET["id"]) && !empty($_GET["id"])){
|
if (isset($_GET["id"]) && !empty($_GET["id"])){
|
||||||
try {
|
try {
|
||||||
@@ -17,11 +18,25 @@ if (isset($_GET["id"]) && !empty($_GET["id"])){
|
|||||||
$category = $article->getCategory();
|
$category = $article->getCategory();
|
||||||
$author = $article->getAuthor();
|
$author = $article->getAuthor();
|
||||||
$tags = $article->getTags();
|
$tags = $article->getTags();
|
||||||
|
$articleObj = $article; // Objekt für die Like-Abfagen sichern
|
||||||
}else{
|
}else{
|
||||||
//header("location: index.php?pfad=404");
|
//header("location: index.php?pfad=404");
|
||||||
include_once "content/404.php";
|
include_once "content/404.php";
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$commentManager = CommentManager::getInstance();
|
||||||
|
$comments = $commentManager->getCommentsByArticle($_GET["id"]);
|
||||||
|
|
||||||
|
foreach ($comments as $comment) {
|
||||||
|
if ($comment->isReply()) {
|
||||||
|
$parentId = $comment->getParentCommentId();
|
||||||
|
$repliesByParent[$parentId][] = $comment;
|
||||||
|
} else {
|
||||||
|
$mainComments[] = $comment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} catch (Exception $e){
|
} catch (Exception $e){
|
||||||
$_SESSION["message"] = "internal_error";
|
$_SESSION["message"] = "internal_error";
|
||||||
exit();
|
exit();
|
||||||
|
|||||||
@@ -8,10 +8,15 @@ require_once '../model/ArticleManager.php';
|
|||||||
require_once '../model/Article.php';
|
require_once '../model/Article.php';
|
||||||
require_once '../validator/article-validator.php';
|
require_once '../validator/article-validator.php';
|
||||||
|
|
||||||
|
if (!isset($_SESSION["user_email"])) {
|
||||||
|
header("Location: index.php?pfad=login");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||||
$_SESSION["old_title"] = $_POST["title"] ?? '';
|
$_SESSION["old_title"] = $_POST["title"] ?? '';
|
||||||
$_SESSION["old_content"] = $_POST["content"] ?? '';
|
$_SESSION["old_content"] = $_POST["content"] ?? '';
|
||||||
$_SESSION["old_category"] = $_POST["category"] ?? ''; // TODO: die Kategorie im Dropdown setzen, wenn der Editor erneut geöffnet wird.
|
$_SESSION["old_category"] = $_POST["category"] ?? '';
|
||||||
$_SESSION["old_tags"] = $_POST["tags"] ?? '';
|
$_SESSION["old_tags"] = $_POST["tags"] ?? '';
|
||||||
|
|
||||||
if (isset($_GET["id"]) && !empty($_GET["id"])) {
|
if (isset($_GET["id"]) && !empty($_GET["id"])) {
|
||||||
@@ -22,6 +27,20 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
|||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$articleManager = ArticleManager::getInstance();
|
||||||
|
$article = $articleManager->getArticle($id);
|
||||||
|
if ($article->getAuthor() != $_SESSION["user_email"]) {
|
||||||
|
$_SESSION["message"] = "unauthorized_access";
|
||||||
|
header("location: ../../index.php");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$_SESSION["message"] = $e->getMessage();
|
||||||
|
header("location: ../../index.php?pfad=updateArticle&id=$id");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
if (!isset($_POST["title"]) ||!isset($_POST["content"]) || !isset($_POST["category"])){
|
if (!isset($_POST["title"]) ||!isset($_POST["content"]) || !isset($_POST["category"])){
|
||||||
$_SESSION["message"] = "missing_parameters";
|
$_SESSION["message"] = "missing_parameters";
|
||||||
header("location: ../../index.php?pfad=updateArticle&id=$id");
|
header("location: ../../index.php?pfad=updateArticle&id=$id");
|
||||||
|
|||||||
+39
-10
@@ -7,13 +7,14 @@
|
|||||||
*/
|
*/
|
||||||
class Article
|
class Article
|
||||||
{
|
{
|
||||||
public $id;
|
private $id;
|
||||||
public $title;
|
private $title;
|
||||||
public $content;
|
private $content;
|
||||||
public $author;
|
private $author;
|
||||||
public $creationDate;
|
private $creationDate;
|
||||||
public $category;
|
private $category;
|
||||||
public $tags;
|
private $tags;
|
||||||
|
private $likes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Konstruktor
|
* Konstruktor
|
||||||
@@ -26,7 +27,7 @@ class Article
|
|||||||
* @param $tags string optionale Schlagworte für eine bessere Suche
|
* @param $tags string optionale Schlagworte für eine bessere Suche
|
||||||
* @param $creationDate string Datum der Beitragserstellung
|
* @param $creationDate string Datum der Beitragserstellung
|
||||||
*/
|
*/
|
||||||
public function __construct(int $id, string $title, string $content, string $author, string $category, string $tags, string $creationDate)
|
public function __construct(int $id, string $title, string $content, string $author, string $category, string $tags, string $creationDate, array $likes = [])
|
||||||
{
|
{
|
||||||
$this->id = $id;
|
$this->id = $id;
|
||||||
$this->title = $title;
|
$this->title = $title;
|
||||||
@@ -35,6 +36,7 @@ class Article
|
|||||||
$this->creationDate = $creationDate;
|
$this->creationDate = $creationDate;
|
||||||
$this->category = $category;
|
$this->category = $category;
|
||||||
$this->tags = $tags;
|
$this->tags = $tags;
|
||||||
|
$this->likes = $likes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,7 +69,7 @@ class Article
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gibt den Content eines Beitrags zurück.
|
* Gibt den Content eines Beitrags zurück.
|
||||||
* TODO: Content muss noch definiert werden.
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getContent(): string
|
public function getContent(): string
|
||||||
@@ -77,7 +79,7 @@ class Article
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Setzt den Content eines Beitrags.
|
* Setzt den Content eines Beitrags.
|
||||||
* TODO: Content muss noch definiert werden.
|
*
|
||||||
* @param $content
|
* @param $content
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
@@ -141,7 +143,34 @@ class Article
|
|||||||
$this->tags = $tags;
|
$this->tags = $tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt alle User-IDs zurück, die diesen Beitrag geliked haben.
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getLikes(): array
|
||||||
|
{
|
||||||
|
return $this->likes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt die Gesamtzahl der Likes zurück.
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getLikeCount(): int
|
||||||
|
{
|
||||||
|
return count($this->likes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prüft, ob ein bestimmter Nutzer den Beitrag bereits geliked hat.
|
||||||
|
*
|
||||||
|
* @param string $userId
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasLiked(string $userId): bool
|
||||||
|
{
|
||||||
|
return in_array($userId, $this->likes);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -18,152 +18,9 @@ class ArticleManager
|
|||||||
*/
|
*/
|
||||||
public static function getInstance()
|
public static function getInstance()
|
||||||
{
|
{
|
||||||
$articleManager = DatabaseArticleManager::getInstance(); // Hier kann zwischen dem lokalen und datenbankbasiertem ArticleManager gewechselt werden.
|
|
||||||
|
|
||||||
// 100 fiktionale Fachbeiträge:
|
return DatabaseArticleManager::getInstance(); // Hier kann zwischen dem lokalen und datenbankbasiertem ArticleManager gewechselt werden.
|
||||||
$dummyArticles = [
|
|
||||||
// --- INFORMATIK & MATHE (1-20) ---
|
|
||||||
1 => ["Satz des Pythagoras", "Der Satz des Pythagoras beschreibt das Verhältnis der Seitenlängen in einem rechtwinkligen Dreieck.", "mathe", "Dreiecke, Geometrie"],
|
|
||||||
2 => ["Tunneleffekt", "Der Tunneleffekt beschreibt das quantenmechanische Phänomen, dass Teilchen Barrieren überwinden können.", "physik", "Quantenphysik, Energie"],
|
|
||||||
3 => ["Datenschutz vs Datensicherheit", "Datenschutz schützt Personen, während Datensicherheit Systeme vor unbefugten Zugriffen schützt.", "informatik", "Daten, DSGVO"],
|
|
||||||
4 => ["Einführung in Algorithmen", "Ein Algorithmus ist eine präzise Handlungsanweisung zur Lösung eines vordefinierten Problems.", "informatik", "Code, Logik"],
|
|
||||||
5 => ["Primzahlen im Detail", "Primzahlen sind natürliche Zahlen, die nur durch eins und sich selbst ohne Rest teilbar sind.", "mathe", "Zahlentheorie"],
|
|
||||||
6 => ["Lineare Algebra", "Vektoren und Matrizen bilden das Fundament für moderne Computergrafik und 3D-Engines.", "mathe", "Matrizen, Vektoren"],
|
|
||||||
7 => ["Objektorientierte Programmierung", "Die OOP nutzt Klassen und Objekte, um reale Strukturen im Quellcode abzubilden.", "informatik", "OOP, Klassen"],
|
|
||||||
8 => ["Grundlagen von HTML und CSS", "HTML strukturiert den Inhalt einer Webseite, während CSS für das optische Design zuständig ist.", "informatik", "Web, Frontend"],
|
|
||||||
9 => ["Die Relativitätstheorie", "Einsteins Theorie revolutionierte unser Verständnis von Raum, Zeit und Gravitation massiv.", "physik", "Einstein, Gravitation"],
|
|
||||||
10 => ["Datenbanken und SQL", "Strukturierte Abfragesprachen erlauben das effiziente Speichern und Abrufen großer Datenmengen.", "informatik", "SQL, Datenbank"],
|
|
||||||
11 => ["Wahrscheinlichkeitsrechnung", "Die Stochastik befasst sich mit der mathematischen Analyse von Zufallsexperimenten.", "mathe", "Zufall, Stochastik"],
|
|
||||||
12 => ["Quantencomputing", "Künftige Quantencomputer nutzen Qubits, um komplexe Berechnungen in Rekordzeit zu lösen.", "informatik", "Hardware, Zukunft"],
|
|
||||||
13 => ["Die Fibonacci-Folge", "Diese Zahlenreihe beschreibt mathematische Wachstumsmuster, die oft in der Natur vorkommen.", "mathe", "Zahlen, Natur"],
|
|
||||||
14 => ["Thermodynamik", "Die Hauptsätze der Thermodynamik regeln den Energieaustausch und die Entropie in Systemen.", "physik", "Energie, Wärme"],
|
|
||||||
15 => ["Cybersecurity Grundlagen", "Die Absicherung von Netzwerken erfordert Firewalls, Verschlüsselung und regelmäßige Audits.", "informatik", "Sicherheit, Hacker"],
|
|
||||||
16 => ["Kryptographie", "Asymmetrische Verschlüsselungsverfahren sichern heutzutage den gesamten Datenverkehr im Web.", "informatik", "Krypto, Security"],
|
|
||||||
17 => ["Analysis und Ableitungen", "Die Differentialrechnung untersucht die lokalen Änderungsraten von mathematischen Funktionen.", "mathe", "Analysis, Funktionen"],
|
|
||||||
18 => ["Schwarze Löcher", "Diese Regionen im Raum besitzen eine so starke Gravitation, dass selbst Licht nicht entkommt.", "physik", "Astronomie, Kosmos"],
|
|
||||||
19 => ["Git Versionsverwaltung", "Git erlaubt Entwicklern das parallele Arbeiten an Code-Projekten ohne Datenverlust.", "informatik", "Git, DevOps"],
|
|
||||||
20 => ["Künstliche Intelligenz", "Neuronale Netze versuchen das menschliche Gehirn für maschinelles Lernen nachzubilden.", "informatik", "KI, Software"],
|
|
||||||
|
|
||||||
// --- CHEMIE & BIOLOGIE (21-40) ---
|
|
||||||
21 => ["Das Periodensystem", "Die Elemente sind nach ihrer Ordnungszahl und chemischen Eigenschaften geordnet.", "chemie", "Elemente, Moleküle"],
|
|
||||||
22 => ["Photosynthese", "Pflanzen wandeln mithilfe von Sonnenlicht Kohlendioxid und Wasser in Glukose und Sauerstoff um.", "biologie", "Pflanzen, Energie"],
|
|
||||||
23 => ["Aufbau einer Zelle", "Die Zelle ist die kleinste lebende Einheit aller Organismen mit spezialisierten Organellen.", "biologie", "Zellen, Biologie"],
|
|
||||||
24 => ["Säuren und Basen", "Der pH-Wert misst die Konzentration von Wasserstoff-Ionen in einer wässrigen Lösung.", "chemie", "Labor, pH-Wert"],
|
|
||||||
25 => ["Die DNA-Struktur", "Die Doppelhelix enthält den genetischen Bauplan für die Entwicklung aller Lebewesen.", "biologie", "Genetik, Erbgut"],
|
|
||||||
26 => ["Chemische Bindungen", "Kovalente Bindungen entstehen durch das Teilen von Elektronenpaaren zwischen Atomen.", "chemie", "Atome, Bindung"],
|
|
||||||
27 => ["Das Immunsystem", "Weiße Blutkörperchen und Antikörper schützen den menschlichen Körper vor Krankheitserregern.", "biologie", "Gesundheit, Abwehr"],
|
|
||||||
28 => ["Katalysatoren", "Katalysatoren beschleunigen chemische Reaktionen, ohne dabei selbst verbraucht zu werden.", "chemie", "Reaktion, Chemie"],
|
|
||||||
29 => ["Ökosystem Wald", "Das Zusammenspiel von Flora, Fauna und Klima bildet ein hochsensibles ökologisches System.", "biologie", "Natur, Wald"],
|
|
||||||
30 => ["Die Mendelschen Regeln", "Diese Grundgesetze der Vererbung beschreiben, wie Merkmale an Nachkommen weitergegeben werden.", "biologie", "Genetik, Erbung"],
|
|
||||||
31 => ["Zustandsformen der Materie", "Fest, flüssig und gasförmig sind die klassischen Aggregatzustände von Stoffen.", "chemie", "Physik, Materie"],
|
|
||||||
32 => ["Evolutionstheorie", "Charles Darwin begründete die Theorie der natürlichen Auslese und Anpassung von Arten.", "biologie", "Darwin, Evolution"],
|
|
||||||
33 => ["Organische Chemie", "Die Chemie der Kohlenstoffverbindungen bildet die Basis für alles bekannte Leben.", "chemie", "Kohlenstoff, Chemie"],
|
|
||||||
34 => ["Das menschliche Gehirn", "Milliarden von Neuronen kommunizieren über Synapsen, um Reize und Gedanken zu verarbeiten.", "biologie", "Neurologie, Nerven"],
|
|
||||||
35 => ["Der Wasserkreislauf", "Verdunstung, Kondensation und Niederschlag halten das Wasser auf der Erde in Bewegung.", "geographie", "Wasser, Klima"],
|
|
||||||
36 => ["Aggregatzustände von Wasser", "Wasser zeigt ungewöhnliche Eigenschaften wie die Dichteanomalie beim Gefrieren.", "chemie", "Wasser, Eis"],
|
|
||||||
37 => ["Blutkreislauf des Menschen", "Das Herz pumpt sauerstoffreiches Blut durch Arterien in alle Organe des Körpers.", "biologie", "Herz, Medizin"],
|
|
||||||
38 => ["Das Ohmsche Gesetz", "Es beschreibt den direkten Zusammenhang zwischen Spannung, Stromstärke und Widerstand.", "physik", "Strom, Elektronik"],
|
|
||||||
39 => ["Plattentektonik", "Die Bewegung der Kontinentalplatten führt zu Erdbeben, Vulkanismus und Gebirgsbildung.", "geographie", "Erde, Geologie"],
|
|
||||||
40 => ["Proteine und Enzyme", "Enzyme wirken als Biokatalysatoren und steuern fast alle Stoffwechselprozesse.", "biologie", "Biochemie, Enzyme"],
|
|
||||||
|
|
||||||
// --- GESCHICHTE & WIRTSCHAFT (41-60) ---
|
|
||||||
41 => ["Das Römische Reich", "Vom Stadtstaat zum Weltreich prägte Rom die Rechts- und Kulturgeschichte Europas.", "geschichte", "Antike, Rom"],
|
|
||||||
42 => ["Die Französische Revolution", "Freiheit, Gleichheit, Brüderlichkeit beendeten 1789 die absolute Monarchie in Frankreich.", "geschichte", "Europa, Politik"],
|
|
||||||
43 => ["Inflation erklärt", "Inflation bezeichnet die kontinuierliche Geldentwertung und den Kaufkraftverlust.", "wirtschaft", "Geld, Finanzen"],
|
|
||||||
44 => ["Die Industrielle Revolution", "Die Erfindung der Dampfmaschine veränderte die Produktion und die Gesellschaft tiefgreifend.", "geschichte", "Industrie, Arbeit"],
|
|
||||||
45 => ["Angebot und Nachfrage", "Dieses fundamentale Marktgesetz bestimmt den Preis von Gütern in einer freien Wirtschaft.", "wirtschaft", "Markt, Preise"],
|
|
||||||
46 => ["Der Buchdruck", "Johannes Gutenbergs Erfindung revolutionierte die Verbreitung von Wissen im Mittelalter.", "geschichte", "Medien, Wissen"],
|
|
||||||
47 => ["Die Entdeckung Amerikas", "Kolumbus' Seereise im Jahr 1492 leitete das Zeitalter der Kolonialisierung ein.", "geschichte", "Entdeckung, Seefahrt"],
|
|
||||||
48 => ["Kryptowährungen", "Bitcoin nutzt Blockchain-Technologie, um dezentralen digitalen Werttransfer zu erlauben.", "wirtschaft", "Blockchain, Finanzen"],
|
|
||||||
49 => ["Das antike Griechenland", "Die Wiege der Demokratie und Philosophie brachte Denker wie Sokrates und Platon hervor.", "geschichte", "Antike, Philosophie"],
|
|
||||||
50 => ["Globalisierung", "Die weltweite Verflechtung in Wirtschaft, Kultur und Politik bringt Chancen und Risiken.", "wirtschaft", "Weltwirtschaft, Handel"],
|
|
||||||
51 => ["Der Dreißigjährige Krieg", "Ein religiöser und politischer Konflikt verwüstete zwischen 1618 und 1648 Mitteleuropa.", "geschichte", "Krieg, Europa"],
|
|
||||||
52 => ["Die Weimarer Republik", "Die erste deutsche Demokratie scheiterte an wirtschaftlichen und politischen Krisen.", "geschichte", "Deutschland, Weimar"],
|
|
||||||
53 => ["Aktien und Börse", "Unternehmen beschaffen sich Kapital durch die Ausgabe von Anteilen an Investoren.", "wirtschaft", "Aktien, Investieren"],
|
|
||||||
54 => ["Das alte Ägypten", "Pharaonen, Pyramiden und Hieroglyphen zeugen von einer hochentwickelten Hochkultur am Nil.", "geschichte", "Ägypten, Antike"],
|
|
||||||
55 => ["Der Kalte Krieg", "Das Wettrüsten zwischen USA und UdSSR prägte die globale Politik der Nachkriegszeit.", "geschichte", "Ost-West, Politik"],
|
|
||||||
56 => ["Zentralbanken und Leitzins", "Durch Zinsänderungen steuern Notenbanken die Geldmenge und bekämpfen Inflation.", "wirtschaft", "Zinsen, Geldpolitik"],
|
|
||||||
57 => ["Die Seidenstraße", "Das historische Netzwerk von Handelsrouten verband über Jahrhunderte Asien und Europa.", "geschichte", "Handel, Asien"],
|
|
||||||
58 => ["Das Mittelalter", "Ritter, Burgen und das Feudalsystem prägten diese tausendjährige Epoche Europas.", "geschichte", "Mittelalter, Feudalismus"],
|
|
||||||
59 => ["Planwirtschaft vs Marktwirtschaft", "Zentrale staatliche Steuerung steht dem freien Spiel der Marktkräfte gegenüber.", "wirtschaft", "Systeme, Wirtschaft"],
|
|
||||||
60 => ["Die Berliner Mauer", "Ihr Bau 1961 zementierte die Teilung Deutschlands, ihr Fall 1989 beendete sie.", "geschichte", "DDR, Wiedervereinigung"],
|
|
||||||
|
|
||||||
// --- ANWENDUNGEN & WEITERE THEMEN (61-100) ---
|
|
||||||
61 => ["Cloud Computing", "Das Auslagern von Rechenleistung in das Internet spart lokale IT-Infrastruktur ein.", "informatik", "Cloud, Web"],
|
|
||||||
62 => ["Responsive Webdesign", "Moderne Webseiten passen ihr Layout dynamisch an Smartphones und Desktops an.", "informatik", "Design, CSS"],
|
|
||||||
63 => ["Der Treibhauseffekt", "Gase in der Atmosphäre verhindern das Entweichen von Wärme ins Weltall.", "physik", "Klima, Umwelt"],
|
|
||||||
64 => ["Mechanik und Kräfte", "Die Newtonschen Axiome beschreiben, wie Kräfte auf Körper wirken und sie bewegen.", "physik", "Newton, Kraft"],
|
|
||||||
65 => ["Die Mendelschen Gesetze", "Die Vererbung von Genen folgt klaren statistischen Wahrscheinlichkeiten.", "biologie", "Genetik, Erbsen"],
|
|
||||||
66 => ["Lichtgeschwindigkeit", "Im Vakuum bewegt sich Licht mit knapp 300.000 Kilometern pro Sekunde.", "physik", "Licht, Relativität"],
|
|
||||||
67 => ["Die Funktion von APIs", "Programmierschnittstellen erlauben den Datenaustausch zwischen verschiedenen Systemen.", "informatik", "API, Schnittstelle"],
|
|
||||||
68 => ["Der Goldstandard", "Ein historischen Währungssystem, bei dem Geld durch echtes Gold gedeckt war.", "wirtschaft", "Gold, Währung"],
|
|
||||||
69 => ["Der Wiener Kongress", "1815 ordneten die europäischen Mächte die Landkarte nach den Napoleonischen Kriegen neu.", "geschichte", "Europa, Diplomatie"],
|
|
||||||
70 => ["Integrierte Schaltkreise", "Mikrochips enthalten Millionen Transistoren auf kleinstem Raum für Logikschaltungen.", "informatik", "Hardware, Chips"],
|
|
||||||
71 => ["Die Magellan-Expedition", "Die erste erfolgreiche Weltumsegelung bewies praktisch die Kugelgestalt der Erde.", "geschichte", "Seefahrt, Erde"],
|
|
||||||
72 => ["Das Internet der Dinge", "Alltagsgegenstände werden vernetzt, um smarte Automatisierungen zu ermöglichen.", "informatik", "IoT, SmartHome"],
|
|
||||||
73 => ["Halbwertszeit", "Die Zeitspanne, in der sich die Hälfte der instabilen Atome radioaktiv abbaut.", "physik", "Atomphysik, Strahlung"],
|
|
||||||
74 => ["Elektromagnetismus", "Die Verknüpfung von elektrischen Strömen und magnetischen Feldern treibt Motoren an.", "physik", "Strom, Magnet"],
|
|
||||||
75 => ["Das Ökosystem Meer", "Ozeane regulieren das Weltklima und bieten Lebensraum für unzählige Arten.", "biologie", "Meer, Ökologie"],
|
|
||||||
76 => ["Einführung in Docker", "Containerisierung isoliert Anwendungen samt Abhängigkeiten für stabilen Betrieb.", "informatik", "Docker, DevOps"],
|
|
||||||
77 => ["Das Römische Recht", "Viele moderne europäische Gesetzbücher basieren auf antiken römischen Rechtsprinzipien.", "geschichte", "Recht, Gesetz"],
|
|
||||||
78 => ["Verhaltensbiologie", "Untersuchung von angeborenen und erlernten Verhaltensweisen bei Mensch und Tier.", "biologie", "Verhalten, Tiere"],
|
|
||||||
79 => ["Verschlüsselung im Alltag", "HTTPS schützt Passwörter und Zahlungsdaten beim Surfen vor dem Mitlesen.", "informatik", "Web, HTTPS"],
|
|
||||||
80 => ["Die Magna Carta", "1215 schränkte dieses Dokument die absolute Macht des englischen Königs ein.", "geschichte", "England, Verfassung"],
|
|
||||||
81 => ["Marktversagen", "Wenn der freie Markt Ressourcen unvollständig verteilt, muss der Staat eingreifen.", "wirtschaft", "Markt, Staat"],
|
|
||||||
82 => ["Optische Linsen", "Konvexe und konkave Linsen brechen Licht für Brillen, Mikroskope und Kameras.", "physik", "Optik, Licht"],
|
|
||||||
83 => ["Die Entstehung der Erde", "Vor rund 4,5 Milliarden Jahren ballte sich kosmischer Staub zu unserem Planeten.", "geographie", "Erde, Kosmos"],
|
|
||||||
84 => ["Grundlagen von JavaScript", "Diese Skriptsprache macht statische Webseiten interaktiv und dynamisch nutzbar.", "informatik", "JS, Webentwicklung"],
|
|
||||||
85 => ["Die industrielle Landwirtschaft", "Moderne Techniken sichern Welternährung, belasten jedoch oft die Umwelt.", "biologie", "Landwirtschaft, Umwelt"],
|
|
||||||
86 => ["Das Schwarze Jahr 1929", "Der New Yorker Börsencrash löste die verheerende Weltwirtschaftskrise aus.", "geschichte", "Krise, Finanzen"],
|
|
||||||
87 => ["Die Evolution des Menschen", "Der Stammbaum des Homo Sapiens entwickelte sich über Millionen Jahre in Afrika.", "biologie", "Mensch, Evolution"],
|
|
||||||
88 => ["Einführung in Linux", "Das Open-Source-Betriebssystem bildet das Rückgrat moderner Server-Infrastrukturen.", "informatik", "Linux, OS"],
|
|
||||||
89 => ["Der Urknall", "Die Urknalltheorie beschreibt den Beginn des Universums aus einer Singularität.", "physik", "Astronomie, Urknall"],
|
|
||||||
90 => ["Das Periodensystem der Elemente", "Dmitri Mendelejew ordnete Elemente logisch nach ihren Atommassen.", "chemie", "Periodensystem, Chemie"],
|
|
||||||
91 => ["Die Hanse", "Ein mächtiger mittelalterlicher Bund von Kaufleuten dominierte den Nordseehandel.", "geschichte", "Handel, Mittelalter"],
|
|
||||||
92 => ["Wirtschaftswachstum", "Die Steigerung des Bruttoinlandsprodukts gilt oft als Indikator für Wohlstand.", "wirtschaft", "BIP, Finanzen"],
|
|
||||||
93 => ["Neuronale Netze", "Diese Strukturen lernen durch mathematische Gewichtung aus riesigen Datenmengen.", "informatik", "KI, Mathematik"],
|
|
||||||
94 => ["Der Erste Weltkrieg", "Der globale Konflikt von 1914 bis 1918 zerstörte das alte europäische Machtgefüge.", "geschichte", "Europa, Krieg"],
|
|
||||||
95 => ["Das Gehirn und Hormone", "Botenstoffe steuern Gefühle, Schlafzyklen und Reaktionen des Körpers.", "biologie", "Medizin, Hormone"],
|
|
||||||
96 => ["SQL Joins erklärt", "Joins verknüpfen Daten aus mehreren Tabellen über gemeinsame Schlüssel.", "informatik", "SQL, Datenbanken"],
|
|
||||||
97 => ["Wellen-Teilchen-Dualismus", "Quantenobjekte zeigen je nach Messaufbau Eigenschaften von Wellen oder Teilchen.", "physik", "Quanten, Licht"],
|
|
||||||
98 => ["Der Absolutismus", "Der Sonnenkönig Ludwig XIV. verkörperte die unbeschränkte Herrschaft des Monarchen.", "geschichte", "Frankreich, Monarchie"],
|
|
||||||
99 => ["Die Funktion von Routern", "Netzwerkgeräte leiten Datenpakete über IP-Adressen an den richtigen Empfänger.", "informatik", "Netzwerk, Internet"],
|
|
||||||
100 => ["Die Entstehung des Geldes", "Vom Tauschhandel über Naturalgeld bis hin zu modernen digitalen Fiat-Währungen.", "wirtschaft", "Geld, Geschichte"]
|
|
||||||
];
|
|
||||||
|
|
||||||
// 10 Dummy-User:
|
|
||||||
$authors = [
|
|
||||||
'max.mustermann@web.de', 'erika.mustermann@web.de', 'john.doe@gmail.com',
|
|
||||||
'jane.doe@gmail.com', 'anna.schmidt@gmx.de', 'thomas.mueller@gmx.de',
|
|
||||||
'sabine.fischer@outlook.com', 'michael.weber@outlook.com', 'julia.wagner@t-online.de',
|
|
||||||
'stefan.becker@t-online.de'
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($dummyArticles as $id => $data) {
|
|
||||||
// Falls der Artikel mit der ID noch nicht existiert, lege ihn an
|
|
||||||
if ($articleManager->getArticle($id) == null) {
|
|
||||||
// Verteilt die 10 Autoren gleichmäßig (ID 1 -> Autor 1, ID 10 -> Autor 10, ID 11 -> Autor 1)
|
|
||||||
$authorEmail = $authors[($id - 1) % 10];
|
|
||||||
|
|
||||||
$blockStructure = [
|
|
||||||
[
|
|
||||||
'type' => 'text',
|
|
||||||
'value' => $data[1] // Der originale Text aus dem Dummy-Array
|
|
||||||
]
|
|
||||||
];
|
|
||||||
$jsonContent = json_encode($blockStructure, JSON_UNESCAPED_UNICODE);
|
|
||||||
|
|
||||||
$articleManager->addArticle(
|
|
||||||
$data[0], // Titel
|
|
||||||
$jsonContent, // Inhalt
|
|
||||||
$authorEmail, // Rotierende Autoren-E-Mail
|
|
||||||
$data[2], // Kategorie
|
|
||||||
$data[3] // Tags
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $articleManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -92,6 +92,18 @@ interface ArticleManagerDAO
|
|||||||
*/
|
*/
|
||||||
public function getArticlesByCategory($category);
|
public function getArticlesByCategory($category);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registriert oder entfernt ein Like eines Nutzers für einen Beitrag.
|
||||||
|
* Wenn schon geliked -> Unlike
|
||||||
|
* Wenn noch nicht geliked -> Like
|
||||||
|
*
|
||||||
|
* @param int $articleId Die ID des Beitrags
|
||||||
|
* @param string $userId Die ID des Nutzers
|
||||||
|
* @return bool True wenn geliked, False wenn unliked
|
||||||
|
* @throws InternalServerErrorException
|
||||||
|
* @throws NotFoundException
|
||||||
|
*/
|
||||||
|
public function toggleLike(int $articleId, string $userId): bool;
|
||||||
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
require_once 'DatabaseInitializer.php';
|
||||||
require_once 'ArticleManagerDAO.php';
|
require_once 'ArticleManagerDAO.php';
|
||||||
require_once 'Article.php';
|
require_once 'Article.php';
|
||||||
/**
|
/**
|
||||||
@@ -9,50 +10,35 @@ require_once 'Article.php';
|
|||||||
class DatabaseArticleManager implements ArticleManagerDAO {
|
class DatabaseArticleManager implements ArticleManagerDAO {
|
||||||
|
|
||||||
private static $instance = null;
|
private static $instance = null;
|
||||||
|
private $dbPath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Konstruktor
|
* Konstruktor
|
||||||
*
|
*
|
||||||
* Erstellt die Datenbankverbindung und die Tabelle articles.
|
* Erstellt die Datenbankverbindung und die Tabelle articles.
|
||||||
* @throws InternalServerErrorException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
if (!file_exists(__DIR__ . '/../../db/articles.db')) {
|
$this->dbPath = __DIR__ . '/../../db/eduforgeDB.db';
|
||||||
try {
|
DatabaseInitializer::initialize($this->dbPath);
|
||||||
|
|
||||||
$db = $this->getConnection();
|
|
||||||
|
|
||||||
$db->exec("
|
|
||||||
CREATE TABLE articles (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
title TEXT,
|
|
||||||
content TEXT,
|
|
||||||
author TEXT,
|
|
||||||
category TEXT,
|
|
||||||
tags TEXT,
|
|
||||||
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
||||||
);");
|
|
||||||
unset($db);
|
|
||||||
} catch (PDOException $e) {
|
|
||||||
throw new InternalServerErrorException($e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Baut die Verbindung zur Datenbank auf.
|
* Baut die Verbindung zur Datenbank auf.
|
||||||
* @throws InternalServerErrorException
|
*
|
||||||
|
* @return PDO Datenbankverbindung
|
||||||
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
private function getConnection()
|
private function getConnection()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$user = 'root';
|
$db = new PDO('sqlite:' . $this->dbPath, null, null);
|
||||||
$pw = null;
|
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
$dsn = 'sqlite:' . __DIR__ . '/../../db/articles.db';
|
$db->exec('PRAGMA foreign_keys = ON;');
|
||||||
return new PDO($dsn, $user, $pw);
|
return $db;
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
throw new InternalServerErrorException($e->getMessage());
|
throw new RuntimeException("internal_error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +175,8 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
|||||||
$row = $command->fetch(PDO::FETCH_ASSOC);
|
$row = $command->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
if ($row) {
|
if ($row) {
|
||||||
|
$likes = $this->getLikesForArticle(intval($row['id']));
|
||||||
|
|
||||||
return new Article(
|
return new Article(
|
||||||
intval($row['id']),
|
intval($row['id']),
|
||||||
$row['title'],
|
$row['title'],
|
||||||
@@ -196,7 +184,8 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
|||||||
$row['author'],
|
$row['author'],
|
||||||
$row['category'],
|
$row['category'],
|
||||||
$row['tags'],
|
$row['tags'],
|
||||||
$row['created']
|
$row['created'],
|
||||||
|
$likes
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,6 +243,8 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
|||||||
$filteredArticles = [];
|
$filteredArticles = [];
|
||||||
|
|
||||||
foreach ($rows as $row) {
|
foreach ($rows as $row) {
|
||||||
|
$likes = $this->getLikesForArticle(intval($row['id']));
|
||||||
|
|
||||||
$filteredArticles[] = new Article(
|
$filteredArticles[] = new Article(
|
||||||
intval($row['id']),
|
intval($row['id']),
|
||||||
$row['title'],
|
$row['title'],
|
||||||
@@ -261,7 +252,8 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
|||||||
$row['author'],
|
$row['author'],
|
||||||
$row['category'],
|
$row['category'],
|
||||||
$row['tags'],
|
$row['tags'],
|
||||||
$row['created']
|
$row['created'],
|
||||||
|
$likes
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,6 +279,8 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
|||||||
$filteredArticles = [];
|
$filteredArticles = [];
|
||||||
|
|
||||||
foreach ($rows as $row) {
|
foreach ($rows as $row) {
|
||||||
|
$likes = $this->getLikesForArticle(intval($row['id']));
|
||||||
|
|
||||||
$filteredArticles[] = new Article(
|
$filteredArticles[] = new Article(
|
||||||
intval($row['id']),
|
intval($row['id']),
|
||||||
$row['title'],
|
$row['title'],
|
||||||
@@ -294,7 +288,8 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
|||||||
$row['author'],
|
$row['author'],
|
||||||
$row['category'],
|
$row['category'],
|
||||||
$row['tags'],
|
$row['tags'],
|
||||||
$row['created']
|
$row['created'],
|
||||||
|
$likes
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,6 +336,8 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
|||||||
$filteredArticles = [];
|
$filteredArticles = [];
|
||||||
|
|
||||||
foreach ($rows as $row) {
|
foreach ($rows as $row) {
|
||||||
|
$likes = $this->getLikesForArticle(intval($row['id']));
|
||||||
|
|
||||||
$filteredArticles[] = new Article(
|
$filteredArticles[] = new Article(
|
||||||
intval($row['id']),
|
intval($row['id']),
|
||||||
$row['title'] ?? '',
|
$row['title'] ?? '',
|
||||||
@@ -348,7 +345,8 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
|||||||
$row['author'] ?? '',
|
$row['author'] ?? '',
|
||||||
$row['category'] ?? '',
|
$row['category'] ?? '',
|
||||||
$row['tags'] ?? '',
|
$row['tags'] ?? '',
|
||||||
$row['created'] ?? '' // Nutzt 'created' aus deiner DB-Struktur
|
$row['created'] ?? '',
|
||||||
|
$likes
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,4 +357,69 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holt alle User-IDs, die einen bestimmten Beitrag geliked haben.
|
||||||
|
*
|
||||||
|
* @return String[] UserIDs
|
||||||
|
* @throws InternalServerErrorException
|
||||||
|
*/
|
||||||
|
private function getLikesForArticle(int $articleId): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$db = $this->getConnection();
|
||||||
|
$sql = "SELECT user_id FROM likes WHERE article_id = :article_id;";
|
||||||
|
$command = $db->prepare($sql);
|
||||||
|
$command->execute([':article_id' => $articleId]);
|
||||||
|
|
||||||
|
return $command->fetchAll(PDO::FETCH_COLUMN) ?: [];
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toggleLike(int $articleId, string $userId): bool
|
||||||
|
{
|
||||||
|
// prüfen, ob der Artikel überhaupt existiert
|
||||||
|
$article = $this->getArticle($articleId);
|
||||||
|
if (!$article) {
|
||||||
|
throw new NotFoundException("missing_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = $this->getConnection();
|
||||||
|
|
||||||
|
// prüfen, ob das Like bereits existiert
|
||||||
|
$checkSql = "SELECT COUNT(*) FROM likes WHERE article_id = :article_id AND user_id = :user_id;";
|
||||||
|
$checkCommand = $db->prepare($checkSql);
|
||||||
|
$checkCommand->execute([
|
||||||
|
':article_id' => $articleId,
|
||||||
|
':user_id' => $userId
|
||||||
|
]);
|
||||||
|
|
||||||
|
$hasLiked = (int)$checkCommand->fetchColumn() > 0;
|
||||||
|
|
||||||
|
if ($hasLiked) {
|
||||||
|
// wenn bereits geliked -> Unlike
|
||||||
|
$deleteSql = "DELETE FROM likes WHERE article_id = :article_id AND user_id = :user_id;";
|
||||||
|
$deleteCommand = $db->prepare($deleteSql);
|
||||||
|
$deleteCommand->execute([
|
||||||
|
':article_id' => $articleId,
|
||||||
|
':user_id' => $userId
|
||||||
|
]);
|
||||||
|
return false; // gibt false zurück, da der Beitrag jetzt nicht mehr geliked ist
|
||||||
|
} else {
|
||||||
|
// wenn noch nicht geliked -> Like
|
||||||
|
$insertSql = "INSERT INTO likes (article_id, user_id) VALUES (:article_id, :user_id);";
|
||||||
|
$insertCommand = $db->prepare($insertSql);
|
||||||
|
$insertCommand->execute([
|
||||||
|
':article_id' => $articleId,
|
||||||
|
':user_id' => $userId
|
||||||
|
]);
|
||||||
|
return true; // gibt true zurück, da der Beitrag jetzt geliked ist
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
throw new InternalServerErrorException("internal_error");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
require_once 'DatabaseInitializer.php';
|
||||||
require_once "CommentManagerDAO.php";
|
require_once "CommentManagerDAO.php";
|
||||||
require_once "Comment.php";
|
require_once "Comment.php";
|
||||||
|
|
||||||
@@ -12,43 +12,15 @@ require_once "Comment.php";
|
|||||||
class DatabaseCommentManager implements CommentManagerDAO
|
class DatabaseCommentManager implements CommentManagerDAO
|
||||||
{
|
{
|
||||||
private static $instance = null;
|
private static $instance = null;
|
||||||
|
private $dbPath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erstellt die Kommentartabelle, falls diese noch nicht existiert.
|
* Erstellt die Kommentartabelle, falls diese noch nicht existiert.
|
||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
try {
|
$this->dbPath = __DIR__ . '/../../db/eduforgeDB.db';
|
||||||
$db = $this->getConnection();
|
DatabaseInitializer::initialize($this->dbPath);
|
||||||
|
|
||||||
$db->exec("
|
|
||||||
CREATE TABLE IF NOT EXISTS comments (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
article_id INTEGER NOT NULL,
|
|
||||||
parent_comment_id INTEGER NULL,
|
|
||||||
author TEXT NOT NULL,
|
|
||||||
content TEXT NOT NULL,
|
|
||||||
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
||||||
);
|
|
||||||
");
|
|
||||||
|
|
||||||
$columns = $db->query("PRAGMA table_info(comments);")->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
$hasParentColumn = false;
|
|
||||||
|
|
||||||
foreach ($columns as $column) {
|
|
||||||
if ($column["name"] === "parent_comment_id") {
|
|
||||||
$hasParentColumn = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$hasParentColumn) {
|
|
||||||
$db->exec("ALTER TABLE comments ADD COLUMN parent_comment_id INTEGER NULL;");
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
|
||||||
throw new RuntimeException("internal_error");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,13 +31,10 @@ class DatabaseCommentManager implements CommentManagerDAO
|
|||||||
private function getConnection()
|
private function getConnection()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$dsn = 'sqlite:' . __DIR__ . '/../../db/comments.db';
|
$db = new PDO('sqlite:' . $this->dbPath, null, null);
|
||||||
|
|
||||||
$db = new PDO($dsn, null, null);
|
|
||||||
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
$db->exec('PRAGMA foreign_keys = ON;');
|
||||||
return $db;
|
return $db;
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
throw new RuntimeException("internal_error");
|
throw new RuntimeException("internal_error");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,244 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Diese Klasse legt einmalig beim allerersten Start in der exakt korrekten Reihenfolge die Tabellen an
|
||||||
|
*
|
||||||
|
* @author Niklas Ortmann
|
||||||
|
*/
|
||||||
|
class DatabaseInitializer {
|
||||||
|
public static function initialize($dbPath) {
|
||||||
|
if (!file_exists($dbPath)) {
|
||||||
|
try {
|
||||||
|
$db = new PDO('sqlite:' . $dbPath);
|
||||||
|
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
$db->exec('PRAGMA foreign_keys = ON;');
|
||||||
|
|
||||||
|
$db->exec("
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
email TEXT PRIMARY KEY,
|
||||||
|
vorname TEXT NOT NULL,
|
||||||
|
nachname TEXT NOT NULL,
|
||||||
|
password TEXT NOT NULL
|
||||||
|
);
|
||||||
|
");
|
||||||
|
|
||||||
|
$db->exec("
|
||||||
|
CREATE TABLE IF NOT EXISTS articles (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
title TEXT,
|
||||||
|
content TEXT,
|
||||||
|
author TEXT,
|
||||||
|
category TEXT,
|
||||||
|
tags TEXT,
|
||||||
|
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (author) REFERENCES users(email) ON DELETE SET NULL ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
");
|
||||||
|
|
||||||
|
$db->exec("
|
||||||
|
CREATE TABLE IF NOT EXISTS likes (
|
||||||
|
article_id INTEGER,
|
||||||
|
user_id TEXT,
|
||||||
|
PRIMARY KEY (article_id, user_id),
|
||||||
|
FOREIGN KEY (article_id) REFERENCES articles(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(email) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
");
|
||||||
|
|
||||||
|
$db->exec("
|
||||||
|
CREATE TABLE IF NOT EXISTS comments (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
article_id INTEGER NOT NULL,
|
||||||
|
parent_comment_id INTEGER NULL,
|
||||||
|
author TEXT NOT NULL,
|
||||||
|
content TEXT NOT NULL,
|
||||||
|
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (article_id) REFERENCES articles(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (author) REFERENCES users(email) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (parent_comment_id) REFERENCES comments(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
");
|
||||||
|
|
||||||
|
$initializer = new self();
|
||||||
|
$availableEmails = $initializer->seedDummyUsers($db);
|
||||||
|
$initializer->seedDummyArticles($db, $availableEmails);
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
throw new RuntimeException("internal-error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erstellt die Dummy-Benutzer in der Datenbank.
|
||||||
|
*
|
||||||
|
* @param PDO $db Die aktive Datenbankverbindung
|
||||||
|
* @return array Liste der erfolgreich angelegten E-Mail-Adressen
|
||||||
|
*/
|
||||||
|
private function seedDummyUsers(PDO $db): array {
|
||||||
|
$dummyUsers = [
|
||||||
|
['email' => 'max.mustermann@web.de', 'vorname' => 'Max', 'nachname' => 'Mustermann'],
|
||||||
|
['email' => 'erika.mustermann@web.de', 'vorname' => 'Erika', 'nachname' => 'Mustermann'],
|
||||||
|
['email' => 'john.doe@gmail.com', 'vorname' => 'John', 'nachname' => 'Doe'],
|
||||||
|
['email' => 'jane.doe@gmail.com', 'vorname' => 'Jane', 'nachname' => 'Doe'],
|
||||||
|
['email' => 'anna.schmidt@gmx.de', 'vorname' => 'Anna', 'nachname' => 'Schmidt'],
|
||||||
|
['email' => 'thomas.mueller@gmx.de', 'vorname' => 'Thomas', 'nachname' => 'Müller'],
|
||||||
|
['email' => 'sabine.fischer@outlook.com', 'vorname' => 'Sabine', 'nachname' => 'Fischer'],
|
||||||
|
['email' => 'michael.weber@outlook.com', 'vorname' => 'Michael', 'nachname' => 'Weber'],
|
||||||
|
['email' => 'julia.wagner@t-online.de', 'vorname' => 'Julia', 'nachname' => 'Wagner'],
|
||||||
|
['email' => 'stefan.becker@t-online.de', 'vorname' => 'Stefan', 'nachname' => 'Becker']
|
||||||
|
];
|
||||||
|
|
||||||
|
$passwordHash = password_hash("test12345", PASSWORD_DEFAULT);
|
||||||
|
$userInsertStmt = $db->prepare("INSERT INTO users (email, vorname, nachname, password) VALUES (:email, :vorname, :nachname, :password);");
|
||||||
|
|
||||||
|
$availableEmails = [];
|
||||||
|
foreach ($dummyUsers as $user) {
|
||||||
|
$userInsertStmt->execute([
|
||||||
|
':email' => $user['email'],
|
||||||
|
':vorname' => $user['vorname'],
|
||||||
|
':nachname' => $user['nachname'],
|
||||||
|
':password' => $passwordHash
|
||||||
|
]);
|
||||||
|
$availableEmails[] = $user['email'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $availableEmails;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erstellt die 100 Fachbeiträge in der Datenbank.
|
||||||
|
*
|
||||||
|
* @param PDO $db Die aktive Datenbankverbindung
|
||||||
|
* @param array $availableEmails Pool für die Foreign-Key-Zuweisung des Autors
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function seedDummyArticles(PDO $db, array $availableEmails): void
|
||||||
|
{
|
||||||
|
$dummyArticles = [
|
||||||
|
// --- INFORMATIK & MATHE (1-20) ---
|
||||||
|
1 => ["Satz des Pythagoras", "Der Satz des Pythagoras beschreibt das Verhältnis der Seitenlängen in einem rechtwinkligen Dreieck.", "mathe", "Dreiecke, Geometrie"],
|
||||||
|
2 => ["Tunneleffekt", "Der Tunneleffekt beschreibt das quantenmechanische Phänomen, dass Teilchen Barrieren überwinden können.", "physik", "Quantenphysik, Energie"],
|
||||||
|
3 => ["Datenschutz vs Datensicherheit", "Datenschutz schützt Personen, während Datensicherheit Systeme vor unbefugten Zugriffen schützt.", "informatik", "Daten, DSGVO"],
|
||||||
|
4 => ["Einführung in Algorithmen", "Ein Algorithmus ist eine präzise Handlungsanweisung zur Lösung eines vordefinierten Problems.", "informatik", "Code, Logik"],
|
||||||
|
5 => ["Primzahlen im Detail", "Primzahlen sind natürliche Zahlen, die nur durch eins und sich selbst ohne Rest teilbar sind.", "mathe", "Zahlentheorie"],
|
||||||
|
6 => ["Lineare Algebra", "Vektoren und Matrizen bilden das Fundament für moderne Computergrafik und 3D-Engines.", "mathe", "Matrizen, Vektoren"],
|
||||||
|
7 => ["Objektorientierte Programmierung", "Die OOP nutzt Klassen und Objekte, um reale Strukturen im Quellcode abzubilden.", "informatik", "OOP, Klassen"],
|
||||||
|
8 => ["Grundlagen von HTML und CSS", "HTML strukturiert den Inhalt einer Webseite, während CSS für das optische Design zuständig ist.", "informatik", "Web, Frontend"],
|
||||||
|
9 => ["Die Relativitätstheorie", "Einsteins Theorie revolutionierte unser Verständnis von Raum, Zeit und Gravitation massiv.", "physik", "Einstein, Gravitation"],
|
||||||
|
10 => ["Datenbanken und SQL", "Strukturierte Abfragesprachen erlauben das effiziente Speichern und Abrufen großer Datenmengen.", "informatik", "SQL, Datenbank"],
|
||||||
|
11 => ["Wahrscheinlichkeitsrechnung", "Die Stochastik befasst sich mit der mathematischen Analyse von Zufallsexperimenten.", "mathe", "Zufall, Stochastik"],
|
||||||
|
12 => ["Quantencomputing", "Künftige Quantencomputer nutzen Qubits, um komplexe Berechnungen in Rekordzeit zu lösen.", "informatik", "Hardware, Zukunft"],
|
||||||
|
13 => ["Die Fibonacci-Folge", "Diese Zahlenreihe beschreibt mathematische Wachstumsmuster, die oft in der Natur vorkommen.", "mathe", "Zahlen, Natur"],
|
||||||
|
14 => ["Thermodynamik", "Die Hauptsätze der Thermodynamik regeln den Energieaustausch und die Entropie in Systemen.", "physik", "Energie, Wärme"],
|
||||||
|
15 => ["Cybersecurity Grundlagen", "Die Absicherung von Netzwerken erfordert Firewalls, Verschlüsselung und regelmäßige Audits.", "informatik", "Sicherheit, Hacker"],
|
||||||
|
16 => ["Kryptographie", "Asymmetrische Verschlüsselungsverfahren sichern heutzutage den gesamten Datenverkehr im Web.", "informatik", "Krypto, Security"],
|
||||||
|
17 => ["Analysis und Ableitungen", "Die Differentialrechnung untersucht die lokalen Änderungsraten von mathematischen Funktionen.", "mathe", "Analysis, Funktionen"],
|
||||||
|
18 => ["Schwarze Löcher", "Diese Regionen im Raum besitzen eine so starke Gravitation, dass selbst Licht nicht entkommt.", "physik", "Astronomie, Kosmos"],
|
||||||
|
19 => ["Git Versionsverwaltung", "Git erlaubt Entwicklern das parallele Arbeiten an Code-Projekten ohne Datenverlust.", "informatik", "Git, DevOps"],
|
||||||
|
20 => ["Künstliche Intelligenz", "Neuronale Netze versuchen das menschliche Gehirn für maschinelles Lernen nachzubilden.", "informatik", "KI, Software"],
|
||||||
|
|
||||||
|
// --- CHEMIE & BIOLOGIE (21-40) ---
|
||||||
|
21 => ["Das Periodensystem", "Die Elemente sind nach ihrer Ordnungszahl und chemischen Eigenschaften geordnet.", "chemie", "Elemente, Moleküle"],
|
||||||
|
22 => ["Photosynthese", "Pflanzen wandeln mithilfe von Sonnenlicht Kohlendioxid und Wasser in Glukose und Sauerstoff um.", "biologie", "Pflanzen, Energie"],
|
||||||
|
23 => ["Aufbau einer Zelle", "Die Zelle ist die kleinste lebende Einheit aller Organismen mit spezialisierten Organellen.", "biologie", "Zellen, Biologie"],
|
||||||
|
24 => ["Säuren und Basen", "Der pH-Wert misst die Konzentration von Wasserstoff-Ionen in einer wässrigen Lösung.", "chemie", "Labor, pH-Wert"],
|
||||||
|
25 => ["Die DNA-Struktur", "Die Doppelhelix enthält den genetischen Bauplan für die Entwicklung aller Lebewesen.", "biologie", "Genetik, Erbgut"],
|
||||||
|
26 => ["Chemische Bindungen", "Kovalente Bindungen entstehen durch das Teilen von Elektronenpaaren zwischen Atomen.", "chemie", "Atome, Bindung"],
|
||||||
|
27 => ["Das Immunsystem", "Weiße Blutkörperchen und Antikörper schützen den menschlichen Körper vor Krankheitserregern.", "biologie", "Gesundheit, Abwehr"],
|
||||||
|
28 => ["Katalysatoren", "Katalysatoren beschleunigen chemische Reaktionen, ohne dabei selbst verbraucht zu werden.", "chemie", "Reaktion, Chemie"],
|
||||||
|
29 => ["Ökosystem Wald", "Das Zusammenspiel von Flora, Fauna und Klima bildet ein hochsensibles ökologisches System.", "biologie", "Natur, Wald"],
|
||||||
|
30 => ["Die Mendelschen Regeln", "Diese Grundgesetze der Vererbung beschreiben, wie Merkmale an Nachkommen weitergegeben werden.", "biologie", "Genetik, Erbung"],
|
||||||
|
31 => ["Zustandsformen der Materie", "Fest, flüssig und gasförmig sind die klassischen Aggregatzustände von Stoffen.", "chemie", "Physik, Materie"],
|
||||||
|
32 => ["Evolutionstheorie", "Charles Darwin begründete die Theorie der natürlichen Auslese und Anpassung von Arten.", "biologie", "Darwin, Evolution"],
|
||||||
|
33 => ["Organische Chemie", "Die Chemie der Kohlenstoffverbindungen bildet die Basis für alles bekannte Leben.", "chemie", "Kohlenstoff, Chemie"],
|
||||||
|
34 => ["Das menschliche Gehirn", "Milliarden von Neuronen kommunizieren über Synapsen, um Reize und Gedanken zu verarbeiten.", "biologie", "Neurologie, Nerven"],
|
||||||
|
35 => ["Der Wasserkreislauf", "Verdunstung, Kondensation und Niederschlag halten das Wasser auf der Erde in Bewegung.", "geographie", "Wasser, Klima"],
|
||||||
|
36 => ["Aggregatzustände von Wasser", "Wasser zeigt ungewöhnliche Eigenschaften wie die Dichteanomalie beim Gefrieren.", "chemie", "Wasser, Eis"],
|
||||||
|
37 => ["Blutkreislauf des Menschen", "Das Herz pumpt sauerstoffreiches Blut durch Arterien in alle Organe des Körpers.", "biologie", "Herz, Medizin"],
|
||||||
|
38 => ["Das Ohmsche Gesetz", "Es beschreibt den direkten Zusammenhang zwischen Spannung, Stromstärke und Widerstand.", "physik", "Strom, Elektronik"],
|
||||||
|
39 => ["Plattentektonik", "Die Bewegung der Kontinentalplatten führt zu Erdbeben, Vulkanismus und Gebirgsbildung.", "geographie", "Erde, Geologie"],
|
||||||
|
40 => ["Proteine und Enzyme", "Enzyme wirken als Biokatalysatoren und steuern fast alle Stoffwechselprozesse.", "biologie", "Biochemie, Enzyme"],
|
||||||
|
|
||||||
|
// --- GESCHICHTE & WIRTSCHAFT (41-60) ---
|
||||||
|
41 => ["Das Römische Reich", "Vom Stadtstaat zum Weltreich prägte Rom die Rechts- und Kulturgeschichte Europas.", "geschichte", "Antike, Rom"],
|
||||||
|
42 => ["Die Französische Revolution", "Freiheit, Gleichheit, Brüderlichkeit beendeten 1789 die absolute Monarchie in Frankreich.", "geschichte", "Europa, Politik"],
|
||||||
|
43 => ["Inflation erklärt", "Inflation bezeichnet die kontinuierliche Geldentwertung und den Kaufkraftverlust.", "wirtschaft", "Geld, Finanzen"],
|
||||||
|
44 => ["Die Industrielle Revolution", "Die Erfindung der Dampfmaschine veränderte die Produktion und die Gesellschaft tiefgreifend.", "geschichte", "Industrie, Arbeit"],
|
||||||
|
45 => ["Angebot und Nachfrage", "Dieses fundamentale Marktgesetz bestimmt den Preis von Gütern in einer freien Wirtschaft.", "wirtschaft", "Markt, Preise"],
|
||||||
|
46 => ["Der Buchdruck", "Johannes Gutenbergs Erfindung revolutionierte die Verbreitung von Wissen im Mittelalter.", "geschichte", "Medien, Wissen"],
|
||||||
|
47 => ["Die Entdeckung Amerikas", "Kolumbus' Seereise im Jahr 1492 leitete das Zeitalter der Kolonialisierung ein.", "geschichte", "Entdeckung, Seefahrt"],
|
||||||
|
48 => ["Kryptowährungen", "Bitcoin nutzt Blockchain-Technologie, um dezentralen digitalen Werttransfer zu erlauben.", "wirtschaft", "Blockchain, Finanzen"],
|
||||||
|
49 => ["Das antike Griechenland", "Die Wiege der Demokratie und Philosophie brachte Denker wie Sokrates und Platon hervor.", "geschichte", "Antike, Philosophie"],
|
||||||
|
50 => ["Globalisierung", "Die weltweite Verflechtung in Wirtschaft, Kultur und Politik bringt Chancen und Risiken.", "wirtschaft", "Weltwirtschaft, Handel"],
|
||||||
|
51 => ["Der Dreißigjährige Krieg", "Ein religiöser und politischer Konflikt verwüstete zwischen 1618 und 1648 Mitteleuropa.", "geschichte", "Krieg, Europa"],
|
||||||
|
52 => ["Die Weimarer Republik", "Die erste deutsche Demokratie scheiterte an wirtschaftlichen und politischen Krisen.", "geschichte", "Deutschland, Weimar"],
|
||||||
|
53 => ["Aktien und Börse", "Unternehmen beschaffen sich Kapital durch die Ausgabe von Anteilen an Investoren.", "wirtschaft", "Aktien, Investieren"],
|
||||||
|
54 => ["Das alte Ägypten", "Pharaonen, Pyramiden und Hieroglyphen zeugen von einer hochentwickelten Hochkultur am Nil.", "geschichte", "Ägypten, Antike"],
|
||||||
|
55 => ["Der Kalte Krieg", "Das Wettrüsten zwischen USA und UdSSR prägte die globale Politik der Nachkriegszeit.", "geschichte", "Ost-West, Politik"],
|
||||||
|
56 => ["Zentralbanken und Leitzins", "Durch Zinsänderungen steuern Notenbanken die Geldmenge und bekämpfen Inflation.", "wirtschaft", "Zinsen, Geldpolitik"],
|
||||||
|
57 => ["Die Seidenstraße", "Das historische Netzwerk von Handelsrouten verband über Jahrhunderte Asien und Europa.", "geschichte", "Handel, Asien"],
|
||||||
|
58 => ["Das Mittelalter", "Ritter, Burgen und das Feudalsystem prägten diese tausendjährige Epoche Europas.", "geschichte", "Mittelalter, Feudalismus"],
|
||||||
|
59 => ["Planwirtschaft vs Marktwirtschaft", "Zentrale staatliche Steuerung steht dem freien Spiel der Marktkräfte gegenüber.", "wirtschaft", "Systeme, Wirtschaft"],
|
||||||
|
60 => ["Die Berliner Mauer", "Ihr Bau 1961 zementierte die Teilung Deutschlands, ihr Fall 1989 beendete sie.", "geschichte", "DDR, Wiedervereinigung"],
|
||||||
|
|
||||||
|
// --- ANWENDUNGEN & WEITERE THEMEN (61-100) ---
|
||||||
|
61 => ["Cloud Computing", "Das Auslagern von Rechenleistung in das Internet spart lokale IT-Infrastruktur ein.", "informatik", "Cloud, Web"],
|
||||||
|
62 => ["Responsive Webdesign", "Moderne Webseiten passen ihr Layout dynamisch an Smartphones und Desktops an.", "informatik", "Design, CSS"],
|
||||||
|
63 => ["Der Treibhauseffekt", "Gase in der Atmosphäre verhindern das Entweichen von Wärme ins Weltall.", "physik", "Klima, Umwelt"],
|
||||||
|
64 => ["Mechanik und Kräfte", "Die Newtonschen Axiome beschreiben, wie Kräfte auf Körper wirken und sie bewegen.", "physik", "Newton, Kraft"],
|
||||||
|
65 => ["Die Mendelschen Gesetze", "Die Vererbung von Genen folgt klaren statistischen Wahrscheinlichkeiten.", "biologie", "Genetik, Erbsen"],
|
||||||
|
66 => ["Lichtgeschwindigkeit", "Im Vakuum bewegt sich Licht mit knapp 300.000 Kilometern pro Sekunde.", "physik", "Licht, Relativität"],
|
||||||
|
67 => ["Die Funktion von APIs", "Programmierschnittstellen erlauben den Datenaustausch zwischen verschiedenen Systemen.", "informatik", "API, Schnittstelle"],
|
||||||
|
68 => ["Der Goldstandard", "Ein historischen Währungssystem, bei dem Geld durch echtes Gold gedeckt war.", "wirtschaft", "Gold, Währung"],
|
||||||
|
69 => ["Der Wiener Kongress", "1815 ordneten die europäischen Mächte die Landkarte nach den Napoleonischen Kriegen neu.", "geschichte", "Europa, Diplomatie"],
|
||||||
|
70 => ["Integrierte Schaltkreise", "Mikrochips enthalten Millionen Transistoren auf kleinstem Raum für Logikschaltungen.", "informatik", "Hardware, Chips"],
|
||||||
|
71 => ["Die Magellan-Expedition", "Die erste erfolgreiche Weltumsegelung bewies praktisch die Kugelgestalt der Erde.", "geschichte", "Seefahrt, Erde"],
|
||||||
|
72 => ["Das Internet der Dinge", "Alltagsgegenstände werden vernetzt, um smarte Automatisierungen zu ermöglichen.", "informatik", "IoT, SmartHome"],
|
||||||
|
73 => ["Halbwertszeit", "Die Zeitspanne, in der sich die Hälfte der instabilen Atome radioaktiv abbaut.", "physik", "Atomphysik, Strahlung"],
|
||||||
|
74 => ["Elektromagnetismus", "Die Verknüpfung von elektrischen Strömen und magnetischen Feldern treibt Motoren an.", "physik", "Strom, Magnet"],
|
||||||
|
75 => ["Das Ökosystem Meer", "Ozeane regulieren das Weltklima und bieten Lebensraum für unzählige Arten.", "biologie", "Meer, Ökologie"],
|
||||||
|
76 => ["Einführung in Docker", "Containerisierung isoliert Anwendungen samt Abhängigkeiten für stabilen Betrieb.", "informatik", "Docker, DevOps"],
|
||||||
|
77 => ["Das Römische Recht", "Viele moderne europäische Gesetzbücher basieren auf antiken römischen Rechtsprinzipien.", "geschichte", "Recht, Gesetz"],
|
||||||
|
78 => ["Verhaltensbiologie", "Untersuchung von angeborenen und erlernten Verhaltensweisen bei Mensch und Tier.", "biologie", "Verhalten, Tiere"],
|
||||||
|
79 => ["Verschlüsselung im Alltag", "HTTPS schützt Passwörter und Zahlungsdaten beim Surfen vor dem Mitlesen.", "informatik", "Web, HTTPS"],
|
||||||
|
80 => ["Die Magna Carta", "1215 schränkte dieses Dokument die absolute Macht des englischen Königs ein.", "geschichte", "England, Verfassung"],
|
||||||
|
81 => ["Marktversagen", "Wenn der freie Markt Ressourcen unvollständig verteilt, muss der Staat eingreifen.", "wirtschaft", "Markt, Staat"],
|
||||||
|
82 => ["Optische Linsen", "Konvexe und konkave Linsen brechen Licht für Brillen, Mikroskope und Kameras.", "physik", "Optik, Licht"],
|
||||||
|
83 => ["Die Entstehung der Erde", "Vor rund 4,5 Milliarden Jahren ballte sich kosmischer Staub zu unserem Planeten.", "geographie", "Erde, Kosmos"],
|
||||||
|
84 => ["Grundlagen von JavaScript", "Diese Skriptsprache macht statische Webseiten interaktiv und dynamisch nutzbar.", "informatik", "JS, Webentwicklung"],
|
||||||
|
85 => ["Die industrielle Landwirtschaft", "Moderne Techniken sichern Welternährung, belasten jedoch oft die Umwelt.", "biologie", "Landwirtschaft, Umwelt"],
|
||||||
|
86 => ["Das Schwarze Jahr 1929", "Der New Yorker Börsencrash löste die verheerende Weltwirtschaftskrise aus.", "geschichte", "Krise, Finanzen"],
|
||||||
|
87 => ["Die Evolution des Menschen", "Der Stammbaum des Homo Sapiens entwickelte sich über Millionen Jahre in Afrika.", "biologie", "Mensch, Evolution"],
|
||||||
|
88 => ["Einführung in Linux", "Das Open-Source-Betriebssystem bildet das Rückgrat moderner Server-Infrastrukturen.", "informatik", "Linux, OS"],
|
||||||
|
89 => ["Der Urknall", "Die Urknalltheorie beschreibt den Beginn des Universums aus einer Singularität.", "physik", "Astronomie, Urknall"],
|
||||||
|
90 => ["Das Periodensystem der Elemente", "Dmitri Mendelejew ordnete Elemente logisch nach ihren Atommassen.", "chemie", "Periodensystem, Chemie"],
|
||||||
|
91 => ["Die Hanse", "Ein mächtiger mittelalterlicher Bund von Kaufleuten dominierte den Nordseehandel.", "geschichte", "Handel, Mittelalter"],
|
||||||
|
92 => ["Wirtschaftswachstum", "Die Steigerung des Bruttoinlandsprodukts gilt oft als Indikator für Wohlstand.", "wirtschaft", "BIP, Finanzen"],
|
||||||
|
93 => ["Neuronale Netze", "Diese Strukturen lernen durch mathematische Gewichtung aus riesigen Datenmengen.", "informatik", "KI, Mathematik"],
|
||||||
|
94 => ["Der Erste Weltkrieg", "Der globale Konflikt von 1914 bis 1918 zerstörte das alte europäische Machtgefüge.", "geschichte", "Europa, Krieg"],
|
||||||
|
95 => ["Das Gehirn und Hormone", "Botenstoffe steuern Gefühle, Schlafzyklen und Reaktionen des Körpers.", "biologie", "Medizin, Hormone"],
|
||||||
|
96 => ["SQL Joins erklärt", "Joins verknüpfen Daten aus mehreren Tabellen über gemeinsame Schlüssel.", "informatik", "SQL, Datenbanken"],
|
||||||
|
97 => ["Wellen-Teilchen-Dualismus", "Quantenobjekte zeigen je nach Messaufbau Eigenschaften von Wellen oder Teilchen.", "physik", "Quanten, Licht"],
|
||||||
|
98 => ["Der Absolutismus", "Der Sonnenkönig Ludwig XIV. verkörperte die unbeschränkte Herrschaft des Monarchen.", "geschichte", "Frankreich, Monarchie"],
|
||||||
|
99 => ["Die Funktion von Routern", "Netzwerkgeräte leiten Datenpakete über IP-Adressen an den richtigen Empfänger.", "informatik", "Netzwerk, Internet"],
|
||||||
|
100 => ["Die Entstehung des Geldes", "Vom Tauschhandel über Naturalgeld bis hin zu modernen digitalen Fiat-Währungen.", "wirtschaft", "Geld, Geschichte"]
|
||||||
|
|
||||||
|
];
|
||||||
|
$articleInsertStmt = $db->prepare("
|
||||||
|
INSERT INTO articles (title, content, author, category, tags)
|
||||||
|
VALUES (:title, :content, :author, :category, :tags);");
|
||||||
|
|
||||||
|
foreach ($dummyArticles as $article) {
|
||||||
|
// Bestimmt per Zufall einen Autor aus dem Pool der gültigen E-Mails
|
||||||
|
$randomAuthor = $availableEmails[array_rand($availableEmails)];
|
||||||
|
|
||||||
|
$articleInsertStmt->execute([
|
||||||
|
':title' => $article[0],
|
||||||
|
':content' => $article[1],
|
||||||
|
':author' => $randomAuthor,
|
||||||
|
':category' => $article[2],
|
||||||
|
':tags' => $article[3]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
require_once 'DatabaseInitializer.php';
|
||||||
require_once "UserManagerDAO.php";
|
require_once "UserManagerDAO.php";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -11,6 +11,7 @@ require_once "UserManagerDAO.php";
|
|||||||
class DatabaseUserManager implements UserManagerDAO {
|
class DatabaseUserManager implements UserManagerDAO {
|
||||||
|
|
||||||
private static $instance = null;
|
private static $instance = null;
|
||||||
|
private $dbPath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Konstruktor.
|
* Konstruktor.
|
||||||
@@ -22,23 +23,8 @@ class DatabaseUserManager implements UserManagerDAO {
|
|||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
try {
|
$this->dbPath = __DIR__ . '/../../db/eduforgeDB.db';
|
||||||
$db = $this->getConnection();
|
DatabaseInitializer::initialize($this->dbPath);
|
||||||
|
|
||||||
$db->exec("
|
|
||||||
CREATE TABLE IF NOT EXISTS users (
|
|
||||||
email TEXT PRIMARY KEY,
|
|
||||||
vorname TEXT NOT NULL,
|
|
||||||
nachname TEXT NOT NULL,
|
|
||||||
password TEXT NOT NULL
|
|
||||||
);
|
|
||||||
");
|
|
||||||
|
|
||||||
unset($db);
|
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
|
||||||
throw new RuntimeException("Benutzerdatenbank konnte nicht erstellt werden.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,15 +37,12 @@ class DatabaseUserManager implements UserManagerDAO {
|
|||||||
private function getConnection()
|
private function getConnection()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$dsn = 'sqlite:' . __DIR__ . '/../../db/users.db';
|
$db = new PDO('sqlite:' . $this->dbPath, null, null);
|
||||||
|
|
||||||
$db = new PDO($dsn, null, null);
|
|
||||||
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
$db->exec('PRAGMA foreign_keys = ON;');
|
||||||
return $db;
|
return $db;
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
throw new RuntimeException("Verbindung zur Benutzerdatenbank fehlgeschlagen.");
|
throw new RuntimeException("internal_error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,8 @@ class LocalArticleManager implements ArticleManagerDAO {
|
|||||||
"author" => $author,
|
"author" => $author,
|
||||||
"category" => $category,
|
"category" => $category,
|
||||||
"tags" => $tags,
|
"tags" => $tags,
|
||||||
"creationDate" => date("Y-m-d H:i:s")
|
"creationDate" => date("Y-m-d H:i:s"),
|
||||||
|
"likes" => []
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->saveArticle($articles);
|
$this->saveArticle($articles);
|
||||||
@@ -92,7 +93,8 @@ class LocalArticleManager implements ArticleManagerDAO {
|
|||||||
"author" => $author,
|
"author" => $author,
|
||||||
"category" => $article->getCategory(),
|
"category" => $article->getCategory(),
|
||||||
"tags" => $article->getTags(),
|
"tags" => $article->getTags(),
|
||||||
"creationDate" => $article->getCreationDate()
|
"creationDate" => $article->getCreationDate(),
|
||||||
|
"likes" => $storedArticle['likes'] ?? []
|
||||||
];
|
];
|
||||||
$updated = true;
|
$updated = true;
|
||||||
break;
|
break;
|
||||||
@@ -142,7 +144,17 @@ class LocalArticleManager implements ArticleManagerDAO {
|
|||||||
|
|
||||||
foreach ($articles as $article) {
|
foreach ($articles as $article) {
|
||||||
if (isset($article['id']) && $article['id'] == $id) {
|
if (isset($article['id']) && $article['id'] == $id) {
|
||||||
return new Article(intval($article['id']), $article['title'], $article['content'], $article['author'], $article['category'], $article['tags'], $article['creationDate']);
|
$likes = isset($article['likes']) && is_array($article['likes']) ? $article['likes'] : [];
|
||||||
|
return new Article(
|
||||||
|
intval($article['id']),
|
||||||
|
$article['title'],
|
||||||
|
$article['content'],
|
||||||
|
$article['author'],
|
||||||
|
$article['category'],
|
||||||
|
$article['tags'],
|
||||||
|
$article['creationDate'],
|
||||||
|
$likes
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,6 +180,7 @@ class LocalArticleManager implements ArticleManagerDAO {
|
|||||||
|
|
||||||
foreach ($articles as $article) {
|
foreach ($articles as $article) {
|
||||||
if (isset($article['author']) && $article['author'] == $author) {
|
if (isset($article['author']) && $article['author'] == $author) {
|
||||||
|
$likes = isset($article['likes']) && is_array($article['likes']) ? $article['likes'] : [];
|
||||||
$filteredArticles[] = new Article(
|
$filteredArticles[] = new Article(
|
||||||
intval($article['id']),
|
intval($article['id']),
|
||||||
$article['title'],
|
$article['title'],
|
||||||
@@ -175,7 +188,8 @@ class LocalArticleManager implements ArticleManagerDAO {
|
|||||||
$article['author'],
|
$article['author'],
|
||||||
$article['category'],
|
$article['category'],
|
||||||
$article['tags'],
|
$article['tags'],
|
||||||
$article['creationDate']
|
$article['creationDate'],
|
||||||
|
$likes
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,6 +215,7 @@ class LocalArticleManager implements ArticleManagerDAO {
|
|||||||
if (($cleanKeyword !== '' && strpos($title, $cleanKeyword) !== false) ||
|
if (($cleanKeyword !== '' && strpos($title, $cleanKeyword) !== false) ||
|
||||||
($cleanKeyword !== '' && strpos($content, $cleanKeyword) !== false)) {
|
($cleanKeyword !== '' && strpos($content, $cleanKeyword) !== false)) {
|
||||||
|
|
||||||
|
$likes = isset($article['likes']) && is_array($article['likes']) ? $article['likes'] : [];
|
||||||
$filteredArticles[] = new Article(
|
$filteredArticles[] = new Article(
|
||||||
intval($article['id'] ?? 0),
|
intval($article['id'] ?? 0),
|
||||||
$article['title'] ?? '',
|
$article['title'] ?? '',
|
||||||
@@ -208,7 +223,8 @@ class LocalArticleManager implements ArticleManagerDAO {
|
|||||||
$article['author'] ?? '',
|
$article['author'] ?? '',
|
||||||
$article['category'] ?? '',
|
$article['category'] ?? '',
|
||||||
$article['tags'] ?? '',
|
$article['tags'] ?? '',
|
||||||
$article['creationDate'] ?? ''
|
$article['creationDate'] ?? '',
|
||||||
|
$likes
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -223,6 +239,7 @@ class LocalArticleManager implements ArticleManagerDAO {
|
|||||||
|
|
||||||
foreach ($articles as $article) {
|
foreach ($articles as $article) {
|
||||||
if (isset($article['category']) && $article['category'] == $category) {
|
if (isset($article['category']) && $article['category'] == $category) {
|
||||||
|
$likes = isset($article['likes']) && is_array($article['likes']) ? $article['likes'] : [];
|
||||||
$filteredArticles[] = new Article(
|
$filteredArticles[] = new Article(
|
||||||
intval($article['id']),
|
intval($article['id']),
|
||||||
$article['title'],
|
$article['title'],
|
||||||
@@ -230,12 +247,53 @@ class LocalArticleManager implements ArticleManagerDAO {
|
|||||||
$article['author'],
|
$article['author'],
|
||||||
$article['category'],
|
$article['category'],
|
||||||
$article['tags'],
|
$article['tags'],
|
||||||
$article['creationDate']
|
$article['creationDate'],
|
||||||
|
$likes
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $filteredArticles;
|
return $filteredArticles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function toggleLike(int $articleId, string $userId): bool
|
||||||
|
{
|
||||||
|
$articles = $this->getAllArticles();
|
||||||
|
$articleFound = false;
|
||||||
|
$isLikedNow = false;
|
||||||
|
|
||||||
|
foreach ($articles as $index => $article) {
|
||||||
|
if (isset($article['id']) && $article['id'] == $articleId) {
|
||||||
|
$articleFound = true;
|
||||||
|
|
||||||
|
// Likes-Array initialisieren, falls nicht vorhanden
|
||||||
|
if (!isset($articles[$index]['likes']) || !is_array($articles[$index]['likes'])) {
|
||||||
|
$articles[$index]['likes'] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$likeIndex = array_search($userId, $articles[$index]['likes']);
|
||||||
|
|
||||||
|
if ($likeIndex !== false) {
|
||||||
|
// Bereits geliked -> Unlike
|
||||||
|
unset($articles[$index]['likes'][$likeIndex]);
|
||||||
|
// Array-Keys neu indizieren, damit JSON sauber bleibt
|
||||||
|
$articles[$index]['likes'] = array_values($articles[$index]['likes']);
|
||||||
|
$isLikedNow = false;
|
||||||
|
} else {
|
||||||
|
// Noch nicht geliked -> Like (User-ID hinzufügen)
|
||||||
|
$articles[$index]['likes'][] = $userId;
|
||||||
|
$isLikedNow = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$articleFound) {
|
||||||
|
throw new NotFoundException("missing_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->saveArticle($articles);
|
||||||
|
return $isLikedNow;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -12,38 +12,8 @@ require_once "DatabaseUserManager.php";
|
|||||||
class UserManager {
|
class UserManager {
|
||||||
|
|
||||||
public static function getInstance() {
|
public static function getInstance() {
|
||||||
$userManager = DatabaseUserManager::getInstance();
|
|
||||||
|
|
||||||
/*
|
return DatabaseUserManager::getInstance();
|
||||||
* Dummy-User anlegen, falls sie noch nicht existieren.
|
|
||||||
* Passwort für alle User: test12345
|
|
||||||
*/
|
|
||||||
$dummyUsers = [
|
|
||||||
['email' => 'max.mustermann@web.de', 'vorname' => 'Max', 'nachname' => 'Mustermann'],
|
|
||||||
['email' => 'erika.mustermann@web.de', 'vorname' => 'Erika', 'nachname' => 'Mustermann'],
|
|
||||||
['email' => 'john.doe@gmail.com', 'vorname' => 'John', 'nachname' => 'Doe'],
|
|
||||||
['email' => 'jane.doe@gmail.com', 'vorname' => 'Jane', 'nachname' => 'Doe'],
|
|
||||||
['email' => 'anna.schmidt@gmx.de', 'vorname' => 'Anna', 'nachname' => 'Schmidt'],
|
|
||||||
['email' => 'thomas.mueller@gmx.de', 'vorname' => 'Thomas', 'nachname' => 'Müller'],
|
|
||||||
['email' => 'sabine.fischer@outlook.com', 'vorname' => 'Sabine', 'nachname' => 'Fischer'],
|
|
||||||
['email' => 'michael.weber@outlook.com', 'vorname' => 'Michael', 'nachname' => 'Weber'],
|
|
||||||
['email' => 'julia.wagner@t-online.de', 'vorname' => 'Julia', 'nachname' => 'Wagner'],
|
|
||||||
['email' => 'stefan.becker@t-online.de', 'vorname' => 'Stefan', 'nachname' => 'Becker']
|
|
||||||
];
|
|
||||||
|
|
||||||
$passwordHash = password_hash("test12345", PASSWORD_DEFAULT);
|
|
||||||
|
|
||||||
foreach ($dummyUsers as $user) {
|
|
||||||
if ($userManager->findUser($user['email']) == null) {
|
|
||||||
$userManager->addUser(
|
|
||||||
$user['email'],
|
|
||||||
$user['vorname'],
|
|
||||||
$user['nachname'],
|
|
||||||
$passwordHash
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $userManager;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user