Massive cleanup of project, added support for MySQL, implemented visibility
This commit is contained in:
parent
166a1d7e2b
commit
bd3c6f065f
8
db/mysql/create_links_table.sql
Normal file
8
db/mysql/create_links_table.sql
Normal file
@ -0,0 +1,8 @@
|
||||
CREATE table if not exists links (
|
||||
id integer primary key auto_increment,
|
||||
label text not null,
|
||||
url text not null,
|
||||
icon text not null,
|
||||
position text not null,
|
||||
visibility text null,
|
||||
sort integer not null default 0)
|
9
db/mysql/create_posts_table.sql
Normal file
9
db/mysql/create_posts_table.sql
Normal file
@ -0,0 +1,9 @@
|
||||
CREATE table if not exists posts (
|
||||
id integer primary key auto_increment,
|
||||
username text not null,
|
||||
content text not null,
|
||||
location text not null,
|
||||
visibility text null,
|
||||
created timestamp not null default current_timestamp,
|
||||
updated timestamp not null default current_timestamp,
|
||||
sort integer not null default 0)
|
5
db/mysql/create_sessions_table.sql
Normal file
5
db/mysql/create_sessions_table.sql
Normal file
@ -0,0 +1,5 @@
|
||||
CREATE table if not exists sessions (
|
||||
id integer primary key auto_increment,
|
||||
username text not null,
|
||||
token text not null,
|
||||
expires timestamp null)
|
4
db/mysql/create_settings_table.sql
Normal file
4
db/mysql/create_settings_table.sql
Normal file
@ -0,0 +1,4 @@
|
||||
CREATE table if not exists settings (
|
||||
id integer primary key auto_increment,
|
||||
setting text not null,
|
||||
value text not null)
|
7
db/mysql/create_users_table.sql
Normal file
7
db/mysql/create_users_table.sql
Normal file
@ -0,0 +1,7 @@
|
||||
CREATE table if not exists users (
|
||||
id integer primary key auto_increment,
|
||||
username text not null,
|
||||
hash text not null,
|
||||
can_post integer not null default 0,
|
||||
is_admin integer not null default 0,
|
||||
created timestamp not null default current_timestamp)
|
4
db/mysql/get_last_post.sql
Normal file
4
db/mysql/get_last_post.sql
Normal file
@ -0,0 +1,4 @@
|
||||
SELECT *
|
||||
from posts
|
||||
where
|
||||
id = last_insert_id()
|
8
db/sqlite/create_links_table.sql
Normal file
8
db/sqlite/create_links_table.sql
Normal file
@ -0,0 +1,8 @@
|
||||
CREATE table if not exists links (
|
||||
id integer primary key autoincrement,
|
||||
label text not null,
|
||||
url text not null,
|
||||
icon text not null,
|
||||
position text not null,
|
||||
visibility text null,
|
||||
sort integer not null default 0)
|
9
db/sqlite/create_posts_table.sql
Normal file
9
db/sqlite/create_posts_table.sql
Normal file
@ -0,0 +1,9 @@
|
||||
CREATE table if not exists posts (
|
||||
id integer primary key autoincrement,
|
||||
username text not null,
|
||||
content text not null,
|
||||
location text not null,
|
||||
visibility text null,
|
||||
created timestamp not null default current_timestamp,
|
||||
updated timestamp not null default current_timestamp,
|
||||
sort integer not null default 0)
|
5
db/sqlite/create_sessions_table.sql
Normal file
5
db/sqlite/create_sessions_table.sql
Normal file
@ -0,0 +1,5 @@
|
||||
CREATE table if not exists sessions (
|
||||
id integer primary key autoincrement,
|
||||
username text not null,
|
||||
token text not null,
|
||||
expires timestamp null)
|
4
db/sqlite/create_settings_table.sql
Normal file
4
db/sqlite/create_settings_table.sql
Normal file
@ -0,0 +1,4 @@
|
||||
CREATE table if not exists settings (
|
||||
id integer primary key autoincrement,
|
||||
setting text not null,
|
||||
value text not null)
|
7
db/sqlite/create_users_table.sql
Normal file
7
db/sqlite/create_users_table.sql
Normal file
@ -0,0 +1,7 @@
|
||||
CREATE table if not exists users (
|
||||
id integer primary key autoincrement,
|
||||
username text not null,
|
||||
hash text not null,
|
||||
can_post integer not null default 0,
|
||||
is_admin integer not null default 0,
|
||||
created timestamp not null default current_timestamp)
|
4
db/sqlite/get_last_post.sql
Normal file
4
db/sqlite/get_last_post.sql
Normal file
@ -0,0 +1,4 @@
|
||||
SELECT *
|
||||
from posts
|
||||
where
|
||||
rowid = last_insert_rowid()
|
46
files/FormValidator/FormValidator.js
Normal file
46
files/FormValidator/FormValidator.js
Normal file
@ -0,0 +1,46 @@
|
||||
$(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");
|
||||
});
|
||||
|
||||
};
|
||||
});
|
37
files/SearchableInput/SearchableInput.css
Normal file
37
files/SearchableInput/SearchableInput.css
Normal file
@ -0,0 +1,37 @@
|
||||
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;
|
||||
}
|
206
files/SearchableInput/SearchableInput.js
Normal file
206
files/SearchableInput/SearchableInput.js
Normal file
@ -0,0 +1,206 @@
|
||||
$(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();
|
||||
});
|
24
footer.php
24
footer.php
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
global $c;
|
||||
$varUser = UserAuth::getUser();
|
||||
$varFooterLinks = $c->query("SELECT * from links where position like 'footer' order by sort");
|
||||
?>
|
||||
|
||||
@ -9,6 +10,8 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<?php foreach ($varFooterLinks as $varLink): ?>
|
||||
<?php if (!UserAuth::visible($varLink["visibility"])) continue; ?>
|
||||
|
||||
<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>
|
||||
@ -16,3 +19,24 @@
|
||||
</div>
|
||||
</div>
|
||||
</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>
|
||||
|
||||
<script>
|
||||
<?php
|
||||
echo Settings::get(
|
||||
"js",
|
||||
"$(function() {\n // My script here.\n});",
|
||||
true);
|
||||
?>
|
||||
</script>
|
||||
|
27
head.php
27
head.php
@ -1,10 +1,35 @@
|
||||
<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;
|
||||
}
|
||||
</style>
|
||||
|
||||
<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>
|
||||
|
31
header.php
31
header.php
@ -1,17 +1,11 @@
|
||||
<?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);
|
||||
?>
|
||||
|
||||
<style>
|
||||
/* https://github.com/twbs/bootstrap/issues/37184 */
|
||||
.dropdown-menu {
|
||||
z-index: 1040 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// Make the page's theme dark:
|
||||
$("body").first().attr("data-bs-theme", "dark");
|
||||
@ -20,6 +14,8 @@
|
||||
<div class="offcanvas offcanvas-start" id="sidebar">
|
||||
<div class="offcanvas-body">
|
||||
<?php foreach ($varSidebarLinks as $varLink): ?>
|
||||
<?php if (!UserAuth::visible($varLink["visibility"])) continue; ?>
|
||||
|
||||
<a class="btn btn-outline-secondary d-block w-100 mb-2" href="<?= $varLink["url"]; ?>"><i class="fa fa-fw fa-<?= $varLink["icon"]; ?> pe-2"></i> <?= $varLink["label"]; ?></a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
@ -43,42 +39,31 @@
|
||||
|
||||
<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">
|
||||
<?php
|
||||
$varUser = UserAuth::getUser();
|
||||
$strUserText = "User";
|
||||
|
||||
if ($varUser !== null)
|
||||
$strUserText = $varUser["user_name"] ?? $varUser["email"] ?? "User";
|
||||
?>
|
||||
|
||||
<a class="btn btn-secondary dropdown-toggle h-100" data-bs-toggle="dropdown"><i class="fa fa-fw fa-user"></i> </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> <?= $strUserText; ?></a>
|
||||
|
||||
<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>
|
||||
|
||||
<!--
|
||||
<a class="nav-link" href="/user/signin">Account</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>
|
||||
|
190
init.php
190
init.php
@ -1,84 +1,101 @@
|
||||
<?php
|
||||
global $c;
|
||||
|
||||
$strDBCSFile = "dbcs.txt";
|
||||
$strDBCSFile = "dbcs.txt";
|
||||
$strDBCS = "sqlite:sqlite.db";
|
||||
|
||||
if (!file_exists($strDBCSFile))
|
||||
file_put_contents($strDBCSFile, "sqlite:sqlite.db");
|
||||
file_put_contents($strDBCSFile, $strDBCS);
|
||||
|
||||
$c = new DatabaseConnection(
|
||||
trim(file_get_contents($strDBCSFile)));
|
||||
$strDBCS = trim(file_get_contents($strDBCSFile));
|
||||
|
||||
$c = new DatabaseConnection($strDBCS);
|
||||
|
||||
$intInitialize = 1;
|
||||
if ($intInitialize == 1)
|
||||
{
|
||||
$c->query(
|
||||
"CREATE table if not exists globals (
|
||||
id integer primary key autoincrement,
|
||||
global text not null,
|
||||
content text not null)");
|
||||
|
||||
$c->query(
|
||||
"CREATE table if not exists credentials (
|
||||
id integer primary key autoincrement,
|
||||
email text not null,
|
||||
hash text not null)");
|
||||
|
||||
$c->query(
|
||||
"CREATE table if not exists users (
|
||||
id integer primary key autoincrement,
|
||||
email text not null,
|
||||
user_name text not null,
|
||||
display_name text not null)");
|
||||
|
||||
$c->query(
|
||||
"CREATE table if not exists sessions (
|
||||
id integer primary key autoincrement,
|
||||
email text not null,
|
||||
token text not null,
|
||||
expires timestamp null)");
|
||||
|
||||
$c->query(
|
||||
"CREATE table if not exists permissions (
|
||||
id integer primary key autoincrement,
|
||||
email text not null,
|
||||
permission text not null)");
|
||||
|
||||
$c->query(
|
||||
"CREATE table if not exists links (
|
||||
id integer primary key autoincrement,
|
||||
label text not null,
|
||||
url text not null,
|
||||
icon text not null,
|
||||
position text not null,
|
||||
sort integer not null default 0)");
|
||||
|
||||
$c->query(
|
||||
"CREATE table if not exists posts (
|
||||
id integer primary key autoincrement,
|
||||
email text not null,
|
||||
path text not null,
|
||||
content text not null,
|
||||
created timestamp not null default current_timestamp,
|
||||
updated timestamp not null default current_timestamp,
|
||||
sort integer not null default 0)");
|
||||
$c->query([
|
||||
"create_users_table.sql",
|
||||
"create_sessions_table.sql",
|
||||
"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)
|
||||
"INSERT into links (label, url, icon, position, visibility)
|
||||
values
|
||||
('Home', '/', 'home', 'navbar'),
|
||||
('Post', '/post?to=/', 'edit', 'navbar'),
|
||||
('Links', '/edit/links', 'link', 'navbar'),
|
||||
('Go home', '/', 'home', 'sidebar'),
|
||||
('Copyright © 2025 Your Company.', '/', 'home', 'footer')");
|
||||
('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'),
|
||||
|
||||
('Copyright © 2025 Your Company.', '/', 'building', 'footer', ''),
|
||||
('Edit this page', '?edit=1', 'edit', 'footer', 'admin')"
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Settings
|
||||
{
|
||||
public static function get($strSettingName, $strDefault="", $intSave=0)
|
||||
{
|
||||
global $c;
|
||||
|
||||
$varExisting = $c->query("
|
||||
SELECT *
|
||||
from settings
|
||||
where
|
||||
setting like ?
|
||||
order by
|
||||
id desc",
|
||||
$strSettingName);
|
||||
|
||||
if (count($varExisting) > 0)
|
||||
return $varExisting[0]["value"];
|
||||
|
||||
if ($intSave)
|
||||
Settings::set($strSettingName, $strDefault);
|
||||
|
||||
return $strDefault;
|
||||
}
|
||||
|
||||
public static function set($strSettingName, $strValue)
|
||||
{
|
||||
global $c;
|
||||
|
||||
$varExisting = $c->query("
|
||||
SELECT *
|
||||
from settings
|
||||
where
|
||||
setting like ?
|
||||
order by
|
||||
id desc",
|
||||
$strSettingName);
|
||||
|
||||
if (count($varExisting) !== 1)
|
||||
{
|
||||
$c->query("DELETE from settings where setting like ?", $strSettingName);
|
||||
$c->query("INSERT into settings (setting, value) values (?, ?)", $strSettingName, $strValue);
|
||||
}
|
||||
|
||||
$c->query(
|
||||
"UPDATE settings
|
||||
set
|
||||
value = ?
|
||||
where setting like ?",
|
||||
$strValue,
|
||||
$strSettingName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class UserAuth
|
||||
{
|
||||
@ -93,13 +110,9 @@
|
||||
if (strlen($strToken) > 0)
|
||||
{
|
||||
$varSessions = $c->query(
|
||||
"SELECT
|
||||
u.*,
|
||||
c.*,
|
||||
s.*
|
||||
"SELECT *
|
||||
from sessions as s
|
||||
join credentials as c on c.email = s.email
|
||||
left join users as u on u.email = s.email
|
||||
join users as u on u.username = s.username
|
||||
where
|
||||
s.token = ?
|
||||
and (
|
||||
@ -116,7 +129,7 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function hasPermission($strPermission)
|
||||
public static function has($strColumnName)
|
||||
{
|
||||
global $c;
|
||||
$varUser = UserAuth::getUser();
|
||||
@ -124,31 +137,42 @@
|
||||
if ($varUser == null)
|
||||
return false;
|
||||
|
||||
$varPermissions = $c->query(
|
||||
"SELECT *
|
||||
from permissions
|
||||
where
|
||||
email like ?
|
||||
and (
|
||||
permission like ?
|
||||
or permission like '*'
|
||||
)",
|
||||
$varUser["email"],
|
||||
$strPermission);
|
||||
|
||||
if (count($varPermissions) > 0)
|
||||
return true;
|
||||
if (array_key_exists($strColumnName, $varUser))
|
||||
if (intval($varUser[$strColumnName]) > 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function requirePermission($strPermission)
|
||||
public static function require($strColumnName)
|
||||
{
|
||||
if (!UserAuth::hasPermission($strPermission))
|
||||
if (!UserAuth::has($strColumnName))
|
||||
{
|
||||
BootstrapRender::message("You do not have permission to do that, please sign into an account that does.", "warning");
|
||||
Respond::redirect("/user/signin");
|
||||
}
|
||||
}
|
||||
|
||||
public static function visible($strVisibility)
|
||||
{
|
||||
global $c;
|
||||
|
||||
$varUser = UserAuth::getUser();
|
||||
$varRegex = [
|
||||
["/user/i", ($varUser == null)],
|
||||
["/admin/i", (!UserAuth::has("is_admin"))],
|
||||
];
|
||||
|
||||
$intExit = 0;
|
||||
|
||||
foreach ($varRegex as $re)
|
||||
if (preg_match($re[0], $strVisibility))
|
||||
if ($re[1])
|
||||
$intExit = 1;
|
||||
|
||||
if ($intExit == 1)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
@ -20,20 +20,49 @@
|
||||
$strMessageClass = "info";
|
||||
|
||||
?>
|
||||
<?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")
|
||||
<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();
|
||||
});
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
return messageElem;
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php
|
||||
|
||||
Cookie::set("message");
|
||||
@ -42,68 +71,69 @@
|
||||
|
||||
public static function input($varOptions)
|
||||
{
|
||||
$strName = $varOptions["name"];
|
||||
$strLabel = $varOptions["label"] ?? $strName;
|
||||
$strPlaceholder = $varOptions["placeholder"] ?? "Enter {$strLabel}";
|
||||
$strValue = $varOptions["value"] ?? "";
|
||||
$intReadonly = $varOptions["readonly"] ?? 0;
|
||||
$intDisabled = $varOptions["disabled"] ?? 0;
|
||||
$strType = $varOptions["type"] ?? "text";
|
||||
$intInline = $varOptions["inline"] ?? 0;
|
||||
$strTag = $varOptions["tag"] ?? "input";
|
||||
$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
|
||||
}
|
||||
|
||||
<?php if ($intInline == 1): ?>
|
||||
public static function button($varOptions)
|
||||
{
|
||||
$varOptions["tag"] = $varOptions["tag"] ?? "a";
|
||||
$varOptionsExtras = $varOptions;
|
||||
$varDefaultKeys = ["tag", "label", "name", "type", "value", "hint"];
|
||||
|
||||
<div class="row g-3 align-items-center mb-3">
|
||||
<div class="col-3">
|
||||
<label class="col-form-label"><?= $strLabel; ?></label>
|
||||
</div>
|
||||
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; ?>
|
||||
|
||||
<div class="col-8">
|
||||
<<?= $strTag; ?> type="<?= $strType; ?>"
|
||||
class="form-control"
|
||||
name="<?= $strName; ?>"
|
||||
placeholder="Enter <?= $strLabel; ?>"
|
||||
value="<?= $strValue; ?>"
|
||||
<?= $intReadonly? "readonly": ""; ?>
|
||||
<?= $intDisabled? "disabled": ""; ?>
|
||||
|
||||
<?php if ($strTag == "textarea"): ?>
|
||||
><?= $strValue; ?></<?= $strTag; ?>>
|
||||
<?php else: ?>
|
||||
/>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="col-auto">
|
||||
<span class="form-text">test</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php else: ?>
|
||||
<?= $varOptions["label"] ?? "Button"; ?>
|
||||
</<?= $varOptions["tag"]; ?>>
|
||||
<?php
|
||||
}
|
||||
|
||||
public static function buttons($varButtons)
|
||||
{
|
||||
?>
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= $strLabel; ?></label>
|
||||
<div class="input-group">
|
||||
<<?= $strTag; ?> type="<?= $strType; ?>"
|
||||
class="form-control"
|
||||
name="<?= $strName; ?>"
|
||||
placeholder="Enter <?= $strLabel; ?>"
|
||||
value="<?= $strValue; ?>"
|
||||
<?= $intReadonly? "readonly": ""; ?>
|
||||
<?= $intDisabled? "disabled": ""; ?>
|
||||
|
||||
<?php if ($strTag == "textarea"): ?>
|
||||
><?= $strValue; ?></<?= $strTag; ?>>
|
||||
<?php else: ?>
|
||||
/>
|
||||
<?php endif; ?>
|
||||
<div>
|
||||
<?php foreach ($varButtons as $b): ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
@ -3,14 +3,14 @@
|
||||
{
|
||||
public static function rows($varRows)
|
||||
{
|
||||
$varParsedown = new Parsedown();
|
||||
|
||||
$varUser = UserAuth::getUser();
|
||||
$varParsedown = new Parsedown();
|
||||
$intRenderedRows = 0;
|
||||
?>
|
||||
<?php if (file_exists("files/site.css")): ?>
|
||||
<link rel="stylesheet" href="/files/site.css" />
|
||||
<?php endif; ?>
|
||||
|
||||
<?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">
|
||||
@ -19,7 +19,7 @@
|
||||
</div>
|
||||
<hr />
|
||||
<div class="text-muted">
|
||||
<div>by <?= $r["display_name"] ?? $r["user_name"] ?? $r["email"]; ?></div>
|
||||
<div>by <?= $r["username"]; ?></div>
|
||||
<div>on <?= $r["created"]; ?> UTC</div>
|
||||
</div>
|
||||
<?php if (Request::getParam("edit")): ?>
|
||||
@ -30,9 +30,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php $intRenderedRows++; ?>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<?php if (count($varRows) < 1): ?>
|
||||
<?php if ($intRenderedRows < 1): ?>
|
||||
<div class="container my-5">
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
@ -41,10 +43,6 @@
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (file_exists("files/site.js")): ?>
|
||||
<script src="/files/site.js"></script>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
@ -1,67 +0,0 @@
|
||||
<?php
|
||||
global $c;
|
||||
$strFile = "files/site.js";
|
||||
$strContent = "";
|
||||
|
||||
UserAuth::requirePermission("admin");
|
||||
|
||||
if (file_exists($strFile))
|
||||
$strContent = file_get_contents($strFile);
|
||||
|
||||
if (Request::posts("content"))
|
||||
{
|
||||
$strContent = Request::getPosted("content");
|
||||
file_put_contents($strFile, $strContent);
|
||||
}
|
||||
?>
|
||||
|
||||
<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"><?= $strFile; ?></span>
|
||||
|
||||
<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">
|
||||
</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>
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
global $c;
|
||||
UserAuth::requirePermission("admin");
|
||||
TableEditor::render("links", ["label", "url", "icon", "position", "sort"]);
|
||||
UserAuth::require("is_admin");
|
||||
TableEditor::render("links", ["label", "url", "icon", "position", "visibility", "sort"]);
|
||||
?>
|
||||
|
@ -5,59 +5,16 @@
|
||||
$strPath .= implode("/", Request::getPathParts());
|
||||
|
||||
$varPosts = $c->query(
|
||||
"SELECT
|
||||
p.*,
|
||||
u.user_name,
|
||||
u.display_name
|
||||
"SELECT *
|
||||
from posts as p
|
||||
left join users as u on u.email = p.email
|
||||
where
|
||||
path like ?
|
||||
or path like '*'
|
||||
location like ?
|
||||
or location like '*'
|
||||
order by
|
||||
created desc",
|
||||
$strPath);
|
||||
|
||||
$strSearchQuery = Request::getParam("q");
|
||||
|
||||
if ($strSearchQuery)
|
||||
{
|
||||
$varPosts = $c->query(
|
||||
"SELECT
|
||||
p.*,
|
||||
u.user_name,
|
||||
u.display_name
|
||||
from posts as p
|
||||
left join users as u on u.email = p.email
|
||||
where
|
||||
content like concat('%', ?, '%')
|
||||
order by
|
||||
created desc",
|
||||
$strSearchQuery);
|
||||
}
|
||||
|
||||
|
||||
$varParsedown = new Parsedown();
|
||||
?>
|
||||
|
||||
<?php if ($strSearchQuery): ?>
|
||||
<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="path" placeholder="e.g. /home" value="<?= $strSearchQuery; ?>" />
|
||||
|
||||
<a class="btn btn-outline-primary text-nowrap" onclick="fnSave();"><i class="fa fa-fw fa-search"></i> Search</a>
|
||||
</div>
|
||||
|
||||
<div class="navbar-nav d-inline-flex">
|
||||
<?php BootstrapRender::message(); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (Request::getParam("edit")): ?>
|
||||
<div class="container my-5">
|
||||
<div class="row">
|
||||
|
@ -1,13 +1,15 @@
|
||||
<?php
|
||||
global $c;
|
||||
|
||||
UserAuth::requirePermission("admin");
|
||||
UserAuth::require("can_post");
|
||||
|
||||
$varUser = UserAuth::getUser();
|
||||
$strId = Request::getArg(0);
|
||||
$strPath = Request::getParam("to") ?? "";
|
||||
$strContent = "";
|
||||
$strVerb = "Create";
|
||||
$varUser = UserAuth::getUser();
|
||||
$strId = Request::getArg(0);
|
||||
|
||||
$strContent = "";
|
||||
$strLocation = Request::getParam("to") ?? "";
|
||||
$strVisibility = "";
|
||||
$strVerb = "Create";
|
||||
|
||||
if (strlen($strId) > 0)
|
||||
{
|
||||
@ -20,27 +22,30 @@
|
||||
Respond::redirect("/post");
|
||||
}
|
||||
|
||||
$varRow = $varRows[0];
|
||||
$strPath = $varRow["path"];
|
||||
$strContent = $varRow["content"];
|
||||
$varRow = $varRows[0];
|
||||
$strContent = $varRow["content"];
|
||||
$strLocation = $varRow["location"];
|
||||
$strVisibility = $varRow["visibility"];
|
||||
}
|
||||
|
||||
|
||||
if (Request::posts("path", "content"))
|
||||
if (Request::posts("location", "content", "visibility"))
|
||||
{
|
||||
$strPath = Request::getPosted("path");
|
||||
$strContent = Request::getPosted("content");
|
||||
$strLocation = Request::getPosted("location");
|
||||
$strContent = Request::getPosted("content");
|
||||
$strVisibility = Request::getPosted("visibility");
|
||||
|
||||
if ($strId == null || strlen($strId) < 1)
|
||||
{
|
||||
$c->query(
|
||||
"INSERT into posts (email, path, content)
|
||||
values (?, ?, ?)",
|
||||
$varUser["email"],
|
||||
$strPath,
|
||||
$strContent);
|
||||
"INSERT into posts (username, content, location, visibility)
|
||||
values (?, ?, ?, ?)",
|
||||
$varUser["username"],
|
||||
$strContent,
|
||||
$strLocation,
|
||||
$strVisibility);
|
||||
|
||||
$strId = $c->query("SELECT * from posts where rowid = last_insert_rowid()")[0]["id"];
|
||||
$strId = $c->query("get_last_post.sql")[0]["id"];
|
||||
}
|
||||
|
||||
if (strlen($strContent) < 1)
|
||||
@ -53,15 +58,18 @@
|
||||
$c->query(
|
||||
"UPDATE posts
|
||||
set
|
||||
path = ?,
|
||||
content = ?,
|
||||
updated = current_timestamp
|
||||
content = ?,
|
||||
location = ?,
|
||||
visibility = ?,
|
||||
updated = current_timestamp
|
||||
where
|
||||
id = ?",
|
||||
$strPath,
|
||||
$strContent,
|
||||
$strLocation,
|
||||
$strVisibility,
|
||||
$strId);
|
||||
|
||||
BootstrapRender::message("Post saved.", "success");
|
||||
Respond::redirect("/post/{$strId}");
|
||||
}
|
||||
?>
|
||||
@ -77,35 +85,75 @@
|
||||
<div class="container justify-content-between">
|
||||
<div class="navbar-nav d-inline-flex align-items-center">
|
||||
<span class="navbar-brand"><?= $strVerb; ?> Post</span>
|
||||
|
||||
<span class="nav-item text-nowrap me-2">Location</span>
|
||||
<input class="form-control me-2" type="text" name="path" placeholder="e.g. /home" value="<?= $strPath; ?>" />
|
||||
|
||||
<?php if ($strId == null || strlen($strId) < 1): ?>
|
||||
<a class="btn btn-outline-primary text-nowrap" onclick="fnSave();"><i class="fa fa-fw fa-paper-plane"></i> Submit</a>
|
||||
<?php else: ?>
|
||||
<a class="btn btn-outline-success text-nowrap" onclick="fnSave();"><i class="fa fa-fw fa-save"></i> Save</a>
|
||||
<?php endif; ?>
|
||||
</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 class="col-lg-3">
|
||||
<?php BootstrapRender::message(); ?>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-12">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Content</label>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
<div class="col-lg-3">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Visible To</label>
|
||||
<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>
|
||||
|
||||
<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>
|
||||
</div>
|
||||
</form>
|
||||
@ -113,10 +161,18 @@
|
||||
<script>
|
||||
$(function() {
|
||||
fnSave = function() {
|
||||
$("form").first().submit();
|
||||
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";
|
||||
};
|
||||
|
@ -1,18 +1,18 @@
|
||||
<?php
|
||||
global $c;
|
||||
$strFile = "files/site.css";
|
||||
$strContent = "";
|
||||
|
||||
UserAuth::requirePermission("admin");
|
||||
UserAuth::require("is_admin");
|
||||
|
||||
if (file_exists($strFile))
|
||||
$strContent = file_get_contents($strFile);
|
||||
$varUser = UserAuth::getUser();
|
||||
$strId = Request::getArg(0);
|
||||
|
||||
if ($strId == null || strlen($strId) < 1)
|
||||
$strId = "none";
|
||||
|
||||
if (Request::posts("content"))
|
||||
{
|
||||
$strContent = Request::getPosted("content");
|
||||
file_put_contents($strFile, $strContent);
|
||||
}
|
||||
Settings::set($strId, Request::getPosted("content"));
|
||||
|
||||
$strContent = Settings::get($strId, "");
|
||||
?>
|
||||
|
||||
<style>
|
||||
@ -25,12 +25,16 @@
|
||||
<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"><?= $strFile; ?></span>
|
||||
<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>
|
@ -5,9 +5,7 @@
|
||||
if (UserAuth::getUser() == null)
|
||||
Respond::redirect("/user/signin");
|
||||
|
||||
$varUser = UserAuth::getUser();
|
||||
$strUsername = $varUser["user_name"] ?? "";
|
||||
$strDisplayName = $varUser["display_name"] ?? "";
|
||||
$varUser = UserAuth::getUser();
|
||||
|
||||
if ($varUser == null)
|
||||
Respond::redirect("/");
|
||||
@ -43,20 +41,15 @@
|
||||
|
||||
<div class="container">
|
||||
<div class="row my-5">
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="mb-3">Edit your account details here.</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
|
||||
<?php BootstrapRender::message(); ?>
|
||||
|
||||
<form method="post">
|
||||
<?php BootstrapRender::input([
|
||||
"name" => "email",
|
||||
"label" => "E-Mail Address",
|
||||
"value" => $varUser["email"],
|
||||
"name" => "username",
|
||||
"label" => "Username",
|
||||
"value" => $varUser["username"],
|
||||
"disabled" => 1,
|
||||
]); ?>
|
||||
|
||||
@ -72,14 +65,13 @@
|
||||
"value" => $strDisplayName,
|
||||
]); ?>
|
||||
|
||||
<?php BootstrapRender::buttons([
|
||||
"input_group" => 0,
|
||||
"buttons" => [[
|
||||
"icon" => "save",
|
||||
"label" => "Save",
|
||||
"type" => "submit",
|
||||
"class" => "outline-success"
|
||||
]]]); ?>
|
||||
<?php BootstrapRender::button([
|
||||
"tag" => "button",
|
||||
"type" => "submit",
|
||||
"class" => "outline-success",
|
||||
"icon" => "save",
|
||||
"label" => "Save"
|
||||
]); ?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
global $c;
|
||||
UserAuth::requirePermission("admin");
|
||||
UserAuth::require("is_admin");
|
||||
TableEditor::render("credentials", ["email", "hash"]);
|
||||
?>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
global $c;
|
||||
UserAuth::requirePermission("admin");
|
||||
UserAuth::require("is_admin");
|
||||
TableEditor::render("permissions", ["email", "permission"]);
|
||||
?>
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
try
|
||||
{
|
||||
$intUserCount = $c->query("SELECT count(*) as c from credentials")[0]["c"];
|
||||
$intUserCount = $c->query("SELECT count(*) as c from users")[0]["c"];
|
||||
|
||||
if ($intUserCount < 1)
|
||||
{
|
||||
@ -12,14 +12,14 @@
|
||||
"warning");
|
||||
}
|
||||
|
||||
if (Request::posts("email", "password", "repeat"))
|
||||
if (Request::posts("username", "password", "repeat"))
|
||||
{
|
||||
$strEmail = Request::getPosted("email");
|
||||
$strUsername = Request::getPosted("username");
|
||||
$strPassword = Request::getPosted("password");
|
||||
$strRepeat = Request::getPosted("repeat");
|
||||
|
||||
if (!preg_match("/^[a-zA-Z0-9+_.-]+@[a-zA-Z0-9.-]+$/", $strEmail))
|
||||
throw new Exception("Not a valid e-mail address");
|
||||
if (!preg_match("/^[A-Za-z0-9]{1,}$/", $strUsername))
|
||||
throw new Exception("Not a valid username");
|
||||
|
||||
if (Request::getPosted("password") !== Request::getPosted("repeat"))
|
||||
throw new Exception("Passwords do not match");
|
||||
@ -27,27 +27,22 @@
|
||||
if (strlen($strPassword) < 6)
|
||||
throw new Exception("Password must be at least 6 characters");
|
||||
|
||||
$varUsers = $c->query("SELECT * from credentials where email like ?", $strEmail);
|
||||
$varUsers = $c->query("SELECT * from users where username like ?", $strUsername);
|
||||
|
||||
if (count($varUsers) > 0)
|
||||
throw new Exception("E-mail address in use");
|
||||
throw new Exception("Username in use");
|
||||
|
||||
$strHash = sha1($strPassword);
|
||||
|
||||
$c->query(
|
||||
"INSERT into credentials (email, hash) values (?, ?)",
|
||||
$strEmail,
|
||||
"INSERT into users (username, hash) values (?, ?)",
|
||||
$strUsername,
|
||||
$strHash);
|
||||
|
||||
$intUserCount = $c->query("SELECT count(*) as c from credentials")[0]["c"];
|
||||
$intUserCount = $c->query("SELECT count(*) as c from users")[0]["c"];
|
||||
|
||||
if ($intUserCount == 1)
|
||||
{
|
||||
$c->query(
|
||||
"INSERT into permissions (email, permission) values (?, ?)",
|
||||
$strEmail,
|
||||
"admin");
|
||||
}
|
||||
$c->query("UPDATE users set can_post = 1, is_admin = 1");
|
||||
|
||||
BootstrapRender::message("Registration was a success, please sign in to continue.");
|
||||
|
||||
@ -74,9 +69,9 @@
|
||||
<form method="post">
|
||||
|
||||
<?php BootstrapRender::input([
|
||||
"name" => "email",
|
||||
"label" => "E-Mail Address",
|
||||
"value" => Request::getPosted("email")
|
||||
"name" => "username",
|
||||
"label" => "Username",
|
||||
"value" => Request::getPosted("username")
|
||||
]); ?>
|
||||
|
||||
<?php BootstrapRender::input([
|
||||
|
@ -3,23 +3,23 @@
|
||||
|
||||
try
|
||||
{
|
||||
$intUserCount = $c->query("SELECT count(*) as c from credentials")[0]["c"];
|
||||
$intUserCount = $c->query("SELECT count(*) as c from users")[0]["c"];
|
||||
|
||||
if ($intUserCount < 1)
|
||||
Respond::redirect("/user/register");
|
||||
|
||||
if (Request::posts("email", "password"))
|
||||
if (Request::posts("username", "password"))
|
||||
{
|
||||
$strEmail = Request::getPosted("email");
|
||||
$strUsername = Request::getPosted("username");
|
||||
$strPassword = Request::getPosted("password");
|
||||
$strHash = sha1($strPassword);
|
||||
$varUsers = $c->query(
|
||||
"SELECT *
|
||||
from credentials
|
||||
from users
|
||||
where
|
||||
email like ?
|
||||
username like ?
|
||||
and hash = ?",
|
||||
$strEmail,
|
||||
$strUsername,
|
||||
$strHash);
|
||||
|
||||
if (count($varUsers) !== 1)
|
||||
@ -28,8 +28,8 @@
|
||||
$strToken = sha1(microtime());
|
||||
|
||||
$c->query(
|
||||
"INSERT into sessions (email, token) values (?, ?)",
|
||||
$strEmail,
|
||||
"INSERT into sessions (username, token) values (?, ?)",
|
||||
$strUsername,
|
||||
$strToken);
|
||||
|
||||
Cookie::set("token", $strToken);
|
||||
@ -59,8 +59,8 @@
|
||||
|
||||
<form method="post">
|
||||
<?php BootstrapRender::input([
|
||||
"name" => "email",
|
||||
"label" => "E-Mail Address",
|
||||
"name" => "username",
|
||||
"label" => "Username",
|
||||
"value" => Request::getPosted("email")
|
||||
]); ?>
|
||||
|
||||
|
@ -10,8 +10,8 @@
|
||||
"UPDATE sessions
|
||||
set
|
||||
expires = current_timestamp
|
||||
where email = ?",
|
||||
$varUser["email"]);
|
||||
where username = ?",
|
||||
$varUser["username"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user