Major changes, see source

This commit is contained in:
Conner Harkness 2025-08-05 08:20:13 -06:00
parent eafc2588dc
commit ecb5c59eb7
30 changed files with 578 additions and 1554 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* text=auto

View File

@ -1,46 +0,0 @@
$(function() {
FormValidator = {};
FormValidator.onError = function(str)
{
alert(str);
console.log(str);
};
FormValidator.validate = function(callback)
{
var pass = 1;
$("[fv-regex]").each(function(i, x) {
if (pass == 0)
return;
x = $(x);
let input = x.val();
let regex = new RegExp(x.attr("fv-regex"), "g");
if (!input.match(regex))
{
x.addClass("border-danger");
x.focus();
x.select();
let warning = x.attr("fv-warning") ?? "Please correct the highlighted input and try again";
FormValidator.onError(warning)
pass = 0;
return;
}
if (pass == 1)
if (typeof callback === "function")
callback();
x.removeClass("border-danger");
});
};
});

View File

@ -1,37 +0,0 @@
div.searchable-input input
{
width: 100%;
box-sizing: border-box;
}
div.searchable-input div.items
{
padding-top: 0.5em;
padding-bottom: 0.5em;
border: 1px solid #aaa;
/*border-top: 0;*/
max-width: 100%;
max-height: 10em;
overflow-x: scroll;
overflow-y: scroll;
position: absolute;
background: #fff;
box-sizing: border-box;
}
div.searchable-input div.item
{
white-space: normal;
padding-left: 0.5em;
padding-right: 0.5em;
user-select: none;
}
div.searchable-input div.item:hover
{
/*background: #0af;
color: #fff;*/
background: highlight;
color: highlighttext;
cursor: pointer;
}

View File

@ -1,206 +0,0 @@
$(function() {
SearchableInput = {};
SearchableInput.initItems = function()
{
var items = $("div.searchable-input div.item");
items.each(function(i, x) {
x = $(x);
var parent = x.parents("div.searchable-input").first();
var input = parent.find("input").first();
var item = x;
var itemContainer = parent.find("div.items").first();
if (item.is("[onclick]"))
return;
if (!item.is("[data-value]"))
return;
item.unbind("mousedown");
item.bind("mousedown", function() {
input.attr("data-value", item.attr("data-value"));
input.val(item.text().trim());
itemContainer.hide();
});
});
};
SearchableInput.init = function()
{
$("div.searchable-input input").each(function(i, x) {
x = $(x);
var parent = x.parents("div.searchable-input").first();
var backgroundColor = null;
var selectColor = null;
var input = x;
var itemContainer = parent.find("div.items").first();
var items = itemContainer.find("div.item");
var strictSearch = parent.attr("strict-search");
// Get first opaque body color:
parent.parents("*").each(function(i, x) {
if (backgroundColor !== null)
return;
x = $(x);
var color = x.css("backgroundColor");
if (/^rgba/.test(color))
{
var alphaPart = parseFloat(color.split(",")[3]);
if (isNaN(alphaPart))
return;
if (alphaPart > 0.9)
backgroundColor = color;
return;
}
if (/^rgb/.test(color))
backgroundColor = color;
});
itemContainer.hide();
x.unbind("blur");
x.bind("blur", function() {
setTimeout(function() {
itemContainer.hide();
if (input.val().trim().length < 1)
input.attr("data-value", null);
}, 10);
});
x.unbind("input");
x.bind("input", function() {
var fnOnInputCooldown = function(itemContainer)
{
var parent = itemContainer.parents("div.searchable-input").first();
var input = parent.find("input").first();
var items = itemContainer.find("div.item");
var searchTermsString = input.val().toLowerCase().trim();
var searchTerms = searchTermsString.split(" ");
items.hide();
items.each(function(i, x) {
x = $(x);
var item = x;
var pass = 1;
var itemText = item.text().toLowerCase().trim();
if (strictSearch)
{
if (itemText.includes(searchTermsString))
item.show();
return;
}
for (var i = 0; i < searchTerms.length; i++)
{
var searchTerm = searchTerms[i];
if (searchTerm.length < 1)
continue;
if (!itemText.includes(searchTerm))
pass = 0;
}
//item.hide();
if (pass == 1)
item.show();
});
};
var dataSourceApi = itemContainer.attr("data-source-api");
if (dataSourceApi)
{
if (typeof(SearchableInput.timeout) !== "undefined")
clearTimeout(SearchableInput.timeout);
SearchableInput.timeout = setTimeout(function() {
var searchTermsString = input.val().toLowerCase().trim();
console.log(dataSourceApi);
$.get({
url: `${dataSourceApi}?q=${searchTermsString}`,
//url: `${dataSourceApi}`,
method: "get",
success: function(data)
{
console.log(data);
itemContainer.html("");
for (var i = 0; i < data.length; i++)
{
var item = data[i];
var itemElement = $("<div></div>");
itemElement.addClass("item");
itemElement.attr("data-value", item.value);
itemElement.html(item.name);
itemContainer.append(itemElement);
}
SearchableInput.initItems();
fnOnInputCooldown(itemContainer);
},
error: function(xhr, e, m)
{
console.log(e);
console.log(m);
}
});
}, 1000);
}
fnOnInputCooldown(itemContainer);
});
x.unbind("focus");
x.bind("focus", function() {
//x.trigger("input");
itemContainer.css("width", parent.width() + "px");
itemContainer.css("background", backgroundColor);
// If data-source is a valid jQuery selector, use that container's innerHTML:
var dataSource = itemContainer.attr("data-source");
if (dataSource)
{
var dataSourceObject = $(dataSource);
if (dataSourceObject.length > 0)
{
itemContainer.html(dataSourceObject.first().html());
//SearchableInput.init();
SearchableInput.initItems();
}
}
itemContainer.show();
items.show();
input.select();
});
SearchableInput.initItems();
});
};
SearchableInput.init();
});

View File

@ -1,61 +1,22 @@
<?php
global $c;
$varUser = UserAuth::getUser();
$varFooterLinks2 = $c->query("SELECT * from links where position like 'footer' order by sort");
$varFooterLinks = [];
$strDefaults =
"---
foreach ($varFooterLinks2 as $varLink)
{
if (UserAuth::visible($varLink["visibility"]))
$varFooterLinks[] = $varLink;
}
Copyright ©
* [Website Home](/)
* [Post](/post)
* [CSS](/edit/css)";
$strDefaults = preg_replace("/[ ]{4,}/", "", $strDefaults);
$strContent = Settings::get("footer", $strDefaults, true);
?>
<div class="mb-5">
<hr />
<?php
$strSidebarContent = Settings::get("footer_content", "Copyright ©", true);
?>
<?php if (strlen($strSidebarContent) > 0): ?>
<div class="container">
<div class="row">
<div class="col-lg-8">
<div>
<?php if (strlen($strContent) > 0): ?>
<div class="footer-content">
<?php
$varParsedown = new Parsedown();
echo $varParsedown->text($strSidebarContent);
echo $varParsedown->text($strContent);
?>
</div>
</div>
</div>
</div>
<?php endif; ?>
<?php if (count($varFooterLinks) > 0): ?>
<div class="container">
<div class="row">
<div class="col-lg-4">
<?php foreach ($varFooterLinks as $varLink): ?>
<div>
<a class="link-underline link-underline-opacity-0" href="<?= $varLink["url"]; ?>"><i class="fa fa-fw fa-<?= $varLink["icon"]; ?> pe-2"></i> <?= $varLink["label"]; ?></a>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<?php endif; ?>
</div>
<script>
$(function() {
$("input, textarea").each(function(i, x) {
x = $(x);
x.attr("autocomplete", "0");
x.attr("autocorrect", "0");
x.attr("autocapitalize", "0");
x.attr("spellcheck", "false");
});
});
</script>

View File

@ -1,26 +1,29 @@
<meta name="viewport" content="initial-scale=1, width=device-width" />
<!-- Bootstrap -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" ></script>
<!-- JQuery -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<!-- FontAwesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/js/all.min.js"></script>
<!-- SearchableInput -->
<link rel="stylesheet" href="/files/SearchableInput/SearchableInput.css" />
<script src="/files/SearchableInput/SearchableInput.js"></script>
<!-- FormValidator -->
<script src="/files/FormValidator/FormValidator.js"></script>
<style>
/* https://github.com/twbs/bootstrap/issues/37184 */
.dropdown-menu {
z-index: 1040 !important;
}
<?php
$strDefaults = "
/* Put in your custom CSS here: */
.header-content { margin-bottom: 3em; }
.footer-content { margin-top: 3em; }
html { background: #aaa; font-family: Georgia; }
body { max-width: 7in; margin: 0 auto; padding: 3em; background: #fff; }
hr { border: none; background: #aaa; min-height: 1px; }
textarea { width: 100%; min-width: 100%; max-width: 100%; min-height: 3in; margin-bottom: 0.5em; }
.message-danger { background: #f00; color: #fff; padding: 0.5em; }
.message-warning { background: #fd0; color: #000; padding: 0.5em; }
.message-success { background: #070; color: #fff; padding: 0.5em; }
.message-info { background: #0df; color: #000; padding: 0.5em; }
.post-container { margin-top: 3em; margin-bottom: 3em; }
.post-container > hr { border: 0; background: none; border-bottom: 2px dotted #aaa; margin-top: 3em; margin-bottom: 3em; }
.post img { max-width: 2in; }
table { margin-bottom: 1em; }
a[href], a[href]:visited { color: #07a; text-decoration: none; }
a[href]:hover { text-decoration: underline; }
";
$strDefaults = preg_replace("/[ ]{4,}/", "", $strDefaults);
$strContent = Settings::get("css", $strDefaults, true);
echo $strContent;
?>
</style>

View File

@ -1,92 +1,20 @@
<?php
global $c;
$varUser = UserAuth::getUser();
$varNavbarLinks = $c->query("SELECT * from links where position like 'navbar' order by sort");
$varSidebarLinks = $c->query("SELECT * from links where position like 'sidebar' order by sort");
$varFirstNavbarLink = array_shift($varNavbarLinks);
$strDefaults =
"[Website Home](/) —
[Post](/post) ·
[CSS](/edit/css)
---";
$strDefaults = preg_replace("/[ ]{4,}/", "", $strDefaults);
$strContent = Settings::get("header", $strDefaults, true);
?>
<script>
// Make the page's theme dark:
$("body").first().attr("data-bs-theme", "dark");
</script>
<div class="offcanvas offcanvas-start" id="sidebar">
<div class="offcanvas-body">
<?php
$strSidebarContent = Settings::get("sidebar_content", "#### Sidebar Navigation", true);
?>
<?php if (strlen($strSidebarContent) > 0): ?>
<div class="mt-5">
<?php if (strlen($strContent) > 0): ?>
<div class="header-content">
<?php
$varParsedown = new Parsedown();
echo $varParsedown->text($strSidebarContent);
echo $varParsedown->text($strContent);
?>
</div>
<?php endif; ?>
<?php foreach ($varSidebarLinks as $varLink): ?>
<?php if (!UserAuth::visible($varLink["visibility"])) continue; ?>
<div class="mb-2">
<a class="btn btn-outline-secondary w-100" href="<?= $varLink["url"]; ?>"><i class="fa fa-fw fa-<?= $varLink["icon"]; ?> pe-2"></i> <?= $varLink["label"]; ?></a>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="navbar navbar-expand bg-secondary d-flex px-3">
<div class="container justify-content-between">
<div class="navbar-nav d-inline-flex align-items-center">
<div class="navbar-nav d-inline-flex">
<a class="btn btn-secondary me-2" data-bs-toggle="offcanvas" data-bs-target="#sidebar">&nbsp; <i class="fa fa-fw fa-bars"></i> &nbsp;</a>
</div>
<a class="navbar-brand" href="<?= $varFirstNavbarLink["url"]; ?>"><?= $varFirstNavbarLink["label"]; ?></a>
<div class="dropdown d-lg-none">
<a class="btn btn-secondary dropdown-toggle" data-bs-toggle="dropdown">...</a>
<div class="dropdown-menu">
<?php foreach ($varNavbarLinks as $varLink): ?>
<?php if (!UserAuth::visible($varLink["visibility"])) continue; ?>
<a class="dropdown-item" href="<?= $varLink["url"]; ?>"><i class="fa fa-fw fa-<?= $varLink["icon"]; ?> pe-2"></i> <?= $varLink["label"]; ?></a>
<?php endforeach; ?>
</div>
</div>
<?php foreach ($varNavbarLinks as $varLink): ?>
<?php if (!UserAuth::visible($varLink["visibility"])) continue; ?>
<a class="nav-link d-none d-lg-inline" href="<?= $varLink["url"]; ?>"><?= $varLink["label"]; ?></a>
<?php endforeach; ?>
</div>
<div class="navbar-nav d-inline-flex align-items-center">
<div class="dropdown">
<a class="btn btn-secondary dropdown-toggle h-100" data-bs-toggle="dropdown"><i class="fa fa-fw fa-user"></i> &nbsp;</a>
<div class="dropdown-menu dropdown-menu-end">
<?php if ($varUser !== null): ?>
<a class="dropdown-item" href="/user/info"><i class="fa fa-fw fa-user pe-2"></i> <?= $varUser["username"]; ?></a>
<a class="dropdown-item" href="/user/signout"><i class="fa fa-fw fa-right-from-bracket pe-2"></i> Sign Out</a>
<?php else: ?>
<a class="dropdown-item" href="/user/signin"><i class="fa fa-fw fa-right-to-bracket pe-2"></i> Sign In</a>
<a class="dropdown-item" href="/user/register"><i class="fa fa-fw fa-user-plus pe-2"></i> Register</a>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>

View File

@ -20,28 +20,5 @@
"create_links_table.sql",
"create_posts_table.sql",
"create_settings_table.sql"]);
$varLinks = $c->query("SELECT * from links");
if (count($varLinks) < 1)
{
$c->query(
"INSERT into links (label, url, icon, position, visibility)
values
('Home', '/', 'home', 'navbar', ''),
('Post', '/post', 'edit', 'navbar', 'user'),
('Home', '/', 'home', 'sidebar', ''),
('Edit Links', '/edit/links', 'link', 'sidebar', 'admin'),
('Edit CSS', '/settings/css', 'code', 'sidebar', 'admin'),
('Edit JS', '/settings/js', 'code', 'sidebar', 'admin'),
('Edit sidebar content', '/settings/sidebar_content', 'comment', 'sidebar', 'admin'),
('Edit footer content', '/settings/footer_content', 'comment', 'sidebar', 'admin'),
('Go home', '/', 'home', 'footer', ''),
('Search', '/search', 'search', 'footer', '')"
);
}
}
?>

View File

@ -1,140 +0,0 @@
<?php
class BootstrapRender
{
public static function message()
{
if (func_num_args() > 0)
{
Cookie::set("message", func_get_arg(0));
if (func_num_args() > 1)
Cookie::set("messageClass", func_get_arg(1));
return;
}
$strMessage = Cookie::get("message");
$strMessageClass = Cookie::get("messageClass");
if (!isset($strMessageClass) || $strMessageClass == null || strlen($strMessageClass) < 1)
$strMessageClass = "info";
?>
<div id="page-message-container">
<?php if (isset($strMessage) && $strMessage !== null && strlen($strMessage) > 0): ?>
<div class="alert alert-<?= $strMessageClass; ?> d-none" id="page-message">
<?= $strMessage; ?>
</div>
<script>
$(function() {
$("#page-message")
.hide()
.removeClass("d-none")
.fadeIn();
});
</script>
<?php endif; ?>
</div>
<script>
$(function() {
BootstrapRender = {};
BootstrapRender.message = function(message, messageClass = "info") {
var messageElem = $("<div></div>");
messageElem.addClass(`alert alert-${messageClass} d-none`);
messageElem.attr("id", "page-message");
messageElem.html(message);
$("#page-message-container")
.empty()
.append(messageElem);
messageElem
.hide()
.removeClass("d-none")
.fadeIn();
return messageElem;
};
});
</script>
<?php
Cookie::set("message");
Cookie::set("messageClass");
}
public static function input($varOptions)
{
$varOptions["tag"] = $varOptions["tag"] ?? "input";
$varOptionsExtras = $varOptions;
$varDefaultKeys = ["tag", "label", "name", "type", "value", "hint"];
foreach ($varDefaultKeys as $k)
if (array_key_exists($k, $varOptionsExtras))
unset($varOptionsExtras[$k]);
?>
<div class="mb-3">
<label class="form-label"><?= $varOptions["label"] ?? $varOptions["name"] ?? "input"; ?></label>
<<?= $varOptions["tag"]; ?>
type="<?= $varOptions["type"] ?? "text"; ?>"
class="form-control"
name="<?= $varOptions["name"] ?? "text"; ?>"
placeholder="Enter <?= $varOptions["label"] ?? "value"; ?>"
<?php if ($varOptions["tag"] !== "textarea"): ?>
value="<?= $varOptions["value"] ?? ""; ?>"
<?php endif; ?>
<?php foreach ($varOptionsExtras as $k => $v): ?>
<?= $k; ?>="<?= $v; ?>"
<?php endforeach; ?>
/><?= $varOptions["tag"] == "textarea"? "{$varOptions["value"]}</textarea>" : ""; ?>
<small class="text-muted"><?= $varOptions["hint"] ?? ""; ?></small>
</div>
<?php
}
public static function button($varOptions)
{
$varOptions["tag"] = $varOptions["tag"] ?? "a";
$varOptionsExtras = $varOptions;
$varDefaultKeys = ["tag", "label", "name", "type", "value", "hint"];
foreach ($varDefaultKeys as $k)
if (array_key_exists($k, $varOptionsExtras))
unset($varOptionsExtras[$k]);
?>
<<?= $varOptions["tag"]; ?>
class="btn btn-<?= $varOptions["class"] ?? "secondary"; ?>"
<?php foreach ($varOptionsExtras as $k => $v): ?>
<?= $k; ?>="<?= $v; ?>"
<?php endforeach; ?>
>
<?php if (array_key_exists("icon", $varOptions)): ?>
<i class="fa fa-fw fa-<?= $varOptions["icon"]; ?>"></i>
<?php endif; ?>
<?= $varOptions["label"] ?? "Button"; ?>
</<?= $varOptions["tag"]; ?>>
<?php
}
public static function buttons($varButtons)
{
?>
<div class="mb-3">
<label class="form-label">Actions</label>
<div>
<?php foreach ($varButtons as $b): ?>
<?php BootstrapRender::button($b); ?>
<?php endforeach; ?>
</div>
</div>
<?php
}
}
?>

69
lib/PageRender.php Normal file
View File

@ -0,0 +1,69 @@
<?php
class PageRender
{
public static function message()
{
if (func_num_args() > 0)
{
Cookie::set("message", func_get_arg(0));
if (func_num_args() > 1)
Cookie::set("messageClass", func_get_arg(1));
return;
}
$strMessage = Cookie::get("message");
$strMessageClass = Cookie::get("messageClass");
if (!isset($strMessageClass) || $strMessageClass == null || strlen($strMessageClass) < 1)
$strMessageClass = "info";
?>
<?php if (isset($strMessage) && $strMessage !== null && strlen($strMessage) > 0): ?>
<p class="message message-<?= $strMessageClass; ?>">
<?= $strMessage; ?>
</p>
<?php endif; ?>
<?php
Cookie::set("message");
Cookie::set("messageClass");
}
public static function uploads()
{
$varUploads = [];
try
{
$varUploads = scandir("files");
if ($varUploads !== false)
{
$varUploads = array_diff($varUploads, [".", ".."]);
rsort($varUploads);
}
}
catch (Exception $x) {}
$varUploads = array_slice($varUploads, 0, 20);
?>
<div class="uploads">
<div>
<label>Uploads</label>
</div>
<ul>
<li><a href="/upload" target="_blank">Manage</a></li>
<?php foreach ($varUploads as $u): ?>
<li><a href="/files/<?= $u; ?>" target="_blank">/files/<?= $u; ?></a></li>
<?php endforeach; ?>
</ul>
</div>
<?php
}
}
?>

View File

@ -8,33 +8,35 @@
$intRenderedRows = 0;
?>
<style>
<?php
echo Settings::get(
"css",
"/* Put in your custom CSS here: */\nblockquote {\n padding: 1em;\n background:\n rgba(127, 127, 127, 0.2);\n border-left: 3px solid rgba(127, 127, 127, 0.2); \n}",
true);
?>
</style>
<div class="post-container">
<?php foreach ($varRows as $r): ?>
<?php if (!UserAuth::visible($r["visibility"])) continue; ?>
<div class="container my-5">
<div class="row">
<div class="col-lg-8">
<div class="xborder xborder-secondary xrounded xp-3">
<?php if ($intRenderedRows > 0): ?>
<hr />
<?php endif; ?>
<div class="post">
<div class="post-body">
<?php echo $varParsedown->text($r["content"]); ?>
</div>
<hr />
<div class="text-muted">
<div>by <?= $r["username"]; ?></div>
<div>on <?= $r["created"]; ?> UTC</div>
</div>
<?php if (UserAuth::has("is_admin")): ?>
<div>
<a class="link-underline link-underline-opacity-0" href="/post/<?= $r["id"]; ?>"><i class="fa fa-fw fa-edit"></i> Edit</a>
</div>
<div class="post-footer">
<div class="post-author">by <?= $r["username"]; ?></div>
<div class="post-date">on <?= $r["created"]; ?> UTC</div>
<div class="post-links">
<a href="/<?= $r["id"]; ?>">Permalink</a> &middot;
<a href="<?= $r["location"]; ?>">Related</a>
<?php
$intOwnership =
UserAuth::has("is_admin") ||
$varUser["username"] == $r["username"];
?>
<?php if ($intOwnership): ?>
&middot; <a href="/post/<?= $r["id"]; ?>">Edit</a>
<?php endif; ?>
</div>
</div>
@ -44,24 +46,9 @@
<?php endforeach; ?>
<?php if ($intRenderedRows < 1): ?>
<div class="container my-5">
<div class="row">
<div class="col-lg-8">
<p>Sorry, there is nothing here to show.</p>
</div>
</div>
</div>
<div>Sorry, there is nothing here to show.</div>
<?php endif; ?>
<script>
<?php
echo Settings::get(
"js",
"$(function() {\n // My script here.\n});",
true);
?>
</script>
</div>
<?php
}
}

View File

@ -1,264 +0,0 @@
<?php
class TableEditor
{
public static function render($strTableName, $varColumns)
{
global $c;
$varRows = [];
$varKeys = [];
try
{
$varRows = $c->query("SELECT * from {$strTableName} order by sort asc");
}
catch (Exception $x)
{
$varRows = $c->query("SELECT * from {$strTableName}");
}
$strInput = file_get_contents("php://input");
if (strlen($strInput) > 0)
{
$a = json_decode($strInput, true);
$output = [];
foreach ($a as $r)
{
$strColumns = "";
$strQMarks = "";
$strSetLns = "";
$varValues = [];
foreach ($varColumns as $strCol)
{
$strColumns .= "{$strCol}, ";
$strQMarks .= "?, ";
$strSetLns .= "{$strCol} = ?, ";
$varValues[] = $r[$strCol];
}
$strColumns = preg_replace("/, $/", "", $strColumns);
$strQMarks = preg_replace("/, $/", "", $strQMarks);
$strSetLns = preg_replace("/, $/", "", $strSetLns);
if (strlen($r["id"]) < 1)
{
$c->query(
"INSERT into {$strTableName} ({$strColumns}) values ({$strQMarks})",
$varValues);
continue;
}
if (intval($r["delete"]) == 1)
{
$c->query("DELETE from {$strTableName} where id = ?", $r["id"]);
continue;
}
$c->query(
"UPDATE {$strTableName}
set {$strSetLns}
where id = ?",
$varValues,
$r["id"]);
$output[] = $r;
}
Respond::json(["message" => "success", "output" => $output]);
}
?>
<div class="navbar navbar-expand bg-body-tertiary d-flex px-3 sticky-top">
<div class="container justify-content-between">
<div class="navbar-nav d-inline-flex">
<span class="navbar-brand">Options</span>
<a class="btn btn-outline-success" onclick="fnSave();"><i class="fa fa-fw fa-save"></i> Save</a>
</div>
<div class="navbar-nav d-inline-flex">
</div>
</div>
</div>
<style>
/* https://github.com/twbs/bootstrap/issues/37184 */
.dropdown-menu {
z-index: 1040 !important;
}
/*
th:first-child,
th:last-child {
width: 7.5%;
background: #F00 !important;
}*/
.table-responsive {
overflow-x: scroll;
}
.w-input {
width: 15em !important;
}
tr td:first-child input[type="text"]
{
width: 5em !important;
}
</style>
<div class="container">
<div class="row my-5">
<div class="col-lg-12">
<?php if (count($varRows) > 0): ?>
<div class="table-responsive">
<table class="table table-borderless">
<thead>
<tr>
<?php foreach($varRows[0] as $k => $v): ?>
<?php
if ($k == "sort")
continue;
$varKeys[] = $k;
?>
<th><?= $k; ?></th>
<?php endforeach; ?>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($varRows as $r): ?>
<tr>
<?php foreach ($varKeys as $k): ?>
<td>
<div class="input-group">
<input type="text" class="form-control w-input" name="<?= $k; ?>" value="<?= $r[$k]; ?>" />
</div>
</td>
<?php endforeach; ?>
<td class="align-middle text-nowrap">
<input type="hidden" name="delete" value="0" />
<a class="" onclick="fnCloneRow(this);"><i class="fa fa-fw fa-copy"></i></a>
<a class="" onclick="fnDeleteRow(this);"><i class="fa fa-fw fa-trash"></i></a>
<?php if (in_array("sort", $varColumns)): ?>
<a class="" onclick="fnMoveRowUp(this);"><i class="fa fa-fw fa-arrow-up"></i></a>
<a class="" onclick="fnMoveRowDown(this);"><i class="fa fa-fw fa-arrow-down"></i></a>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
</div>
<script>
$(function() {
$("[name='id']").each(function(i, x) {
x = $(x);
x.attr("readonly", 1);
});
fnSerialize = function() {
var a = [];
var sort = 0;
$("table tbody tr").each(function(i, x) {
x = $(x);
var inputs = x.find("input");
var o = {};
inputs.each(function(i2, x2) {
x2 = $(x2);
var key = x2.attr("name");
var value = x2.val();
o[key] = value;
});
o["sort"] = sort;
a.push(o);
sort++;
});
console.log(a);
return a;
};
fnSave = function()
{
var data = fnSerialize();
$.ajax({
url: "",
method: "post",
data: JSON.stringify(data),
success: function(r)
{
console.log(r);
window.location.href = window.location.href;
}
});
};
fnCloneRow = function(x)
{
x = $(x);
var row = x.parents("tr").first();
var rowCopy = row.clone();
rowCopy.insertAfter(row);
rowCopy.find("input").each(function(i, x2) {
x2 = $(x2);
x2.val("");
});
};
fnDeleteRow = function(x)
{
x = $(x);
var row = x.parents("tr").first();
row.hide();
row.find("[name='delete']").first().val("1");
};
fnMoveRowUp = function(x)
{
x = $(x);
var row = x.parents("tr").first();
row.insertBefore(row.prev());
}
fnMoveRowDown = function(x)
{
x = $(x);
var row = x.parents("tr").first();
row.insertAfter(row.next());
}
});
</script>
<?php
}
}
?>

View File

@ -50,7 +50,7 @@
{
if (!UserAuth::has($strColumnName))
{
BootstrapRender::message("You do not have permission to do that, please sign into an account that does.", "warning");
PageRender::message("You do not have permission to do that, please sign into an account that does.", "warning");
Respond::redirect("/user/signin");
}
}
@ -82,6 +82,9 @@
$strVisibility = $strVisibility["visibility"];
}
if ($strVisibility == null)
$strVisibility = "";
// Handle hiding the post from non-admins:
if (preg_match("/^(admin|hid(e|den)|invisible|no(ne|body)|private)$/i", $strVisibility))
return false;

View File

@ -1,46 +1,17 @@
<?php
global $c;
$varPostLocations = $c->query("SELECT distinct location from posts order by location");
$varLinks = $c->query("SELECT * from links order by sort");
?>
<div class="navbar navbar-expand bg-body-tertiary d-flex px-3 sticky-top">
<div class="container justify-content-between">
<div class="navbar-nav d-inline-flex align-items-center">
<span class="navbar-brand">Directory</span>
<div>
<label>Directory</label>
</div>
<div class="navbar-nav d-inline-flex">
</div>
</div>
</div>
<div class="container my-5">
<div class="row mb-4">
<div class="col-lg-6">
<h5 class="mb-3"><i class="fa fa-fw fa-comment pe-2"></i> Posts</h5>
<ul>
<?php foreach ($varPostLocations as $i): ?>
<?php
$intPostCount = $c->query("SELECT count(*) as c from posts where location = ?", $i["location"])[0]["c"];
?>
<div class="border p-2 mb-2">
<a class="link-underline link-underline-opacity-0" href="<?= $i["location"]; ?>"><i class="fa fa-fw fa-file pe-2"></i> <?= $i["location"]; ?></a>
<small class="text-muted">&mdash; <?= $intPostCount !== 1? "{$intPostCount} posts": "{$intPostCount} post"; ?></small>
</div>
<li><a href="<?= $i["location"]; ?>"><?= $i["location"]; ?></a> <small>&mdash; <?= $intPostCount !== 1? "{$intPostCount} posts": "{$intPostCount} post"; ?></small></li>
<?php endforeach; ?>
</div>
</div>
<div class="row mb-4">
<div class="col-lg-6">
<h5 class="mb-3"><i class="fa fa-fw fa-link pe-2"></i> Links</h5>
<?php foreach ($varLinks as $i): ?>
<?php if (!UserAuth::visible($i["visibility"])) continue; ?>
<div class="border p-2 mb-2">
<a class="link-underline link-underline-opacity-0" href="<?= $i["url"]; ?>"><i class="fa fa-fw fa-<?= $i["icon"]; ?> pe-2"></i> <?= $i["label"]; ?></a>
<small class="text-muted">&mdash; <?= $i["position"]; ?></small>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
</ul>

59
pages/edit.php Normal file
View File

@ -0,0 +1,59 @@
<?php
global $c;
UserAuth::require("is_admin");
$varUser = UserAuth::getUser();
$strId = Request::getArg(0);
// if ($strId == null || strlen($strId) < 1)
// $strId = "none";
if (Request::posts("content"))
Settings::set($strId, Request::getPosted("content"));
$strContent = Settings::get($strId, "");
?>
<?php if ($strId == null || strlen($strId) < 1): ?>
<?php $varRows = Settings::get(); ?>
<div>
<label>Edit</label>
</div>
<ul>
<?php foreach ($varRows as $k => $v): ?>
<li><a href="/edit/<?= $k; ?>"><?= $k; ?></a></li>
<?php endforeach; ?>
</ul>
<?php else: ?>
<style>
textarea {
font-family: monospace;
}
</style>
<form method="post">
<div>
<label><?= $strId; ?></label>
</div>
<div>
<textarea
class="form-control border-0 shadow-none"
name="content"
placeholder="Enter content here..."
oninput="fnResize(this);"
autocomplete="off"
autocorrect="off"
autocapitalize="off"
spellcheck="false"><?= $strContent; ?></textarea>
</div>
<div><input type="submit" value="Save" /></div>
</form>
<?php endif; ?>

View File

@ -1,5 +0,0 @@
<?php
global $c;
UserAuth::require("is_admin");
TableEditor::render("links", ["label", "url", "icon", "position", "visibility", "sort"]);
?>

View File

@ -1,71 +0,0 @@
<?php
global $c;
UserAuth::require("is_admin");
$varUser = UserAuth::getUser();
$strId = Request::getArg(0);
if ($strId == null || strlen($strId) < 1)
$strId = "none";
if (Request::posts("content"))
Settings::set($strId, Request::getPosted("content"));
$strContent = Settings::get($strId, "");
?>
<style>
textarea {
font-family: monospace;
}
</style>
<form method="post">
<div class="navbar navbar-expand bg-body-tertiary d-flex px-3 sticky-top">
<div class="container justify-content-between">
<div class="navbar-nav d-inline-flex align-items-center">
<span class="navbar-brand">Setting</span>
<span class="nav-item text-nowrap me-2">Name</span>
<input class="form-control me-2" type="text" name="location" value="<?= $strId; ?>" readonly disabled />
<a class="btn btn-outline-success text-nowrap" onclick="fnSave();"><i class="fa fa-fw fa-save"></i> Save</a>
</div>
<div class="navbar-nav d-inline-flex">
<?php BootstrapRender::message(); ?>
</div>
</div>
</div>
<?php /**/ ?>
<div class="container my-5">
<div class="row">
<textarea
class="form-control border-0 shadow-none"
name="content"
placeholder="Enter content here..."
oninput="fnResize(this);"
autocomplete="off"
autocorrect="off"
autocapitalize="off"
spellcheck="false"><?= $strContent; ?></textarea>
</div>
</div>
</form>
<script>
$(function() {
fnSave = function() {
$("form").first().submit();
};
fnResize = function(x) {
x.style.height = "auto";
x.style.height = x.scrollHeight + "px";
};
fnResize($("textarea").first()[0]);
});
</script>

View File

@ -1,163 +0,0 @@
<?php
global $c;
UserAuth::require("is_admin");
$varUser = UserAuth::getUser();
$varRows = Settings::get();
$strInput = file_get_contents("php://input");
if (strlen($strInput) > 0)
{
$a = json_decode($strInput, true);
$output = [];
foreach ($a as $r)
{
$strSetting = $r["setting"];
$strValue = $r["value"];
Settings::set($strSetting, $strValue);
}
Respond::json(["message" => "success", "output" => $output]);
}
?>
<div class="navbar navbar-expand bg-body-tertiary d-flex px-3 sticky-top">
<div class="container justify-content-between">
<div class="navbar-nav d-inline-flex">
<span class="navbar-brand">Options</span>
<a class="btn btn-outline-success" onclick="fnSave();"><i class="fa fa-fw fa-save"></i> Save</a>
</div>
<div class="navbar-nav d-inline-flex">
</div>
</div>
</div>
<style>
/* https://github.com/twbs/bootstrap/issues/37184 */
.dropdown-menu {
z-index: 1040 !important;
}
/*
th:first-child,
th:last-child {
width: 7.5%;
background: #F00 !important;
}*/
.w-1 { width: 1%; }
.table-responsive {
overflow-x: scroll;
}
.w-input {
width: 15em !important;
}
tr td:first-child input[type="text"]
{
width: 5em !important;
}
</style>
<div class="container">
<div class="row my-5">
<div class="col-lg-12">
<?php if (count($varRows) > 0): ?>
<div class="table-responsive">
<table class="table table-borderless">
<thead>
<tr>
<th>Setting</th>
<th>Value<th>
</tr>
</thead>
<tbody>
<?php foreach ($varRows as $k => $v): ?>
<tr>
<td>
<div class="input-group">
<input type="text" class="form-control w-input" name="setting" value="<?= $k; ?>" />
</div>
</td>
<td>
<?php
$strClass = "";
if (preg_match("/\n/", $v))
$strClass = "disabled readonly";
?>
<div class="input-group">
<input type="text" class="form-control w-input <?= $strClass; ?>" name="value" value="<?= $v; ?>" <?= $strClass; ?> />
</div>
<div>
<small>
<a class="link-underline link-underline-opacity-0" href="/edit/setting/<?= $k; ?>">Edit in multi-line editor</a>
</small>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
</div>
<script>
$(function() {
$("[name='setting']").each(function(i, x) {
x = $(x);
x.attr("readonly", 1);
});
fnSerialize = function() {
var a = [];
$("table tbody tr").each(function(i, x) {
x = $(x);
var valueInput = x.find("[name='value']").first();
var o = {};
o["setting"] = x.find("[name='setting']").first().val().trim();
o["value"] = valueInput.val();
if (valueInput.attr("disabled"))
return;
a.push(o);
});
console.log(a);
return a;
};
fnSave = function()
{
var data = fnSerialize();
$.ajax({
url: "",
method: "post",
data: JSON.stringify(data),
success: function(r)
{
console.log(r);
window.location.href = window.location.href;
}
});
};
});
</script>

82
pages/find.php Normal file
View File

@ -0,0 +1,82 @@
<?php
global $c;
$strPath = "/";
$strPath .= implode("/", Request::getPathParts());
$varPosts = [];
$strQuery = Request::getParam("q");
$strAuthor = Request::getParam("username");
$strId = Request::getParam("id");
$intHasQuery = $strQuery !== null && strlen($strQuery) > 0;
$intHasAuthor = $strAuthor !== null && strlen($strAuthor) > 0;
$intHasId = $strId !== null && strlen($strId) > 0;
if ($intHasQuery)
{
$strQuery = preg_replace("/[^A-Za-z0-9]/", "", $strQuery);
$varPosts = $c->query(
"SELECT *
from posts as p
where
content like concat('%', ?, '%')
order by
created desc",
$strQuery);
$i = 0;
for ($i = 0; $i < count($varPosts); $i++)
{
$varOld = $varPosts[$i];
$varOld["content"] = preg_replace("/({$strQuery})/i", "<mark>$1</mark>", $varOld["content"]);
$varPosts[$i] = $varOld;
}
}
if ($intHasAuthor)
{
$varPosts = $c->query(
"SELECT *
from posts as p
where
username like ?
order by
created desc",
$strAuthor);
}
if ($intHasId)
{
$varPosts = $c->query(
"SELECT *
from posts as p
where
id = ?
order by
created desc",
$strId);
}
?>
<?php if (!$intHasAuthor && !$intHasId): ?>
<form method="get">
<table>
<tbody>
<tr>
<td><label>Search</label></td>
<td><input type="text" name="q" value="<?= $strQuery; ?>" /></td>
<td>
<input type="submit" value="Go" />
</td>
</tr>
</tbody>
</table>
</form>
<?php endif; ?>
<?php if ($intHasQuery || $intHasAuthor || $intHasId): ?>
<?php PostRender::rows($varPosts); ?>
<?php endif; ?>

View File

@ -1,9 +1,38 @@
<?php
global $c;
$strPath = "/";
$strPath .= implode("/", Request::getPathParts());
$strArg1 = substr(Request::getPath(), 1);
$varPosts = [];
// Get one post by its id:
if (preg_match("/^[0-9]{1,}$/", $strArg1))
{
$varPosts = $c->query(
"SELECT *
from posts as p
where
id = ?
order by
created desc",
intval($strArg1));
}
// Get many post by its author:
if (preg_match("/^\@[A-Za-z0-9]{1,}$/", $strArg1))
{
$strArg1 = substr($strArg1, 1);
$varPosts = $c->query(
"SELECT *
from posts as p
where
username like ?
order by
created desc",
$strArg1);
}
if (count($varPosts) < 1)
{
$varPosts = $c->query(
"SELECT *
from posts as p
@ -12,7 +41,8 @@
or location like '*'
order by
created desc",
$strPath);
Request::getPath());
}
?>
<?php PostRender::rows($varPosts); ?>

View File

@ -18,7 +18,7 @@
if (count($varRows) !== 1)
{
BootstrapRender::message("Zero or more than one row returned", "danger");
PageRender::message("Zero or more than one row returned", "danger");
Respond::redirect("/post");
}
@ -26,6 +26,13 @@
$strContent = $varRow["content"];
$strLocation = $varRow["location"];
$strVisibility = $varRow["visibility"];
if (!UserAuth::has("is_admin"))
if ($varUser["username"] !== $varRow["username"])
{
PageRender::message("You are not the author of that post.");
Respond::redirect("/post");
}
}
@ -46,12 +53,15 @@
$strVisibility);
$strId = $c->query("get_last_post.sql")[0]["id"];
PageRender::message("Post created.", "success");
Respond::redirect("/{$strId}");
}
if (strlen($strContent) < 1)
{
$c->query("DELETE from posts where id = ?", $strId);
BootstrapRender::message("Post deleted successfully.", "success");
PageRender::message("Post deleted successfully.", "success");
Respond::redirect("/post");
}
@ -69,11 +79,13 @@
$strVisibility,
$strId);
BootstrapRender::message("Post saved.", "success");
PageRender::message("Post saved.", "success");
Respond::redirect("/post/{$strId}");
}
?>
<?php PageRender::message(); ?>
<style>
textarea {
font-family: monospace;
@ -81,102 +93,54 @@
</style>
<form method="post">
<div class="navbar navbar-expand bg-body-tertiary d-flex px-3 sticky-top">
<div class="container justify-content-between">
<div class="navbar-nav d-inline-flex align-items-center">
<span class="navbar-brand"><?= $strVerb; ?> Post</span>
<div>
<div>
<label>Content</label>
</div>
<div class="navbar-nav d-inline-flex">
</div>
</div>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-3">
<?php BootstrapRender::message(); ?>
</div>
<div class="col-lg-12">
<div class="mb-3">
<label class="form-label">Content</label>
<div>
<textarea
class="form-control"
name="content"
placeholder="Enter markdown content here..."
oninput="fnResize(this);"
><?= $strContent; ?></textarea>
<small class="text-muted">Test</small>
</div>
</div>
<div class="col-lg-3">
<div class="mb-3">
<label class="form-label">Location</label>
<div>
<table>
<tbody>
<tr>
<td><label>Location</label></td>
<td>
<input
type="text"
class="form-control"
name="location"
placeholder="/"
value="<?= $strLocation; ?>"
fv-regex="^\/"
fv-warning="Location must start with a forward slash" />
<small class="text-muted">e.g. /home or /info</small>
</div>
</div>
value="<?= $strLocation; ?>" />
</td>
</tr>
<div class="col-lg-3">
<div class="mb-3">
<label class="form-label">Visible To</label>
<tr>
<td><label>Visible To</label></td>
<td>
<input
type="text"
class="form-control"
name="visibility"
placeholder="everyone"
value="<?= $strVisibility; ?>"
fv-regex="^(|everyone|users|admins)$"
fv-warning="Visibility must be empty, everyone, users, or admins" />
<small class="text-muted">e.g. everyone, users, admins</small>
</div>
</div>
value="<?= $strVisibility; ?>" />
</td>
</tr>
<div class="col-lg-3">
<div class="mb-3">
<label class="form-label">Actions</label>
<div>
<?php if ($strId == null || strlen($strId) < 1): ?>
<a class="btn btn-primary" onclick="fnSave();"><i class="fa fa-fw fa-paper-plane"></i> Submit</a>
<?php else: ?>
<a class="btn btn-success" onclick="fnSave();"><i class="fa fa-fw fa-save"></i> Save</a>
<?php endif; ?>
</div>
</div>
</div>
</div>
<tr>
<td></td>
<td>
<input
type="submit"
value="Go" />
</td>
</tr>
</tbody>
</table>
</div>
</form>
<script>
$(function() {
fnSave = function() {
FormValidator.onError = function(str)
{
BootstrapRender.message(str, "danger");
};
FormValidator.validate(function() {
$("form").first().submit();
});
};
fnResize = function(x) {
x.style.minHeight = "2in";
x.style.height = "auto";
x.style.height = x.scrollHeight + "px";
};
fnResize($("textarea").first()[0]);
});
</script>
<?php PageRender::uploads(); ?>

View File

@ -1,54 +0,0 @@
<?php
global $c;
$strPath = "/";
$strPath .= implode("/", Request::getPathParts());
$varPosts = [];
$strQuery = Request::getParam("q");
if ($strQuery !== null && strlen($strQuery) > 0)
{
$varPosts = $c->query(
"SELECT *
from posts as p
where
content like concat('%', ?, '%')
order by
created desc",
$strQuery);
$i = 0;
for ($i = 0; $i < count($varPosts); $i++)
{
$varOld = $varPosts[$i];
$varOld["content"] = preg_replace("/({$strQuery})/i", "<mark>$1</mark>", $varOld["content"]);
$varPosts[$i] = $varOld;
}
}
?>
<form method="get">
<div class="navbar navbar-expand bg-body-tertiary d-flex px-3 sticky-top">
<div class="container justify-content-between">
<div class="navbar-nav d-inline-flex align-items-center">
<span class="navbar-brand">Search</span>
<input class="form-control me-2" type="text" name="q" value="<?= $strQuery; ?>" />
<button type="submit" class="btn btn-outline-info text-nowrap"><i class="fa fa-fw fa-search"></i> Go</a>
</div>
<div class="navbar-nav d-inline-flex"></div>
</div>
</div>
</form>
<div class="container">
<div class="row">
<div class="col-lg-4">
<?php BootstrapRender::message(); ?>
</div>
</div>
</div>
<?php PostRender::rows($varPosts); ?>

65
pages/upload.php Normal file
View File

@ -0,0 +1,65 @@
<?php
UserAuth::require("is_admin");
if (isset($_FILES["file"]))
{
$varFile = $_FILES["file"];
try
{
$strUploadName = basename($varFile["name"]);
$strUploadName = preg_replace("/ /", "_", $strUploadName);
$strUploadName = preg_replace("/[^A-Za-z0-9_\-\.]/", "", $strUploadName);
$strTimestamp = date("YmdHis");
$strDestinationPath = "files/{$strTimestamp}_{$strUploadName}";
$intAllow = 0;
// Check file size (optional)
if ($varFile["size"] > 1024 * 1024 * 5)
throw new Exception("Upload exceeds maximum file size.");
if (file_exists($strDestinationPath))
throw new Exception("Destination file already exists.");
foreach (["/\.jpg$/", "/\.png$/"] as $strExtension)
if (preg_match_all($strExtension, $strDestinationPath))
$intAllow = 1;
if ($intAllow == 0)
throw new Exception("File type not allowed.");
$intResult = move_uploaded_file($varFile["tmp_name"], $strDestinationPath);
if (!$intResult)
throw new Exception("Problem uploading file.");
}
catch (Exception $x)
{
PageRender::message($x->getMessage(), "danger");
}
}
?>
<?php PageRender::message(); ?>
<form method="post" enctype="multipart/form-data">
<table>
<tbody>
<tr>
<td>File</td>
<td><input type="file" name="file" /></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="Upload" /></td>
</tr>
</tbody>
</table>
</form>
<?php PageRender::uploads(); ?>

49
pages/user/index.php Normal file
View File

@ -0,0 +1,49 @@
<?php
global $c;
$strError = null;
if (UserAuth::getUser() == null)
Respond::redirect("/user/signin");
$varUser = UserAuth::getUser();
if ($varUser == null)
Respond::redirect("/");
try
{
if (Request::posts("user_name", "display_name"))
{
$strUsername = Request::getPosted("user_name");
$strDisplayName = Request::getPosted("display_name");
if (!preg_match("/^[A-Za-z0-9]{1,}$/", $strUsername))
throw new Exception("Username must be alphanumeric characters only");
$c->query(
"INSERT or replace into users (email, user_name, display_name)
select
?,
?,
?",
$varUser["email"],
$strUsername,
$strDisplayName);
PageRender::message("Profile updated", "success");
}
}
catch (Exception $x)
{
PageRender::message($x->getMessage(), "danger");
}
$strUsername = $varUser["username"];
PageRender::message("You are signed in as {$strUsername}.");
?>
<?php PageRender::message(); ?>
<ul>
<li><a href="/user/signout">Sign out</a></li>
</ul>

View File

@ -1,80 +0,0 @@
<?php
global $c;
$strError = null;
if (UserAuth::getUser() == null)
Respond::redirect("/user/signin");
$varUser = UserAuth::getUser();
if ($varUser == null)
Respond::redirect("/");
try
{
if (Request::posts("user_name", "display_name"))
{
$strUsername = Request::getPosted("user_name");
$strDisplayName = Request::getPosted("display_name");
if (!preg_match("/^[A-Za-z0-9]{1,}$/", $strUsername))
throw new Exception("Username must be alphanumeric characters only");
$c->query(
"INSERT or replace into users (email, user_name, display_name)
select
?,
?,
?",
$varUser["email"],
$strUsername,
$strDisplayName);
BootstrapRender::message("Profile updated", "success");
}
}
catch (Exception $x)
{
BootstrapRender::message($x->getMessage(), "danger");
}
?>
<div class="container">
<div class="row my-5">
<div class="col-md-4">
<?php BootstrapRender::message(); ?>
<form method="post">
<?php BootstrapRender::input([
"name" => "username",
"label" => "Username",
"value" => $varUser["username"],
"disabled" => 1,
]); ?>
<?php BootstrapRender::input([
"name" => "user_name",
"label" => "Username",
"value" => $strUsername,
]); ?>
<?php BootstrapRender::input([
"name" => "display_name",
"label" => "Display Name",
"value" => $strDisplayName,
]); ?>
<?php BootstrapRender::button([
"tag" => "button",
"type" => "submit",
"class" => "outline-success",
"icon" => "save",
"label" => "Save"
]); ?>
</form>
</div>
</div>
</div>

View File

@ -1,5 +0,0 @@
<?php
global $c;
UserAuth::require("is_admin");
TableEditor::render("credentials", ["email", "hash"]);
?>

View File

@ -1,5 +0,0 @@
<?php
global $c;
UserAuth::require("is_admin");
TableEditor::render("permissions", ["email", "permission"]);
?>

View File

@ -7,7 +7,7 @@
if ($intUserCount < 1)
{
BootstrapRender::message(
PageRender::message(
"Please create an administrator account.",
"warning");
}
@ -44,7 +44,7 @@
if ($intUserCount == 1)
$c->query("UPDATE users set can_post = 1, is_admin = 1");
BootstrapRender::message("Registration was a success, please sign in to continue.");
PageRender::message("Registration was a success, please sign in to continue.");
Respond::redirect("/user/signin");
}
@ -52,57 +52,32 @@
}
catch (Exception $x)
{
BootstrapRender::message($x->getMessage(), "danger");
PageRender::message($x->getMessage(), "danger");
}
?>
<script>
$(".app-header").hide();
</script>
<div class="container">
<div class="row my-5">
<div class="col-md-4 offset-md-4">
<?php BootstrapRender::message(); ?>
<form method="post">
<table>
<tbody>
<tr>
<td><label>Username</label></td>
<td><input type="text" name="username" value="" /></td>
</tr>
<?php BootstrapRender::input([
"name" => "username",
"label" => "Username",
"value" => Request::getPosted("username")
]); ?>
<tr>
<td><label>Password</label></td>
<td><input type="password" name="password" value="" /></td>
</tr>
<?php BootstrapRender::input([
"name" => "password",
"label" => "Password",
"value" => Request::getPosted("password"),
"type" => "password",
]); ?>
<tr>
<td><label>Repeat</label></td>
<td><input type="password" name="repeat" value="" /></td>
</tr>
<?php BootstrapRender::input([
"name" => "repeat",
"label" => "Repeat Password",
"value" => Request::getPosted("repeat"),
"type" => "password",
]); ?>
<?php BootstrapRender::buttons([
[
"tag" => "button",
"icon" => "right-to-bracket",
"label" => "Continue",
"type" => "submit",
"class" => "outline-primary"
]
]); ?>
<div class="mb-3">
<a class="text-decoration-none" href="/user/signin">Already have an account?</a>
</div>
<tr>
<td></td>
<td><input type="submit" value="Go" /></td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
</div>

View File

@ -34,63 +34,39 @@
Cookie::set("token", $strToken);
BootstrapRender::message(
PageRender::message(
"Successfully signed in",
"info");
Respond::redirect("/user/info");
Respond::redirect("/user");
}
}
catch (Exception $x)
{
BootstrapRender::message($x->getMessage(), "danger");
PageRender::message($x->getMessage(), "danger");
}
?>
<script>
$(".app-header").hide();
</script>
<div class="container">
<div class="row my-5">
<div class="col-md-4 offset-md-4">
<?php BootstrapRender::message(); ?>
<?php PageRender::message(); ?>
<form method="post">
<?php BootstrapRender::input([
"name" => "username",
"label" => "Username",
"value" => Request::getPosted("email")
]); ?>
<table>
<tbody>
<tr>
<td><label>Username</label></td>
<td><input type="text" name="username" value="" /></td>
</tr>
<?php BootstrapRender::input([
"name" => "password",
"label" => "Password",
"value" => Request::getPosted("password"),
"type" => "password",
]); ?>
<tr>
<td><label>Password</label></td>
<td><input type="password" name="password" value="" /></td>
</tr>
<?php BootstrapRender::buttons([
[
"tag" => "button",
"icon" => "right-to-bracket",
"label" => "Continue",
"type" => "submit",
"class" => "outline-primary"
],
[
"icon" => "home",
"label" => "Home",
"href" => "/",
"class" => "outline-secondary"
]
]); ?>
<div class="mb-3">
<a class="text-decoration-none" href="/user/register">Don't have an account?</a>
</div>
<tr>
<td></td>
<td><input type="submit" value="Go" /></td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
</div>

View File

@ -24,6 +24,6 @@
}
}
BootstrapRender::message("You have successfully signed out");
PageRender::message("You have successfully signed out");
Respond::redirect("/user/signin");
?>