mirror of
https://github.com/sbrl/Pepperminty-Wiki.git
synced 2024-11-25 17:23:00 +00:00
337 lines
18 KiB
PHP
337 lines
18 KiB
PHP
<?php
|
|
register_module([
|
|
"name" => "User Preferences",
|
|
"version" => "0.3.4",
|
|
"author" => "Starbeamrainbowlabs",
|
|
"description" => "Adds a user preferences page, letting people do things like change their email address and password.",
|
|
"id" => "feature-user-preferences",
|
|
"code" => function() {
|
|
global $env, $settings;
|
|
/**
|
|
* @api {get} ?action=user-preferences Get a user preferences configuration page
|
|
* @apiName UserPreferences
|
|
* @apiGroup Settings
|
|
* @apiPermission User
|
|
*/
|
|
|
|
/*
|
|
* ██ ██ ███████ ███████ ██████
|
|
* ██ ██ ██ ██ ██ ██
|
|
* ██ ██ ███████ █████ ██████ █████
|
|
* ██ ██ ██ ██ ██ ██
|
|
* ██████ ███████ ███████ ██ ██
|
|
*
|
|
* ██████ ██████ ███████ ███████ ███████
|
|
* ██ ██ ██ ██ ██ ██ ██
|
|
* ██████ ██████ █████ █████ ███████
|
|
* ██ ██ ██ ██ ██ ██
|
|
* ██ ██ ██ ███████ ██ ███████
|
|
*/
|
|
add_action("user-preferences", function() {
|
|
global $env, $settings;
|
|
|
|
if(!$env->is_logged_in)
|
|
{
|
|
exit(page_renderer::render_main("Error - $settings->sitename", "<p>Since you aren't logged in, you can't change your preferences. This is because stored preferences are tied to each registered user account. You can login <a href='?action=login&returnto=" . rawurlencode("?action=user-preferences") . "'>here</a>.</p>"));
|
|
}
|
|
|
|
$statusMessages = [
|
|
"change-password" => "Password changed successfully!"
|
|
];
|
|
|
|
if(!isset($env->user_data->emailAddress)) {
|
|
$env->user_data->emailAddress = "";
|
|
save_userdata();
|
|
}
|
|
|
|
$content = "<h2>User Preferences</h2>\n";
|
|
if(isset($_GET["success"]) && $_GET["success"] === "yes") {
|
|
$content .= "<p class='user-prefs-status-message'><em>" . $statusMessages[$_GET["operation"]] . "</em></p>\n";
|
|
}
|
|
|
|
if(has_action("watchlist") && module_exists("feature-watchlist")) {
|
|
$content .= "<p><em>Looking for your watchlist? Find it <a href='?action=watchlist'>here</a>!</p>";
|
|
}
|
|
|
|
// If avatar support is present, allow the user to upload a new avatar
|
|
if(has_action("avatar") && module_exists("feature-upload")) {
|
|
$content .= "<a href='?action=upload&avatar=yes' class='preview'><figure>\n";
|
|
$content .= "\t<img class='avatar' src='?action=avatar&user=" . urlencode($env->user) . "&size=256' title='Your current avatar - click to upload a new one' />\n";
|
|
$content .= "<figcaption>Upload a new avatar</figcaption>\n";
|
|
$content .= "</figure></a><br />\n";
|
|
}
|
|
$content .= "<label for='username'>Username:</label>\n";
|
|
$content .= "<input type='text' name='username' value='$env->user' readonly />\n";
|
|
$content .= "<form method='post' action='?action=save-preferences'>\n";
|
|
$content .= " <label for='email-address'>Email Address:</label>\n";
|
|
$content .= " <input type='email' id='email-address' name='email-address' placeholder='e.g. bob@bobsrockets.com' value='{$env->user_data->emailAddress}' />\n";
|
|
$content .= " <p><small>Used to send you notifications etc. Never shared with anyone except $settings->admindetails_name, $settings->sitename's administrator.</small></p>\n";
|
|
if($settings->email_user_verify) {
|
|
$content .= " <p>Verification status: ".(!empty($env->user_data->emailAddressVerificationCode) || !$env->user_data->emailAddressVerificationCode ? "not " : "")."verified <em>Email address verification is required in order to receive emails (other than the verification email itself, of course).</em></p>";
|
|
}
|
|
$content .= " <input type='submit' value='Save Preferences' />\n";
|
|
$content .= "</form>\n";
|
|
$content .= "<h3>Change Password</h3\n>";
|
|
$content .= "<form method='post' action='?action=change-password'>\n";
|
|
$content .= " <label for='old-pass'>Current Password:</label>\n";
|
|
$content .= " <input type='password' name='current-pass' />\n";
|
|
$content .= " <br />\n";
|
|
$content .= " <label for='new-pass'>New Password:</label>\n";
|
|
$content .= " <input type='password' name='new-pass' />\n";
|
|
$content .= " <br />\n";
|
|
$content .= " <label for='new-pass-confirm'>Confirm New Password:</label>\n";
|
|
$content .= " <input type='password' name='new-pass-confirm' />\n";
|
|
$content .= " <br />\n";
|
|
$content .= " <input type='submit' value='Change Password' />\n";
|
|
$content .= "</form>\n";
|
|
|
|
if($env->is_admin)
|
|
$content .= "<p>As an admin, you can also <a href='?action=configure'>edit $settings->sitename's master settings</a>.</p>\n";
|
|
|
|
exit(page_renderer::render_main("User Preferences - $settings->sitename", $content));
|
|
});
|
|
|
|
/**
|
|
* @api {post} ?action=save-preferences Save your user preferences
|
|
* @apiName UserPreferencesSave
|
|
* @apiGroup Settings
|
|
* @apiPermission User
|
|
*/
|
|
add_action("save-preferences", function() {
|
|
global $env, $settings;
|
|
|
|
if(!$env->is_logged_in)
|
|
{
|
|
http_response_code(400);
|
|
exit(page_renderer::render_main("Error Saving Preferences - $settings->sitename", "<p>You aren't logged in, so you can't save your preferences. Try <a href='?action=login&returnto=" . rawurlencode("?action=user-preferences") . "'>logging in</a> first.</p>"));
|
|
}
|
|
|
|
if(isset($_POST["email-address"])) {
|
|
if(mb_strlen($_POST["email-address"]) > 320) {
|
|
http_response_code(413);
|
|
exit(page_renderer::render_main("Error Saving Email Address - $settings->sitename", "<p>The email address you supplied (<code>{$_POST['email-address']}</code>) is too long. Email addresses can only be 320 characters long. <a href='javascript:window.history.back();'>Go back</a>."));
|
|
}
|
|
|
|
if(mb_strpos($_POST["email-address"], "@") === false) {
|
|
http_response_code(422);
|
|
exit(page_renderer::render_main("Error Saving Email Address - $settings->sitename", "<p>The email address you supplied (<code>{$_POST['email-address']}</code>) doesn't appear to be valid. <a href='javascript:window.history.back();'>Go back</a>."));
|
|
}
|
|
$old_address = $env->user_data->emailAddress ?? null;
|
|
$env->user_data->emailAddress = $_POST["email-address"];
|
|
// If email address verification is required and the email
|
|
// address has changed, send a verification email now
|
|
if($settings->email_user_verify && $old_address !== $_POST["email-address"]) {
|
|
$env->user_data->emailAddressVerified = false;
|
|
if(!email_user_verify($env->user)) {
|
|
http_response_code(503);
|
|
exit(page_renderer::render_main("Server error sending verification code - $settings->sitename", "<p>$settings->sitename tried to send you an email to verify your email address, but was unable to do so. The changes to your settings have not been saved. Please contact $settings->admindetails_name, whose email address can be found at the bottom of this page.</p>"));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Save the user's preferences
|
|
if(!save_userdata()) {
|
|
http_response_code(503);
|
|
exit(page_renderer::render_main("Error Saving Preferences - $settings->sitename", "<p>$settings->sitename had some trouble saving your preferences! Please contact $settings->admindetails_name, $settings->sitename's administrator and tell them about this error if it still occurs in 5 minutes. They can be contacted by email at this address: <a href='mailto:" . hide_email($settings->admindetails_email) . "'>" . hide_email($settings->admindetails_email) . "</a>.</p>"));
|
|
}
|
|
|
|
exit(page_renderer::render_main("Preferences Saved Successfully - $settings->sitename", "<p>Your preferences have been saved successfully! You could go back your <a href='?action=user-preferences'>preferences page</a>, or on to the <a href='?page=" . rawurlencode($settings->defaultpage) . "'>$settings->defaultpage</a>.</p>
|
|
<p>If you changed your email address, a verification code will have been sent to the email address you specified. Click on the link provided to verify your new email address.</p>"));
|
|
});
|
|
|
|
/**
|
|
* @api {get} ?action=email-address-verify&code={code} Verify the current user's email address
|
|
* @apiName EmailAddressVerify
|
|
* @apiGroup Settings
|
|
* @apiPermission User
|
|
*
|
|
* @apiParam {string} code The verfication code.
|
|
*
|
|
* @apiError VerificationCodeIncorrect The supplied verification code is not correct.
|
|
*/
|
|
add_action("email-address-verify", function() {
|
|
global $env, $settings;
|
|
|
|
if(!$env->is_logged_in) {
|
|
http_response_code(307);
|
|
header("x-status: failed");
|
|
header("x-problem: not-logged-in");
|
|
exit(page_renderer::render_main("Not logged in - $settings->sitename", "<p>You aren't logged in, so you can't verify your email address. Try <a href='?action=login&returnto=".rawurlencode("?action=email-address-verify&code=".($_GET["code"]??""))."'>logging in</a>.</p>"));
|
|
}
|
|
|
|
if($env->user_data->emailAddressVerified) {
|
|
header("x-status: success");
|
|
exit(page_renderer::render_main("Already verified - $settings->sitename", "<p>Your email address is already verified, so you don't need to verify it again.</p>\n<p> <a href='index.php'>Go to the main page</a>.</p>"));
|
|
}
|
|
|
|
if(empty($_GET["code"])) {
|
|
http_response_code(400);
|
|
header("x-status: failed");
|
|
header("x-problem: no-code-specified");
|
|
exit(page_renderer::render_main("No verification code specified - $settings->sitename", "<p>No verification code specified. Do so with the <code>code</code> GET parameter.</p>"));
|
|
}
|
|
|
|
if($env->user_data->emailAddressVerificationCode !== $_GET["code"]) {
|
|
http_resonse_code(400);
|
|
header("x-status: failed");
|
|
header("x-problem: code-incorrect");
|
|
exit(page_renderer::render_main("Verification code incorrect", "<p>That verification code was incorrect. Try specifying another one, or going to your <a href='?action=user-preferences'>user preferences</a> and changing your email address to re-send another code (you can change it to the same address).</p>"));
|
|
}
|
|
|
|
// The code supplied must be valid
|
|
unset($env->user_data->emailAddressVerificationCode);
|
|
$env->user_data->emailAddressVerified = true;
|
|
|
|
if(!save_settings()) {
|
|
http_response_code(503);
|
|
header("x-status: failed");
|
|
header("x-problem: server-error-disk-io");
|
|
exit(page_renderer::render_main("Server error - $settings->sitename", "<p>Your verification code was correct, but $settings->sitename was unable to update your user details because it failed to write the changes to disk. Please contact $settings->admindetails_name, whose email address can be found at the bottom of the page.</p>"));
|
|
}
|
|
|
|
header("x-status: success");
|
|
exit(page_renderer::render_main("Email Address Verified - $settings->sitename", "<p>Your email address was verified successfully. <a href='index.php'>Go to the main page</p>, or <a href='?action=user-preferences'>to your user preferences</a> to make further changes.</p>"));
|
|
});
|
|
|
|
/**
|
|
* @api {post} ?action=change-password Change your password
|
|
* @apiName ChangePassword
|
|
* @apiGroup Settings
|
|
* @apiPermission User
|
|
*
|
|
* @apiParam {string} current-pass Your current password.
|
|
* @apiParam {string} new-pass Your new password.
|
|
* @apiParam {string} new-pass-confirm Your new password again, to make sure you've typed it correctly.
|
|
*
|
|
* @apiError PasswordMismatchError The new password fields don't match.
|
|
*/
|
|
add_action("change-password", function() {
|
|
global $env, $settings;
|
|
|
|
// Make sure the new password was typed correctly
|
|
// This comes before the current password check since that's more intensive
|
|
if($_POST["new-pass"] !== $_POST["new-pass-confirm"]) {
|
|
exit(page_renderer::render_main("Password mismatch - $settings->sitename", "<p>The new password you typed twice didn't match! <a href='javascript:history.back();'>Go back</a>.</p>"));
|
|
}
|
|
// Check the current password
|
|
if(!verify_password($_POST["current-pass"], $env->user_data->password)) {
|
|
exit(page_renderer::render_main("Password mismatch - $settings->sitename", "<p>Error: You typed your current password incorrectly! <a href='javascript:history.back();'>Go back</a>.</p>"));
|
|
}
|
|
|
|
// All's good! Go ahead and change the password.
|
|
$env->user_data->password = hash_password($_POST["new-pass"]);
|
|
// Save the userdata back to disk
|
|
if(!save_userdata()) {
|
|
http_response_code(503);
|
|
exit(page_renderer::render_main("Error Saving Password - $settings->sitename", "<p>While you entered your old password correctly, $settings->sitename encountered an error whilst saving your password to disk! Your password has not been changed. Please contact $settings->admindetails_name for assistance (you can find their email address at the bottom of this page)."));
|
|
}
|
|
|
|
http_response_code(307);
|
|
header("location: ?action=user-preferences&success=yes&operation=change-password");
|
|
exit(page_renderer::render_main("Password Changed Successfully", "<p>You password was changed successfully. <a href='?action=user-preferences'>Go back to the user preferences page</a>.</p>"));
|
|
});
|
|
|
|
|
|
/*
|
|
* █████ ██ ██ █████ ████████ █████ ██████
|
|
* ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
* ███████ ██ ██ ███████ ██ ███████ ██████
|
|
* ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
* ██ ██ ████ ██ ██ ██ ██ ██ ██ ██
|
|
*/
|
|
|
|
/**
|
|
* @api {get} ?action=avatar&user={username}[&size={size}] Get a user's avatar
|
|
* @apiName Avatar
|
|
* @apiGroup Upload
|
|
* @apiPermission Anonymous
|
|
*
|
|
* @apiParam {string} user The username to fetch the avatar for
|
|
* @apiParam {string} size The preferred size of the avatar
|
|
*/
|
|
add_action("avatar", function() {
|
|
global $settings;
|
|
|
|
$size = intval($_GET["size"] ?? 32);
|
|
|
|
/// Use gravatar if there's some issue with the requested user
|
|
|
|
// No user specified
|
|
if(empty($_GET["user"])) {
|
|
http_response_code(307);
|
|
header("x-reason: no-user-specified");
|
|
header("location: https://gravatar.com/avatar/?default=blank");
|
|
}
|
|
|
|
$requested_username = $_GET["user"];
|
|
|
|
// The user hasn't uploaded an avatar
|
|
if(empty($pageindex->{"User/$requested_username/Avatar"}) || !$pageindex->{"User/$requested_username/Avatar"}->uploadedfile) {
|
|
$user_fragment = !empty($settings->users->$requested_username->emailAddress) ? $settings->users->$requested_username->emailAddress : $requested_username;
|
|
|
|
http_response_code(307);
|
|
header("x-reason: no-avatar-found");
|
|
header("x-hash-method: " . ($user_fragment === $requested_username ? "username" : "email_address"));
|
|
header("location: https://gravatar.com/avatar/" . md5($user_fragment) . "?default=identicon&rating=g&size=$size");
|
|
exit();
|
|
}
|
|
|
|
// The user has uploaded an avatar, so we can redirec to the regular previewer :D
|
|
|
|
http_response_code(307);
|
|
header("x-reason: found-local-avatar");
|
|
header("location: ?action=preview&size=$size&page=" . urlencode("Users/$requested_username/Avatar"));
|
|
exit("This user's avatar can be found at Files/$requested_username/Avatar");
|
|
});
|
|
|
|
// Display a help section on the user preferences, but only if the user
|
|
// is logged in and so able to access them
|
|
if($env->is_logged_in) {
|
|
add_help_section("910-user-preferences", "User Preferences", "<p>As you are logged in, $settings->sitename lets you configure a selection of personal preferences. These can be viewed and tweaked to you liking over on the <a href='?action=user-preferences'>preferences page</a>, which can be accessed at any time by clicking the cog icon (it looks something like this: <a href='?action=user-preferences'>$settings->user_preferences_button_text</a>), though the administrator of $settings->sitename ($settings->admindetails_name) may have changed its appearance.</p>");
|
|
}
|
|
|
|
if($settings->avatars_show) {
|
|
add_help_section("915-avatars", "Avatars", "<p>$settings->sitename allows you to upload an avatar and have it displayed next to your name. If you don't have an avatar uploaded yet, then $settings->sitename will take a <a href='https://www.techopedia.com/definition/19744/hash-function'>hash</a> of your email address and ask <a href='https://gravatar.com'>Gravatar</a> for for your Gravatar instead. If you haven't told $settings->sitename what your email address is either, a hash of your username is used instead. If you don't have a gravatar, then $settings->sitename asks Gravatar for an identicon instead.</p>
|
|
<p>Your avatar on $settings->sitename currently looks like this: <img class='avatar' src='?action=avatar&user=" . urlencode($env->user) . "' />" . ($settings->upload_enabled ? " - you can upload a new one by going to your <a href='?action=user-preferences'>preferences</a>, or <a href='?action=upload&avatar=yes' />clicking here</a>." : ", but $settings->sitename currently has uploads disabled, so you can't upload a new one directly to $settings->sitename. You can, however, set your email address in your <a href='?action=user-preferences'>preferences</a> and <a href='https://en.gravatar.com/'>create a Gravatar</a>, and then it should show up here on $settings->sitename shortly.") . "</p>");
|
|
}
|
|
}
|
|
]);
|
|
|
|
/**
|
|
* Sends a verification email to the specified user, assuming they need to
|
|
* verify their email address.
|
|
* If a user does not need to verify their email address, no verification email
|
|
* is sent and true is returned.
|
|
* @param string $username The name of the user to send the verification code to.
|
|
* @return boolean Whether the verification code was sent successfully. If a user does not need to verify their email address, this returns true.
|
|
*/
|
|
function email_user_verify(string $username) : boolean {
|
|
global $settings;
|
|
|
|
$user_data = $settings->users->$username;
|
|
|
|
if(!empty($user_data->emailAddressVerified) &&
|
|
$user_data->emailAddressVerified === true) {
|
|
return true;
|
|
}
|
|
|
|
// Generate a verification code
|
|
$user_data->emailAddressVerificationCode = crypto_id(64);
|
|
if(!save_settings())
|
|
return false;
|
|
|
|
return email_user(
|
|
$username,
|
|
"Verify your account - $settings->sitename",
|
|
"Hey there! Click this link to verify your account on $settings->sitename:
|
|
|
|
".url_stem()."?action=email-address-verify&code=$user_data->emailAddressVerificationCode
|
|
|
|
$settings->sitename requires that you verify your email address in order to use it.
|
|
|
|
--$settings->sitename
|
|
Powered by Pepperminty Wiki"
|
|
);
|
|
}
|
|
|
|
?>
|