Compare commits
77 Commits
Author | SHA1 | Date | |
---|---|---|---|
7b6ec52d5e | |||
1696f97b80 | |||
892878313a | |||
ec3214d1f9 | |||
6a53db6ec6 | |||
f93a528822 | |||
3a08a2e50c | |||
cbf36ebafa | |||
b62e86f7a6 | |||
063c8398a9 | |||
53e158b553 | |||
474047ab34 | |||
c97e058786 | |||
26a662c399 | |||
289aaeaa9f | |||
3ca062d995 | |||
7d30251cd6 | |||
7173a50c36 | |||
e66280e07a | |||
3ed75822a1 | |||
7531dc362d | |||
b250908663 | |||
892102528b | |||
69c634ea99 | |||
6ceeeaa087 | |||
f1c36fdeb1 | |||
d36b340692 | |||
d7ca7125ce | |||
1729b842ba | |||
4d2b78bdba | |||
106e697fc3 | |||
e0802f582b | |||
016c71d30d | |||
ba1369d842 | |||
a559901ac0 | |||
3f32258ba0 | |||
129efd13c7 | |||
c179ed7ebb | |||
f1a85f47fd | |||
61d660be69 | |||
5b7ab65946 | |||
59ace4fa05 | |||
3b6df75195 | |||
13b60de915 | |||
32cd18933d | |||
4f1b81ff4b | |||
cb3c8aaf2d | |||
ec44a6740f | |||
7f0bb2a18d | |||
47539de2d7 | |||
12aea4a2e2 | |||
20082e2ba2 | |||
0f889f9590 | |||
56a223c430 | |||
34f49bfd01 | |||
d4621de80f | |||
41bb633940 | |||
c36c365a1b | |||
80d0a017ed | |||
a17f51b72d | |||
1271317eb9 | |||
404b9220b8 | |||
9887a96c74 | |||
7bf050d730 | |||
963fbfbf00 | |||
027f20cb7e | |||
cfbd9a3706 | |||
10575f6f59 | |||
724f57531a | |||
2f9eccf931 | |||
0c4f9fce64 | |||
769d24b4b7 | |||
66aa3d6fdc | |||
ee0c0f65e3 | |||
5bd9b908ce | |||
66fa86e04e | |||
dafc3b76ea |
18
LICENSE.md
18
LICENSE.md
@ -1,19 +1,7 @@
|
||||
Copyright (c) 2018 Netsyms Technologies.
|
||||
Copyright (c) 2017-2019 Netsyms Technologies. Some rights reserved.
|
||||
|
||||
If you modify and redistribute this project, you must replace the branding
|
||||
assets with your own.
|
||||
|
||||
The branding assets include:
|
||||
* the application icon
|
||||
* the Netsyms N punchcard logo
|
||||
* the Netsyms for Business graph logo
|
||||
|
||||
If you are unsure if your usage is allowed, please contact us:
|
||||
https://netsyms.com/contact
|
||||
legal@netsyms.com
|
||||
|
||||
All other portions of this application,
|
||||
unless otherwise noted (in comments, headers, etc), are licensed as follows:
|
||||
Licensed under the Mozilla Public License Version 2.0. Files without MPL header
|
||||
comments, including third party code, may be under a different license.
|
||||
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
@ -39,3 +39,4 @@ Installing
|
||||
8. Set the URL of this app ("URL")
|
||||
9. Copy webroot.htaccess to your webroot and adjust paths if needed
|
||||
10. Run `composer install` (or `composer.phar install`) to install dependency libraries
|
||||
11. Run `git submodule init` and `git submodule update` to install other dependencies via git.
|
||||
|
81
action.php
81
action.php
@ -9,7 +9,6 @@
|
||||
*/
|
||||
require_once __DIR__ . "/required.php";
|
||||
require_once __DIR__ . "/lib/util.php";
|
||||
require_once __DIR__ . "/lib/login.php";
|
||||
|
||||
if ($VARS['action'] !== "signout") {
|
||||
dieifnotloggedin();
|
||||
@ -23,11 +22,11 @@ if ($VARS['action'] !== "signout") {
|
||||
*/
|
||||
function returnToSender($msg, $arg = "") {
|
||||
global $VARS;
|
||||
if ($arg == "") {
|
||||
header("Location: app.php?page=" . urlencode($VARS['source']) . "&msg=" . $msg);
|
||||
} else {
|
||||
header("Location: app.php?page=" . urlencode($VARS['source']) . "&msg=$msg&arg=$arg");
|
||||
$header = "Location: app.php?page=" . urlencode($VARS['source']) . "&msg=$msg";
|
||||
if ($arg != "") {
|
||||
$header .= "&arg=$arg";
|
||||
}
|
||||
header($header);
|
||||
die();
|
||||
}
|
||||
|
||||
@ -37,18 +36,20 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST' && empty($_POST) &&
|
||||
returnToSender("upload_too_big");
|
||||
}
|
||||
|
||||
$user = new User($_SESSION['uid']);
|
||||
|
||||
switch ($VARS['action']) {
|
||||
case "newpage":
|
||||
if (!account_has_permission($_SESSION['username'], "SITEWRITER") && !account_has_permission($_SESSION['username'], "SITEWRITER_EDIT")) {
|
||||
if (!$user->hasPermission("SITEWRITER") && !$user->hasPermission("SITEWRITER_EDIT")) {
|
||||
returnToSender("no_permission");
|
||||
}
|
||||
if (is_empty($VARS['siteid']) || !$database->has("sites", ["siteid" => $VARS['siteid']])) {
|
||||
if (empty($VARS['siteid']) || !$database->has("sites", ["siteid" => $VARS['siteid']])) {
|
||||
returnToSender("invalid_parameters");
|
||||
}
|
||||
if (is_empty($VARS['title'])) {
|
||||
if (empty($VARS['title'])) {
|
||||
returnToSender("invalid_parameters", $VARS['siteid']);
|
||||
}
|
||||
if (!is_empty($VARS['slug'])) {
|
||||
if (!empty($VARS['slug'])) {
|
||||
$slug = strtolower($VARS['slug']);
|
||||
$slug = preg_replace("/[^[:alnum:][:space:]]/u", '', $slug);
|
||||
$slug = preg_replace("/[[:space:]]/u", '-', $slug);
|
||||
@ -69,7 +70,7 @@ switch ($VARS['action']) {
|
||||
}
|
||||
}
|
||||
$template = "default";
|
||||
if (!is_empty($VARS['template'])) {
|
||||
if (!empty($VARS['template'])) {
|
||||
$template = preg_replace("/[^A-Za-z0-9]/", '', $VARS['template']);
|
||||
}
|
||||
$theme = $database->get("sites", "theme", ["siteid" => $VARS['siteid']]);
|
||||
@ -80,24 +81,24 @@ switch ($VARS['action']) {
|
||||
returnToSender("page_added", $VARS['siteid'] . "|" . $database->id());
|
||||
break;
|
||||
case "pagesettings":
|
||||
if (!account_has_permission($_SESSION['username'], "SITEWRITER")) {
|
||||
if (!$user->hasPermission("SITEWRITER")) {
|
||||
returnToSender("no_permission");
|
||||
}
|
||||
if (is_empty($VARS['siteid']) || !$database->has("sites", ["siteid" => $VARS['siteid']])) {
|
||||
if (empty($VARS['siteid']) || !$database->has("sites", ["siteid" => $VARS['siteid']])) {
|
||||
returnToSender("invalid_parameters");
|
||||
}
|
||||
if (is_empty($VARS['pageid']) || !$database->has("pages", ["AND" => ["pageid" => $VARS['pageid'], "siteid" => $VARS['siteid']]])) {
|
||||
if (empty($VARS['pageid']) || !$database->has("pages", ["AND" => ["pageid" => $VARS['pageid'], "siteid" => $VARS['siteid']]])) {
|
||||
returnToSender("invalid_parameters");
|
||||
}
|
||||
if (is_empty($VARS['title'])) {
|
||||
if (empty($VARS['title'])) {
|
||||
returnToSender("invalid_parameters", $VARS['siteid']);
|
||||
}
|
||||
if (is_empty($VARS['template'])) {
|
||||
if (empty($VARS['template'])) {
|
||||
returnToSender("invalid_parameters", $VARS['siteid']);
|
||||
}
|
||||
$nav = null;
|
||||
if ($VARS['innavbar'] == 1) {
|
||||
if (is_empty($VARS['navbartitle'])) {
|
||||
if (empty($VARS['navbartitle'])) {
|
||||
returnToSender("invalid_parameters", $VARS['siteid']);
|
||||
}
|
||||
$nav = $VARS['navbartitle'];
|
||||
@ -122,7 +123,7 @@ switch ($VARS['action']) {
|
||||
"pageid" => $VARS['pageid']
|
||||
]
|
||||
]);
|
||||
if (!is_empty($VARS['navorder']) && preg_match("/^[0-9]+([0-9|]*([0-9])|[0-9])$/", $VARS['navorder'])) {
|
||||
if (!empty($VARS['navorder']) && preg_match("/^[0-9]+([0-9|]*([0-9])|[0-9])$/", $VARS['navorder'])) {
|
||||
$pages = explode("|", preg_replace("/[|]{2,}/", "", $VARS['navorder']));
|
||||
for ($i = 0; $i < count($pages); $i++) {
|
||||
$database->update("pages", [
|
||||
@ -138,24 +139,24 @@ switch ($VARS['action']) {
|
||||
returnToSender("settings_saved", $VARS['siteid'] . "|" . $VARS['pageid']);
|
||||
break;
|
||||
case "sitesettings":
|
||||
if (!account_has_permission($_SESSION['username'], "SITEWRITER")) {
|
||||
if (!$user->hasPermission("SITEWRITER")) {
|
||||
returnToSender("no_permission");
|
||||
}
|
||||
if (!is_empty($VARS['siteid'])) {
|
||||
if (!empty($VARS['siteid'])) {
|
||||
if (!$database->has("sites", ["siteid" => $VARS['siteid']])) {
|
||||
returnToSender("invalid_parameters");
|
||||
}
|
||||
}
|
||||
if (is_empty($VARS['name'])) {
|
||||
if (empty($VARS['name'])) {
|
||||
returnToSender("invalid_parameters");
|
||||
}
|
||||
if (is_empty($VARS['url'])) {
|
||||
if (empty($VARS['url'])) {
|
||||
returnToSender("invalid_parameters");
|
||||
}
|
||||
if (is_empty($VARS['theme'])) {
|
||||
if (empty($VARS['theme'])) {
|
||||
returnToSender("invalid_parameters");
|
||||
}
|
||||
if (is_empty($VARS['color'])) {
|
||||
if (empty($VARS['color'])) {
|
||||
returnToSender("invalid_parameters");
|
||||
}
|
||||
$url = formatsiteurl($VARS['url']);
|
||||
@ -167,7 +168,7 @@ switch ($VARS['action']) {
|
||||
if ($color != "default" && !file_exists(__DIR__ . "/public/themes/$theme/colors/$color")) {
|
||||
returnToSender("invalid_parameters");
|
||||
}
|
||||
if (is_empty($VARS['siteid'])) {
|
||||
if (empty($VARS['siteid'])) {
|
||||
$database->insert('sites', ["sitename" => $VARS['name'], "url" => $url, "theme" => $theme, "color" => $color]);
|
||||
$siteid = $database->id();
|
||||
$template = (file_exists(__DIR__ . "/public/themes/$theme/home.php") ? "home" : "default");
|
||||
@ -198,8 +199,8 @@ switch ($VARS['action']) {
|
||||
break;
|
||||
case "saveedits":
|
||||
header("Content-Type: application/json");
|
||||
if (!account_has_permission($_SESSION['username'], "SITEWRITER") && !account_has_permission($_SESSION['username'], "SITEWRITER_EDIT")) {
|
||||
exit(json_encode(['status' => "ERROR", 'message' => lang("no permission", false)]));
|
||||
if (!$user->hasPermission("SITEWRITER") && !$user->hasPermission("SITEWRITER_EDIT")) {
|
||||
exit(json_encode(['status' => "ERROR", 'message' => $Strings->get("no permission", false)]));
|
||||
}
|
||||
$slug = $VARS['slug'];
|
||||
$site = $VARS['site'];
|
||||
@ -228,7 +229,7 @@ switch ($VARS['action']) {
|
||||
exit(json_encode(["status" => "OK"]));
|
||||
break;
|
||||
case "deletemessage":
|
||||
if (!account_has_permission($_SESSION['username'], "SITEWRITER") && !account_has_permission($_SESSION['username'], "SITEWRITER_CONTACT")) {
|
||||
if (!$user->hasPermission("SITEWRITER") && !$user->hasPermission("SITEWRITER_CONTACT")) {
|
||||
returnToSender("no_permission");
|
||||
}
|
||||
if ($database->count('messages', ["mid" => $VARS['id']]) !== 1) {
|
||||
@ -238,11 +239,11 @@ switch ($VARS['action']) {
|
||||
returnToSender("message_deleted");
|
||||
break;
|
||||
case "fileupload":
|
||||
if (!account_has_permission($_SESSION['username'], "SITEWRITER") && !account_has_permission($_SESSION['username'], "SITEWRITER_FILES")) {
|
||||
if (!$user->hasPermission("SITEWRITER") && !$user->hasPermission("SITEWRITER_FILES")) {
|
||||
returnToSender("no_permission");
|
||||
}
|
||||
$destpath = FILE_UPLOAD_PATH . $VARS['path'];
|
||||
if (strpos(realpath($destpath), FILE_UPLOAD_PATH) !== 0) {
|
||||
$destpath = $SETTINGS["file_upload_path"] . $VARS['path'];
|
||||
if (strpos(realpath($destpath), $SETTINGS["file_upload_path"]) !== 0) {
|
||||
returnToSender("file_security_error");
|
||||
}
|
||||
if (!file_exists($destpath) || !is_dir($destpath)) {
|
||||
@ -310,11 +311,11 @@ switch ($VARS['action']) {
|
||||
returnToSender("upload_success", "&path=" . $VARS['path']);
|
||||
break;
|
||||
case "newfolder":
|
||||
if (!account_has_permission($_SESSION['username'], "SITEWRITER") && !account_has_permission($_SESSION['username'], "SITEWRITER_FILES")) {
|
||||
if (!$user->hasPermission("SITEWRITER") && !$user->hasPermission("SITEWRITER_FILES")) {
|
||||
returnToSender("no_permission");
|
||||
}
|
||||
$foldername = preg_replace("/[^a-z0-9_\-]/", "_", strtolower($VARS['folder']));
|
||||
$newfolder = FILE_UPLOAD_PATH . $VARS['path'] . '/' . $foldername;
|
||||
$newfolder = $SETTINGS["file_upload_path"] . $VARS['path'] . '/' . $foldername;
|
||||
|
||||
if (mkdir($newfolder, 0755)) {
|
||||
returnToSender("folder_created", "&path=" . $VARS['path']);
|
||||
@ -322,18 +323,18 @@ switch ($VARS['action']) {
|
||||
returnToSender("folder_not_created", "&path=" . $VARS['path']);
|
||||
break;
|
||||
case "filedelete":
|
||||
if (!account_has_permission($_SESSION['username'], "SITEWRITER") && !account_has_permission($_SESSION['username'], "SITEWRITER_FILES")) {
|
||||
if (!$user->hasPermission("SITEWRITER") && !$user->hasPermission("SITEWRITER_FILES")) {
|
||||
returnToSender("no_permission");
|
||||
}
|
||||
$file = FILE_UPLOAD_PATH . $VARS['file'];
|
||||
if (strpos(realpath($file), FILE_UPLOAD_PATH) !== 0) {
|
||||
$file = $SETTINGS["file_upload_path"] . $VARS['file'];
|
||||
if (strpos(realpath($file), $SETTINGS["file_upload_path"]) !== 0) {
|
||||
returnToSender("file_security_error");
|
||||
}
|
||||
if (!file_exists($file)) {
|
||||
// Either way the file is gone
|
||||
returnToSender("file_deleted");
|
||||
}
|
||||
if (!is_writable($file) || realpath($file) == realpath(FILE_UPLOAD_PATH)) {
|
||||
if (!is_writable($file) || realpath($file) == realpath($SETTINGS["file_upload_path"])) {
|
||||
returnToSender("undeletable_file");
|
||||
}
|
||||
if (is_dir($file)) {
|
||||
@ -349,9 +350,9 @@ switch ($VARS['action']) {
|
||||
break;
|
||||
case "unsplash_download":
|
||||
Crew\Unsplash\HttpClient::init([
|
||||
'applicationId' => UNSPLASH_ACCESSKEY,
|
||||
'secret' => UNSPLASH_SECRETKEY,
|
||||
'utmSource' => UNSPLASH_UTMSOURCE
|
||||
'applicationId' => $SETTINGS["unsplash"]["accesskey"],
|
||||
'secret' => $SETTINGS["unsplash"]["secretkey"],
|
||||
'utmSource' => $SETTINGS["unsplash"]["utmsource"]
|
||||
]);
|
||||
Crew\Unsplash\Photo::find($VARS['imageid'])->download();
|
||||
header('Content-Type: application/json');
|
||||
@ -359,6 +360,6 @@ switch ($VARS['action']) {
|
||||
break;
|
||||
case "signout":
|
||||
session_destroy();
|
||||
header('Location: index.php');
|
||||
header('Location: index.php?logout=1');
|
||||
die("Logged out.");
|
||||
}
|
35
api.php
35
api.php
@ -4,37 +4,6 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Simple JSON API to allow other apps to access data from this app.
|
||||
*
|
||||
* Requests can be sent via either GET or POST requests. POST is recommended
|
||||
* as it has a lower chance of being logged on the server, exposing unencrypted
|
||||
* user passwords.
|
||||
*/
|
||||
require __DIR__ . '/required.php';
|
||||
require_once __DIR__ . '/lib/login.php';
|
||||
require_once __DIR__ . '/lib/userinfo.php';
|
||||
header("Content-Type: application/json");
|
||||
|
||||
$username = $VARS['username'];
|
||||
$password = $VARS['password'];
|
||||
if (user_exists($username) !== true || authenticate_user($username, $password, $errmsg) !== true) {
|
||||
header("HTTP/1.1 403 Unauthorized");
|
||||
die("\"403 Unauthorized\"");
|
||||
}
|
||||
$userinfo = getUserByUsername($username);
|
||||
|
||||
// query max results
|
||||
$max = 20;
|
||||
if (preg_match("/^[0-9]+$/", $VARS['max']) === 1 && $VARS['max'] <= 1000) {
|
||||
$max = (int) $VARS['max'];
|
||||
}
|
||||
|
||||
switch ($VARS['action']) {
|
||||
case "ping":
|
||||
$out = ["status" => "OK", "maxresults" => $max, "pong" => true];
|
||||
exit(json_encode($out));
|
||||
default:
|
||||
header("HTTP/1.1 400 Bad Request");
|
||||
die("\"400 Bad Request\"");
|
||||
}
|
||||
// Load in new API from legacy location (a.k.a. here)
|
||||
require __DIR__ . "/api/index.php";
|
5
api/.htaccess
Normal file
5
api/.htaccess
Normal file
@ -0,0 +1,5 @@
|
||||
# Rewrite for Nextcloud Notes API
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine on
|
||||
RewriteRule ([a-zA-Z0-9]+) index.php?action=$1 [PT]
|
||||
</IfModule>
|
9
api/actions/ping.php
Normal file
9
api/actions/ping.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
sendJsonResp();
|
15
api/apisettings.php
Normal file
15
api/apisettings.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
$APIS = [
|
||||
"ping" => [
|
||||
"load" => "ping.php",
|
||||
"vars" => [
|
||||
]
|
||||
]
|
||||
];
|
149
api/functions.php
Normal file
149
api/functions.php
Normal file
@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Build and send a simple JSON response.
|
||||
* @param string $msg A message
|
||||
* @param string $status "OK" or "ERROR"
|
||||
* @param array $data More JSON data
|
||||
*/
|
||||
function sendJsonResp(string $msg = null, string $status = "OK", array $data = null) {
|
||||
$resp = [];
|
||||
if (!is_null($data)) {
|
||||
$resp = $data;
|
||||
}
|
||||
if (!is_null($msg)) {
|
||||
$resp["msg"] = $msg;
|
||||
}
|
||||
$resp["status"] = $status;
|
||||
header("Content-Type: application/json");
|
||||
exit(json_encode($resp));
|
||||
}
|
||||
|
||||
function exitWithJson(array $json) {
|
||||
header("Content-Type: application/json");
|
||||
exit(json_encode($json));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the API key with most of the characters replaced with *s.
|
||||
* @global string $key
|
||||
* @return string
|
||||
*/
|
||||
function getCensoredKey() {
|
||||
global $key;
|
||||
$resp = $key;
|
||||
if (strlen($key) > 5) {
|
||||
for ($i = 2; $i < strlen($key) - 2; $i++) {
|
||||
$resp[$i] = "*";
|
||||
}
|
||||
}
|
||||
return $resp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the request is allowed
|
||||
* @global array $VARS
|
||||
* @return bool true if the request should continue, false if the request is bad
|
||||
*/
|
||||
function authenticate(): bool {
|
||||
global $VARS, $SETTINGS;
|
||||
// HTTP basic auth
|
||||
if (!empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW'])) {
|
||||
$username = $_SERVER['PHP_AUTH_USER'];
|
||||
$password = $_SERVER['PHP_AUTH_PW'];
|
||||
} else if (!empty($VARS['username']) && !empty($VARS['password'])) {
|
||||
$username = $VARS['username'];
|
||||
$password = $VARS['password'];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
$user = User::byUsername($username);
|
||||
if (!$user->exists()) {
|
||||
return false;
|
||||
}
|
||||
if ($user->checkPassword($password, true)) {
|
||||
// Check that the user has permission to access the app
|
||||
$perms = is_array($SETTINGS['api_permissions']) ? $SETTINGS['api_permissions'] : $SETTINGS['permissions'];
|
||||
foreach ($perms as $perm) {
|
||||
if (!$user->hasPermission($perm)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the User whose credentials were used to make the request.
|
||||
*/
|
||||
function getRequestUser(): User {
|
||||
global $VARS;
|
||||
if (!empty($_SERVER['PHP_AUTH_USER'])) {
|
||||
return User::byUsername($_SERVER['PHP_AUTH_USER']);
|
||||
} else {
|
||||
return User::byUsername($VARS['username']);
|
||||
}
|
||||
}
|
||||
|
||||
function checkVars($vars, $or = false) {
|
||||
global $VARS;
|
||||
$ok = [];
|
||||
foreach ($vars as $key => $val) {
|
||||
if (strpos($key, "OR") === 0) {
|
||||
checkVars($vars[$key], true);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only check type of optional variables if they're set, and don't
|
||||
// mark them as bad if they're not set
|
||||
if (strpos($key, " (optional)") !== false) {
|
||||
$key = str_replace(" (optional)", "", $key);
|
||||
if (empty($VARS[$key])) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (empty($VARS[$key])) {
|
||||
$ok[$key] = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (strpos($val, "/") === 0) {
|
||||
// regex
|
||||
$ok[$key] = preg_match($val, $VARS[$key]) === 1;
|
||||
} else {
|
||||
$checkmethod = "is_$val";
|
||||
$ok[$key] = !($checkmethod($VARS[$key]) !== true);
|
||||
}
|
||||
}
|
||||
if ($or) {
|
||||
$success = false;
|
||||
$bad = "";
|
||||
foreach ($ok as $k => $v) {
|
||||
if ($v) {
|
||||
$success = true;
|
||||
break;
|
||||
} else {
|
||||
$bad = $k;
|
||||
}
|
||||
}
|
||||
if (!$success) {
|
||||
http_response_code(400);
|
||||
die("400 Bad request: variable $bad is missing or invalid");
|
||||
}
|
||||
} else {
|
||||
foreach ($ok as $key => $bool) {
|
||||
if (!$bool) {
|
||||
http_response_code(400);
|
||||
die("400 Bad request: variable $key is missing or invalid");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
81
api/index.php
Normal file
81
api/index.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
require __DIR__ . '/../required.php';
|
||||
require __DIR__ . '/functions.php';
|
||||
require __DIR__ . '/apisettings.php';
|
||||
|
||||
header("Access-Control-Allow-Origin: *");
|
||||
|
||||
$VARS = $_GET;
|
||||
if ($_SERVER['REQUEST_METHOD'] != "GET") {
|
||||
$VARS = array_merge($VARS, $_POST);
|
||||
}
|
||||
|
||||
$requestbody = file_get_contents('php://input');
|
||||
$requestjson = json_decode($requestbody, TRUE);
|
||||
if (json_last_error() == JSON_ERROR_NONE) {
|
||||
$VARS = array_merge($VARS, $requestjson);
|
||||
}
|
||||
|
||||
// If we're not using the old api.php file, allow more flexible requests
|
||||
if (strpos($_SERVER['REQUEST_URI'], "/api.php") === FALSE) {
|
||||
$route = explode("/", substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], "api/") + 4));
|
||||
|
||||
if (count($route) >= 1) {
|
||||
$VARS["action"] = $route[0];
|
||||
}
|
||||
if (count($route) >= 2 && strpos($route[1], "?") !== 0) {
|
||||
for ($i = 1; $i < count($route); $i++) {
|
||||
if (empty($route[$i]) || strpos($route[$i], "=") === false) {
|
||||
continue;
|
||||
}
|
||||
$key = explode("=", $route[$i], 2)[0];
|
||||
$val = explode("=", $route[$i], 2)[1];
|
||||
$VARS[$key] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
if (strpos($route[count($route) - 1], "?") === 0) {
|
||||
$morevars = explode("&", substr($route[count($route) - 1], 1));
|
||||
foreach ($morevars as $var) {
|
||||
$key = explode("=", $var, 2)[0];
|
||||
$val = explode("=", $var, 2)[1];
|
||||
$VARS[$key] = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!authenticate()) {
|
||||
header('WWW-Authenticate: Basic realm="' . $SETTINGS['site_title'] . '"');
|
||||
header('HTTP/1.1 401 Unauthorized');
|
||||
die("401 Unauthorized: you need to supply valid credentials.");
|
||||
}
|
||||
|
||||
if (empty($VARS['action'])) {
|
||||
http_response_code(404);
|
||||
die("404 No action specified");
|
||||
}
|
||||
|
||||
if (!isset($APIS[$VARS['action']])) {
|
||||
http_response_code(404);
|
||||
die("404 Action not defined");
|
||||
}
|
||||
|
||||
$APIACTION = $APIS[$VARS["action"]];
|
||||
|
||||
if (!file_exists(__DIR__ . "/actions/" . $APIACTION["load"])) {
|
||||
http_response_code(404);
|
||||
die("404 Action not found");
|
||||
}
|
||||
|
||||
if (!empty($APIACTION["vars"])) {
|
||||
checkVars($APIACTION["vars"]);
|
||||
}
|
||||
|
||||
require_once __DIR__ . "/actions/" . $APIACTION["load"];
|
85
app.php
85
app.php
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
@ -14,7 +13,7 @@ if ($_SESSION['loggedin'] != true) {
|
||||
require_once __DIR__ . "/pages.php";
|
||||
|
||||
$pageid = "home";
|
||||
if (isset($_GET['page']) && !is_empty($_GET['page'])) {
|
||||
if (!empty($_GET['page'])) {
|
||||
$pg = strtolower($_GET['page']);
|
||||
$pg = preg_replace('/[^0-9a-z_]/', "", $pg);
|
||||
if (array_key_exists($pg, PAGES) && file_exists(__DIR__ . "/pages/" . $pg . ".php")) {
|
||||
@ -28,10 +27,10 @@ header("Link: <static/fonts/Roboto.css>; rel=preload; as=style", false);
|
||||
header("Link: <static/css/bootstrap.min.css>; rel=preload; as=style", false);
|
||||
header("Link: <static/css/material-color/material-color.min.css>; rel=preload; as=style", false);
|
||||
header("Link: <static/css/app.css>; rel=preload; as=style", false);
|
||||
header("Link: <static/css/fa-svg-with-js.css>; rel=preload; as=style", false);
|
||||
header("Link: <static/css/svg-with-js.min.css>; rel=preload; as=style", false);
|
||||
header("Link: <static/js/fontawesome-all.min.js>; rel=preload; as=script", false);
|
||||
header("Link: <static/js/jquery-3.3.1.min.js>; rel=preload; as=script", false);
|
||||
header("Link: <static/js/bootstrap.min.js>; rel=preload; as=script", false);
|
||||
header("Link: <static/js/bootstrap.bundle.min.js>; rel=preload; as=script", false);
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
@ -40,14 +39,14 @@ header("Link: <static/js/bootstrap.min.js>; rel=preload; as=script", false);
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<title><?php echo SITE_TITLE; ?></title>
|
||||
<title><?php echo $SETTINGS['site_title']; ?></title>
|
||||
|
||||
<link rel="icon" href="static/img/logo.svg">
|
||||
|
||||
<link href="static/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="static/css/material-color/material-color.min.css" rel="stylesheet">
|
||||
<link href="static/css/app.css" rel="stylesheet">
|
||||
<link href="static/css/fa-svg-with-js.css" rel="stylesheet">
|
||||
<link href="static/css/svg-with-js.min.css" rel="stylesheet">
|
||||
<script nonce="<?php echo $SECURE_NONCE; ?>">
|
||||
FontAwesomeConfig = {autoAddCss: false}
|
||||
</script>
|
||||
@ -66,35 +65,47 @@ header("Link: <static/js/bootstrap.min.js>; rel=preload; as=script", false);
|
||||
|
||||
<?php
|
||||
// Alert messages
|
||||
if (isset($_GET['msg']) && !is_empty($_GET['msg']) && array_key_exists($_GET['msg'], MESSAGES)) {
|
||||
// optional string generation argument
|
||||
if (!isset($_GET['arg']) || is_empty($_GET['arg'])) {
|
||||
$alertmsg = lang(MESSAGES[$_GET['msg']]['string'], false);
|
||||
if (!empty($_GET['msg'])) {
|
||||
if (array_key_exists($_GET['msg'], MESSAGES)) {
|
||||
// optional string generation argument
|
||||
if (empty($_GET['arg'])) {
|
||||
$alertmsg = $Strings->get(MESSAGES[$_GET['msg']]['string'], false);
|
||||
} else {
|
||||
$alertmsg = $Strings->build(MESSAGES[$_GET['msg']]['string'], ["arg" => strip_tags($_GET['arg'])], false);
|
||||
}
|
||||
$alerttype = MESSAGES[$_GET['msg']]['type'];
|
||||
$alerticon = "square-o";
|
||||
switch (MESSAGES[$_GET['msg']]['type']) {
|
||||
case "danger":
|
||||
$alerticon = "times";
|
||||
break;
|
||||
case "warning":
|
||||
$alerticon = "exclamation-triangle";
|
||||
break;
|
||||
case "info":
|
||||
$alerticon = "info-circle";
|
||||
break;
|
||||
case "success":
|
||||
$alerticon = "check";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$alertmsg = lang2(MESSAGES[$_GET['msg']]['string'], ["arg" => strip_tags($_GET['arg'])], false);
|
||||
}
|
||||
$alerttype = MESSAGES[$_GET['msg']]['type'];
|
||||
$alerticon = "square-o";
|
||||
switch (MESSAGES[$_GET['msg']]['type']) {
|
||||
case "danger":
|
||||
$alerticon = "times";
|
||||
break;
|
||||
case "warning":
|
||||
$alerticon = "exclamation-triangle";
|
||||
break;
|
||||
case "info":
|
||||
$alerticon = "info-circle";
|
||||
break;
|
||||
case "success":
|
||||
$alerticon = "check";
|
||||
break;
|
||||
// We don't have a message for this, so just assume an error and escape stuff.
|
||||
$alertmsg = htmlentities($Strings->get($_GET['msg'], false));
|
||||
$alerticon = "times";
|
||||
$alerttype = "danger";
|
||||
}
|
||||
echo <<<END
|
||||
<div class="row justify-content-center" id="msg-alert-box">
|
||||
<div class="col-11 col-sm-6 col-md-5 col-lg-4 col-xl-4">
|
||||
<div class="alert alert-dismissible alert-$alerttype">
|
||||
<button type="button" class="close">×</button>
|
||||
<i class="fas fa-$alerticon"></i> $alertmsg
|
||||
<div class="alert alert-dismissible alert-$alerttype mt-2 p-0 border-0 shadow">
|
||||
<div class="p-2 pl-3">
|
||||
<button type="button" class="close">×</button>
|
||||
<i class="fas fa-$alerticon"></i> $alertmsg
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div class="progress-bar bg-$alerttype w-0" id="msg-alert-timeout-bar"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -116,7 +127,7 @@ END;
|
||||
</button>
|
||||
<a class="navbar-brand py-0 mr-auto" href="app.php">
|
||||
<img src="static/img/logo.svg" alt="" class="d-none d-<?php echo $navbar_breakpoint; ?>-inline brand-img py-0" />
|
||||
<?php echo SITE_TITLE; ?>
|
||||
<?php echo $SETTINGS['site_title']; ?>
|
||||
</a>
|
||||
|
||||
<div class="collapse navbar-collapse py-0" id="navbar-collapse">
|
||||
@ -141,7 +152,7 @@ END;
|
||||
if (isset($pg['icon'])) {
|
||||
?><i class="<?php echo $pg['icon']; ?> fa-fw"></i> <?php
|
||||
}
|
||||
lang($pg['title']);
|
||||
$Strings->get($pg['title']);
|
||||
?>
|
||||
</a>
|
||||
</span>
|
||||
@ -152,13 +163,13 @@ END;
|
||||
</div>
|
||||
<div class="navbar-nav ml-auto py-0" id="navbar-right">
|
||||
<span class="nav-item py-<?php echo $navbar_breakpoint; ?>-0">
|
||||
<a class="nav-link py-<?php echo $navbar_breakpoint; ?>-0" href="<?php echo PORTAL_URL; ?>">
|
||||
<a class="nav-link py-<?php echo $navbar_breakpoint; ?>-0" href="<?php echo $SETTINGS['accounthub']['home']; ?>">
|
||||
<i class="fas fa-user fa-fw"></i><span> <?php echo $_SESSION['realname'] ?></span>
|
||||
</a>
|
||||
</span>
|
||||
<span class="nav-item mr-auto py-<?php echo $navbar_breakpoint; ?>-0">
|
||||
<a class="nav-link py-<?php echo $navbar_breakpoint; ?>-0" href="action.php?action=signout">
|
||||
<i class="fas fa-sign-out-alt fa-fw"></i><span> <?php lang("sign out") ?></span>
|
||||
<i class="fas fa-sign-out-alt fa-fw"></i><span> <?php $Strings->get("sign out") ?></span>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
@ -172,12 +183,12 @@ END;
|
||||
?>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<?php echo FOOTER_TEXT; ?><br />
|
||||
Copyright © <?php echo date('Y'); ?> <?php echo COPYRIGHT_NAME; ?>
|
||||
<?php echo $SETTINGS['footer_text']; ?><br />
|
||||
Copyright © <?php echo date('Y'); ?> <?php echo $SETTINGS['copyright']; ?>
|
||||
</div>
|
||||
</div>
|
||||
<script src="static/js/jquery-3.3.1.min.js"></script>
|
||||
<script src="static/js/bootstrap.min.js"></script>
|
||||
<script src="static/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="static/js/app.js"></script>
|
||||
<?php
|
||||
// custom page scripts
|
||||
|
@ -3,10 +3,11 @@
|
||||
"description": "Template for a webapp integrated with an AccountHub server.",
|
||||
"type": "project",
|
||||
"require": {
|
||||
"catfan/medoo": "^1.5",
|
||||
"catfan/medoo": "^1.7",
|
||||
"guzzlehttp/guzzle": "^6.2",
|
||||
"geoip2/geoip2": "~2.0",
|
||||
"unsplash/unsplash": "^2.4"
|
||||
"geoip2/geoip2": "^2.11",
|
||||
"unsplash/unsplash": "^3.1",
|
||||
"phpmailer/phpmailer": "^6.1"
|
||||
},
|
||||
"license": "MPL-2.0",
|
||||
"authors": [
|
||||
|
610
composer.lock
generated
610
composer.lock
generated
@ -4,21 +4,20 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "14eefa1d98fa62ca2f2fe52de606868c",
|
||||
"content-hash": "e9f318b9d8bd1dfa6c7fb56c820d1910",
|
||||
"content-hash": "fca7101f9c5ca04ba9cf15ae46d3867a",
|
||||
"packages": [
|
||||
{
|
||||
"name": "catfan/medoo",
|
||||
"version": "v1.5.6",
|
||||
"version": "v1.7.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/catfan/Medoo.git",
|
||||
"reference": "f77a93f72864e892c99d1033b8733e5da8fb0b3b"
|
||||
"reference": "2d675f73e23f63bbaeb9a8aa33318659a3d3c32f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/catfan/Medoo/zipball/f77a93f72864e892c99d1033b8733e5da8fb0b3b",
|
||||
"reference": "f77a93f72864e892c99d1033b8733e5da8fb0b3b",
|
||||
"url": "https://api.github.com/repos/catfan/Medoo/zipball/2d675f73e23f63bbaeb9a8aa33318659a3d3c32f",
|
||||
"reference": "2d675f73e23f63bbaeb9a8aa33318659a3d3c32f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -32,7 +31,7 @@
|
||||
"ext-pdo_oci8": "For Oracle version 8 database",
|
||||
"ext-pdo_pqsql": "For PostgreSQL database",
|
||||
"ext-pdo_sqlite": "For SQLite database",
|
||||
"ext-pdo_sqlsrv": "For MSSQL database"
|
||||
"ext-pdo_sqlsrv": "For MSSQL database on both Window/Liunx platform"
|
||||
},
|
||||
"type": "framework",
|
||||
"autoload": {
|
||||
@ -50,10 +49,11 @@
|
||||
"email": "angel@catfan.me"
|
||||
}
|
||||
],
|
||||
"description": "The lightest PHP database framework to accelerate development",
|
||||
"description": "The lightweight PHP database framework to accelerate development",
|
||||
"homepage": "https://medoo.in",
|
||||
"keywords": [
|
||||
"database",
|
||||
"database library",
|
||||
"lightweight",
|
||||
"mariadb",
|
||||
"mssql",
|
||||
@ -64,31 +64,31 @@
|
||||
"sql",
|
||||
"sqlite"
|
||||
],
|
||||
"time": "2018-03-26 17:54:24"
|
||||
"time": "2020-02-11T08:20:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/ca-bundle",
|
||||
"version": "1.1.1",
|
||||
"version": "1.2.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/ca-bundle.git",
|
||||
"reference": "d2c0a83b7533d6912e8d516756ebd34f893e9169"
|
||||
"reference": "8a7ecad675253e4654ea05505233285377405215"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/d2c0a83b7533d6912e8d516756ebd34f893e9169",
|
||||
"reference": "d2c0a83b7533d6912e8d516756ebd34f893e9169",
|
||||
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/8a7ecad675253e4654ea05505233285377405215",
|
||||
"reference": "8a7ecad675253e4654ea05505233285377405215",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-openssl": "*",
|
||||
"ext-pcre": "*",
|
||||
"php": "^5.3.2 || ^7.0"
|
||||
"php": "^5.3.2 || ^7.0 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5",
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8",
|
||||
"psr/log": "^1.0",
|
||||
"symfony/process": "^2.5 || ^3.0 || ^4.0"
|
||||
"symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@ -120,30 +120,31 @@
|
||||
"ssl",
|
||||
"tls"
|
||||
],
|
||||
"time": "2018-03-29 19:57:20"
|
||||
"time": "2020-08-23T12:54:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "geoip2/geoip2",
|
||||
"version": "v2.9.0",
|
||||
"version": "v2.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/maxmind/GeoIP2-php.git",
|
||||
"reference": "a807fbf65212eef5d8d2db1a1b31082b53633d77"
|
||||
"reference": "d01be5894a5c1a3381c58c9b1795cd07f96c30f7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/maxmind/GeoIP2-php/zipball/a807fbf65212eef5d8d2db1a1b31082b53633d77",
|
||||
"reference": "a807fbf65212eef5d8d2db1a1b31082b53633d77",
|
||||
"url": "https://api.github.com/repos/maxmind/GeoIP2-php/zipball/d01be5894a5c1a3381c58c9b1795cd07f96c30f7",
|
||||
"reference": "d01be5894a5c1a3381c58c9b1795cd07f96c30f7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"maxmind-db/reader": "~1.0",
|
||||
"maxmind/web-service-common": "~0.5",
|
||||
"php": ">=5.4"
|
||||
"ext-json": "*",
|
||||
"maxmind-db/reader": "~1.8",
|
||||
"maxmind/web-service-common": "~0.8",
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "2.*",
|
||||
"phpunit/phpunit": "4.*",
|
||||
"phpunit/phpunit": "^8.0 || ^9.0",
|
||||
"squizlabs/php_codesniffer": "3.*"
|
||||
},
|
||||
"type": "library",
|
||||
@ -160,7 +161,7 @@
|
||||
{
|
||||
"name": "Gregory J. Oschwald",
|
||||
"email": "goschwald@maxmind.com",
|
||||
"homepage": "http://www.maxmind.com/"
|
||||
"homepage": "https://www.maxmind.com/"
|
||||
}
|
||||
],
|
||||
"description": "MaxMind GeoIP2 PHP API",
|
||||
@ -172,31 +173,33 @@
|
||||
"geolocation",
|
||||
"maxmind"
|
||||
],
|
||||
"time": "2018-04-10 15:32:59"
|
||||
"time": "2020-10-01T18:48:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
"version": "6.3.2",
|
||||
"version": "6.5.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/guzzle.git",
|
||||
"reference": "68d0ea14d5a3f42a20e87632a5f84931e2709c90"
|
||||
"reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/68d0ea14d5a3f42a20e87632a5f84931e2709c90",
|
||||
"reference": "68d0ea14d5a3f42a20e87632a5f84931e2709c90",
|
||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/9d4290de1cfd701f38099ef7e183b64b4b7b0c5e",
|
||||
"reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"guzzlehttp/promises": "^1.0",
|
||||
"guzzlehttp/psr7": "^1.4",
|
||||
"php": ">=5.5"
|
||||
"guzzlehttp/psr7": "^1.6.1",
|
||||
"php": ">=5.5",
|
||||
"symfony/polyfill-intl-idn": "^1.17.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-curl": "*",
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4",
|
||||
"psr/log": "^1.0"
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
|
||||
"psr/log": "^1.1"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/log": "Required for using the Log middleware"
|
||||
@ -204,16 +207,16 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "6.3-dev"
|
||||
"dev-master": "6.5-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions_include.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\": "src/"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"src/functions_include.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@ -237,27 +240,27 @@
|
||||
"rest",
|
||||
"web service"
|
||||
],
|
||||
"time": "2018-03-26 16:33:04"
|
||||
"time": "2020-06-16T21:01:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/promises",
|
||||
"version": "v1.3.1",
|
||||
"version": "1.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/promises.git",
|
||||
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
|
||||
"reference": "60d379c243457e073cff02bc323a2a86cb355631"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
|
||||
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
|
||||
"url": "https://api.github.com/repos/guzzle/promises/zipball/60d379c243457e073cff02bc323a2a86cb355631",
|
||||
"reference": "60d379c243457e073cff02bc323a2a86cb355631",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5.0"
|
||||
"php": ">=5.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.0"
|
||||
"symfony/phpunit-bridge": "^4.4 || ^5.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@ -288,36 +291,41 @@
|
||||
"keywords": [
|
||||
"promise"
|
||||
],
|
||||
"time": "2016-12-20 10:07:11"
|
||||
"time": "2020-09-30T07:37:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/psr7",
|
||||
"version": "1.4.2",
|
||||
"version": "1.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/psr7.git",
|
||||
"reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c"
|
||||
"reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
|
||||
"reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
|
||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/53330f47520498c0ae1f61f7e2c90f55690c06a3",
|
||||
"reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4.0",
|
||||
"psr/http-message": "~1.0"
|
||||
"psr/http-message": "~1.0",
|
||||
"ralouphie/getallheaders": "^2.0.5 || ^3.0.0"
|
||||
},
|
||||
"provide": {
|
||||
"psr/http-message-implementation": "1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
"ext-zlib": "*",
|
||||
"phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10"
|
||||
},
|
||||
"suggest": {
|
||||
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.4-dev"
|
||||
"dev-master": "1.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -347,13 +355,14 @@
|
||||
"keywords": [
|
||||
"http",
|
||||
"message",
|
||||
"psr-7",
|
||||
"request",
|
||||
"response",
|
||||
"stream",
|
||||
"uri",
|
||||
"url"
|
||||
],
|
||||
"time": "2017-03-20 17:10:46"
|
||||
"time": "2020-09-30T07:37:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "hughbertd/oauth2-unsplash",
|
||||
@ -405,25 +414,25 @@
|
||||
"oauth2",
|
||||
"single sign on"
|
||||
],
|
||||
"time": "2017-12-14 13:08:42"
|
||||
"time": "2017-12-14T13:08:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/oauth2-client",
|
||||
"version": "2.3.0",
|
||||
"version": "2.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/oauth2-client.git",
|
||||
"reference": "aa2e3df188f0bfd87f7880cc880e906e99923580"
|
||||
"reference": "d9f2a1e000dc14eb3c02e15d15759385ec7ff0fb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/aa2e3df188f0bfd87f7880cc880e906e99923580",
|
||||
"reference": "aa2e3df188f0bfd87f7880cc880e906e99923580",
|
||||
"url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/d9f2a1e000dc14eb3c02e15d15759385ec7ff0fb",
|
||||
"reference": "d9f2a1e000dc14eb3c02e15d15759385ec7ff0fb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"guzzlehttp/guzzle": "^6.0",
|
||||
"paragonie/random_compat": "^1|^2",
|
||||
"guzzlehttp/guzzle": "^6.0 || ^7.0",
|
||||
"paragonie/random_compat": "^1|^2|^9.99",
|
||||
"php": "^5.6|^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
@ -472,29 +481,33 @@
|
||||
"oauth2",
|
||||
"single sign on"
|
||||
],
|
||||
"time": "2018-01-13 05:27:58"
|
||||
"time": "2020-07-18T17:54:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "maxmind-db/reader",
|
||||
"version": "v1.3.0",
|
||||
"version": "v1.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/maxmind/MaxMind-DB-Reader-php.git",
|
||||
"reference": "e042b4f8a2dff41e19019faf16427178b07fbd58"
|
||||
"reference": "b566d429ac9aec10594b0935be8ff38302f8d5c8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/e042b4f8a2dff41e19019faf16427178b07fbd58",
|
||||
"reference": "e042b4f8a2dff41e19019faf16427178b07fbd58",
|
||||
"url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/b566d429ac9aec10594b0935be8ff38302f8d5c8",
|
||||
"reference": "b566d429ac9aec10594b0935be8ff38302f8d5c8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4"
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"conflict": {
|
||||
"ext-maxminddb": "<1.8.0,>=2.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "2.*",
|
||||
"phpunit/phpunit": "4.* || 5.*",
|
||||
"satooshi/php-coveralls": "1.0.*",
|
||||
"php-coveralls/php-coveralls": "^2.1",
|
||||
"phpunit/phpcov": ">=6.0.0",
|
||||
"phpunit/phpunit": ">=8.0.0,<10.0.0",
|
||||
"squizlabs/php_codesniffer": "3.*"
|
||||
},
|
||||
"suggest": {
|
||||
@ -516,7 +529,7 @@
|
||||
{
|
||||
"name": "Gregory J. Oschwald",
|
||||
"email": "goschwald@maxmind.com",
|
||||
"homepage": "http://www.maxmind.com/"
|
||||
"homepage": "https://www.maxmind.com/"
|
||||
}
|
||||
],
|
||||
"description": "MaxMind DB Reader API",
|
||||
@ -528,31 +541,31 @@
|
||||
"geolocation",
|
||||
"maxmind"
|
||||
],
|
||||
"time": "2018-02-21 21:23:33"
|
||||
"time": "2020-10-01T17:30:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "maxmind/web-service-common",
|
||||
"version": "v0.5.0",
|
||||
"version": "v0.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/maxmind/web-service-common-php.git",
|
||||
"reference": "61a9836fa3bb1743ab89752bae5005d71e78c73b"
|
||||
"reference": "ba67d9532cfaf499bd71774b8170d05df4f75fb7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/61a9836fa3bb1743ab89752bae5005d71e78c73b",
|
||||
"reference": "61a9836fa3bb1743ab89752bae5005d71e78c73b",
|
||||
"url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/ba67d9532cfaf499bd71774b8170d05df4f75fb7",
|
||||
"reference": "ba67d9532cfaf499bd71774b8170d05df4f75fb7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer/ca-bundle": "^1.0.3",
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"php": ">=5.4"
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "2.*",
|
||||
"phpunit/phpunit": "4.*",
|
||||
"phpunit/phpunit": "^8.0 || ^9.0",
|
||||
"squizlabs/php_codesniffer": "3.*"
|
||||
},
|
||||
"type": "library",
|
||||
@ -574,37 +587,33 @@
|
||||
],
|
||||
"description": "Internal MaxMind Web Service API",
|
||||
"homepage": "https://github.com/maxmind/web-service-common-php",
|
||||
"time": "2018-02-12 22:31:54"
|
||||
"time": "2020-10-01T15:28:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
"version": "v2.0.12",
|
||||
"version": "v9.99.100",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/random_compat.git",
|
||||
"reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb"
|
||||
"reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/258c89a6b97de7dfaf5b8c7607d0478e236b04fb",
|
||||
"reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
|
||||
"reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2.0"
|
||||
"php": ">= 7"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.*|5.*"
|
||||
"phpunit/phpunit": "4.*|5.*",
|
||||
"vimeo/psalm": "^1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"lib/random.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
@ -619,10 +628,74 @@
|
||||
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
|
||||
"keywords": [
|
||||
"csprng",
|
||||
"polyfill",
|
||||
"pseudorandom",
|
||||
"random"
|
||||
],
|
||||
"time": "2018-04-04 21:24:14"
|
||||
"time": "2020-10-15T08:29:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpmailer/phpmailer",
|
||||
"version": "v6.1.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPMailer/PHPMailer.git",
|
||||
"reference": "917ab212fa00dc6eacbb26e8bc387ebe40993bc1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/917ab212fa00dc6eacbb26e8bc387ebe40993bc1",
|
||||
"reference": "917ab212fa00dc6eacbb26e8bc387ebe40993bc1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-ctype": "*",
|
||||
"ext-filter": "*",
|
||||
"ext-hash": "*",
|
||||
"php": ">=5.5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/annotations": "^1.2",
|
||||
"friendsofphp/php-cs-fixer": "^2.2",
|
||||
"phpunit/phpunit": "^4.8 || ^5.7"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mbstring": "Needed to send email in multibyte encoding charset",
|
||||
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
|
||||
"league/oauth2-google": "Needed for Google XOAUTH2 authentication",
|
||||
"psr/log": "For optional PSR-3 debug logging",
|
||||
"stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication",
|
||||
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PHPMailer\\PHPMailer\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-2.1-only"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marcus Bointon",
|
||||
"email": "phpmailer@synchromedia.co.uk"
|
||||
},
|
||||
{
|
||||
"name": "Jim Jagielski",
|
||||
"email": "jimjag@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Andy Prevost",
|
||||
"email": "codeworxtech@users.sourceforge.net"
|
||||
},
|
||||
{
|
||||
"name": "Brent R. Matzelle"
|
||||
}
|
||||
],
|
||||
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
|
||||
"time": "2020-10-09T14:55:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-message",
|
||||
@ -672,40 +745,339 @@
|
||||
"request",
|
||||
"response"
|
||||
],
|
||||
"time": "2016-08-06 14:39:51"
|
||||
"time": "2016-08-06T14:39:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "unsplash/unsplash",
|
||||
"version": "2.4.3",
|
||||
"name": "ralouphie/getallheaders",
|
||||
"version": "3.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/unsplash/unsplash-php.git",
|
||||
"reference": "7c6fed642cf4234545624a1263d57c9cb0970fbf"
|
||||
"url": "https://github.com/ralouphie/getallheaders.git",
|
||||
"reference": "120b605dfeb996808c31b6477290a714d356e822"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/unsplash/unsplash-php/zipball/7c6fed642cf4234545624a1263d57c9cb0970fbf",
|
||||
"reference": "7c6fed642cf4234545624a1263d57c9cb0970fbf",
|
||||
"url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
|
||||
"reference": "120b605dfeb996808c31b6477290a714d356e822",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"guzzlehttp/guzzle": "^6.3.0",
|
||||
"hughbertd/oauth2-unsplash": ">=1.0.3",
|
||||
"league/oauth2-client": ">=1.4.2",
|
||||
"php": ">=5.6.0"
|
||||
"php": ">=5.6"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "~0.9.0",
|
||||
"php-vcr/php-vcr": "dev-master",
|
||||
"php-vcr/phpunit-testlistener-vcr": "*",
|
||||
"phpunit/phpunit": "~5.1",
|
||||
"satooshi/php-coveralls": "dev-master",
|
||||
"vlucas/phpdotenv": "dev-master"
|
||||
"php-coveralls/php-coveralls": "^2.1",
|
||||
"phpunit/phpunit": "^5 || ^6.5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/getallheaders.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ralph Khattar",
|
||||
"email": "ralph.khattar@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "A polyfill for getallheaders.",
|
||||
"time": "2019-03-08T08:55:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-idn",
|
||||
"version": "v1.19.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-idn.git",
|
||||
"reference": "4ad5115c0f5d5172a9fe8147675ec6de266d8826"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/4ad5115c0f5d5172a9fe8147675ec6de266d8826",
|
||||
"reference": "4ad5115c0f5d5172a9fe8147675ec6de266d8826",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"symfony/polyfill-intl-normalizer": "^1.10",
|
||||
"symfony/polyfill-php70": "^1.10",
|
||||
"symfony/polyfill-php72": "^1.10"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.19-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Intl\\Idn\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Laurent Bassin",
|
||||
"email": "laurent@bassin.info"
|
||||
},
|
||||
{
|
||||
"name": "Trevor Rowbotham",
|
||||
"email": "trevor.rowbotham@pm.me"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"idn",
|
||||
"intl",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2020-10-21T09:57:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-normalizer",
|
||||
"version": "v1.19.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
|
||||
"reference": "8db0ae7936b42feb370840cf24de1a144fb0ef27"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8db0ae7936b42feb370840cf24de1a144fb0ef27",
|
||||
"reference": "8db0ae7936b42feb370840cf24de1a144fb0ef27",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.19-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Intl\\Normalizer\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"classmap": [
|
||||
"Resources/stubs"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for intl's Normalizer class and related functions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"intl",
|
||||
"normalizer",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2020-10-23T09:01:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php70",
|
||||
"version": "v1.19.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php70.git",
|
||||
"reference": "3fe414077251a81a1b15b1c709faf5c2fbae3d4e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/3fe414077251a81a1b15b1c709faf5c2fbae3d4e",
|
||||
"reference": "3fe414077251a81a1b15b1c709faf5c2fbae3d4e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"paragonie/random_compat": "~1.0|~2.0|~9.99",
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.19-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Php70\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"classmap": [
|
||||
"Resources/stubs"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2020-10-23T09:01:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php72",
|
||||
"version": "v1.19.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php72.git",
|
||||
"reference": "beecef6b463b06954638f02378f52496cb84bacc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/beecef6b463b06954638f02378f52496cb84bacc",
|
||||
"reference": "beecef6b463b06954638f02378f52496cb84bacc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.19-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Php72\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2020-10-23T09:01:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "unsplash/unsplash",
|
||||
"version": "3.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/unsplash/unsplash-php.git",
|
||||
"reference": "6f9cf13ff4538589717bd7eadabd65a2b175c321"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/unsplash/unsplash-php/zipball/6f9cf13ff4538589717bd7eadabd65a2b175c321",
|
||||
"reference": "6f9cf13ff4538589717bd7eadabd65a2b175c321",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"guzzlehttp/guzzle": "^6.3.0|^7.0.1",
|
||||
"hughbertd/oauth2-unsplash": ">=1.0.3",
|
||||
"league/oauth2-client": ">=1.4.2",
|
||||
"php": ">=7.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "~1.4.0",
|
||||
"php-vcr/php-vcr": "~1.4",
|
||||
"php-vcr/phpunit-testlistener-vcr": "~3.1",
|
||||
"phpunit/phpunit": "~9.0",
|
||||
"vlucas/phpdotenv": "~4.1.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Crew\\Unsplash\\": "src/"
|
||||
"Unsplash\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
@ -713,14 +1085,6 @@
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Charles Lalonde",
|
||||
"email": "charles@pickcrew.com"
|
||||
},
|
||||
{
|
||||
"name": "Hugh Downer",
|
||||
"email": "hugh.downer@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Aaron Klaassen",
|
||||
"email": "aaron@unsplash.com"
|
||||
@ -728,10 +1092,18 @@
|
||||
{
|
||||
"name": "Luke Chesser",
|
||||
"email": "luke@unsplash.com"
|
||||
},
|
||||
{
|
||||
"name": "Charles Lalonde",
|
||||
"email": "charles@pickcrew.com"
|
||||
},
|
||||
{
|
||||
"name": "Hugh Downer",
|
||||
"email": "hugh.downer@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Wrapper to access the Unsplash API and photo library",
|
||||
"time": "2018-03-30 17:45:15"
|
||||
"time": "2020-10-05T22:04:54+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
|
254
index.php
254
index.php
@ -1,161 +1,131 @@
|
||||
<?php
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
require_once __DIR__ . "/required.php";
|
||||
|
||||
require_once __DIR__ . "/lib/login.php";
|
||||
|
||||
// if we're logged in, we don't need to be here.
|
||||
if ($_SESSION['loggedin']) {
|
||||
if (!empty($_SESSION['loggedin']) && $_SESSION['loggedin'] === true && !isset($_GET['permissionerror'])) {
|
||||
header('Location: app.php');
|
||||
die();
|
||||
}
|
||||
|
||||
/* Authenticate user */
|
||||
$userpass_ok = false;
|
||||
$multiauth = false;
|
||||
if (checkLoginServer()) {
|
||||
if ($VARS['progress'] == "1") {
|
||||
if (!CAPTCHA_ENABLED || (CAPTCHA_ENABLED && verifyCaptcheck($VARS['captcheck_session_code'], $VARS['captcheck_selected_answer'], CAPTCHA_SERVER . "/api.php"))) {
|
||||
$errmsg = "";
|
||||
if (authenticate_user($VARS['username'], $VARS['password'], $errmsg)) {
|
||||
switch (get_account_status($VARS['username'])) {
|
||||
case "LOCKED_OR_DISABLED":
|
||||
$alert = lang("account locked", false);
|
||||
break;
|
||||
case "TERMINATED":
|
||||
$alert = lang("account terminated", false);
|
||||
break;
|
||||
case "CHANGE_PASSWORD":
|
||||
$alert = lang("password expired", false);
|
||||
case "NORMAL":
|
||||
$userpass_ok = true;
|
||||
break;
|
||||
case "ALERT_ON_ACCESS":
|
||||
sendLoginAlertEmail($VARS['username']);
|
||||
$userpass_ok = true;
|
||||
break;
|
||||
}
|
||||
if ($userpass_ok) {
|
||||
$_SESSION['passok'] = true; // stop logins using only username and authcode
|
||||
if (userHasTOTP($VARS['username'])) {
|
||||
$multiauth = true;
|
||||
} else {
|
||||
doLoginUser($VARS['username'], $VARS['password']);
|
||||
header('Location: app.php');
|
||||
die("Logged in, go to app.php");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!is_empty($errmsg)) {
|
||||
$alert = lang2("login server error", ['arg' => $errmsg], false);
|
||||
} else {
|
||||
$alert = lang("login incorrect", false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$alert = lang("captcha error", false);
|
||||
}
|
||||
} else if ($VARS['progress'] == "2") {
|
||||
if ($_SESSION['passok'] !== true) {
|
||||
// stop logins using only username and authcode
|
||||
sendError("Password integrity check failed!");
|
||||
}
|
||||
if (verifyTOTP($VARS['username'], $VARS['authcode'])) {
|
||||
if (doLoginUser($VARS['username'])) {
|
||||
header('Location: app.php');
|
||||
die("Logged in, go to app.php");
|
||||
} else {
|
||||
$alert = lang("login server user data error", false);
|
||||
}
|
||||
} else {
|
||||
$alert = lang("2fa incorrect", false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$alert = lang("login server unavailable", false);
|
||||
}
|
||||
header("Link: <static/fonts/Roboto.css>; rel=preload; as=style", false);
|
||||
header("Link: <static/css/bootstrap.min.css>; rel=preload; as=style", false);
|
||||
header("Link: <static/css/material-color/material-color.min.css>; rel=preload; as=style", false);
|
||||
header("Link: <static/css/index.css>; rel=preload; as=style", false);
|
||||
header("Link: <static/js/jquery-3.3.1.min.js>; rel=preload; as=script", false);
|
||||
header("Link: <static/js/bootstrap.min.js>; rel=preload; as=script", false);
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
/**
|
||||
* Show a simple HTML page with a line of text and a button. Matches the UI of
|
||||
* the AccountHub login flow.
|
||||
*
|
||||
* @global type $SETTINGS
|
||||
* @global type $SECURE_NONCE
|
||||
* @global type $Strings
|
||||
* @param string $title Text to show, passed through i18n
|
||||
* @param string $button Button text, passed through i18n
|
||||
* @param string $url URL for the button
|
||||
*/
|
||||
function showHTML(string $title, string $button, string $url) {
|
||||
global $SETTINGS, $SECURE_NONCE, $Strings;
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<title><?php echo SITE_TITLE; ?></title>
|
||||
<title><?php echo $SETTINGS['site_title']; ?></title>
|
||||
|
||||
<link rel="icon" href="static/img/logo.svg">
|
||||
<link rel="icon" href="static/img/logo.svg">
|
||||
|
||||
<link href="static/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="static/css/material-color/material-color.min.css" rel="stylesheet">
|
||||
<link href="static/css/index.css" rel="stylesheet">
|
||||
<?php if (CAPTCHA_ENABLED) { ?>
|
||||
<script src="<?php echo CAPTCHA_SERVER ?>/captcheck.dist.js"></script>
|
||||
<?php } ?>
|
||||
</head>
|
||||
<body>
|
||||
<link href="static/css/bootstrap.min.css" rel="stylesheet">
|
||||
<style nonce="<?php echo $SECURE_NONCE; ?>">
|
||||
.display-5 {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 300;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.banner-image {
|
||||
max-height: 100px;
|
||||
margin: 2em auto;
|
||||
border: 1px solid grey;
|
||||
border-radius: 15%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container mt-4">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-auto">
|
||||
<img class="banner-image" src="static/img/logo.svg" />
|
||||
<div class="col-12 text-center">
|
||||
<img class="banner-image" src="./static/img/logo.svg" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="card col-11 col-xs-11 col-sm-8 col-md-6 col-lg-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><?php lang("sign in"); ?></h5>
|
||||
<form action="" method="POST">
|
||||
<?php
|
||||
if (!is_empty($alert)) {
|
||||
?>
|
||||
<div class="alert alert-danger">
|
||||
<i class="fa fa-fw fa-exclamation-triangle"></i> <?php echo $alert; ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
if ($multiauth != true) {
|
||||
?>
|
||||
<input type="text" class="form-control" name="username" placeholder="<?php lang("username"); ?>" required="required" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" autofocus /><br />
|
||||
<input type="password" class="form-control" name="password" placeholder="<?php lang("password"); ?>" required="required" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" /><br />
|
||||
<?php if (CAPTCHA_ENABLED) { ?>
|
||||
<div class="captcheck_container" data-stylenonce="<?php echo $SECURE_NONCE; ?>"></div>
|
||||
<br />
|
||||
<?php } ?>
|
||||
<input type="hidden" name="progress" value="1" />
|
||||
<?php
|
||||
} else if ($multiauth) {
|
||||
?>
|
||||
<div class="alert alert-info">
|
||||
<?php lang("2fa prompt"); ?>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="authcode" placeholder="<?php lang("authcode"); ?>" required="required" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" autofocus /><br />
|
||||
<input type="hidden" name="progress" value="2" />
|
||||
<input type="hidden" name="username" value="<?php echo $VARS['username']; ?>" />
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<?php lang("continue"); ?>
|
||||
</button>
|
||||
</form>
|
||||
<div class="col-12 text-center">
|
||||
<h1 class="display-5 mb-4"><?php $Strings->get($title); ?></h1>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-8 col-lg-6">
|
||||
<div class="card mt-4">
|
||||
<div class="card-body">
|
||||
<a href="<?php echo $url; ?>" class="btn btn-primary btn-block"><?php $Strings->get($button); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<?php echo FOOTER_TEXT; ?><br />
|
||||
Copyright © <?php echo date('Y'); ?> <?php echo COPYRIGHT_NAME; ?>
|
||||
</div>
|
||||
</div>
|
||||
<script src="static/js/jquery-3.3.1.min.js"></script>
|
||||
<script src="static/js/bootstrap.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
}
|
||||
|
||||
if (!empty($_GET['logout'])) {
|
||||
showHTML("You have been logged out.", "Log in again", "./index.php");
|
||||
die();
|
||||
}
|
||||
if (empty($_SESSION["login_code"])) {
|
||||
$redirecttologin = true;
|
||||
} else {
|
||||
try {
|
||||
$uidinfo = AccountHubApi::get("checkloginkey", ["code" => $_SESSION["login_code"]]);
|
||||
if ($uidinfo["status"] == "ERROR") {
|
||||
throw new Exception();
|
||||
}
|
||||
if (is_numeric($uidinfo['uid'])) {
|
||||
$user = new User($uidinfo['uid'] * 1);
|
||||
foreach ($SETTINGS['permissions'] as $perm) {
|
||||
if (!$user->hasPermission($perm)) {
|
||||
showHTML("no access permission", "sign out", "./action.php?action=signout");
|
||||
die();
|
||||
}
|
||||
}
|
||||
Session::start($user);
|
||||
$_SESSION["login_code"] = null;
|
||||
header('Location: app.php');
|
||||
showHTML("Logged in", "Continue", "./app.php");
|
||||
die();
|
||||
} else {
|
||||
throw new Exception();
|
||||
}
|
||||
} catch (Exception $ex) {
|
||||
$redirecttologin = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($redirecttologin) {
|
||||
try {
|
||||
$urlbase = (isset($_SERVER['HTTPS']) ? "https" : "http") . "://" . $_SERVER['HTTP_HOST'] . (($_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) ? ":" . $_SERVER['SERVER_PORT'] : "");
|
||||
$iconurl = $urlbase . str_replace("index.php", "", $_SERVER["REQUEST_URI"]) . "static/img/logo.svg";
|
||||
$codedata = AccountHubApi::get("getloginkey", ["appname" => $SETTINGS["site_title"], "appicon" => $iconurl]);
|
||||
|
||||
if ($codedata['status'] != "OK") {
|
||||
throw new Exception($Strings->get("login server unavailable", false));
|
||||
}
|
||||
|
||||
$redirecturl = $urlbase . $_SERVER['REQUEST_URI'];
|
||||
|
||||
$_SESSION["login_code"] = $codedata["code"];
|
||||
|
||||
$locationurl = $codedata["loginurl"] . "?code=" . htmlentities($codedata["code"]) . "&redirect=" . htmlentities($redirecturl);
|
||||
header("Location: $locationurl");
|
||||
showHTML("Continue", "Continue", $locationurl);
|
||||
die();
|
||||
} catch (Exception $ex) {
|
||||
sendError($ex->getMessage());
|
||||
}
|
||||
}
|
141
lang/en_us.php
141
lang/en_us.php
@ -1,141 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
define("STRINGS", [
|
||||
"sign in" => "Sign In",
|
||||
"username" => "Username",
|
||||
"password" => "Password",
|
||||
"continue" => "Continue",
|
||||
"authcode" => "Authentication code",
|
||||
"2fa prompt" => "Enter the six-digit code from your mobile authenticator app.",
|
||||
"2fa incorrect" => "Authentication code incorrect.",
|
||||
"login incorrect" => "Login incorrect.",
|
||||
"login server unavailable" => "Login server unavailable. Try again later or contact technical support.",
|
||||
"account locked" => "This account has been disabled. Contact technical support.",
|
||||
"password expired" => "You must change your password before continuing.",
|
||||
"account terminated" => "Account terminated. Access denied.",
|
||||
"account state error" => "Your account state is not stable. Log out, restart your browser, and try again.",
|
||||
"welcome user" => "Welcome, {user}!",
|
||||
"sign out" => "Sign out",
|
||||
"settings" => "Settings",
|
||||
"options" => "Options",
|
||||
"404 error" => "404 Error",
|
||||
"page not found" => "Page not found.",
|
||||
"invalid parameters" => "Invalid request parameters.",
|
||||
"login server error" => "The login server returned an error: {arg}",
|
||||
"login server user data error" => "The login server refused to provide account information. Try again or contact technical support.",
|
||||
"captcha error" => "There was a problem with the CAPTCHA (robot test). Try again.",
|
||||
"actions" => "Actions",
|
||||
"no permission" => "You don't have permission to do that.",
|
||||
"home" => "Home",
|
||||
"editor" => "Editor",
|
||||
"sites" => "Sites",
|
||||
"theme" => "Theme",
|
||||
"name" => "Name",
|
||||
"new site" => "New Site",
|
||||
"site name" => "Site Name",
|
||||
"url" => "URL",
|
||||
"adding site" => "Creating site {site}",
|
||||
"editing site" => "Editing {site}",
|
||||
"settings saved" => "Settings saved",
|
||||
"theme type" => "Theme type",
|
||||
"single page" => "Single page",
|
||||
"multiple page" => "Multiple page",
|
||||
"templates" => "Templates",
|
||||
"template" => "Template",
|
||||
"color styles" => "Color styles",
|
||||
"save" => "Save",
|
||||
"edit" => "Edit",
|
||||
"view" => "View",
|
||||
"preview" => "Preview",
|
||||
"cancel" => "Cancel",
|
||||
"save needed" => "Press Save to see recent changes.",
|
||||
"saved" => "Saved",
|
||||
"icon" => "Icon",
|
||||
"image" => "Image",
|
||||
"link" => "Link",
|
||||
"text" => "Text",
|
||||
"select page or enter url" => "Select a page or enter URL",
|
||||
"edit component" => "Edit component",
|
||||
"default" => "Default",
|
||||
"page added" => "Page added.",
|
||||
"chosen page id slug already taken" => "Chosen page ID (slug) already taken. Choose another.",
|
||||
"template missing" => "Template missing from theme.",
|
||||
"new page" => "New Page",
|
||||
"title" => "Title",
|
||||
"page id" => "Page ID (slug)",
|
||||
"add page" => "Add page",
|
||||
"page settings" => "Page Settings",
|
||||
"analytics" => "Analytics",
|
||||
"today" => "Today",
|
||||
"this week" => "This Week",
|
||||
"visit" => "visit",
|
||||
"visits" => "visits",
|
||||
"page view" => "page view",
|
||||
"page views" => "page views",
|
||||
"site" => "Site",
|
||||
"filter by site" => "Filter by site",
|
||||
"all sites" => "All Sites",
|
||||
"filter" => "Filter",
|
||||
"start date" => "Start date",
|
||||
"end date" => "End date",
|
||||
"recent actions" => "Recent Actions",
|
||||
"overview" => "Overview",
|
||||
"views per visit" => "views per visit",
|
||||
"visits over time" => "Visits Over Time",
|
||||
"page views over time" => "Page Views Over Time",
|
||||
"page ranking" => "Page Ranking",
|
||||
"x views" => "{views} views",
|
||||
"no data" => "No data.",
|
||||
"visitor map" => "Visitor Map",
|
||||
"enable built-in analytics" => "Enable built-in analytics",
|
||||
"disable built-in analytics" => "Disable built-in analytics",
|
||||
"extra code" => "Extra code (inserted in site head)",
|
||||
"company info" => "Company Info",
|
||||
"phone" => "Phone",
|
||||
"address" => "Address",
|
||||
"email" => "Email",
|
||||
"social links" => "Social Links",
|
||||
"site info" => "Site Info",
|
||||
"loading" => "Loading...",
|
||||
"current" => "Current",
|
||||
"messages" => "Messages",
|
||||
"message" => "Message",
|
||||
"date" => "Date",
|
||||
"message deleted" => "Message deleted.",
|
||||
"files" => "Files",
|
||||
"browse" => "Browse",
|
||||
"upload" => "Upload",
|
||||
"operation cancelled for security reasons" => "Operation cancelled for security reasons.",
|
||||
"upload successful" => "Upload successful.",
|
||||
"upload warning" => "Upload finished with some problems:<br>{arg}",
|
||||
"destination folder does not exist" => "Destination folder does not exist.",
|
||||
"destination folder does not allow uploads" => "Destination folder does not allow uploads.",
|
||||
"uploaded data too large" => "Uploaded data too large.",
|
||||
"undeletable file" => "The file could not be deleted.",
|
||||
"folder not empty" => "Folder must be empty to be deleted.",
|
||||
"file not deleted" => "The file could not be deleted.",
|
||||
"file deleted" => "File deleted.",
|
||||
"folder deleted" => "Folder deleted.",
|
||||
"folder created" => "Folder created.",
|
||||
"folder not created" => "Folder not created.",
|
||||
"nothing here" => "There doesn't seem to be anything here...",
|
||||
"navbar options" => "Site Menu Options",
|
||||
"in navbar" => "Add page to menu",
|
||||
"navbar title" => "Page title for menu",
|
||||
"navbar position" => "Menu position (drag to change position):",
|
||||
"remove image" => "Remove image",
|
||||
"site footer links" => "Site Footer Links",
|
||||
"uploaded files" => "Uploaded Files",
|
||||
"stock photos" => "Free Stock Photos",
|
||||
"load more" => "Load more",
|
||||
"search images" => "Search images",
|
||||
"x results" => "{results} results",
|
||||
"reply" => "Reply",
|
||||
"delete" => "Delete",
|
||||
"new folder" => "New Folder",
|
||||
"new" => "New",
|
||||
]);
|
7
langs/en/core.json
Normal file
7
langs/en/core.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"sign out": "Sign out",
|
||||
"404 error": "404 Error",
|
||||
"page not found": "Page not found.",
|
||||
"invalid parameters": "Invalid request parameters.",
|
||||
"login server error": "The login server returned an error: {arg}"
|
||||
}
|
8
langs/en/index.json
Normal file
8
langs/en/index.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"You have been logged out.": "You have been logged out.",
|
||||
"Log in again": "Log in again",
|
||||
"login server unavailable": "Login server unavailable. Try again later or contact technical support.",
|
||||
"no access permission": "You do not have permission to access this system.",
|
||||
"Logged in": "Logged in",
|
||||
"Continue": "Continue"
|
||||
}
|
116
langs/en/strings.json
Normal file
116
langs/en/strings.json
Normal file
@ -0,0 +1,116 @@
|
||||
{
|
||||
"actions": "Actions",
|
||||
"no permission": "You don't have permission to do that.",
|
||||
"editor": "Editor",
|
||||
"sites": "Sites",
|
||||
"theme": "Theme",
|
||||
"name": "Name",
|
||||
"new site": "New Site",
|
||||
"site name": "Site Name",
|
||||
"url": "URL",
|
||||
"adding site": "Creating site {site}",
|
||||
"editing site": "Editing {site}",
|
||||
"settings saved": "Settings saved",
|
||||
"theme type": "Theme type",
|
||||
"single page": "Single page",
|
||||
"multiple page": "Multiple page",
|
||||
"templates": "Templates",
|
||||
"template": "Template",
|
||||
"color styles": "Color styles",
|
||||
"save": "Save",
|
||||
"edit": "Edit",
|
||||
"view": "View",
|
||||
"preview": "Preview",
|
||||
"cancel": "Cancel",
|
||||
"save needed": "Press Save to see recent changes.",
|
||||
"saved": "Saved",
|
||||
"icon": "Icon",
|
||||
"image": "Image",
|
||||
"link": "Link",
|
||||
"text": "Text",
|
||||
"select page or enter url": "Select a page or enter URL",
|
||||
"edit component": "Edit component",
|
||||
"default": "Default",
|
||||
"page added": "Page added.",
|
||||
"chosen page id slug already taken": "Chosen page ID (slug) already taken. Choose another.",
|
||||
"template missing": "Template missing from theme.",
|
||||
"new page": "New Page",
|
||||
"title": "Title",
|
||||
"page id": "Page ID (slug)",
|
||||
"add page": "Add page",
|
||||
"page settings": "Page Settings",
|
||||
"analytics": "Analytics",
|
||||
"today": "Today",
|
||||
"this week": "This Week",
|
||||
"visit": "visit",
|
||||
"visits": "visits",
|
||||
"page view": "page view",
|
||||
"page views": "page views",
|
||||
"site": "Site",
|
||||
"filter by site": "Filter by site",
|
||||
"all sites": "All Sites",
|
||||
"filter": "Filter",
|
||||
"start date": "Start date",
|
||||
"end date": "End date",
|
||||
"recent actions": "Recent Actions",
|
||||
"overview": "Overview",
|
||||
"views per visit": "views per visit",
|
||||
"visits over time": "Visits Over Time",
|
||||
"page views over time": "Page Views Over Time",
|
||||
"page ranking": "Page Ranking",
|
||||
"x views": "{views} views",
|
||||
"no data": "No data.",
|
||||
"visitor map": "Visitor Map",
|
||||
"enable built-in analytics": "Enable built-in analytics",
|
||||
"disable built-in analytics": "Disable built-in analytics",
|
||||
"extra code": "Extra code (inserted in site head)",
|
||||
"company info": "Company Info",
|
||||
"phone": "Phone",
|
||||
"address": "Address",
|
||||
"email": "Email",
|
||||
"social links": "Social Links",
|
||||
"site info": "Site Info",
|
||||
"loading": "Loading...",
|
||||
"current": "Current",
|
||||
"messages": "Messages",
|
||||
"message": "Message",
|
||||
"date": "Date",
|
||||
"message deleted": "Message deleted.",
|
||||
"files": "Files",
|
||||
"browse": "Browse",
|
||||
"upload": "Upload",
|
||||
"operation cancelled for security reasons": "Operation cancelled for security reasons.",
|
||||
"upload successful": "Upload successful.",
|
||||
"upload warning": "Upload finished with some problems:<br>{arg}",
|
||||
"destination folder does not exist": "Destination folder does not exist.",
|
||||
"destination folder does not allow uploads": "Destination folder does not allow uploads.",
|
||||
"uploaded data too large": "Uploaded data too large.",
|
||||
"undeletable file": "The file could not be deleted.",
|
||||
"folder not empty": "Folder must be empty to be deleted.",
|
||||
"file not deleted": "The file could not be deleted.",
|
||||
"file deleted": "File deleted.",
|
||||
"folder deleted": "Folder deleted.",
|
||||
"folder created": "Folder created.",
|
||||
"folder not created": "Folder not created.",
|
||||
"nothing here": "There doesn't seem to be anything here...",
|
||||
"navbar options": "Site Menu Options",
|
||||
"in navbar": "Add page to menu",
|
||||
"navbar title": "Page title for menu",
|
||||
"navbar position": "Menu position (drag to change position):",
|
||||
"remove image": "Remove image",
|
||||
"site footer links": "Site Footer Links",
|
||||
"uploaded files": "Uploaded Files",
|
||||
"stock photos": "Free Stock Photos",
|
||||
"load more": "Load more",
|
||||
"search images": "Search images",
|
||||
"x results": "{results} results",
|
||||
"reply": "Reply",
|
||||
"delete": "Delete",
|
||||
"new folder": "New Folder",
|
||||
"new": "New",
|
||||
"search": "Search",
|
||||
"no results": "No results.",
|
||||
"contact form": "Contact Form",
|
||||
"contact form messages will be forwarded to this email address": "Contact form messages will be forwarded to this email address, if it is set.",
|
||||
"settings": "Settings"
|
||||
}
|
3
langs/en/titles.json
Normal file
3
langs/en/titles.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"home": "Home"
|
||||
}
|
56
lib/AccountHubApi.lib.php
Normal file
56
lib/AccountHubApi.lib.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
class AccountHubApi {
|
||||
|
||||
public static function get(string $action, array $data = null, bool $throwex = false) {
|
||||
global $SETTINGS;
|
||||
|
||||
$content = [
|
||||
"action" => $action,
|
||||
"key" => $SETTINGS['accounthub']['key']
|
||||
];
|
||||
if (!is_null($data)) {
|
||||
$content = array_merge($content, $data);
|
||||
}
|
||||
$options = [
|
||||
'http' => [
|
||||
'method' => 'POST',
|
||||
'content' => json_encode($content),
|
||||
'header' => "Content-Type: application/json\r\n" .
|
||||
"Accept: application/json\r\n",
|
||||
"ignore_errors" => true
|
||||
]
|
||||
];
|
||||
|
||||
$context = stream_context_create($options);
|
||||
$result = file_get_contents($SETTINGS['accounthub']['api'], false, $context);
|
||||
$response = json_decode($result, true);
|
||||
if ($result === false || !AccountHubApi::checkHttpRespCode($http_response_header) || json_last_error() != JSON_ERROR_NONE) {
|
||||
if ($throwex) {
|
||||
throw new Exception($result);
|
||||
} else {
|
||||
sendError($result);
|
||||
}
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
private static function checkHttpRespCode(array $headers): bool {
|
||||
foreach ($headers as $header) {
|
||||
if (preg_match("/HTTP\/[0-9]\.[0-9] [0-9]{3}.*/", $header)) {
|
||||
$respcode = explode(" ", $header)[1] * 1;
|
||||
if ($respcode >= 200 && $respcode < 300) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
13
lib/Exceptions.lib.php
Normal file
13
lib/Exceptions.lib.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
class IncorrectPasswordException extends Exception {
|
||||
public function __construct(string $message = "Incorrect password.", int $code = 0, \Throwable $previous = null) {
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
326
lib/FormBuilder.lib.php
Normal file
326
lib/FormBuilder.lib.php
Normal file
@ -0,0 +1,326 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
class FormBuilder {
|
||||
|
||||
private $items = [];
|
||||
private $hiddenitems = [];
|
||||
private $title = "";
|
||||
private $icon = "";
|
||||
private $buttons = [];
|
||||
private $action = "action.php";
|
||||
private $method = "POST";
|
||||
private $id = "editform";
|
||||
|
||||
/**
|
||||
* Create a form with autogenerated HTML.
|
||||
*
|
||||
* @param string $title Form title/heading
|
||||
* @param string $icon FontAwesone icon next to the title.
|
||||
* @param string $action URL to submit the form to.
|
||||
* @param string $method Form submission method (POST, GET, etc.)
|
||||
*/
|
||||
public function __construct(string $title = "Untitled Form", string $icon = "fas fa-file-alt", string $action = "action.php", string $method = "POST") {
|
||||
$this->title = $title;
|
||||
$this->icon = $icon;
|
||||
$this->action = $action;
|
||||
$this->method = $method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the title of the form.
|
||||
* @param string $title
|
||||
*/
|
||||
public function setTitle(string $title) {
|
||||
$this->title = $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the icon for the form.
|
||||
* @param string $icon FontAwesome icon (example: "fas fa-toilet-paper")
|
||||
*/
|
||||
public function setIcon(string $icon) {
|
||||
$this->icon = $icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL the form will submit to.
|
||||
* @param string $action
|
||||
*/
|
||||
public function setAction(string $action) {
|
||||
$this->action = $action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the form submission method (GET, POST, etc)
|
||||
* @param string $method
|
||||
*/
|
||||
public function setMethod(string $method = "POST") {
|
||||
$this->method = $method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the form ID.
|
||||
* @param string $id
|
||||
*/
|
||||
public function setID(string $id = "editform") {
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an input to the form.
|
||||
*
|
||||
* @param string $name Element name
|
||||
* @param string $value Element value
|
||||
* @param string $type Input type (text, number, date, select, tel...)
|
||||
* @param bool $required If the element is required for form submission.
|
||||
* @param string $id Element ID
|
||||
* @param array $options Array of [value => text] pairs for a select element
|
||||
* @param string $label Text label to display near the input
|
||||
* @param string $icon FontAwesome icon (example: "fas fa-toilet-paper")
|
||||
* @param int $width Bootstrap column width for the input, out of 12.
|
||||
* @param int $minlength Minimum number of characters for the input.
|
||||
* @param int $maxlength Maximum number of characters for the input.
|
||||
* @param string $pattern Regex pattern for custom client-side validation.
|
||||
* @param string $error Message to show if the input doesn't validate.
|
||||
*/
|
||||
public function addInput(string $name, string $value = "", string $type = "text", bool $required = true, string $id = null, array $options = null, string $label = "", string $icon = "", int $width = 4, int $minlength = 1, int $maxlength = 100, string $pattern = "", string $error = "") {
|
||||
$item = [
|
||||
"name" => $name,
|
||||
"value" => $value,
|
||||
"type" => $type,
|
||||
"required" => $required,
|
||||
"label" => $label,
|
||||
"icon" => $icon,
|
||||
"width" => $width,
|
||||
"minlength" => $minlength,
|
||||
"maxlength" => $maxlength
|
||||
];
|
||||
if (!empty($id)) {
|
||||
$item["id"] = $id;
|
||||
}
|
||||
if (!empty($options) && $type == "select") {
|
||||
$item["options"] = $options;
|
||||
}
|
||||
if (!empty($pattern)) {
|
||||
$item["pattern"] = $pattern;
|
||||
}
|
||||
if (!empty($error)) {
|
||||
$item["error"] = $error;
|
||||
}
|
||||
$this->items[] = $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a text input.
|
||||
*
|
||||
* @param string $name Element name
|
||||
* @param string $value Element value
|
||||
* @param bool $required If the element is required for form submission.
|
||||
* @param string $id Element ID
|
||||
* @param string $label Text label to display near the input
|
||||
* @param string $icon FontAwesome icon (example: "fas fa-toilet-paper")
|
||||
* @param int $width Bootstrap column width for the input, out of 12.
|
||||
* @param int $minlength Minimum number of characters for the input.
|
||||
* @param int $maxlength Maximum number of characters for the input.
|
||||
* @param string $pattern Regex pattern for custom client-side validation.
|
||||
* @param string $error Message to show if the input doesn't validate.
|
||||
*/
|
||||
public function addTextInput(string $name, string $value = "", bool $required = true, string $id = "", string $label = "", string $icon = "", int $width = 4, int $minlength = 1, int $maxlength = 100, string $pattern = "", string $error = "") {
|
||||
$this->addInput($name, $value, "text", $required, $id, null, $label, $icon, $width, $minlength, $maxlength, $pattern, $error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a select dropdown.
|
||||
*
|
||||
* @param string $name Element name
|
||||
* @param string $value Element value
|
||||
* @param bool $required If the element is required for form submission.
|
||||
* @param string $id Element ID
|
||||
* @param array $options Array of [value => text] pairs for a select element
|
||||
* @param string $label Text label to display near the input
|
||||
* @param string $icon FontAwesome icon (example: "fas fa-toilet-paper")
|
||||
* @param int $width Bootstrap column width for the input, out of 12.
|
||||
*/
|
||||
public function addSelect(string $name, string $value = "", bool $required = true, string $id = null, array $options = null, string $label = "", string $icon = "", int $width = 4) {
|
||||
$this->addInput($name, $value, "select", $required, $id, $options, $label, $icon, $width);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a button to the form.
|
||||
*
|
||||
* @param string $text Text string to show on the button.
|
||||
* @param string $icon FontAwesome icon to show next to the text.
|
||||
* @param string $href If not null, the button will actually be a hyperlink.
|
||||
* @param string $type Usually "button" or "submit". Ignored if $href is set.
|
||||
* @param string $id The element ID.
|
||||
* @param string $name The element name for the button.
|
||||
* @param string $value The form value for the button. Ignored if $name is null.
|
||||
* @param string $class The CSS classes for the button, if a standard success-colored one isn't right.
|
||||
*/
|
||||
public function addButton(string $text, string $icon = "", string $href = null, string $type = "button", string $id = null, string $name = null, string $value = "", string $class = "btn btn-success") {
|
||||
$button = [
|
||||
"text" => $text,
|
||||
"icon" => $icon,
|
||||
"class" => $class,
|
||||
"type" => $type,
|
||||
"id" => $id,
|
||||
"href" => $href,
|
||||
"name" => $name,
|
||||
"value" => $value
|
||||
];
|
||||
$this->buttons[] = $button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a hidden input.
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
*/
|
||||
public function addHiddenInput(string $name, string $value) {
|
||||
$this->hiddenitems[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the form HTML.
|
||||
* @param bool $echo If false, returns HTML string instead of outputting it.
|
||||
*/
|
||||
public function generate(bool $echo = true) {
|
||||
$html = <<<HTMLTOP
|
||||
<form action="$this->action" method="$this->method" id="$this->id">
|
||||
<div class="card">
|
||||
<h3 class="card-header d-flex">
|
||||
<div>
|
||||
<i class="$this->icon"></i> $this->title
|
||||
</div>
|
||||
</h3>
|
||||
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
HTMLTOP;
|
||||
|
||||
foreach ($this->items as $item) {
|
||||
$required = $item["required"] ? "required" : "";
|
||||
$id = empty($item["id"]) ? "" : "id=\"$item[id]\"";
|
||||
$pattern = empty($item["pattern"]) ? "" : "pattern=\"$item[pattern]\"";
|
||||
if (empty($item['type'])) {
|
||||
$item['type'] = "text";
|
||||
}
|
||||
$itemhtml = "";
|
||||
$itemlabel = "";
|
||||
|
||||
if ($item['type'] == "textarea") {
|
||||
$itemlabel = "<label class=\"mb-0\"><i class=\"$item[icon]\"></i> $item[label]:</label>";
|
||||
} else if ($item['type'] != "checkbox") {
|
||||
$itemlabel = "<label class=\"mb-0\">$item[label]:</label>";
|
||||
}
|
||||
$strippedlabel = strip_tags($item['label']);
|
||||
$itemhtml .= <<<ITEMTOP
|
||||
\n\n <div class="col-12 col-md-$item[width]">
|
||||
<div class="form-group mb-3">
|
||||
$itemlabel
|
||||
ITEMTOP;
|
||||
$inputgrouptop = <<<INPUTG
|
||||
\n <div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="$item[icon]"></i></span>
|
||||
</div>
|
||||
INPUTG;
|
||||
switch ($item['type']) {
|
||||
case "select":
|
||||
$itemhtml .= $inputgrouptop;
|
||||
$itemhtml .= <<<SELECT
|
||||
\n <select class="form-control" name="$item[name]" aria-label="$strippedlabel" $required>
|
||||
SELECT;
|
||||
foreach ($item['options'] as $value => $label) {
|
||||
$selected = "";
|
||||
if (!empty($item['value']) && $value == $item['value']) {
|
||||
$selected = " selected";
|
||||
}
|
||||
$itemhtml .= "\n <option value=\"$value\"$selected>$label</option>";
|
||||
}
|
||||
$itemhtml .= "\n </select>";
|
||||
break;
|
||||
case "checkbox":
|
||||
$itemhtml .= $inputgrouptop;
|
||||
$itemhtml .= <<<CHECKBOX
|
||||
\n <div class="form-group form-check">
|
||||
<input type="checkbox" name="$item[name]" $id class="form-check-input" value="$item[value]" $required aria-label="$strippedlabel">
|
||||
<label class="form-check-label">$item[label]</label>
|
||||
</div>
|
||||
CHECKBOX;
|
||||
break;
|
||||
case "textarea":
|
||||
$val = htmlentities($item['value']);
|
||||
$itemhtml .= <<<TEXTAREA
|
||||
\n <textarea class="form-control" id="info" name="$item[name]" aria-label="$strippedlabel" minlength="$item[minlength]" maxlength="$item[maxlength]" $required>$val</textarea>
|
||||
TEXTAREA;
|
||||
break;
|
||||
default:
|
||||
$itemhtml .= $inputgrouptop;
|
||||
$itemhtml .= <<<INPUT
|
||||
\n <input type="$item[type]" name="$item[name]" $id class="form-control" aria-label="$strippedlabel" minlength="$item[minlength]" maxlength="$item[maxlength]" $pattern value="$item[value]" $required />
|
||||
INPUT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($item["error"])) {
|
||||
$itemhtml .= <<<ERROR
|
||||
\n <div class="invalid-feedback">
|
||||
$item[error]
|
||||
</div>
|
||||
ERROR;
|
||||
}
|
||||
if ($item["type"] != "textarea") {
|
||||
$itemhtml .= "\n </div>";
|
||||
}
|
||||
$itemhtml .= <<<ITEMBOTTOM
|
||||
\n </div>
|
||||
</div>\n
|
||||
ITEMBOTTOM;
|
||||
$html .= $itemhtml;
|
||||
}
|
||||
|
||||
$html .= <<<HTMLBOTTOM
|
||||
|
||||
</div>
|
||||
</div>
|
||||
HTMLBOTTOM;
|
||||
|
||||
if (!empty($this->buttons)) {
|
||||
$html .= "\n <div class=\"card-footer d-flex\">";
|
||||
foreach ($this->buttons as $btn) {
|
||||
$btnhtml = "";
|
||||
$inner = "<i class=\"$btn[icon]\"></i> $btn[text]";
|
||||
$id = empty($btn['id']) ? "" : "id=\"$btn[id]\"";
|
||||
if (!empty($btn['href'])) {
|
||||
$btnhtml = "<a href=\"$btn[href]\" class=\"$btn[class]\" $id>$inner</a>";
|
||||
} else {
|
||||
$name = empty($btn['name']) ? "" : "name=\"$btn[name]\"";
|
||||
$value = (!empty($btn['name']) && !empty($btn['value'])) ? "value=\"$btn[value]\"" : "";
|
||||
$btnhtml = "<button type=\"$btn[type]\" class=\"$btn[class]\" $id $name $value>$inner</button>";
|
||||
}
|
||||
$html .= "\n $btnhtml";
|
||||
}
|
||||
$html .= "\n </div>";
|
||||
}
|
||||
|
||||
$html .= "\n </div>";
|
||||
foreach ($this->hiddenitems as $name => $value) {
|
||||
$value = htmlentities($value);
|
||||
$html .= "\n <input type=\"hidden\" name=\"$name\" value=\"$value\" />";
|
||||
}
|
||||
$html .= "\n</form>\n";
|
||||
|
||||
if ($echo) {
|
||||
echo $html;
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
}
|
135
lib/IPUtils.lib.php
Normal file
135
lib/IPUtils.lib.php
Normal file
@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
class IPUtils {
|
||||
|
||||
/**
|
||||
* Check if a given ipv4 address is in a given cidr
|
||||
* @param string $ip IP to check in IPV4 format eg. 127.0.0.1
|
||||
* @param string $range IP/CIDR netmask eg. 127.0.0.0/24, also 127.0.0.1 is accepted and /32 assumed
|
||||
* @return boolean true if the ip is in this range / false if not.
|
||||
* @author Thorsten Ott <https://gist.github.com/tott/7684443>
|
||||
*/
|
||||
public static function ip4_in_cidr($ip, $cidr) {
|
||||
if (strpos($cidr, '/') == false) {
|
||||
$cidr .= '/32';
|
||||
}
|
||||
// $range is in IP/CIDR format eg 127.0.0.1/24
|
||||
list( $cidr, $netmask ) = explode('/', $cidr, 2);
|
||||
$range_decimal = ip2long($cidr);
|
||||
$ip_decimal = ip2long($ip);
|
||||
$wildcard_decimal = pow(2, ( 32 - $netmask)) - 1;
|
||||
$netmask_decimal = ~ $wildcard_decimal;
|
||||
return ( ( $ip_decimal & $netmask_decimal ) == ( $range_decimal & $netmask_decimal ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given ipv6 address is in a given cidr
|
||||
* @param string $ip IP to check in IPV6 format
|
||||
* @param string $cidr CIDR netmask
|
||||
* @return boolean true if the IP is in this range, false otherwise.
|
||||
* @author MW. <https://stackoverflow.com/a/7952169>
|
||||
*/
|
||||
public static function ip6_in_cidr($ip, $cidr) {
|
||||
$address = inet_pton($ip);
|
||||
$subnetAddress = inet_pton(explode("/", $cidr)[0]);
|
||||
$subnetMask = explode("/", $cidr)[1];
|
||||
|
||||
$addr = str_repeat("f", $subnetMask / 4);
|
||||
switch ($subnetMask % 4) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
$addr .= "8";
|
||||
break;
|
||||
case 2:
|
||||
$addr .= "c";
|
||||
break;
|
||||
case 3:
|
||||
$addr .= "e";
|
||||
break;
|
||||
}
|
||||
$addr = str_pad($addr, 32, '0');
|
||||
$addr = pack("H*", $addr);
|
||||
|
||||
$binMask = $addr;
|
||||
return ($address & $binMask) == $subnetAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the REMOTE_ADDR is on Cloudflare's network.
|
||||
* @return boolean true if it is, otherwise false
|
||||
*/
|
||||
public static function validateCloudflare() {
|
||||
if (filter_var($_SERVER["REMOTE_ADDR"], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
||||
// Using IPv6
|
||||
$cloudflare_ips_v6 = [
|
||||
"2400:cb00::/32",
|
||||
"2405:8100::/32",
|
||||
"2405:b500::/32",
|
||||
"2606:4700::/32",
|
||||
"2803:f800::/32",
|
||||
"2c0f:f248::/32",
|
||||
"2a06:98c0::/29"
|
||||
];
|
||||
$valid = false;
|
||||
foreach ($cloudflare_ips_v6 as $cidr) {
|
||||
if (ip6_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) {
|
||||
$valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Using IPv4
|
||||
$cloudflare_ips_v4 = [
|
||||
"103.21.244.0/22",
|
||||
"103.22.200.0/22",
|
||||
"103.31.4.0/22",
|
||||
"104.16.0.0/12",
|
||||
"108.162.192.0/18",
|
||||
"131.0.72.0/22",
|
||||
"141.101.64.0/18",
|
||||
"162.158.0.0/15",
|
||||
"172.64.0.0/13",
|
||||
"173.245.48.0/20",
|
||||
"188.114.96.0/20",
|
||||
"190.93.240.0/20",
|
||||
"197.234.240.0/22",
|
||||
"198.41.128.0/17"
|
||||
];
|
||||
$valid = false;
|
||||
foreach ($cloudflare_ips_v4 as $cidr) {
|
||||
if (ip4_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) {
|
||||
$valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a good guess at the client's real IP address.
|
||||
*
|
||||
* @return string Client IP or `0.0.0.0` if we can't find anything
|
||||
*/
|
||||
public static function getClientIP() {
|
||||
// If CloudFlare is in the mix, we should use it.
|
||||
// Check if the request is actually from CloudFlare before trusting it.
|
||||
if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
|
||||
if (validateCloudflare()) {
|
||||
return $_SERVER["HTTP_CF_CONNECTING_IP"];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_SERVER["REMOTE_ADDR"])) {
|
||||
return $_SERVER["REMOTE_ADDR"];
|
||||
}
|
||||
|
||||
return "0.0.0.0"; // This will not happen unless we aren't a web server
|
||||
}
|
||||
|
||||
}
|
80
lib/Login.lib.php
Normal file
80
lib/Login.lib.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
class Login {
|
||||
|
||||
const BAD_USERPASS = 1;
|
||||
const BAD_2FA = 2;
|
||||
const ACCOUNT_DISABLED = 3;
|
||||
const LOGIN_OK = 4;
|
||||
|
||||
public static function auth(string $username, string $password, string $twofa = ""): int {
|
||||
global $database;
|
||||
$username = strtolower($username);
|
||||
|
||||
$user = User::byUsername($username);
|
||||
|
||||
if (!$user->exists()) {
|
||||
return Login::BAD_USERPASS;
|
||||
}
|
||||
if (!$user->checkPassword($password)) {
|
||||
return Login::BAD_USERPASS;
|
||||
}
|
||||
|
||||
if ($user->has2fa()) {
|
||||
if (!$user->check2fa($twofa)) {
|
||||
return Login::BAD_2FA;
|
||||
}
|
||||
}
|
||||
|
||||
switch ($user->getStatus()->get()) {
|
||||
case AccountStatus::TERMINATED:
|
||||
return Login::BAD_USERPASS;
|
||||
case AccountStatus::LOCKED_OR_DISABLED:
|
||||
return Login::ACCOUNT_DISABLED;
|
||||
case AccountStatus::NORMAL:
|
||||
default:
|
||||
return Login::LOGIN_OK;
|
||||
}
|
||||
|
||||
return Login::LOGIN_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the login server API for sanity
|
||||
* @return boolean true if OK, else false
|
||||
*/
|
||||
public static function checkLoginServer() {
|
||||
try {
|
||||
$resp = AccountHubApi::get("ping");
|
||||
if ($resp['status'] == "OK") {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given AccountHub API key is valid by attempting to
|
||||
* access the API with it.
|
||||
* @param String $key The API key to check
|
||||
* @return boolean TRUE if the key is valid, FALSE if invalid or something went wrong
|
||||
*/
|
||||
function checkAPIKey($key) {
|
||||
try {
|
||||
$resp = AccountHubApi::get("ping", null, true);
|
||||
return false;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
53
lib/Notifications.lib.php
Normal file
53
lib/Notifications.lib.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
class Notifications {
|
||||
|
||||
/**
|
||||
* Add a new notification.
|
||||
* @global $database
|
||||
* @param User $user
|
||||
* @param string $title
|
||||
* @param string $content
|
||||
* @param string $timestamp If left empty, the current date and time will be used.
|
||||
* @param string $url
|
||||
* @param bool $sensitive If true, the notification is marked as containing sensitive content, and the $content might be hidden on lockscreens and other non-secure places.
|
||||
* @return int The newly-created notification ID.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function add(User $user, string $title, string $content, string $timestamp = "", string $url = "", bool $sensitive = false): int {
|
||||
global $Strings;
|
||||
if ($user->exists()) {
|
||||
if (empty($title) || empty($content)) {
|
||||
throw new Exception($Strings->get("invalid parameters", false));
|
||||
}
|
||||
|
||||
$timestamp = date("Y-m-d H:i:s");
|
||||
if (!empty($timestamp)) {
|
||||
$timestamp = date("Y-m-d H:i:s", strtotime($timestamp));
|
||||
}
|
||||
|
||||
$resp = AccountHubApi::get("addnotification", [
|
||||
'uid' => $user->getUID(),
|
||||
'title' => $title,
|
||||
'content' => $content,
|
||||
'timestamp' => $timestamp,
|
||||
'url' => $url,
|
||||
'sensitive' => $sensitive
|
||||
]
|
||||
);
|
||||
if ($resp['status'] == "OK") {
|
||||
return $resp['id'] * 1;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
throw new Exception($Strings->get("user does not exist", false));
|
||||
}
|
||||
|
||||
}
|
19
lib/Session.lib.php
Normal file
19
lib/Session.lib.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
class Session {
|
||||
|
||||
public static function start(User $user) {
|
||||
$_SESSION['username'] = $user->getUsername();
|
||||
$_SESSION['uid'] = $user->getUID();
|
||||
$_SESSION['email'] = $user->getEmail();
|
||||
$_SESSION['realname'] = $user->getName();
|
||||
$_SESSION['loggedin'] = true;
|
||||
}
|
||||
|
||||
}
|
122
lib/Strings.lib.php
Normal file
122
lib/Strings.lib.php
Normal file
@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides translated language strings.
|
||||
*/
|
||||
class Strings {
|
||||
|
||||
private $language = "en";
|
||||
private $strings = [];
|
||||
|
||||
public function __construct($language = "en") {
|
||||
if (!preg_match("/[a-zA-Z\_\-]+/", $language)) {
|
||||
throw new Exception("Invalid language code $language");
|
||||
}
|
||||
|
||||
$this->load("en");
|
||||
|
||||
if ($language == "en") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_exists(__DIR__ . "/../langs/$language/")) {
|
||||
$this->language = $language;
|
||||
$this->load($language);
|
||||
} else {
|
||||
trigger_error("Language $language could not be found.", E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all JSON files for the specified language.
|
||||
* @param string $language
|
||||
*/
|
||||
private function load(string $language) {
|
||||
$files = glob(__DIR__ . "/../langs/$language/*.json");
|
||||
foreach ($files as $file) {
|
||||
$strings = json_decode(file_get_contents($file), true);
|
||||
foreach ($strings as $key => $val) {
|
||||
if (array_key_exists($key, $this->strings)) {
|
||||
trigger_error("Language key \"$key\" is defined more than once.", E_USER_WARNING);
|
||||
}
|
||||
$this->strings[$key] = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add language strings dynamically.
|
||||
* @param array $strings ["key" => "value", ...]
|
||||
*/
|
||||
public function addStrings(array $strings) {
|
||||
foreach ($strings as $key => $val) {
|
||||
$this->strings[$key] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* I18N string getter. If the key isn't found, it outputs the key itself.
|
||||
* @param string $key
|
||||
* @param bool $echo True to echo the result, false to return it. Default is true.
|
||||
* @return string
|
||||
*/
|
||||
public function get(string $key, bool $echo = true): string {
|
||||
$str = $key;
|
||||
if (array_key_exists($key, $this->strings)) {
|
||||
$str = $this->strings[$key];
|
||||
} else {
|
||||
trigger_error("Language key \"$key\" does not exist in " . $this->language, E_USER_WARNING);
|
||||
}
|
||||
|
||||
if ($echo) {
|
||||
echo $str;
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* I18N string getter (with builder). If the key doesn't exist, outputs the key itself.
|
||||
* @param string $key
|
||||
* @param array $replace key-value array of replacements.
|
||||
* If the string value is "hello {abc}" and you give ["abc" => "123"], the
|
||||
* result will be "hello 123".
|
||||
* @param bool $echo True to echo the result, false to return it. Default is true.
|
||||
* @return string
|
||||
*/
|
||||
public function build(string $key, array $replace, bool $echo = true): string {
|
||||
$str = $key;
|
||||
if (array_key_exists($key, $this->strings)) {
|
||||
$str = $this->strings[$key];
|
||||
} else {
|
||||
trigger_error("Language key \"$key\" does not exist in " . $this->language, E_USER_WARNING);
|
||||
}
|
||||
|
||||
foreach ($replace as $find => $repl) {
|
||||
$str = str_replace("{" . $find . "}", $repl, $str);
|
||||
}
|
||||
|
||||
if ($echo) {
|
||||
echo $str;
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns a JSON key:value string for the supplied array of keys.
|
||||
* @param array $keys ["key1", "key2", ...]
|
||||
*/
|
||||
public function getJSON(array $keys): string {
|
||||
$strings = [];
|
||||
foreach ($keys as $k) {
|
||||
$strings[$k] = $this->get($k, false);
|
||||
}
|
||||
return json_encode($strings);
|
||||
}
|
||||
|
||||
}
|
221
lib/User.lib.php
Normal file
221
lib/User.lib.php
Normal file
@ -0,0 +1,221 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
class User {
|
||||
|
||||
private $uid = null;
|
||||
private $username;
|
||||
private $email;
|
||||
private $realname;
|
||||
private $has2fa = false;
|
||||
private $exists = false;
|
||||
|
||||
public function __construct(int $uid, string $username = "") {
|
||||
// Check if user exists
|
||||
$resp = AccountHubApi::get("userexists", ["uid" => $uid]);
|
||||
if ($resp['status'] == "OK" && $resp['exists'] === true) {
|
||||
$this->exists = true;
|
||||
} else {
|
||||
$this->uid = $uid;
|
||||
$this->username = $username;
|
||||
$this->exists = false;
|
||||
}
|
||||
|
||||
if ($this->exists) {
|
||||
// Get user info
|
||||
$resp = AccountHubApi::get("userinfo", ["uid" => $uid]);
|
||||
if ($resp['status'] == "OK") {
|
||||
$this->uid = $resp['data']['uid'] * 1;
|
||||
$this->username = $resp['data']['username'];
|
||||
$this->email = $resp['data']['email'];
|
||||
$this->realname = $resp['data']['name'];
|
||||
} else {
|
||||
sendError("Login server error: " . $resp['msg']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function byUsername(string $username): User {
|
||||
$resp = AccountHubApi::get("userinfo", ["username" => $username]);
|
||||
if (!isset($resp['status'])) {
|
||||
sendError("Login server error: " . $resp);
|
||||
}
|
||||
if ($resp['status'] == "OK") {
|
||||
return new self($resp['data']['uid'] * 1);
|
||||
} else {
|
||||
return new self(-1, $username);
|
||||
}
|
||||
}
|
||||
|
||||
public function exists(): bool {
|
||||
return $this->exists;
|
||||
}
|
||||
|
||||
public function has2fa(): bool {
|
||||
if (!$this->exists) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$resp = AccountHubApi::get("hastotp", ['username' => $this->username]);
|
||||
if ($resp['status'] == "OK") {
|
||||
return $resp['otp'] == true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function getUsername() {
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
function getUID() {
|
||||
return $this->uid;
|
||||
}
|
||||
|
||||
function getEmail() {
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
function getName() {
|
||||
return $this->realname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the given plaintext password against the stored hash.
|
||||
* @param string $password
|
||||
* @param bool $apppass Set to true to enforce app passwords when 2fa is on.
|
||||
* @return bool
|
||||
*/
|
||||
function checkPassword(string $password, bool $apppass = false): bool {
|
||||
$resp = AccountHubApi::get("auth", ['username' => $this->username, 'password' => $password, 'apppass' => ($apppass ? "1" : "0")]);
|
||||
if ($resp['status'] == "OK") {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function check2fa(string $code): bool {
|
||||
if (!$this->has2fa) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$resp = AccountHubApi::get("verifytotp", ['username' => $this->username, 'code' => $code]);
|
||||
if ($resp['status'] == "OK") {
|
||||
return $resp['valid'];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given username has the given permission (or admin access)
|
||||
* @global $database $database
|
||||
* @param string $code
|
||||
* @return boolean TRUE if the user has the permission (or admin access), else FALSE
|
||||
*/
|
||||
function hasPermission(string $code): bool {
|
||||
$resp = AccountHubApi::get("permission", ['username' => $this->username, 'code' => $code]);
|
||||
if ($resp['status'] == "OK") {
|
||||
return $resp['has_permission'];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the account status.
|
||||
* @return \AccountStatus
|
||||
*/
|
||||
function getStatus(): AccountStatus {
|
||||
$resp = AccountHubApi::get("acctstatus", ['username' => $this->username]);
|
||||
if ($resp['status'] == "OK") {
|
||||
return AccountStatus::fromString($resp['account']);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function sendAlertEmail(string $appname = null) {
|
||||
global $SETTINGS;
|
||||
if (is_null($appname)) {
|
||||
$appname = $SETTINGS['site_title'];
|
||||
}
|
||||
$resp = AccountHubApi::get("alertemail", ['username' => $this->username, 'appname' => $SETTINGS['site_title']]);
|
||||
|
||||
if ($resp['status'] == "OK") {
|
||||
return true;
|
||||
} else {
|
||||
return $resp['msg'];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class AccountStatus {
|
||||
|
||||
const NORMAL = 1;
|
||||
const LOCKED_OR_DISABLED = 2;
|
||||
const CHANGE_PASSWORD = 3;
|
||||
const TERMINATED = 4;
|
||||
const ALERT_ON_ACCESS = 5;
|
||||
|
||||
private $status;
|
||||
|
||||
public function __construct(int $status) {
|
||||
$this->status = $status;
|
||||
}
|
||||
|
||||
public static function fromString(string $status): AccountStatus {
|
||||
switch ($status) {
|
||||
case "NORMAL":
|
||||
return new self(self::NORMAL);
|
||||
case "LOCKED_OR_DISABLED":
|
||||
return new self(self::LOCKED_OR_DISABLED);
|
||||
case "CHANGE_PASSWORD":
|
||||
return new self(self::CHANGE_PASSWORD);
|
||||
case "TERMINATED":
|
||||
return new self(self::TERMINATED);
|
||||
case "ALERT_ON_ACCESS":
|
||||
return new self(self::ALERT_ON_ACCESS);
|
||||
default:
|
||||
return new self(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the account status/state as an integer.
|
||||
* @return int
|
||||
*/
|
||||
public function get(): int {
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the account status/state as a string representation.
|
||||
* @return string
|
||||
*/
|
||||
public function getString(): string {
|
||||
switch ($this->status) {
|
||||
case self::NORMAL:
|
||||
return "NORMAL";
|
||||
case self::LOCKED_OR_DISABLED:
|
||||
return "LOCKED_OR_DISABLED";
|
||||
case self::CHANGE_PASSWORD:
|
||||
return "CHANGE_PASSWORD";
|
||||
case self::TERMINATED:
|
||||
return "TERMINATED";
|
||||
case self::ALERT_ON_ACCESS:
|
||||
return "ALERT_ON_ACCESS";
|
||||
default:
|
||||
return "OTHER_" . $this->status;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
2523
lib/bots.json
2523
lib/bots.json
File diff suppressed because it is too large
Load Diff
4552
lib/crawler-user-agents.json
Normal file
4552
lib/crawler-user-agents.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -9,10 +9,10 @@ dieifnotloggedin();
|
||||
|
||||
include_once __DIR__ . "/../lib/mimetypes.php";
|
||||
|
||||
$base = FILE_UPLOAD_PATH;
|
||||
$base = $SETTINGS["file_upload_path"];
|
||||
|
||||
$folder = "";
|
||||
if (isset($VARS['path']) && file_exists($base . $VARS['path']) && strpos(realpath($base . $VARS['path']), FILE_UPLOAD_PATH) === 0) {
|
||||
if (isset($VARS['path']) && file_exists($base . $VARS['path']) && strpos(realpath($base . $VARS['path']), $SETTINGS["file_upload_path"]) === 0) {
|
||||
$folder = $VARS['path'];
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ if (isset($VARS['type']) && $VARS['type'] != "") {
|
||||
$type = explode("|", $VARS['type']);
|
||||
}
|
||||
|
||||
$enableunsplash = ENABLE_UNSPLASH;
|
||||
$enableunsplash = $SETTINGS["unsplash"]["enable"];
|
||||
if (count($type) > 0 && !in_array("image", $type)) {
|
||||
$enableunsplash = false;
|
||||
}
|
||||
@ -35,12 +35,12 @@ if ($enableunsplash) {
|
||||
<ul class="nav nav-tabs" id="fileBrowserTabs" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" id="uploadedFilesTabBtn" data-toggle="tab" href="#uploadedFilesTab">
|
||||
<i class="fas fa-folder-open"></i> <?php lang('uploaded files'); ?>
|
||||
<i class="fas fa-folder-open"></i> <?php $Strings->get('uploaded files'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="unsplashTabBtn" data-toggle="tab" href="#unsplashTab">
|
||||
<i class="fas fa-image"></i> <?php lang('stock photos'); ?>
|
||||
<i class="fas fa-image"></i> <?php $Strings->get('stock photos'); ?>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@ -60,20 +60,20 @@ if ($enableunsplash) {
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" id="unsplashSearch" placeholder="<?php lang("search images"); ?>" />
|
||||
<input type="text" class="form-control" id="unsplashSearch" placeholder="<?php $Strings->get("search images"); ?>" />
|
||||
<div class="input-group-append">
|
||||
<div class="btn btn-primary" id="unsplashSearchBtn">
|
||||
<i class="fas fa-search"></i> <?php lang("search"); ?>
|
||||
<i class="fas fa-search"></i> <?php $Strings->get("search"); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span id="unsplashResults"></span> <span>via <a href="https://unsplash.com/?utm_source=<?php echo urlencode(UNSPLASH_UTMSOURCE); ?>&utm_medium=referral">Unsplash</a></span>
|
||||
<span id="unsplashResults"></span> <span>via <a href="https://unsplash.com/?utm_source=<?php echo urlencode($SETTINGS["unsplash"]["utmsource"]); ?>&utm_medium=referral">Unsplash</a></span>
|
||||
</div>
|
||||
<div id="unsplashPhotoBin" class="px-2 pr-3">
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<button type="button" class="btn btn-primary btn-block" id="unsplashLoadMoreBtn">
|
||||
<?php lang("load more"); ?>
|
||||
<?php $Strings->get("load more"); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -9,10 +9,10 @@ dieifnotloggedin();
|
||||
|
||||
include_once __DIR__ . "/../lib/mimetypes.php";
|
||||
|
||||
$base = FILE_UPLOAD_PATH;
|
||||
$base = $SETTINGS["file_upload_path"];
|
||||
|
||||
$folder = "";
|
||||
if (isset($VARS['path']) && file_exists($base . $VARS['path']) && strpos(realpath($base . $VARS['path']), FILE_UPLOAD_PATH) === 0) {
|
||||
if (isset($VARS['path']) && file_exists($base . $VARS['path']) && strpos(realpath($base . $VARS['path']), $SETTINGS["file_upload_path"]) === 0) {
|
||||
$folder = $VARS['path'];
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ if (isset($VARS['type']) && $VARS['type'] != "") {
|
||||
$type = explode("|", $VARS['type']);
|
||||
}
|
||||
|
||||
$enableunsplash = ENABLE_UNSPLASH;
|
||||
$enableunsplash = $SETTINGS["unsplash"]["enable"];
|
||||
if (count($type) > 0 && !in_array("image", $type)) {
|
||||
$enableunsplash = false;
|
||||
}
|
||||
@ -129,7 +129,7 @@ $fullpath = $base . $folder;
|
||||
<i class="far fa-folder-open fa-5x fa-fw"></i>
|
||||
</p>
|
||||
<p class="h5 text-muted">
|
||||
<?php lang("nothing here"); ?>
|
||||
<?php $Strings->get("nothing here"); ?>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
|
@ -13,9 +13,9 @@ dieifnotloggedin();
|
||||
header('Content-Type: application/json');
|
||||
|
||||
Crew\Unsplash\HttpClient::init([
|
||||
'applicationId' => UNSPLASH_ACCESSKEY,
|
||||
'secret' => UNSPLASH_SECRETKEY,
|
||||
'utmSource' => UNSPLASH_UTMSOURCE
|
||||
'applicationId' => $SETTINGS["unsplash"]["accesskey"],
|
||||
'secret' => $SETTINGS["unsplash"]["secretkey"],
|
||||
'utmSource' => $SETTINGS["unsplash"]["utmsource"]
|
||||
]);
|
||||
|
||||
$page = 1;
|
||||
@ -34,12 +34,11 @@ if (isset($_GET['query']) && $_GET['query'] != "") {
|
||||
$images = Crew\Unsplash\Photo::all($page, $per_page, 'popular');
|
||||
}
|
||||
|
||||
$images->
|
||||
|
||||
$htmlout = "";
|
||||
|
||||
if (count($images) == 0) {
|
||||
$htmlout = "<span>" . lang("no results", false) . "</span>";
|
||||
$htmlout = "<div class=\"card text-center\"><div class=\"card-body\"><i class=\"fas fa-search-minus\"></i> " . $Strings->get("no results", false) . "</div></div>";
|
||||
}
|
||||
|
||||
$htmlout .= '<div class="card-columns">';
|
||||
@ -70,7 +69,7 @@ $jsonout = [
|
||||
];
|
||||
|
||||
if (!is_null($results)) {
|
||||
$jsonout['total'] = lang2("x results", ["results" => $results->getTotal()], false);
|
||||
$jsonout['total'] = $Strings->build("x results", ["results" => $results->getTotal()], false);
|
||||
$jsonout['pages'] = $results->getTotalPages();
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -21,7 +21,7 @@ if (!$database->has("settings", ["AND" => ["siteid" => getsiteid(), "key" => "an
|
||||
throw new Exception("Do-Not-Track header detected, skipping analytics");
|
||||
}
|
||||
|
||||
$bots = json_decode(file_get_contents(__DIR__ . "/bots.json"), true);
|
||||
$bots = json_decode(file_get_contents(__DIR__ . "/crawler-user-agents.json"), true);
|
||||
foreach ($bots as $bot) {
|
||||
if (preg_match('/' . $bot['pattern'] . '/', $_SERVER['HTTP_USER_AGENT'])) {
|
||||
throw new Exception("Bot/crawler detected, skipping analytics");
|
||||
@ -78,7 +78,7 @@ if (!$database->has("settings", ["AND" => ["siteid" => getsiteid(), "key" => "an
|
||||
// Lookup IP address
|
||||
//
|
||||
|
||||
$reader = new Reader(GEOIP_DB);
|
||||
$reader = new Reader($SETTINGS["geoip_db"]);
|
||||
|
||||
$record = $reader->city($clientip);
|
||||
|
||||
@ -108,12 +108,12 @@ if (!$database->has("settings", ["AND" => ["siteid" => getsiteid(), "key" => "an
|
||||
"time" => $time
|
||||
]);
|
||||
} catch (GeoIp2\Exception\AddressNotFoundException $e) {
|
||||
if (DEBUG) {
|
||||
if ($SETTINGS["debug"]) {
|
||||
echo "<!-- The client IP was not found in the GeoIP database. -->";
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// Silently fail so the rest of the site still works
|
||||
if (DEBUG) {
|
||||
if ($SETTINGS["debug"]) {
|
||||
echo "<!-- Analytics error: " . $e->getMessage() . " -->";
|
||||
}
|
||||
}
|
||||
|
131
lib/iputils.php
131
lib/iputils.php
@ -1,131 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Check if a given ipv4 address is in a given cidr
|
||||
* @param string $ip IP to check in IPV4 format eg. 127.0.0.1
|
||||
* @param string $range IP/CIDR netmask eg. 127.0.0.0/24, also 127.0.0.1 is accepted and /32 assumed
|
||||
* @return boolean true if the ip is in this range / false if not.
|
||||
* @author Thorsten Ott <https://gist.github.com/tott/7684443>
|
||||
*/
|
||||
function ip4_in_cidr($ip, $cidr) {
|
||||
if (strpos($cidr, '/') == false) {
|
||||
$cidr .= '/32';
|
||||
}
|
||||
// $range is in IP/CIDR format eg 127.0.0.1/24
|
||||
list( $cidr, $netmask ) = explode('/', $cidr, 2);
|
||||
$range_decimal = ip2long($cidr);
|
||||
$ip_decimal = ip2long($ip);
|
||||
$wildcard_decimal = pow(2, ( 32 - $netmask)) - 1;
|
||||
$netmask_decimal = ~ $wildcard_decimal;
|
||||
return ( ( $ip_decimal & $netmask_decimal ) == ( $range_decimal & $netmask_decimal ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given ipv6 address is in a given cidr
|
||||
* @param string $ip IP to check in IPV6 format
|
||||
* @param string $cidr CIDR netmask
|
||||
* @return boolean true if the IP is in this range, false otherwise.
|
||||
* @author MW. <https://stackoverflow.com/a/7952169>
|
||||
*/
|
||||
function ip6_in_cidr($ip, $cidr) {
|
||||
$address = inet_pton($ip);
|
||||
$subnetAddress = inet_pton(explode("/", $cidr)[0]);
|
||||
$subnetMask = explode("/", $cidr)[1];
|
||||
|
||||
$addr = str_repeat("f", $subnetMask / 4);
|
||||
switch ($subnetMask % 4) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
$addr .= "8";
|
||||
break;
|
||||
case 2:
|
||||
$addr .= "c";
|
||||
break;
|
||||
case 3:
|
||||
$addr .= "e";
|
||||
break;
|
||||
}
|
||||
$addr = str_pad($addr, 32, '0');
|
||||
$addr = pack("H*", $addr);
|
||||
|
||||
$binMask = $addr;
|
||||
return ($address & $binMask) == $subnetAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the REMOTE_ADDR is on Cloudflare's network.
|
||||
* @return boolean true if it is, otherwise false
|
||||
*/
|
||||
function validateCloudflare() {
|
||||
if (filter_var($_SERVER["REMOTE_ADDR"], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
||||
// Using IPv6
|
||||
$cloudflare_ips_v6 = [
|
||||
"2400:cb00::/32",
|
||||
"2405:8100::/32",
|
||||
"2405:b500::/32",
|
||||
"2606:4700::/32",
|
||||
"2803:f800::/32",
|
||||
"2c0f:f248::/32",
|
||||
"2a06:98c0::/29"
|
||||
];
|
||||
$valid = false;
|
||||
foreach ($cloudflare_ips_v6 as $cidr) {
|
||||
if (ip6_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) {
|
||||
$valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Using IPv4
|
||||
$cloudflare_ips_v4 = [
|
||||
"103.21.244.0/22",
|
||||
"103.22.200.0/22",
|
||||
"103.31.4.0/22",
|
||||
"104.16.0.0/12",
|
||||
"108.162.192.0/18",
|
||||
"131.0.72.0/22",
|
||||
"141.101.64.0/18",
|
||||
"162.158.0.0/15",
|
||||
"172.64.0.0/13",
|
||||
"173.245.48.0/20",
|
||||
"188.114.96.0/20",
|
||||
"190.93.240.0/20",
|
||||
"197.234.240.0/22",
|
||||
"198.41.128.0/17"
|
||||
];
|
||||
$valid = false;
|
||||
foreach ($cloudflare_ips_v4 as $cidr) {
|
||||
if (ip4_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) {
|
||||
$valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a good guess at the client's real IP address.
|
||||
*
|
||||
* @return string Client IP or `0.0.0.0` if we can't find anything
|
||||
*/
|
||||
function getClientIP() {
|
||||
// If CloudFlare is in the mix, we should use it.
|
||||
// Check if the request is actually from CloudFlare before trusting it.
|
||||
if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
|
||||
if (validateCloudflare()) {
|
||||
return $_SERVER["HTTP_CF_CONNECTING_IP"];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_SERVER["REMOTE_ADDR"])) {
|
||||
return $_SERVER["REMOTE_ADDR"];
|
||||
}
|
||||
|
||||
return "0.0.0.0"; // This will not happen unless we aren't a web server
|
||||
}
|
402
lib/login.php
402
lib/login.php
@ -1,402 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Authentication and account functions. Connects to an AccountHub instance.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Check the login server API for sanity
|
||||
* @return boolean true if OK, else false
|
||||
*/
|
||||
function checkLoginServer() {
|
||||
try {
|
||||
$client = new GuzzleHttp\Client();
|
||||
|
||||
$response = $client
|
||||
->request('POST', PORTAL_API, [
|
||||
'form_params' => [
|
||||
'key' => PORTAL_KEY,
|
||||
'action' => "ping"
|
||||
]
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() != 200) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$resp = json_decode($response->getBody(), TRUE);
|
||||
if ($resp['status'] == "OK") {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given AccountHub API key is valid by attempting to
|
||||
* access the API with it.
|
||||
* @param String $key The API key to check
|
||||
* @return boolean TRUE if the key is valid, FALSE if invalid or something went wrong
|
||||
*/
|
||||
function checkAPIKey($key) {
|
||||
try {
|
||||
$client = new GuzzleHttp\Client();
|
||||
|
||||
$response = $client
|
||||
->request('POST', PORTAL_API, [
|
||||
'form_params' => [
|
||||
'key' => $key,
|
||||
'action' => "ping"
|
||||
]
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() === 200) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Account handling //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Checks the given credentials against the API.
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @return boolean True if OK, else false
|
||||
*/
|
||||
function authenticate_user($username, $password, &$errmsg) {
|
||||
$client = new GuzzleHttp\Client();
|
||||
|
||||
$response = $client
|
||||
->request('POST', PORTAL_API, [
|
||||
'form_params' => [
|
||||
'key' => PORTAL_KEY,
|
||||
'action' => "auth",
|
||||
'username' => $username,
|
||||
'password' => $password
|
||||
]
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() > 299) {
|
||||
sendError("Login server error: " . $response->getBody());
|
||||
}
|
||||
|
||||
$resp = json_decode($response->getBody(), TRUE);
|
||||
if ($resp['status'] == "OK") {
|
||||
return true;
|
||||
} else {
|
||||
$errmsg = $resp['msg'];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a username exists.
|
||||
* @param String $username
|
||||
*/
|
||||
function user_exists($username) {
|
||||
$client = new GuzzleHttp\Client();
|
||||
|
||||
$response = $client
|
||||
->request('POST', PORTAL_API, [
|
||||
'form_params' => [
|
||||
'key' => PORTAL_KEY,
|
||||
'action' => "userexists",
|
||||
'username' => $username
|
||||
]
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() > 299) {
|
||||
sendError("Login server error: " . $response->getBody());
|
||||
}
|
||||
|
||||
$resp = json_decode($response->getBody(), TRUE);
|
||||
if ($resp['status'] == "OK" && $resp['exists'] === true) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a UID exists.
|
||||
* @param String $uid
|
||||
*/
|
||||
function uid_exists($uid) {
|
||||
$client = new GuzzleHttp\Client();
|
||||
|
||||
$response = $client
|
||||
->request('POST', PORTAL_API, [
|
||||
'form_params' => [
|
||||
'key' => PORTAL_KEY,
|
||||
'action' => "userexists",
|
||||
'uid' => $uid
|
||||
]
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() > 299) {
|
||||
sendError("Login server error: " . $response->getBody());
|
||||
}
|
||||
|
||||
$resp = json_decode($response->getBody(), TRUE);
|
||||
if ($resp['status'] == "OK" && $resp['exists'] === true) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the account status: NORMAL, TERMINATED, LOCKED_OR_DISABLED,
|
||||
* CHANGE_PASSWORD, or ALERT_ON_ACCESS
|
||||
* @param string $username
|
||||
* @return string
|
||||
*/
|
||||
function get_account_status($username) {
|
||||
$client = new GuzzleHttp\Client();
|
||||
|
||||
$response = $client
|
||||
->request('POST', PORTAL_API, [
|
||||
'form_params' => [
|
||||
'key' => PORTAL_KEY,
|
||||
'action' => "acctstatus",
|
||||
'username' => $username
|
||||
]
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() > 299) {
|
||||
sendError("Login server error: " . $response->getBody());
|
||||
}
|
||||
|
||||
$resp = json_decode($response->getBody(), TRUE);
|
||||
if ($resp['status'] == "OK") {
|
||||
return $resp['account'];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given username has the given permission (or admin access)
|
||||
* @param string $username
|
||||
* @param string $permcode
|
||||
* @return boolean TRUE if the user has the permission (or admin access), else FALSE
|
||||
*/
|
||||
function account_has_permission($username, $permcode) {
|
||||
$client = new GuzzleHttp\Client();
|
||||
|
||||
$response = $client
|
||||
->request('POST', PORTAL_API, [
|
||||
'form_params' => [
|
||||
'key' => PORTAL_KEY,
|
||||
'action' => "permission",
|
||||
'username' => $username,
|
||||
'code' => $permcode
|
||||
]
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() > 299) {
|
||||
sendError("Login server error: " . $response->getBody());
|
||||
}
|
||||
|
||||
$resp = json_decode($response->getBody(), TRUE);
|
||||
if ($resp['status'] == "OK") {
|
||||
return $resp['has_permission'];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Login handling //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Setup $_SESSION values with user data and set loggedin flag to true
|
||||
* @param string $username
|
||||
*/
|
||||
function doLoginUser($username) {
|
||||
$client = new GuzzleHttp\Client();
|
||||
|
||||
$response = $client
|
||||
->request('POST', PORTAL_API, [
|
||||
'form_params' => [
|
||||
'key' => PORTAL_KEY,
|
||||
'action' => "userinfo",
|
||||
'username' => $username
|
||||
]
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() > 299) {
|
||||
sendError("Login server error: " . $response->getBody());
|
||||
}
|
||||
|
||||
$resp = json_decode($response->getBody(), TRUE);
|
||||
|
||||
if ($resp['status'] == "OK") {
|
||||
$userinfo = $resp['data'];
|
||||
session_regenerate_id(true);
|
||||
$newSession = session_id();
|
||||
session_write_close();
|
||||
session_id($newSession);
|
||||
session_start();
|
||||
$_SESSION['username'] = $username;
|
||||
$_SESSION['uid'] = $userinfo['uid'];
|
||||
$_SESSION['email'] = $userinfo['email'];
|
||||
$_SESSION['realname'] = $userinfo['name'];
|
||||
$_SESSION['loggedin'] = true;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function sendLoginAlertEmail($username) {
|
||||
$client = new GuzzleHttp\Client();
|
||||
|
||||
$response = $client
|
||||
->request('POST', PORTAL_API, [
|
||||
'form_params' => [
|
||||
'key' => PORTAL_KEY,
|
||||
'action' => "alertemail",
|
||||
'username' => $username,
|
||||
'appname' => SITE_TITLE
|
||||
]
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() > 299) {
|
||||
return "An unknown error occurred.";
|
||||
}
|
||||
|
||||
$resp = json_decode($response->getBody(), TRUE);
|
||||
if ($resp['status'] == "OK") {
|
||||
return true;
|
||||
} else {
|
||||
return $resp['msg'];
|
||||
}
|
||||
}
|
||||
|
||||
function simLogin($username, $password) {
|
||||
$client = new GuzzleHttp\Client();
|
||||
|
||||
$response = $client
|
||||
->request('POST', PORTAL_API, [
|
||||
'form_params' => [
|
||||
'key' => PORTAL_KEY,
|
||||
'action' => "login",
|
||||
'username' => $username,
|
||||
'password' => $password
|
||||
]
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() > 299) {
|
||||
sendError("Login server error: " . $response->getBody());
|
||||
}
|
||||
|
||||
$resp = json_decode($response->getBody(), TRUE);
|
||||
if ($resp['status'] == "OK") {
|
||||
return true;
|
||||
} else {
|
||||
return $resp['msg'];
|
||||
}
|
||||
}
|
||||
|
||||
function verifyCaptcheck($session, $answer, $url) {
|
||||
$data = [
|
||||
'session_id' => $session,
|
||||
'answer_id' => $answer,
|
||||
'action' => "verify"
|
||||
];
|
||||
$options = [
|
||||
'http' => [
|
||||
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
|
||||
'method' => 'POST',
|
||||
'content' => http_build_query($data)
|
||||
]
|
||||
];
|
||||
$context = stream_context_create($options);
|
||||
$result = file_get_contents($url, false, $context);
|
||||
$resp = json_decode($result, TRUE);
|
||||
if (!$resp['result']) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 2-factor authentication //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Check if a user has TOTP setup
|
||||
* @param string $username
|
||||
* @return boolean true if TOTP secret exists, else false
|
||||
*/
|
||||
function userHasTOTP($username) {
|
||||
$client = new GuzzleHttp\Client();
|
||||
|
||||
$response = $client
|
||||
->request('POST', PORTAL_API, [
|
||||
'form_params' => [
|
||||
'key' => PORTAL_KEY,
|
||||
'action' => "hastotp",
|
||||
'username' => $username
|
||||
]
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() > 299) {
|
||||
sendError("Login server error: " . $response->getBody());
|
||||
}
|
||||
|
||||
$resp = json_decode($response->getBody(), TRUE);
|
||||
if ($resp['status'] == "OK") {
|
||||
return $resp['otp'];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a TOTP multiauth code
|
||||
* @global $database
|
||||
* @param string $username
|
||||
* @param int $code
|
||||
* @return boolean true if it's legit, else false
|
||||
*/
|
||||
function verifyTOTP($username, $code) {
|
||||
$client = new GuzzleHttp\Client();
|
||||
|
||||
$response = $client
|
||||
->request('POST', PORTAL_API, [
|
||||
'form_params' => [
|
||||
'key' => PORTAL_KEY,
|
||||
'action' => "verifytotp",
|
||||
'username' => $username,
|
||||
'code' => $code
|
||||
]
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() > 299) {
|
||||
sendError("Login server error: " . $response->getBody());
|
||||
}
|
||||
|
||||
$resp = json_decode($response->getBody(), TRUE);
|
||||
if ($resp['status'] == "OK") {
|
||||
return $resp['valid'];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ ob_start(); // allow sending headers after content
|
||||
// Settings file
|
||||
require __DIR__ . '/../settings.php';
|
||||
|
||||
if (!DEBUG) {
|
||||
if (!$SETTINGS["debug"]) {
|
||||
error_reporting(0);
|
||||
} else {
|
||||
error_reporting(E_ALL);
|
||||
@ -57,7 +57,7 @@ function sendError($error) {
|
||||
. "<p>" . htmlspecialchars($error) . "</p>");
|
||||
}
|
||||
|
||||
date_default_timezone_set(TIMEZONE);
|
||||
date_default_timezone_set($SETTINGS['timezone']);
|
||||
|
||||
// Database settings
|
||||
// Also inits database and stuff
|
||||
@ -66,12 +66,12 @@ use Medoo\Medoo;
|
||||
$database;
|
||||
try {
|
||||
$database = new Medoo([
|
||||
'database_type' => DB_TYPE,
|
||||
'database_name' => DB_NAME,
|
||||
'server' => DB_SERVER,
|
||||
'username' => DB_USER,
|
||||
'password' => DB_PASS,
|
||||
'charset' => DB_CHARSET
|
||||
'database_type' => $SETTINGS['database']['type'],
|
||||
'database_name' => $SETTINGS['database']['name'],
|
||||
'server' => $SETTINGS['database']['server'],
|
||||
'username' => $SETTINGS['database']['user'],
|
||||
'password' => $SETTINGS['database']['password'],
|
||||
'charset' => $SETTINGS['database']['charset']
|
||||
]);
|
||||
} catch (Exception $ex) {
|
||||
//header('HTTP/1.1 500 Internal Server Error');
|
||||
|
@ -87,10 +87,11 @@ function get_page_slug($echo = true) {
|
||||
* @return string
|
||||
*/
|
||||
function get_page_clean_url($echo = true, $slug = null) {
|
||||
global $SETTINGS;
|
||||
if ($slug == null) {
|
||||
$slug = get_page_slug(false);
|
||||
}
|
||||
if (PRETTY_URLS) {
|
||||
if ($SETTINGS["pretty_urls"]) {
|
||||
$url = formatsiteurl(get_site_url(false)) . "$slug";
|
||||
} else {
|
||||
$url = formatsiteurl(get_site_url(false)) . "index.php?id=$slug";
|
||||
@ -108,6 +109,7 @@ function get_page_clean_url($echo = true, $slug = null) {
|
||||
* @return string
|
||||
*/
|
||||
function get_page_url($echo = true, $slug = null) {
|
||||
global $SETTINGS;
|
||||
if ($slug == null) {
|
||||
$slug = get_page_slug(false);
|
||||
}
|
||||
@ -132,7 +134,7 @@ function get_page_url($echo = true, $slug = null) {
|
||||
$siteid = "&siteid=" . preg_replace("/[^0-9]/", '', $_GET['siteid']);
|
||||
}
|
||||
$args = "$edit$theme$template$color$siteid";
|
||||
if (PRETTY_URLS) {
|
||||
if ($SETTINGS["pretty_urls"]) {
|
||||
if ($args != "") {
|
||||
$args = "?$args";
|
||||
}
|
||||
@ -214,6 +216,7 @@ function is_component_empty($name, $context = null) {
|
||||
* @return array
|
||||
*/
|
||||
function get_complex_component($name, $context = null, $include = []) {
|
||||
global $SETTINGS;
|
||||
$db = getdatabase();
|
||||
if ($context == null) {
|
||||
$context = getpageslug();
|
||||
@ -234,14 +237,14 @@ function get_complex_component($name, $context = null, $include = []) {
|
||||
$filtered = [];
|
||||
foreach ($include as $i) {
|
||||
if (array_key_exists($i, $content)) {
|
||||
if (!isset($_GET['edit']) && $i == "image" && $content[$i] == URL . "/static/img/no-image.svg") {
|
||||
if (!isset($_GET['edit']) && $i == "image" && $content[$i] == $SETTINGS["url"] . "/static/img/no-image.svg") {
|
||||
$filtered[$i] = "";
|
||||
} else {
|
||||
$filtered[$i] = $content[$i];
|
||||
}
|
||||
} else {
|
||||
if (isset($_GET['edit']) && $i == "image") {
|
||||
$filtered[$i] = URL . "/static/img/no-image.svg";
|
||||
$filtered[$i] = $SETTINGS["url"] . "/static/img/no-image.svg";
|
||||
} else {
|
||||
$filtered[$i] = "";
|
||||
}
|
||||
@ -258,12 +261,13 @@ function get_complex_component($name, $context = null, $include = []) {
|
||||
* @return boolean
|
||||
*/
|
||||
function is_complex_empty($name, $context = null) {
|
||||
global $SETTINGS;
|
||||
if (isset($_GET['edit'])) {
|
||||
return false;
|
||||
}
|
||||
$comp = get_complex_component($name, $context);
|
||||
foreach ($comp as $c => $v) {
|
||||
if ($c == "image" && $v == URL . "/static/img/no-image.svg") {
|
||||
if ($c == "image" && $v == $SETTINGS["url"] . "/static/img/no-image.svg") {
|
||||
continue;
|
||||
}
|
||||
if (isset($v) && !empty($v)) {
|
||||
@ -314,13 +318,14 @@ function get_url_or_slug($str, $echo = true) {
|
||||
* @return string
|
||||
*/
|
||||
function get_file_url($file, $echo = true) {
|
||||
global $SETTINGS;
|
||||
$url = "file.php?file=$file";
|
||||
$base = FILE_UPLOAD_PATH;
|
||||
$base = $SETTINGS["file_upload_path"];
|
||||
$filepath = $base . $file;
|
||||
if (!file_exists($filepath) || is_dir($filepath)) {
|
||||
$url = $file;
|
||||
} else {
|
||||
if (strpos(realpath($filepath), FILE_UPLOAD_PATH) !== 0) {
|
||||
if (strpos(realpath($filepath), $SETTINGS["file_upload_path"]) !== 0) {
|
||||
$url = $file;
|
||||
}
|
||||
}
|
||||
@ -382,10 +387,11 @@ function get_setting($key, $echo = false) {
|
||||
* @return string
|
||||
*/
|
||||
function get_theme_url($echo = true) {
|
||||
global $SETTINGS;
|
||||
$db = getdatabase();
|
||||
$site = $db->get('sites', ["sitename", "url", "theme"], ["siteid" => getsiteid()]);
|
||||
if (isset($_GET['edit']) || isset($_GET['in_sw'])) {
|
||||
$url = URL . "/public/themes/" . SITE_THEME;
|
||||
$url = $SETTINGS["url"] . "/public/themes/" . SITE_THEME;
|
||||
} else {
|
||||
$url = formatsiteurl($site["url"]) . "themes/" . SITE_THEME;
|
||||
}
|
||||
|
127
lib/userinfo.php
127
lib/userinfo.php
@ -1,127 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Get user info for the given username.
|
||||
* @param int $u username
|
||||
* @return [string] Array of [uid, username, name]
|
||||
*/
|
||||
function getUserByUsername($u) {
|
||||
$client = new GuzzleHttp\Client();
|
||||
|
||||
$response = $client
|
||||
->request('POST', PORTAL_API, [
|
||||
'form_params' => [
|
||||
'key' => PORTAL_KEY,
|
||||
'action' => "userinfo",
|
||||
'username' => $u
|
||||
]
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() > 299) {
|
||||
sendError("Login server error: " . $response->getBody());
|
||||
}
|
||||
|
||||
$resp = json_decode($response->getBody(), TRUE);
|
||||
if ($resp['status'] == "OK") {
|
||||
return $resp['data'];
|
||||
} else {
|
||||
// this shouldn't happen, but in case it does just fake it.
|
||||
return ["name" => $u, "username" => $u, "uid" => $u];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user info for the given UID.
|
||||
* @param int $u user ID
|
||||
* @return [string] Array of [uid, username, name]
|
||||
*/
|
||||
function getUserByID($u) {
|
||||
$client = new GuzzleHttp\Client();
|
||||
|
||||
$response = $client
|
||||
->request('POST', PORTAL_API, [
|
||||
'form_params' => [
|
||||
'key' => PORTAL_KEY,
|
||||
'action' => "userinfo",
|
||||
'uid' => $u
|
||||
]
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() > 299) {
|
||||
sendError("Login server error: " . $response->getBody());
|
||||
}
|
||||
|
||||
$resp = json_decode($response->getBody(), TRUE);
|
||||
if ($resp['status'] == "OK") {
|
||||
return $resp['data'];
|
||||
} else {
|
||||
// this shouldn't happen, but in case it does just fake it.
|
||||
return ["name" => $u, "username" => $u, "uid" => $u];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the first UID is a manager of the second UID.
|
||||
* @param int $m Manager UID
|
||||
* @param int $e Employee UID
|
||||
* @return boolean
|
||||
*/
|
||||
function isManagerOf($m, $e) {
|
||||
$client = new GuzzleHttp\Client();
|
||||
|
||||
$response = $client
|
||||
->request('POST', PORTAL_API, [
|
||||
'form_params' => [
|
||||
'key' => PORTAL_KEY,
|
||||
'action' => "ismanagerof",
|
||||
'manager' => $m,
|
||||
'employee' => $e,
|
||||
'uid' => 1
|
||||
]
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() > 299) {
|
||||
sendError("Login server error: " . $response->getBody());
|
||||
}
|
||||
|
||||
$resp = json_decode($response->getBody(), TRUE);
|
||||
if ($resp['status'] == "OK") {
|
||||
return $resp['managerof'] === true;
|
||||
} else {
|
||||
// this shouldn't happen, but in case it does just fake it.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of UIDs the given UID is a manager of.
|
||||
* @param int $manageruid The UID of the manager to find employees for.
|
||||
* @return [int]
|
||||
*/
|
||||
function getManagedUIDs($manageruid) {
|
||||
$client = new GuzzleHttp\Client();
|
||||
|
||||
$response = $client
|
||||
->request('POST', PORTAL_API, [
|
||||
'form_params' => [
|
||||
'key' => PORTAL_KEY,
|
||||
'action' => "getmanaged",
|
||||
'uid' => $manageruid
|
||||
]
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() > 299) {
|
||||
sendError("Login server error: " . $response->getBody());
|
||||
}
|
||||
|
||||
$resp = json_decode($response->getBody(), TRUE);
|
||||
if ($resp['status'] == "OK") {
|
||||
return $resp['employees'];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
@ -8,14 +8,8 @@
|
||||
* Mobile app API
|
||||
*/
|
||||
|
||||
// The name of the permission needed to log in.
|
||||
// Set to null if you don't need it.
|
||||
$access_permission = null;
|
||||
|
||||
require __DIR__ . "/../required.php";
|
||||
|
||||
require __DIR__ . "/../lib/login.php";
|
||||
|
||||
header('Content-Type: application/json');
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
|
||||
@ -25,21 +19,7 @@ if ($VARS['action'] == "ping") {
|
||||
}
|
||||
|
||||
function mobile_enabled() {
|
||||
$client = new GuzzleHttp\Client();
|
||||
|
||||
$response = $client
|
||||
->request('POST', PORTAL_API, [
|
||||
'form_params' => [
|
||||
'key' => PORTAL_KEY,
|
||||
'action' => "mobileenabled"
|
||||
]
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() > 299) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$resp = json_decode($response->getBody(), TRUE);
|
||||
$resp = AccountHubApi::get("mobileenabled");
|
||||
if ($resp['status'] == "OK" && $resp['mobile'] === TRUE) {
|
||||
return true;
|
||||
} else {
|
||||
@ -48,36 +28,25 @@ function mobile_enabled() {
|
||||
}
|
||||
|
||||
function mobile_valid($username, $code) {
|
||||
$client = new GuzzleHttp\Client();
|
||||
try {
|
||||
$resp = AccountHubApi::get("mobilevalid", ["code" => $code, "username" => $username], true);
|
||||
|
||||
$response = $client
|
||||
->request('POST', PORTAL_API, [
|
||||
'form_params' => [
|
||||
'key' => PORTAL_KEY,
|
||||
"code" => $code,
|
||||
"username" => $username,
|
||||
'action' => "mobilevalid"
|
||||
]
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() > 299) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$resp = json_decode($response->getBody(), TRUE);
|
||||
if ($resp['status'] == "OK" && $resp['valid'] === TRUE) {
|
||||
return true;
|
||||
} else {
|
||||
if ($resp['status'] == "OK" && $resp['valid'] === TRUE) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (Exception $ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (mobile_enabled() !== TRUE) {
|
||||
exit(json_encode(["status" => "ERROR", "msg" => lang("mobile login disabled", false)]));
|
||||
exit(json_encode(["status" => "ERROR", "msg" => $Strings->get("mobile login disabled", false)]));
|
||||
}
|
||||
|
||||
// Make sure we have a username and access key
|
||||
if (is_empty($VARS['username']) || is_empty($VARS['key'])) {
|
||||
if (empty($VARS['username']) || empty($VARS['key'])) {
|
||||
http_response_code(401);
|
||||
die(json_encode(["status" => "ERROR", "msg" => "Missing username and/or access key."]));
|
||||
}
|
||||
@ -93,20 +62,22 @@ if (!mobile_valid($VARS['username'], $VARS['key'])) {
|
||||
switch ($VARS['action']) {
|
||||
case "start_session":
|
||||
// Do a web login.
|
||||
if (user_exists($VARS['username'])) {
|
||||
if (get_account_status($VARS['username']) == "NORMAL") {
|
||||
if (authenticate_user($VARS['username'], $VARS['password'], $autherror)) {
|
||||
if (is_null($access_permission) || account_has_permission($VARS['username'], $access_permission)) {
|
||||
doLoginUser($VARS['username'], $VARS['password']);
|
||||
$_SESSION['mobile'] = true;
|
||||
exit(json_encode(["status" => "OK"]));
|
||||
} else {
|
||||
exit(json_encode(["status" => "ERROR", "msg" => lang("no admin permission", false)]));
|
||||
$user = User::byUsername($VARS['username']);
|
||||
if ($user->exists()) {
|
||||
if ($user->getStatus()->getString() == "NORMAL") {
|
||||
if ($user->checkPassword($VARS['password'])) {
|
||||
foreach ($SETTINGS['permissions'] as $perm) {
|
||||
if (!$user->hasPermission($perm)) {
|
||||
exit(json_encode(["status" => "ERROR", "msg" => $Strings->get("no permission", false)]));
|
||||
}
|
||||
}
|
||||
Session::start($user);
|
||||
$_SESSION['mobile'] = true;
|
||||
exit(json_encode(["status" => "OK"]));
|
||||
}
|
||||
}
|
||||
}
|
||||
exit(json_encode(["status" => "ERROR", "msg" => lang("login incorrect", false)]));
|
||||
exit(json_encode(["status" => "ERROR", "msg" => $Strings->get("login incorrect", false)]));
|
||||
default:
|
||||
http_response_code(404);
|
||||
die(json_encode(["status" => "ERROR", "msg" => "The requested action is not available."]));
|
||||
|
29
nbproject/fa5tophp.php
Normal file
29
nbproject/fa5tophp.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
// Script to convert icons.json in the FontAwesome download into a PHP array for SiteWriter
|
||||
|
||||
$json = file_get_contents(__DIR__ . "/icons.json");
|
||||
$icons = json_decode($json, true);
|
||||
$output = [];
|
||||
foreach ($icons as $icon => $data) {
|
||||
$meta = [];
|
||||
$meta["label"] = $data["label"];
|
||||
$meta["search"] = $data["search"]["terms"];
|
||||
foreach ($data["styles"] as $s) {
|
||||
$class = "fa";
|
||||
switch ($s) {
|
||||
case "solid":
|
||||
$class = "fas";
|
||||
break;
|
||||
case "regular":
|
||||
$class = "far";
|
||||
break;
|
||||
case "brands":
|
||||
$class = "fab";
|
||||
break;
|
||||
}
|
||||
$output["$class fa-$icon"] = $meta;
|
||||
}
|
||||
}
|
||||
|
||||
var_export($output);
|
51733
nbproject/icons.json
Normal file
51733
nbproject/icons.json
Normal file
File diff suppressed because one or more lines are too long
@ -5,6 +5,6 @@
|
||||
?>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-12 col-sm-10 col-md-8 col-lg-6">
|
||||
<div class="alert alert-warning"><b><?php lang("404 error");?></b><br /> <?php lang("page not found"); ?></div>
|
||||
<div class="alert alert-warning"><b><?php $Strings->get("404 error");?></b><br /> <?php $Strings->get("page not found"); ?></div>
|
||||
</div>
|
||||
</div>
|
@ -7,8 +7,9 @@ require_once __DIR__ . '/../required.php';
|
||||
|
||||
redirectifnotloggedin();
|
||||
|
||||
require_once __DIR__ . "/../lib/login.php";
|
||||
if (!account_has_permission($_SESSION['username'], "SITEWRITER") && !account_has_permission($_SESSION['username'], "SITEWRITER_ANALYTICS")) {
|
||||
$user = new User($_SESSION['uid']);
|
||||
|
||||
if (!$user->hasPermission("SITEWRITER") && !$user->hasPermission("SITEWRITER_ANALYTICS")) {
|
||||
if ($_GET['msg'] != "no_permission") {
|
||||
header("Location: app.php?page=analytics&msg=no_permission");
|
||||
}
|
||||
@ -17,18 +18,18 @@ if (!account_has_permission($_SESSION['username'], "SITEWRITER") && !account_has
|
||||
|
||||
$select_filter = [];
|
||||
|
||||
if (isset($VARS['siteid']) && !is_empty($VARS['siteid'])) {
|
||||
if (!empty($VARS['siteid'])) {
|
||||
if ($database->has('sites', ['siteid' => $VARS['siteid']])) {
|
||||
$select_filter["analytics.siteid"] = $VARS['siteid'];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($VARS['after']) && !is_empty($VARS['after'])) {
|
||||
if (!empty($VARS['after'])) {
|
||||
if (strtotime($VARS['after']) !== FALSE) {
|
||||
$select_filter["time[>]"] = date("Y-m-d H:i:s", strtotime($VARS['after']));
|
||||
}
|
||||
}
|
||||
if (isset($VARS['before']) && !is_empty($VARS['before'])) {
|
||||
if (!empty($VARS['before'])) {
|
||||
if (strtotime($VARS['before']) !== FALSE) {
|
||||
$select_filter["time[<]"] = date("Y-m-d H:i:s", strtotime($VARS['before']));
|
||||
}
|
||||
@ -140,13 +141,13 @@ foreach ($states as $id => $count) {
|
||||
<div class="card p-2">
|
||||
<form class="form-inline" action="app.php" method="GET">
|
||||
<button type="submit" class="btn btn-primary"><i class="fas fa-sync"></i></button>
|
||||
<label for="siteid_select" class="sr-only"><?php lang("filter by site") ?></label>
|
||||
<label for="siteid_select" class="sr-only"><?php $Strings->get("filter by site") ?></label>
|
||||
<div class="input-group mx-2">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fas fa-sitemap"></i></span>
|
||||
</div>
|
||||
<select name="siteid" class="form-control pr-4" id="siteid_select">
|
||||
<option value=""><?php lang("all sites"); ?></option>
|
||||
<option value=""><?php $Strings->get("all sites"); ?></option>
|
||||
<?php
|
||||
$sites = $database->select("sites", ["siteid", "sitename"]);
|
||||
foreach ($sites as $s) {
|
||||
@ -164,22 +165,22 @@ foreach ($states as $id => $count) {
|
||||
|
||||
<span class="vertline d-none d-lg-inline"></span>
|
||||
|
||||
<label for="date_after" class="sr-only"><?php lang("filter after date") ?></label>
|
||||
<label for="date_before" class="sr-only"><?php lang("filter before date") ?></label>
|
||||
<label for="date_after" class="sr-only"><?php $Strings->get("filter after date") ?></label>
|
||||
<label for="date_before" class="sr-only"><?php $Strings->get("filter before date") ?></label>
|
||||
<div class="input-group mx-2">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fas fa-calendar"></i></span>
|
||||
</div>
|
||||
<input type="text" id="date_after" name="after" value="<?php echo htmlspecialchars($VARS['after']); ?>" class="form-control" placeholder="<?php lang("start date"); ?>" data-toggle="datetimepicker" data-target="#date_after" />
|
||||
<input type="text" id="date_after" name="after" value="<?php echo htmlspecialchars($VARS['after']); ?>" class="form-control" placeholder="<?php $Strings->get("start date"); ?>" data-toggle="datetimepicker" data-target="#date_after" />
|
||||
<div class="input-group-prepend input-group-append">
|
||||
<span class="input-group-text"><i class="fas fa-caret-right"></i></span>
|
||||
</div>
|
||||
<input type="text" id="date_before" name="before" value="<?php echo htmlspecialchars($VARS['before']); ?>" class="form-control" placeholder="<?php lang("end date"); ?>" data-toggle="datetimepicker" data-target="#date_before" />
|
||||
<input type="text" id="date_before" name="before" value="<?php echo htmlspecialchars($VARS['before']); ?>" class="form-control" placeholder="<?php $Strings->get("end date"); ?>" data-toggle="datetimepicker" data-target="#date_before" />
|
||||
</div>
|
||||
|
||||
|
||||
<input type="hidden" name="page" value="analytics" />
|
||||
<button type="submit" class="btn btn-secondary"><i class="fas fa-filter"></i> <?php lang("filter"); ?></button>
|
||||
<button type="submit" class="btn btn-secondary"><i class="fas fa-filter"></i> <?php $Strings->get("filter"); ?></button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@ -191,14 +192,14 @@ if (count($records) > 0) {
|
||||
<!-- Overview -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title"><?php lang("overview"); ?></h4>
|
||||
<h4 class="card-title"><?php $Strings->get("overview"); ?></h4>
|
||||
<?php
|
||||
$ratio = round($pageviews / $visits, 1);
|
||||
?>
|
||||
<h5>
|
||||
<i class="fas fa-users fa-fw"></i> <?php echo $visits; ?> <?php lang("visits") ?> <br />
|
||||
<i class="fas fa-eye fa-fw"></i> <?php echo $pageviews; ?> <?php lang("page views") ?> <br />
|
||||
<i class="fas fa-percent fa-fw"></i> <?php echo $ratio; ?> <?php lang("views per visit") ?>
|
||||
<i class="fas fa-users fa-fw"></i> <?php echo $visits; ?> <?php $Strings->get("visits") ?> <br />
|
||||
<i class="fas fa-eye fa-fw"></i> <?php echo $pageviews; ?> <?php $Strings->get("page views") ?> <br />
|
||||
<i class="fas fa-percent fa-fw"></i> <?php echo $ratio; ?> <?php $Strings->get("views per visit") ?>
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
@ -206,7 +207,7 @@ if (count($records) > 0) {
|
||||
<!-- Visits Over Time -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title"><?php lang("visits over time"); ?></h4>
|
||||
<h4 class="card-title"><?php $Strings->get("visits over time"); ?></h4>
|
||||
<script nonce="<?php echo $SECURE_NONCE; ?>">
|
||||
var visitsOverTimeData = [
|
||||
<?php foreach ($visitsovertime as $d => $c) { ?>
|
||||
@ -226,7 +227,7 @@ if (count($records) > 0) {
|
||||
<!-- Views Over Time -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title"><?php lang("page views over time"); ?></h4>
|
||||
<h4 class="card-title"><?php $Strings->get("page views over time"); ?></h4>
|
||||
<script nonce="<?php echo $SECURE_NONCE; ?>">
|
||||
var viewsOverTimeData = [
|
||||
<?php foreach ($viewsovertime as $d => $c) { ?>
|
||||
@ -246,7 +247,7 @@ if (count($records) > 0) {
|
||||
<!-- Visitor Map -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title"><?php lang("visitor map"); ?></h4>
|
||||
<h4 class="card-title"><?php $Strings->get("visitor map"); ?></h4>
|
||||
<script nonce="<?php echo $SECURE_NONCE; ?>">
|
||||
visitorMap_Countries = <?php echo json_encode($countrymapdata); ?>;
|
||||
visitorMap_States = <?php echo json_encode($statemapdata); ?>;
|
||||
@ -259,7 +260,7 @@ if (count($records) > 0) {
|
||||
<!-- Page Ranking -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title"><?php lang("page ranking"); ?></h4>
|
||||
<h4 class="card-title"><?php $Strings->get("page ranking"); ?></h4>
|
||||
</div>
|
||||
<div class="list-group">
|
||||
<?php
|
||||
@ -272,7 +273,7 @@ if (count($records) > 0) {
|
||||
<span><i class="fas fa-sitemap fa-fw"></i> <?php echo $p["sitename"]; ?></span>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<span><i class="fas fa-eye fa-fw"></i> <?php lang2("x views", ["views" => $p['views']]); ?></span>
|
||||
<span><i class="fas fa-eye fa-fw"></i> <?php $Strings->build("x views", ["views" => $p['views']]); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -285,7 +286,7 @@ if (count($records) > 0) {
|
||||
<!-- Recent Actions -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title"><?php lang("recent actions"); ?></h4>
|
||||
<h4 class="card-title"><?php $Strings->get("recent actions"); ?></h4>
|
||||
</div>
|
||||
<div class="list-group list-group-scrolly">
|
||||
<?php
|
||||
@ -329,7 +330,7 @@ if (count($records) > 0) {
|
||||
<div class="col-12 col-sm-10 col-md-8 col-lg-6">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<i class="fas fa-info-circle"></i> <?php lang("no data"); ?>
|
||||
<i class="fas fa-info-circle"></i> <?php $Strings->get("no data"); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -7,15 +7,16 @@ require_once __DIR__ . '/../required.php';
|
||||
|
||||
redirectifnotloggedin();
|
||||
|
||||
require_once __DIR__ . "/../lib/login.php";
|
||||
if (!account_has_permission($_SESSION['username'], "SITEWRITER") && !account_has_permission($_SESSION['username'], "SITEWRITER_EDIT")) {
|
||||
$user = new User($_SESSION['uid']);
|
||||
|
||||
if (!$user->hasPermission("SITEWRITER") && !$user->hasPermission("SITEWRITER_EDIT")) {
|
||||
if ($_GET['msg'] != "no_permission") {
|
||||
header("Location: app.php?page=editor&msg=no_permission");
|
||||
}
|
||||
die();
|
||||
}
|
||||
|
||||
if (isset($VARS['arg']) && !is_empty($VARS['arg'])) {
|
||||
if (!empty($VARS['arg'])) {
|
||||
// Allow action.php to do a better redirect
|
||||
$VARS['siteid'] = $VARS['arg'];
|
||||
if (strpos($VARS['arg'], "|") !== FALSE) {
|
||||
@ -27,7 +28,7 @@ if (isset($VARS['arg']) && !is_empty($VARS['arg'])) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_empty($VARS['siteid'])) {
|
||||
if (!empty($VARS['siteid'])) {
|
||||
if ($database->has('sites', ['siteid' => $VARS['siteid']])) {
|
||||
$sitedata = $database->get(
|
||||
'sites', [
|
||||
@ -86,16 +87,16 @@ if (!is_empty($VARS['siteid'])) {
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="fileBrowseLabel"><i class="far fa-folder-open"></i> <?php lang("browse"); ?></h5>
|
||||
<h5 class="modal-title" id="fileBrowseLabel"><i class="far fa-folder-open"></i> <?php $Strings->get("browse"); ?></h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body" id="fileBrowseModalBody">
|
||||
<i class="fas fa-spin fa-circle-notch"></i> <?php lang("loading"); ?>
|
||||
<i class="fas fa-spin fa-circle-notch"></i> <?php $Strings->get("loading"); ?>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php lang("cancel"); ?></button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php $Strings->get("cancel"); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -105,18 +106,18 @@ if (!is_empty($VARS['siteid'])) {
|
||||
<div class="modal-dialog" role="document">
|
||||
<form class="modal-content" action="action.php" method="POST">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="pageSettingsLabel"><i class="fas fa-cog"></i> <?php lang("page settings"); ?></h5>
|
||||
<h5 class="modal-title" id="pageSettingsLabel"><i class="fas fa-cog"></i> <?php $Strings->get("page settings"); ?></h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body" id="pageSettingsModalBody">
|
||||
<div class="form-group">
|
||||
<label for="pageSettingsTitle"><i class="fas fa-font"></i> <?php lang("title"); ?></label>
|
||||
<label for="pageSettingsTitle"><i class="fas fa-font"></i> <?php $Strings->get("title"); ?></label>
|
||||
<input type="text" id="pageSettingsTitle" name="title" class="form-control" required="required" minlength="1" maxlength="200" value="<?php echo $thispage['title']; ?>" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label><i class="fas fa-paint-brush"></i> <?php lang("template"); ?></label>
|
||||
<label><i class="fas fa-paint-brush"></i> <?php $Strings->get("template"); ?></label>
|
||||
<select id="pageSettingsTemplate" name="template" class="form-control" required="required">
|
||||
<?php
|
||||
$json = file_get_contents(__DIR__ . "/../public/themes/" . $sitedata['theme'] . "/theme.json");
|
||||
@ -135,11 +136,11 @@ if (!is_empty($VARS['siteid'])) {
|
||||
if ($singlepage !== true) {
|
||||
?>
|
||||
<div class="form-group">
|
||||
<label><i class="fas fa-bars"></i> <?php lang("navbar options"); ?></label>
|
||||
<label><i class="fas fa-bars"></i> <?php $Strings->get("navbar options"); ?></label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="innavbar" id="innavbarCheckbox" value="1" <?php echo (is_empty($thispage['nav']) ? "" : "checked") ?> />
|
||||
<input class="form-check-input" type="checkbox" name="innavbar" id="innavbarCheckbox" value="1" <?php echo (empty($thispage['nav']) ? "" : "checked") ?> />
|
||||
<label class="form-check-label" for="innavbarCheckbox">
|
||||
<?php lang("in navbar"); ?>
|
||||
<?php $Strings->get("in navbar"); ?>
|
||||
</label>
|
||||
</div>
|
||||
<div id="navbarSettings" class="card p-2 mt-3 d-none">
|
||||
@ -149,16 +150,16 @@ if (!is_empty($VARS['siteid'])) {
|
||||
</script>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<label class="input-group-text" for="navbarTitle"><?php lang("navbar title"); ?></label>
|
||||
<label class="input-group-text" for="navbarTitle"><?php $Strings->get("navbar title"); ?></label>
|
||||
</div>
|
||||
<input type="text" id="navbarTitle" name="navbartitle" class="form-control" required="required" minlength="1" maxlength="200" value="<?php echo (is_empty($thispage['nav']) ? $thispage['title'] : $thispage['nav']); ?>" />
|
||||
<input type="text" id="navbarTitle" name="navbartitle" class="form-control" required="required" minlength="1" maxlength="200" value="<?php echo (empty($thispage['nav']) ? $thispage['title'] : $thispage['nav']); ?>" />
|
||||
</div>
|
||||
|
||||
<label class="mb-0 pb-0"><?php lang("navbar position"); ?></label>
|
||||
<label class="mb-0 pb-0"><?php $Strings->get("navbar position"); ?></label>
|
||||
<div class="list-group py-3" id="navbar-order-list">
|
||||
<?php
|
||||
foreach ($pagedata as $page) {
|
||||
if (is_empty($page['nav'])) {
|
||||
if (empty($page['nav'])) {
|
||||
continue;
|
||||
}
|
||||
?>
|
||||
@ -183,8 +184,8 @@ if (!is_empty($VARS['siteid'])) {
|
||||
<input type="hidden" name="pageid" value="<?php echo $thispage['pageid']; ?>" />
|
||||
<input type="hidden" name="action" value="pagesettings" />
|
||||
<input type="hidden" name="source" value="editor" />
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php lang("cancel"); ?></button>
|
||||
<button type="submit" class="btn btn-success" id="pageSettingsModalSave"><i class="fas fa-save"></i> <?php lang("save"); ?></button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php $Strings->get("cancel"); ?></button>
|
||||
<button type="submit" class="btn btn-success" id="pageSettingsModalSave"><i class="fas fa-save"></i> <?php $Strings->get("save"); ?></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -194,22 +195,22 @@ if (!is_empty($VARS['siteid'])) {
|
||||
<div class="modal-dialog" role="document">
|
||||
<form class="modal-content" action="action.php" method="POST">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="newPageLabel"><i class="fas fa-plus"></i> <?php lang("new page"); ?></h5>
|
||||
<h5 class="modal-title" id="newPageLabel"><i class="fas fa-plus"></i> <?php $Strings->get("new page"); ?></h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body" id="newPageModalBody">
|
||||
<div class="form-group">
|
||||
<label><i class="fas fa-font"></i> <?php lang("title"); ?></label>
|
||||
<label><i class="fas fa-font"></i> <?php $Strings->get("title"); ?></label>
|
||||
<input type="text" id="newPageTitle" name="title" class="form-control" required="required" minlength="1" maxlength="200" />
|
||||
</div>
|
||||
<!--<div class="form-group">
|
||||
<label><i class="fas fa-link"></i> <?php lang("page id"); ?></label>
|
||||
<label><i class="fas fa-link"></i> <?php $Strings->get("page id"); ?></label>
|
||||
<input type="text" id="newPageSlug" name="slug" class="form-control" placeholder="" minlength="1" maxlength="200" />
|
||||
</div>-->
|
||||
<div class="form-group">
|
||||
<label><i class="fas fa-paint-brush"></i> <?php lang("template"); ?></label>
|
||||
<label><i class="fas fa-paint-brush"></i> <?php $Strings->get("template"); ?></label>
|
||||
<select id="newPageTemplate" name="template" class="form-control" required="required">
|
||||
<?php
|
||||
$json = file_get_contents(__DIR__ . "/../public/themes/" . $sitedata['theme'] . "/theme.json");
|
||||
@ -225,8 +226,8 @@ if (!is_empty($VARS['siteid'])) {
|
||||
<input type="hidden" name="siteid" value="<?php echo $sitedata['siteid']; ?>" />
|
||||
<input type="hidden" name="action" value="newpage" />
|
||||
<input type="hidden" name="source" value="editor" />
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php lang("cancel"); ?></button>
|
||||
<button type="submit" class="btn btn-success" id="newPageModalSave"><i class="fas fa-plus"></i> <?php lang("add page"); ?></button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php $Strings->get("cancel"); ?></button>
|
||||
<button type="submit" class="btn btn-success" id="newPageModalSave"><i class="fas fa-plus"></i> <?php $Strings->get("add page"); ?></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -236,40 +237,40 @@ if (!is_empty($VARS['siteid'])) {
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="editLabel"><?php lang("edit component"); ?></h5>
|
||||
<h5 class="modal-title" id="editLabel"><?php $Strings->get("edit component"); ?></h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body" id="editModalBody">
|
||||
<div class="form-group d-none" id="iconEdit">
|
||||
<label><i class="fas fa-paint-brush"></i> <?php lang("icon"); ?></label>
|
||||
<label><i class="fas fa-paint-brush"></i> <?php $Strings->get("icon"); ?></label>
|
||||
<br /> <div class="card d-inline-block mb-2">
|
||||
<div class="card-body p-1">
|
||||
<?php lang("current"); ?>: <span id="selectedicon"><i class="fa-fw"></i></span>
|
||||
<?php $Strings->get("current"); ?>: <span id="selectedicon"><i class="fa-fw"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="iconpicker"><i class="fas fa-spin fa-circle-notch ml-2"></i> <?php lang("loading"); ?></div>
|
||||
<div id="iconpicker"><i class="fas fa-spin fa-circle-notch ml-2"></i> <?php $Strings->get("loading"); ?></div>
|
||||
</div>
|
||||
<div class="form-group d-none" id="imageEdit" data-image="">
|
||||
<label><i class="fas fa-image"></i> <?php lang("image"); ?></label>
|
||||
<label><i class="fas fa-image"></i> <?php $Strings->get("image"); ?></label>
|
||||
<br /> <div class="card d-inline-block mb-2">
|
||||
<div class="card-body p-1">
|
||||
<img id="selectedimage" class="img-responsive" />
|
||||
<br />
|
||||
<span class="btn btn-sm btn-outline-danger mt-1" id="removeimagebtn">
|
||||
<span class="fas fa-times fa-fw"></span> <?php lang("remove image"); ?>
|
||||
<span class="fas fa-times fa-fw"></span> <?php $Strings->get("remove image"); ?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="imagepicker">
|
||||
<i class="fas fa-spin fa-circle-notch ml-2"></i> <?php lang("loading"); ?>
|
||||
<i class="fas fa-spin fa-circle-notch ml-2"></i> <?php $Strings->get("loading"); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" id="linkEdit">
|
||||
<label><i class="fas fa-link"></i> <?php lang("link"); ?></label>
|
||||
<label><i class="fas fa-link"></i> <?php $Strings->get("link"); ?></label>
|
||||
<select id="linkPage" class="form-control">
|
||||
<option value=""><?php lang("select page or enter url"); ?></option>
|
||||
<option value=""><?php $Strings->get("select page or enter url"); ?></option>
|
||||
<?php
|
||||
foreach ($pagedata as $p) {
|
||||
echo "<option value=\"" . $p['slug'] . "\">" . $p['title'] . ' (' . $p['slug'] . ')' . "</option>\n";
|
||||
@ -279,13 +280,13 @@ if (!is_empty($VARS['siteid'])) {
|
||||
<input type="text" id="linkBox" class="form-control" placeholder="http://example.com" />
|
||||
</div>
|
||||
<div class="form-group" id="textEdit">
|
||||
<label><i class="fas fa-font"></i> <?php lang("text"); ?></label>
|
||||
<label><i class="fas fa-font"></i> <?php $Strings->get("text"); ?></label>
|
||||
<input type="text" id="textBox" class="form-control" placeholder="Edit me" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php lang("cancel"); ?></button>
|
||||
<button type="button" class="btn btn-success" id="editModalSave"><i class="fas fa-save"></i> <?php lang("save"); ?></button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php $Strings->get("cancel"); ?></button>
|
||||
<button type="button" class="btn btn-success" id="editModalSave"><i class="fas fa-save"></i> <?php $Strings->get("save"); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -295,24 +296,24 @@ if (!is_empty($VARS['siteid'])) {
|
||||
<div class="col-12 col-sm-6">
|
||||
<div class="btn-group">
|
||||
<div class="btn btn-success" id="savebtn">
|
||||
<i class="fas fa-save"></i> <?php lang("save"); ?>
|
||||
<i class="fas fa-save"></i> <?php $Strings->get("save"); ?>
|
||||
</div>
|
||||
<div class="btn btn-secondary" id="pagesettingsbtn">
|
||||
<i class="fas fa-cog"></i> <?php lang("settings"); ?>
|
||||
<i class="fas fa-cog"></i> <?php $Strings->get("settings"); ?>
|
||||
</div>
|
||||
<a class="btn btn-info" id="viewbtn" target="_BLANK" href="public/index.php?id=<?php echo $slug; ?>&siteid=<?php echo $VARS['siteid']; ?>">
|
||||
<i class="fas fa-eye"></i> <?php lang("view"); ?>
|
||||
<i class="fas fa-eye"></i> <?php $Strings->get("view"); ?>
|
||||
</a>
|
||||
<?php if (!$singlepage) { ?>
|
||||
<div class="btn btn-primary" id="newpagebtn">
|
||||
<i class="fas fa-plus"></i> <?php lang("new"); ?>
|
||||
<i class="fas fa-plus"></i> <?php $Strings->get("new"); ?>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<span class="badge badge-success d-none" id="savedBadge"><i class="fas fa-check"></i> <?php lang("saved"); ?></span>
|
||||
<span class="badge badge-success d-none" id="savedBadge"><i class="fas fa-check"></i> <?php $Strings->get("saved"); ?></span>
|
||||
<div id="reloadprompt" class="badge badge-info d-none">
|
||||
<i class="fas fa-sync-alt"></i>
|
||||
<?php lang("save needed"); ?>
|
||||
<?php $Strings->get("save needed"); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php if (!$singlepage) { ?>
|
||||
@ -332,7 +333,7 @@ if (!is_empty($VARS['siteid'])) {
|
||||
?>
|
||||
</select>
|
||||
<div class="input-group-append">
|
||||
<button type="submit" class="btn btn-primary"><i class="fas fa-edit"></i> <?php lang("edit"); ?></button>
|
||||
<button type="submit" class="btn btn-primary"><i class="fas fa-edit"></i> <?php $Strings->get("edit"); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -7,8 +7,9 @@ require_once __DIR__ . '/../required.php';
|
||||
|
||||
redirectifnotloggedin();
|
||||
|
||||
require_once __DIR__ . "/../lib/login.php";
|
||||
if (!account_has_permission($_SESSION['username'], "SITEWRITER") && !account_has_permission($_SESSION['username'], "SITEWRITER_FILES") && !account_has_permission($_SESSION['username'], "SITEWRITER_EDIT")) {
|
||||
$user = new User($_SESSION['uid']);
|
||||
|
||||
if (!$user->hasPermission("SITEWRITER") && !$user->hasPermission("SITEWRITER_FILES") && !$user->hasPermission("SITEWRITER_EDIT")) {
|
||||
// Note: the EDIT permission is valid here because content editors can browse files anyways
|
||||
if ($_GET['msg'] != "no_permission") {
|
||||
header("Location: app.php?page=files&msg=no_permission");
|
||||
@ -18,10 +19,10 @@ if (!account_has_permission($_SESSION['username'], "SITEWRITER") && !account_has
|
||||
|
||||
include_once __DIR__ . "/../lib/mimetypes.php";
|
||||
|
||||
$base = FILE_UPLOAD_PATH;
|
||||
$base = $SETTINGS["file_upload_path"];
|
||||
|
||||
$folder = "";
|
||||
if (isset($VARS['path']) && file_exists($base . $VARS['path']) && strpos(realpath($base . $VARS['path']), FILE_UPLOAD_PATH) === 0) {
|
||||
if (isset($VARS['path']) && file_exists($base . $VARS['path']) && strpos(realpath($base . $VARS['path']), $SETTINGS["file_upload_path"]) === 0) {
|
||||
$folder = $VARS['path'];
|
||||
}
|
||||
|
||||
@ -63,9 +64,9 @@ $fullpath = $base . $folder;
|
||||
<input type="text" id="uploadstatus" class="form-control" readonly />
|
||||
<div class="input-group-append">
|
||||
<span class="btn btn-primary btn-file">
|
||||
<i class="fas fa-folder-open"></i> <?php lang("browse"); ?> <input id="fileupload" type="file" name="files[]" multiple required />
|
||||
<i class="fas fa-folder-open"></i> <?php $Strings->get("browse"); ?> <input id="fileupload" type="file" name="files[]" multiple required />
|
||||
</span>
|
||||
<button class="btn btn-success" type="submit"><i class="fas fa-cloud-upload-alt"></i> <?php lang("upload"); ?></button>
|
||||
<button class="btn btn-success" type="submit"><i class="fas fa-cloud-upload-alt"></i> <?php $Strings->get("upload"); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="action" value="fileupload" />
|
||||
@ -76,7 +77,7 @@ $fullpath = $base . $folder;
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="text" class="form-control" name="folder" required />
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-success" type="submit"><i class="fas fa-folder"></i> <?php lang("new folder"); ?></button>
|
||||
<button class="btn btn-success" type="submit"><i class="fas fa-folder"></i> <?php $Strings->get("new folder"); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="action" value="newfolder" />
|
||||
@ -133,7 +134,7 @@ $fullpath = $base . $folder;
|
||||
<input type="hidden" name="action" value="filedelete" />
|
||||
<input type="hidden" name="source" value="files" />
|
||||
<input type="hidden" name="file" value="<?php echo "$folder/$f"; ?>" />
|
||||
<button type="submit" class="btn btn-outline-danger btn-sm"><i class="fas fa-trash"></i> <?php lang("delete"); ?></button>
|
||||
<button type="submit" class="btn btn-outline-danger btn-sm"><i class="fas fa-trash"></i> <?php $Strings->get("delete"); ?></button>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
@ -146,7 +147,7 @@ $fullpath = $base . $folder;
|
||||
<i class="far fa-folder-open fa-10x fa-fw"></i>
|
||||
</p>
|
||||
<p class="h4 text-muted">
|
||||
<?php lang("nothing here"); ?>
|
||||
<?php $Strings->get("nothing here"); ?>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
|
26
pages/form.php
Normal file
26
pages/form.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file demonstrates creating a form with the FormBuilder class.
|
||||
*/
|
||||
|
||||
$form = new FormBuilder("Sample Form", "fas fa-code", "", "GET");
|
||||
|
||||
$form->setID("sampleform");
|
||||
|
||||
$form->addHiddenInput("page", "form");
|
||||
|
||||
$form->addInput("name", "John", "text", true, null, null, "Your name", "fas fa-user", 6, 5, 20, "John(ny)?|Steve", "Invalid name, please enter John, Johnny, or Steve.");
|
||||
$form->addInput("location", "", "select", true, null, ["1" => "Here", "2" => "There"], "Location", "fas fa-map-marker");
|
||||
$form->addInput("textbox", "Hello world", "textarea", true, null, null, "Text area", "fas fa-font");
|
||||
$form->addInput("box", "1", "checkbox", true, null, null, "I agree to the terms of service");
|
||||
|
||||
$form->addButton("Submit", "fas fa-save", null, "submit", "savebtn");
|
||||
|
||||
$form->generate();
|
@ -24,19 +24,19 @@ die();
|
||||
?>
|
||||
<div class="card bg-blue text-light">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title"><?php lang("today") ?></h4>
|
||||
<h4 class="card-title"><?php $Strings->get("today") ?></h4>
|
||||
<h1><i class="fas fa-fw fa-users"></i> <?php echo $visits_today; ?> <?php
|
||||
if ($visits_today == 1) {
|
||||
lang("visit");
|
||||
$Strings->get("visit");
|
||||
} else {
|
||||
lang("visits");
|
||||
$Strings->get("visits");
|
||||
}
|
||||
?></h1>
|
||||
<h1><i class="fas fa-fw fa-eye"></i> <?php echo $views_today; ?> <?php
|
||||
if ($views_today == 1) {
|
||||
lang("page view");
|
||||
$Strings->get("page view");
|
||||
} else {
|
||||
lang("page views");
|
||||
$Strings->get("page views");
|
||||
}
|
||||
?></h1>
|
||||
</div>
|
||||
@ -54,19 +54,19 @@ die();
|
||||
?>
|
||||
<div class="card bg-green text-light">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title"><?php lang("this week") ?></h4>
|
||||
<h4 class="card-title"><?php $Strings->get("this week") ?></h4>
|
||||
<h1><i class="fas fa-fw fa-users"></i> <?php echo $visits_week; ?> <?php
|
||||
if ($visits_week == 1) {
|
||||
lang("visit");
|
||||
$Strings->get("visit");
|
||||
} else {
|
||||
lang("visits");
|
||||
$Strings->get("visits");
|
||||
}
|
||||
?></h1>
|
||||
<h1><i class="fas fa-fw fa-eye"></i> <?php echo $views_week; ?> <?php
|
||||
if ($views_week == 1) {
|
||||
lang("page view");
|
||||
$Strings->get("page view");
|
||||
} else {
|
||||
lang("page views");
|
||||
$Strings->get("page views");
|
||||
}
|
||||
?></h1>
|
||||
</div>
|
||||
|
@ -7,8 +7,9 @@ require_once __DIR__ . '/../required.php';
|
||||
|
||||
redirectifnotloggedin();
|
||||
|
||||
require_once __DIR__ . "/../lib/login.php";
|
||||
if (!account_has_permission($_SESSION['username'], "SITEWRITER") && !account_has_permission($_SESSION['username'], "SITEWRITER_CONTACT")) {
|
||||
$user = new User($_SESSION['uid']);
|
||||
|
||||
if (!$user->hasPermission("SITEWRITER") && !$user->hasPermission("SITEWRITER_CONTACT")) {
|
||||
if ($_GET['msg'] != "no_permission") {
|
||||
header("Location: app.php?page=messages&msg=no_permission");
|
||||
}
|
||||
@ -19,12 +20,12 @@ if (!account_has_permission($_SESSION['username'], "SITEWRITER") && !account_has
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-priority="0"></th>
|
||||
<th data-priority="1"><?php lang('actions'); ?></th>
|
||||
<th data-priority="1"><i class="fas fa-user d-none d-md-inline"></i> <?php lang('name'); ?></th>
|
||||
<th data-priority="2"><i class="fas fa-envelope d-none d-md-inline"></i> <?php lang('message'); ?></th>
|
||||
<th data-priority="3"><i class="fas fa-at d-none d-md-inline"></i> <?php lang('email'); ?></th>
|
||||
<th data-priority="4"><i class="fas fa-globe d-none d-md-inline"></i> <?php lang('site'); ?></th>
|
||||
<th data-priority="5"><i class="fas fa-calendar d-none d-md-inline"></i> <?php lang('date'); ?></th>
|
||||
<th data-priority="1"><?php $Strings->get('actions'); ?></th>
|
||||
<th data-priority="1"><i class="fas fa-user d-none d-md-inline"></i> <?php $Strings->get('name'); ?></th>
|
||||
<th data-priority="2"><i class="fas fa-envelope d-none d-md-inline"></i> <?php $Strings->get('message'); ?></th>
|
||||
<th data-priority="3"><i class="fas fa-at d-none d-md-inline"></i> <?php $Strings->get('email'); ?></th>
|
||||
<th data-priority="4"><i class="fas fa-globe d-none d-md-inline"></i> <?php $Strings->get('site'); ?></th>
|
||||
<th data-priority="5"><i class="fas fa-calendar d-none d-md-inline"></i> <?php $Strings->get('date'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -58,20 +59,20 @@ if (!account_has_permission($_SESSION['username'], "SITEWRITER") && !account_has
|
||||
class="btn btn-primary btn-sm"
|
||||
href="<?php echo $mailto; ?>"
|
||||
>
|
||||
<i class="fas fa-reply"></i> <?php lang("reply"); ?>
|
||||
<i class="fas fa-reply"></i> <?php $Strings->get("reply"); ?>
|
||||
</a>
|
||||
<span
|
||||
class="btn btn-danger btn-sm deletemsgbtn"
|
||||
data-message="<?php echo $m['mid']; ?>"
|
||||
>
|
||||
<i class="fas fa-trash"></i> <?php lang("delete"); ?>
|
||||
<i class="fas fa-trash"></i> <?php $Strings->get("delete"); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td><?php echo $m['name']; ?></td>
|
||||
<td><?php echo $m['message']; ?></td>
|
||||
<td><?php echo $m['email']; ?></td>
|
||||
<td><?php echo $m['sitename']; ?></td>
|
||||
<td><?php echo date("M j Y, g:i A", strtotime($m['date'])); ?></td>
|
||||
<td><span class="d-none"><?php echo strtotime($m['date']); ?></span><?php echo date("M j Y, g:i A", strtotime($m['date'])); ?></td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
@ -80,12 +81,12 @@ if (!account_has_permission($_SESSION['username'], "SITEWRITER") && !account_has
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th data-priority="0"></th>
|
||||
<th data-priority="1"><?php lang('actions'); ?></th>
|
||||
<th data-priority="1"><i class="fas fa-user d-none d-md-inline"></i> <?php lang('name'); ?></th>
|
||||
<th data-priority="2"><i class="fas fa-envelope d-none d-md-inline"></i> <?php lang('message'); ?></th>
|
||||
<th data-priority="3"><i class="fas fa-at d-none d-md-inline"></i> <?php lang('email'); ?></th>
|
||||
<th data-priority="4"><i class="fas fa-globe d-none d-md-inline"></i> <?php lang('site'); ?></th>
|
||||
<th data-priority="5"><i class="fas fa-calendar d-none d-md-inline"></i> <?php lang('date'); ?></th>
|
||||
<th data-priority="1"><?php $Strings->get('actions'); ?></th>
|
||||
<th data-priority="1"><i class="fas fa-user d-none d-md-inline"></i> <?php $Strings->get('name'); ?></th>
|
||||
<th data-priority="2"><i class="fas fa-envelope d-none d-md-inline"></i> <?php $Strings->get('message'); ?></th>
|
||||
<th data-priority="3"><i class="fas fa-at d-none d-md-inline"></i> <?php $Strings->get('email'); ?></th>
|
||||
<th data-priority="4"><i class="fas fa-globe d-none d-md-inline"></i> <?php $Strings->get('site'); ?></th>
|
||||
<th data-priority="5"><i class="fas fa-calendar d-none d-md-inline"></i> <?php $Strings->get('date'); ?></th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
@ -8,23 +8,24 @@ require_once __DIR__ . '/../lib/util.php';
|
||||
|
||||
redirectifnotloggedin();
|
||||
|
||||
require_once __DIR__ . "/../lib/login.php";
|
||||
$user = new User($_SESSION['uid']);
|
||||
|
||||
$showbuttons = true;
|
||||
if (!account_has_permission($_SESSION['username'], "SITEWRITER") && !account_has_permission($_SESSION['username'], "SITEWRITER_EDIT")) {
|
||||
if (!$user->hasPermission("SITEWRITER") && !$user->hasPermission("SITEWRITER_EDIT")) {
|
||||
$showbuttons = false;
|
||||
}
|
||||
?>
|
||||
<div class="btn-group mb-2">
|
||||
<a href="app.php?page=sitesettings" class="btn btn-success"><i class="fas fa-plus"></i> <?php lang("new site"); ?></a>
|
||||
<a href="app.php?page=sitesettings" class="btn btn-success"><i class="fas fa-plus"></i> <?php $Strings->get("new site"); ?></a>
|
||||
</div>
|
||||
<table class="table table-bordered table-hover table-sm table-responsive-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-priority="0"></th>
|
||||
<th data-priority="1"><?php lang('actions'); ?></th>
|
||||
<th data-priority="1"><i class="fas fa-font d-none d-md-inline"></i> <?php lang('site name'); ?></th>
|
||||
<th data-priority="2"><i class="fas fa-globe d-none d-md-inline"></i> <?php lang('url'); ?></th>
|
||||
<th data-priority="3" class="d-none d-sm-table-cell"><i class="fas fa-paint-brush d-none d-md-inline"></i> <?php lang('theme'); ?></th>
|
||||
<th data-priority="1"><?php $Strings->get('actions'); ?></th>
|
||||
<th data-priority="1"><i class="fas fa-font d-none d-md-inline"></i> <?php $Strings->get('site name'); ?></th>
|
||||
<th data-priority="2"><i class="fas fa-globe d-none d-md-inline"></i> <?php $Strings->get('url'); ?></th>
|
||||
<th data-priority="3" class="d-none d-sm-table-cell"><i class="fas fa-paint-brush d-none d-md-inline"></i> <?php $Strings->get('theme'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -46,12 +47,12 @@ if (!account_has_permission($_SESSION['username'], "SITEWRITER") && !account_has
|
||||
<?php
|
||||
if ($showbuttons) {
|
||||
?>
|
||||
<a class="btn btn-primary btn-sm" href="app.php?page=editor&siteid=<?php echo $site['siteid']; ?>"><i class="fas fa-edit"></i> <?php lang("editor"); ?></a>
|
||||
<a class="btn btn-secondary btn-sm" href="app.php?page=sitesettings&siteid=<?php echo $site['siteid']; ?>"><i class="fas fa-cog"></i> <?php lang("settings"); ?></a>
|
||||
<a class="btn btn-primary btn-sm" href="app.php?page=editor&siteid=<?php echo $site['siteid']; ?>"><i class="fas fa-edit"></i> <?php $Strings->get("editor"); ?></a>
|
||||
<a class="btn btn-secondary btn-sm" href="app.php?page=sitesettings&siteid=<?php echo $site['siteid']; ?>"><i class="fas fa-cog"></i> <?php $Strings->get("settings"); ?></a>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<a class="btn btn-info btn-sm" href="<?php echo formatsiteurl($site['url']); ?>" target="_BLANK"><i class="fas fa-eye"></i> <?php lang("view"); ?></a>
|
||||
<a class="btn btn-info btn-sm" href="<?php echo formatsiteurl($site['url']); ?>" target="_BLANK"><i class="fas fa-eye"></i> <?php $Strings->get("view"); ?></a>
|
||||
</td>
|
||||
<td><?php echo $site['sitename']; ?></td>
|
||||
<td><?php echo $site['url']; ?></td>
|
||||
@ -64,10 +65,10 @@ if (!account_has_permission($_SESSION['username'], "SITEWRITER") && !account_has
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th data-priority="0"></th>
|
||||
<th data-priority="1"><?php lang('actions'); ?></th>
|
||||
<th data-priority="1"><i class="fas fa-font d-none d-md-inline"></i> <?php lang('site name'); ?></th>
|
||||
<th data-priority="2"><i class="fas fa-globe d-none d-md-inline"></i> <?php lang('url'); ?></th>
|
||||
<th data-priority="3" class="d-none d-sm-table-cell"><i class="fas fa-paint-brush d-none d-md-inline"></i> <?php lang('theme'); ?></th>
|
||||
<th data-priority="1"><?php $Strings->get('actions'); ?></th>
|
||||
<th data-priority="1"><i class="fas fa-font d-none d-md-inline"></i> <?php $Strings->get('site name'); ?></th>
|
||||
<th data-priority="2"><i class="fas fa-globe d-none d-md-inline"></i> <?php $Strings->get('url'); ?></th>
|
||||
<th data-priority="3" class="d-none d-sm-table-cell"><i class="fas fa-paint-brush d-none d-md-inline"></i> <?php $Strings->get('theme'); ?></th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
@ -7,8 +7,9 @@ require_once __DIR__ . '/../required.php';
|
||||
|
||||
redirectifnotloggedin();
|
||||
|
||||
require_once __DIR__ . "/../lib/login.php";
|
||||
if (!account_has_permission($_SESSION['username'], "SITEWRITER")) {
|
||||
$user = new User($_SESSION['uid']);
|
||||
|
||||
if (!$user->hasPermission("SITEWRITER")) {
|
||||
if ($_GET['msg'] != "no_permission") {
|
||||
header("Location: app.php?page=sitesettings&msg=no_permission");
|
||||
}
|
||||
@ -27,7 +28,7 @@ $sitedata = [
|
||||
];
|
||||
$settings = [];
|
||||
|
||||
if (isset($VARS['siteid']) && !is_empty($VARS['siteid'])) {
|
||||
if (!empty($VARS['siteid'])) {
|
||||
if ($database->has('sites', ['siteid' => $VARS['siteid']])) {
|
||||
$siteid = $VARS['siteid'];
|
||||
$sitedata = $database->select(
|
||||
@ -74,11 +75,11 @@ function getsetting($name) {
|
||||
<?php
|
||||
if ($editing) {
|
||||
?>
|
||||
<i class="fas fa-edit"></i> <?php lang2("editing site", ['site' => "<span id=\"name_title\">" . htmlspecialchars($sitedata['sitename']) . "</span>"]); ?>
|
||||
<i class="fas fa-edit"></i> <?php $Strings->build("editing site", ['site' => "<span id=\"name_title\">" . htmlspecialchars($sitedata['sitename']) . "</span>"]); ?>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<i class="fas fa-plus"></i> <?php lang2("adding site", ['site' => "<span id=\"name_title\">" . htmlspecialchars($sitedata['sitename']) . "</span>"]); ?>
|
||||
<i class="fas fa-plus"></i> <?php $Strings->build("adding site", ['site' => "<span id=\"name_title\">" . htmlspecialchars($sitedata['sitename']) . "</span>"]); ?>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
@ -86,16 +87,16 @@ function getsetting($name) {
|
||||
<div class="card-body">
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="fas fa-info-circle"></i> <?php lang("site info"); ?></h5>
|
||||
<h5 class="card-title"><i class="fas fa-info-circle"></i> <?php $Strings->get("site info"); ?></h5>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><label for="name"><i class="fas fa-font"></i> <?php lang("title"); ?></label></span>
|
||||
<span class="input-group-text"><label for="name"><i class="fas fa-font"></i> <?php $Strings->get("title"); ?></label></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" id="name" name="name" placeholder="Foo Bar" required="required" value="<?php echo htmlspecialchars($sitedata['sitename']); ?>" />
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><label for="url"><i class="fas fa-globe"></i> <?php lang("url"); ?></label></span>
|
||||
<span class="input-group-text"><label for="url"><i class="fas fa-globe"></i> <?php $Strings->get("url"); ?></label></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" id="url" name="url" placeholder="https://example.com" required="required" value="<?php echo htmlspecialchars($sitedata['url']); ?>" />
|
||||
</div>
|
||||
@ -104,7 +105,7 @@ function getsetting($name) {
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<h5 class="card-title"><label for="theme"><i class="fas fa-paint-brush"></i> <?php lang('theme'); ?></label></h5>
|
||||
<h5 class="card-title"><label for="theme"><i class="fas fa-paint-brush"></i> <?php $Strings->get('theme'); ?></label></h5>
|
||||
<div class="theme_bin_overflow">
|
||||
<div class="theme_bin card-columns">
|
||||
<?php
|
||||
@ -132,18 +133,18 @@ function getsetting($name) {
|
||||
<span class="d-flex">
|
||||
<h4 class="mr-auto"><?php echo $info['name']; ?></h4>
|
||||
<a href="public/index.php?page=index&siteid=<?php echo $siteid; ?>&theme=<?php echo $t; ?>" target="_BLANK">
|
||||
<i class="fas fa-eye"></i> <?php lang("preview"); ?>
|
||||
<i class="fas fa-eye"></i> <?php $Strings->get("preview"); ?>
|
||||
</a>
|
||||
</span>
|
||||
<b><?php lang("theme type"); ?></b>:
|
||||
<b><?php $Strings->get("theme type"); ?></b>:
|
||||
<?php
|
||||
if ($info['singlepage'] == true) {
|
||||
lang("single page");
|
||||
$Strings->get("single page");
|
||||
} else {
|
||||
lang("multiple page");
|
||||
$Strings->get("multiple page");
|
||||
}
|
||||
?><br />
|
||||
<b><?php lang("templates"); ?></b>:
|
||||
<b><?php $Strings->get("templates"); ?></b>:
|
||||
<?php
|
||||
$temtitles = [];
|
||||
foreach ($info['templates'] as $tem) {
|
||||
@ -151,11 +152,11 @@ function getsetting($name) {
|
||||
}
|
||||
echo implode(", ", $temtitles);
|
||||
?><br />
|
||||
<b><?php lang("color styles"); ?></b>:
|
||||
<b><?php $Strings->get("color styles"); ?></b>:
|
||||
<div class="list-group colorSelector">
|
||||
<?php
|
||||
if (count($info['colors']) == 0) {
|
||||
$info['colors'] = ["default" => ["title" => lang("default", false), "description" => ""]];
|
||||
$info['colors'] = ["default" => ["title" => $Strings->get("default", false), "description" => ""]];
|
||||
}
|
||||
foreach ($info['colors'] as $c => $color) {
|
||||
$checked = "";
|
||||
@ -169,7 +170,7 @@ function getsetting($name) {
|
||||
<b><?php echo $color["title"]; ?></b>
|
||||
<div class="text-nowrap">
|
||||
<a href="public/index.php?page=index&siteid=<?php echo $siteid; ?>&theme=<?php echo $t; ?>&color=<?php echo $c; ?>" target="_BLANK">
|
||||
<i class="fas fa-eye"></i> <?php lang("preview"); ?>
|
||||
<i class="fas fa-eye"></i> <?php $Strings->get("preview"); ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@ -194,32 +195,32 @@ function getsetting($name) {
|
||||
<!-- Company/Org Info -->
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="fas fa-briefcase"></i> <?php lang("company info"); ?></h5>
|
||||
<h5 class="card-title"><i class="fas fa-briefcase"></i> <?php $Strings->get("company info"); ?></h5>
|
||||
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><label for="businessname"><i class="fas fa-font"></i> <?php lang("name"); ?></label></span>
|
||||
<span class="input-group-text"><label for="businessname"><i class="fas fa-font"></i> <?php $Strings->get("name"); ?></label></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="settings[businessname]" id="businessname" value="<?php echo getsetting("businessname"); ?>" />
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><label for="phone"><i class="fas fa-phone"></i> <?php lang("phone"); ?></label></span>
|
||||
<span class="input-group-text"><label for="phone"><i class="fas fa-phone"></i> <?php $Strings->get("phone"); ?></label></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="settings[phone]" id="phone" value="<?php echo getsetting("phone"); ?>" />
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><label for="address"><i class="fas fa-map-marker"></i> <?php lang("address"); ?></label></span>
|
||||
<span class="input-group-text"><label for="address"><i class="fas fa-map-marker"></i> <?php $Strings->get("address"); ?></label></span>
|
||||
</div>
|
||||
<textarea class="form-control" name="settings[address]" id="address" rows="2"><?php echo getsetting("address"); ?></textarea>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><label for="email"><i class="fas fa-envelope"></i> <?php lang("email"); ?></label></span>
|
||||
<span class="input-group-text"><label for="email"><i class="fas fa-envelope"></i> <?php $Strings->get("email"); ?></label></span>
|
||||
</div>
|
||||
<input type="email" class="form-control" name="settings[email]" id="email" value="<?php echo getsetting("email"); ?>" />
|
||||
</div>
|
||||
@ -229,26 +230,40 @@ function getsetting($name) {
|
||||
<!-- Analytics -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="fas fa-chart-bar"></i> <?php lang("analytics"); ?></h5>
|
||||
<h5 class="card-title"><i class="fas fa-chart-bar"></i> <?php $Strings->get("analytics"); ?></h5>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="settings[analytics]" value="" id="analytics_on" <?php echo ((isset($settings["analytics"]) && $settings["analytics"] === "off") ? "" : "checked") ?>>
|
||||
<label class="form-check-label" for="analytics_on">
|
||||
<?php lang("enable built-in analytics"); ?>
|
||||
<?php $Strings->get("enable built-in analytics"); ?>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="settings[analytics]" value="off" id="analytics_off" <?php echo ((isset($settings["analytics"]) && $settings["analytics"] === "off") ? "checked" : "") ?>>
|
||||
<label class="form-check-label" for="analytics_off">
|
||||
<?php lang("disable built-in analytics"); ?>
|
||||
<?php $Strings->get("disable built-in analytics"); ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contact Form -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="fas fa-comments"></i> <?php $Strings->get("contact form"); ?></h5>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><label for="contactemail"><i class="fas fa-envelope"></i> Forward to:</label></span>
|
||||
</div>
|
||||
<input type="email" class="form-control" name="settings[contactemail]" id="contactemail" value="<?php echo getsetting("contactemail"); ?>" />
|
||||
</div>
|
||||
<small class="form-text"><?php $Strings->get("contact form messages will be forwarded to this email address"); ?></small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Extra code header snippets -->
|
||||
<div class="card mt-4 mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><label for="extracode"><i class="fas fa-code"></i> <?php lang("extra code"); ?></label></h5>
|
||||
<h5 class="card-title"><label for="extracode"><i class="fas fa-code"></i> <?php $Strings->get("extra code"); ?></label></h5>
|
||||
<textarea class="form-control" name="settings[extracode]" id="extracode" placeholder="<script></script>" rows="5"><?php echo (isset($settings["extracode"]) ? $settings["extracode"] : ""); ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
@ -258,7 +273,7 @@ function getsetting($name) {
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="fas fa-share-square"></i> <?php lang("social links"); ?></h5>
|
||||
<h5 class="card-title"><i class="fas fa-share-square"></i> <?php $Strings->get("social links"); ?></h5>
|
||||
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
@ -351,7 +366,7 @@ function getsetting($name) {
|
||||
<div class="col-12">
|
||||
<div class="card mt-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><label><i class="fas fa-list"></i> <?php lang("site footer links"); ?></label></h5>
|
||||
<h5 class="card-title"><label><i class="fas fa-list"></i> <?php $Strings->get("site footer links"); ?></label></h5>
|
||||
<div id="footer-link-bin">
|
||||
<?php
|
||||
$footerset = false;
|
||||
@ -373,11 +388,11 @@ function getsetting($name) {
|
||||
?>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><?php lang("title"); ?>:</span>
|
||||
<span class="input-group-text"><?php $Strings->get("title"); ?>:</span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="settings[footerlinks][<?php echo $i; ?>][title]" value="<?php echo $title; ?>" />
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><?php lang("link"); ?>:</span>
|
||||
<span class="input-group-text"><?php $Strings->get("link"); ?>:</span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="settings[footerlinks][<?php echo $i; ?>][link]" value="<?php echo $url; ?>" />
|
||||
</div>
|
||||
@ -396,7 +411,7 @@ function getsetting($name) {
|
||||
<input type="hidden" name="source" value="sites" />
|
||||
|
||||
<div class="card-footer d-flex">
|
||||
<button type="submit" class="btn btn-success mr-auto"><i class="fas fa-save"></i> <?php lang("save"); ?></button>
|
||||
<button type="submit" class="btn btn-success mr-auto"><i class="fas fa-save"></i> <?php $Strings->get("save"); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
@ -1,345 +1 @@
|
||||
/*!
|
||||
* Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
*/
|
||||
svg:not(:root).svg-inline--fa {
|
||||
overflow: visible; }
|
||||
|
||||
.svg-inline--fa {
|
||||
display: inline-block;
|
||||
font-size: inherit;
|
||||
height: 1em;
|
||||
overflow: visible;
|
||||
vertical-align: -.125em; }
|
||||
.svg-inline--fa.fa-lg {
|
||||
vertical-align: -.225em; }
|
||||
.svg-inline--fa.fa-w-1 {
|
||||
width: 0.0625em; }
|
||||
.svg-inline--fa.fa-w-2 {
|
||||
width: 0.125em; }
|
||||
.svg-inline--fa.fa-w-3 {
|
||||
width: 0.1875em; }
|
||||
.svg-inline--fa.fa-w-4 {
|
||||
width: 0.25em; }
|
||||
.svg-inline--fa.fa-w-5 {
|
||||
width: 0.3125em; }
|
||||
.svg-inline--fa.fa-w-6 {
|
||||
width: 0.375em; }
|
||||
.svg-inline--fa.fa-w-7 {
|
||||
width: 0.4375em; }
|
||||
.svg-inline--fa.fa-w-8 {
|
||||
width: 0.5em; }
|
||||
.svg-inline--fa.fa-w-9 {
|
||||
width: 0.5625em; }
|
||||
.svg-inline--fa.fa-w-10 {
|
||||
width: 0.625em; }
|
||||
.svg-inline--fa.fa-w-11 {
|
||||
width: 0.6875em; }
|
||||
.svg-inline--fa.fa-w-12 {
|
||||
width: 0.75em; }
|
||||
.svg-inline--fa.fa-w-13 {
|
||||
width: 0.8125em; }
|
||||
.svg-inline--fa.fa-w-14 {
|
||||
width: 0.875em; }
|
||||
.svg-inline--fa.fa-w-15 {
|
||||
width: 0.9375em; }
|
||||
.svg-inline--fa.fa-w-16 {
|
||||
width: 1em; }
|
||||
.svg-inline--fa.fa-w-17 {
|
||||
width: 1.0625em; }
|
||||
.svg-inline--fa.fa-w-18 {
|
||||
width: 1.125em; }
|
||||
.svg-inline--fa.fa-w-19 {
|
||||
width: 1.1875em; }
|
||||
.svg-inline--fa.fa-w-20 {
|
||||
width: 1.25em; }
|
||||
.svg-inline--fa.fa-pull-left {
|
||||
margin-right: .3em;
|
||||
width: auto; }
|
||||
.svg-inline--fa.fa-pull-right {
|
||||
margin-left: .3em;
|
||||
width: auto; }
|
||||
.svg-inline--fa.fa-border {
|
||||
height: 1.5em; }
|
||||
.svg-inline--fa.fa-li {
|
||||
width: 2em; }
|
||||
.svg-inline--fa.fa-fw {
|
||||
width: 1.25em; }
|
||||
|
||||
.fa-layers svg.svg-inline--fa {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0; }
|
||||
|
||||
.fa-layers {
|
||||
display: inline-block;
|
||||
height: 1em;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
vertical-align: -.125em;
|
||||
width: 1em; }
|
||||
.fa-layers svg.svg-inline--fa {
|
||||
-webkit-transform-origin: center center;
|
||||
transform-origin: center center; }
|
||||
|
||||
.fa-layers-text, .fa-layers-counter {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
text-align: center; }
|
||||
|
||||
.fa-layers-text {
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
-webkit-transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%);
|
||||
-webkit-transform-origin: center center;
|
||||
transform-origin: center center; }
|
||||
|
||||
.fa-layers-counter {
|
||||
background-color: #ff253a;
|
||||
border-radius: 1em;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
color: #fff;
|
||||
height: 1.5em;
|
||||
line-height: 1;
|
||||
max-width: 5em;
|
||||
min-width: 1.5em;
|
||||
overflow: hidden;
|
||||
padding: .25em;
|
||||
right: 0;
|
||||
text-overflow: ellipsis;
|
||||
top: 0;
|
||||
-webkit-transform: scale(0.25);
|
||||
transform: scale(0.25);
|
||||
-webkit-transform-origin: top right;
|
||||
transform-origin: top right; }
|
||||
|
||||
.fa-layers-bottom-right {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
top: auto;
|
||||
-webkit-transform: scale(0.25);
|
||||
transform: scale(0.25);
|
||||
-webkit-transform-origin: bottom right;
|
||||
transform-origin: bottom right; }
|
||||
|
||||
.fa-layers-bottom-left {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: auto;
|
||||
top: auto;
|
||||
-webkit-transform: scale(0.25);
|
||||
transform: scale(0.25);
|
||||
-webkit-transform-origin: bottom left;
|
||||
transform-origin: bottom left; }
|
||||
|
||||
.fa-layers-top-right {
|
||||
right: 0;
|
||||
top: 0;
|
||||
-webkit-transform: scale(0.25);
|
||||
transform: scale(0.25);
|
||||
-webkit-transform-origin: top right;
|
||||
transform-origin: top right; }
|
||||
|
||||
.fa-layers-top-left {
|
||||
left: 0;
|
||||
right: auto;
|
||||
top: 0;
|
||||
-webkit-transform: scale(0.25);
|
||||
transform: scale(0.25);
|
||||
-webkit-transform-origin: top left;
|
||||
transform-origin: top left; }
|
||||
|
||||
.fa-lg {
|
||||
font-size: 1.33333em;
|
||||
line-height: 0.75em;
|
||||
vertical-align: -.0667em; }
|
||||
|
||||
.fa-xs {
|
||||
font-size: .75em; }
|
||||
|
||||
.fa-sm {
|
||||
font-size: .875em; }
|
||||
|
||||
.fa-1x {
|
||||
font-size: 1em; }
|
||||
|
||||
.fa-2x {
|
||||
font-size: 2em; }
|
||||
|
||||
.fa-3x {
|
||||
font-size: 3em; }
|
||||
|
||||
.fa-4x {
|
||||
font-size: 4em; }
|
||||
|
||||
.fa-5x {
|
||||
font-size: 5em; }
|
||||
|
||||
.fa-6x {
|
||||
font-size: 6em; }
|
||||
|
||||
.fa-7x {
|
||||
font-size: 7em; }
|
||||
|
||||
.fa-8x {
|
||||
font-size: 8em; }
|
||||
|
||||
.fa-9x {
|
||||
font-size: 9em; }
|
||||
|
||||
.fa-10x {
|
||||
font-size: 10em; }
|
||||
|
||||
.fa-fw {
|
||||
text-align: center;
|
||||
width: 1.25em; }
|
||||
|
||||
.fa-ul {
|
||||
list-style-type: none;
|
||||
margin-left: 2.5em;
|
||||
padding-left: 0; }
|
||||
.fa-ul > li {
|
||||
position: relative; }
|
||||
|
||||
.fa-li {
|
||||
left: -2em;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 2em;
|
||||
line-height: inherit; }
|
||||
|
||||
.fa-border {
|
||||
border: solid 0.08em #eee;
|
||||
border-radius: .1em;
|
||||
padding: .2em .25em .15em; }
|
||||
|
||||
.fa-pull-left {
|
||||
float: left; }
|
||||
|
||||
.fa-pull-right {
|
||||
float: right; }
|
||||
|
||||
.fa.fa-pull-left,
|
||||
.fas.fa-pull-left,
|
||||
.far.fa-pull-left,
|
||||
.fal.fa-pull-left,
|
||||
.fab.fa-pull-left {
|
||||
margin-right: .3em; }
|
||||
|
||||
.fa.fa-pull-right,
|
||||
.fas.fa-pull-right,
|
||||
.far.fa-pull-right,
|
||||
.fal.fa-pull-right,
|
||||
.fab.fa-pull-right {
|
||||
margin-left: .3em; }
|
||||
|
||||
.fa-spin {
|
||||
-webkit-animation: fa-spin 2s infinite linear;
|
||||
animation: fa-spin 2s infinite linear; }
|
||||
|
||||
.fa-pulse {
|
||||
-webkit-animation: fa-spin 1s infinite steps(8);
|
||||
animation: fa-spin 1s infinite steps(8); }
|
||||
|
||||
@-webkit-keyframes fa-spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg); }
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg); } }
|
||||
|
||||
@keyframes fa-spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg); }
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg); } }
|
||||
|
||||
.fa-rotate-90 {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";
|
||||
-webkit-transform: rotate(90deg);
|
||||
transform: rotate(90deg); }
|
||||
|
||||
.fa-rotate-180 {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";
|
||||
-webkit-transform: rotate(180deg);
|
||||
transform: rotate(180deg); }
|
||||
|
||||
.fa-rotate-270 {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";
|
||||
-webkit-transform: rotate(270deg);
|
||||
transform: rotate(270deg); }
|
||||
|
||||
.fa-flip-horizontal {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";
|
||||
-webkit-transform: scale(-1, 1);
|
||||
transform: scale(-1, 1); }
|
||||
|
||||
.fa-flip-vertical {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
|
||||
-webkit-transform: scale(1, -1);
|
||||
transform: scale(1, -1); }
|
||||
|
||||
.fa-flip-horizontal.fa-flip-vertical {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
|
||||
-webkit-transform: scale(-1, -1);
|
||||
transform: scale(-1, -1); }
|
||||
|
||||
:root .fa-rotate-90,
|
||||
:root .fa-rotate-180,
|
||||
:root .fa-rotate-270,
|
||||
:root .fa-flip-horizontal,
|
||||
:root .fa-flip-vertical {
|
||||
-webkit-filter: none;
|
||||
filter: none; }
|
||||
|
||||
.fa-stack {
|
||||
display: inline-block;
|
||||
height: 2em;
|
||||
position: relative;
|
||||
width: 2em; }
|
||||
|
||||
.fa-stack-1x,
|
||||
.fa-stack-2x {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0; }
|
||||
|
||||
.svg-inline--fa.fa-stack-1x {
|
||||
height: 1em;
|
||||
width: 1em; }
|
||||
|
||||
.svg-inline--fa.fa-stack-2x {
|
||||
height: 2em;
|
||||
width: 2em; }
|
||||
|
||||
.fa-inverse {
|
||||
color: #fff; }
|
||||
|
||||
.sr-only {
|
||||
border: 0;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 1px; }
|
||||
|
||||
.sr-only-focusable:active, .sr-only-focusable:focus {
|
||||
clip: auto;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
overflow: visible;
|
||||
position: static;
|
||||
width: auto; }
|
||||
.svg-inline--fa,svg:not(:root).svg-inline--fa{overflow:visible}.svg-inline--fa{display:inline-block;font-size:inherit;height:1em;vertical-align:-.125em}.svg-inline--fa.fa-lg{vertical-align:-.225em}.svg-inline--fa.fa-w-1{width:.0625em}.svg-inline--fa.fa-w-2{width:.125em}.svg-inline--fa.fa-w-3{width:.1875em}.svg-inline--fa.fa-w-4{width:.25em}.svg-inline--fa.fa-w-5{width:.3125em}.svg-inline--fa.fa-w-6{width:.375em}.svg-inline--fa.fa-w-7{width:.4375em}.svg-inline--fa.fa-w-8{width:.5em}.svg-inline--fa.fa-w-9{width:.5625em}.svg-inline--fa.fa-w-10{width:.625em}.svg-inline--fa.fa-w-11{width:.6875em}.svg-inline--fa.fa-w-12{width:.75em}.svg-inline--fa.fa-w-13{width:.8125em}.svg-inline--fa.fa-w-14{width:.875em}.svg-inline--fa.fa-w-15{width:.9375em}.svg-inline--fa.fa-w-16{width:1em}.svg-inline--fa.fa-w-17{width:1.0625em}.svg-inline--fa.fa-w-18{width:1.125em}.svg-inline--fa.fa-w-19{width:1.1875em}.svg-inline--fa.fa-w-20{width:1.25em}.svg-inline--fa.fa-pull-left{margin-right:.3em;width:auto}.svg-inline--fa.fa-pull-right{margin-left:.3em;width:auto}.svg-inline--fa.fa-border{height:1.5em}.svg-inline--fa.fa-li{width:2em}.svg-inline--fa.fa-fw{width:1.25em}.fa-layers svg.svg-inline--fa{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.fa-layers{display:inline-block;height:1em;position:relative;text-align:center;vertical-align:-.125em;width:1em}.fa-layers svg.svg-inline--fa{transform-origin:center center}.fa-layers-counter,.fa-layers-text{display:inline-block;position:absolute;text-align:center}.fa-layers-text{left:50%;top:50%;transform:translate(-50%,-50%);transform-origin:center center}.fa-layers-counter{background-color:#ff253a;border-radius:1em;box-sizing:border-box;color:#fff;height:1.5em;line-height:1;max-width:5em;min-width:1.5em;overflow:hidden;padding:.25em;right:0;text-overflow:ellipsis;top:0;transform:scale(.25);transform-origin:top right}.fa-layers-bottom-right{bottom:0;right:0;top:auto;transform:scale(.25);transform-origin:bottom right}.fa-layers-bottom-left{bottom:0;left:0;right:auto;top:auto;transform:scale(.25);transform-origin:bottom left}.fa-layers-top-right{right:0;top:0;transform:scale(.25);transform-origin:top right}.fa-layers-top-left{left:0;right:auto;top:0;transform:scale(.25);transform-origin:top left}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{animation:fa-spin 2s infinite linear}.fa-pulse{animation:fa-spin 1s infinite steps(8)}@keyframes fa-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{display:inline-block;height:2em;position:relative;width:2.5em}.fa-stack-1x,.fa-stack-2x{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.svg-inline--fa.fa-stack-1x{height:1em;width:1.25em}.svg-inline--fa.fa-stack-2x{height:2em;width:2.5em}.fa-inverse{color:#fff}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}
|
6
public/assets/css/fontawesome-all.min.css
vendored
6
public/assets/css/fontawesome-all.min.css
vendored
File diff suppressed because one or more lines are too long
6
public/assets/fontawesome-all.min.js
vendored
6
public/assets/fontawesome-all.min.js
vendored
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 586 KiB After Width: | Height: | Size: 644 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 141 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 477 KiB After Width: | Height: | Size: 797 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@ -4,9 +4,13 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
ignore_user_abort(true);
|
||||
|
||||
require __DIR__ . "/../lib/requiredpublic.php";
|
||||
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use PHPMailer\PHPMailer\Exception;
|
||||
|
||||
function output_card($content) {
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
@ -24,7 +28,7 @@ function output_card($content) {
|
||||
<?php
|
||||
}
|
||||
|
||||
if (empty($_POST['name']) || empty($_POST['message']) || !filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
|
||||
if (empty($_POST['name']) || empty($_POST['message']) || !filter_var($_POST['real_email'], FILTER_VALIDATE_EMAIL) || !empty($_POST['email'])) {
|
||||
$content = <<<END
|
||||
<p>Whoops! You didn't fill out the contact form properly.</p>
|
||||
<p><a href="javascript:history.back()" class="btn btn-primary btn-sm">Go back</a> and try again.</p>
|
||||
@ -33,10 +37,12 @@ END;
|
||||
die();
|
||||
}
|
||||
|
||||
$siteid = getsiteid();
|
||||
|
||||
$database->insert("messages", [
|
||||
"siteid" => getsiteid(),
|
||||
"siteid" => $siteid,
|
||||
"name" => htmlspecialchars($_POST['name']),
|
||||
"email" => htmlspecialchars($_POST['email']),
|
||||
"email" => htmlspecialchars($_POST['real_email']),
|
||||
"message" => htmlspecialchars($_POST['message']),
|
||||
"date" => date("Y-m-d H:i:s")
|
||||
]);
|
||||
@ -47,4 +53,36 @@ $content = <<<END
|
||||
<a href="./" class="btn btn-success">Continue</a>
|
||||
END;
|
||||
|
||||
output_card($content);
|
||||
output_card($content);
|
||||
ob_flush();
|
||||
flush();
|
||||
|
||||
|
||||
if ($database->has('settings', ["AND" => ['siteid' => $siteid, 'key' => 'contactemail']])) {
|
||||
$emailto = $database->get('settings', "value", ["AND" => ['siteid' => $siteid, 'key' => 'contactemail']]);
|
||||
// Setup mailer
|
||||
$mail = new PHPMailer(true);
|
||||
$mail->isSMTP();
|
||||
$mail->Host = $SETTINGS["email"]["host"];
|
||||
$mail->SMTPAuth = $SETTINGS["email"]["auth"];
|
||||
if ($SETTINGS["email"]["auth"]) {
|
||||
$mail->Username = $SETTINGS["email"]["user"];
|
||||
$mail->Password = $SETTINGS["email"]["password"];
|
||||
}
|
||||
if ($SETTINGS["email"]["secure"] != "none") {
|
||||
$mail->SMTPSecure = $SETTINGS["email"]["secure"];
|
||||
}
|
||||
$mail->Port = $SETTINGS["email"]["port"];
|
||||
$mail->isHTML(true);
|
||||
$mail->setFrom($SETTINGS["email"]["fromaddress"], $SETTINGS["email"]["fromname"]);
|
||||
|
||||
$mail->addAddress($emailto);
|
||||
$mail->addReplyTo($_POST['email'], $_POST['name']);
|
||||
|
||||
$mail->Subject = 'Website Contact Form Message';
|
||||
$mail->Body = '<p><b>From:</b> ' . htmlspecialchars($_POST['name']) . ' <<a href="mailto:' . htmlspecialchars($_POST['email']) . '">' . $_POST['email'] . '</a>></p>'
|
||||
. '<p><b>Message:</b> <br>' . htmlspecialchars($_POST['message']) . '</p>';
|
||||
$mail->AltBody = "From: $_POST[name] <$_POST[email]>\r\n\r\nMessage: \r\n$_POST[message]";
|
||||
|
||||
$mail->send();
|
||||
}
|
@ -8,11 +8,11 @@
|
||||
|
||||
require_once __DIR__ . "/../lib/requiredpublic.php";
|
||||
|
||||
$base = FILE_UPLOAD_PATH;
|
||||
$base = $SETTINGS["file_upload_path"];
|
||||
|
||||
$filepath = "";
|
||||
|
||||
if ($_GET['file'] === URL . "/static/img/no-image.svg") {
|
||||
if ($_GET['file'] === $SETTINGS["url"] . "/static/img/no-image.svg") {
|
||||
header("Content-Type: image/svg+xml");
|
||||
ob_end_flush();
|
||||
|
||||
@ -26,7 +26,7 @@ if (isset($_GET['file'])) {
|
||||
http_response_code(404);
|
||||
die("404 File Not Found");
|
||||
}
|
||||
if (strpos(realpath($filepath), FILE_UPLOAD_PATH) !== 0) {
|
||||
if (strpos(realpath($filepath), $SETTINGS["file_upload_path"]) !== 0) {
|
||||
http_response_code(404);
|
||||
die("404 File Not Found");
|
||||
}
|
||||
@ -56,6 +56,7 @@ $ts = gmdate("D, d M Y H:i:s", time() + $seconds_to_cache) . " GMT";
|
||||
header("Expires: $ts");
|
||||
header("Pragma: cache");
|
||||
header("Cache-Control: max-age=$seconds_to_cache");
|
||||
header("Content-Disposition: filename=\"" . pathinfo($filepath)['basename'] . "\"");
|
||||
|
||||
ob_end_flush();
|
||||
|
||||
|
@ -23,8 +23,8 @@ if (!getsiteid()) {
|
||||
<h2 class="card-title">Welcome!</h2>
|
||||
<p>You're seeing this message because no website has been created yet.
|
||||
<br />
|
||||
Open <?php echo SITE_TITLE; ?> to make one.</p>
|
||||
<p><a href="<?php echo PORTAL_URL; ?>" class="btn btn-primary">Log In</a></p>
|
||||
Open <?php echo $SETTINGS["site_title"]; ?> to make one.</p>
|
||||
<p><a href="<?php echo $SETTINGS["accounthub"]["home"]; ?>" class="btn btn-primary">Log In</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -57,15 +57,15 @@ if (isset($_GET['edit'])) {
|
||||
}
|
||||
?>
|
||||
<style><?php echo file_get_contents(__DIR__ . "/../static/css/editor.css"); ?></style>
|
||||
<script src="<?php echo URL; ?>/static/js/jquery-3.3.1.min.js"></script>
|
||||
<script src="<?php echo URL; ?>/static/js/tinymce/tinymce.min.js"></script>
|
||||
<script src="<?php echo $SETTINGS["url"]; ?>/static/js/jquery-3.3.1.min.js"></script>
|
||||
<script src="<?php echo $SETTINGS["url"]; ?>/static/js/tinymce/tinymce.min.js"></script>
|
||||
<script>
|
||||
static_dir = "<?php echo URL; ?>/static";
|
||||
static_dir = "<?php echo $SETTINGS["url"]; ?>/static";
|
||||
page_slug = "<?php echo getpageslug(); ?>";
|
||||
site_id = "<?php echo getsiteid(); ?>";
|
||||
pages_list = <?php echo json_encode($allpages); ?>;
|
||||
</script>
|
||||
<script src="<?php echo URL; ?>/static/js/editor.js"></script>
|
||||
<script src="<?php echo $SETTINGS["url"]; ?>/static/js/editor.js"></script>
|
||||
<?php
|
||||
}
|
||||
?>
|
@ -17,6 +17,10 @@ include __DIR__ . "/inc/header.inc.php";
|
||||
</div>
|
||||
<div class="container">
|
||||
<form action="<?php get_site_url(); ?>contact.php" method="POST">
|
||||
<span style="display: none;">
|
||||
Leave this box empty
|
||||
<input name="email" id="email" placeholder="Email" type="email" style="display: none;" autocomplete="off" />
|
||||
</span>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<label for="name">Name</label>
|
||||
@ -24,7 +28,7 @@ include __DIR__ . "/inc/header.inc.php";
|
||||
</div>
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<label for="email">Email</label>
|
||||
<input type="email" class="form-control" name="email" id="email" placeholder="you@example.com" required />
|
||||
<input type="email" class="form-control" name="real_email" id="email" placeholder="you@example.com" required />
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label for="message">Message</label>
|
||||
|
@ -10,13 +10,17 @@
|
||||
<h2 class="major"><?php get_page_clean_title(); ?></h2>
|
||||
<p class="sw-text" data-component="lead"><?php get_component("lead"); ?></p>
|
||||
<form method="post" action="contact.php">
|
||||
<span style="display: none;">
|
||||
Leave this box empty
|
||||
<input name="email" id="email" placeholder="Email" type="email" style="display: none;" autocomplete="off" />
|
||||
</span>
|
||||
<div class="field half first">
|
||||
<label for="name">Name</label>
|
||||
<input type="text" name="name" id="name" required />
|
||||
</div>
|
||||
<div class="field half">
|
||||
<label for="email">Email</label>
|
||||
<input type="text" name="email" id="email" required />
|
||||
<input type="text" name="real_email" id="email" required />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="message">Message</label>
|
||||
@ -46,7 +50,7 @@
|
||||
</div>
|
||||
|
||||
<?php include __DIR__ . "/inc/bg-edit.inc.php"; ?>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<?php include __DIR__ . "/inc/footer.inc.php"; ?>
|
@ -163,13 +163,17 @@ include __DIR__ . "/inc/head.inc.php";
|
||||
<div class="split style1">
|
||||
<section>
|
||||
<form method="post" action="contact.php">
|
||||
<span style="display: none;">
|
||||
Leave this box empty
|
||||
<input name="email" id="email" placeholder="Email" type="email" style="display: none;" autocomplete="off" />
|
||||
</span>
|
||||
<div class="field half first">
|
||||
<label for="name">Name</label>
|
||||
<input type="text" name="name" id="name" required />
|
||||
</div>
|
||||
<div class="field half">
|
||||
<label for="email">Email</label>
|
||||
<input type="email" name="email" id="email" required />
|
||||
<input type="email" name="real_email" id="email" required />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="message">Message</label>
|
||||
|
@ -6,11 +6,15 @@ include __DIR__ . "/inc/header.inc.php";
|
||||
<?php get_component("contact-header"); ?>
|
||||
</div></h2>
|
||||
<form method="post" action="contact.php">
|
||||
<span style="display: none;">
|
||||
Leave this box empty
|
||||
<input name="email" id="email" placeholder="Email" type="email" style="display: none;" autocomplete="off" />
|
||||
</span>
|
||||
<div class="field">
|
||||
<input type="text" name="name" id="name" placeholder="Name" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<input type="email" name="email" id="email" placeholder="Email" />
|
||||
<input type="email" name="real_email" id="email" placeholder="Email" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<textarea name="message" id="message" placeholder="Message" rows="4"></textarea>
|
||||
|
@ -74,7 +74,7 @@
|
||||
<a href="<?php get_url_or_slug($article['link']); ?>" class="image fit"><img src="<?php get_file_url($article['image']); ?>" alt="" /></a>
|
||||
<span class="sw-complex" data-json="<?php get_escaped_json($article); ?>" data-component="<?php echo "article-$i"; ?>"></span>
|
||||
<div class="sw-editable" data-component="article-text-<?php echo $i; ?>">
|
||||
<p><?php get_component("article-text-$i"); ?></p>
|
||||
<?php get_component("article-text-$i"); ?>
|
||||
</div>
|
||||
<?php
|
||||
if (!empty($article['text'])) {
|
||||
|
@ -2,13 +2,17 @@
|
||||
<footer id="footer">
|
||||
<section>
|
||||
<form method="post" action="contact.php">
|
||||
<span style="display: none;">
|
||||
Leave this box empty
|
||||
<input name="email" id="email" placeholder="Email" type="email" style="display: none;" autocomplete="off" />
|
||||
</span>
|
||||
<div class="field">
|
||||
<label for="name">Name</label>
|
||||
<input type="text" name="name" id="name" required />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="email">Email</label>
|
||||
<input type="text" name="email" id="email" required />
|
||||
<input type="text" name="real_email" id="email" required />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="message">Message</label>
|
||||
|
@ -4,11 +4,15 @@
|
||||
<section>
|
||||
<h2>Get in touch</h2>
|
||||
<form method="post" action="contact.php">
|
||||
<span style="display: none;">
|
||||
Leave this box empty
|
||||
<input name="email" id="email" placeholder="Email" type="email" style="display: none;" autocomplete="off" />
|
||||
</span>
|
||||
<div class="field half first">
|
||||
<input type="text" name="name" id="name" placeholder="Name" required />
|
||||
</div>
|
||||
<div class="field half">
|
||||
<input type="email" name="email" id="email" placeholder="Email" required />
|
||||
<input type="email" name="real_email" id="email" placeholder="Email" required />
|
||||
</div>
|
||||
<div class="field">
|
||||
<textarea name="message" id="message" placeholder="Message" required ></textarea>
|
||||
|
@ -19,6 +19,10 @@
|
||||
</h3>
|
||||
|
||||
<form action="<?php get_site_url(); ?>contact.php" method="POST">
|
||||
<span style="display: none;">
|
||||
Leave this box empty
|
||||
<input name="email" id="email" placeholder="Email" type="email" style="display: none;" autocomplete="off" />
|
||||
</span>
|
||||
<div class="row">
|
||||
<div class="6u 12u(medium)">
|
||||
<label for="name">Name</label>
|
||||
@ -26,7 +30,7 @@
|
||||
</div>
|
||||
<div class="6u 12u(medium)">
|
||||
<label for="email">Email</label>
|
||||
<input type="email" name="email" id="email" placeholder="you@example.com" required />
|
||||
<input type="email" name="real_email" id="email" placeholder="you@example.com" required />
|
||||
</div>
|
||||
<div class="12u">
|
||||
<label for="message">Message</label>
|
||||
|
143
required.php
143
required.php
@ -32,7 +32,6 @@ session_start(); // stick some cookies in it
|
||||
// renew session cookie
|
||||
setcookie(session_name(), session_id(), time() + $session_length, "/", false, false);
|
||||
|
||||
$captcha_server = (CAPTCHA_ENABLED === true ? preg_replace("/http(s)?:\/\//", "", CAPTCHA_SERVER) : "");
|
||||
if ($_SESSION['mobile'] === TRUE) {
|
||||
header("Content-Security-Policy: "
|
||||
. "default-src 'self';"
|
||||
@ -42,8 +41,8 @@ if ($_SESSION['mobile'] === TRUE) {
|
||||
. "frame-src 'self'; "
|
||||
. "font-src 'self'; "
|
||||
. "connect-src *; "
|
||||
. "style-src 'self' 'unsafe-inline' $captcha_server; "
|
||||
. "script-src 'self' 'unsafe-inline' $captcha_server");
|
||||
. "style-src 'self' 'unsafe-inline'; "
|
||||
. "script-src 'self' 'unsafe-inline'");
|
||||
} else {
|
||||
header("Content-Security-Policy: "
|
||||
. "default-src 'self';"
|
||||
@ -53,8 +52,8 @@ if ($_SESSION['mobile'] === TRUE) {
|
||||
. "frame-src 'self'; "
|
||||
. "font-src 'self'; "
|
||||
. "connect-src *; "
|
||||
. "style-src 'self' 'unsafe-inline' $captcha_server; "
|
||||
. "script-src 'self' 'nonce-$SECURE_NONCE' $captcha_server");
|
||||
. "style-src 'self' 'nonce-$SECURE_NONCE'; "
|
||||
. "script-src 'self' 'nonce-$SECURE_NONCE'");
|
||||
}
|
||||
|
||||
//
|
||||
@ -62,9 +61,14 @@ if ($_SESSION['mobile'] === TRUE) {
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
// List of alert messages
|
||||
require __DIR__ . '/lang/messages.php';
|
||||
// text strings (i18n)
|
||||
require __DIR__ . '/lang/' . LANGUAGE . ".php";
|
||||
require __DIR__ . '/langs/messages.php';
|
||||
|
||||
$libs = glob(__DIR__ . "/lib/*.lib.php");
|
||||
foreach ($libs as $lib) {
|
||||
require_once $lib;
|
||||
}
|
||||
|
||||
$Strings = new Strings($SETTINGS['language']);
|
||||
|
||||
/**
|
||||
* Kill off the running process and spit out an error message
|
||||
@ -88,7 +92,7 @@ function sendError($error) {
|
||||
. "<p>" . htmlspecialchars($error) . "</p>");
|
||||
}
|
||||
|
||||
date_default_timezone_set(TIMEZONE);
|
||||
date_default_timezone_set($SETTINGS['timezone']);
|
||||
|
||||
// Database settings
|
||||
// Also inits database and stuff
|
||||
@ -97,12 +101,12 @@ use Medoo\Medoo;
|
||||
$database;
|
||||
try {
|
||||
$database = new Medoo([
|
||||
'database_type' => DB_TYPE,
|
||||
'database_name' => DB_NAME,
|
||||
'server' => DB_SERVER,
|
||||
'username' => DB_USER,
|
||||
'password' => DB_PASS,
|
||||
'charset' => DB_CHARSET
|
||||
'database_type' => $SETTINGS['database']['type'],
|
||||
'database_name' => $SETTINGS['database']['name'],
|
||||
'server' => $SETTINGS['database']['server'],
|
||||
'username' => $SETTINGS['database']['user'],
|
||||
'password' => $SETTINGS['database']['password'],
|
||||
'charset' => $SETTINGS['database']['charset']
|
||||
]);
|
||||
} catch (Exception $ex) {
|
||||
//header('HTTP/1.1 500 Internal Server Error');
|
||||
@ -110,7 +114,7 @@ try {
|
||||
}
|
||||
|
||||
|
||||
if (!DEBUG) {
|
||||
if (!$SETTINGS['debug']) {
|
||||
error_reporting(0);
|
||||
} else {
|
||||
error_reporting(E_ALL);
|
||||
@ -127,66 +131,18 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
define("GET", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a string or whatever is empty.
|
||||
* @param $str The thingy to check
|
||||
* @return boolean True if it's empty or whatever.
|
||||
*/
|
||||
function is_empty($str) {
|
||||
return (is_null($str) || !isset($str) || $str == '');
|
||||
}
|
||||
|
||||
/**
|
||||
* I18N string getter. If the key doesn't exist, outputs the key itself.
|
||||
* @param string $key I18N string key
|
||||
* @param boolean $echo whether to echo the result or return it (default echo)
|
||||
*/
|
||||
function lang($key, $echo = true) {
|
||||
if (array_key_exists($key, STRINGS)) {
|
||||
$str = STRINGS[$key];
|
||||
} else {
|
||||
trigger_error("Language key \"$key\" does not exist in " . LANGUAGE, E_USER_WARNING);
|
||||
$str = $key;
|
||||
}
|
||||
|
||||
if ($echo) {
|
||||
echo $str;
|
||||
} else {
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* I18N string getter (with builder). If the key doesn't exist, outputs the key itself.
|
||||
* @param string $key I18N string key
|
||||
* @param array $replace key-value array of replacements.
|
||||
* If the string value is "hello {abc}" and you give ["abc" => "123"], the
|
||||
* result will be "hello 123".
|
||||
* @param boolean $echo whether to echo the result or return it (default echo)
|
||||
*/
|
||||
function lang2($key, $replace, $echo = true) {
|
||||
if (array_key_exists($key, STRINGS)) {
|
||||
$str = STRINGS[$key];
|
||||
} else {
|
||||
trigger_error("Language key \"$key\" does not exist in " . LANGUAGE, E_USER_WARNING);
|
||||
$str = $key;
|
||||
}
|
||||
|
||||
foreach ($replace as $find => $repl) {
|
||||
$str = str_replace("{" . $find . "}", $repl, $str);
|
||||
}
|
||||
|
||||
if ($echo) {
|
||||
echo $str;
|
||||
} else {
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
function dieifnotloggedin() {
|
||||
global $SETTINGS;
|
||||
if ($_SESSION['loggedin'] != true) {
|
||||
sendError("Session expired. Please log out and log in again.");
|
||||
}
|
||||
$user = new User($_SESSION['uid']);
|
||||
foreach ($SETTINGS['permissions'] as $perm) {
|
||||
if (!$user->hasPermission($perm)) {
|
||||
session_destroy();
|
||||
die("You don't have permission to be here.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -206,41 +162,18 @@ function checkDBError($specials = []) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* http://stackoverflow.com/a/20075147
|
||||
*/
|
||||
if (!function_exists('base_url')) {
|
||||
|
||||
function base_url($atRoot = FALSE, $atCore = FALSE, $parse = FALSE) {
|
||||
if (isset($_SERVER['HTTP_HOST'])) {
|
||||
$http = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off' ? 'https' : 'http';
|
||||
$hostname = $_SERVER['HTTP_HOST'];
|
||||
$dir = str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']);
|
||||
|
||||
$core = preg_split('@/@', str_replace($_SERVER['DOCUMENT_ROOT'], '', realpath(dirname(__FILE__))), NULL, PREG_SPLIT_NO_EMPTY);
|
||||
$core = $core[0];
|
||||
|
||||
$tmplt = $atRoot ? ($atCore ? "%s://%s/%s/" : "%s://%s/") : ($atCore ? "%s://%s/%s/" : "%s://%s%s");
|
||||
$end = $atRoot ? ($atCore ? $core : $hostname) : ($atCore ? $core : $dir);
|
||||
$base_url = sprintf($tmplt, $http, $hostname, $end);
|
||||
} else
|
||||
$base_url = 'http://localhost/';
|
||||
|
||||
if ($parse) {
|
||||
$base_url = parse_url($base_url);
|
||||
if (isset($base_url['path']))
|
||||
if ($base_url['path'] == '/')
|
||||
$base_url['path'] = '';
|
||||
}
|
||||
|
||||
return $base_url;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function redirectIfNotLoggedIn() {
|
||||
global $SETTINGS;
|
||||
if ($_SESSION['loggedin'] !== TRUE) {
|
||||
header('Location: ' . URL . '/index.php');
|
||||
header('Location: ' . $SETTINGS['url'] . '/index.php');
|
||||
die();
|
||||
}
|
||||
$user = new User($_SESSION['uid']);
|
||||
foreach ($SETTINGS['permissions'] as $perm) {
|
||||
if (!$user->hasPermission($perm)) {
|
||||
session_destroy();
|
||||
header('Location: ./index.php');
|
||||
die("You don't have permission to be here.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,68 +1,85 @@
|
||||
<?php
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// Whether to show debugging data in output.
|
||||
// DO NOT SET TO TRUE IN PRODUCTION!!!
|
||||
define("DEBUG", false);
|
||||
// Settings for the app.
|
||||
// Copy to settings.php and customize.
|
||||
|
||||
// Database connection settings
|
||||
// See http://medoo.in/api/new for info
|
||||
define("DB_TYPE", "mysql");
|
||||
define("DB_NAME", "sitewriter");
|
||||
define("DB_SERVER", "localhost");
|
||||
define("DB_USER", "sitewriter");
|
||||
define("DB_PASS", "");
|
||||
define("DB_CHARSET", "utf8");
|
||||
|
||||
// Name of the app.
|
||||
define("SITE_TITLE", "SiteWriter");
|
||||
|
||||
|
||||
// URL of the AccountHub API endpoint
|
||||
define("PORTAL_API", "http://localhost/accounthub/api.php");
|
||||
// URL of the AccountHub home page
|
||||
define("PORTAL_URL", "http://localhost/accounthub/home.php");
|
||||
// AccountHub API Key
|
||||
define("PORTAL_KEY", "123");
|
||||
|
||||
// For supported values, see http://php.net/manual/en/timezones.php
|
||||
define("TIMEZONE", "America/Denver");
|
||||
|
||||
// Base URL for site links.
|
||||
define('URL', '/sitewriter');
|
||||
|
||||
// Folder for public files
|
||||
// This should not be inside the web root for security reasons.
|
||||
define('FILE_UPLOAD_PATH', __DIR__ . '/public/files');
|
||||
|
||||
// Use pretty URLs (requires correct web server configuration)
|
||||
define('PRETTY_URLS', false);
|
||||
|
||||
// Location of MaxMind GeoIP database
|
||||
//
|
||||
// I'll just leave this here:
|
||||
// This product includes GeoLite2 data created by MaxMind, available from
|
||||
// http://www.maxmind.com
|
||||
define('GEOIP_DB', __DIR__ . "/GeoLite2-City.mmdb");
|
||||
|
||||
// Unsplash photo integration
|
||||
define('ENABLE_UNSPLASH', false);
|
||||
define('UNSPLASH_APPID', '');
|
||||
define('UNSPLASH_ACCESSKEY', '');
|
||||
define('UNSPLASH_SECRETKEY', '');
|
||||
define('UNSPLASH_UTMSOURCE', 'SiteWriter');
|
||||
|
||||
// Use Captcheck on login screen
|
||||
// https://captcheck.netsyms.com
|
||||
define("CAPTCHA_ENABLED", FALSE);
|
||||
define('CAPTCHA_SERVER', 'https://captcheck.netsyms.com');
|
||||
|
||||
// See lang folder for language options
|
||||
define('LANGUAGE', "en_us");
|
||||
|
||||
|
||||
define("FOOTER_TEXT", "");
|
||||
define("COPYRIGHT_NAME", "Netsyms Technologies");
|
||||
$SETTINGS = [
|
||||
// Whether to output debugging info like PHP notices, warnings,
|
||||
// and stacktraces.
|
||||
// Turning this on in production is a security risk and can sometimes break
|
||||
// things, such as JSON output where extra content is not expected.
|
||||
"debug" => false,
|
||||
// Database connection settings
|
||||
// See http://medoo.in/api/new for info
|
||||
"database" => [
|
||||
"type" => "mysql",
|
||||
"name" => "sitewriter",
|
||||
"server" => "localhost",
|
||||
"user" => "",
|
||||
"password" => "",
|
||||
"charset" => "utf8"
|
||||
],
|
||||
// Name of the app.
|
||||
"site_title" => "SiteWriter",
|
||||
// Settings for connecting to the AccountHub server.
|
||||
"accounthub" => [
|
||||
// URL for the API endpoint
|
||||
"api" => "http://localhost/accounthub/api/",
|
||||
// URL of the home page
|
||||
"home" => "http://localhost/accounthub/home.php",
|
||||
// API key
|
||||
"key" => "123"
|
||||
],
|
||||
// Folder for public files
|
||||
"file_upload_path" => __DIR__ . "/public/files",
|
||||
// Use pretty URLs (requires correct web server configuration)
|
||||
"pretty_urls" => false,
|
||||
// Location of MaxMind GeoIP database
|
||||
//
|
||||
// I'll just leave this here:
|
||||
// This product includes GeoLite2 data created by MaxMind, available from
|
||||
// http://www.maxmind.com
|
||||
"geoip_db" => __DIR__ . "/GeoLite2-City.mmdb",
|
||||
"unsplash" => [
|
||||
"enable" => false,
|
||||
"appid" => "",
|
||||
"accesskey" => "",
|
||||
"secretkey" => "",
|
||||
"utmsource" => "SiteWriter"
|
||||
],
|
||||
"email" => [
|
||||
"host" => "",
|
||||
"auth" => true,
|
||||
"secure" => "tls",
|
||||
"port" => 587,
|
||||
"user" => "",
|
||||
"password" => "",
|
||||
"fromaddress" => "",
|
||||
"fromname" => "SiteWriter"
|
||||
],
|
||||
// List of required user permissions to access this app.
|
||||
"permissions" => [
|
||||
],
|
||||
// List of permissions required for API access. Remove to use the value of
|
||||
// "permissions" instead.
|
||||
"api_permissions" => [
|
||||
],
|
||||
// For supported values, see http://php.net/manual/en/timezones.php
|
||||
"timezone" => "America/Denver",
|
||||
// Language to use for localization. See langs folder to add a language.
|
||||
"language" => "en",
|
||||
// Shown in the footer of all the pages.
|
||||
"footer_text" => "",
|
||||
// Also shown in the footer, but with "Copyright <current_year>" in front.
|
||||
"copyright" => "Netsyms Technologies",
|
||||
// Base URL for building links relative to the location of the app.
|
||||
// Only used when there's no good context for the path.
|
||||
// The default is almost definitely fine.
|
||||
"url" => "."
|
||||
];
|
||||
|
12
static/css/bootstrap.min.css
vendored
12
static/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
@ -1,345 +0,0 @@
|
||||
/*!
|
||||
* Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
*/
|
||||
svg:not(:root).svg-inline--fa {
|
||||
overflow: visible; }
|
||||
|
||||
.svg-inline--fa {
|
||||
display: inline-block;
|
||||
font-size: inherit;
|
||||
height: 1em;
|
||||
overflow: visible;
|
||||
vertical-align: -.125em; }
|
||||
.svg-inline--fa.fa-lg {
|
||||
vertical-align: -.225em; }
|
||||
.svg-inline--fa.fa-w-1 {
|
||||
width: 0.0625em; }
|
||||
.svg-inline--fa.fa-w-2 {
|
||||
width: 0.125em; }
|
||||
.svg-inline--fa.fa-w-3 {
|
||||
width: 0.1875em; }
|
||||
.svg-inline--fa.fa-w-4 {
|
||||
width: 0.25em; }
|
||||
.svg-inline--fa.fa-w-5 {
|
||||
width: 0.3125em; }
|
||||
.svg-inline--fa.fa-w-6 {
|
||||
width: 0.375em; }
|
||||
.svg-inline--fa.fa-w-7 {
|
||||
width: 0.4375em; }
|
||||
.svg-inline--fa.fa-w-8 {
|
||||
width: 0.5em; }
|
||||
.svg-inline--fa.fa-w-9 {
|
||||
width: 0.5625em; }
|
||||
.svg-inline--fa.fa-w-10 {
|
||||
width: 0.625em; }
|
||||
.svg-inline--fa.fa-w-11 {
|
||||
width: 0.6875em; }
|
||||
.svg-inline--fa.fa-w-12 {
|
||||
width: 0.75em; }
|
||||
.svg-inline--fa.fa-w-13 {
|
||||
width: 0.8125em; }
|
||||
.svg-inline--fa.fa-w-14 {
|
||||
width: 0.875em; }
|
||||
.svg-inline--fa.fa-w-15 {
|
||||
width: 0.9375em; }
|
||||
.svg-inline--fa.fa-w-16 {
|
||||
width: 1em; }
|
||||
.svg-inline--fa.fa-w-17 {
|
||||
width: 1.0625em; }
|
||||
.svg-inline--fa.fa-w-18 {
|
||||
width: 1.125em; }
|
||||
.svg-inline--fa.fa-w-19 {
|
||||
width: 1.1875em; }
|
||||
.svg-inline--fa.fa-w-20 {
|
||||
width: 1.25em; }
|
||||
.svg-inline--fa.fa-pull-left {
|
||||
margin-right: .3em;
|
||||
width: auto; }
|
||||
.svg-inline--fa.fa-pull-right {
|
||||
margin-left: .3em;
|
||||
width: auto; }
|
||||
.svg-inline--fa.fa-border {
|
||||
height: 1.5em; }
|
||||
.svg-inline--fa.fa-li {
|
||||
width: 2em; }
|
||||
.svg-inline--fa.fa-fw {
|
||||
width: 1.25em; }
|
||||
|
||||
.fa-layers svg.svg-inline--fa {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0; }
|
||||
|
||||
.fa-layers {
|
||||
display: inline-block;
|
||||
height: 1em;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
vertical-align: -.125em;
|
||||
width: 1em; }
|
||||
.fa-layers svg.svg-inline--fa {
|
||||
-webkit-transform-origin: center center;
|
||||
transform-origin: center center; }
|
||||
|
||||
.fa-layers-text, .fa-layers-counter {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
text-align: center; }
|
||||
|
||||
.fa-layers-text {
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
-webkit-transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%);
|
||||
-webkit-transform-origin: center center;
|
||||
transform-origin: center center; }
|
||||
|
||||
.fa-layers-counter {
|
||||
background-color: #ff253a;
|
||||
border-radius: 1em;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
color: #fff;
|
||||
height: 1.5em;
|
||||
line-height: 1;
|
||||
max-width: 5em;
|
||||
min-width: 1.5em;
|
||||
overflow: hidden;
|
||||
padding: .25em;
|
||||
right: 0;
|
||||
text-overflow: ellipsis;
|
||||
top: 0;
|
||||
-webkit-transform: scale(0.25);
|
||||
transform: scale(0.25);
|
||||
-webkit-transform-origin: top right;
|
||||
transform-origin: top right; }
|
||||
|
||||
.fa-layers-bottom-right {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
top: auto;
|
||||
-webkit-transform: scale(0.25);
|
||||
transform: scale(0.25);
|
||||
-webkit-transform-origin: bottom right;
|
||||
transform-origin: bottom right; }
|
||||
|
||||
.fa-layers-bottom-left {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: auto;
|
||||
top: auto;
|
||||
-webkit-transform: scale(0.25);
|
||||
transform: scale(0.25);
|
||||
-webkit-transform-origin: bottom left;
|
||||
transform-origin: bottom left; }
|
||||
|
||||
.fa-layers-top-right {
|
||||
right: 0;
|
||||
top: 0;
|
||||
-webkit-transform: scale(0.25);
|
||||
transform: scale(0.25);
|
||||
-webkit-transform-origin: top right;
|
||||
transform-origin: top right; }
|
||||
|
||||
.fa-layers-top-left {
|
||||
left: 0;
|
||||
right: auto;
|
||||
top: 0;
|
||||
-webkit-transform: scale(0.25);
|
||||
transform: scale(0.25);
|
||||
-webkit-transform-origin: top left;
|
||||
transform-origin: top left; }
|
||||
|
||||
.fa-lg {
|
||||
font-size: 1.33333em;
|
||||
line-height: 0.75em;
|
||||
vertical-align: -.0667em; }
|
||||
|
||||
.fa-xs {
|
||||
font-size: .75em; }
|
||||
|
||||
.fa-sm {
|
||||
font-size: .875em; }
|
||||
|
||||
.fa-1x {
|
||||
font-size: 1em; }
|
||||
|
||||
.fa-2x {
|
||||
font-size: 2em; }
|
||||
|
||||
.fa-3x {
|
||||
font-size: 3em; }
|
||||
|
||||
.fa-4x {
|
||||
font-size: 4em; }
|
||||
|
||||
.fa-5x {
|
||||
font-size: 5em; }
|
||||
|
||||
.fa-6x {
|
||||
font-size: 6em; }
|
||||
|
||||
.fa-7x {
|
||||
font-size: 7em; }
|
||||
|
||||
.fa-8x {
|
||||
font-size: 8em; }
|
||||
|
||||
.fa-9x {
|
||||
font-size: 9em; }
|
||||
|
||||
.fa-10x {
|
||||
font-size: 10em; }
|
||||
|
||||
.fa-fw {
|
||||
text-align: center;
|
||||
width: 1.25em; }
|
||||
|
||||
.fa-ul {
|
||||
list-style-type: none;
|
||||
margin-left: 2.5em;
|
||||
padding-left: 0; }
|
||||
.fa-ul > li {
|
||||
position: relative; }
|
||||
|
||||
.fa-li {
|
||||
left: -2em;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 2em;
|
||||
line-height: inherit; }
|
||||
|
||||
.fa-border {
|
||||
border: solid 0.08em #eee;
|
||||
border-radius: .1em;
|
||||
padding: .2em .25em .15em; }
|
||||
|
||||
.fa-pull-left {
|
||||
float: left; }
|
||||
|
||||
.fa-pull-right {
|
||||
float: right; }
|
||||
|
||||
.fa.fa-pull-left,
|
||||
.fas.fa-pull-left,
|
||||
.far.fa-pull-left,
|
||||
.fal.fa-pull-left,
|
||||
.fab.fa-pull-left {
|
||||
margin-right: .3em; }
|
||||
|
||||
.fa.fa-pull-right,
|
||||
.fas.fa-pull-right,
|
||||
.far.fa-pull-right,
|
||||
.fal.fa-pull-right,
|
||||
.fab.fa-pull-right {
|
||||
margin-left: .3em; }
|
||||
|
||||
.fa-spin {
|
||||
-webkit-animation: fa-spin 2s infinite linear;
|
||||
animation: fa-spin 2s infinite linear; }
|
||||
|
||||
.fa-pulse {
|
||||
-webkit-animation: fa-spin 1s infinite steps(8);
|
||||
animation: fa-spin 1s infinite steps(8); }
|
||||
|
||||
@-webkit-keyframes fa-spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg); }
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg); } }
|
||||
|
||||
@keyframes fa-spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg); }
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg); } }
|
||||
|
||||
.fa-rotate-90 {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";
|
||||
-webkit-transform: rotate(90deg);
|
||||
transform: rotate(90deg); }
|
||||
|
||||
.fa-rotate-180 {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";
|
||||
-webkit-transform: rotate(180deg);
|
||||
transform: rotate(180deg); }
|
||||
|
||||
.fa-rotate-270 {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";
|
||||
-webkit-transform: rotate(270deg);
|
||||
transform: rotate(270deg); }
|
||||
|
||||
.fa-flip-horizontal {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";
|
||||
-webkit-transform: scale(-1, 1);
|
||||
transform: scale(-1, 1); }
|
||||
|
||||
.fa-flip-vertical {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
|
||||
-webkit-transform: scale(1, -1);
|
||||
transform: scale(1, -1); }
|
||||
|
||||
.fa-flip-horizontal.fa-flip-vertical {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
|
||||
-webkit-transform: scale(-1, -1);
|
||||
transform: scale(-1, -1); }
|
||||
|
||||
:root .fa-rotate-90,
|
||||
:root .fa-rotate-180,
|
||||
:root .fa-rotate-270,
|
||||
:root .fa-flip-horizontal,
|
||||
:root .fa-flip-vertical {
|
||||
-webkit-filter: none;
|
||||
filter: none; }
|
||||
|
||||
.fa-stack {
|
||||
display: inline-block;
|
||||
height: 2em;
|
||||
position: relative;
|
||||
width: 2em; }
|
||||
|
||||
.fa-stack-1x,
|
||||
.fa-stack-2x {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0; }
|
||||
|
||||
.svg-inline--fa.fa-stack-1x {
|
||||
height: 1em;
|
||||
width: 1em; }
|
||||
|
||||
.svg-inline--fa.fa-stack-2x {
|
||||
height: 2em;
|
||||
width: 2em; }
|
||||
|
||||
.fa-inverse {
|
||||
color: #fff; }
|
||||
|
||||
.sr-only {
|
||||
border: 0;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 1px; }
|
||||
|
||||
.sr-only-focusable:active, .sr-only-focusable:focus {
|
||||
clip: auto;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
overflow: visible;
|
||||
position: static;
|
||||
width: auto; }
|
@ -1,15 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
.banner-image {
|
||||
max-height: 100px;
|
||||
margin: 2em auto;
|
||||
border: 1px solid grey;
|
||||
border-radius: 15%;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 10em;
|
||||
text-align: center;
|
||||
}
|
1
static/css/svg-with-js.min.css
vendored
Normal file
1
static/css/svg-with-js.min.css
vendored
Normal file
@ -0,0 +1 @@
|
||||
.svg-inline--fa,svg:not(:root).svg-inline--fa{overflow:visible}.svg-inline--fa{display:inline-block;font-size:inherit;height:1em;vertical-align:-.125em}.svg-inline--fa.fa-lg{vertical-align:-.225em}.svg-inline--fa.fa-w-1{width:.0625em}.svg-inline--fa.fa-w-2{width:.125em}.svg-inline--fa.fa-w-3{width:.1875em}.svg-inline--fa.fa-w-4{width:.25em}.svg-inline--fa.fa-w-5{width:.3125em}.svg-inline--fa.fa-w-6{width:.375em}.svg-inline--fa.fa-w-7{width:.4375em}.svg-inline--fa.fa-w-8{width:.5em}.svg-inline--fa.fa-w-9{width:.5625em}.svg-inline--fa.fa-w-10{width:.625em}.svg-inline--fa.fa-w-11{width:.6875em}.svg-inline--fa.fa-w-12{width:.75em}.svg-inline--fa.fa-w-13{width:.8125em}.svg-inline--fa.fa-w-14{width:.875em}.svg-inline--fa.fa-w-15{width:.9375em}.svg-inline--fa.fa-w-16{width:1em}.svg-inline--fa.fa-w-17{width:1.0625em}.svg-inline--fa.fa-w-18{width:1.125em}.svg-inline--fa.fa-w-19{width:1.1875em}.svg-inline--fa.fa-w-20{width:1.25em}.svg-inline--fa.fa-pull-left{margin-right:.3em;width:auto}.svg-inline--fa.fa-pull-right{margin-left:.3em;width:auto}.svg-inline--fa.fa-border{height:1.5em}.svg-inline--fa.fa-li{width:2em}.svg-inline--fa.fa-fw{width:1.25em}.fa-layers svg.svg-inline--fa{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.fa-layers{display:inline-block;height:1em;position:relative;text-align:center;vertical-align:-.125em;width:1em}.fa-layers svg.svg-inline--fa{transform-origin:center center}.fa-layers-counter,.fa-layers-text{display:inline-block;position:absolute;text-align:center}.fa-layers-text{left:50%;top:50%;transform:translate(-50%,-50%);transform-origin:center center}.fa-layers-counter{background-color:#ff253a;border-radius:1em;box-sizing:border-box;color:#fff;height:1.5em;line-height:1;max-width:5em;min-width:1.5em;overflow:hidden;padding:.25em;right:0;text-overflow:ellipsis;top:0;transform:scale(.25);transform-origin:top right}.fa-layers-bottom-right{bottom:0;right:0;top:auto;transform:scale(.25);transform-origin:bottom right}.fa-layers-bottom-left{bottom:0;left:0;right:auto;top:auto;transform:scale(.25);transform-origin:bottom left}.fa-layers-top-right{right:0;top:0;transform:scale(.25);transform-origin:top right}.fa-layers-top-left{left:0;right:auto;top:0;transform:scale(.25);transform-origin:top left}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{animation:fa-spin 2s infinite linear}.fa-pulse{animation:fa-spin 1s infinite steps(8)}@keyframes fa-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{display:inline-block;height:2em;position:relative;width:2.5em}.fa-stack-1x,.fa-stack-2x{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.svg-inline--fa.fa-stack-1x{height:1em;width:1.25em}.svg-inline--fa.fa-stack-2x{height:2em;width:2.5em}.fa-inverse{color:#fff}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}
|
@ -3,10 +3,64 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
$(document).ready(function () {
|
||||
/* Fade out alerts */
|
||||
$(".alert .close").click(function (e) {
|
||||
$(this).parent().fadeOut("slow");
|
||||
});
|
||||
|
||||
if ($("#msg-alert-box").length) {
|
||||
$("#msg-alert-box .progress").css("height", "3px");
|
||||
$("#msg-alert-box .progress").css("border-radius", "0px 0px .25rem .25rem");
|
||||
$("#msg-alert-box .progress-bar").css("transition", "width 0.25s linear");
|
||||
var msginteractiontick = 0;
|
||||
var fifty = 10;
|
||||
var gone = 20;
|
||||
|
||||
var msgticker = setInterval(function () {
|
||||
if ($("#msg-alert-box .alert:hover").length) {
|
||||
msginteractiontick = 0;
|
||||
} else {
|
||||
msginteractiontick++;
|
||||
}
|
||||
if (msginteractiontick > 0) {
|
||||
function setBarWidth(offset) {
|
||||
$("#msg-alert-timeout-bar").css("width", (msginteractiontick + offset) / gone * 100 + "%");
|
||||
}
|
||||
setBarWidth(-1 + .25);
|
||||
setTimeout(function () {
|
||||
setBarWidth(-1 + .5);
|
||||
}, 250);
|
||||
setTimeout(function () {
|
||||
setBarWidth(-1 + .75);
|
||||
}, 500);
|
||||
setTimeout(function () {
|
||||
setBarWidth(0);
|
||||
}, 750);
|
||||
} else {
|
||||
$("#msg-alert-timeout-bar").css("width", "0%");
|
||||
}
|
||||
|
||||
if (msginteractiontick < fifty) {
|
||||
$("#msg-alert-box").css("opacity", "1");
|
||||
}
|
||||
if (msginteractiontick == fifty) {
|
||||
$("#msg-alert-box").fadeTo(1000, 0.5);
|
||||
}
|
||||
if (msginteractiontick >= gone) {
|
||||
setTimeout(function () {
|
||||
if (msginteractiontick >= gone) {
|
||||
$("#msg-alert-box").fadeOut("slow");
|
||||
window.clearInterval(msgticker);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
}, 1000 * 1);
|
||||
|
||||
$("#msg-alert-box").on("mouseenter", function () {
|
||||
$("#msg-alert-box").css("opacity", "1");
|
||||
msginteractiontick = 0;
|
||||
});
|
||||
$("#msg-alert-box").on("click", ".close", function (e) {
|
||||
$("#msg-alert-box").fadeOut("slow");
|
||||
window.clearInterval(msgticker);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
7
static/js/bootstrap.bundle.min.js
vendored
Normal file
7
static/js/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
static/js/bootstrap.min.js
vendored
7
static/js/bootstrap.min.js
vendored
File diff suppressed because one or more lines are too long
@ -74,9 +74,10 @@ $(document).ready(function () {
|
||||
});
|
||||
|
||||
$(".sw-text").each(function () {
|
||||
var text = $(this).text().trim();
|
||||
var text = $(this).text().trim().replace(/"/g, """);
|
||||
var component = $(this).data("component");
|
||||
$(this).html("<input type=\"text\" data-component=\"" + component + "\" class=\"sw-text-input\" value=\"" + text + "\" placeholder=\"Click to edit\">");
|
||||
$(this).closest("a").removeAttr("href"); // Issue #33
|
||||
});
|
||||
|
||||
$(".sw-complex").each(function () {
|
||||
|
6
static/js/fontawesome-all.min.js
vendored
6
static/js/fontawesome-all.min.js
vendored
File diff suppressed because one or more lines are too long
16
static/js/form.js
Normal file
16
static/js/form.js
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
|
||||
$("#savebtn").click(function (event) {
|
||||
var form = $("#sampleform");
|
||||
|
||||
if (form[0].checkValidity() === false) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
form.addClass("was-validated");
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user