]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
baculum: Add group_limit, order_by and order_direction parameters to objects endpoint
authorMarcin Haba <marcin.haba@bacula.pl>
Mon, 5 Dec 2022 14:03:59 +0000 (15:03 +0100)
committerMarcin Haba <marcin.haba@bacula.pl>
Mon, 9 Jan 2023 12:34:42 +0000 (13:34 +0100)
gui/baculum/protected/API/Modules/Database.php
gui/baculum/protected/API/Modules/ObjectManager.php
gui/baculum/protected/API/Pages/API/Jobs.php
gui/baculum/protected/API/Pages/API/Objects.php
gui/baculum/protected/API/openapi_baculum.json

index a94248dccc4849fb1041f32a39f0f3b7416fdfd9..b9bedb92b41c5df019a9379c6e6392149cf1821b 100644 (file)
@@ -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;
+               }
+       }
 }
 ?>
index 73f15ac2246953af22fa80e52281291eca45dd43..39043bbcbd82890377aab7d1319116aa35c04fed 100644 (file)
@@ -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;
        }
 
index 06ec3b6e95aa4889961169c4f71d267f048c61fd..4c101d1ed8055bd51aac8d2b479adbdc6afa6973 100644 (file)
@@ -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 {
index 37be7fca21f09b7d2f0883d2d2227266549a22cf..97e1b9fdbee94acd7eb70ea2925bf21d2f826af8 100644 (file)
@@ -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;
        }
index 88033bba4a4701beaf28d364c6c0407a898604b8..bbad2f0b17f0ef68eef0edb770005d15727511c9 100644 (file)
                                                        "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",