.
This commit is contained in:
@@ -5,6 +5,8 @@ if (session_status() === PHP_SESSION_NONE) {
|
||||
|
||||
require_once "../model/CommentManager.php";
|
||||
require_once "../model/UserManager.php";
|
||||
require_once "../model/ArticleManager.php";
|
||||
require_once "../../includes/csrf.php";
|
||||
|
||||
/**
|
||||
* Prüft, ob die Anfrage durch JavaScript per AJAX gesendet wurde.
|
||||
@@ -41,6 +43,7 @@ function sendCommentResponse(
|
||||
$additionalData
|
||||
)
|
||||
);
|
||||
|
||||
exit();
|
||||
}
|
||||
|
||||
@@ -96,6 +99,17 @@ if (!isset($_SESSION["user_email"])) {
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* CSRF-Token prüfen, bevor irgendeine Änderung vorgenommen wird.
|
||||
*/
|
||||
if (!csrf_verify()) {
|
||||
sendCommentResponse(
|
||||
false,
|
||||
"Deine Sitzung ist abgelaufen. Bitte lade die Seite neu und versuche es erneut.",
|
||||
$articleId !== false ? $articleId : null
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Weitere Formulardaten einlesen.
|
||||
*/
|
||||
@@ -128,6 +142,18 @@ if ($articleId === false || $articleId === null) {
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Der Beitrag muss tatsächlich existieren.
|
||||
*/
|
||||
$existingArticle = ArticleManager::getInstance()->getArticle($articleId);
|
||||
if ($existingArticle === null) {
|
||||
sendCommentResponse(
|
||||
false,
|
||||
"Der zugehörige Beitrag wurde nicht gefunden.",
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
if ($content === "") {
|
||||
sendCommentResponse(
|
||||
false,
|
||||
@@ -152,6 +178,30 @@ if (
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Falls eine Eltern-ID angegeben wurde, muss dieser Kommentar
|
||||
* tatsächlich existieren und zum selben Beitrag gehören.
|
||||
*/
|
||||
if ($parentCommentId !== null) {
|
||||
$existingComments = CommentManager::getInstance()->getCommentsByArticle($articleId);
|
||||
$parentExists = false;
|
||||
|
||||
foreach ($existingComments as $existingComment) {
|
||||
if ($existingComment->getId() === $parentCommentId) {
|
||||
$parentExists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$parentExists) {
|
||||
sendCommentResponse(
|
||||
false,
|
||||
"Der ausgewählte Kommentar wurde nicht gefunden.",
|
||||
$articleId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$commentManager = CommentManager::getInstance();
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ require_once '../model/LocalArticleManager.php';
|
||||
require_once '../model/ArticleManager.php';
|
||||
require_once '../validator/article-validator.php';
|
||||
require_once '../../includes/article-block-helper.php';
|
||||
require_once '../../includes/csrf.php';
|
||||
|
||||
if (!isset($_SESSION["user"])) {
|
||||
header("Location: index.php?pfad=login");
|
||||
@@ -14,6 +15,13 @@ if (!isset($_SESSION["user"])) {
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
|
||||
// CSRF-Token prüfen, bevor irgendeine Änderung vorgenommen wird
|
||||
if (!csrf_verify()) {
|
||||
$_SESSION["message"] = "invalid_csrf_token";
|
||||
header("location: ../../index.php?pfad=createArticle");
|
||||
exit();
|
||||
}
|
||||
|
||||
$uploadDir = __DIR__ . '/../../uploads/';
|
||||
if (!file_exists($uploadDir)) {
|
||||
mkdir($uploadDir, 0755, true);
|
||||
|
||||
@@ -5,12 +5,24 @@ if (session_status() === PHP_SESSION_NONE) {
|
||||
|
||||
require_once __DIR__ . "/../model/UserManager.php";
|
||||
require_once __DIR__ . "/../model/ArticleManager.php";
|
||||
require_once __DIR__ . "/../../includes/csrf.php";
|
||||
|
||||
if (!isset($_SESSION["user"])) {
|
||||
header("Location: index.php?pfad=login");
|
||||
exit();
|
||||
}
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] !== "POST") {
|
||||
header("Location: ../../index.php?pfad=profile");
|
||||
exit();
|
||||
}
|
||||
|
||||
if (!csrf_verify()) {
|
||||
$_SESSION["message"] = "invalid_csrf_token";
|
||||
header("Location: ../../index.php?pfad=profile");
|
||||
exit();
|
||||
}
|
||||
|
||||
/*
|
||||
Deregistrierung
|
||||
Funktion: Entfernt User aus der Datenbank und beendet die Session
|
||||
|
||||
@@ -4,6 +4,7 @@ if (session_status() === PHP_SESSION_NONE) {
|
||||
}
|
||||
|
||||
require_once __DIR__ . "/../model/ArticleManager.php";
|
||||
require_once __DIR__ . "/../../includes/csrf.php";
|
||||
|
||||
if (!isset($_SESSION["user"])) {
|
||||
header("Location: index.php?pfad=login");
|
||||
@@ -12,6 +13,13 @@ if (!isset($_SESSION["user"])) {
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
|
||||
// CSRF-Token prüfen, bevor irgendeine Änderung vorgenommen wird
|
||||
if (!csrf_verify()) {
|
||||
$_SESSION["message"] = "invalid_csrf_token";
|
||||
header("location: ../../index.php?pfad=profile");
|
||||
exit();
|
||||
}
|
||||
|
||||
if (isset($_SESSION["user_email"])) {
|
||||
$user = $_SESSION["user_email"];
|
||||
} else {
|
||||
@@ -22,9 +30,10 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
exit();
|
||||
}
|
||||
|
||||
if (isset($_POST["id"]) && !empty($_POST["id"])) {
|
||||
$id = $_POST["id"];
|
||||
} else {
|
||||
// Die Beitrags-ID muss eine gültige numerische ID sein.
|
||||
$id = filter_input(INPUT_POST, "id", FILTER_VALIDATE_INT);
|
||||
|
||||
if ($id === false || $id === null) {
|
||||
$_SESSION["message"] = "missing_id";
|
||||
header("location: ../../index.php?pfad=profile");
|
||||
exit();
|
||||
@@ -44,4 +53,4 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
$_SESSION["message"] = "article_deleted";
|
||||
header("location: ../../index.php?pfad=profile");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ if (session_status() === PHP_SESSION_NONE) {
|
||||
}
|
||||
|
||||
require_once __DIR__ . "/../model/CommentManager.php";
|
||||
require_once __DIR__ . "/../../includes/csrf.php";
|
||||
|
||||
/*
|
||||
* Kommentare dürfen nur über ein POST-Formular gelöscht werden.
|
||||
@@ -44,6 +45,23 @@ if (!isset($_SESSION["user_email"])) {
|
||||
exit();
|
||||
}
|
||||
|
||||
// CSRF-Token prüfen, bevor irgendeine Änderung vorgenommen wird
|
||||
if (!csrf_verify()) {
|
||||
$_SESSION["comment_message"] = "Deine Sitzung ist abgelaufen. Bitte lade die Seite neu.";
|
||||
$_SESSION["comment_message_type"] = "error";
|
||||
|
||||
if ($articleId !== false && $articleId !== null) {
|
||||
header(
|
||||
"Location: index.php?pfad=showArticle&id="
|
||||
. urlencode((string) $articleId)
|
||||
. "#comments"
|
||||
);
|
||||
} else {
|
||||
header("Location: index.php");
|
||||
}
|
||||
exit();
|
||||
}
|
||||
|
||||
/*
|
||||
* Kommentar-ID und Beitrags-ID müssen gültige Zahlen sein.
|
||||
*/
|
||||
@@ -102,4 +120,4 @@ header(
|
||||
. "#comments"
|
||||
);
|
||||
|
||||
exit();
|
||||
exit();
|
||||
@@ -20,6 +20,8 @@ if ($pfad === "login") {
|
||||
include_once "php/controller/confirm-register-controller.php";
|
||||
} elseif ($pfad === "confirm-password") {
|
||||
include_once "php/controller/confirm-password-controller.php";
|
||||
} elseif ($pfad === "profile") {
|
||||
include_once "php/controller/profile-controller.php";
|
||||
} elseif ($pfad === "updateComment") {
|
||||
include_once "php/controller/updateComment-controller.php";
|
||||
} elseif($pfad === "deleteComment") {
|
||||
|
||||
@@ -5,6 +5,12 @@ if (session_status() === PHP_SESSION_NONE) {
|
||||
|
||||
require_once __DIR__ . '/../model/Article.php';
|
||||
require_once __DIR__ . '/../model/ArticleManager.php';
|
||||
require_once __DIR__ . '/../../includes/csrf.php';
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] !== "POST") {
|
||||
header("Location: ../../index.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
// 2. Prüfen, ob eine gültige Artikel-ID übergeben wurde
|
||||
if (isset($_GET["id"]) && !empty($_GET["id"])) {
|
||||
@@ -17,6 +23,13 @@ if (isset($_GET["id"]) && !empty($_GET["id"])) {
|
||||
exit();
|
||||
}
|
||||
|
||||
// CSRF-Token prüfen, bevor der Like-Status verändert wird
|
||||
if (!csrf_verify()) {
|
||||
$_SESSION["message"] = "invalid_csrf_token";
|
||||
header("Location: ../../index.php?pfad=showArticle&id=" . $articleId);
|
||||
exit();
|
||||
}
|
||||
|
||||
try {
|
||||
$articleManager = ArticleManager::getInstance();
|
||||
$articleManager->toggleLike($articleId, $userEmail);
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
<?php
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
$_SESSION = [];
|
||||
session_destroy();
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ require_once "php/model/Article.php";
|
||||
require_once "php/model/ArticleManager.php";
|
||||
require_once "php/model/CommentManager.php";
|
||||
require_once "php/validator/user-validator.php";
|
||||
require_once "includes/csrf.php";
|
||||
|
||||
$error = null;
|
||||
|
||||
@@ -27,6 +28,7 @@ try {
|
||||
}
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_POST["saveProfile"])) {
|
||||
|
||||
$oldEmail = $_SESSION["user_email"];
|
||||
|
||||
$newEmail = trim($_POST["email"] ?? "");
|
||||
@@ -34,7 +36,12 @@ try {
|
||||
$nachname = trim($_POST["nachname"] ?? "");
|
||||
$password = $_POST["password"] ?? "";
|
||||
|
||||
if (!userEmailValidator($newEmail)) {
|
||||
if (!csrf_verify()) {
|
||||
// CSRF-Token prüfen, bevor irgendeine Änderung vorgenommen wird
|
||||
$error = "Deine Sitzung ist abgelaufen. Bitte lade die Seite neu und versuche es erneut.";
|
||||
$_GET["edit"] = "1";
|
||||
|
||||
} elseif (!userEmailValidator($newEmail)) {
|
||||
$error = "Bitte gib eine gültige E-Mail-Adresse ein.";
|
||||
$_GET["edit"] = "1";
|
||||
|
||||
|
||||
@@ -7,10 +7,14 @@ require_once 'php/model/Article.php';
|
||||
require_once 'php/model/ArticleManager.php';
|
||||
require_once 'php/model/UserManager.php';
|
||||
require_once 'php/model/CommentManager.php';
|
||||
require_once 'php/validator/article-validator.php';
|
||||
|
||||
if (isset($_GET["id"]) && !empty($_GET["id"])){
|
||||
// Die übergebene ID muss eine gültige, positive Zahl sein, bevor sie
|
||||
// weiterverwendet wird. Vorher wurde jeder nicht-leere Wert akzeptiert.
|
||||
$id = isset($_GET["id"]) ? articleIdValidator($_GET["id"]) : false;
|
||||
|
||||
if ($id !== false) {
|
||||
try {
|
||||
$id = $_GET["id"];
|
||||
$articleManager = ArticleManager::getInstance();
|
||||
$article = $articleManager->getArticle($id);
|
||||
if($article != null){
|
||||
@@ -38,7 +42,7 @@ if (isset($_GET["id"]) && !empty($_GET["id"])){
|
||||
}
|
||||
|
||||
$commentManager = CommentManager::getInstance();
|
||||
$comments = $commentManager->getCommentsByArticle($_GET["id"]);
|
||||
$comments = $commentManager->getCommentsByArticle($id); // NEU: validierte ID statt rohem $_GET["id"]
|
||||
|
||||
foreach ($comments as $comment) {
|
||||
if ($comment->isReply()) {
|
||||
|
||||
@@ -8,6 +8,7 @@ require_once '../model/ArticleManager.php';
|
||||
require_once '../model/Article.php';
|
||||
require_once '../validator/article-validator.php';
|
||||
require_once '../../includes/article-block-helper.php';
|
||||
require_once '../../includes/csrf.php'; // NEU: CSRF-Schutz
|
||||
|
||||
if (!isset($_SESSION["user"])) {
|
||||
header("Location: index.php?pfad=login");
|
||||
@@ -16,9 +17,17 @@ if (!isset($_SESSION["user"])) {
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
|
||||
if (isset($_GET["id"]) && !empty($_GET["id"])) {
|
||||
$id = $_GET["id"];
|
||||
} else {
|
||||
// CSRF-Token prüfen, bevor irgendeine Änderung vorgenommen wird
|
||||
if (!csrf_verify()) {
|
||||
$_SESSION["message"] = "invalid_csrf_token";
|
||||
header("location: ../../index.php?pfad=updateArticle");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Die Beitrags-ID muss eine gültige numerische ID sein
|
||||
$id = filter_input(INPUT_GET, "id", FILTER_VALIDATE_INT);
|
||||
|
||||
if ($id === false || $id === null) {
|
||||
$_SESSION["message"] = "missing_id";
|
||||
header("location: ../../index.php?pfad=updateArticle");
|
||||
exit();
|
||||
@@ -27,6 +36,14 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
try {
|
||||
$articleManager = ArticleManager::getInstance();
|
||||
$article = $articleManager->getArticle($id);
|
||||
|
||||
// Existenz des Beitrags prüfen, bevor auf $article zugegriffen wird.
|
||||
if ($article === null) {
|
||||
$_SESSION["message"] = "missing_id";
|
||||
header("location: ../../index.php?pfad=updateArticle");
|
||||
exit();
|
||||
}
|
||||
|
||||
if ($article->getAuthor() != $_SESSION["user_email"]) {
|
||||
$_SESSION["message"] = "unauthorized_access";
|
||||
header("location: ../../index.php");
|
||||
|
||||
@@ -5,6 +5,7 @@ if (session_status() === PHP_SESSION_NONE) {
|
||||
}
|
||||
|
||||
require_once "php/model/CommentManager.php";
|
||||
require_once "includes/csrf.php";
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] !== "POST") {
|
||||
header("Location: index.php");
|
||||
@@ -16,6 +17,14 @@ if (!isset($_SESSION["user_email"])) {
|
||||
exit();
|
||||
}
|
||||
|
||||
// CSRF-Token prüfen, bevor irgendeine Änderung vorgenommen wird
|
||||
if (!csrf_verify()) {
|
||||
$_SESSION["comment_message"] = "Deine Sitzung ist abgelaufen. Bitte lade die Seite neu.";
|
||||
$_SESSION["comment_message_type"] = "error";
|
||||
header("Location: index.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$commentId = filter_input(
|
||||
INPUT_POST,
|
||||
"comment_id",
|
||||
@@ -89,4 +98,4 @@ header(
|
||||
. urlencode((string) $articleId)
|
||||
. "#comments"
|
||||
);
|
||||
exit();
|
||||
exit();
|
||||
@@ -63,12 +63,9 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
||||
VALUES (:title, :content, :author, :category, :tags);";
|
||||
|
||||
$command = $db->prepare($sql);
|
||||
if (!$command) {
|
||||
throw new InternalServerErrorException("internal_error");
|
||||
}
|
||||
|
||||
// Verknüpft die übergebenen Parameter exakt mit den SQL-Platzhaltern
|
||||
$success = $command->execute([
|
||||
$command->execute([
|
||||
":title" => $title,
|
||||
":content" => $content,
|
||||
":author" => $author,
|
||||
@@ -76,14 +73,10 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
||||
":tags" => $tags
|
||||
]);
|
||||
|
||||
if (!$success) {
|
||||
throw new InternalServerErrorException("internal_error");
|
||||
}
|
||||
|
||||
return intval($db->lastInsertId());
|
||||
|
||||
} catch (PDOException $e) {
|
||||
throw new InternalServerErrorException($e->getMessage());
|
||||
throw new InternalServerErrorException("internal_error");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,11 +99,8 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
||||
WHERE id = :id;";
|
||||
|
||||
$command = $db->prepare($sql);
|
||||
if (!$command) {
|
||||
throw new InternalServerErrorException("internal_error");
|
||||
}
|
||||
|
||||
$success = $command->execute([
|
||||
$command->execute([
|
||||
":id" => $id,
|
||||
":title" => $article->getTitle(),
|
||||
":content" => $article->getContent(),
|
||||
@@ -120,7 +110,7 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
||||
]);
|
||||
|
||||
// rowCount() prüft, ob eine Zeile mit dieser ID existierte und geändert werden konnte
|
||||
if (!$success || $command->rowCount() === 0) {
|
||||
if ($command->rowCount() === 0) {
|
||||
// Falls die ID nicht existiert, prüfen wir, ob sie überhaupt da ist
|
||||
if (!$this->getArticle($id)) {
|
||||
throw new NotFoundException("missing_id");
|
||||
@@ -148,13 +138,7 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
||||
$sql = "DELETE FROM articles WHERE id = :id;";
|
||||
|
||||
$command = $db->prepare($sql);
|
||||
if (!$command) {
|
||||
throw new InternalServerErrorException("internal_error");
|
||||
}
|
||||
|
||||
if (!$command->execute([":id" => $id])) {
|
||||
throw new InternalServerErrorException("internal_error");
|
||||
}
|
||||
$command->execute([":id" => $id]);
|
||||
} catch (PDOException $exc) {
|
||||
throw new InternalServerErrorException("internal_error");
|
||||
}
|
||||
@@ -167,10 +151,6 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
||||
$sql = "SELECT * FROM articles WHERE id = :id;";
|
||||
|
||||
$command = $db->prepare($sql);
|
||||
if (!$command) {
|
||||
throw new InternalServerErrorException("internal_error");
|
||||
}
|
||||
|
||||
$command->execute([":id" => $id]);
|
||||
$row = $command->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
@@ -202,10 +182,6 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
||||
$sql = "SELECT * FROM articles;";
|
||||
|
||||
$command = $db->query($sql);
|
||||
if (!$command) {
|
||||
throw new InternalServerErrorException("internal_error");
|
||||
}
|
||||
|
||||
$rows = $command->fetchAll(PDO::FETCH_ASSOC);
|
||||
$articles = [];
|
||||
|
||||
@@ -234,10 +210,6 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
||||
$sql = "SELECT * FROM articles WHERE author = :author;";
|
||||
|
||||
$command = $db->prepare($sql);
|
||||
if (!$command) {
|
||||
throw new InternalServerErrorException("internal_error");
|
||||
}
|
||||
|
||||
$command->execute([":author" => $author]);
|
||||
$rows = $command->fetchAll(PDO::FETCH_ASSOC);
|
||||
$filteredArticles = [];
|
||||
@@ -270,10 +242,6 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
||||
$sql = "SELECT * FROM articles WHERE category = :category;";
|
||||
|
||||
$command = $db->prepare($sql);
|
||||
if (!$command) {
|
||||
throw new InternalServerErrorException("internal_error");
|
||||
}
|
||||
|
||||
$command->execute([":category" => $category]);
|
||||
$rows = $command->fetchAll(PDO::FETCH_ASSOC);
|
||||
$filteredArticles = [];
|
||||
@@ -310,7 +278,7 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
||||
|
||||
try {
|
||||
$db = $this->getConnection();
|
||||
|
||||
|
||||
$sql = "SELECT id, title, content, author, category, tags, created
|
||||
FROM articles
|
||||
WHERE title LIKE :keyword
|
||||
@@ -318,20 +286,14 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
||||
OR tags LIKE :keyword;";
|
||||
|
||||
$command = $db->prepare($sql);
|
||||
if (!$command) {
|
||||
throw new InternalServerErrorException("internal_error");
|
||||
}
|
||||
|
||||
// Wildcards für die SQL-Suche hinzufügen
|
||||
// Wildcards für die Suche hinzufügen
|
||||
$searchParam = '%' . $cleankeyword . '%';
|
||||
$success = $command->execute([
|
||||
|
||||
$command->execute([
|
||||
":keyword" => $searchParam
|
||||
]);
|
||||
|
||||
if (!$success) {
|
||||
throw new InternalServerErrorException("internal_error");
|
||||
}
|
||||
|
||||
$rows = $command->fetchAll(PDO::FETCH_ASSOC);
|
||||
$filteredArticles = [];
|
||||
|
||||
@@ -358,7 +320,6 @@ class DatabaseArticleManager implements ArticleManagerDAO {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Holt alle User-IDs, die einen bestimmten Beitrag geliked haben.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* NEU: Prüft, ob ein übergebener Wert eine gültige, positive
|
||||
* Beitrags-ID ist. Wird überall dort verwendet, wo eine Artikel-ID
|
||||
* aus $_GET oder $_POST entgegengenommen wird
|
||||
*
|
||||
* @param mixed $id
|
||||
* @return int|false Die validierte ID als int, oder false bei Ungültigkeit
|
||||
*/
|
||||
function articleIdValidator($id)
|
||||
{
|
||||
$options = ["options" => ["min_range" => 1]];
|
||||
|
||||
return filter_var($id, FILTER_VALIDATE_INT, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft, ob der Titel die folgenden Bedingungen erfüllt:
|
||||
* Buchstaben von a-z; A-Z
|
||||
|
||||
Reference in New Issue
Block a user