From 45fab928ada601db8ee8a8130bc825b39f0bfa05 Mon Sep 17 00:00:00 2001 From: Paolo Date: Thu, 7 Oct 2021 17:32:49 +0200 Subject: [PATCH] - Renamed private method _manageUDFs to _prepareUDFsWrite in application/core/DB_Model.php - Changed private method _toPhp in application/core/DB_Model.php to check permissions on UDFs - Adapted code to fit the changes in application/libraries/UDFLib.php - Renamed public method manageUDFs to prepareUDFsWrite in application/libraries/UDFLib.php - Added new public method prepareUDFsRead to application/libraries/UDFLib.php - Fixed bugs, comments & code style --- application/core/DB_Model.php | 105 +++++++++---------- application/libraries/UDFLib.php | 175 ++++++++++++++++++++++++------- 2 files changed, 183 insertions(+), 97 deletions(-) diff --git a/application/core/DB_Model.php b/application/core/DB_Model.php index 4b89ae5bf..0c43a9baf 100644 --- a/application/core/DB_Model.php +++ b/application/core/DB_Model.php @@ -86,7 +86,7 @@ class DB_Model extends CI_Model if (is_null($this->dbTable)) return error('The given database table name is not valid', EXIT_MODEL); // If this table has UDF and the validation of them is ok - if (isError($validate = $this->_manageUDFs($data, $this->dbTable))) return $validate; + if (isError($validate = $this->_prepareUDFsWrite($data, $this->dbTable))) return $validate; // DB-INSERT $insert = $this->db->insert($this->dbTable, $data); @@ -137,7 +137,7 @@ class DB_Model extends CI_Model if (is_null($this->dbTable)) return error('The given database table name is not valid', EXIT_MODEL); // If this table has UDF and the validation of them is ok - if (isError($validate = $this->_manageUDFs($data, $this->dbTable, $id))) return $validate; + if (isError($validate = $this->_prepareUDFsWrite($data, $this->dbTable, $id))) return $validate; $tmpId = $id; @@ -844,25 +844,25 @@ class DB_Model extends CI_Model } /** - * Wrapper method for UDFLib->manageUDFs + * Wrapper method for UDFLib->prepareUDFsWrite */ - private function _manageUDFs(&$data, $schemaAndTable, $id = null) + private function _prepareUDFsWrite(&$data, $schemaAndTable, $id = null) { - $manageUDFs = success(); + $prepareUDFsWrite = success(); if ($this->hasUDF()) { if ($id != null) { - $manageUDFs = $this->udflib->manageUDFs($data, $this->dbTable, $this->getUDFs($id)); + $prepareUDFsWrite = $this->udflib->prepareUDFsWrite($data, $this->dbTable, $this->getUDFs($id)); } else { - $manageUDFs = $this->udflib->manageUDFs($data, $this->dbTable); + $prepareUDFsWrite = $this->udflib->prepareUDFsWrite($data, $this->dbTable); } } - return $manageUDFs; + return $prepareUDFsWrite; } /** @@ -874,9 +874,10 @@ class DB_Model extends CI_Model */ private function _toPhp($result) { + $udfs = false; // if UDFs are inside the given result set $toPhp = $result; // if there is nothing to convert then return the result from DB - // If it's an object its fields will be parsed to find booleans and arrays types + // If it's an object its fields will be parsed to find booleans, arrays and UDFs types if (is_object($result)) { $toBeConverterdArray = array(); // Fields to be converted @@ -884,40 +885,48 @@ class DB_Model extends CI_Model $this->executedQueryMetaData = $result->field_data(); // Fields information $this->executedQueryListFields = $result->list_fields(); // List of the retrieved fields - for ($i = 0; $i < count($this->executedQueryMetaData); $i++) // Looking for booleans and arrays + // Looking for booleans, arrays and UDFs + foreach ($this->executedQueryMetaData as $eqmd) { // If array type, boolean type OR a UDF - if (strpos($this->executedQueryMetaData[$i]->type, DB_Model::PGSQL_ARRAY_TYPE) !== false - || $this->executedQueryMetaData[$i]->type == DB_Model::PGSQL_BOOLEAN_TYPE - || $this->udflib->isUDFColumn($this->executedQueryMetaData[$i]->name, $this->executedQueryMetaData[$i]->type)) + if (strpos($eqmd->type, DB_Model::PGSQL_ARRAY_TYPE) !== false + || $eqmd->type == DB_Model::PGSQL_BOOLEAN_TYPE + || $this->udflib->isUDFColumn($eqmd->name, $eqmd->type)) { - // Name and type of the field to be converted - $toBeConverted = new stdClass(); - // Set the type of the field to be converted - $toBeConverted->type = $this->executedQueryMetaData[$i]->type; - // Set the name of the field to be converted - $toBeConverted->name = $this->executedQueryMetaData[$i]->name; - // Add the field to be converted to $toBeConverterdArray - array_push($toBeConverterdArray, $toBeConverted); + // If UDFs are inside this result set + if ($this->udflib->isUDFColumn($eqmd->name, $eqmd->type)) + { + $udfs = true; + } + else // all the other cases + { + // Name and type of the field to be converted + $toBeConverted = new stdClass(); + // Set the type of the field to be converted + $toBeConverted->type = $eqmd->type; + // Set the name of the field to be converted + $toBeConverted->name = $eqmd->name; + // Add the field to be converted to $toBeConverterdArray + array_push($toBeConverterdArray, $toBeConverted); + } } } - // If there is something to convert, otherwhise don't lose time - if (count($toBeConverterdArray) > 0) - { - // Returns the array of objects, each of them represents a DB record - $resultsArray = $result->result(); - // Looping on results - for ($i = 0; $i < count($resultsArray); $i++) - { - // Single element - $resultElement = $resultsArray[$i]; - // Looping on fields to be converted - for ($j = 0; $j < count($toBeConverterdArray); $j++) - { - // Single element - $toBeConverted = $toBeConverterdArray[$j]; + // Returns the array of objects, each of them represents a DB record + $resultsArray = $result->result(); + // If in this result set there are UDFs then prepare them + if ($udfs) $this->udflib->prepareUDFsRead($resultsArray, $this->dbTable); + + // If there is something to convert, otherwhise don't waste time + if (!isEmptyArray($toBeConverterdArray)) + { + // Looping on results + foreach ($resultsArray as $resultElement) + { + // Looping on fields to be converted + foreach ($toBeConverterdArray as $toBeConverted) + { // Array type if (strpos($toBeConverted->type, DB_Model::PGSQL_ARRAY_TYPE) !== false) { @@ -931,30 +940,12 @@ class DB_Model extends CI_Model { $resultElement->{$toBeConverted->name} = $this->pgBoolPhp($resultElement->{$toBeConverted->name}); } - // UDF - elseif ($this->udflib->isUDFColumn($toBeConverted->name, $toBeConverted->type)) - { - $jsonValues = json_decode($resultElement->{$toBeConverted->name}); // decode UDFs values - if ($jsonValues != null) // if decode is ok - { - // For every UDF - foreach ($jsonValues as $key => $value) - { - $resultElement->{$key} = $value; // create a new element called like the UDF - } - } - unset($resultElement->{UDFLib::COLUMN_NAME}); // remove udf_values from the response - } } } - // Returns DB data as an array - $toPhp = $resultsArray; - } - // And returns DB data as an array - else - { - $toPhp = $result->result(); } + + // Returns DB data as an array + $toPhp = $resultsArray; } return $toPhp; diff --git a/application/libraries/UDFLib.php b/application/libraries/UDFLib.php index 756c382dd..26ae1ec78 100644 --- a/application/libraries/UDFLib.php +++ b/application/libraries/UDFLib.php @@ -135,7 +135,7 @@ class UDFLib $udfResults = $this->_loadUDF($schema, $table); // loads UDF definition if (hasData($udfResults)) { - $udf = $udfResults->retval[0]; // only one record is loaded + $udf = getData($udfResults)[0]; // only one record is loaded if (isset($udf->jsons)) { $jsonSchemas = json_decode($udf->jsons); // decode the json schema @@ -234,9 +234,94 @@ class UDFLib } /** - * Manage UDFs + * UDFs permissions check and convertion to read them from database */ - public function manageUDFs(&$data, $schemaAndTable, $udfValues = null) + public function prepareUDFsRead(&$data, $schemaAndTable, $udfValues = null) + { + $this->_ci->load->model('system/UDF_model', 'UDFModel'); + + // Retrieves UDFs definitions for this table + $resultUDFsDefinitions = $this->_ci->UDFModel->getUDFsDefinitions($schemaAndTable); + + // If an error occurred while reading from database + if (isError($resultUDFsDefinitions)) + { + $data = array(); // then set data as an empty array + return; // and exit from this method + } + + // If there are no UDFs defined for this table the return + if (!hasData($resultUDFsDefinitions)) return; + + // If not an error and has data, decodes json that define the UDFs for this table + $decodedUDFDefinitions = json_decode( + getData($resultUDFsDefinitions)[0]->{self::COLUMN_JSON_DESCRIPTION} + ); + + // Looping on results, resultElement is an object that represent a database record + foreach ($data as $resultElement) + { + // Decode the JSON column udf_values + $udfColumn = json_decode($resultElement->{self::COLUMN_NAME}); + + // If this is not a valid JSON then skip to the next database record + if ($udfColumn == null) continue; + + // For each UDF column of this database record + foreach (get_object_vars($udfColumn) as $columnName => $columnValue) + { + $udfColumnToBeRemoved = $columnName; // let's try to remove it + + // Loops through the UDFs definitions + foreach ($decodedUDFDefinitions as $decodedUDFDefinition) + { + // If the column exists in the UDF definition + if ($columnName == $decodedUDFDefinition->{self::NAME}) + { + $udfColumnToBeRemoved = null; // then keep it + } + } + + // If in this record have been found a _not_ defined UDF then remove it + if (!isEmptyString($udfColumnToBeRemoved)) unset($udfColumn->{$udfColumnToBeRemoved}); + } + + // Loops through the UDFs definitions + foreach ($decodedUDFDefinitions as $decodedUDFDefinition) + { + // Checks if the requiredPermissions is available and it is a valid array or a valid string + if (isset($decodedUDFDefinition->{self::REQUIRED_PERMISSIONS_PARAMETER}) + && (!isEmptyArray($decodedUDFDefinition->{self::REQUIRED_PERMISSIONS_PARAMETER}) + || !isEmptyString($decodedUDFDefinition->{self::REQUIRED_PERMISSIONS_PARAMETER}))) + { + // Then check if the user has the permissions to read such UDF + if (!$this->_readAllowed($decodedUDFDefinition->{self::REQUIRED_PERMISSIONS_PARAMETER})) + { + // If not then remove the UDF from the result set + unset($udfColumn->{$decodedUDFDefinition->{self::NAME}}); + } + } + else // If not then remove the UDF from the result set + { + unset($udfColumn->{$decodedUDFDefinition->{self::NAME}}); + } + } + + // Add the defined and permitted UDF columns to the record set + foreach (get_object_vars($udfColumn) as $columnName => $columnValue) + { + $resultElement->{$columnName} = $columnValue; + } + } + + // And finally remove the UDFs column + unset($resultElement->{self::COLUMN_NAME}); + } + + /** + * UDFs validation and permissions check to write them into database + */ + public function prepareUDFsWrite(&$data, $schemaAndTable, $udfValues = null) { $validate = success(true); // returned value // Contains a list of validation errors for the UDFs that have not passed the validation @@ -259,14 +344,12 @@ class UDFLib // Decodes json that define the UDFs for this table $decodedUDFDefinitions = json_decode( - $resultUDFsDefinitions->retval[0]->{self::COLUMN_JSON_DESCRIPTION} + getData($resultUDFsDefinitions)[0]->{self::COLUMN_JSON_DESCRIPTION} ); // Loops through the UDFs definitions - for ($i = 0; $i < count($decodedUDFDefinitions); $i++) + foreach ($decodedUDFDefinitions as $decodedUDFDefinition) { - $decodedUDFDefinition = $decodedUDFDefinitions[$i]; // Definition of a single UDF - // Checks if the requiredPermissions is available and it is a valid array or a valid string if (isset($decodedUDFDefinition->{self::REQUIRED_PERMISSIONS_PARAMETER}) && (!isEmptyArray($decodedUDFDefinition->{self::REQUIRED_PERMISSIONS_PARAMETER}) @@ -275,12 +358,14 @@ class UDFLib // Then check if the user has the permissions to write such UDF if (!$this->_writeAllowed($decodedUDFDefinition->{self::REQUIRED_PERMISSIONS_PARAMETER})) { - $notValidUDFsArray[] = error('Writing not allowed for UDF: '.$decodedUDFDefinition->{self::NAME}); + // If the logged user has no permissions then remove the UDF + unset($udfsParameters[$decodedUDFDefinition->{self::NAME}]); } } else { - $notValidUDFsArray[] = error('Writing permissions not defined for UDF: '.$decodedUDFDefinition->{self::NAME}); + // If no permissions have been defined for this UDF then remove it + unset($udfsParameters[$decodedUDFDefinition->{self::NAME}]); } // Loops through the UDFs values that should be stored @@ -378,11 +463,11 @@ class UDFLib } // If the validation of all the supplied UDFs is ok - if (count($notValidUDFsArray) == 0) + if (isEmptyArray($notValidUDFsArray)) { // An update is performed, then in this case it preserves the values // of the UDF that are not updated - if (is_array($udfValues) && count($udfValues) > 0) + if (!isEmptyArray($udfValues)) { foreach ($udfValues as $fieldName => $fieldValue) { @@ -413,7 +498,7 @@ class UDFLib /** * isUDFColumn */ - public function isUDFColumn($columnName, $columnType) + public function isUDFColumn($columnName, $columnType = self::COLUMN_TYPE) { $isUDFColumn = false; @@ -558,9 +643,21 @@ class UDFLib */ private function _readAllowed($requiredPermissions) { - $this->_ci->load->library('PermissionLib'); // Load permission library + $readAllowed = false; - return $this->_ci->permissionlib->hasAtLeastOne($requiredPermissions, self::PERMISSION_TABLE_METHOD, self::PERMISSION_TYPE_READ); + // If the user is logged then it is possible to check the permissions + if (isLogged()) + { + $this->_ci->load->library('PermissionLib'); // Load permission library + + $readAllowed = $this->_ci->permissionlib->hasAtLeastOne( + $requiredPermissions, + self::PERMISSION_TABLE_METHOD, + self::PERMISSION_TYPE_READ + ); + } // otherwise it is not possible to check the permissions + + return $readAllowed; } /** @@ -569,9 +666,21 @@ class UDFLib */ private function _writeAllowed($requiredPermissions) { - $this->_ci->load->library('PermissionLib'); // Load permission library + $writeAllowed = false; - return $this->_ci->permissionlib->hasAtLeastOne($requiredPermissions, self::PERMISSION_TABLE_METHOD, self::PERMISSION_TYPE_WRITE); + // If the user is logged then it is possible to check the permissions + if (isLogged()) + { + $this->_ci->load->library('PermissionLib'); // Load permission library + + $writeAllowed = $this->_ci->permissionlib->hasAtLeastOne( + $requiredPermissions, + self::PERMISSION_TABLE_METHOD, + self::PERMISSION_TYPE_WRITE + ); + } // otherwise it is not possible to check the permissions + + return $writeAllowed; } /** @@ -624,12 +733,12 @@ class UDFLib { $udfsParameters = array(); - foreach ($data as $key => $val) + foreach ($data as $columnName => $columnValue) { - if (substr($key, 0, 4) == self::COLUMN_PREFIX) + if ($this->isUDFColumn($columnName)) { - $udfsParameters[$key] = $val; // stores UDF value into property UDFs - unset($data[$key]); // remove from data + $udfsParameters[$columnName] = $columnValue; // stores UDF value into property UDFs + unset($data[$columnName]); // remove from data } } @@ -726,10 +835,7 @@ class UDFLib } // If no UDF validation errors were raised, it's a success!! - if (count($returnArrayValidation) == 0) - { - $returnArrayValidation = success(true); - } + if (isEmptyArray($returnArrayValidation)) $returnArrayValidation = success(true); return $returnArrayValidation; } @@ -799,18 +905,7 @@ class UDFLib if (isError($udfResults)) { - if (is_object($udfResults) && isset($udfResults->retval)) - { - show_error(getError($udfResults)); - } - elseif (is_string($udfResults)) - { - show_error($udfResults); - } - else - { - show_error('UDFWidget: generic error occurred'); - } + show_error(getError($udfResults)); } elseif (!hasData($udfResults)) { @@ -888,7 +983,7 @@ class UDFLib $queryResult = $this->_ci->UDFModel->execReadOnlyQuery($jsonSchema->{self::LIST_VALUES}->sql); if (hasData($queryResult)) { - $parameters = $queryResult->retval; + $parameters = getData($queryResult); } } @@ -989,7 +1084,7 @@ class UDFLib ); if (hasData($tmpResult)) { - $htmlParameters[HTMLWidget::LABEL] = $tmpResult->retval[0]->text; + $htmlParameters[HTMLWidget::LABEL] = getData($tmpResult)[0]->text; } } @@ -1007,7 +1102,7 @@ class UDFLib ); if (hasData($tmpResult)) { - $htmlParameters[HTMLWidget::TITLE] = $tmpResult->retval[0]->text; + $htmlParameters[HTMLWidget::TITLE] = getData($tmpResult)[0]->text; } } @@ -1025,7 +1120,7 @@ class UDFLib ); if (hasData($tmpResult)) { - $htmlParameters[HTMLWidget::PLACEHOLDER] = $tmpResult->retval[0]->text; + $htmlParameters[HTMLWidget::PLACEHOLDER] = getData($tmpResult)[0]->text; } } }