diff options
Diffstat (limited to 'src/application/actions/viewuser')
-rw-r--r-- | src/application/actions/viewuser/_common.php | 21 | ||||
-rw-r--r-- | src/application/actions/viewuser/get.php | 34 | ||||
-rw-r--r-- | src/application/actions/viewuser/post.php | 173 |
3 files changed, 228 insertions, 0 deletions
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"); +} |