diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 000000000..fd4c0ee21
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,4 @@
+[submodule "packages/core/apps/workbench"]
+ path = packages/core/apps/workbench/sources
+ url = https://github.com/f7ed0/equal-workbench.git
+ branch = dev
diff --git a/packages/core/actions/config/create-view.php b/packages/core/actions/config/create-view.php
index b6b8b89cc..e769b22f4 100644
--- a/packages/core/actions/config/create-view.php
+++ b/packages/core/actions/config/create-view.php
@@ -56,7 +56,7 @@
throw new Exception("view_id_invalid",QN_ERROR_INVALID_PARAM);
}
-if(strcmp($type, "form")!==0 && strcmp($type, "list")!==0) {
+if(strcmp($type, "form")!==0 && strcmp($type, "list")!==0 && strcmp($type, "search")!==0 && strcmp($type, "app")!==0 && strcmp($type, $package)!==0 ) {
$test = strcmp($type, "list");
throw new Exception("view_type_invalid",QN_ERROR_INVALID_PARAM);
}
@@ -85,10 +85,10 @@
throw new Exception('file_access_denied', QN_ERROR_UNKNOWN);
}
-if($type == "form") {
+if($type == "form" || $type == "search") {
fputs($f,"{\"layout\" : {\"groups\" : []}}");
}
-elseif($type == "list") {
+else {
fputs($f,"{\"layout\" : {\"items\" : []}}");
}
diff --git a/packages/core/actions/config/update-controller.php b/packages/core/actions/config/update-controller.php
index 9e9571c48..1c7c31f1c 100644
--- a/packages/core/actions/config/update-controller.php
+++ b/packages/core/actions/config/update-controller.php
@@ -22,6 +22,7 @@
'controller' => [
'description' => 'Name of the controller.',
'type' => 'string',
+ 'usage' => 'orm/entity'
// 'required' => true
],
'operation' => [
@@ -55,8 +56,8 @@
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
// Get the parts of the entity string, separated by backslashes
-$params['entity'] = str_replace('_', '\\', $params['entity']);
-$parts = explode('\\', $params['entity']);
+$params['controller'] = str_replace('_', '\\', $params['controller']);
+$parts = explode('\\', $params['controller']);
// Get the package name from the first part of the string
$package = array_shift($parts);
@@ -65,9 +66,12 @@
// Get the class path from the remaining part
$class_path = implode('/', $parts);
+/*if(!($decoded = json_decode($params['payload'],true))) {
+ throw new Exception('Malformed Json', QN_ERROR_INVALID_PARAM);
+}*/
// Get a string representation from the code_php variable, with backslashes escaped
-$code_string = str_replace("\\\\", "\\", var_export($params['payload'], true));
+$code_string = str_replace("\\\\", "\\", var_export( $params['payload'], true));
// #test #toremove
// $code_string = "[
@@ -137,9 +141,10 @@ public function leaveNode(Node $node) {
);
// Get the full path of the file
-$dir = ['do' => 'actions', 'get' => 'date', 'show' => 'apps'][$params['operation']];
+$dir = ['do' => 'actions', 'get' => 'data', 'show' => 'apps'][$params['operation']];
$file = QN_BASEDIR."/packages/{$package}/{$dir}/{$class_path}/{$filename}.php";
+$file = str_replace("//","/",$file);
// Get the code from the original file ...
$code = file_get_contents($file);
// ... and parse it to create an AST
@@ -174,7 +179,8 @@ public function leaveNode(Node $node) {
}
}
catch(Exception $e) {
- trigger_error("PHP::unable to beautify rendered file ($file): ".$e->getMessage(), QN_REPORT_INFO);
+ throw new Exception('unable to beautfy the file', QN_ERROR_UNKNOWN);
+ //trigger_error("PHP::unable to beautify rendered file ($file): ".$e->getMessage(), QN_REPORT_INFO);
}
$result = file_get_contents($file);
diff --git a/packages/core/apps/workbench/.gitignore b/packages/core/apps/workbench/.gitignore
deleted file mode 100644
index eef52883d..000000000
--- a/packages/core/apps/workbench/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-source/
diff --git a/packages/core/apps/workbench/manifest.json b/packages/core/apps/workbench/manifest.json
old mode 100644
new mode 100755
index 73da546c0..c0f34d874
--- a/packages/core/apps/workbench/manifest.json
+++ b/packages/core/apps/workbench/manifest.json
@@ -1,13 +1,9 @@
{
"name": "Workbench",
- "description": "App for customizing models, views and controllers from the user interface without code.",
- "version": "1.0",
- "authors": ["Cedric Francoys", "Sylvain Sausse", "Quentin Leveque"],
- "license": "LGPL-3",
- "repository": "https://github.com/equalframework/apps-core-settings.git",
+ "description": "This is the workbench application.",
"url": "/workbench",
"icon": "edit_note",
- "color": "#0f1397",
+ "color": "#d2252c",
"access": {
"groups": [
"users", "admin"
diff --git a/packages/core/apps/workbench/sources b/packages/core/apps/workbench/sources
new file mode 160000
index 000000000..2efc9f222
--- /dev/null
+++ b/packages/core/apps/workbench/sources
@@ -0,0 +1 @@
+Subproject commit 2efc9f2227c9786368b9c981084e466a02fbf7bf
diff --git a/packages/core/apps/workbench/web.app b/packages/core/apps/workbench/web.app
index be2b6f8fc..222b96e52 100644
Binary files a/packages/core/apps/workbench/web.app and b/packages/core/apps/workbench/web.app differ
diff --git a/packages/core/data/config/menus.php b/packages/core/data/config/menus.php
new file mode 100644
index 000000000..1f2675e8a
--- /dev/null
+++ b/packages/core/data/config/menus.php
@@ -0,0 +1,98 @@
+
+ Some Rights Reserved, Cedric Francoys, 2010-2021
+ Licensed under GNU LGPL 3 license
+*/
+list($params, $providers) = eQual::announce([
+ 'description' => 'Returns the list of menus defined in a given package, or applicable to a given entity.',
+ 'response' => [
+ 'content-type' => 'application/json',
+ 'charset' => 'UTF-8',
+ 'accept-origin' => '*'
+ ],
+ 'params' => [
+ 'package' => [
+ 'description' => 'Name of the package for which the list is requested.',
+ 'type' => 'string',
+ 'required' => true
+ ],
+ ],
+ 'providers' => ['context', 'orm']
+]);
+
+/**
+ * @var \equal\php\Context $context
+ * @var \equal\orm\ObjectManager $orm
+ */
+list($context, $orm) = [$providers['context'], $providers['orm']];
+
+$result = [];
+
+if(!file_exists("packages/{$params['package']}")) {
+ throw new Exception('missing_package_dir', QN_ERROR_INVALID_CONFIG);
+}
+if(!file_exists("packages/{$params['package']}/views")) {
+ throw new Exception('missing_views_dir', QN_ERROR_INVALID_CONFIG);
+}
+// recurse through all sub-folders of `views` directory
+$result = recurse_dir("packages/{$params['package']}/views", 'json', $params['package']);
+
+
+$context->httpResponse()
+ ->body($result)
+ ->send();
+
+function has_sub_items($directory, $extension) {
+ $files = glob($directory.'/*.'.$extension);
+ if(count($files)) {
+ return true;
+ }
+ foreach(glob($directory.'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $node) {
+ if(has_sub_items($node, $extension)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * #memo - this method slightly differs from the one in controllers.php and translations.php
+ */
+function recurse_dir($directory, $extension, $parent_name='') {
+ $result = array();
+ if( is_dir($directory) ) {
+ $dir_name = basename($directory);
+ $list = glob($directory.'/*');
+ foreach($list as $node) {
+ $filename = basename($node, '.'.$extension);
+ list($entity_name, $view_id) = explode('.', $filename, 2);
+ if(!($entity_name == 'menu')) continue;
+ if(is_dir($node)) {
+ if(!has_sub_items($node, $extension)) {
+ continue;
+ }
+ $result = array_merge($result, recurse_dir($node, $extension, (strlen($parent_name)?$parent_name.'\\'.$filename:$filename)));
+ }
+ elseif(pathinfo($node, PATHINFO_EXTENSION) == $extension) {
+ $entity = (strlen($parent_name)?$parent_name.'\\':'').$entity_name;
+ try {
+ // #memo - ! can be controller or class
+ // $entity::getType();
+ $result[] = $view_id;
+ }
+ catch(Exception $e) {
+ if($entity_name == 'menu') {
+ // ignore
+ }
+ else {
+ // entity should be a controller
+ // #todo - check that the controller actually exists
+ $result[] = str_replace('\\', '_', $entity).':'.$view_id;
+ }
+ }
+ }
+ }
+ }
+ return $result;
+}
diff --git a/packages/core/data/config/types.php b/packages/core/data/config/types.php
index 93535393e..fb18f4fdf 100755
--- a/packages/core/data/config/types.php
+++ b/packages/core/data/config/types.php
@@ -136,7 +136,10 @@
'computed' => [
'type' => ['type' => 'string'],
//'default' => ['type' => 'string'],
- 'function', 'result_type', 'onupdate', 'store', 'instant', 'multilang', 'selection'
+ 'function', 'result_type', 'onupdate', 'store', 'instant', 'multilang'
+ ],
+ 'array' => [
+ 'default','type' => ['type' => 'string'],'dependencies','onupdate', 'selection','usage'
]
];
diff --git a/packages/core/data/config/views.php b/packages/core/data/config/views.php
index 5823a3585..02272597c 100644
--- a/packages/core/data/config/views.php
+++ b/packages/core/data/config/views.php
@@ -132,6 +132,7 @@ function recurse_dir($directory, $extension, $parent_name='') {
foreach($list as $node) {
$filename = basename($node, '.'.$extension);
list($entity_name, $view_id) = explode('.', $filename, 2);
+ if($entity_name == 'menu') continue;
if(is_dir($node)) {
if(!has_sub_items($node, $extension)) {
continue;
diff --git a/packages/core/data/console.php b/packages/core/data/console.php
new file mode 100644
index 000000000..17f5a1ef9
--- /dev/null
+++ b/packages/core/data/console.php
@@ -0,0 +1,196 @@
+
+/*
+ This file is part of the eQual framework
+ Some Rights Reserved, Cedric Francoys, 2010-2021
+ Licensed under GNU LGPL 3 license
+*/
+
+list($params, $providers) = eQual::announce([
+ 'description' => 'Returns a descriptor of current installation Settings, holding specific values for current User, if applicable.',
+ 'access' => [
+ 'visibility' => 'public'
+ ],
+ 'params' => [
+ 'thread_id' => [
+ 'type' => 'string',
+ 'description' => 'Thread_id of the line'
+ ],
+ 'level' => [
+ 'type' => 'string',
+ 'description' => 'Level of the WARNING | DEBUG | INFO | ERROR'
+ ],
+ 'mode' => [
+ 'type' => 'string',
+ 'description' => 'php | orm | sql | api | app'
+ ],
+ 'time' => [
+ 'type' => 'string',
+ 'description' => 'Indicates the time of the log'
+
+ ],
+ 'mtime' => [
+ 'type' => 'string',
+ 'description' => 'Mtime allows to look for a precise time'
+
+ ],
+ 'help' => [
+ 'type' => 'boolean',
+ 'description' => 'Set to true to display help'
+ ],
+ 'limit' => [
+ 'type' => 'integer',
+ 'description' => 'Returns the selected number of lines'
+ ]
+ ],
+ 'response' => [
+ 'content-type' => 'application/json',
+ 'charset' => 'UTF-8',
+ 'accept-origin' => '*'
+ ],
+ 'providers' => ['context', 'orm', 'auth']
+]);
+
+
+list($context, $om, $auth) = [$providers['context'], $providers['orm'], $providers['auth']];
+
+/**
+ * @var string $level
+ * @return string ANSI escape codes to change the color of the level text according to their values
+ * example $level = "WARNING" returns yellow color
+ */
+function calColor(string $level)
+{
+ $green = "\e[32;1m";
+ $red = "\e[31;1m";
+ $blue = "\e[34;1m";
+ $yellow = "\e[33;1m";
+ $white = "\e[0m";
+
+ if (is_null($level)) return $white;
+ switch (strtoupper($level)) {
+ case 'WARNING':
+ case E_USER_WARNING:
+ return $yellow;
+ case 'DEBUG':
+ case E_USER_DEPRECATED:
+ return $green;
+ case 'INFO':
+ case 'NOTICE':
+ case E_USER_NOTICE:
+ return $blue;
+ case 'ERROR':
+ case 'FATAL':
+ case 'Fatal error':
+ case 'Parse error':
+ return $red;
+ default:
+ return $white;
+ }
+}
+
+/**
+ * Displays a thread
+ * @var Array $thread
+ */
+function displayThread(array $thread)
+{
+ $green = "\e[32;1m";
+ $red = "\e[31;1m";
+ $white = "\e[0m";
+ $bold = "\e[00;1m";
+ $text = "";
+
+ $text .= "$green ${thread['time']} $white";
+ if ($thread['mtime']) {
+ $text .= "$bold {$thread['mtime']} $white";
+ }
+ if (is_string($thread['level'])) {
+ $text .= calColor($thread['level']) . "[${thread['level']}]$white";
+ }
+ $text .= " ${thread['mode']}";
+ $text .= "${bold} ${thread['function']} ";
+ $text .= "${white}@ ${thread['file']} : ";
+ $text .= "line $bold${thread['line']}$white | ";
+ $text .= "thread_id $red ${thread['thread_id']} $white";
+ if (is_string($thread['message'])) {
+ // check message format to display in lines if it is an associative array
+ if (is_array(json_decode($thread['message'], true))) {
+ $newMessage = json_decode($thread['message'], true);
+ foreach ($newMessage as $val) {
+ if (is_array($val)) {
+ $m = "";
+ foreach ($val as $id => $v) {
+ $m .= "$white ${bold}${id}${white} : \e[3m${v} \e[23m";
+ }
+ $text .= "\n${bold}message:$m";
+ } else if (is_string($val)) {
+ $text .= "${bold}\nmessage:$white \e[3m${val} \e[23m"; // message displays in italics
+ }
+ }
+ } else {
+ $text .= "$bold \nmessage:$white \e[3m${thread['message']} \e[23m";
+ }
+ // message displays in italics
+ }
+ if (isset($thread['stack'])) {
+ for ($i = 0; $i < count($thread['stack']); $i++) {
+ $stack = $thread['stack'][count($thread['stack']) - $i - 1];
+ $text .= $i == count($thread['stack']) - 1 ? "\n └ " : "\n ├ ";
+ $text .= "${stack['function']} @ ${stack['file']} ${stack['line']} $white";
+ }
+ }
+ return ($text);
+}
+
+/**
+ * Filters a thread arguments are given in params
+ * @return Array $thread | null
+ */
+function filterThreadByParams(array $thread, array $params)
+{
+ if (isset($params['mode']) && $params['mode'] !== '' && $thread['mode'] == strtoupper($params['mode'])) {
+ return $thread;
+ }
+ if (isset($params['level']) && isset($params['level']) != '' && $thread['level'] == strtoupper($params['level'])) {
+ return $thread;
+ };
+ if (isset($params['thread_id']) && $params['thread_id'] != '' && $thread['thread_id'] == $params['thread_id']) {
+ return $thread;
+ }
+ if (isset($params['mtime']) && $params['mtime'] != '' && $thread['mtime'] == $params['mtime']) {
+ return $thread;
+ }
+ if (isset($params['time']) && $params['time'] != '' && str_contains(($thread['time']), $params['time'])) {
+ return $thread;
+ }
+ if (!isset($params['time']) && !isset($params['mtime']) && !isset($params['thread_id']) && !isset($params['level']) && !isset($params['mode'])) {
+ return $thread;
+ }
+}
+
+if (file_exists('/var/www/html/log/eq_error.log')) {
+ // read raw data from pointer log file
+ $fp = fopen("/var/www/html/log/eq_error.log", "r");
+ echo "START LOG\n";
+ $cpt = 0;
+ if ($fp) {
+ while ((($data = stream_get_line($fp, 65535, PHP_EOL)) !== false) && ((isset($params["limit"]) && $cpt <= $params["limit"]) || !isset($params["limit"]))) {
+
+ $thread = json_decode($data, true);
+ if (!is_null($thread)) {
+ $filteredThread = filterThreadByParams($thread, $params);
+ if (!is_null($filteredThread)) {
+ print(displayThread($thread));
+ echo ("\n---------------------------------------------------------------------------------------------------------------------------------------------\n");
+ };
+ }
+ $cpt++;
+ }
+ fclose($fp);
+ }
+ echo "\nEND LOG \e[0m \n";
+};
+
+// $context->httpResponse()
+// ->body($text)
+// ->send();