From 64b1ec0fabbf7328a79a20ff58502ebfa80fad8b Mon Sep 17 00:00:00 2001
From: Jonas Kohl
Date: Thu, 10 Oct 2024 17:33:13 +0200
Subject: Break up actions into individual files

---
 src/application/actions/viewuser/_common.php |  21 ++++
 src/application/actions/viewuser/get.php     |  34 ++++++
 src/application/actions/viewuser/post.php    | 173 +++++++++++++++++++++++++++
 3 files changed, 228 insertions(+)
 create mode 100644 src/application/actions/viewuser/_common.php
 create mode 100644 src/application/actions/viewuser/get.php
 create mode 100644 src/application/actions/viewuser/post.php

(limited to 'src/application/actions/viewuser')

diff --git a/src/application/actions/viewuser/_common.php b/src/application/actions/viewuser/_common.php
new file mode 100644
index 0000000..3f8236c
--- /dev/null
+++ b/src/application/actions/viewuser/_common.php
@@ -0,0 +1,21 @@
+<?php
+
+use mystic\forum\orm\User;
+
+$userId = $_GET["user"] ?? throw new Exception("Missing user id");
+$user = new User();
+$user->id = $userId;
+if (!$db->fetch($user)) {
+    http_response_code(404);
+    msg_error(__("No user exists with this id"));
+    exit;
+}
+
+$lastNameChangeTooRecent = false;
+$isOwnProfile = $user->id === $currentUser?->id;
+if ($isOwnProfile && $user->nameLastChanged !== null) {
+    $diff = $user->nameLastChanged->diff(new DateTime());
+    $diffSeconds = (new DateTime())->setTimestamp(0)->add($diff)->getTimestamp();
+    $diffDays = $diffSeconds / 60.0 / 60.0 / 24.0 / 30.0;
+    $lastNameChangeTooRecent = $diffDays <= 30;
+}
diff --git a/src/application/actions/viewuser/get.php b/src/application/actions/viewuser/get.php
new file mode 100644
index 0000000..c98df16
--- /dev/null
+++ b/src/application/actions/viewuser/get.php
@@ -0,0 +1,34 @@
+<?php
+
+use mystic\forum\orm\Attachment;
+use mystic\forum\orm\Post;
+use mystic\forum\orm\Topic;
+
+$posts = $db->fetchCustom(Post::class, 'WHERE author_id = $1 ORDER BY post_date DESC', [ $userId ]);
+$topics = [];
+$attachments = [];
+foreach ($posts as $item) {
+    if (!isset($topics[$item->topicId])) {
+        $topic = new Topic();
+        $topic->id = $item->topicId;
+        if ($db->fetch($topic))
+            $topics[$item->topicId] = $topic;
+    }
+    $attachs = $db->fetchCustom(Attachment::class, 'WHERE post_id = $1', [ $item->id ]);
+    $attachments[$item->id] = $attachs;
+}
+_view("template_start", ["_title" => $user->displayName]);
+_view("template_navigation_start");
+_view("template_navigation", [
+    "user" => $currentUser,
+    "isViewingOwnProfile" => $isOwnProfile,
+]);
+_view("template_navigation_end");
+_view("view_user", [
+    "user" => $user,
+    "posts" => $posts,
+    "topics" => $topics,
+    "attachments" => $attachments,
+    "lastNameChangeTooRecent" => $lastNameChangeTooRecent,
+]);
+_view("template_end", [...getThemeAndLangInfo()]);
diff --git a/src/application/actions/viewuser/post.php b/src/application/actions/viewuser/post.php
new file mode 100644
index 0000000..e16a6a8
--- /dev/null
+++ b/src/application/actions/viewuser/post.php
@@ -0,0 +1,173 @@
+<?php
+
+use mystic\forum\orm\User;
+use mystic\forum\orm\UserPermissions;
+use mystic\forum\utils\RequestUtils;
+use mystic\forum\utils\ValidationUtils;
+use Symfony\Component\Mailer\Exception\TransportException;
+use Symfony\Component\Mailer\Transport;
+use Symfony\Component\Mime\Address;
+use Symfony\Component\Mime\Email;
+
+$formId = $_POST["form_id"] ?? null;
+if ($formId === null) {
+    http_response_code(400);
+    msg_error("Missing form_id");
+    exit;
+}
+
+if ($formId === "update_password") {
+    if (!$currentUser) {
+        http_response_code(403);
+        msg_error(__("You must be logged in to update your password"));
+        exit;
+    }
+
+    if (!$isOwnProfile) {
+        RequestUtils::triggerFormError(__("You don't have permission to update this user's password"), $formId);
+    }
+
+    RequestUtils::ensureRequestMethod("POST");
+    $currentPassword = RequestUtils::getRequiredField("current_password", $formId);
+    $newPassword = RequestUtils::getRequiredField("new_password", $formId);
+    $retypePassword = RequestUtils::getRequiredField("retype_password", $formId);
+
+    if (!password_verify($currentPassword, $currentUser->passwordHash)) {
+        RequestUtils::triggerFormError(__("Current password is incorrect"), $formId);
+    }
+
+    if ($newPassword !== $retypePassword) {
+        RequestUtils::triggerFormError(__("New passwords don't match"), $formId);
+    }
+
+    if (strlen($newPassword) < 8) {
+        RequestUtils::triggerFormError(__("Password too short! Your password must consist of 8 or more characters"), $formId);
+    }
+
+    $currentUser->passwordHash = password_hash($newPassword, PASSWORD_DEFAULT);
+    
+    if (!$db->update($currentUser)) {
+        RequestUtils::triggerFormError(__("Failed to update password"), $formId);
+    }
+
+    header("Location: $_SERVER[REQUEST_URI]");
+} elseif ($formId === "update_profile") {
+    if (!$currentUser) {
+        http_response_code(403);
+        msg_error(__("You must be logged in to update your profile"));
+        exit;
+    }
+
+    $canEdit = ($currentUser?->id === $user?->id && $user?->hasPermission(UserPermissions::EDIT_OWN_USER))
+            || ($currentUser?->hasPermission(UserPermissions::EDIT_OTHER_USER));
+
+    if (!$canEdit) {
+        http_response_code(403);
+        msg_error(__("You don't have permission to update this profile"));
+        exit;
+    }
+
+    $displayName = RequestUtils::getRequiredField("display_name", $formId);
+    $pfpAction = RequestUtils::getRequiredField("pfp_action", $formId);
+
+    $userName = $_POST["name"] ?? $user->name;
+    $email = $_POST["email"] ?? $user->email;
+
+    $user->displayName = $displayName;
+
+    $userName = strtolower($userName);
+
+    if ($userName !== $user->name) {
+        if ($lastNameChangeTooRecent) {
+            RequestUtils::triggerFormError(__("You can only change your username every 30 days!"), $formId);
+        } else {
+            if (!ValidationUtils::isUsernameValid($userName))
+                RequestUtils::triggerFormError(__("Invalid username!"), $formId);
+            if (!ValidationUtils::isUsernameAvailable($db, $userName))
+                RequestUtils::triggerFormError(__("This username is already taken!"), $formId);
+            $user->name = $userName;
+            $user->nameLastChanged = new DateTimeImmutable();
+        }
+    }
+
+    if ($email !== $user->email) {
+        if ($user->pendingEmailCreated !== null) {
+            RequestUtils::triggerFormError(__("Please verify your email first!"), $formId);
+        } else {
+            $queryUser = new User();
+            $queryUser->email = $email;
+            $queryUser->pendingEmail = $email;
+            if ($db->fetchWhere($queryUser, "email") || $db->fetchWhere($queryUser, "pending_email")) {
+                RequestUtils::triggerFormError(__("This email address is already in use!"), $formId);
+            }
+            $user->pendingEmail = $email;
+            $user->pendingEmailCreated = new DateTimeImmutable();
+            $user->activationToken = $db->generateId(12);
+
+            try {
+                Transport::fromDsn(env("MAILER_DSN"))->send(
+                    (new Email())
+                        ->from(env("MAILER_FROM"))
+                        ->to(new Address($email, $displayName))
+                        ->text(__(
+                            "Hello, %user_display_name%!\n" .
+                            "\n" .
+                            "Please verify your new email address by clicking the link below:\n" .
+                            "%verify_link%\n" .
+                            "\n" .
+                            "Kind regards,\n" .
+                            "%forum_copyright%",
+                            params: [
+                                "forum_title" => (env("MYSTIC_FORUM_TITLE") ?? "Forum"),
+                                "user_display_name" => $displayName,
+                                "verify_link" => env("PUBLIC_URL") . "?_action=verifyemail&token=" . urlencode($user->activationToken) . "&sig=" . urlencode(base64_encode(hash("sha256", env("SECRET") . $user->activationToken . $user->id, true))),
+                                "forum_copyright" => (env("MYSTIC_FORUM_COPYRIGHT") ?? env("MYSTIC_FORUM_TITLE") ?? "Forum")
+                            ]
+                        ))
+                        ->subject(__("Please verify your email address"))
+                );
+            } catch (TransportException $_) {
+                RequestUtils::triggerFormError(__("Failed to send verification email"), $formId);
+            }
+        }
+    }
+
+    switch ($pfpAction) {
+        case "keep":
+            // Do nothing
+            break;
+        case "remove":
+            $user->profilePicture = null;
+            break;
+        case "replace": {
+            if (!isset($_FILES["pfp"]) || $_FILES["pfp"]["error"] !== UPLOAD_ERR_OK) {
+                RequestUtils::triggerFormError(__("Please upload an image to change your profile picture"), $formId);
+            }
+            $im = @imagecreatefromjpeg($_FILES["pfp"]["tmp_name"]);
+            if ($im === false)
+                $im = @imagecreatefrompng($_FILES["pfp"]["tmp_name"]);
+            if ($im === false)
+                RequestUtils::triggerFormError(__("Please upload a valid PNG or JPEG file"), $formId);
+            /** @var \GdImage $im */
+            $thumb = imagecreatetruecolor(64, 64);
+            imagecopyresampled($thumb, $im, 0, 0, 0, 0, 64, 64, imagesx($im), imagesy($im));
+            imagedestroy($im);
+            $stream = fopen("php://memory", "w+");
+            imagejpeg($thumb, $stream, 50);
+            rewind($stream);
+            imagedestroy($thumb);
+            $user->profilePicture = stream_get_contents($stream);
+            fclose($stream);
+        } break;
+        default:
+            RequestUtils::triggerFormError("Invalid value for pfp_action", $formId);
+            break;
+    }
+
+    if (!$db->update($user))
+        RequestUtils::triggerFormError(__("Failed to save changes", context: "Update profile"), $formId);
+
+    header("Location: $_SERVER[REQUEST_URI]");
+} else {
+    msg_error("Invalid formId");
+}
-- 
cgit v1.2.3