diff --git a/content/createArticle.php b/content/createArticle.php index 8fa550d..41f1ca8 100644 --- a/content/createArticle.php +++ b/content/createArticle.php @@ -10,7 +10,7 @@ session_start();

- Es ist ein Fehler beim Speichern aufgetreten. Bitte versuche es erneut. + Es ist ein interner Fehler beim Speichern aufgetreten. Bitte versuche es erneut.

@@ -18,8 +18,40 @@ session_start(); Jeder Beitrag muss einen Titel, Kategorie und Inhalt besitzen.

- - + +

+ Der Titel enthält ungültige Zeichen oder erfüllt die Länge von 5-120 Zeichen nicht. +

+ + +

+ Der Text erlaubt eine Länge von 10 bis maximal 7.000 Zeichen (ca. 1.000 Wörter). +

+ + +

+ Die ausgewählte Kategorie ist ungültig. +

+ + +

+ Ungültige Schlagworte gefunden. Erlaubt sind nur Buchstaben, Zahlen, Leerzeichen und Bindestriche (2-50 Zeichen). +

+ + +

+ Bei der Validierung deiner Daten ist ein Fehler aufgetreten. Bitte versuche es erneut. +

+ + + +
@@ -76,7 +108,9 @@ session_start(); diff --git a/content/profile.php b/content/profile.php index 1d9b970..0cc0ae0 100644 --- a/content/profile.php +++ b/content/profile.php @@ -1,45 +1,101 @@ + +
-
+
+ +
+
+ + "> -

Mein Profil

+ + "> - - - "> + + +
+
- - "> + - - - +

-
+ +
- - -

- - + +
+

Meine Beiträge

+
+ +

+ Es ist ein interner Fehler aufgetreten. Bitte versuche es erneut. +

+ 0): ?> + + +
+ +

getTitle()); ?>

+ getTags(); + if (isset($tags) && !empty($tags)): ?> +
+
Tags:
+
+ + + +
+
+ + Bearbeiten +
+ + +

Du hast noch keine Beiträge erstellt.

+ + + +
+
\ No newline at end of file diff --git a/content/showArticle.php b/content/showArticle.php index b069b88..4457dcc 100644 --- a/content/showArticle.php +++ b/content/showArticle.php @@ -1,21 +1,44 @@ + - -
+ +

+ Es ist ein interner Fehler aufgetreten. Bitte versuche es erneut. +

+ + +

+ Es ist ein Fehler aufgetreten. Die ID konnte nicht ausgelesen werden. Bitte versuche es erneut. +

+ + + +

+ Jeder Beitrag muss einen Titel, Kategorie und Inhalt besitzen. +

+ + +

+ Dein Beitrag wurde erfolgreich bearbeitet! +

+ + +
-

@@ -28,7 +51,7 @@ include_once 'php/controller/showArticle-controller.php';
- +
@@ -36,7 +59,7 @@ include_once 'php/controller/showArticle-controller.php';
- +
Tags:
diff --git a/content/updateArticle.php b/content/updateArticle.php new file mode 100644 index 0000000..ac86814 --- /dev/null +++ b/content/updateArticle.php @@ -0,0 +1,142 @@ + + +
" id="editor-form" class="article-editor-scope.editor-container article-editor-scope editor-container"> + +
+ +

+ Es ist ein interner Fehler beim Speichern aufgetreten. Bitte versuche es erneut. +

+ + +

+ Es ist ein Fehler aufgetreten. Die ID konnte nicht ausgelesen werden. Bitte versuche es erneut. +

+ + +

+ Jeder Beitrag muss einen Titel, Kategorie und Inhalt besitzen. +

+ + +

+ Der Titel enthält ungültige Zeichen oder erfüllt die Länge von 5-120 Zeichen nicht. +

+ + +

+ Der Text erlaubt eine Länge von 10 bis maximal 7.000 Zeichen (ca. 1.000 Wörter). +

+ + +

+ Die ausgewählte Kategorie ist ungültig. +

+ + +

+ Ungültige Schlagworte gefunden. Erlaubt sind nur Buchstaben, Zahlen, Leerzeichen und Bindestriche (2-20 Zeichen). +

+ + +

+ Bei der Validierung deiner Daten ist ein Fehler aufgetreten. Bitte versuche es erneut. +

+ + + + +
+ + + + +
diff --git a/css/main.css b/css/main.css index b0634b1..b448a22 100644 --- a/css/main.css +++ b/css/main.css @@ -212,3 +212,13 @@ a, button, input, select, textarea, label, main{ border-radius: 10px; box-shadow: 0 6px 20px rgba(0,0,0,0.1); } + +.form-container { + flex: 1 1 450px; + padding: 30px; + background-color: white; + border: 1px solid #dbe3ec; + border-radius: 10px; + box-shadow: 0 6px 20px rgba(0,0,0,0.1); + box-sizing: border-box; +} \ No newline at end of file diff --git a/css/profile.css b/css/profile.css new file mode 100644 index 0000000..dca1cef --- /dev/null +++ b/css/profile.css @@ -0,0 +1,89 @@ +/* +CSS für die Profilseite + */ + +/* Roter Button für Account löschen */ +.delete-account-button { + background-color: #dc2626; + margin-bottom: 0; +} + +.delete-account-button:hover { + background-color: #b91c1c; +} + +/* Beitragsliste Styling */ +.section-title { + margin-top: 0; + margin-bottom: 25px; + font-size: 1.5rem; + color: #1f2937; + border-bottom: 2px solid #eef2f7; + padding-bottom: 10px; +} + +.articles-list { + display: flex; + flex-direction: column; + gap: 20px; +} + +.article-item { + padding: 15px; + border: 1px solid #e5e7eb; + border-radius: 8px; + background-color: #f9fafb; + position: relative; +} + +.article-meta { + display: flex; + justify-content: space-between; + font-size: 0.85rem; + color: #6b7280; + margin-bottom: 8px; +} + +.article-category { + font-weight: bold; + color: #2563eb; +} + +.article-title { + margin: 0 0 10px 0; + font-size: 1.2rem; + color: #1f2937; +} + +.article-tags { + display: flex; + flex-wrap: wrap; + gap: 6px; + margin-bottom: 15px; +} + +.tag { + font-size: 0.75rem; + background-color: #e5e7eb; + color: #374151; + padding: 3px 8px; + border-radius: 4px; +} + +/* Bearbeiten-Button als Link deklariert */ +.edit-link-button { + display: inline-block; + text-decoration: none; + font-size: 0.9rem; + font-weight: bold; + color: #2563eb; + border: 1px solid #2563eb; + padding: 6px 12px; + border-radius: 6px; + transition: background-color 0.2s, color 0.2s; +} + +.edit-link-button:hover { + background-color: #2563eb; + color: white; +} \ No newline at end of file diff --git a/css/search-results.css b/css/search-results.css index f2fc36f..4fc5d97 100644 --- a/css/search-results.css +++ b/css/search-results.css @@ -69,12 +69,12 @@ CSS für die Suchergebnis-Seite .s-res-filter-option input[type="radio"] { margin: 0; - accent-color: #3182ce; /* Moderne Färbung des Radio-Buttons */ + accent-color: #3182ce; } /* --- HAUPTINHALT (ERGEBNISSE) --- */ .s-res-main-content { - min-width: 0; /* Verhindert das Ausbrechen von Flex-Elementen */ + min-width: 0; } .s-res-header { @@ -164,7 +164,7 @@ CSS für die Suchergebnis-Seite transform: translateX(3px); } -/* --- ERGEBNISSE PRO SEITE & PAGINIERUNG --- */ +/* ERGEBNISSE PRO SEITE & PAGINIERUNG */ .s-res-pagination-footer { display: flex; justify-content: space-between; @@ -247,7 +247,7 @@ CSS für die Suchergebnis-Seite cursor: not-allowed; } -/* --- RESPONSIVE DESIGN (MOBILGERÄTE) --- */ +/* Responsive Anpassungen unter 760px (für z.B. Smartphones) */ @media (max-width: 768px) { .s-res-layout-grid { grid-template-columns: 1fr; /* Stapelt Seitenleiste und Inhalt untereinander */ diff --git a/index.php b/index.php index c6743e2..258a29e 100644 --- a/index.php +++ b/index.php @@ -1,3 +1,4 @@ + + + + + + EduForge - + diff --git a/php/controller/createArticle-controller.php b/php/controller/createArticle-controller.php index 375d136..d4c1cec 100644 --- a/php/controller/createArticle-controller.php +++ b/php/controller/createArticle-controller.php @@ -2,30 +2,84 @@ session_start(); require_once '../model/LocalArticleManager.php'; require_once '../model/ArticleManager.php'; +require_once '../validator/article-validator.php'; if ($_SERVER["REQUEST_METHOD"] === "POST") { + $_SESSION["old_title"] = $_POST["title"] ?? ''; + $_SESSION["old_content"] = $_POST["content"] ?? ''; + $_SESSION["old_category"] = $_POST["category"] ?? ''; + $_SESSION["old_tags"] = $_POST["tags"] ?? ''; + if(!isset($_POST["title"]) ||!isset($_POST["content"]) || !isset($_POST["category"])){ $_SESSION["message"] = "missing_parameters"; header("location: ../../index.php?pfad=createArticle"); + exit(); } else { - $title = $_POST["title"]; $content = $_POST["content"]; - $category = $_POST["category"]; $author = "max.mustermann"; // TODO: später aus Session den angemeldeten Nutzer beziehen. - $tags = $_POST["tags"]; + $category = $_POST["category"]; + $tags = $_POST['tags'] ?? ''; + // -------------------------------- Validierung der Daten: ------------------------- + if (!articleAuthorValidator($author)) { + $_SESSION["message"] = "author_not_valid"; + header("location: ../../index.php?pfad=createArticle"); + exit(); + } + + if (!articleTitleValidator($title)) { + $_SESSION["message"] = "invalid_title"; + header("location: ../../index.php?pfad=createArticle"); + exit(); + } + + if (!articleContentValidator($content)) { + $_SESSION["message"] = "invalid_content"; + header("location: ../../index.php?pfad=createArticle"); + exit(); + } + + if (!articleCategoryValidator($category)) { + $_SESSION["message"] = "invalid_category"; + header("location: ../../index.php?pfad=createArticle"); + exit(); + } + + if (!articleTagValidator($tags)) { + $_SESSION["message"] = "invalid_tags"; + header("location: ../../index.php?pfad=createArticle"); + exit(); + } else { + $cleanedTags = []; + $rawTags = explode(',', $tags); + foreach ($rawTags as $rawTag) { + // Leerzeichen am Anfang/Ende des einzelnen Tags entfernen: + $tag = trim($rawTag); + $cleanedTags[] = $tag; + } + // Duplikate entfernen: + $cleanedTags = array_unique($cleanedTags); + $cleanedTags = implode(',', $cleanedTags); + } + // ----------------- Übertragung der validierten Daten in ArticleManager: --------------------------- try { $articleManager = ArticleManager::getInstance(); - $articleManager->addArticle($title, $content, $author, $category, $tags); + $articleManager->addArticle($title, $content, $author, $category, $cleanedTags); + + // Formulardaten nach erfolgreichem Erstellen aus der Session löschen + unset($_SESSION["old_title"], $_SESSION["old_content"], $_SESSION["old_category"], $_SESSION["old_tags"]); + } catch (Exception $e){ $_SESSION["message"] = "internal_error"; + header("location: ../../index.php?pfad=createArticle"); + exit(); } + $_SESSION["message"] = "new_article"; // Weiterleitung zur Homepage header("location: ../../index.php"); exit(); - } } diff --git a/php/controller/profileArticles-controller.php b/php/controller/profileArticles-controller.php new file mode 100644 index 0000000..11e49d3 --- /dev/null +++ b/php/controller/profileArticles-controller.php @@ -0,0 +1,21 @@ +getArticlesByAuthor($author); + if(!isset($userArticles)) { + $_SESSION["message"] = "user_has_no_articles"; + } +} catch (Exception $e) { + $_SESSION["message"] = "internal_error"; +} + +?> \ No newline at end of file diff --git a/php/controller/showArticle-controller.php b/php/controller/showArticle-controller.php index d9be3f5..38bb3f2 100644 --- a/php/controller/showArticle-controller.php +++ b/php/controller/showArticle-controller.php @@ -3,10 +3,11 @@ session_start(); require_once 'php/model/Article.php'; require_once 'php/model/ArticleManager.php'; -if (isset($_GET["id"])){ +if (isset($_GET["id"]) && !empty($_GET["id"])){ try { + $id = $_GET["id"]; $articleManager = ArticleManager::getInstance(); - $article = $articleManager->getArticle($_GET["id"]); + $article = $articleManager->getArticle($id); if($article != null){ $title = $article->getTitle(); $content = $article->getContent(); @@ -14,15 +15,15 @@ if (isset($_GET["id"])){ $author = $article->getAuthor(); $tags = $article->getTags(); }else{ - $_SESSION["message"] = "article_not_found"; - echo "article_not_found"; + //header("location: index.php?pfad=404"); + include_once "content/404.php"; + exit(); } } catch (Exception $e){ $_SESSION["message"] = "internal_error"; - echo "Fehler aufgetreten: " . $e->getMessage(); + exit(); } }else{ - $_SESSION["message"] = "article_not_found"; - echo "article_not_found"; + $_SESSION["message"] = "missing_id"; } ?> \ No newline at end of file diff --git a/php/controller/updateArticle-controller.php b/php/controller/updateArticle-controller.php new file mode 100644 index 0000000..6ff32ec --- /dev/null +++ b/php/controller/updateArticle-controller.php @@ -0,0 +1,95 @@ +getArticle($id); + $article->setTitle($title); + $article->setContent($content); + $article->setCategory($category); + $article->setTags($cleanedTags); + $articleManager->updateArticle($id ,$article, $author); + } catch (Exception $e){ + $_SESSION["message"] = "internal_error"; + header("location: ../../index.php?pfad=updateArticle"); + exit(); + } + $_SESSION["message"] = "article_updated"; + // Weiterleitung zur Homepage + header("location: ../../index.php?pfad=showArticle&id=$id"); + } +} + +?> \ No newline at end of file diff --git a/php/model/Article.php b/php/model/Article.php index ebb370e..9ffd701 100644 --- a/php/model/Article.php +++ b/php/model/Article.php @@ -1,7 +1,7 @@ category = $category; + } + + /** + * Gibt die Schlagworte eines Beitrags zurück. * @return string */ public function getTags(): string @@ -123,7 +133,7 @@ class Article } /** - * Setzt die Schlagworte eines Artikels. + * Setzt die Schlagworte eines Beitrags. * @param string $tags */ public function setTags(string $tags) diff --git a/php/model/ArticleManagerDAO.php b/php/model/ArticleManagerDAO.php index 95b04cc..92bdfa0 100644 --- a/php/model/ArticleManagerDAO.php +++ b/php/model/ArticleManagerDAO.php @@ -21,26 +21,24 @@ interface ArticleManagerDAO public function addArticle($title, $content, $author, $category, $tags); /** - * Ein angemeldeter Nutzer bearbeitet einen Beitrag. - * $id ID des Beitrags - * $title Titel des Beitrags - * $content Der Inhalt des Beitrags - * $author dem Author des des Beitrags (NID oder email) + * Ändert den gespeicherten Beitrag eines übergebenen Beitrags und eines Autors. + * Es wird geprüft, ob der zu änderne Beitrag existiert und ob der übergebene Autor der Autor des originalen + * Beitrages ist. + * @param $id + * @param $article + * @param $author + * @return void * - * Mögliche Exceptions: - * TODO Fehlerbeschreibung hinzufügen + * TODO: Fehlerbeschreibung hinzufügen */ - public function updateArticle($id, $title, $content, $author); + public function updateArticle($id, $article, $author); - /* - * Ein angemeldeter Nutzer löscht einen seiner Beiträge. - * $id ID des Beitrags - * $title Titel des Beitrags - * $content Der Inhalt des Beitrags - * $author dem Author des des Beitrags (NID oder email) + /** + * Löscht einen Beitrag aus übergebener ID. + * @param $id + * @return void * - * Mögliche Exceptions: - * TODO Fehlerbeschreibung hinzufügen + * TODO: Fehlerbeschreibung hinzufügen */ public function deleteArticle($id); @@ -62,6 +60,12 @@ interface ArticleManagerDAO */ public function getAllArticles(); + /** + * Gibt alle Beiträge eines Nutzer mit einer gegebenen ID aus. + * @param $author + * @return Article[] + */ + public function getArticlesByAuthor($author); } ?> \ No newline at end of file diff --git a/php/model/LocalArticleManager.php b/php/model/LocalArticleManager.php index b3e84cd..7e795f0 100644 --- a/php/model/LocalArticleManager.php +++ b/php/model/LocalArticleManager.php @@ -62,14 +62,65 @@ class LocalArticleManager implements ArticleManagerDAO { $this->saveArticle($articles); } - public function updateArticle($id, $title, $content, $author) + public function updateArticle($id, $article, $author) { - // TODO: Implement updateArticle() method. + if (empty($article)) { + // TODO: Implement Exception. + return; + } + + // Berechtigungsprüfung: + if ($article->getAuthor() !== $author) { + // TODO: Implement Exception. + return; + } + + // Beitrag aktualisieren: + $articles = $this->getAllArticles(); + $updated = false; + + foreach ($articles as $index => $storedArticle) { + if (isset($storedArticle['id']) && $storedArticle['id'] == $id) { + $articles[$index] = [ + "id" => $id, + "title" => $article->getTitle(), + "content" => $article->getContent(), + "author" => $author, + "category" => $article->getCategory(), + "tags" => $article->getTags(), + "creationDate" => $article->getCreationDate() + ]; + $updated = true; + break; + }else{ + // TODO: Implement Exception. + return; + } + } + + // Nur speichern, wenn Beitrag geändert wurde: + if ($updated) { + $this->saveArticle($articles); + } } public function deleteArticle($id) { - // TODO: Implement deleteArticle() method. + $articles = $this->getAllArticles(); + $articleFound = false; + + foreach ($articles as $index => $article) { + if (isset($article['id']) && $article['id'] == $id) { + unset($articles[$index]); + $articleFound = true; + break; // Schleife abbrechen, da die ID eindeutig ist + } + } + + if ($articleFound) { + // array_values stellt sicher, dass die Array-Keys wieder fortlaufend bei 0 beginnen + $this->saveArticle(array_values($articles)); + } } public function getArticle($id) @@ -97,5 +148,25 @@ class LocalArticleManager implements ArticleManagerDAO { return is_array($articles) ? $articles : []; } + public function getArticlesByAuthor($author) + { + $articles = $this->getAllArticles(); + $filteredArticles = []; + + foreach ($articles as $article) { + if (isset($article['author']) && $article['author'] == $author) { + $filteredArticles[] = new Article( + intval($article['id']), + $article['title'], + $article['content'], + $article['author'], + $article['category'], + $article['tags'], + $article['creationDate'] + ); + } + } + return $filteredArticles; + } } ?> \ No newline at end of file diff --git a/php/validator/article-validator.php b/php/validator/article-validator.php new file mode 100644 index 0000000..02c4f94 --- /dev/null +++ b/php/validator/article-validator.php @@ -0,0 +1,107 @@ += 10) { + return true; + }else{ + return false; + } +} + +/** + * Prüft, ob die Kategorie eine erlaubt Kategorie ist. + * @param $category + * @return bool + */ +function articleCategoryValidator($category) +{ + $allowedCategories = [ + 'deutsch', 'englisch', 'franzoesisch', 'latein', 'literatur', + 'mathe', 'biologie', 'chemie', 'physik', 'informatik', 'astronomie', + 'geschichte', 'erdkunde', 'sozialkunde', 'wirtschaft', 'religion', + 'ethik', 'philosophie', 'psychologie', 'kunst', 'musik', 'theater', + 'technik', 'werken', 'hauswirtschaft', 'sport' + ]; + if (in_array($category, $allowedCategories, true)) { + return true; + } else { + return false; + } +} + +/** + * Prüft, ob die Tags die folgenden Bedingungen erfüllen: + * Buchstaben von a-z; A-Z + * Zahlen von 0-9 + * Umlaute äöüÄÖÜß + * Satzeichen - + * 2-50 Zeichen + * @param $tags + * @return bool + */ +function articleTagValidator($tags) +{ + if (!isset($tags)) { + $tags = ''; + } + + $rawTags = explode(',', $tags); + + foreach ($rawTags as $rawTag) { + // Leerzeichen am Anfang/Ende des einzelnen Tags entfernen: + $tag = trim($rawTag); + + // leere Elemente überspringen: + if ($tag === '') { + continue; + } + + // Tag mit Regex prüfen: + $tagPattern = '/^[a-zA-Z0-9äöüÄÖÜß\s-]{2,50}$/u'; + if (!preg_match($tagPattern, $tag)) { + return false; + } + } + return true; +} + +?> \ No newline at end of file