Browse Source

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
Skylar Ittner 1 month ago
parent
commit
59136bd8eb

+ 3
- 15
LICENSE.md View File

@@ -1,19 +1,7 @@
1
-Copyright (c) 2018 Netsyms Technologies.
1
+Copyright (c) 2017-2019 Netsyms Technologies.  Some rights reserved.
2 2
 
3
-If you modify and redistribute this project, you must replace the branding
4
-assets with your own.
5
-
6
-The branding assets include:
7
- * the application icon
8
- * the Netsyms N punchcard logo
9
- * the Netsyms for Business graph logo
10
-
11
-If you are unsure if your usage is allowed, please contact us:
12
-https://netsyms.com/contact
13
-legal@netsyms.com
14
-
15
-All other portions of this application,
16
-unless otherwise noted (in comments, headers, etc), are licensed as follows:
3
+Licensed under the Mozilla Public License Version 2.0.  Files without MPL header
4
+comments, including third party code, may be under a different license.
17 5
 
18 6
 Mozilla Public License Version 2.0
19 7
 ==================================

+ 4
- 4
action.php View File

@@ -23,11 +23,11 @@ dieifnotloggedin();
23 23
 
24 24
 function returnToSender($msg, $arg = "") {
25 25
     global $VARS;
26
-    if ($arg == "") {
27
-        header("Location: app.php?page=" . urlencode($VARS['source']) . "&msg=$msg");
28
-    } else {
29
-        header("Location: app.php?page=" . urlencode($VARS['source']) . "&msg=$msg&arg=" . urlencode($arg));
26
+    $header = "Location: app.php?page=" . urlencode($VARS['source']) . "&msg=$msg";
27
+    if ($arg != "") {
28
+        $header .= "&arg=$arg";
30 29
     }
30
+    header($header);
31 31
     die();
32 32
 }
33 33
 

+ 3
- 2
api/functions.php View File

@@ -64,8 +64,9 @@ function authenticate(): bool {
64 64
             Log::insert(LogType::API_BAD_KEY, null, "Key: " . $key);
65 65
             return false;
66 66
         }
67
+        return true;
67 68
     }
68
-    return true;
69
+    return false;
69 70
 }
70 71
 
71 72
 function checkVars($vars, $or = false) {
@@ -160,4 +161,4 @@ function checkkeytype(string $type): bool {
160 161
         }
161 162
     }
162 163
     return true;
163
-}
164
+}

+ 2
- 0
api/index.php View File

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

+ 57
- 6
lib/FormBuilder.lib.php View File

@@ -116,6 +116,41 @@ class FormBuilder {
116 116
         $this->items[] = $item;
117 117
     }
118 118
 
119
+    /**
120
+     * Add a text input.
121
+     *
122
+     * @param string $name Element name
123
+     * @param string $value Element value
124
+     * @param bool $required If the element is required for form submission.
125
+     * @param string $id Element ID
126
+     * @param string $label Text label to display near the input
127
+     * @param string $icon FontAwesome icon (example: "fas fa-toilet-paper")
128
+     * @param int $width Bootstrap column width for the input, out of 12.
129
+     * @param int $minlength Minimum number of characters for the input.
130
+     * @param int $maxlength Maximum number of characters for the input.
131
+     * @param string $pattern Regex pattern for custom client-side validation.
132
+     * @param string $error Message to show if the input doesn't validate.
133
+     */
134
+    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 = "") {
135
+        $this->addInput($name, $value, "text", $required, $id, null, $label, $icon, $width, $minlength, $maxlength, $pattern, $error);
136
+    }
137
+
138
+    /**
139
+     * Add a select dropdown.
140
+     *
141
+     * @param string $name Element name
142
+     * @param string $value Element value
143
+     * @param bool $required If the element is required for form submission.
144
+     * @param string $id Element ID
145
+     * @param array $options Array of [value => text] pairs for a select element
146
+     * @param string $label Text label to display near the input
147
+     * @param string $icon FontAwesome icon (example: "fas fa-toilet-paper")
148
+     * @param int $width Bootstrap column width for the input, out of 12.
149
+     */
150
+    public function addSelect(string $name, string $value = "", bool $required = true, string $id = null, array $options = null, string $label = "", string $icon = "", int $width = 4) {
151
+        $this->addInput($name, $value, "select", $required, $id, $options, $label, $icon, $width);
152
+    }
153
+
119 154
     /**
120 155
      * Add a button to the form.
121 156
      *
@@ -178,7 +213,10 @@ HTMLTOP;
178 213
             }
179 214
             $itemhtml = "";
180 215
             $itemlabel = "";
181
-            if ($item['type'] != "checkbox") {
216
+
217
+            if ($item['type'] == "textarea") {
218
+                $itemlabel = "<label class=\"mb-0\"><i class=\"$item[icon]\"></i> $item[label]:</label>";
219
+            } else if ($item['type'] != "checkbox") {
182 220
                 $itemlabel = "<label class=\"mb-0\">$item[label]:</label>";
183 221
             }
184 222
             $strippedlabel = strip_tags($item['label']);
@@ -186,13 +224,16 @@ HTMLTOP;
186 224
 \n\n                <div class="col-12 col-md-$item[width]">
187 225
                     <div class="form-group mb-3">
188 226
                         $itemlabel
189
-                        <div class="input-group">
227
+ITEMTOP;
228
+            $inputgrouptop = <<<INPUTG
229
+\n                            <div class="input-group">
190 230
                             <div class="input-group-prepend">
191 231
                                 <span class="input-group-text"><i class="$item[icon]"></i></span>
192 232
                             </div>
193
-ITEMTOP;
233
+INPUTG;
194 234
             switch ($item['type']) {
195 235
                 case "select":
236
+                    $itemhtml .= $inputgrouptop;
196 237
                     $itemhtml .= <<<SELECT
197 238
 \n                            <select class="form-control" name="$item[name]" aria-label="$strippedlabel" $required>
198 239
 SELECT;
@@ -206,6 +247,7 @@ SELECT;
206 247
                     $itemhtml .= "\n                            </select>";
207 248
                     break;
208 249
                 case "checkbox":
250
+                    $itemhtml .= $inputgrouptop;
209 251
                     $itemhtml .= <<<CHECKBOX
210 252
 \n                            <div class="form-group form-check">
211 253
                                 <input type="checkbox" name="$item[name]" $id class="form-check-input" value="$item[value]" $required aria-label="$strippedlabel">
@@ -213,7 +255,14 @@ SELECT;
213 255
                               </div>
214 256
 CHECKBOX;
215 257
                     break;
258
+                case "textarea":
259
+                    $val = htmlentities($item['value']);
260
+                    $itemhtml .= <<<TEXTAREA
261
+\n                            <textarea class="form-control" id="info" name="$item[name]" aria-label="$strippedlabel" minlength="$item[minlength]" maxlength="$item[maxlength]" $required>$val</textarea>
262
+TEXTAREA;
263
+                    break;
216 264
                 default:
265
+                    $itemhtml .= $inputgrouptop;
217 266
                     $itemhtml .= <<<INPUT
218 267
 \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 />
219 268
 INPUT;
@@ -227,9 +276,11 @@ INPUT;
227 276
                             </div>
228 277
 ERROR;
229 278
             }
279
+            if ($item["type"] != "textarea") {
280
+                $itemhtml .= "\n                                </div>";
281
+            }
230 282
             $itemhtml .= <<<ITEMBOTTOM
231
-\n                        </div>
232
-                    </div>
283
+\n                    </div>
233 284
                 </div>\n
234 285
 ITEMBOTTOM;
235 286
             $html .= $itemhtml;
@@ -242,7 +293,7 @@ ITEMBOTTOM;
242 293
 HTMLBOTTOM;
243 294
 
244 295
         if (!empty($this->buttons)) {
245
-            $html .= "\n        <div class=\"card-footer\">";
296
+            $html .= "\n        <div class=\"card-footer d-flex\">";
246 297
             foreach ($this->buttons as $btn) {
247 298
                 $btnhtml = "";
248 299
                 $inner = "<i class=\"$btn[icon]\"></i> $btn[text]";

+ 2
- 0
lib/User.lib.php View File

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

+ 1
- 1
required.php View File

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

+ 6
- 6
static/css/bootstrap.min.css
File diff suppressed because it is too large
View File


+ 1
- 5
static/css/svg-with-js.min.css View File

@@ -1,5 +1 @@
1
-/*!
2
- * Font Awesome Free 5.6.0 by @fontawesome - https://fontawesome.com
3
- * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4
- */
5
-.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}
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}

+ 1
- 2
static/js/app.js View File

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

+ 3
- 3
static/js/bootstrap.bundle.min.js
File diff suppressed because it is too large
View File


+ 1
- 5
static/js/fontawesome-all.min.js
File diff suppressed because it is too large
View File


Loading…
Cancel
Save