1
0
Fork 0
mirror of https://github.com/sbrl/Pepperminty-Wiki.git synced 2024-12-22 13:45:02 +00:00
Pepperminty-Wiki/modules/feature-guiconfig.php
2023-02-23 22:46:00 +03:00

280 lines
14 KiB
PHP

<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
register_module([
"name" => "Settings GUI",
"version" => "0.1.8",
"author" => "Starbeamrainbowlabs",
"description" => "The module everyone has been waiting for! Adds a web based gui that lets mods change the wiki settings.",
"id" => "feature-guiconfig",
"code" => function() {
global $settings;
/**
* @api {get} ?action=configure Get a page to change the global wiki settings
* @apiName ConfigureSettings
* @apiGroup Utility
* @apiPermission Moderator
*/
/*
* ██████ ██████ ███ ██ ███████ ██ ██████ ██ ██ ██████ ███████
* ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██
* ██ ██ ██ ██ ██ ██ █████ ██ ██ ███ ██ ██ ██████ █████
* ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
* ██████ ██████ ██ ████ ██ ██ ██████ ██████ ██ ██ ███████
*/
add_action("configure", function() {
global $settings, $env, $guiConfig, $version, $commit;
if(!$env->is_admin)
{
$errorMessage = "<p>You don't have permission to change $settings->sitename's master settings.</p>\n";
if(!$env->is_logged_in)
$errorMessage .= "<p>You could try <a href='?action=login&returnto=%3Faction%3Dconfigure'>logging in</a>.</p>";
else
$errorMessage .= "<p>You could try <a href='?action=logout&returnto=%3Faction%3Dconfigure'>logging out</a> and then <a href='?action=login&returnto=%3Faction%3Dconfigure'>logging in</a> again with a different account that has the appropriate privileges.</a>.</p>";
exit(page_renderer::render_main("Error - $settings->sitename", $errorMessage));
}
$content = "<h1>Master Control Panel</h1>\n";
$content .= "<p>This page lets you configure $settings->sitename's master settings. Please be careful - you can break things easily on this page if you're not careful!</p>\n";
if(module_exists("feature-user-table"))
$content .= "<p><em>Looking to manage $settings->sitename's users? Try the <a href='?action=user-table'>user table</a> instead!</em></p>\n";
if(module_exists("feature-theme-gallery"))
$content .= "<p><em>Want to change $settings->sitename's theme? Try the <a href='?action=theme-gallery'>theme gallery</a>!</em></p>";
$content .= "<p>You're currently running Pepperminty Wiki $version+" . substr($commit, 0, 7) . ".</p>\n";
$content .= "<h2>Actions</h2>";
// rebuild search index button
$content .= "<button class='action-invindex-rebuild' title='Rebuilds the index that is consulted when searching the wiki. Hit this button if some pages are not showing up.'>Rebuild Search Index</button>\n";
$content .= "<progress class='action-invindex-rebuild-progress' min='0' max='100' value='0' style='display: none;'></progress><br />\n";
$content .= "<output class='action-invindex-rebuild-latestmessage'></output><br />\n";
$invindex_rebuild_script = <<<SCRIPT
window.addEventListener("load", function(event) {
document.querySelector(".action-invindex-rebuild").addEventListener("click", function(event) {
var rebuildActionEvents = new EventSource("?action=invindex-rebuild");
var latestMessageElement = document.querySelector(".action-invindex-rebuild-latestmessage");
var progressElement = document.querySelector(".action-invindex-rebuild-progress");
rebuildActionEvents.addEventListener("message", function(event) {
console.log(event);
let message = event.data;
latestMessageElement.value = event.data;
let parts = message.match(/^\[\s*(\d+)\s+\/\s+(\d+)\s*\]/);
if(parts != null) {
progressElement.style.display = "";
progressElement.min = 0;
progressElement.max = parseInt(parts[2]);
progressElement.value = parseInt(parts[1]);
}
if(message.startsWith("Done! Saving new search index to"))
rebuildActionEvents.close();
});
// Close the connection on error & don't try again
rebuildActionEvents.addEventListener("error", (_event) => rebuildActionEvents.close());
});
});
SCRIPT;
page_renderer::add_js_snippet($invindex_rebuild_script);
// rebuild page index button
$content .= "<button class='action-pageindex-rebuild' title='Rebuilds the page index that contains information (tags, author, dates, filename) about all wiki pages. Hit this button if MD files were changed externally.'>Rebuild Page Index</button>\n";
$content .= "<progress class='action-pageindex-rebuild-progress' min='0' max='100' value='0' style='display: none;'></progress><br />\n";
$content .= "<output class='action-pageindex-rebuild-latestmessage'></output><br />\n";
$pageindex_rebuild_script = <<<SCRIPT
window.addEventListener("load", function(event) {
document.querySelector(".action-pageindex-rebuild").addEventListener("click", function(event) {
var rebuildActionEvents = new EventSource("?action=pageindex-rebuild");
var latestMessageElement = document.querySelector(".action-pageindex-rebuild-latestmessage");
var progressElement = document.querySelector(".action-pageindex-rebuild-progress");
rebuildActionEvents.addEventListener("message", function(event) {
console.log(event);
let message = event.data;
latestMessageElement.value = event.data;
let parts = message.match(/^\[\s*(\d+)\s+\/\s+(\d+)\s*\]/);
if(parts != null) {
progressElement.style.display = "";
progressElement.min = 0;
progressElement.max = parseInt(parts[2]);
progressElement.value = parseInt(parts[1]);
}
if(message.startsWith("Done!"))
rebuildActionEvents.close();
});
// Close the connection on error & don't try again
rebuildActionEvents.addEventListener("error", (_event) => rebuildActionEvents.close());
});
});
SCRIPT;
page_renderer::add_js_snippet($pageindex_rebuild_script);
$content .= "<h2>Settings</h2>";
$content .= "<p>Mouse over the name of each setting to see a description of what it does.</p>\n";
$content .= "<form action='?action=configure-save' method='post'>\n";
foreach($guiConfig as $configKey => $configData)
{
// Don't display the site secret~!
// Apparently it got lost in translation, but I'll be re-adding
// it again at some point I'm sure - so support for it is
// included here.
if($configKey == "sitesecret") continue;
$reverse = false;
$inputControl = "";
$label = "<label for='setting-$configKey' title=\"$configData->description\" class='cursor-query'>$configKey</label>";
switch($configData->type)
{
case "url":
case "email":
case "number":
case "text":
$inputControl = "<input type='$configData->type' id='$configKey' name='$configKey' value='".htmlentities($settings->$configKey)."' />";
break;
case "textarea":
$inputControl = "<textarea id='$configKey' name='$configKey'>".htmlentities($settings->$configKey)."</textarea>";
break;
case "checkbox":
$reverse = true;
$inputControl = "<input type='checkbox' id='$configKey' name='$configKey' " . ($settings->$configKey ? " checked" : "") . " />";
break;
case "usertable":
$label = "";
if(module_exists("feature-user-table"))
$inputControl = "<p>The users can be managed in the <a href='?action=user-table'>User Table</a>.</p>";
else
$inputControl = "<p><em>The users can be managed in the user table, but the required module <code>feature-user-table</code> is not installed.</em></p>";
break;
default:
$label = "";
$inputControl = "<p><em>Sorry! The <code>".htmlentities($configKey)."</code> setting isn't editable yet through the gui. Please try editing <code>peppermint.json</code> for the time being.</em></p>";
break;
}
$content .= "<div class='setting-configurator'>\n\t";
$content .= $reverse ? "$inputControl\n\t$label" : "$label\n\t$inputControl";
$content .= "\n</div>\n";
}
$content .= "<input type='submit' value='Save Settings' />";
$content .= "</form>\n";
exit(page_renderer::render_main("Master Control Panel - $settings->sitename", $content));
});
/**
* @api {post} ?action=configure-save Save changes to the global wiki settings
* @apiName ConfigureSettings
* @apiGroup Utility
* @apiPermission Moderator
*/
/*
* ██████ ██████ ███ ██ ███████ ██ ██████ ██ ██ ██████ ███████
* ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██
* ██ ██ ██ ██ ██ ██ █████ ██ ██ ███ ██ ██ ██████ █████ █████
* ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
* ██████ ██████ ██ ████ ██ ██ ██████ ██████ ██ ██ ███████
* ███████ █████ ██ ██ ███████
* ██ ██ ██ ██ ██ ██
* ███████ ███████ ██ ██ █████
* ██ ██ ██ ██ ██ ██
* ███████ ██ ██ ████ ███████
*/
add_action("configure-save", function () {
global $env, $settings, $paths, $defaultCSS;
// If the user isn't an admin, then the regular configuration page will display an appropriate error
if(!$env->is_admin)
{
http_response_code(307);
header("location: ?action=configure");
exit();
}
// Build a new settings object
$newSettings = new stdClass();
foreach($settings as $configKey => $rawValue)
{
$configValue = $rawValue;
if(isset($_POST[$configKey]))
{
$decodedConfigValue = json_decode($_POST[$configKey]);
if(json_last_error() === JSON_ERROR_NONE)
$configValue = $decodedConfigValue;
else
$configValue = $_POST[$configKey];
// Convert bool settings to a bool, since POST
// parameters don't decode correctly.
if(is_bool($settings->$configKey))
$configValue = in_array($configValue, [ 1, "on"], true) ? true : false;
// If the CSS hasn't changed, then we can replace it with
// 'auto' - this will ensure that upon update the new
// default CSS will be used. Also make sure we ignore line
// ending nonsense & differences here, since they really
// don't matter
if($configKey === "css" && str_replace("\r\n", "\n", $defaultCSS) === str_replace("\r\n", "\n", $configValue))
$configValue = "auto";
}
$newSettings->$configKey = $configValue;
}
// Take a backup of the current settings file
rename($paths->settings_file, "$paths->settings_file.bak");
// Save the new settings file
file_put_contents($paths->settings_file, json_encode($newSettings, JSON_PRETTY_PRINT));
$content = "<h1>Master settings updated sucessfully</h1>\n";
$content .= "<p>$settings->sitename's master settings file has been updated successfully. A backup of the original settings has been created under the name <code>peppermint.json.bak</code>, just in case. You can <a href='?action=configure'>go back</a> and continue editing the master settings file, or you can go to the <a href='?action=view&page=" . rawurlencode($settings->defaultpage) . "'>" . htmlentities($settings->defaultpage) . "</a>.</p>\n";
$content .= "<p>For reference, the newly generated master settings file is as follows:</p>\n";
$content .= "<textarea name='content'>";
$content .= json_encode($newSettings, JSON_PRETTY_PRINT);
$content .= "</textarea>\n";
exit(page_renderer::render_main("Master Settings Updated - $settings->sitename", $content));
});
/**
* @api {get} ?action=pageindex-rebuild[&format=json] Rebuilds the page index
* @apiName UserList
* @apiGroup Utility
* @apiPermission Anonymous
*/
/* _ _ _ _ _ _
* (_) | | | | (_) | | | |
* _ __ __ _ __ _ ___ _ _ __ __| | ___ __ __ ______ _ __ ___ | |__ _ _ _ | | __| |
* | '_ \ / _` | / _` | / _ \ | | | '_ \ / _` | / _ \ \ \/ / |______| | '__| / _ \ | '_ \ | | | | | | | | / _` |
* | |_) | | (_| | | (_| | | __/ | | | | | | | (_| | | __/ > < | | | __/ | |_) | | |_| | | | | | | (_| |
* | .__/ \__,_| \__, | \___| |_| |_| |_| \__,_| \___| /_/\_\ |_| \___| |_.__/ \__,_| |_| |_| \__,_|
* | | __/ |
* |_| |___/
*
*/
add_action("pageindex-rebuild", function() {
global $env, $settings;
if($env->is_admin ||
(
!empty($_POST["secret"]) &&
$_POST["secret"] === $settings->secret
)
)
pageindex_rebuild();
else
{
http_response_code(401);
exit(page_renderer::render_main("Error - Page index regenerator - $settings->sitename", "<p>Error: You aren't allowed to regenerate the page index. Try logging in as an admin, or setting the <code>secret</code> POST parameter to $settings->sitename's secret - which can be found in $settings->sitename's <code>peppermint.json</code> file.</p>"));
}
});
add_help_section("800-raw-page-content", "Viewing Raw Page Content", "<p>Although you can use the edit page to view a page's source, you can also ask $settings->sitename to send you the raw page source and nothing else. This feature is intented for those who want to automate their interaction with $settings->sitename.</p>
<p>To use this feature, navigate to the page for which you want to see the source, and then alter the <code>action</code> parameter in the url's query string to be <code>raw</code>. If the <code>action</code> parameter doesn't exist, add it. Note that when used on an file's page this action will return the source of the description and not the file itself.</p>");
}
]);
?>