Browse Source

NEW: admin->config.ini management
NEW: admin->toast notifications
ADD: admin.js->AjaxReq()

Giancarlo 7 years ago
parent
commit
aa349c1f83

+ 3 - 1
index.php

@@ -8,6 +8,8 @@
 //error_reporting(E_ALL);
 
 // Init Framework
+use OpenMind\System\OMUtils;
+
 require_once 'lib/f3/base.php';
 
 /** @var \Base $f3 */
@@ -20,7 +22,7 @@ $f3->set('GLOBALMENU', array());
 require_once "src/OpenMind/System/OMUtils.php";
 
 // Initialize Util library
-$frameworkUtils = new \OpenMind\System\OMUtils();
+$frameworkUtils = new OMUtils();
 
 // PHP Check Version
 $frameworkUtils->DieByOldPhpVersion();

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "OM-Link",
-  "version": "1.8.0",
+  "version": "1.8.1",
   "private": true,
   "description": "OM-Link Engine",
   "scripts": {

+ 4 - 1
src/OpenMind/Admin/Admin.php

@@ -17,7 +17,10 @@ class Admin extends PluginStrategy
     $this->AddRoute('GET @admin: /admin', __NAMESPACE__ . '\Pages->Admin');
     $this->AddRoute('GET @admin: /admin/eslstatus', __NAMESPACE__ . '\Pages->ESLStatus');
     $this->AddRoute('GET @admin: /admin/eslissues', __NAMESPACE__ . '\Pages->ESLIssues');
-    $this->AddRoute('GET @admin: /admin/apstatus', __NAMESPACE__ . '\Pages->APStatus');
+		$this->AddRoute('GET @admin: /admin/apstatus', __NAMESPACE__ . '\Pages->APStatus');
+		$this->AddRoute('GET @admin: /admin/omlsettings', __NAMESPACE__ . '\Pages->OML_Settings');
+		// Admin Save
+		$this->AddRoute('POST @admin: /admin/config', __NAMESPACE__ . '\Pages->Config');
 
     $this->AddMenuItem('Admin', ['url' => 'admin', 'permissionName' => 'admin']);
 

+ 51 - 1
src/OpenMind/Admin/Pages.php

@@ -15,7 +15,7 @@ class Pages extends Controller
 {
 	private $findBoxCore = null;
 
-  public function __construct($f3)
+	public function __construct($f3)
 	{
 		parent::__construct($f3);
 
@@ -47,4 +47,54 @@ class Pages extends Controller
 		$f3->set('CONTENT', 'labelstatus.tpl');
 		echo Template::instance()->render('masterpage.tpl');
 	}
+
+	public function OML_Settings($f3)
+	{
+		global $frameworkUtils;
+
+		$path = 'cfg/config.bin';
+		if (!file_exists($path))
+			throw new \Exception('Config file not found');
+
+		$data = file_get_contents($path);
+		$config = $frameworkUtils->Decrypt($data);
+
+		$f3->set('PAGENAME', 'OM-Link Settings');
+		$f3->set('CONTENT', 'omlsettings.tpl');
+		$f3->set('CONFIG_TEXT', $config);
+		echo Template::instance()->render('masterpage.tpl');
+	}
+
+	public function Config($f3)
+	{
+		global $frameworkUtils;
+		$config = $f3->get('BODY');
+		if (strlen($config) == 0) {
+			echo json_encode([
+				"err" => "Empty body command"
+			]);
+			return;
+		}
+
+		$configOBJ = json_decode($config);
+		switch ($configOBJ->method) {
+			case 'saveconfig':
+				$newConfig = $frameworkUtils->Encrypt($configOBJ->value);
+				@rename('cfg/config.bin', 'cfg/config.bin.old');
+				@file_put_contents('cfg/config.bin', $newConfig);
+				echo json_encode([
+					"err" => "Configuration saved"
+				]);
+				break;
+			case 'loadconfig':
+				$config = $frameworkUtils->Decrypt(file_get_contents('cfg/config.bin'));
+				echo json_encode([
+					"err" => "Configuration reloaded successfully",
+					"value" => $config
+				]);
+				break;
+		}
+
+		return;
+	}
 }

+ 3 - 0
src/OpenMind/Admin/build.css.list

@@ -8,6 +8,9 @@ ui/assets/plugins/datatables/responsive.bootstrap4.min.css
 ; Multi Item Selection examples
 ui/assets/plugins/datatables/select.bootstrap4.min.css
 
+; Toastr
+ui/assets/plugins/toastr/toastr.min.css
+
 ; App CSS
 ui/assets/css/bootstrap.min.css
 ui/assets/css/icons.css

+ 3 - 0
src/OpenMind/Admin/build.js.list

@@ -28,6 +28,9 @@ ui/assets/plugins/datatables/responsive.bootstrap4.min.js
 ; Selection table
 ui/assets/plugins/datatables/dataTables.select.min.js
 
+; Toastr
+ui/assets/plugins/toastr/toastr.min.js
+
 ; App js
 ui/assets/js/jquery.core.js
 ui/assets/js/jquery.app.js

+ 4 - 0
src/OpenMind/Admin/ui/assets/css/admin.scss

@@ -1,3 +1,7 @@
 .badge-light {
 	background-color: #868e96;
 }
+
+.debugborder {
+	border: 1px solid red;
+}

+ 58 - 1
src/OpenMind/Admin/ui/assets/js/admin.js

@@ -1,4 +1,14 @@
+const fetchHeaders = {
+	'Accept': 'text/html',
+	'Content-Type': 'text/html',
+	'X-Requested-With': 'XMLHttpRequest',
+	'Cache-Control': 'no-cache',
+	'Pragma': 'no-cache',
+	'Expires': '0'
+};
+
 $(function () {
+	// DataTable fix
 	$("#datatable").DataTable({
 		paging: false,
 		scrollY: true,
@@ -12,5 +22,52 @@ $(function () {
 				height: "50vh"
 			})
 		}
+	});
+});
+
+/**
+ * Make an AJAX request.
+ *
+ * If error, catch return a promise error object:
+ *
+ *  .catch(err => alert(`${err.url}\n\n${err.status} (${err.statusText})`));
+ *
+ * @param url
+ * @param options
+ * @returns {Promise<Response | never>}
+ */
+function AjaxReq(url, options) {
+	let defaults = {headers: fetchHeaders}
+	// Extend default options
+	Object.assign(defaults, options);
+
+	return fetch(url, defaults)
+		.then(resp => {
+			if (resp.status === 200)
+				return resp.json();
+			else
+				return Promise.reject(resp);
+		});
+}
+
+function SaveConfig() {
+	let config = $('#config_text').val();
+	AjaxReq(`${BASEURL}/admin/config`, {
+		method: 'POST',
+		body: JSON.stringify({"method": "saveconfig", "value": config})
 	})
-});
+		.then(json => toastr.success(json.err))
+		.catch(err => toastr.error(err.url, `${err.status} (${err.statusText})`));
+}
+
+function LoadConfig() {
+	AjaxReq(`${BASEURL}/admin/config`, {
+		method: 'POST',
+		body: JSON.stringify({"method": "loadconfig"})
+	})
+		.then(json => {
+			$('#config_text').val(json.value);
+			toastr.success(json.err);
+		})
+		.catch(err => toastr.error(err.url, `${err.status} (${err.statusText})`));
+}

+ 200 - 0
src/OpenMind/Admin/ui/assets/plugins/toastr/toastr.css

@@ -0,0 +1,200 @@
+.toast-title {
+  font-weight: bold;
+}
+.toast-message {
+  -ms-word-wrap: break-word;
+  word-wrap: break-word;
+}
+.toast-message a,
+.toast-message label {
+  color: #ffffff;
+}
+.toast-message a:hover {
+  color: #cccccc;
+  text-decoration: none;
+}
+.toast-close-button {
+  position: relative;
+  right: -0.3em;
+  top: -0.3em;
+  float: right;
+  font-size: 20px;
+  font-weight: bold;
+  color: #ffffff;
+  -webkit-text-shadow: 0 1px 0 #ffffff;
+  text-shadow: 0 1px 0 #ffffff;
+  opacity: 0.8;
+  -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
+  filter: alpha(opacity=80);
+}
+.toast-close-button:hover,
+.toast-close-button:focus {
+  color: #000000;
+  text-decoration: none;
+  cursor: pointer;
+  opacity: 0.4;
+  -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40);
+  filter: alpha(opacity=40);
+}
+/*Additional properties for button version
+ iOS requires the button element instead of an anchor tag.
+ If you want the anchor version, it requires `href="#"`.*/
+button.toast-close-button {
+  padding: 0;
+  cursor: pointer;
+  background: transparent;
+  border: 0;
+  -webkit-appearance: none;
+}
+.toast-top-center {
+  top: 0;
+  right: 0;
+  width: 100%;
+}
+.toast-bottom-center {
+  bottom: 0;
+  right: 0;
+  width: 100%;
+}
+.toast-top-full-width {
+  top: 0;
+  right: 0;
+  width: 100%;
+}
+.toast-bottom-full-width {
+  bottom: 0;
+  right: 0;
+  width: 100%;
+}
+.toast-top-left {
+  top: 12px;
+  left: 12px;
+}
+.toast-top-right {
+  top: 12px;
+  right: 12px;
+}
+.toast-bottom-right {
+  right: 12px;
+  bottom: 12px;
+}
+.toast-bottom-left {
+  bottom: 12px;
+  left: 12px;
+}
+#toast-container {
+  position: fixed;
+  z-index: 999999;
+  pointer-events: none;
+  /*overrides*/
+}
+#toast-container * {
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  box-sizing: border-box;
+}
+#toast-container > div {
+  position: relative;
+  pointer-events: auto;
+  overflow: hidden;
+  margin: 0 0 6px;
+  padding: 15px 15px 15px 50px;
+  width: 300px;
+  -moz-border-radius: 3px 3px 3px 3px;
+  -webkit-border-radius: 3px 3px 3px 3px;
+  border-radius: 3px 3px 3px 3px;
+  background-position: 15px center;
+  background-repeat: no-repeat;
+  -moz-box-shadow: 0 0 12px #999999;
+  -webkit-box-shadow: 0 0 12px #999999;
+  box-shadow: 0 0 12px #999999;
+  color: #ffffff;
+  opacity: 0.8;
+  -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
+  filter: alpha(opacity=80);
+}
+#toast-container > :hover {
+  -moz-box-shadow: 0 0 12px #000000;
+  -webkit-box-shadow: 0 0 12px #000000;
+  box-shadow: 0 0 12px #000000;
+  opacity: 1;
+  -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
+  filter: alpha(opacity=100);
+  cursor: pointer;
+}
+#toast-container > .toast-info {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important;
+}
+#toast-container > .toast-error {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important;
+}
+#toast-container > .toast-success {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important;
+}
+#toast-container > .toast-warning {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important;
+}
+#toast-container.toast-top-center > div,
+#toast-container.toast-bottom-center > div {
+  width: 300px;
+  margin-left: auto;
+  margin-right: auto;
+}
+#toast-container.toast-top-full-width > div,
+#toast-container.toast-bottom-full-width > div {
+  width: 96%;
+  margin-left: auto;
+  margin-right: auto;
+}
+.toast {
+  background-color: #030303;
+}
+.toast-success {
+  background-color: #51a351;
+}
+.toast-error {
+  background-color: #bd362f;
+}
+.toast-info {
+  background-color: #2f96b4;
+}
+.toast-warning {
+  background-color: #f89406;
+}
+.toast-progress {
+  position: absolute;
+  left: 0;
+  bottom: 0;
+  height: 4px;
+  background-color: #000000;
+  opacity: 0.4;
+  -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40);
+  filter: alpha(opacity=40);
+}
+/*Responsive Design*/
+@media all and (max-width: 240px) {
+  #toast-container > div {
+    padding: 8px 8px 8px 50px;
+    width: 11em;
+  }
+  #toast-container .toast-close-button {
+    right: -0.2em;
+    top: -0.2em;
+  }
+}
+@media all and (min-width: 241px) and (max-width: 480px) {
+  #toast-container > div {
+    padding: 8px 8px 8px 50px;
+    width: 18em;
+  }
+  #toast-container .toast-close-button {
+    right: -0.2em;
+    top: -0.2em;
+  }
+}
+@media all and (min-width: 481px) and (max-width: 768px) {
+  #toast-container > div {
+    padding: 15px 15px 15px 50px;
+    width: 25em;
+  }
+}

File diff suppressed because it is too large
+ 0 - 0
src/OpenMind/Admin/ui/assets/plugins/toastr/toastr.min.css


File diff suppressed because it is too large
+ 0 - 0
src/OpenMind/Admin/ui/assets/plugins/toastr/toastr.min.js


+ 31 - 0
src/OpenMind/Admin/ui/errors.tpl

@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html lang="it">
+<head>
+	<meta charset="UTF-8">
+	<meta content="width=device-width, initial-scale=1" name="viewport">
+	<title>{{@SITENAME}} error page</title>
+	<link href="{{@BASEURL}}/bundle.css" rel="stylesheet" type="text/css"/>
+</head>
+<body class="bg-light error_body">
+
+<div class="container-fluid">
+	<div class="row">
+		<div class="col-md-6 mx-auto">
+			<div class="card bg-white m-1 p-2">
+				<h1 class="text-center text-info">{{@ERROR.code}} {{@ERROR.status}}</h1>
+				<br/>
+				<h3 class="text-success">Dettaglio errore:</h3>
+				<p style="color: black">{{@ERROR.text | raw}}</p>
+				<h3 class="text-success">Debug Trace:</h3>
+				<pre style="font-size: 0.8rem">{{@ERROR.trace | raw}}</pre>
+				<br/>
+				<a class="text-uppercase" href="{{@BASEURL}}">Torna alla pagina principale.</a>
+			</div>
+		</div>
+	</div>
+</div>
+
+<script src="{{@BASEURL}}/bundle.js"></script>
+
+</body>
+</html>

+ 20 - 0
src/OpenMind/Admin/ui/omlsettings.tpl

@@ -0,0 +1,20 @@
+<div class="col-xl-4">
+	<div class="card-box slimscroll" style="max-height: 50%;">
+		<div class="dropdown pull-right">
+			<a href="#" class="dropdown-toggle arrow-none card-drop" data-toggle="dropdown" aria-expanded="false">
+				<i class="mdi mdi-dots-vertical"></i>
+			</a>
+			<div class="dropdown-menu dropdown-menu-right">
+				<a href="javascript:SaveConfig();" class="dropdown-item">Save</a>
+				<a href="javascript:LoadConfig();" class="dropdown-item">Reload</a>
+			</div>
+		</div>
+
+		<h4 class="header-title mt-0 m-b-30">Configuration</h4>
+		<div class="row">
+			<div class="col-md-12">
+				<textarea id="config_text" class="form-control" style="height: 100vh">{{@CONFIG_TEXT}}</textarea>
+			</div>
+		</div>
+	</div>
+</div>

+ 2 - 1
src/OpenMind/FindBox/FindBoxCoreSystem.php

@@ -206,6 +206,7 @@ class FindBoxCoreSystem
 	 */
 	public function GetAllESLStatus($force = false): ?array
 	{
+		global $frameworkUtils;
 		// Retrieve all labels
 		$URI = '/1.0.0/index.php/smartesl.getstatus/4.0.0/[[],false]';
 		$ret = $this->CallAPI($URI, "");
@@ -214,7 +215,7 @@ class FindBoxCoreSystem
 
 		$fbOSResponse = $this->getLabelsFromResponse($ret);
 		if (!$fbOSResponse) {
-			$this->log->write('GetAllESLStatus: ' . $ret['value']['value'], 'd/m/Y H:i:s');
+			$frameworkUtils->getLogger()->write('GetAllESLStatus: ' . $ret['value']['value'], 'd/m/Y H:i:s');
 			return null;
 		}
 

+ 23 - 1
src/OpenMind/System/OMUtils.php

@@ -102,12 +102,34 @@ class OMUtils
 			throw new \Exception('Config file not found');
 
 		$tmpFilepath = tempnam(sys_get_temp_dir(), 'om');
-		$config = gzuncompress(base64_decode(file_get_contents($path)));
+		$config = $this->Decrypt(file_get_contents($path));
 		file_put_contents($tmpFilepath, $config);
 		$f3->config($tmpFilepath, true);
 		unlink($tmpFilepath);
 	}
 
+	/**
+	 * Encrypt $data using OM-Link algorithm
+	 *
+	 * @param $data
+	 * @return string
+	 */
+	public function Encrypt($data)
+	{
+		return base64_encode(gzcompress($data));
+	}
+
+	/**
+	 * Decrypt $data using OM-Link algorithm
+	 *
+	 * @param $binaryData
+	 * @return string
+	 */
+	public function Decrypt($binaryData)
+	{
+		return gzuncompress(base64_decode($binaryData));
+	}
+
 	/*
 	 * Exit from APP if the OMLINK requirement aren't meet
 	 */

Some files were not shown because too many files changed in this diff