From: Marcin Haba Date: Mon, 5 Dec 2022 14:03:59 +0000 (+0100) Subject: baculum: Add group_limit, order_by and order_direction parameters to objects endpoint X-Git-Tag: Release-13.0.2~42 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bae2036f80e66128d0f32b1b7c37ce3fc99c8cbf;p=thirdparty%2Fbacula.git baculum: Add group_limit, order_by and order_direction parameters to objects endpoint --- diff --git a/gui/baculum/protected/API/Modules/Database.php b/gui/baculum/protected/API/Modules/Database.php index a94248dcc..b9bedb92b 100644 --- a/gui/baculum/protected/API/Modules/Database.php +++ b/gui/baculum/protected/API/Modules/Database.php @@ -213,5 +213,33 @@ class Database extends APIModule { } return array('where' => $where, 'params' => $parameters); } + + /** + * Group database records by specific column. + * + * @param string $group_by column to use as group + * @param array $result database results/records (please note - reference) + * @param integer $group_limit group limit (zero means no limit) + */ + public static function groupBy($group_by, &$result, $group_limit = 0) { + if (is_string($group_by) && is_array($result)) { + // Group results + $new_result = []; + for ($i = 0; $i < count($result); $i++) { + if (!property_exists($result[$i], $group_by)) { + continue; + } + if (!key_exists($result[$i]->{$group_by}, $new_result)) { + $new_result[$result[$i]->{$group_by}] = []; + } + if ($group_limit > 0 && count($new_result[$result[$i]->{$group_by}]) >= $group_limit) { + // limit per group reached + continue; + } + $new_result[$result[$i]->{$group_by}][] = $result[$i]; + } + $result = $new_result; + } + } } ?> diff --git a/gui/baculum/protected/API/Modules/ObjectManager.php b/gui/baculum/protected/API/Modules/ObjectManager.php index 73f15ac22..39043bbcb 100644 --- a/gui/baculum/protected/API/Modules/ObjectManager.php +++ b/gui/baculum/protected/API/Modules/ObjectManager.php @@ -29,18 +29,36 @@ namespace Baculum\API\Modules; * @category Module * @package Baculum API */ -class ObjectManager extends APIModule { +class ObjectManager extends APIModule +{ - public function getObjects($criteria = array(), $limit_val = null, $groupby = null) { - $sort_col = 'ObjectId'; + /** + * Get objects. + * + * @param array $criteria criteria in nested array format (@see Databaes::getWhere) + * @param integer $limit_val maximum number of elements to return + * @param string $sort_col column to sort + * @param string $sort_order sort order (asc - ascending, desc - descending) + * @param string $group_by column to group + * @param integer $group_limit maximum number of elements in one group + * @return array object list + */ + public function getObjects($criteria = array(), $limit_val = null, $sort_col = 'ObjectId', $sort_order = 'DESC', $group_by = null, $group_limit = 0) { $db_params = $this->getModule('api_config')->getConfig('db'); if ($db_params['type'] === Database::PGSQL_TYPE) { $sort_col = strtolower($sort_col); } - $order = ' ORDER BY ' . $sort_col . ' DESC'; + $order = sprintf( + ' ORDER BY %s %s', + $sort_col, + $sort_order + ); $limit = ''; if(is_int($limit_val) && $limit_val > 0) { - $limit = ' LIMIT ' . $limit_val; + $limit = sprintf( + ' LIMIT %s', + $limit_val + ); } $where = Database::getWhere($criteria); @@ -52,20 +70,7 @@ LEFT JOIN Job USING (JobId) ' . $where['where'] . $order . $limit; $result = ObjectRecord::finder()->findAllBySql($sql, $where['params']); - if (is_string($groupby) && is_array($result)) { - // Group results - $new_result = []; - for ($i = 0; $i < count($result); $i++) { - if (!property_exists($result[$i], $groupby)) { - continue; - } - if (!key_exists($result[$i]->{$groupby}, $new_result)) { - $new_result[$result[$i]->{$groupby}] = []; - } - $new_result[$result[$i]->{$groupby}][] = $result[$i]; - } - $result = $new_result; - } + Database::groupBy($group_by, $result, $group_limit); return $result; } diff --git a/gui/baculum/protected/API/Pages/API/Jobs.php b/gui/baculum/protected/API/Pages/API/Jobs.php index 06ec3b6e9..4c101d1ed 100644 --- a/gui/baculum/protected/API/Pages/API/Jobs.php +++ b/gui/baculum/protected/API/Pages/API/Jobs.php @@ -238,8 +238,13 @@ class Jobs extends BaculumAPIServer { } if ($error === false) { - $jobs = $this->getModule('job')->getJobs($params, $limit, $order_by, $order_direction); - $this->output = $jobs; + $result = $this->getModule('job')->getJobs( + $params, + $limit, + $order_by, + $order_direction + ); + $this->output = $result; $this->error = JobError::ERROR_NO_ERRORS; } } else { diff --git a/gui/baculum/protected/API/Pages/API/Objects.php b/gui/baculum/protected/API/Pages/API/Objects.php index 37be7fca2..97e1b9fdb 100644 --- a/gui/baculum/protected/API/Pages/API/Objects.php +++ b/gui/baculum/protected/API/Pages/API/Objects.php @@ -43,7 +43,8 @@ class Objects extends BaculumAPIServer { $objectstatus = $this->Request->contains('objectstatus') && $misc->isValidState($this->Request['objectstatus']) ? $this->Request['objectstatus'] : null; $jobname = $this->Request->contains('jobname') && $misc->isValidName($this->Request['jobname']) ? $this->Request['jobname'] : null; $jobids = $this->Request->contains('jobids') && $misc->isValidIdsList($this->Request['jobids']) ? explode(',', $this->Request['jobids']) : []; - $groupby = $this->Request->contains('groupby') && $misc->isValidColumn($this->Request['groupby']) ? strtolower($this->Request['groupby']) : null; + $group_by = $this->Request->contains('groupby') && $misc->isValidColumn($this->Request['groupby']) ? strtolower($this->Request['groupby']) : null; + $group_limit = $this->Request->contains('group_limit') ? intval($this->Request['group_limit']) : 0; $schedtime_from = $this->Request->contains('schedtime_from') && $misc->isValidInteger($this->Request['schedtime_from']) ? (int)$this->Request['schedtime_from'] : null; $schedtime_to = $this->Request->contains('schedtime_to') && $misc->isValidInteger($this->Request['schedtime_to']) ? (int)$this->Request['schedtime_to'] : null; $starttime_from = $this->Request->contains('starttime_from') && $misc->isValidInteger($this->Request['starttime_from']) ? (int)$this->Request['starttime_from'] : null; @@ -52,14 +53,16 @@ class Objects extends BaculumAPIServer { $endtime_to = $this->Request->contains('endtime_to') && $misc->isValidInteger($this->Request['endtime_to']) ? (int)$this->Request['endtime_to'] : null; $realendtime_from = $this->Request->contains('realendtime_from') && $misc->isValidInteger($this->Request['realendtime_from']) ? (int)$this->Request['realendtime_from'] : null; $realendtime_to = $this->Request->contains('realendtime_to') && $misc->isValidInteger($this->Request['realendtime_to']) ? (int)$this->Request['realendtime_to'] : null; + $order_by = $this->Request->contains('order_by') && $misc->isValidColumn($this->Request['order_by']) ? $this->Request['order_by']: 'ObjectId'; + $order_direction = $this->Request->contains('order_direction') && $misc->isValidOrderDirection($this->Request['order_direction']) ? $this->Request['order_direction']: 'DESC'; - if (is_string($groupby)) { - $or = new \ReflectionClass('Baculum\API\Modules\ObjectRecord'); - $group_cols = $or->getProperties(); - - $cols_excl = ['jobname']; + $or = new \ReflectionClass('Baculum\API\Modules\ObjectRecord'); + $prop_cols = $or->getProperties(); + $cols_excl = ['jobname']; + $columns = []; + if (is_string($group_by)) { $columns = []; - foreach ($group_cols as $cols) { + foreach ($prop_cols as $cols) { $name = $cols->getName(); // skip columns not existing in the catalog if (in_array($name, $cols_excl)) { @@ -68,13 +71,30 @@ class Objects extends BaculumAPIServer { $columns[] = $name; } - if (!in_array($groupby, $columns)) { + if (!in_array($group_by, $columns)) { $this->output = ObjectError::MSG_ERROR_INVALID_PROPERTY; $this->error = ObjectError::ERROR_INVALID_PROPERTY; return; } } + $order_by_lc = strtolower($order_by); + $columns = []; + foreach ($prop_cols as $cols) { + $name = $cols->getName(); + // skip columns not existing in the catalog + if (in_array($name, $cols_excl)) { + continue; + } + $columns[] = $name; + } + if (!in_array($order_by_lc, $columns)) { + $this->output = ObjectError::MSG_ERROR_INVALID_PROPERTY; + $this->error = ObjectError::ERROR_INVALID_PROPERTY; + return; + } + + $params = []; if (!empty($objecttype)) { $params['Object.ObjectType'] = []; @@ -194,7 +214,14 @@ class Objects extends BaculumAPIServer { } } - $objects = $this->getModule('object')->getObjects($params, $limit, $groupby); + $objects = $this->getModule('object')->getObjects( + $params, + $limit, + $order_by_lc, + $order_direction, + $group_by, + $group_limit + ); $this->output = $objects; $this->error = ObjectError::ERROR_NO_ERRORS; } diff --git a/gui/baculum/protected/API/openapi_baculum.json b/gui/baculum/protected/API/openapi_baculum.json index 88033bba4..bbad2f0b1 100644 --- a/gui/baculum/protected/API/openapi_baculum.json +++ b/gui/baculum/protected/API/openapi_baculum.json @@ -6503,6 +6503,34 @@ "type": "string" } }, + { + "name": "group_limit", + "in": "query", + "required": false, + "description": "Maximum number elements per group.", + "schema": { + "type": "string" + } + }, + { + "name": "order_by", + "in": "query", + "required": false, + "description": "Sort by selected object property (default objectid). There can be any object property (objectid, objectname, objectsource ...etc.) except jobname.", + "schema": { + "type": "string" + } + }, + { + "name": "order_direction", + "in": "query", + "required": false, + "description": "Order direction. It can be 'asc' (ascending order) or 'desc' (descending order - default)", + "schema": { + "type": "string", + "enum": ["asc", "desc"] + } + }, { "name": "schedtime_from", "in": "query",