$cond[] = "{$key} {$value[$i]['operator']} :{$kval}{$i}";
$vals[":{$kval}{$i}"] = $value[$i]['vals'];
$value[$i]['operator'] = '';
+ } elseif (in_array($value[$i]['operator'], ['IS', 'IS NOT'])) {
+ $cond[] = "{$key} {$value[$i]['operator']} {$value[$i]['vals']}";
+ $value[$i]['operator'] = '';
} else {
$cond[] = "$key = :{$kval}{$i}";
$vals[":{$kval}{$i}"] = $value[$i]['vals'];
--- /dev/null
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum - Bacula web interface
+ *
+ * Copyright (C) 2013-2022 Kern Sibbald
+ *
+ * The main author of Baculum is Marcin Haba.
+ * The original author of Bacula is Kern Sibbald, with contributions
+ * from many others, a complete list can be found in the file AUTHORS.
+ *
+ * You may use this file and others of this release according to the
+ * license defined in the LICENSE file, which includes the Affero General
+ * Public License, v3.0 ("AGPLv3") and some additional permissions and
+ * terms pursuant to its AGPLv3 Section 7.
+ *
+ * This notice must be preserved when any source code is
+ * conveyed and/or propagated.
+ *
+ * Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+
+namespace Baculum\API\Modules;
+
+/**
+ * Source (client + fileset + job) manager module.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Module
+ * @package Baculum API
+ */
+class SourceManager extends APIModule {
+
+ public function getSources($criteria = [], $limit_val = null) {
+ $limit = '';
+ if(is_int($limit_val) && $limit_val > 0) {
+ $limit = ' LIMIT ' . $limit_val;
+ }
+ $where = Database::getWhere($criteria, true);
+ $sql = 'SELECT
+ sres.fileset, sres.client, sres.job, ores.starttime, ores.jobid, jres.jobstatus
+ FROM Job AS jres,
+ (
+ SELECT DISTINCT
+ FileSet.FileSet AS fileset,
+ Client.Name AS client,
+ Job.Name AS job
+ FROM Job
+ JOIN FileSet USING (FileSetId)
+ JOIN Client USING (ClientId)
+ ) AS sres, (
+ SELECT
+ MAX(StartTime) AS starttime,
+ MAX(JobId) AS jobid,
+ FileSet.FileSet AS fileset,
+ Client.Name AS client,
+ Job.Name AS job
+ FROM Job
+ JOIN FileSet USING (FileSetId)
+ JOIN Client USING (ClientId)
+ GROUP BY FileSet.FileSet, Client.Name, Job.Name
+ ) AS ores
+ LEFT JOIN Object USING (JobId)
+ WHERE
+ jres.JobId = ores.jobid
+ AND sres.job = ores.job
+ AND sres.client = ores.client
+ AND sres.fileset = ores.fileset
+ AND jres.Type = \'B\'
+ ' . (!empty($where['where']) ? ' AND ' . $where['where'] : '') . '
+ ORDER BY sres.fileset ASC, sres.client ASC, sres.job ASC, ores.starttime ASC ' . $limit;
+
+ $connection = SourceRecord::finder()->getDbConnection();
+ $connection->setActive(true);
+ $pdo = $connection->getPdoInstance();
+ $sth = $pdo->prepare($sql);
+ $sth->execute($where['params']);
+ return $sth->fetchAll(\PDO::FETCH_ASSOC);
+ }
+}
+?>
--- /dev/null
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum - Bacula web interface
+ *
+ * Copyright (C) 2013-2022 Kern Sibbald
+ *
+ * The main author of Baculum is Marcin Haba.
+ * The original author of Bacula is Kern Sibbald, with contributions
+ * from many others, a complete list can be found in the file AUTHORS.
+ *
+ * You may use this file and others of this release according to the
+ * license defined in the LICENSE file, which includes the Affero General
+ * Public License, v3.0 ("AGPLv3") and some additional permissions and
+ * terms pursuant to its AGPLv3 Section 7.
+ *
+ * This notice must be preserved when any source code is
+ * conveyed and/or propagated.
+ *
+ * Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+
+namespace Baculum\API\Modules;
+
+/**
+ * Source (job + client + fileset) record module.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Database
+ * @package Baculum API
+ */
+class SourceRecord extends APIDbModule {
+
+ const TABLE = 'Job';
+
+ public $fileset;
+ public $client;
+ public $job;
+ public $endtime;
+ public $jobid;
+ public $jobstatus;
+
+ public static function finder($className = __CLASS__) {
+ return parent::finder($className);
+ }
+}
--- /dev/null
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum - Bacula web interface
+ *
+ * Copyright (C) 2013-2022 Kern Sibbald
+ *
+ * The main author of Baculum is Marcin Haba.
+ * The original author of Bacula is Kern Sibbald, with contributions
+ * from many others, a complete list can be found in the file AUTHORS.
+ *
+ * You may use this file and others of this release according to the
+ * license defined in the LICENSE file, which includes the Affero General
+ * Public License, v3.0 ("AGPLv3") and some additional permissions and
+ * terms pursuant to its AGPLv3 Section 7.
+ *
+ * This notice must be preserved when any source code is
+ * conveyed and/or propagated.
+ *
+ * Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+
+use Baculum\API\Modules\BaculumAPIServer;
+use Baculum\Common\Modules\Errors\SourceError;
+
+/**
+ * Sources endpoint.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category API
+ * @package Baculum API
+ */
+class Sources extends BaculumAPIServer {
+
+ public function get() {
+ $misc = $this->getModule('misc');
+ $limit = $this->Request->contains('limit') ? (int)$this->Request['limit'] : 0;
+ $job = $this->Request->contains('job') && $misc->isValidName($this->Request['job']) ? $this->Request['job'] : '';
+ $client = $this->Request->contains('client') && $misc->isValidName($this->Request['client']) ? $this->Request['client'] : '';
+ $fileset = $this->Request->contains('fileset') && $misc->isValidName($this->Request['fileset']) ? $this->Request['fileset'] : '';
+ $starttime_from = $this->Request->contains('starttime_from') && $misc->isValidInteger($this->Request['starttime_from']) ? (int)$this->Request['starttime_from'] : null;
+ $starttime_to = $this->Request->contains('starttime_to') && $misc->isValidInteger($this->Request['starttime_to']) ? (int)$this->Request['starttime_to'] : null;
+ $jobstatus = $this->Request->contains('jobstatus') && $misc->isValidState($this->Request['jobstatus']) ? $this->Request['jobstatus'] : '';
+ $hasobject = $this->Request->contains('hasobject') && $misc->isValidBoolean($this->Request['hasobject']) ? $this->Request['hasobject'] : null;
+
+ // @TODO: Fix using sres and jres in this place. It can lead to a problem when sres or jres will be changed in manager.
+ $params = [];
+ if (!empty($job)) {
+ $params['sres.job'] = [[
+ 'vals' => $job
+ ]];
+ }
+ if (!empty($client)) {
+ $params['sres.client'] = [[
+ 'vals' => $client
+ ]];
+ }
+ if (!empty($fileset)) {
+ $params['sres.fileset'] = [[
+ 'vals' => $fileset
+ ]];
+ }
+ if (!empty($jobstatus)) {
+ $params['jres.jobstatus'] = [[
+ 'vals' => $jobstatus
+ ]];
+ }
+ if (!is_null($hasobject)) {
+ if ($misc->isValidBooleanTrue($hasobject)) {
+ $params['Object.ObjectId'][] = [
+ 'operator' => 'IS NOT',
+ 'vals' => 'NULL'
+ ];
+ } elseif ($misc->isValidBooleanFalse($hasobject)) {
+ $params['Object.ObjectId'][] = [
+ 'operator' => 'IS',
+ 'vals' => 'NULL'
+ ];
+ }
+ }
+
+ // Start time range
+ if (!empty($starttime_from) || !empty($starttime_to)) {
+ $params['ores.starttime'] = [];
+ if (!empty($starttime_from)) {
+ $params['ores.starttime'][] = [
+ 'operator' => '>=',
+ 'vals' => date('Y-m-d H:i:s', $starttime_from)
+ ];
+ }
+ if (!empty($starttime_to)) {
+ $params['ores.starttime'][] = [
+ 'operator' => '<=',
+ 'vals' => date('Y-m-d H:i:s', $starttime_to)
+ ];
+ }
+ }
+
+ $sources = $this->getModule('source')->getSources($params, $limit);
+ $this->output = $sources;
+ $this->error = SourceError::ERROR_NO_ERRORS;
+ }
+}
+?>
<module id="volume" class="Baculum\API\Modules\VolumeManager" />
<module id="object" class="Baculum\API\Modules\ObjectManager" />
<module id="event" class="Baculum\API\Modules\EventManager" />
+ <module id="source" class="Baculum\API\Modules\SourceManager" />
<!-- tools modules -->
<module id="bconsole" class="Baculum\API\Modules\Bconsole" />
<module id="json_tools" class="Baculum\API\Modules\JSONTools" />
<!-- event endpoints -->
<url ServiceParameter="Events" pattern="api/v2/events/" />
<url ServiceParameter="Event" pattern="api/v2/events/{id}" parameters.id="\d+" />
+ <!-- source endpoints -->
+ <url ServiceParameter="Sources" pattern="api/v2/sources/" />
<!-- @TODO: Separate this endpoint outside 'joblog' -->
<url ServiceParameter="Messages" pattern="api/v2/joblog/messages" />
<!-- fileset endpoints -->
"Object": {
"$ref": "#/definitions/Object"
},
+ "Sources": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Source"
+ }
+ },
+ "Source": {
+ "$ref": "#/definitions/Source"
+ },
"Events": {
"type": "array",
"items": {
]
}
},
+ "/api/v2/sources": {
+ "get": {
+ "tags": ["sources"],
+ "summary": "Source list",
+ "description": "Get source list.",
+ "responses": {
+ "200": {
+ "description": "List of sources",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "output": {
+ "$ref": "#/components/schemas/Sources"
+ },
+ "error": {
+ "type": "integer",
+ "description": "Error code",
+ "enum": [0, 1, 2, 3, 6, 7, 1000]
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/Limit"
+ },
+ {
+ "name": "job",
+ "in": "query",
+ "required": false,
+ "description": "Job name filter",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "client",
+ "in": "query",
+ "required": false,
+ "description": "Client name filter",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "fileset",
+ "in": "query",
+ "required": false,
+ "description": "Fileset name filter",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "starttime_from",
+ "in": "query",
+ "required": false,
+ "description": "Start time from (UNIX timestamp format, seconds)",
+ "schema": {
+ "type": "integer"
+ }
+ },
+ {
+ "name": "starttime_to",
+ "in": "query",
+ "required": false,
+ "description": "Start time to (UNIX timestamp format, seconds)",
+ "schema": {
+ "type": "integer"
+ }
+ },
+ {
+ "name": "jobstatus",
+ "in": "query",
+ "required": false,
+ "description": "Job status letter",
+ "schema": {
+ "type": "string",
+ "enum": ["C", "R", "B", "T", "W", "E", "e", "f", "D", "A", "I", "F", "S", "m", "M", "s", "j", "c", "d", "t", "p", "i", "a", "l", "L"]
+ }
+ },
+ {
+ "name": "hasobject",
+ "in": "query",
+ "required": false,
+ "description": "Show sources that have object, 1 - show sources with objects created, 0 - show sources without objects created",
+ "schema": {
+ "type": "boolean"
+ }
+ }
+ ]
+ }
+ },
"/api/v2/events": {
"get": {
"tags": ["events"],
}
}
},
+ "Source": {
+ "type": "object",
+ "properties": {
+ "fileset": {
+ "description": "Fileset name",
+ "type": "string"
+ },
+ "client": {
+ "description": "Client name",
+ "type": "string"
+ },
+ "job": {
+ "description": "Job name",
+ "type": "string"
+ },
+ "starttime": {
+ "description": "Start time latest job using this source",
+ "type": "string"
+ },
+ "jobid": {
+ "description": "Latest jobid",
+ "type": "integer"
+ },
+ "jobstatus": {
+ "description": "Job status latest job",
+ "type": "string"
+ }
+ }
+ },
"Event": {
"type": "object",
"properties": {
--- /dev/null
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum - Bacula web interface
+ *
+ * Copyright (C) 2013-2022 Kern Sibbald
+ *
+ * The main author of Baculum is Marcin Haba.
+ * The original author of Bacula is Kern Sibbald, with contributions
+ * from many others, a complete list can be found in the file AUTHORS.
+ *
+ * You may use this file and others of this release according to the
+ * license defined in the LICENSE file, which includes the Affero General
+ * Public License, v3.0 ("AGPLv3") and some additional permissions and
+ * terms pursuant to its AGPLv3 Section 7.
+ *
+ * This notice must be preserved when any source code is
+ * conveyed and/or propagated.
+ *
+ * Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+
+namespace Baculum\Common\Modules\Errors;
+
+/**
+ * Source error class.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Errors
+ * @package Baculum Common
+ */
+class SourceError extends GenericError {
+}