Merge ../BusinessAppTemplate

# Conflicts:
#	README.md
#	action.php
#	api/functions.php
#	lib/User.lib.php
#	mobile/index.php
#	pages/form.php
#	settings.template.php
#	static/js/form.js
master
Skylar Ittner 5 years ago
commit 59136bd8eb

@ -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 Licensed under the Mozilla Public License Version 2.0. Files without MPL header
assets with your own. comments, including third party code, may be under a different license.
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:
Mozilla Public License Version 2.0 Mozilla Public License Version 2.0
================================== ==================================

@ -23,11 +23,11 @@ dieifnotloggedin();
function returnToSender($msg, $arg = "") { function returnToSender($msg, $arg = "") {
global $VARS; global $VARS;
if ($arg == "") { $header = "Location: app.php?page=" . urlencode($VARS['source']) . "&msg=$msg";
header("Location: app.php?page=" . urlencode($VARS['source']) . "&msg=$msg"); if ($arg != "") {
} else { $header .= "&arg=$arg";
header("Location: app.php?page=" . urlencode($VARS['source']) . "&msg=$msg&arg=" . urlencode($arg));
} }
header($header);
die(); die();
} }

@ -64,8 +64,9 @@ function authenticate(): bool {
Log::insert(LogType::API_BAD_KEY, null, "Key: " . $key); Log::insert(LogType::API_BAD_KEY, null, "Key: " . $key);
return false; return false;
} }
return true;
} }
return true; return false;
} }
function checkVars($vars, $or = false) { function checkVars($vars, $or = false) {
@ -160,4 +161,4 @@ function checkkeytype(string $type): bool {
} }
} }
return true; return true;
} }

@ -10,6 +10,8 @@ require __DIR__ . '/../required.php';
require __DIR__ . '/functions.php'; require __DIR__ . '/functions.php';
require __DIR__ . '/apisettings.php'; require __DIR__ . '/apisettings.php';
header("Access-Control-Allow-Origin: *");
$VARS = $_GET; $VARS = $_GET;
if ($_SERVER['REQUEST_METHOD'] != "GET") { if ($_SERVER['REQUEST_METHOD'] != "GET") {
$VARS = array_merge($VARS, $_POST); $VARS = array_merge($VARS, $_POST);

@ -116,6 +116,41 @@ class FormBuilder {
$this->items[] = $item; $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. * Add a button to the form.
* *
@ -178,7 +213,10 @@ HTMLTOP;
} }
$itemhtml = ""; $itemhtml = "";
$itemlabel = ""; $itemlabel = "";
if ($item['type'] != "checkbox") {
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>"; $itemlabel = "<label class=\"mb-0\">$item[label]:</label>";
} }
$strippedlabel = strip_tags($item['label']); $strippedlabel = strip_tags($item['label']);
@ -186,13 +224,16 @@ HTMLTOP;
\n\n <div class="col-12 col-md-$item[width]"> \n\n <div class="col-12 col-md-$item[width]">
<div class="form-group mb-3"> <div class="form-group mb-3">
$itemlabel $itemlabel
<div class="input-group"> ITEMTOP;
$inputgrouptop = <<<INPUTG
\n <div class="input-group">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="$item[icon]"></i></span> <span class="input-group-text"><i class="$item[icon]"></i></span>
</div> </div>
ITEMTOP; INPUTG;
switch ($item['type']) { switch ($item['type']) {
case "select": case "select":
$itemhtml .= $inputgrouptop;
$itemhtml .= <<<SELECT $itemhtml .= <<<SELECT
\n <select class="form-control" name="$item[name]" aria-label="$strippedlabel" $required> \n <select class="form-control" name="$item[name]" aria-label="$strippedlabel" $required>
SELECT; SELECT;
@ -206,6 +247,7 @@ SELECT;
$itemhtml .= "\n </select>"; $itemhtml .= "\n </select>";
break; break;
case "checkbox": case "checkbox":
$itemhtml .= $inputgrouptop;
$itemhtml .= <<<CHECKBOX $itemhtml .= <<<CHECKBOX
\n <div class="form-group form-check"> \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"> <input type="checkbox" name="$item[name]" $id class="form-check-input" value="$item[value]" $required aria-label="$strippedlabel">
@ -213,7 +255,14 @@ SELECT;
</div> </div>
CHECKBOX; CHECKBOX;
break; 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: default:
$itemhtml .= $inputgrouptop;
$itemhtml .= <<<INPUT $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 /> \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; INPUT;
@ -227,9 +276,11 @@ INPUT;
</div> </div>
ERROR; ERROR;
} }
if ($item["type"] != "textarea") {
$itemhtml .= "\n </div>";
}
$itemhtml .= <<<ITEMBOTTOM $itemhtml .= <<<ITEMBOTTOM
\n </div> \n </div>
</div>
</div>\n </div>\n
ITEMBOTTOM; ITEMBOTTOM;
$html .= $itemhtml; $html .= $itemhtml;
@ -242,7 +293,7 @@ ITEMBOTTOM;
HTMLBOTTOM; HTMLBOTTOM;
if (!empty($this->buttons)) { if (!empty($this->buttons)) {
$html .= "\n <div class=\"card-footer\">"; $html .= "\n <div class=\"card-footer d-flex\">";
foreach ($this->buttons as $btn) { foreach ($this->buttons as $btn) {
$btnhtml = ""; $btnhtml = "";
$inner = "<i class=\"$btn[icon]\"></i> $btn[text]"; $inner = "<i class=\"$btn[icon]\"></i> $btn[text]";

@ -103,6 +103,7 @@ class User {
/** /**
* Check the given plaintext password against the stored hash. * Check the given plaintext password against the stored hash.
* @param string $password * @param string $password
* @param bool $apppass Set to true to enforce app passwords when 2fa is on.
* @return bool * @return bool
*/ */
function checkPassword(string $password): bool { function checkPassword(string $password): bool {
@ -162,6 +163,7 @@ class User {
return true; return true;
} }
function check2fa(string $code): bool { function check2fa(string $code): bool {
if (!$this->has2fa) { if (!$this->has2fa) {
return true; return true;

@ -132,7 +132,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
define("GET", true); define("GET", true);
} }
function dieifnotloggedin() { function dieifnotloggedin() {
if ($_SESSION['loggedin'] != true) { if ($_SESSION['loggedin'] != true) {
sendError("Session expired. Please log out and log in again."); sendError("Session expired. Please log out and log in again.");
@ -157,6 +156,7 @@ function checkDBError($specials = []) {
} }
function redirectIfNotLoggedIn() { function redirectIfNotLoggedIn() {
global $SETTINGS;
if ($_SESSION['loggedin'] !== TRUE) { if ($_SESSION['loggedin'] !== TRUE) {
header('Location: ' . $SETTINGS['url'] . '/index.php'); header('Location: ' . $SETTINGS['url'] . '/index.php');
die(); die();

File diff suppressed because one or more lines are too long

@ -1,5 +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}
* Font Awesome Free 5.6.0 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
*/
.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-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}: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}

@ -13,7 +13,7 @@ $(document).ready(function () {
var gone = 20; var gone = 20;
var msgticker = setInterval(function () { var msgticker = setInterval(function () {
if ($('#msg-alert-box .alert:hover').length) { if ($("#msg-alert-box .alert:hover").length) {
msginteractiontick = 0; msginteractiontick = 0;
} else { } else {
msginteractiontick++; msginteractiontick++;
@ -55,7 +55,6 @@ $(document).ready(function () {
$("#msg-alert-box").on("mouseenter", function () { $("#msg-alert-box").on("mouseenter", function () {
$("#msg-alert-box").css("opacity", "1"); $("#msg-alert-box").css("opacity", "1");
msginteractiontick = 0; msginteractiontick = 0;
console.log("👈😎👈 zoop");
}); });
$("#msg-alert-box").on("click", ".close", function (e) { $("#msg-alert-box").on("click", ".close", function (e) {
$("#msg-alert-box").fadeOut("slow"); $("#msg-alert-box").fadeOut("slow");

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save