Baculum uses DataTables library for tables.
Files:
- protected/Web/JavaScript/datatables.js
- protected/Web/JavaScript/dataTables.responsive.js
- protected/Web/JavaScript/dataTables.buttons.js
- protected/Web/JavaScript/dataTables.select.js
- protected/Web/JavaScript/responsive.jqueryui.js
- protected/Web/JavaScript/buttons.colVis.js
- protected/Web/JavaScript/buttons.html5.js
+ protected/Common/JavaScript/datatables.js
+ protected/Common/JavaScript/dataTables.responsive.js
+ protected/Common/JavaScript/dataTables.buttons.js
+ protected/Common/JavaScript/dataTables.select.js
+ protected/Common/JavaScript/responsive.jqueryui.js
+ protected/Common/JavaScript/buttons.colVis.js
+ protected/Common/JavaScript/buttons.html5.js
themes/Baculum-v2/css/datatables.css
themes/Baculum-v2/css/responsive.dataTables.css
themes/Baculum-v2/css/buttons.dataTables.css
the client-side.
Files:
- protected/Web/JavaScript/buttons.html5.js
+ protected/Common/JavaScript/buttons.html5.js
FileSaver.js (1.3.3) - MIT license
Copyright © 2016 Eli Grey - http://eligrey.com
Baculum uses Font Awesome Free for icons.
Files:
- protected/Web/JavaScript/fontawesome.min.js
+ protected/Common/JavaScript/fontawesome.min.js
themes/Baculum-v2/css/fontawesome-all.min.css
themes/Baculum-v2/webfonts/fa-brands-400.eot
themes/Baculum-v2/webfonts/fa-brands-400.svg
apidatadirsrc = $(datadir)/$(apidir)/Class \
$(datadir)/$(apidir)/Config \
- $(datadir)/$(apidir)/JavaScript \
$(datadir)/$(apidir)/Layouts \
$(datadir)/$(apidir)/Logs \
- $(datadir)/$(apidir)/Pages
+ $(datadir)/$(apidir)/Pages \
+ $(datadir)/$(apidir)/Portlets
commondatadirsrc = $(datadir)/$(commondir)/Class \
+ $(datadir)/$(commondir)/JavaScript \
+ $(datadir)/$(commondir)/Pages \
$(datadir)/$(commondir)/Portlets
+
datafilesrc = $(datadir)/application.xml
webdatafilesrc = $(datadir)/$(webdir)/endpoints.xml \
--- /dev/null
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum - Bacula web interface
+ *
+ * Copyright (C) 2013-2021 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.
+ */
+
+/**
+ * API interfaces.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Interfaces
+ * @package Baculum API
+ */
+
+/**
+ * Defines methods to work with API Server.
+ */
+interface IAPIServer {
+
+ public function get();
+
+ public function put();
+
+ public function post();
+
+ public function delete();
+}
+?>
--- /dev/null
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum - Bacula web interface
+ *
+ * Copyright (C) 2013-2021 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.
+ */
+
+/**
+ * API Server layer.
+ * Introduces main method inherited by particular API server versions.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Module
+ * @package Baculum API
+ */
+class APIServer extends APIModule {
+
+ /**
+ * Default API version if there was not possible to determine version.
+ */
+ const DEFAULT_VERSION = 2;
+
+ const VERSION_PATTERN = '!/api/v(?P<version>\d+)/!';
+
+ /**
+ * Stores API server instance.
+ */
+ protected $server = null;
+
+ /**
+ * Set API server instance.
+ *
+ * @param BaculumAPIServer $obj server object
+ * @return none
+ */
+ public function setServerObj($obj) {
+ $this->server = $obj;
+ }
+
+ /**
+ * Get API server instance.
+ * @return BaculumAPIServer|null API server object
+ */
+ public function getServerObj() {
+ return $this->server;
+ }
+
+ /**
+ * Get requested API version from URL path.
+ *
+ * @return integer requested API version number
+ */
+ public static function getVersion() {
+ $version = self::DEFAULT_VERSION;
+ $path = Prado::getApplication()->Request->getPathInfo();
+ if (preg_match(self::VERSION_PATTERN, $path, $match) === 1) {
+ $version = intval($match['version']);
+ }
+ return $version;
+ }
+}
--- /dev/null
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum - Bacula web interface
+ *
+ * Copyright (C) 2013-2021 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.
+ */
+
+Prado::using('Application.API.Class.APIServer');
+Prado::using('Application.API.Class.APIInterfaces');
+
+/**
+ * API Server version 1.
+ * This version receives parameters as GET and POST parameters.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Module
+ * @package Baculum API
+ */
+class APIServerV1 extends APIServer implements IAPIServer {
+
+ /**
+ * Support for API GET method request.
+ *
+ * @return none;
+ */
+ public function get() {
+ $this->getServerObj()->get();
+ }
+
+ /**
+ * Support for API PUT method request.
+ *
+ * @return none
+ */
+ public function put() {
+ $id = $this->Request->contains('id') ? intval($this->Request['id']) : 0;
+ $params = new StdClass;
+
+ /**
+ * Check if it is possible to read PUT method data.
+ * Note that some clients sends data in PUT request as PHP input stream which
+ * is not possible to read by $_REQUEST data. From this reason, when is
+ * not possible to ready by superglobal $_REQUEST variable, then is try to
+ * read PUT data by PHP input stream.
+ */
+ if ($this->Request->contains('update') && is_array($this->Request['update']) && count($this->Request['update']) > 0) {
+ // $_REQUEST available to read
+ $params = (object)$this->Request['update'];
+ } else {
+ // no possibility to read data from $_REQUEST. Try to load from input stream.
+ $inputstr = file_get_contents("php://input");
+
+ /**
+ * Read using chunks for case large updates (over 1000 values).
+ * Otherwise max_input_vars limitation in php.ini can be reached (usually
+ * set to 1000 variables)
+ * @see http://php.net/manual/en/info.configuration.php#ini.max-input-vars
+ */
+ $chunks = explode('&', $inputstr);
+
+ $response_data = array();
+ for($i = 0; $i<count($chunks); $i++) {
+ // if chunks would not be used, then here occurs reach max_input_vars limit
+ parse_str($chunks[$i], $response_el);
+ if (is_array($response_el) && array_key_exists('update', $response_el) && is_array($response_el['update'])) {
+ $key = key($response_el['update']);
+ $response_data['update'][$key] = $response_el['update'][$key];
+ }
+ }
+ if (is_array($response_data) && array_key_exists('update', $response_data)) {
+ $params = (object)$response_data['update'];
+ }
+ }
+ $this->getServerObj()->set($id, $params);
+ }
+
+ /**
+ * Support for API POST method request.
+ *
+ * @return none
+ */
+ public function post() {
+ $params = new StdClass;
+ if ($this->Request->contains('create') && is_array($this->Request['create']) && count($this->Request['create']) > 0) {
+ $params = (object)$this->Request['create'];
+ }
+ $this->getServerObj()->create($params);
+ }
+
+ /**
+ * Support for API DELETE method request.
+ *
+ * @return none
+ */
+ public function delete() {
+ $id = null;
+ if ($this->Request->contains('id')) {
+ $id = $this->Request['id'];
+ }
+ $this->getServerObj()->remove($id);
+ }
+}
+?>
--- /dev/null
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum - Bacula web interface
+ *
+ * Copyright (C) 2013-2021 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.
+ */
+
+Prado::using('Application.API.Class.APIServer');
+Prado::using('Application.API.Class.APIInterfaces');
+
+/**
+ * API Server version 2.
+ * This version receives parameters as GET and POST parameters.
+ * Main difference comparing to version 1 is that POST params are sent as
+ * a JSON string in POST requests body.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Module
+ * @package Baculum API
+ */
+
+class APIServerV2 extends APIServer implements IAPIServer {
+
+ /**
+ * Support for API GET method request.
+ *
+ * @return none;
+ */
+ public function get() {
+ $this->getServerObj()->get();
+ }
+
+ /**
+ * Support for API PUT method request.
+ *
+ * @return none
+ */
+ public function put() {
+ $id = $this->Request->contains('id') ? intval($this->Request['id']) : 0;
+ $inputstr = file_get_contents("php://input");
+ $params = json_decode($inputstr);
+ if (is_null($params)) {
+ $params = new StdClass;
+ }
+ $this->getServerObj()->set($id, $params);
+ }
+
+ /**
+ * Support for API POST method request.
+ *
+ * @return none
+ */
+ public function post() {
+ $inputstr = file_get_contents("php://input");
+ $params = json_decode($inputstr);
+ if (is_null($params)) {
+ $params = new StdClass;
+ }
+ $this->getServerObj()->create($params);
+ }
+
+ /**
+ * Support for API DELETE method request.
+ *
+ * @return none
+ */
+ public function delete() {
+ $id = null;
+ if ($this->Request->contains('id')) {
+ $id = $this->Request['id'];
+ }
+ $this->getServerObj()->remove($id);
+ }
+}
+?>
* Bacula(R) - The Network Backup Solution
* Baculum - Bacula web interface
*
- * Copyright (C) 2013-2020 Kern Sibbald
+ * Copyright (C) 2013-2021 Kern Sibbald
*
* The main author of Baculum is Marcin Haba.
* The original author of Bacula is Kern Sibbald, with contributions
public function onPreInit($param) {
parent::onPreInit($param);
$config = $this->getModule('api_config')->getConfig('api');
- $lang = array_key_exists('lang', $config) ? $config['lang'] : APIConfig::DEF_LANG;
+ if (count($config) === 0) {
+ if ($this->Service->getRequestedPagePath() != 'APIInstallWizard') {
+ $this->goToPage('APIInstallWizard');
+ }
+ // without config there is no way to use API panel
+ return;
+ }
+ $lang = key_exists('lang', $config) ? $config['lang'] : APIConfig::DEF_LANG;
$this->Application->getGlobalization()->Culture = $lang;
}
}
* Bacula(R) - The Network Backup Solution
* Baculum - Bacula web interface
*
- * Copyright (C) 2013-2019 Kern Sibbald
+ * Copyright (C) 2013-2021 Kern Sibbald
*
* The main author of Baculum is Marcin Haba.
* The original author of Bacula is Kern Sibbald, with contributions
Prado::using('Application.API.Class.APIDbModule');
Prado::using('Application.API.Class.Bconsole');
Prado::using('Application.API.Class.OAuth2.TokenRecord');
+Prado::using('Application.API.Class.APIServer');
/**
* Abstract module from which inherits each of API module.
/**
* API server version (used in HTTP header)
*/
- const API_SERVER_VERSION = 0.1;
+ const API_SERVER_VERSION = 0.2;
/**
* Storing output from API commands in numeric array.
header(OAuth2::HEADER_UNAUTHORIZED);
return;
}
+ $this->runResource();
+ }
+
+ /**
+ * Run requested resource.
+ * It sets output and error values.
+ *
+ * @return none
+ */
+ private function runResource() {
+ $version = APIServer::getVersion();
+ $api = $this->getModule('api_server_v' . $version);
+ $api->setServerObj($this);
+
try {
switch($_SERVER['REQUEST_METHOD']) {
case self::GET_METHOD: {
- $this->get();
+ $api->get();
break;
}
case self::POST_METHOD: {
- $this->post();
+ $api->post();
break;
}
case self::PUT_METHOD: {
- $this->put();
+ $api->put();
break;
}
case self::DELETE_METHOD: {
- $this->delete();
+ $api->delete();
break;
}
}
$this->output = GenericError::MSG_ERROR_INTERNAL_ERROR . ' ' . $e->getErrorMessage();
$this->error = GenericError::ERROR_INTERNAL_ERROR;
}
- }
+ }
}
/**
echo $this->getOutput();
}
- /**
- * Changing/updating values via API.
- *
- * @access private
- * @return none
- */
- private function put() {
- $id = $this->Request->contains('id') ? intval($this->Request['id']) : 0;
-
- /**
- * Check if it is possible to read PUT method data.
- * Note that some clients sends data in PUT request as PHP input stream which
- * is not possible to read by $_REQUEST data. From this reason, when is
- * not possible to ready by superglobal $_REQUEST variable, then is try to
- * read PUT data by PHP input stream.
- */
- if ($this->Request->contains('update') && is_array($this->Request['update']) && count($this->Request['update']) > 0) {
- // $_REQUEST available to read
- $params = (object)$this->Request['update'];
- $this->set($id, $params);
- } else {
- // no possibility to read data from $_REQUEST. Try to load from input stream.
- $inputstr = file_get_contents("php://input");
-
- /**
- * Read using chunks for case large updates (over 1000 values).
- * Otherwise max_input_vars limitation in php.ini can be reached (usually
- * set to 1000 variables)
- * @see http://php.net/manual/en/info.configuration.php#ini.max-input-vars
- */
- $chunks = explode('&', $inputstr);
-
- $response_data = array();
- for($i = 0; $i<count($chunks); $i++) {
- // if chunks would not be used, then here occurs reach max_input_vars limit
- parse_str($chunks[$i], $response_el);
- if (is_array($response_el) && array_key_exists('update', $response_el) && is_array($response_el['update'])) {
- $key = key($response_el['update']);
- $response_data['update'][$key] = $response_el['update'][$key];
- }
- }
- if (is_array($response_data) && array_key_exists('update', $response_data)) {
- $params = (object)$response_data['update'];
- $this->set($id, $params);
- } else {
- /**
- * This case should never occur because it means that there is
- * given nothing to update.
- */
- $params = new stdClass;
- $this->set($id, $params);
- }
- }
- }
-
- /**
- * Creating new elements.
- *
- * @access private
- * @return none
- */
- private function post() {
- $params = new stdClass;
- if ($this->Request->contains('create') && is_array($this->Request['create']) && count($this->Request['create']) > 0) {
- $params = (object)$this->Request['create'];
- }
- $this->create($params);
- }
-
- /**
- * Deleting element by element ID.
- *
- * @access private
- * @return none
- */
- private function delete() {
- $id = null;
- if ($this->Request->contains('id')) {
- $id = $this->Request['id'];
- }
- $this->remove($id);
- }
-
/**
* Shortcut method for getting application modules instances by
* module name.
* Bacula(R) - The Network Backup Solution
* Baculum - Bacula web interface
*
- * Copyright (C) 2013-2019 Kern Sibbald
+ * Copyright (C) 2013-2021 Kern Sibbald
*
* The main author of Baculum is Marcin Haba.
* The original author of Bacula is Kern Sibbald, with contributions
);
if ($result->exitcode === 0) {
$ret['output'] = $this->parseStatus($result->output, $type);
+ $ret['error'] = $result->exitcode;
} else {
$ret['output'] = $result->output;
+ $ret['error'] = GenericError::ERROR_WRONG_EXITCODE;
}
- $ret['error'] = $result->exitcode;
return $ret;
}
+++ /dev/null
-var get_random_string = function(allowed, len) {
- var random_string = "";
- for(var i = 0; i < len; i++) {
- random_string += allowed.charAt(Math.floor(Math.random() * allowed.length));
- }
- return random_string;
-}
-
-var OAuth2Scopes = [
- 'console',
- 'jobs',
- 'directors',
- 'clients',
- 'storages',
- 'volumes',
- 'pools',
- 'bvfs',
- 'joblog',
- 'filesets',
- 'schedules',
- 'config',
- 'status',
- 'actions',
- 'oauth2'
-];
-var set_scopes = function(field_id) {
- document.getElementById(field_id).value = OAuth2Scopes.join(' ');
-}
msgid "select language"
msgstr "select language"
-msgid "« Previous"
-msgstr "« Previous"
+msgid "Previous"
+msgstr "Previous"
msgid "Cancel"
msgstr "Cancel"
-msgid "Next »"
-msgstr "Next »"
+msgid "Next"
+msgstr "Next"
msgid "Step 1 - select language"
msgstr "Step 1 - select language"
msgid "Save"
msgstr "Save"
-msgid "Step 7 - Finish"
-msgstr "Step 7 - Finish"
+msgid "Step 6 - Finish"
+msgstr "Step 6 - Finish"
msgid "Use sudo for Bacula JSON tools:"
msgstr "Use sudo for Bacula JSON tools:"
msgid "Refresh token"
msgstr "Refresh token"
-msgid "New HTTP Basic user"
-msgstr "New HTTP Basic user"
-
msgid "New OAuth2 client"
msgstr "New OAuth2 client"
msgid "Given user already exists in config file."
msgstr "Given user already exists in config file."
-msgid "List HTTP Basic users"
-msgstr "List HTTP Basic users"
-
-msgid "List OAuth2 clients"
-msgstr "List OAuth2 clients"
-
msgid "set all scopes"
msgstr "set all scopes"
-msgid "Go to configuration wizard"
-msgstr "Go to configuration wizard"
-
msgid "Welcome on the Baculum API default page"
msgstr "Welcome on the Baculum API default page"
msgid "Authentication type:"
msgstr "Authentication type:"
-msgid "Step 6 - authentication to API"
-msgstr "Step 6 - authentication to API"
+msgid "Step 5 - authentication to API"
+msgstr "Step 5 - authentication to API"
msgid "Actions"
msgstr "Actions"
msgid "Please use visudo to add this configuration, otherwise please do remember to add empty line at the end of file."
msgstr "Please use visudo to add this configuration, otherwise please do remember to add empty line at the end of file."
+msgid "Dashboard"
+msgstr "Dashboard"
+
+msgid "Basic users"
+msgstr "Basic users"
+
+msgid "OAuth2 clients"
+msgstr "OAuth2 clients"
+
+msgid "Settings"
+msgstr "Settings"
+
+msgid "Configuration wizard"
+msgstr "Configuration wizard"
+
+msgid "Welcome"
+msgstr "Welcome"
+
+msgid "Add user"
+msgstr "Add user"
+
+msgid "Edit user"
+msgstr "Edit user"
+
+msgid "Add OAuth2 client"
+msgstr "Add OAuth2 client"
+
+msgid "Are you sure?"
+msgstr "Are you sure?"
+
+msgid "API settings"
+msgstr "API settings"
+
+msgid "General"
+msgstr "General"
+
+msgid "Catalog"
+msgstr "Catalog"
+
+msgid "Console"
+msgstr "Console"
+
+msgid "Config"
+msgstr "Config"
+
+msgid "Enabled:"
+msgstr "Enabled:"
+
+msgid "Debug:"
+msgstr "Debug:"
+
+msgid "Add client"
+msgstr "Add client"
+
+msgid "Edit client"
+msgstr "Edit client"
+
+msgid "Invalid user. User may contain a-z A-Z 0-9 characters."
+msgstr "Invalid user. User may contain a-z A-Z 0-9 characters."
+
+msgid "Show/hide"
+msgstr "Show/hide"
+
+msgid "Copy to clipboard"
+msgstr "Copy to clipboard"
+
+msgid "Logout"
+msgstr "Logout"
msgid "select language"
msgstr "wybierz język"
-msgid "« Previous"
-msgstr "« Wstecz"
+msgid "Previous"
+msgstr "Wstecz"
msgid "Cancel"
msgstr "Anuluj"
-msgid "Next »"
-msgstr "Dalej »"
+msgid "Next"
+msgstr "Dalej"
msgid "Step 1 - select language"
msgstr "Krok 1 - wybierz język"
msgid "Save"
msgstr "Zapisz"
-msgid "Step 7 - Finish"
-msgstr "Krok 7 - Koniec"
+msgid "Step 6 - Finish"
+msgstr "Krok 6 - Koniec"
msgid "Use sudo for Bacula JSON tools:"
msgstr "Użyj sudo dla narzędzi JSON Bacula."
msgid "Refresh token"
msgstr "Odśwież żeton"
-msgid "New HTTP Basic user"
-msgstr "Nowy użytkownik HTTP Basic"
-
msgid "New OAuth2 client"
msgstr "Nowy klient OAuth2"
msgid "Given user already exists in config file."
msgstr "Podany użytkownik już istnieje w pliku konfiguracyjnym."
-msgid "List HTTP Basic users"
-msgstr "Lista użytkowników HTTP Basic"
-
-msgid "List OAuth2 clients"
-msgstr "Lista klientów OAuth2"
-
msgid "set all scopes"
msgstr "ustaw wszystkie zakresy"
-msgid "Go to configuration wizard"
-msgstr "Idź do przewodnika konfiguracji"
-
msgid "Welcome on the Baculum API default page"
msgstr "Witaj na stronie głównej Baculum API"
msgid "Authentication type:"
msgstr "Typ uwierzytelniania:"
-msgid "Step 6 - authentication to API"
-msgstr "Krok 6 - uwierzytelnianie do API"
+msgid "Step 5 - authentication to API"
+msgstr "Krok 5 - uwierzytelnianie do API"
msgid "Actions"
msgstr "Akcje"
msgid "Please use visudo to add this configuration, otherwise please do remember to add empty line at the end of file."
msgstr "Do dodania tej konfiguracji proszę użyć visudo, w przeciwnym razie proszę pamiętać o tym, aby dodać pustą linię na końcu pliku."
+msgid "Dashboard"
+msgstr "Start"
+
+msgid "Basic users"
+msgstr "Basic users"
+
+msgid "OAuth2 clients"
+msgstr "OAuth2 clients"
+
+msgid "Settings"
+msgstr "Settings"
+
+msgid "Configuration wizard"
+msgstr "Configuration wizard"
+
+msgid "Welcome"
+msgstr "Witaj"
+
+msgid "Add user"
+msgstr "Dodaj użytkownika"
+
+msgid "Edit user"
+msgstr "Edytuj użytkownika"
+
+msgid "Add OAuth2 client"
+msgstr "Dodaj klienta OAuth2"
+
+msgid "Are you sure?"
+msgstr "Czy jesteś pewien?"
+
+msgid "API settings"
+msgstr "Ustawienia API"
+
+msgid "General"
+msgstr "Ogólne"
+
+msgid "Catalog"
+msgstr "Baza danych"
+
+msgid "Console"
+msgstr "Konsola"
+
+msgid "Config"
+msgstr "Konfiguracja"
+
+msgid "Enabled:"
+msgstr "Włączone:"
+
+msgid "Debug:"
+msgstr "Debug:"
+
+msgid "Add client"
+msgstr "Dodaj klienta"
+
+msgid "Edit client"
+msgstr "Edytuj klienta"
+
+msgid "Invalid user. User may contain a-z A-Z 0-9 characters."
+msgstr "Niepoprawna nazwa użytkownika. Użytkownik może zawierać znaki: a-z A-Z 0-9"
+
+msgid "Show/hide"
+msgstr "Pokaż/ukryj"
+
+msgid "Copy to clipboard"
+msgstr "Kopiuj do schowka"
+
+msgid "Logout"
+msgstr "Wyloguj się"
msgid "select language"
msgstr "selecione o idioma"
-msgid "« Previous"
-msgstr "« Voltar"
+msgid "Previous"
+msgstr "Voltar"
msgid "Cancel"
msgstr "Cancelar"
-msgid "Next »"
-msgstr "Avançar »"
+msgid "Next"
+msgstr "Avançar"
msgid "Step 1 - select language"
msgstr "Passo 1 - Selecionar o idioma"
msgid "Save"
msgstr "Salvar"
-msgid "Step 7 - Finish"
-msgstr "Passo 7 - Finalizar"
+msgid "Step 6 - Finish"
+msgstr "Passo 6 - Finalizar"
msgid "Use sudo for Bacula JSON tools:"
msgstr "Utilizar o sudo para os utilitários JSON:"
msgid "Refresh token"
msgstr "Atualizar token"
-msgid "New HTTP Basic user"
-msgstr "Novo usuário HTTP Básico"
-
msgid "New OAuth2 client"
msgstr "Novo cliente OAuth2"
msgid "Given user already exists in config file."
msgstr "O usuário já existe no arquivo de configuração."
-msgid "List HTTP Basic users"
-msgstr "Listar usuários HTTP Básico"
-
-msgid "List OAuth2 clients"
-msgstr "Listar usuários OAuth2"
-
msgid "set all scopes"
msgstr "definir todos os escopos"
-msgid "Go to configuration wizard"
-msgstr "Ir para o assistente de configuração"
-
msgid "Welcome on the Baculum API default page"
msgstr "Bem-vindo à página padrão do Baculum API"
msgid "Authentication type:"
msgstr "Tipo de autenticação:"
-msgid "Step 6 - authentication to API"
-msgstr "Passo 6 - Autenticação da API"
+msgid "Step 5 - authentication to API"
+msgstr "Passo 5 - Autenticação da API"
msgid "Actions"
msgstr "Ações"
msgid "Please use visudo to add this configuration, otherwise please do remember to add empty line at the end of file."
msgstr "Por favor, use o visudo para adicionar essa configuração, caso contrário, lembre-se de adicionar uma linha vazia no final do arquivo."
+msgid "Dashboard"
+msgstr "Painel de controle"
+
+msgid "Basic users"
+msgstr "Basic users"
+
+msgid "OAuth2 clients"
+msgstr "OAuth2 clients"
+
+msgid "Settings"
+msgstr "Settings"
+
+msgid "Configuration wizard"
+msgstr "Configuration wizard"
+
+msgid "Welcome"
+msgstr "Seja bem vindo"
+
+msgid "Add user"
+msgstr "Adicionar usuário"
+
+msgid "Edit user"
+msgstr "Edit user"
+
+msgid "Add OAuth2 client"
+msgstr "Add OAuth2 client"
+
+msgid "Are you sure?"
+msgstr "Are you sure?"
+
+msgid "API settings"
+msgstr "API settings"
+
+msgid "General"
+msgstr "General"
+
+msgid "Catalog"
+msgstr "Catalog"
+
+msgid "Console"
+msgstr "Console"
+
+msgid "Config"
+msgstr "Config"
+
+msgid "Enabled:"
+msgstr "Enabled:"
+
+msgid "Debug:"
+msgstr "Debug:"
+
+msgid "Add client"
+msgstr "Add client"
+
+msgid "Edit client"
+msgstr "Edit client"
+
+msgid "Invalid user. User may contain a-z A-Z 0-9 characters."
+msgstr "Invalid user. User may contain a-z A-Z 0-9 characters."
+
+msgid "Show/hide"
+msgstr "Show/hide"
+
+msgid "Copy to clipboard"
+msgstr "Copy to clipboard"
+
+msgid "Logout"
+msgstr "Logout"
msgid "select language"
msgstr "выберите язык"
-msgid "« Previous"
-msgstr "« Назад"
+msgid "Previous"
+msgstr "Назад"
msgid "Cancel"
msgstr "Отмена"
-msgid "Next »"
-msgstr "Дальше »"
+msgid "Next"
+msgstr "Дальше"
msgid "Step 1 - select language"
msgstr "Шаг 1 - выбор языка"
msgid "Save"
msgstr "Сохранить"
-msgid "Step 7 - Finish"
-msgstr "Шаг 7 - Завершение"
+msgid "Step 6 - Finish"
+msgstr "Шаг 6 - Завершение"
msgid "Use sudo for Bacula JSON tools:"
msgstr "Использовать sudo для инструментов Bacula JSON:"
msgid "Refresh token"
msgstr "Обновить токен"
-msgid "New HTTP Basic user"
-msgstr "Новый базовый пользователь HTTP"
-
msgid "New OAuth2 client"
msgstr "Новый OAuth2 клиент"
msgid "Given user already exists in config file."
msgstr "Данный пользователь уже существует в файле конфигурации."
-msgid "List HTTP Basic users"
-msgstr "Список базовых пользователей HTTP"
-
-msgid "List OAuth2 clients"
-msgstr "Список OAuth2 клиентов"
-
msgid "set all scopes"
msgstr "установить все области"
-msgid "Go to configuration wizard"
-msgstr "Перейти к мастеру настройки"
-
msgid "Welcome on the Baculum API default page"
msgstr "Добро пожаловать. Страница по умолчанию Baculum API."
msgid "Authentication type:"
msgstr "Тип аутентификации:"
-msgid "Step 6 - authentication to API"
-msgstr "Шаг 6 - аутентификация в API"
+msgid "Step 5 - authentication to API"
+msgstr "Шаг 5 - аутентификация в API"
msgid "Actions"
msgstr "Действия"
msgid "Please use visudo to add this configuration, otherwise please do remember to add empty line at the end of file."
msgstr "Пожалуйста, используйте visudo для добавления этой конфигурации, в противном случае не забудьте добавить пустую строку в конце файла."
+msgid "Dashboard"
+msgstr "Панель управления"
+
+msgid "Basic users"
+msgstr "Basic users"
+
+msgid "OAuth2 clients"
+msgstr "OAuth2 clients"
+
+msgid "Settings"
+msgstr "Settings"
+
+msgid "Configuration wizard"
+msgstr "Configuration wizard"
+
+msgid "Welcome"
+msgstr "Добро пожаловать"
+
+msgid "Add user"
+msgstr "Добавить пользователя"
+
+msgid "Edit user"
+msgstr "Edit user"
+
+msgid "Add OAuth2 client"
+msgstr "Add OAuth2 client"
+
+msgid "Are you sure?"
+msgstr "Are you sure?"
+
+msgid "API settings"
+msgstr "API settings"
+
+msgid "General"
+msgstr "General"
+
+msgid "Catalog"
+msgstr "Catalog"
+
+msgid "Console"
+msgstr "Console"
+
+msgid "Config"
+msgstr "Config"
+
+msgid "Enabled:"
+msgstr "Enabled:"
+
+msgid "Debug:"
+msgstr "Debug:"
+
+msgid "Add client"
+msgstr "Add client"
+
+msgid "Edit client"
+msgstr "Edit client"
+
+msgid "Invalid user. User may contain a-z A-Z 0-9 characters."
+msgstr "Invalid user. User may contain a-z A-Z 0-9 characters."
+
+msgid "Show/hide"
+msgstr "Show/hide"
+
+msgid "Copy to clipboard"
+msgstr "Copy to clipboard"
+
+msgid "Logout"
+msgstr "Logout"
<!DOCTYPE html>
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
- <com:THead Title="Baculum - Bacula Web Interface" ShortcutIcon="<%=$this->getPage()->getTheme()->getBaseUrl()%>/favicon.ico" />
- <body class="api">
+<html lang="en">
+ <com:THead Title="Baculum - Bacula Web Interface">
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ <link rel="icon" href="<%=$this->getPage()->getTheme()->getBaseUrl()%>/favicon.ico" type="image/x-icon" />
+ </com:THead>
+ <body class="w3-light-grey">
<com:TForm>
- <com:TClientScript PradoScripts="effects" />
- <com:TContentPlaceHolder ID="Main" />
+ <com:TClientScript PradoScripts="ajax, effects" />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/fontawesome.min.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/datatables.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/dataTables.responsive.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/responsive.jqueryui.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/dataTables.buttons.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/buttons.html5.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/buttons.colVis.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/dataTables.select.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/misc.js %> />
+ <!-- Top container -->
+ <div class="w3-bar w3-top w3-black w3-large" style="z-index: 4">
+ <button type="button" class="w3-bar-item w3-button w3-hover-none w3-hover-text-light-grey" onclick="W3SideBar.open();"><i class="fa fa-bars"></i> Menu</button>
+ <span class="w3-bar-item w3-right">
+ <img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/logo.png" alt="" />
+ </span>
+ </div>
+ <com:Application.API.Portlets.APISideBar />
+ <div class="w3-main page_main_el" id="page_main" style="margin-left: 250px; margin-top: 43px;">
+ <com:TContentPlaceHolder ID="Main" />
+ <footer class="w3-container w3-right-align w3-small"><%[ Version: ]%> <%=Params::BACULUM_VERSION%></footer>
+ </div>
+ <div id="small" class="w3-hide-large"></div>
</com:TForm>
- <footer class="footer"><%[ Version: ]%> <%=Params::BACULUM_VERSION%></footer>
+<script type="text/javascript">
+var is_small = $('#small').is(':visible');
+if (is_small) {
+ W3SideBar.close();
+}
+</script>
</body>
</html>
<com:THead Title="Baculum - Bacula Web Interface" ShortcutIcon="<%=$this->getPage()->getTheme()->getBaseUrl()%>/favicon.ico" />
<body>
<com:TForm>
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/misc.js %> />
<com:TClientScript PradoScripts="effects" />
<com:TContentPlaceHolder ID="Wizard" />
</com:TForm>
* Bacula(R) - The Network Backup Solution
* Baculum - Bacula web interface
*
- * Copyright (C) 2013-2019 Kern Sibbald
+ * Copyright (C) 2013-2021 Kern Sibbald
*
* The main author of Baculum is Marcin Haba.
* The original author of Bacula is Kern Sibbald, with contributions
* Bacula(R) is a registered trademark of Kern Sibbald.
*/
+Prado::using('Application.API.Class.ConsoleOutputPage');
+
/**
* Client status.
*
* @category API
* @package Baculum API
*/
-class ClientStatus extends BaculumAPIServer {
+class ClientStatus extends ConsoleOutputPage {
public function get() {
$clientid = $this->Request->contains('id') ? intval($this->Request['id']) : 0;
$client = $this->getModule('client')->getClientById($clientid);
- $result = $this->getModule('bconsole')->bconsoleCommand($this->director, array('.client'));
+ $status = $this->getModule('status_fd');
+ $type = $this->Request->contains('type') && $status->isValidOutputType($this->Request['type']) ? $this->Request['type'] : null;
+ $out_format = $this->Request->contains('output') && $this->isOutputFormatValid($this->Request['output']) ? $this->Request['output'] : parent::OUTPUT_FORMAT_RAW;
+ $result = $this->getModule('bconsole')->bconsoleCommand(
+ $this->director,
+ array('.client'),
+ null,
+ true
+ );
+
+ $client_exists = false;
if ($result->exitcode === 0) {
- array_shift($result->output);
- if(is_object($client) && in_array($client->name, $result->output)) {
- $result = $this->getModule('bconsole')->bconsoleCommand(
- $this->director,
- array('status', 'client="' . $client->name . '"')
- );
- $this->output = $result->output;
- $this->error = $result->exitcode;
- } else {
- $this->output = ClientError::MSG_ERROR_CLIENT_DOES_NOT_EXISTS;
- $this->error = ClientError::ERROR_CLIENT_DOES_NOT_EXISTS;
- }
- } else {
- $this->output = $result->output;
- $this->error = $result->exitcode;
+ $client_exists = (is_object($client) && in_array($client->name, $result->output));
+ }
+
+ if ($client_exists == false) {
+ // Client doesn't exist or is not available for user because of ACL restrictions
+ $this->output = ClientError::MSG_ERROR_CLIENT_DOES_NOT_EXISTS;
+ $this->error = ClientError::ERROR_CLIENT_DOES_NOT_EXISTS;
+ return;
+ }
+ $out = (object)['output' => [], 'error' => 0];
+ if ($out_format === parent::OUTPUT_FORMAT_RAW) {
+ $out = $this->getRawOutput(['client' => $client->name]);
+ } elseif ($out_format === parent::OUTPUT_FORMAT_JSON) {
+ $out = $this->getJSONOutput([
+ 'client' => $client->name,
+ 'type' => $type
+ ]);
}
+ $this->output = $out['output'];
+ $this->error = $out['error'];
+ }
+
+ protected function getRawOutput($params = []) {
+ // traditional status client output
+ $result = $this->getModule('bconsole')->bconsoleCommand(
+ $this->director,
+ [
+ 'status',
+ 'client="' . $params['client'] . '"'
+ ]
+ );
+ $error = $result->exitcode == 0 ? $result->exitcode : GenericError::ERROR_WRONG_EXITCODE;
+ $ret = [
+ 'output' => $result->output,
+ 'error' => $error
+ ];
+ return $ret;
+ }
+
+ protected function getJSONOutput($params = []) {
+ // status client JSON output by API 2 interface
+ $status = $this->getModule('status_fd');
+ return $status->getStatus(
+ $this->director,
+ $params['client'],
+ $params['type']
+ );
}
}
--- /dev/null
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum - Bacula web interface
+ *
+ * Copyright (C) 2013-2021 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.
+ */
+
+Prado::using('Application.API.Class.ConsoleOutputPage');
+
+/**
+ * Director status command endpoint.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category API
+ * @package Baculum API
+ */
+class DirectorStatus extends ConsoleOutputPage {
+
+ public function get() {
+ $status = $this->getModule('status_dir');
+ $director = $this->Request->contains('name') && $this->getModule('misc')->isValidName($this->Request['name']) ? $this->Request['name'] : null;
+ $type = $this->Request->contains('type') && $status->isValidOutputType($this->Request['type']) ? $this->Request['type'] : null;
+ $out_format = $this->Request->contains('output') && $this->isOutputFormatValid($this->Request['output']) ? $this->Request['output'] : parent::OUTPUT_FORMAT_RAW;
+
+ if (is_null($director)) {
+ // Invalid director
+ $this->output = BconsoleError::MSG_ERROR_INVALID_DIRECTOR;
+ $this->error = BconsoleError::ERROR_INVALID_DIRECTOR;
+ return;
+ }
+
+ $out = (object)['output' => [], 'error' => 0];
+ if ($out_format === parent::OUTPUT_FORMAT_RAW) {
+ $out = $this->getRawOutput(['director' => $director]);
+ } elseif ($out_format === parent::OUTPUT_FORMAT_JSON) {
+ $out = $this->getJSONOutput([
+ 'director' => $director,
+ 'type' => $type
+ ]);
+ }
+ $this->output = $out['output'];
+ $this->error = $out['error'];
+ }
+
+ protected function getRawOutput($params = []) {
+ // traditional status director output
+ $result = $this->getModule('bconsole')->bconsoleCommand(
+ $params['director'],
+ [
+ 'status',
+ 'director'
+ ]
+ );
+ $error = $result->exitcode == 0 ? $result->exitcode : GenericError::ERROR_WRONG_EXITCODE;
+ $ret = [
+ 'output' => $result->output,
+ 'error' => $error
+ ];
+ return $ret;
+ }
+
+ protected function getJSONOutput($params = []) {
+ // status director JSON output by API 2 interface
+ $status = $this->getModule('status_dir');
+ return $status->getStatus(
+ $params['director'],
+ null,
+ $params['type']
+ );
+ }
+}
+
+?>
* Bacula(R) - The Network Backup Solution
* Baculum - Bacula web interface
*
- * Copyright (C) 2013-2019 Kern Sibbald
+ * Copyright (C) 2013-2021 Kern Sibbald
*
* The main author of Baculum is Marcin Haba.
* The original author of Bacula is Kern Sibbald, with contributions
*
* Bacula(R) is a registered trademark of Kern Sibbald.
*/
+
+Prado::using('Application.API.Class.ConsoleOutputPage');
/**
* Storage status command endpoint.
* @category API
* @package Baculum API
*/
-class StorageStatus extends BaculumAPIServer {
+class StorageStatus extends ConsoleOutputPage {
+
public function get() {
$storageid = $this->Request->contains('id') ? intval($this->Request['id']) : 0;
$storage = $this->getModule('storage')->getStorageById($storageid);
-
+ $status = $this->getModule('status_sd');
+ $type = $this->Request->contains('type') && $status->isValidOutputType($this->Request['type']) ? $this->Request['type'] : null;
+ $out_format = $this->Request->contains('output') && $this->isOutputFormatValid($this->Request['output']) ? $this->Request['output'] : parent::OUTPUT_FORMAT_RAW;
$result = $this->getModule('bconsole')->bconsoleCommand(
$this->director,
array('.storage')
);
+
+ $storage_exists = false;
if ($result->exitcode === 0) {
- array_shift($result->output);
- $storage = $this->getModule('storage')->getStorageById($storageid);
- if (is_object($storage) && in_array($storage->name, $result->output)) {
- $result = $this->getModule('bconsole')->bconsoleCommand(
- $this->director,
- array('status', 'storage="' . $storage->name . '"')
- );
- $this->output = $result->output;
- $this->error = $result->exitcode;
- } else {
- $this->output = StorageError::MSG_ERROR_STORAGE_DOES_NOT_EXISTS;
- $this->error = StorageError::ERROR_STORAGE_DOES_NOT_EXISTS;
- }
- } else {
- $this->output = $result->output;
- $this->error = $result->exitcode;
+ $storage_exists = (is_object($storage) && in_array($storage->name, $result->output));
}
+
+ if ($storage_exists == false) {
+ // Storage doesn't exist or is not available for user because of ACL restrictions
+ $this->output = StorageError::MSG_ERROR_STORAGE_DOES_NOT_EXISTS;
+ $this->error = StorageError::ERROR_STORAGE_DOES_NOT_EXISTS;
+ return;
+ }
+
+ $out = (object)['output' => [], 'error' => 0];
+ if ($out_format === parent::OUTPUT_FORMAT_RAW) {
+ $out = $this->getRawOutput(['storage' => $storage->name]);
+ } elseif ($out_format === parent::OUTPUT_FORMAT_JSON) {
+ $out = $this->getJSONOutput([
+ 'storage' => $storage->name,
+ 'type' => $type
+ ]);
+ }
+ $this->output = $out['output'];
+ $this->error = $out['error'];
+ }
+
+ protected function getRawOutput($params = []) {
+ // traditional status storage output
+ $result = $this->getModule('bconsole')->bconsoleCommand(
+ $this->director,
+ [
+ 'status',
+ 'storage="' . $params['storage'] . '"'
+ ]
+ );
+ $error = $result->exitcode == 0 ? $result->exitcode : GenericError::ERROR_WRONG_EXITCODE;
+ $ret = [
+ 'output' => $result->output,
+ 'error' => $error
+ ];
+ return $ret;
+ }
+
+ protected function getJSONOutput($params = []) {
+ // status storage JSON output by API 2 interface
+ $status = $this->getModule('status_sd');
+ return $status->getStatus(
+ $this->director,
+ $params['storage'],
+ $params['type']
+ );
}
}
<module id="oauth2_authid" class="Application.API.Class.OAuth2.AuthIdManager" />
<module id="oauth2_token" class="Application.API.Class.OAuth2.TokenManager" />
+ <!-- API Server modules -->
+ <module id="api_server_v1" class="Application.API.Class.APIServerV1" />
+ <module id="api_server_v2" class="Application.API.Class.APIServerV2" />
+
<!-- database modules -->
<module id="db" class="Application.API.Class.Database" />
<module id="client" class="Application.API.Class.ClientManager" />
<url ServiceParameter="Authorize" pattern="api/auth/" />
<url ServiceParameter="RequestToken" pattern="api/token/" />
+ <!-- API v2 -->
+ <!-- general endpoint -->
+ <url ServiceParameter="Welcome" pattern="api/v2/welcome/" />
+ <!-- bconsole endpoints -->
+ <url ServiceParameter="ConsoleCommand" pattern="api/v2/console/" />
+ <!-- database endpoints -->
+ <url ServiceParameter="Catalog" pattern="api/v2/catalog/" />
+ <url ServiceParameter="DbSize" pattern="api/v2/dbsize/" />
+ <!-- director endpoints -->
+ <url ServiceParameter="Directors" pattern="api/v2/directors/" />
+ <!-- clients (file daemons) endpoints -->
+ <url ServiceParameter="Clients" pattern="api/v2/clients/" />
+ <url ServiceParameter="Client" pattern="api/v2/clients/{id}/" parameters.id="\d+" />
+ <url ServiceParameter="ClientsShow" pattern="api/v2/clients/show/" />
+ <url ServiceParameter="ClientShow" pattern="api/v2/clients/{id}/show/" parameters.id="\d+" />
+ <url ServiceParameter="ClientStatus" pattern="api/v2/clients/{id}/status/" parameters.id="\d+" />
+ <url ServiceParameter="JobsForClient" pattern="api/v2/clients/{id}/jobs/" parameters.id="\d+" />
+ <url ServiceParameter="ClientLs" pattern="api/v2/clients/{id}/ls/" parameters.id="\d+" />
+ <url ServiceParameter="ClientBandwidthLimit" pattern="api/v2/clients/{id}/bandwidth/" parameters.id="\d+" />
+ <!-- storages (storage daemons) endpoints -->
+ <url ServiceParameter="Storages" pattern="api/v2/storages/" />
+ <url ServiceParameter="Storage" pattern="api/v2/storages/{id}/" parameters.id="\d+" />
+ <url ServiceParameter="StoragesShow" pattern="api/v2/storages/show/" />
+ <url ServiceParameter="StorageShow" pattern="api/v2/storages/{id}/show/" parameters.id="\d+" />
+ <url ServiceParameter="StorageStatus" pattern="api/v2/storages/{id}/status/" parameters.id="\d+" />
+ <url ServiceParameter="StorageMount" pattern="api/v2/storages/{id}/mount/" parameters.id="\d+" />
+ <url ServiceParameter="StorageUmount" pattern="api/v2/storages/{id}/umount/" parameters.id="\d+" />
+ <url ServiceParameter="StorageRelease" pattern="api/v2/storages/{id}/release/" parameters.id="\d+" />
+ <!-- volumes (media) endpoints-->
+ <url ServiceParameter="Volumes" pattern="api/v2/volumes/" />
+ <url ServiceParameter="Volume" pattern="api/v2/volumes/{id}/" parameters.id="\d+" />
+ <url ServiceParameter="VolumePrune" pattern="api/v2/volumes/{id}/prune/" parameters.id="\d+" />
+ <url ServiceParameter="VolumePurge" pattern="api/v2/volumes/{id}/purge/" parameters.id="\d+" />
+ <url ServiceParameter="VolumesRequired" pattern="api/v2/volumes/required/{jobid}/{fileid}/" parameters.jobid="\d+" parameters.fileid="\d+" />
+ <url ServiceParameter="JobsOnVolume" pattern="api/v2/volumes/{id}/jobs/" parameters.id="\d+" />
+ <url ServiceParameter="VolumeLabel" pattern="api/v2/volumes/label/" />
+ <url ServiceParameter="VolumeLabelBarcodes" pattern="api/v2/volumes/label/barcodes/" />
+ <url ServiceParameter="SlotsUpdate" pattern="api/v2/volumes/update/" />
+ <url ServiceParameter="SlotsUpdate" pattern="api/v2/volumes/update/{barcodes}/" parameters.barcodes="barcodes" />
+ <!-- pools endpoints -->
+ <url ServiceParameter="Pools" pattern="api/v2/pools/" />
+ <url ServiceParameter="Pool" pattern="api/v2/pools/{id}/" parameters.id="\d+" />
+ <url ServiceParameter="VolumesInPool" pattern="api/v2/pools/{id}/volumes/" parameters.id="\d+" />
+ <url ServiceParameter="PoolUpdate" pattern="api/v2/pools/{id}/update/" parameters.id="\d+" />
+ <url ServiceParameter="PoolUpdateVolumes" pattern="api/v2/pools/{id}/update/volumes/" parameters.id="\d+" />
+ <url ServiceParameter="PoolsShow" pattern="api/v2/pools/show/" />
+ <url ServiceParameter="PoolShow" pattern="api/v2/pools/{id}/show/" parameters.id="\d+" />
+ <!-- jobs endpoints-->
+ <url ServiceParameter="Jobs" pattern="api/v2/jobs/" />
+ <url ServiceParameter="Job" pattern="api/v2/jobs/{id}/" parameters.id="\d+" />
+ <url ServiceParameter="JobResNames" pattern="api/v2/jobs/resnames/" />
+ <url ServiceParameter="JobsShow" pattern="api/v2/jobs/show/" />
+ <url ServiceParameter="JobShow" pattern="api/v2/jobs/{id}/show/" parameters.id="\d+" />
+ <url ServiceParameter="JobBandwidthLimit" pattern="api/v2/jobs/{id}/bandwidth/" parameters.id="\d+" />
+ <url ServiceParameter="JobsRecent" pattern="api/v2/jobs/recent/{name}/" parameters.name="[a-zA-Z0-9:.\-_ ]+" />
+ <url ServiceParameter="JobEstimate" pattern="api/v2/jobs/estimate/" />
+ <url ServiceParameter="JobRun" pattern="api/v2/jobs/run/" />
+ <url ServiceParameter="JobCancel" pattern="api/v2/jobs/{id}/cancel/" parameters.id="\d+"/>
+ <url ServiceParameter="JobTotals" pattern="api/v2/jobs/totals/" />
+ <url ServiceParameter="JobListFiles" pattern="api/v2/jobs/{id}/files/" parameters.id="\d+" />
+ <url ServiceParameter="JobFiles" pattern="api/v2/jobs/files/" />
+ <url ServiceParameter="RestoreRun" pattern="api/v2/jobs/restore/" />
+ <!-- bvfs endpoints-->
+ <url ServiceParameter="BVFSUpdate" pattern="api/v2/bvfs/update/" />
+ <url ServiceParameter="BVFSLsDirs" pattern="api/v2/bvfs/lsdirs/" />
+ <url ServiceParameter="BVFSLsFiles" pattern="api/v2/bvfs/lsfiles/" />
+ <url ServiceParameter="BVFSVersions" pattern="api/v2/bvfs/versions/" />
+ <url ServiceParameter="BVFSGetJobids" pattern="api/v2/bvfs/getjobids/" />
+ <url ServiceParameter="BVFSRestore" pattern="api/v2/bvfs/restore/" />
+ <url ServiceParameter="BVFSClearCache" pattern="api/v2/bvfs/clear/" />
+ <url ServiceParameter="BVFSCleanUp" pattern="api/v2/bvfs/cleanup/" />
+ <!-- joblog endpoints -->
+ <url ServiceParameter="JobLog" pattern="api/v2/joblog/{id}/" parameters.id="\d+" />
+ <!-- @TODO: Separate this endpoint outside 'joblog' -->
+ <url ServiceParameter="Messages" pattern="api/v2/joblog/messages" />
+ <!-- fileset endpoints -->
+ <url ServiceParameter="FileSets" pattern="api/v2/filesets/" />
+ <url ServiceParameter="FileSet" pattern="api/v2/filesets/{id}/" parameters.id="\d+" />
+ <url ServiceParameter="FileSetResNames" pattern="api/v2/filesets/resnames/" />
+ <!-- schedule endpoints -->
+ <url ServiceParameter="Schedules" pattern="api/v2/schedules/resnames/" />
+ <url ServiceParameter="ScheduleStatus" pattern="api/v2/schedules/status/" />
+ <!-- Bacula config module endpoints -->
+ <url ServiceParameter="Config" pattern="api/v2/config/" />
+ <url ServiceParameter="Config" pattern="api/v2/config/{component_type}/" parameters.component_type="[a-z]+" />
+ <url ServiceParameter="Config" pattern="api/v2/config/{component_type}/{resource_type}/" parameters.component_type="[a-z]+" parameters.resource_type="[a-zA-Z]+" />
+ <url ServiceParameter="Config" pattern="api/v2/config/{component_type}/{resource_type}/{resource_name}/" parameters.component_type="[a-z]+" parameters.resource_type="[a-zA-Z]+" parameters.resource_name="[a-zA-Z0-9:.\-_ ]+" />
+ <!-- director endpoints -->
+ <url ServiceParameter="DirectorStatus" pattern="api/v2/directors/{name}/status/" parameters.name="[a-zA-Z0-9:.\-_ ]+" />
+ <!-- actions endpoints -->
+ <url ServiceParameter="Actions" pattern="api/v2/actions/{component}/{action}/" parameters.component="(director|storage|client)" parameters.action="(start|stop|restart)" />
+ <!-- OAuth2 client endpoints -->
+ <url ServiceParameter="OAuth2Clients" pattern="api/v2/oauth2/clients/" />
+ <url ServiceParameter="OAuth2Client" pattern="api/v2/oauth2/clients/{id}/" parameters.id="[a-zA-Z0-9\-_]{32}" />
+
+ <!-- API v1 -->
<!-- general endpoint -->
<url ServiceParameter="Welcome" pattern="api/v1/welcome/" />
<!-- bconsole endpoints -->
--- /dev/null
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum - Bacula web interface
+ *
+ * Copyright (C) 2013-2021 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.
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TCallback');
+Prado::using('Application.API.Class.BaculumAPIPage');
+
+/**
+ * API Basic users page.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Panel
+ * @package Baculum API
+ */
+class APIBasicUsers extends BaculumAPIPage {
+
+ public function onInit($param) {
+ parent::onInit($param);
+
+ $config = $this->getModule('api_config')->getConfig();
+ if(count($config) === 0) {
+ // Config doesn't exist, go to wizard
+ $this->goToPage('APIInstallWizard');
+ return;
+ } elseif (!$this->IsCallback) {
+ $this->loadBasicUsers(null, null);
+ }
+ }
+
+ public function loadBasicUsers($sender, $param) {
+ $users = $this->getBasicUsers();
+ $this->getCallbackClient()->callClientFunction(
+ 'oAPIBasicUsers.load_basic_users_cb',
+ [$users]
+ );
+ $this->hideBasicUserWindow($sender);
+ }
+
+ public function cancelBasicUserWindow($sender, $param) {
+ $this->hideBasicUserWindow($sender);
+ }
+
+ private function hideBasicUserWindow($sender) {
+ if (is_object($sender)) {
+ if ($sender->ID === 'NewBasicClient') {
+ $this->getCallbackClient()->callClientFunction(
+ 'oAPIBasicUsers.show_new_user_window',
+ [false]
+ );
+ } elseif ($sender->ID === 'EditBasicClient') {
+ $this->getCallbackClient()->callClientFunction(
+ 'oAPIBasicUsers.show_edit_user_window',
+ [false]
+ );
+ }
+ }
+ }
+
+ private function getBasicUsers() {
+ $basic_users = array();
+ $basic_cfg = $this->getModule('basic_apiuser')->getUsers();
+ foreach($basic_cfg as $user => $pwd) {
+ $basic_users[] = ['username' => $user];
+ }
+ return $basic_users;
+ }
+
+ public function deleteBasicUser($sender, $param) {
+ $config = $this->getModule('basic_apiuser');
+ $username = $param->getCallbackParameter();
+ $config->removeUser($username);
+ $this->loadBasicUsers(null, null);
+ }
+}
+?>
--- /dev/null
+<%@ MasterClass="Application.API.Layouts.Main" Theme="Baculum-v2"%>
+<com:TContent ID="Main">
+ <header class="w3-container w3-block">
+ <h5>
+ <i class="fas fa-users"></i> <%[ Basic users ]%>
+ </h5>
+ </header>
+ <div class="w3-container">
+ <a href="javascript:void(0)" class="w3-button w3-green w3-margin-bottom" onclick="oAPIBasicUsers.show_new_user_window(true);">
+ <i class="fas fa-plus"></i> <%[ Add user ]%>
+ </a>
+ <table id="basic_user_list" class="w3-table w3-striped w3-hoverable w3-white w3-margin-bottom" style="width: 100%">
+ <thead>
+ <tr>
+ <th></th>
+ <th><%[ Username ]%></th>
+ <th><%[ Actions ]%></th>
+ </tr>
+ </thead>
+ <tbody id="basic_user_list_body"></tbody>
+ <tfoot>
+ <tr>
+ <th></th>
+ <th><%[ Username ]%></th>
+ <th><%[ Actions ]%></th>
+ </tr>
+ </tfoot>
+ </table>
+ </div>
+<script>
+var oBasicUserList = {
+ ids: {
+ basic_user_list: 'basic_user_list',
+ basic_user_list_body: 'basic_user_list_body'
+ },
+ table: null,
+ data: [],
+ init: function() {
+ if (!this.table) {
+ this.set_table();
+ } else {
+ var page = this.table.page();
+ this.table.clear().rows.add(this.data).draw();
+ this.table.page(page).draw(false);
+ }
+ },
+ set_table: function() {
+ this.table = $('#' + this.ids.basic_user_list).DataTable({
+ data: this.data,
+ deferRender: true,
+ dom: 'lBfrtip',
+ stateSave: true,
+ buttons: [
+ 'copy', 'csv', 'colvis'
+ ],
+ columns: [
+ {
+ className: 'details-control',
+ orderable: false,
+ data: null,
+ defaultContent: '<button type="button" class="w3-button w3-blue"><i class="fa fa-angle-down"></i></button>'
+ },
+ {data: 'username'},
+ {
+ data: 'username',
+ render: function(data, type, row) {
+ var span = document.createElement('SPAN');
+ span.className = 'w3-right';
+
+ var edit_btn = document.createElement('BUTTON');
+ edit_btn.className = 'w3-button w3-green';
+ edit_btn.type = 'button';
+ var i = document.createElement('I');
+ i.className = 'fas fa-edit';
+ var label = document.createTextNode(' <%[ Edit ]%>');
+ edit_btn.appendChild(i);
+ edit_btn.innerHTML += ' ';
+ edit_btn.appendChild(label);
+ edit_btn.setAttribute('onclick', 'oAPIBasicUsers.edit_user("' + data + '")');
+
+ span.appendChild(edit_btn);
+
+ if (this.data.length > 1) {
+ var del_btn = document.createElement('BUTTON');
+ del_btn.className = 'w3-button w3-red w3-margin-left';
+ del_btn.type = 'button';
+ var i = document.createElement('I');
+ i.className = 'fas fa-trash-alt';
+ var label = document.createTextNode(' <%[ Delete ]%>');
+ del_btn.appendChild(i);
+ del_btn.innerHTML += ' ';
+ del_btn.appendChild(label);
+ del_btn.setAttribute('onclick', 'oAPIBasicUsers.delete_user("' + data + '")');
+
+ span.appendChild(del_btn);
+ }
+ return span.outerHTML;
+ }.bind(this)
+ }
+ ],
+ responsive: {
+ details: {
+ type: 'column'
+ }
+ },
+ columnDefs: [{
+ className: 'control',
+ orderable: false,
+ targets: 0
+ },
+ {
+ className: "dt-center",
+ targets: [ 2 ]
+ }],
+ order: [1, 'asc'],
+ });
+ }
+};
+</script>
+ <div id="new_basic_user_window" class="w3-modal">
+ <div class="w3-modal-content w3-animate-top w3-card-4">
+ <header class="w3-container w3-teal">
+ <span onclick="document.getElementById('new_basic_user_window').style.display = 'none';" class="w3-button w3-display-topright">×</span>
+ <h2><%[ Add user ]%></h2>
+ </header>
+ <div class="w3-container w3-margin-left w3-margin-right w3-text-teal">
+ <com:Application.Common.Portlets.NewAuthClient
+ ID="NewBasicClient"
+ Mode="add"
+ AuthType="basic"
+ OnSuccess="loadBasicUsers"
+ OnCancel="cancelBasicUserWindow"
+ />
+ </div>
+ </div>
+ </div>
+ <div id="edit_basic_user_window" class="w3-modal">
+ <div class="w3-modal-content w3-animate-top w3-card-4">
+ <header class="w3-container w3-teal">
+ <span onclick="document.getElementById('edit_basic_user_window').style.display = 'none';" class="w3-button w3-display-topright">×</span>
+ <h2><%[ Edit user ]%></h2>
+ </header>
+ <div class="w3-container w3-margin-left w3-margin-right w3-text-teal">
+ <com:Application.Common.Portlets.NewAuthClient
+ ID="EditBasicClient"
+ Mode="edit"
+ AuthType="basic"
+ OnSuccess="loadBasicUsers"
+ OnCancel="cancelBasicUserWindow"
+ />
+ </div>
+ </div>
+ </div>
+<com:TCallback ID="LoadUsers" OnCallback="loadBasicUsers" />
+<com:TCallback ID="DeleteUser" OnCallback="deleteBasicUser" />
+<script>
+var oAPIBasicUsers = {
+ ids: {
+ new_user_window: 'new_basic_user_window',
+ new_basic_user: '<%=$this->NewBasicClient->APIBasicLogin->ClientID%>',
+ edit_user_window: 'edit_basic_user_window',
+ edit_basic_pwd: '<%=$this->EditBasicClient->APIBasicPassword->ClientID%>'
+ },
+ new_obj: <%=$this->NewBasicClient->ClientID%>oNewAuthClient,
+ edit_obj: <%=$this->EditBasicClient->ClientID%>oNewAuthClient,
+ init: function() {
+ this.load_basic_users();
+ },
+ show_new_user_window: function(show) {
+ oAPIBasicUsers.new_obj.hide_errors();
+ oAPIBasicUsers.new_obj.clear_basic_fields();
+ var win = document.getElementById(oAPIBasicUsers.ids.new_user_window);
+ if (show) {
+ win.style.display = 'block';
+ } else {
+ win.style.display = 'none';
+ }
+ document.getElementById(oAPIBasicUsers.ids.new_basic_user).focus();
+ },
+ show_edit_user_window: function(show) {
+ oAPIBasicUsers.edit_obj.hide_errors();
+ var win = document.getElementById(oAPIBasicUsers.ids.edit_user_window);
+ if (show) {
+ win.style.display = 'block';
+ } else {
+ win.style.display = 'none';
+ }
+ document.getElementById(oAPIBasicUsers.ids.edit_basic_pwd).focus();
+ },
+ load_basic_users: function() {
+ var cb = <%=$this->LoadUsers->ActiveControl->Javascript%>;
+ cb.dispatch();
+ },
+ load_basic_users_cb: function(users) {
+ oBasicUserList.data = users;
+ oBasicUserList.init();
+ },
+ edit_user: function(username) {
+ this.edit_obj.clear_basic_fields();
+ this.edit_obj.set_basic_props({
+ username: username
+ });
+ this.show_edit_user_window(true);
+ },
+ delete_user: function(username) {
+ if (!confirm('<%[ Are you sure? ]%>')) {
+ return false;
+ }
+ var cb = <%=$this->DeleteUser->ActiveControl->Javascript%>;
+ cb.setCallbackParameter(username);
+ cb.dispatch();
+ }
+};
+$(function() {
+ oAPIBasicUsers.init();
+});
+</script>
+</com:TContent>
-<%@ MasterClass="Application.API.Layouts.Main" Theme="Baculum-v1"%>
+<%@ MasterClass="Application.API.Layouts.Main" Theme="Baculum-v2"%>
<com:TContent ID="Main">
- <com:BClientScript ScriptUrl=<%~ ../../JavaScript/misc.js %> />
- <h3 style="clear: left"><%[ Welcome on the Baculum API default page ]%> <input type="button" class="bbutton" onclick="window.location.href='<%=$this->getService()->constructUrl('APIInstallWizard')%>'" value="<%[ Go to configuration wizard ]%>" style="float: right" /></h3>
- <div id="tabs">
- <ul>
- <li><a href="#tab1"><%[ Baculum API Client ]%></a></li>
- <li><a href="#tab2"><%[ List HTTP Basic users ]%></a></li>
- <li><a href="#tab3"><%[ List OAuth2 clients ]%></a></li>
- </ul>
- <div id="tab1">
+ <div class="w3-container">
+ <h3><%[ Welcome on the Baculum API default page ]%></h3>
+ <header class="w3-container w3-white">
+ <h5>
+ <i class="fas fa-user-lock"></i> <%[ Baculum API Client ]%>
+ </h5>
+ </header>
+ <div class="w3-container w3-white">
<p><%[ Here you can try one from API commands ]%></p>
<div>
- <com:TJuiProgressbar ID="Progress" Options.Max="3" Options.Value="false" Width="700px" CssClass="center" Style="float: left">
+ <com:TJuiProgressbar ID="Progress" Options.Max="3" Options.Value="false" Width="700px" CssClass="w3-center w3-margin-bottom" Style="float: left; position: relative">
<span id="progress_label"><%[ Starting... ]%></span>
</com:TJuiProgressbar>
- <img id="api_refresh" src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_refresh.png" alt="<%[ Refresh token ]%>" title="<%[ Refresh token ]%>" onclick="oAPIHome.init_oauth2_client();" />
+ <span id="api_refresh" style="cursor: pointer">
+ <i class="w3-padding w3-large fas fa-sync-alt" title="<%[ Refresh token ]%>" onclick="oAPIHome.init_oauth2_client();"></i>
+ <i class="w3-padding-right w3-large fas fa-eye fa-fw" title="<%[ Show/hide ]%>" onclick="oAPIHome.show_hide_token(this);"></i>
+ <i class="w3-padding w3-large fas fa-copy" title="<%[ Copy to clipboard ]%>" onclick="copy_to_clipboard(oAPIHome.token);"></i>
+ </span>
+
</div>
- <div class="line" id="auth_params_combo_container" style="margin-top: 10px; width: 700px; display: none">
- <div class="text"><com:TLabel ForControl="AuthParamsCombo" Text="<%[ Select: ]%>" /></div>
- <div class="field">
- <com:TActiveDropDownList ID="AuthParamsCombo" AutoPostBack="false" />
+ <div class="w3-row w3-section" id="auth_params_combo_container" style="margin-top: 10px; width: 700px; display: none">
+ <div class="w3-quarter w3-center"><com:TLabel ForControl="AuthParamsCombo" Text="<%[ Select: ]%>" /></div>
+ <div class="w3-rest">
+ <com:TActiveDropDownList
+ ID="AuthParamsCombo"
+ AutoPostBack="false"
+ CssClass="w3-select w3-border"
+ />
</div>
</div>
- <div style="clear: left; margin-top: 60px;">
- <select id="section" class="api_select">
+ <div class="w3-row w3-section w3-margin-top">
+ <select id="section" class="w3-select w3-border w3-left" style="width: 200px;">
<option value="none"><%[ Please select API endpoint ]%></option>
<option value="storages">storages</option>
<option value="clients">clients</option>
<option value="joblog">joblog</option>
<option value="bvfs">bvfs</option>
</select>
- <input id="api_command" name="command" onkeydown="if (event.keyCode == 13) { oAPIHome.send_request(); }" /> <input class="api_button" type="button" name="apply" value="<%[ Send request ]%>" onclick="oAPIHome.send_request();" />
+ <input id="api_command" class="w3-input w3-border w3-left" name="command" onkeydown="if (event.keyCode == 13) { oAPIHome.send_request(); }" style="width: 600px;" /> <a class="w3-button w3-green" type="button" name="apply" onclick="oAPIHome.send_request();"><i class="fas fa-paper-plane"></i> <%[ Send request ]%></a>
</div>
<div id="api_output">
<pre id="api_result"></pre>
</div>
</div>
- <div id="tab2">
- <input type="button" class="bbutton" onclick="$('#<%=$this->NewBasicClient->ClientID%>new_auth_client').slideToggle();" value="<%[ New HTTP Basic user ]%>" />
- <com:Application.Common.Portlets.NewAuthClient ID="NewBasicClient" AuthType="basic" OnCallback="loadBasicUsers" />
- <com:TActiveDataGrid
- ID="BasicClientList"
- AutoGenerateColumns="false"
- CellPadding="2"
- AlternatingItemStyle.BackColor="#4e4e50"
- CssClass="tab-grid"
- >
- <com:TBoundColumn
- ID="BasicUsernameColumn"
- HeaderText="<%[ Username ]%>"
- DataField="username"
- />
- <com:TTemplateColumn
- ID="BasicDeleteColumn"
- HeaderText="<%[ Delete ]%>"
- ItemStyle.HorizontalAlign="Center"
- >
- <prop:ItemTemplate>
- <com:TActiveLinkButton
- Text="<%[ Delete ]%>"
- OnCommand="SourceTemplateControl.deleteBasicItem"
- CommandParameter="<%#$this->getParent()->Data['username']%>"
- Attributes.onclick="return confirm('<%[ Are you sure? ]%>')"
- Visible="<%=($this->getParent()->getParent()->getItemCount() > 1)%>"
- />
- </prop:ItemTemplate>
- </com:TTemplateColumn>
- </com:TActiveDataGrid>
- </div>
- <div id="tab3">
- <input type="button" class="bbutton" onclick="$('#<%=$this->NewOAuth2Client->ClientID%>new_auth_client').slideToggle();" value="<%[ New OAuth2 client ]%>" />
- <com:Application.Common.Portlets.NewAuthClient ID="NewOAuth2Client" AuthType="oauth2" OnCallback="loadOAuth2Users" />
- <com:TActiveDataGrid
- ID="OAuth2ClientList"
- AutoGenerateColumns="false"
- CellPadding="2"
- AlternatingItemStyle.BackColor="#4e4e50"
- CssClass="tab-grid"
- >
- <com:TBoundColumn
- HeaderText="<%[ Name ]%>"
- DataField="name"
- />
- <com:TBoundColumn
- ID="ClientIDColumn"
- HeaderText="<%[ Client ID ]%>"
- DataField="client_id"
- />
- <com:TBoundColumn
- HeaderText="<%[ Redirect URI ]%>"
- DataField="redirect_uri"
- />
- <com:TTemplateColumn
- ID="OAuth2DeleteColumn"
- HeaderText="<%[ Delete ]%>"
- ItemStyle.HorizontalAlign="Center"
- >
- <prop:ItemTemplate>
- <com:TActiveLinkButton
- Text="<%[ Edit ]%>"
- OnCommand="SourceTemplateControl.editOAuth2Item"
- CommandParameter="<%#$this->getParent()->Data['client_id']%>"
- />
- <com:TActiveLinkButton
- Text="<%[ Delete ]%>"
- OnCommand="SourceTemplateControl.deleteOAuth2Item"
- CommandParameter="<%#$this->getParent()->Data['client_id']%>"
- Attributes.onclick="if(!confirm('<%[ Are you sure? ]%>')) return false;"
- Visible="<%=($this->getParent()->getParent()->getItemCount() > 1)%>"
- />
- </prop:ItemTemplate>
- </com:TTemplateColumn>
- </com:TActiveDataGrid>
- </div>
- <com:TJuiDialog
- ID="APIOAuth2EditPopup"
- Options.Title="<%[ Edit OAuth2 client parameters ]%>"
- Options.AutoOpen="False"
- Options.Width="700px"
- >
- <com:TPanel DefaultButton="APIOAuth2SaveBtn">
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIOAuth2ClientId" Text="<%[ OAuth2 Client ID: ]%>" /></div>
- <div class="field">
- <com:TActiveTextBox
- ID="APIOAuth2ClientId"
- CssClass="textbox"
- ReadOnly="true"
- />
- </div>
- </div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIOAuth2ClientSecret" Text="<%[ OAuth2 Client Secret: ]%>" /></div>
- <div class="field">
- <com:TActiveTextBox
- ID="APIOAuth2ClientSecret"
- CssClass="textbox"
- CausesValidation="false"
- MaxLength="50"
- />
- <com:TRequiredFieldValidator
- CssClass="validator-block"
- Display="Dynamic"
- ControlCssClass="invalidate"
- ControlToValidate="APIOAuth2ClientSecret"
- ValidationGroup="APIOAuth2Edit"
- Text="<%[ Please enter Client Secret. ]%>"
- />
- <com:TRegularExpressionValidator
- CssClass="validator-block"
- Display="Dynamic"
- ControlCssClass="invalidate"
- ControlToValidate="APIOAuth2ClientSecret"
- RegularExpression="<%=OAuth2::CLIENT_SECRET_PATTERN%>"
- ValidationGroup="APIOAuth2Edit"
- Text="<%[ Invalid Client Secret value. Client Secret may contain any character that is not a whitespace character. ]%>"
- />
- <a href="javascript:void(0)" onclick="document.getElementById('<%=$this->APIOAuth2ClientSecret->ClientID%>').value = get_random_string('ABCDEFabcdef0123456789', 40); return false;"><%[ generate ]%></a>
- </div>
- </div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIOAuth2RedirectURI" Text="<%[ OAuth2 Redirect URI (example: https://baculumgui:9095/web/redirect): ]%>" /></div>
- <div class="field">
- <com:TActiveTextBox
- ID="APIOAuth2RedirectURI"
- CssClass="textbox"
- CausesValidation="false"
- />
- <com:TRequiredFieldValidator
- CssClass="validator-block"
- Display="Dynamic"
- ControlCssClass="invalidate"
- ControlToValidate="APIOAuth2RedirectURI"
- ValidationGroup="APIOAuth2Edit"
- Text="<%[ Please enter Redirect URI. ]%>"
- />
- </div>
- </div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIOAuth2Scope" Text="<%[ OAuth2 scopes (space separated): ]%>" /></div>
- <div class="field">
- <com:TActiveTextBox
- ID="APIOAuth2Scope"
- CssClass="textbox"
- CausesValidation="false"
- TextMode="MultiLine"
- />
- <a href="javascript:void(0)" onclick="set_scopes('<%=$this->APIOAuth2Scope->ClientID%>'); return false;" style="vertical-align: top"><%[ set all scopes ]%></a>
- <com:TRequiredFieldValidator
- CssClass="validator-block"
- Display="Dynamic"
- ControlCssClass="invalidate"
- ControlToValidate="APIOAuth2Scope"
- ValidationGroup="APIOAuth2Edit"
- Text="<%[ Please enter OAuth2 scopes. ]%>"
- />
- </div>
- </div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIOAuth2BconsoleCfgPath" Text="<%[ Dedicated Bconsole config file path: ]%>" /></div>
- <div class="field">
- <com:TActiveTextBox
- ID="APIOAuth2BconsoleCfgPath"
- CssClass="textbox"
- CausesValidation="false"
- /> <%[ (optional) ]%>
- </div>
- </div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIOAuth2Name" Text="<%[ Short name: ]%>" /></div>
- <div class="field">
- <com:TActiveTextBox
- ID="APIOAuth2Name"
- CssClass="textbox"
- CausesValidation="false"
- /> <%[ (optional) ]%>
- </div>
- </div>
- <div class="center">
- <com:BButton
- Text="<%[ Cancel ]%>"
- CausesValidation="false"
- Attributes.onclick="$('#<%=$this->APIOAuth2EditPopup->ClientID%>').dialog('close'); return false;"
- />
- <com:BActiveButton
- ID="APIOAuth2SaveBtn"
- ValidationGroup="APIOAuth2Edit"
- OnCommand="TemplateControl.saveOAuth2Item"
- Text="<%[ Save ]%>"
- >
- </com:BActiveButton>
- </div>
- </com:TPanel>
- </com:TJuiDialog>
</div>
<com:TActiveHiddenField ID="AuthParamsInput" />
<com:TCallback ID="AuthParamsCallback" OnCallback="setAuthParams">
ids: {
section: 'section',
command: 'api_command',
+ output: 'api_output',
result: 'api_result',
progress_bar: '<%=$this->Progress->ClientID%>',
progress_label: 'progress_label',
+ progress_content: 'progress_content',
refresh_token: 'api_refresh',
auth_params_combo_container: 'auth_params_combo_container',
auth_params_combo: '<%=$this->AuthParamsCombo->ClientID%>',
auth_params_input: '<%=$this->AuthParamsInput->ClientID%>'
},
default_commands: {
- storages: '/api/v1/storages/',
- clients: '/api/v1/clients?limit=5',
- volumes: '/api/v1/volumes?limit=4',
- jobs: '/api/v1/jobs?limit=10',
- joblog: '/api/v1/joblog/1/',
- bvfs: '/api/v1/bvfs/lsdirs?jobids=1&path=&limit=8'
+ storages: '/api/v2/storages/',
+ clients: '/api/v2/clients?limit=5',
+ volumes: '/api/v2/volumes?limit=4',
+ jobs: '/api/v2/jobs?limit=10',
+ joblog: '/api/v2/joblog/1/',
+ bvfs: '/api/v2/bvfs/lsdirs?jobids=1&path=&limit=8'
},
token: null,
auth_params_cb: <%=$this->AuthParamsCallback->ActiveControl->Javascript%>,
this.set_events();
this.set_auth_params();
this.init_auth();
- this.init_tabs();
this.change_auth_params();
},
init_auth: function() {
var params = document.getElementById(this.ids.auth_params_input).value;
this.baculum_auth = JSON.parse(params);
},
- set_progress: function(value, text) {
+ set_progress: function(value, content) {
$('#' + this.ids.progress_bar).progressbar('value', value);
- $('#' + this.ids.progress_label).text(text);
- },
- init_tabs: function() {
- $('#tabs').tabs({active: 0});
+ $('#' + this.ids.progress_label).html(content);
},
init_basic: function() {
this.set_progress(3, '<%[ Basic auth ready... ]%>');
request.done(function(data) {
if (typeof(data) == 'object' && data.hasOwnProperty('access_token')) {
this.token = data.access_token;
- this.set_progress(3, '<%[ Access token: ]%> ' + this.token);
+ var text = document.createTextNode('<%[ Access token: ]%> ');
+ var span_out = document.createElement('SPAN');
+ var span_in = document.createElement('SPAN');
+ span_in.id = this.ids.progress_content;
+ span_in.textContent = this.get_masked_token();
+ span_out.appendChild(text);
+ span_out.appendChild(span_in);
+ this.set_progress(3, span_out.outerHTML);
}
}.bind(this));
},
},
send_request: function() {
var url = document.getElementById(this.ids.command).value;
+ if (!url) {
+ return;
+ }
var headers = {};
if (this.baculum_auth.auth_type == 'oauth2' && this.token) {
headers = {'Authorization': 'Bearer ' + this.token};
}.bind(this));
},
show_result: function(data) {
+ document.getElementById(this.ids.output).className = 'w3-code';
document.getElementById(this.ids.result).textContent = JSON.stringify(data, null, 2);
},
clear_result: function() {
+ document.getElementById(this.ids.output).className = '';
document.getElementById(this.ids.result).textContent = '';
+ },
+ show_hide_token: function(el) {
+ var span = document.getElementById(this.ids.progress_content);
+ if (el.classList.contains('fa-eye')) {
+ span.textContent = this.token;
+ el.classList.remove('fa-eye');
+ el.classList.add('fa-eye-slash');
+ } else {
+ span.textContent = this.get_masked_token();
+ el.classList.remove('fa-eye-slash');
+ el.classList.add('fa-eye');
+ }
+ },
+ get_masked_token: function(token) {
+ return this.token.substr(0, 7) + this.token.substr(8).replace(/./g, '*');
}
};
$(function() {
* Bacula(R) - The Network Backup Solution
* Baculum - Bacula web interface
*
- * Copyright (C) 2013-2020 Kern Sibbald
+ * Copyright (C) 2013-2021 Kern Sibbald
*
* The main author of Baculum is Marcin Haba.
* The original author of Bacula is Kern Sibbald, with contributions
$this->goToPage('APIInstallWizard');
return;
} elseif (!$this->IsCallback) {
- $this->loadBasicUsers(null, null);
- $this->loadOAuth2Users(null, null);
$this->setAuthParams(null, null);
+ $this->loadAuthParams(null, null);
}
}
$this->AuthParamsInput->Value = json_encode($params);
}
- public function loadBasicUsers($sender, $param) {
- $basic_users = $this->getBasicUsers();
- $this->BasicClientList->dataSource = $basic_users;
- $this->BasicClientList->dataBind();
- $this->BasicClientList->ensureChildControls();
- }
-
- public function loadOAuth2Users($sender, $param) {
- $oauth2_cfg = $this->getModule('oauth2_config')->getConfig();
- $this->OAuth2ClientList->dataSource = array_values($oauth2_cfg);
- $this->OAuth2ClientList->dataBind();
- $this->loadAuthParams(null, null);
- }
-
public function loadAuthParams($sender, $param) {
$ids = $values = array();
$config = $this->getModule('api_config')->getConfig();
$this->AuthParamsCombo->dataBind();
}
- private function getBasicUsers() {
- $basic_users = array();
- $basic_cfg = $this->getModule('basic_apiuser')->getUsers();
- foreach($basic_cfg as $user => $pwd) {
- $basic_users[] = array('username' => $user);
- }
- return $basic_users;
- }
-
- public function deleteBasicItem($sender, $param) {
- $config = $this->getModule('basic_apiuser');
- $config->removeUser($param->getCommandParameter());
- $this->BasicClientList->DataSource = $this->getBasicUsers();
- $this->BasicClientList->dataBind();
- }
-
- public function deleteOAuth2Item($sender, $param) {
- $config = $this->getModule('oauth2_config');
- $clients = $config->getConfig();
- $client_id = $param->getCommandParameter();
- if (key_exists($client_id, $clients)) {
- unset($clients[$client_id]);
- }
- $config->setConfig($clients);
- $this->OAuth2ClientList->DataSource = array_values($config->getConfig());
- $this->OAuth2ClientList->dataBind();
- $this->loadAuthParams(null, null);
- }
-
- public function editOAuth2Item($sender, $param) {
- $config = $this->getModule('oauth2_config');
- $clients = $config->getConfig();
- $client_id = $param->getCommandParameter();
- if (key_exists($client_id, $clients)) {
- $this->APIOAuth2ClientId->Text = $clients[$client_id]['client_id'];
- $this->APIOAuth2ClientSecret->Text = $clients[$client_id]['client_secret'];
- $this->APIOAuth2RedirectURI->Text = $clients[$client_id]['redirect_uri'];
- $this->APIOAuth2Scope->Text = $clients[$client_id]['scope'];
- $this->APIOAuth2BconsoleCfgPath->Text = $clients[$client_id]['bconsole_cfg_path'];
- $this->APIOAuth2Name->Text = $clients[$client_id]['name'];
- }
- $this->APIOAuth2EditPopup->open();
- }
-
- public function saveOAuth2Item($sender, $param) {
- $config = $this->getModule('oauth2_config');
- $clients = $config->getConfig();
- $client_id = $this->APIOAuth2ClientId->Text;
- if (key_exists($client_id, $clients)) {
- $clients[$client_id]['client_id'] = $client_id;
- $clients[$client_id]['client_secret'] = $this->APIOAuth2ClientSecret->Text;
- $clients[$client_id]['redirect_uri'] = $this->APIOAuth2RedirectURI->Text;
- $clients[$client_id]['scope'] = $this->APIOAuth2Scope->Text;
- $clients[$client_id]['bconsole_cfg_path'] = $this->APIOAuth2BconsoleCfgPath->Text;
- $clients[$client_id]['name'] = $this->APIOAuth2Name->Text;
- $config->setConfig($clients);
- }
- $this->APIOAuth2EditPopup->close();
- $this->OAuth2ClientList->DataSource = array_values($clients);
- $this->OAuth2ClientList->dataBind();
- $this->loadAuthParams(null, null);
- }
}
?>
-<%@ MasterClass="Application.API.Layouts.Wizard" Theme="Baculum-v1"%>
+<%@ MasterClass="Application.API.Layouts.Wizard" Theme="Baculum-v2"%>
<com:TContent ID="Wizard">
- <com:BClientScript ScriptUrl=<%~ ../../JavaScript/misc.js %> />
<com:TWizard ID="InstallWizard"
CssClass="wizard"
- StepStyle.CssClass="steps"
- HeaderStyle.CssClass="header"
- NavigationStyle.CssClass="navigation"
+ StepStyle.CssClass="w3-container"
+ HeaderStyle.CssClass="w3-container"
+ NavigationStyle.CssClass="w3-container"
UseDefaultLayout="false"
ShowSideBar="false"
OnCancelButtonClick="wizardStop"
OnCompleteButtonClick="wizardCompleted"
>
<prop:HeaderTemplate>
- <div>
- <div class="step step-<%=($this->Parent->ActiveStepIndex === 0) ? 'first-active' : (($this->Parent->ActiveStepIndex === 1) ? 'first-next-active' : 'first')%>">
- <div><com:TTranslate Text="Language" /></div>
- </div>
- <div class="step step-<%=($this->Parent->ActiveStepIndex === 1) ? 'active' : (($this->Parent->ActiveStepIndex === 2) ? 'prev-active' : 'normal')%>">
- <div><com:TTranslate Text="Catalog API" /></div>
+ <div class="w3-half">
+ <div class="w3-third w3-padding-16">
+ <div class="step w3-padding w3-text-white w3-margin-right <%=($this->Parent->ActiveStepIndex === 0 ? 'w3-light-green' : 'w3-green')%>">
+ <div class="w3-left"><i class="fa fa-language w3-xxxlarge"></i></div>
+ <div class="w3-clear"></div>
+ <h4><com:TTranslate Text="Language" /></h4>
+ </div>
</div>
- <div class="step step-<%=($this->Parent->ActiveStepIndex === 2) ? 'active' : (($this->Parent->ActiveStepIndex === 3) ? 'prev-active' : 'normal')%>">
- <div><com:TTranslate Text="Console API" /></div>
+ <div class="w3-third w3-padding-16">
+ <div class="step w3-padding w3-text-white w3-margin-right <%=($this->Parent->ActiveStepIndex === 1 ? 'w3-light-green' : 'w3-green')%>">
+ <div class="w3-left"><i class="fa fa-database w3-xxxlarge"></i></div>
+ <div class="w3-clear"></div>
+ <h4><com:TTranslate Text="Catalog" /></h4>
+ </div>
</div>
- <div class="step step-<%=($this->Parent->ActiveStepIndex === 3) ? 'active' : (($this->Parent->ActiveStepIndex === 4) ? 'prev-active' : 'normal')%>">
- <div><com:TTranslate Text="Config API" /></div>
+ <div class="w3-third w3-padding-16">
+ <div class="step w3-padding w3-text-white w3-margin-right <%=($this->Parent->ActiveStepIndex === 2 ? 'w3-light-green' : 'w3-green')%>">
+ <div class="w3-left"><i class="fa fa-terminal w3-xxxlarge"></i></div>
+ <div class="w3-clear"></div>
+ <h4><com:TTranslate Text="Console" /></h4>
+ </div>
</div>
- <div class="step step-<%=($this->Parent->ActiveStepIndex === 4) ? 'active' : (($this->Parent->ActiveStepIndex === 5) ? 'prev-active' : 'normal')%>">
- <div><com:TTranslate Text="Actions" /></div>
+ </div>
+ <div class="w3-half">
+ <div class="w3-third w3-padding-16">
+ <div class="step w3-padding w3-text-white w3-margin-right <%=($this->Parent->ActiveStepIndex === 3 ? 'w3-light-green' : 'w3-green')%>">
+ <div class="w3-left"><i class="fa fa-cog w3-xxxlarge"></i></div>
+ <div class="w3-clear"></div>
+ <h4><com:TTranslate Text="Config" /></h4>
+ </div>
</div>
- <div class="step step-<%=($this->Parent->ActiveStepIndex === 5) ? 'active' : (($this->Parent->ActiveStepIndex === 6) ? 'prev-active' : 'normal')%>">
- <div><com:TTranslate Text="Authentication" /></div>
+ <div class="w3-third w3-padding-16">
+ <div class="step w3-padding w3-text-white w3-margin-right <%=($this->Parent->ActiveStepIndex === 4 ? 'w3-light-green' : 'w3-green')%>">
+ <div class="w3-left"><i class="fa fa-key w3-xxxlarge"></i></div>
+ <div class="w3-clear"></div>
+ <h4><com:TTranslate Text="Authentication" /></h4>
+ </div>
</div>
- <div class="step step-<%=($this->Parent->ActiveStepIndex === 6) ? 'last-active' : (($this->Parent->ActiveStepIndex === 7) ? 'last-prev-active' : 'last')%>">
- <div><com:TTranslate Text="Finish" /></div>
+ <div class="w3-third w3-padding-16">
+ <div class="step w3-padding w3-text-white w3-margin-right <%=($this->Parent->ActiveStepIndex === 5 ? 'w3-light-green' : 'w3-green')%>">
+ <div class="w3-left"><i class="fa fa-check-square w3-xxxlarge"></i></div>
+ <div class="w3-clear"></div>
+ <h4><com:TTranslate Text="Finish" /></h4>
+ </div>
</div>
- <div id="title"><%=$this->Parent->ActiveStep->Title%><div>
+ </div>
+ <div class="w3-clear"></div>
+ <div class="w3-green w3-margin-right w3-margin-bottom w3-padding-small">
+ <h3><%=$this->Parent->ActiveStep->Title%></h3>
</div>
</prop:HeaderTemplate>
<prop:StartNavigationTemplate>
- <com:TPanel CssClass="button-cancel" Visible="<%=$this->getPage()->first_run === false%>"><com:BButton CommandName="Cancel" Text="<%[ Cancel ]%>" /></com:TPanel>
- <div <%=$this->getPage()->first_run === false ? 'class="button-prev-next"' : ''%>><com:BButton CommandName="NextStep" Text="<%[ Next » ]%>" /></div>
+ <div class="w3-center w3-section">
+ <com:TLinkButton
+ CommandName="Cancel"
+ CssClass="w3-button w3-red"
+ Visible="<%=$this->getPage()->first_run === false%>"
+ >
+ <i class="fa fa-times"></i> <%[ Cancel ]%>
+ </com:TLinkButton>
+ <com:TLinkButton
+ CommandName="NextStep"
+ CssClass="w3-button w3-green"
+ >
+ <%[ Next ]%> <i class="fa fa-angle-right"></i>
+ </com:TLinkButton>
+ </div>
</prop:StartNavigationTemplate>
<prop:StepNavigationTemplate>
- <com:TPanel CssClass="button-cancel" Visible="<%=$this->getPage()->first_run === false%>"><com:BButton CommandName="Cancel" Text="<%[ Cancel ]%>" /></com:TPanel>
- <div <%=$this->getPage()->first_run === false ? 'class="button-prev-next"' : ''%>>
- <com:BButton CausesValidation="False" CssClass="bbutton" CommandName="PreviousStep" Text="<%[ « Previous ]%>" />
- <com:BButton ID="NextButton" CommandName="NextStep" Attributes.onclick="return (typeof(wizard_validation) == 'function') ? wizard_validation() : true;" Text="<%[ Next » ]%>" />
+ <div class="w3-center w3-section">
+ <com:TLinkButton
+ CommandName="Cancel"
+ CssClass="w3-button w3-red"
+ Visible="<%=$this->getPage()->first_run === false%>"
+ >
+ <i class="fa fa-times"></i> <%[ Cancel ]%>
+ </com:TLinkButton>
+ <com:TLinkButton
+ ID="PreviousStepBtn"
+ CommandName="PreviousStep"
+ CausesValidation="false"
+ CssClass="w3-button w3-green"
+ >
+ <i class="fa fa-angle-left"></i> <%[ Previous ]%>
+ </com:TLinkButton>
+ <com:TLinkButton
+ ID="NextStepBtn"
+ CommandName="NextStep"
+ CssClass="w3-button w3-green"
+ Attributes.onclick="return (typeof(wizard_validation) == 'function') ? wizard_validation() : true;"
+ >
+ <%[ Next ]%> <i class="fa fa-angle-right"></i>
+ </com:TLinkButton>
</div>
</prop:StepNavigationTemplate>
+
<prop:FinishNavigationTemplate>
- <com:TPanel CssClass="button-cancel" Visible="<%=$this->getPage()->first_run === false%>"><com:BButton CommandName="Cancel" Text="<%[ Cancel ]%>" /></com:TPanel>
- <div <%=$this->getPage()->first_run === false ? 'class="button-prev-next"' : ''%>>
- <com:BButton CausesValidation="False" CssClass="bbutton" CommandName="PreviousStep" Text="<%[ « Previous ]%>" />
- <com:BButton CommandName="Complete" Text="<%[ Save ]%>" />
+ <div class="w3-center w3-section">
+ <com:TLinkButton
+ CommandName="Cancel"
+ CssClass="w3-button w3-red"
+ Visible="<%=$this->getPage()->first_run === false%>"
+ >
+ <i class="fa fa-times"></i> <%[ Cancel ]%>
+ </com:TLinkButton>
+ <com:TLinkButton
+ CommandName="PreviousStep"
+ CausesValidation="false"
+ CssClass="w3-button w3-green"
+ >
+ <i class="fa fa-angle-left"></i> <%[ Previous ]%>
+ </com:TLinkButton>
+ <com:TLinkButton
+ CommandName="Complete"
+ CssClass="w3-button w3-green"
+ >
+ <i class="fa fa-save"></i> <%[ Save ]%>
+ </com:TLinkButton>
</div>
</prop:FinishNavigationTemplate>
<com:TWizardStep ID="Step1" Title="<%[ Step 1 - select language ]%>" StepType="Auto">
- <div class="line">
- <div class="text"><com:TLabel ForControl="Lang" Text="<%[ Language: ]%>" /></div>
- <div class="field">
- <com:TActiveDropDownList ID="Lang" CssClass="textbox" Width="150px" OnTextChanged="setLang" CausesValidation="false" ClientSide.OnComplete="location.reload();">
+ <div class="w3-container">
+ <div class="w3-third"><com:TLabel ForControl="Lang" Text="<%[ Language: ]%>" /></div>
+ <div class="w3-third">
+ <com:TActiveDropDownList
+ ID="Lang"
+ CssClass="w3-select w3-border"
+ Width="150px"
+ OnTextChanged="setLang"
+ CausesValidation="false"
+ ClientSide.OnComplete="location.reload();"
+ >
<com:TListItem Value="en" Text="English" />
<com:TListItem Value="pl" Text="Polish" />
<com:TListItem Value="pt" Text="Portuguese" />
</com:TWizardStep>
<com:TWizardStep ID="Step2" Title="<%[ Step 2 - share the Bacula Catalog Database ]%>" StepType="Auto">
<p><%[ Do you want to setup and to share the Bacula Catalog Database access for this API instance? ]%></p>
- <div class="line left">
- <com:TRadioButton ID="DatabaseNo" GroupName="SelectDatabase" Attributes.onclick="$('#configure_database').hide();" /> <com:TLabel ForControl="DatabaseNo" Text="<%[ No ]%>" />
+ <div class="w3-container w3-section">
+ <com:TRadioButton
+ ID="DatabaseNo"
+ CssClass="w3-radio"
+ GroupName="SelectDatabase"
+ Attributes.onclick="$('#configure_database').hide();"
+ /> <com:TLabel ForControl="DatabaseNo" Text="<%[ No ]%>" />
</div>
- <div class="line left">
- <com:TRadioButton ID="DatabaseYes" GroupName="SelectDatabase" Attributes.onclick="$('#configure_database').show();" /> <com:TLabel ForControl="DatabaseYes" Text="<%[ Yes ]%>" />
+ <div class="w3-container w3-section">
+ <com:TRadioButton
+ ID="DatabaseYes"
+ CssClass="w3-radio"
+ GroupName="SelectDatabase"
+ Attributes.onclick="$('#configure_database').show();"
+ /> <com:TLabel ForControl="DatabaseYes" Text="<%[ Yes ]%>" />
</div>
<div id="configure_database" style="display: <%=($this->DatabaseYes->Checked === true) ? '' : 'none';%>">
<com:TActivePanel ID="Step2Content">
- <div class="line">
- <div class="text"><com:TLabel ForControl="DBType" Text="<%[ Database type: ]%>" /></div>
- <div class="field">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="DBType" Text="<%[ Database type: ]%>" /></div>
+ <div class="w3-col w3-third">
<com:TActiveDropDownList
ID="DBType"
- CssClass="textbox"
+ CssClass="w3-select w3-border"
Width="170px"
OnLoad="setDBType"
OnTextChanged="setDBType"
<com:TListItem Value="sqlite" Text="SQLite" />
</com:TActiveDropDownList>
<com:TCompareValidator
- CssClass="validator-block"
Display="Dynamic"
ControlToValidate="DBType"
DataType="String"
/>
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="DBName" Text="<%[ Database name: ]%>" /></div>
- <div class="field">
- <com:TTextBox ID="DBName" CssClass="textbox" />
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="DBName" Text="<%[ Database name: ]%>" /></div>
+ <div class="w3-col w3-third">
+ <com:TTextBox ID="DBName" CssClass="w3-input w3-border" />
<com:TRequiredFieldValidator
- CssClass="validator-block"
Display="Dynamic"
ControlCssClass="invalidate"
ControlToValidate="DBName"
/>
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="Login" Text="<%[ Login: ]%>" /></div>
- <div class="field">
- <com:TActiveTextBox ID="Login" CssClass="textbox" />
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="Login" Text="<%[ Login: ]%>" /></div>
+ <div class="w3-col w3-third">
+ <com:TActiveTextBox ID="Login" CssClass="w3-input w3-border" />
<com:TRequiredFieldValidator
ID="LoginValidator"
- CssClass="validator-block"
Display="Dynamic"
ControlCssClass="invalidate"
ControlToValidate="Login"
/>
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="Password" Text="<%[ Password: ]%>" /></div>
- <div class="field"><com:TActiveTextBox
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="Password" Text="<%[ Password: ]%>" /></div>
+ <div class="w3-col w3-third"><com:TActiveTextBox
ID="Password"
- CssClass="textbox"
+ CssClass="w3-input w3-border"
TextMode="Password"
PersistPassword="true"
/></div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="IP" Text="<%[ IP address (or hostname): ]%>" /></div>
- <div class="field">
- <com:TActiveTextBox ID="IP" CssClass="textbox" />
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="IP" Text="<%[ IP address (or hostname): ]%>" /></div>
+ <div class="w3-col w3-third">
+ <com:TActiveTextBox ID="IP" CssClass="w3-input w3-border" />
<com:TRequiredFieldValidator
ID="IPValidator"
- CssClass="validator-block"
Display="Dynamic"
- ControlCssClass="invalidate"
ControlToValidate="IP"
ValidationGroup="DbGroup"
Text="<%[ Please enter IP address or hostname. ]%>"
/>
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="Port" Text="<%[ Port: ]%>" /></div>
- <div class="field">
- <com:TActiveTextBox ID="Port" CssClass="textbox" Width="55px" MaxLength="5" Enabled="false" />
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="Port" Text="<%[ Port: ]%>" /></div>
+ <div class="w3-col w3-third">
+ <com:TActiveTextBox ID="Port" CssClass="w3-input w3-border" Width="55px" MaxLength="5" Enabled="false" />
<com:TRequiredFieldValidator
ID="PortValidator"
- CssClass="validator-block"
Display="Dynamic"
- ControlCssClass="invalidate"
ControlToValidate="Port"
ValidationGroup="DbGroup"
Text="<%[ Please enter database port. ]%>"
</div>
<com:TActivePanel
ID="DBPathField"
- CssClass="line"
+ CssClass="w3-row w3-section"
Display="<%=$this->getPage()->first_run === false && !$this->IsCallBack && $this->getPage()->config['db']['type'] == 'sqlite' ? 'Fixed' : $this->DBPathField->Display%>">
- <div class="text"><com:TLabel ForControl="DBPath" Text="<%[ SQLite database path: ]%>" /></div>
- <div class="field">
- <com:TActiveTextBox ID="DBPath" CssClass="textbox" Enabled="false" />
+ <div class="w3-col w3-third"><com:TLabel ForControl="DBPath" Text="<%[ SQLite database path: ]%>" /></div>
+ <div class="w3-col w3-third">
+ <com:TActiveTextBox ID="DBPath" CssClass="w3-input w3-border" Enabled="false" />
<com:TRequiredFieldValidator
ID="DBPathValidator"
Display="Dynamic"
- CssClass="validator-block"
- ControlCssClass="invalidate"
ControlToValidate="DBPath"
ValidationGroup="DbGroup"
Text="<%[ Please enter database path. ]%>"
/>
</div>
</com:TActivePanel>
- <div class="line">
- <div class="text" style="vertical-align: top"><com:TLabel ForControl="ConnectionTest" Text="<%[ Connection test: ]%>" CssClass="test_label" /></div>
- <div class="field">
- <table border="0" cellpadding="1px">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third" style="vertical-align: top"><com:TLabel ForControl="ConnectionTest" Text="<%[ Connection test: ]%>" CssClass="test_label" /></div>
+ <div class="w3-col w3-third">
+ <table>
<tr>
<td align="center" valign="middle">
- <com:TActiveButton ID="ConnectionTest" Text="<%[ test ]%>" CausesValidation="false" OnCallback="connectionDBTest">
+ <com:TActiveLinkButton
+ ID="ConnectionTest"
+ CssClass="w3-button w3-green"
+ CausesValidation="false"
+ OnCallback="connectionDBTest"
+ >
<prop:ClientSide.OnLoading>
- $('#<%=$this->DbTestResultOk->ClientID%>').hide();
+ $('#db_test_result_ok').hide();
+ $('#db_test_result_err').hide();
$('#<%=$this->DbTestResultErr->ClientID%>').hide();
- $('#<%=$this->DbTestLoader->ClientID%>').show();
+ $('#db_test_loader').show();
</prop:ClientSide.OnLoading>
<prop:ClientSide.OnComplete>
- $('#<%=$this->DbTestLoader->ClientID%>').hide();
+ $('#db_test_loader').hide();
</prop:ClientSide.OnComplete>
- </com:TActiveButton>
+ <i class="fas fa-play"></i> <%[ test ]%>
+ </com:TActiveLinkButton>
</td>
- <td align="center" valign="middle">
- <com:TActiveLabel ID="DbTestLoader" Display="None"><img src="<%=$this->getTheme()->getBaseUrl()%>/ajax-loader.gif" alt="<%[ Loading... ]%>" /></com:TActiveLabel>
- <com:TActiveLabel ID="DbTestResultOk" Display="None" CssClass="validate"><img src="<%=$this->getTheme()->getBaseUrl()%>/icon_ok.png" alt="Validate" /> <%[ OK ]%></com:TActiveLabel>
- <com:TActiveLabel ID="DbTestResultErr" Display="None" CssClass="validator-block left"><img src="<%=$this->getTheme()->getBaseUrl()%>/icon_err.png" alt="Invalidate" /> <%[ Connection error ]%></com:TActiveLabel>
+ <td style="padding-left: 10px">
+ <span id="db_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <span id="db_test_result_ok" class="w3-text-green" style="display: none">
+ <i class="fas fa-check"></i> <%[ OK ]%>
+ </span>
+ <span id="db_test_result_err" class="w3-text-red" style="display: none">
+ <i class="fas fa-exclamation-circle"></i>
+ </span>
+ <com:TActiveLabel ID="DbTestResultErr" CssClass="w3-text-red" Display="None"><%[ Connection error ]%></com:TActiveLabel>
</td>
</tr>
</table>
</div>
</div>
- <div style="clear: left"></div>
</com:TActivePanel>
</div>
<script type="text/javascript">
</com:TWizardStep>
<com:TWizardStep ID="Step3" Title="<%[ Step 3 - share the Bacula Bconsole commands interface ]%>" StepType="Auto">
<p><%[ Do you want to setup and share the Bacula Bconsole interface to execute commands in this API instance? ]%></p>
- <div class="line left">
- <com:TRadioButton ID="ConsoleNo" GroupName="SelectConsole" Attributes.onclick="$('#configure_console').hide();" /> <com:TLabel ForControl="ConsoleNo" Text="<%[ No ]%>" />
+ <div class="w3-container w3-section">
+ <com:TRadioButton
+ ID="ConsoleNo"
+ GroupName="SelectConsole"
+ CssClass="w3-radio"
+ Attributes.onclick="$('#configure_console').hide();"
+ /> <com:TLabel ForControl="ConsoleNo" Text="<%[ No ]%>" />
</div>
- <div class="line left">
- <com:TRadioButton ID="ConsoleYes" GroupName="SelectConsole" Attributes.onclick="$('#configure_console').show();" /> <com:TLabel ForControl="ConsoleYes" Text="<%[ Yes ]%>" />
+ <div class="w3-container w3-section">
+ <com:TRadioButton
+ ID="ConsoleYes"
+ GroupName="SelectConsole"
+ CssClass="w3-radio"
+ Attributes.onclick="$('#configure_console').show();"
+ /> <com:TLabel ForControl="ConsoleYes" Text="<%[ Yes ]%>" />
</div>
<div id="configure_console" style="display: <%=($this->ConsoleYes->Checked === true) ? '' : 'none';%>">
- <div class="line">
- <div class="text"><com:TLabel ForControl="BconsolePath" Text="<%[ Bconsole binary file path: ]%>" /></div>
- <div class="field">
- <com:TTextBox ID="BconsolePath" CssClass="textbox" CausesValidation="false" />
- <com:TRequiredFieldValidator CssClass="validator-block" Display="Dynamic" ControlCssClass="invalidate" ControlToValidate="BconsolePath" Text="<%[ Please enter bconsole path. ]%>" />
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third">
+ <com:TLabel
+ ForControl="BconsolePath"
+ Text="<%[ Bconsole binary file path: ]%>" />
+ </div>
+ <div class="w3-col w3-third">
+ <com:TTextBox
+ ID="BconsolePath"
+ CssClass="w3-input w3-border"
+ CausesValidation="false"
+ />
+ <com:TRequiredFieldValidator
+ Display="Dynamic"
+ ControlToValidate="BconsolePath"
+ Text="<%[ Please enter bconsole path. ]%>"
+ />
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="BconsoleConfigPath" Text="<%[ Bconsole admin config file path: ]%>" /></div>
- <div class="field">
- <com:TTextBox ID="BconsoleConfigPath" CssClass="textbox" CausesValidation="false" />
- <com:TRequiredFieldValidator CssClass="validator-block" Display="Dynamic" ControlCssClass="invalidate" ControlToValidate="BconsoleConfigPath" Text="<%[ Please enter bconsole config file path. ]%>" />
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third">
+ <com:TLabel
+ ForControl="BconsoleConfigPath"
+ Text="<%[ Bconsole admin config file path: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-third">
+ <com:TTextBox
+ ID="BconsoleConfigPath"
+ CssClass="w3-input w3-border"
+ CausesValidation="false"
+ />
+ <com:TRequiredFieldValidator
+ Display="Dynamic"
+ ControlToValidate="BconsoleConfigPath"
+ Text="<%[ Please enter bconsole config file path. ]%>"
+ />
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="UseSudo" Text="<%[ Use sudo: ]%>" /></div>
- <div class="field">
- <com:TCheckBox ID="UseSudo" /> <a href="javascript:void(0)" onclick="get_sudo_config('bconsole');"><%[ Get sudo configuration ]%></a>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third">
+ <com:TLabel
+ ForControl="UseSudo"
+ Text="<%[ Use sudo: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-third">
+ <com:TCheckBox
+ ID="UseSudo"
+ CssClass="w3-check"
+ /> <a href="javascript:void(0)" onclick="get_sudo_config('bconsole');"><%[ Get sudo configuration ]%></a>
</div>
</div>
- <div class="line">
- <div class="text" style="vertical-align: top"><com:TLabel ForControl="BconsoleConnectionTest" Text="<%[ Bconsole connection test: ]%>" CssClass="test_label" /></div>
- <div class="field">
- <table border="0" cellpadding="1px">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third">
+ <com:TLabel
+ ForControl="BconsoleConnectionTest"
+ Text="<%[ Bconsole connection test: ]%>"
+ /></div>
+ <div class="w3-col w3-third">
+ <table>
<tr>
- <td align="center" valign="middle">
- <com:TActiveButton ID="BconsoleConnectionTest" Text="<%[ test ]%>" CausesValidation="false" OnCallback="connectionBconsoleTest">
+ <td>
+ <com:TActiveLinkButton
+ ID="BconsoleConnectionTest"
+ CssClass="w3-button w3-green"
+ CausesValidation="false"
+ OnCallback="connectionBconsoleTest"
+ >
<prop:ClientSide.OnLoading>
- $('#<%=$this->BconsoleTestResultOk->ClientID%>').hide();
+ $('#bconsole_test_result_ok').hide();
+ $('#bconsole_test_result_err').hide();
$('#<%=$this->BconsoleTestResultErr->ClientID%>').hide();
- $('#<%=$this->BconsoleTestLoader->ClientID%>').show();
+ $('#bconsole_test_loader').show();
</prop:ClientSide.OnLoading>
<prop:ClientSide.OnComplete>
- $('#<%=$this->BconsoleTestLoader->ClientID%>').hide();
+ $('#bconsole_test_loader').hide();
</prop:ClientSide.OnComplete>
- </com:TActiveButton>
+ <i class="fas fa-play"></i> <%[ test ]%>
+ </com:TActiveLinkButton>
</td>
- <td align="center" valign="middle">
- <com:TActiveLabel ID="BconsoleTestLoader" Display="None"><img src="<%=$this->getTheme()->getBaseUrl()%>/ajax-loader.gif" alt="<%[ Loading... ]%>" /></com:TActiveLabel>
- <com:TActiveLabel ID="BconsoleTestResultOk" Display="None" CssClass="validate" EnableViewState="false"><img src="<%=$this->getTheme()->getBaseUrl()%>/icon_ok.png" alt="Validate" /> <%[ OK ]%></com:TActiveLabel>
- <com:TActiveLabel ID="BconsoleTestResultErr" Display="None" CssClass="validator-block left" EnableViewState="false"><img src="<%=$this->getTheme()->getBaseUrl()%>/icon_err.png" alt="Invalidate" /> <%[ Connection error ]%></com:TActiveLabel>
+ <td style="padding-left: 10px">
+ <span id="bconsole_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <span id="bconsole_test_result_ok" class="w3-text-green" style="display: none">
+ <i class="fas fa-check"></i> <%[ OK ]%>
+ </span>
+ <span id="bconsole_test_result_err" class="w3-text-red" style="display: none">
+ <i class="fas fa-exclamation-circle"></i>
+ </span>
+ <com:TActiveLabel ID="BconsoleTestResultErr" CssClass="w3-text-red" Display="None"><%[ Connection error ]%></com:TActiveLabel>
</td>
</tr>
</table>
</com:TWizardStep>
<com:TWizardStep ID="Step4" Title="<%[ Step 4 - share the Bacula configuration interface ]%>" StepType="Auto">
<p><%[ Do you want to setup and share the Bacula configuration interface to configure Bacula components via this API instance? ]%></p>
- <div class="line left">
- <com:TRadioButton ID="ConfigNo" GroupName="SelectConfig" Attributes.onclick="$('#configure_config').hide();" /> <com:TLabel ForControl="ConfigNo" Text="<%[ No ]%>" />
+ <div class="w3-container w3-section">
+ <com:TRadioButton
+ ID="ConfigNo"
+ GroupName="SelectConfig"
+ CssClass="w3-radio"
+ Attributes.onclick="$('#configure_config').hide();"
+ /> <com:TLabel ForControl="ConfigNo" Text="<%[ No ]%>" />
</div>
- <div class="line left">
- <com:TRadioButton ID="ConfigYes" GroupName="SelectConfig" Attributes.onclick="$('#configure_config').show();" /> <com:TLabel ForControl="ConfigYes" Text="<%[ Yes ]%>" />
+ <div class="w3-container w3-section">
+ <com:TRadioButton
+ ID="ConfigYes"
+ GroupName="SelectConfig"
+ CssClass="w3-radio"
+ Attributes.onclick="$('#configure_config').show();"
+ /> <com:TLabel ForControl="ConfigYes" Text="<%[ Yes ]%>" />
</div>
<div id="configure_config" style="display: <%=($this->ConfigYes->Checked === true) ? 'block' : 'none';%>">
- <div id="config_fields">
- <fieldset class="config_field">
- <legend><%[ General configuration ]%></legend>
- <div class="config_lines">
- <div class="line left" title="<%[ In this directory Baculum API saves temporarily Bacula configuration files (mainly for validation purposes) just before they are written as real Bacula configuration files. ]%>">
- <div class="text"><com:TLabel ForControl="BConfigDir" Text="<%[ Baculum working directory for Bacula config: ]%>" /></div>
- <div class="field">
- <com:TRequiredFieldValidator ValidationGroup="ConfigGroup" ControlToValidate="BConfigDir" Display="Dynamic" Text="<%[ Directory path field is required. ]%>" />
- <com:TActiveCustomValidator ID="BConfigDirWritableTest" ValidationGroup="ConfigGroup" ControlToValidate="BConfigDir" Text="<%[ Provided directory path is not writable by web server. ]%>" ControlCssClass="validation-error" Display="Dynamic" OnServerValidate="testConfigDir" CssClass="validator" />
- <com:TTextBox ID="BConfigDir" CssClass="textbox" />
- </div>
- </div>
- <div class="line left">
- <div class="text"><com:TLabel ForControl="BJSONUseSudo" Text="<%[ Use sudo: ]%>" /></div>
- <div class="field">
- <com:TCheckBox ID="BJSONUseSudo" /> <a href="javascript:void(0)" onclick="get_sudo_config('config');"><%[ Get sudo configuration ]%></a>
-
- </div>
- </div>
+ <fieldset>
+ <legend><%[ General configuration ]%></legend>
+ <div class="w3-row w3-section" title="<%[ In this directory Baculum API saves temporarily Bacula configuration files (mainly for validation purposes) just before they are written as real Bacula configuration files. ]%>">
+ <div class="w3-col w3-third">
+ <com:TLabel
+ ForControl="BConfigDir"
+ Text="<%[ Baculum working directory for Bacula config: ]%>"
+ />
</div>
- <span class="config_test_loader" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/ajax-loader.gif" alt="<%[ Loading... ]%>" /></span>
- <com:TActiveLabel ID="BConfigDirTestOk" Display="None" CssClass="validate config_test_result" EnableViewState="false"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_ok.png" alt="<%[ OK ]%>" /> <%[ OK ]%></com:TActiveLabel>
- <com:TActiveLabel ID="BConfigDirTestErr" Display="None" CssClass="validator left" EnableViewState="false"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_err.png" alt="<%[ Error ]%>" /> <%[ Error ]%></com:TActiveLabel>
- </fieldset>
- <fieldset class="config_field">
- <legend>Director</legend>
- <div class="config_lines">
- <div class="line left">
- <div class="text"><com:TLabel ForControl="BDirJSONPath" Text="<%[ bdirjson binary file path: ]%>" /></div>
- <div class="field">
- <com:TCustomValidator ValidationGroup="ConfigGroup" ControlToValidate="BDirJSONPath" ClientValidationFunction="bjsontools_validator" Display="Dynamic" Text="<%[ There is required to provide both binary file and config file paths. ]%>" />
- <com:TTextBox ID="BDirJSONPath" CssClass="textbox" />
- </div>
- </div>
- <div class="line left">
- <div class="text"><com:TLabel ForControl="DirCfgPath" Text="<%[ Main Director config file path (usually bacula-dir.conf): ]%>" /></div>
- <div class="field">
- <com:TCustomValidator ValidationGroup="ConfigGroup" ControlToValidate="DirCfgPath" ClientValidationFunction="bjsontools_validator" Display="Dynamic" Text="<%[ There is required to provide both binary file and config file paths. ]%>" />
- <com:TTextBox ID="DirCfgPath" CssClass="textbox" />
- </div>
- </div>
+ <div class="w3-col w3-twothird">
+ <com:TTextBox
+ ID="BConfigDir"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <span class="config_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <com:TActiveLabel
+ ID="BConfigDirTestOk"
+ Display="None"
+ CssClass="w3-text-green"
+ EnableViewState="false"
+ >
+ <i class="fas fa-check" title="<%[ OK ]%>"></i> <%[ OK ]%>
+ </com:TActiveLabel>
+ <com:TActiveLabel
+ ID="BConfigDirTestErr"
+ Display="None"
+ CssClass="w3-text-red"
+ EnableViewState="false"
+ >
+ <!--i class="fas fa-exclamation-circle" title="<%[ Error ]%>"></i--> <%[ Error ]%>
+ </com:TActiveLabel>
+ <com:TRequiredFieldValidator
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="BConfigDir"
+ Display="Dynamic"
+ Text="<%[ Directory path field is required. ]%>"
+ />
+ <com:TActiveCustomValidator
+ ID="BConfigDirWritableTest"
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="BConfigDir"
+ Text="<%[ Provided directory path is not writable by web server. ]%>"
+ Display="Dynamic"
+ OnServerValidate="testConfigDir"
+ />
</div>
- <span class="config_test_loader" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/ajax-loader.gif" alt="<%[ Loading... ]%>" /></span>
- <com:TActiveLabel ID="BDirJSONPathTestOk" Display="None" CssClass="validate config_test_result" EnableViewState="false"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_ok.png" alt="<%[ OK ]%>" /> <%[ OK ]%></com:TActiveLabel>
- <com:TActiveLabel ID="BDirJSONPathTestErr" Display="None" CssClass="validator left" EnableViewState="false"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_err.png" alt="<%[ Connection error ]%>" /> <%[ Connection error ]%></com:TActiveLabel>
- </fieldset>
- <fieldset class="config_field">
- <legend>Storage Daemon</legend>
- <div class="config_lines">
- <div class="line left">
- <div class="text"><com:TLabel ForControl="BSdJSONPath" Text="<%[ bsdjson binary file path: ]%>" /></div>
- <div class="field">
- <com:TCustomValidator ValidationGroup="ConfigGroup" ControlToValidate="BSdJSONPath" ClientValidationFunction="bjsontools_validator" Display="Dynamic" Text="<%[ There is required to provide both binary file and config file paths. ]%>" />
- <com:TTextBox ID="BSdJSONPath" CssClass="textbox" />
- </div>
- </div>
- <div class="line left">
- <div class="text"><com:TLabel ForControl="SdCfgPath" Text="<%[ Main Storage Daemon config file path (usually bacula-sd.conf): ]%>" /></div>
- <div class="field">
- <com:TCustomValidator ValidationGroup="ConfigGroup" ControlToValidate="SdCfgPath" ClientValidationFunction="bjsontools_validator" Display="Dynamic" Text="<%[ There is required to provide both binary file and config file paths. ]%>" />
- <com:TTextBox ID="SdCfgPath" CssClass="textbox" />
- </div>
- </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third">
+ <com:TLabel
+ ForControl="BJSONUseSudo"
+ Text="<%[ Use sudo: ]%>"
+ />
</div>
- <span class="config_test_loader" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/ajax-loader.gif" alt="<%[ Loading... ]%>" /></span>
- <com:TActiveLabel ID="BSdJSONPathTestOk" Display="None" CssClass="validate config_test_result" EnableViewState="false"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_ok.png" alt="<%[ OK ]%>" /> <%[ OK ]%></com:TActiveLabel>
- <com:TActiveLabel ID="BSdJSONPathTestErr" Display="None" CssClass="validator left" EnableViewState="false"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_err.png" alt="<%[ Connection error ]%>" /> <%[ Connection error ]%></com:TActiveLabel>
- </fieldset>
- <fieldset class="config_field">
- <legend>File Daemon/Client</legend>
- <div class="config_lines">
- <div class="line left">
- <div class="text"><com:TLabel ForControl="BFdJSONPath" Text="<%[ bfdjson binary file path: ]%>" /></div>
- <div class="field">
- <com:TCustomValidator ValidationGroup="ConfigGroup" ControlToValidate="BFdJSONPath" ClientValidationFunction="bjsontools_validator" Display="Dynamic" Text="<%[ There is required to provide both binary file and config file paths. ]%>" />
- <com:TTextBox ID="BFdJSONPath" CssClass="textbox" />
- </div>
- </div>
- <div class="line left">
- <div class="text"><com:TLabel ForControl="FdCfgPath" Text="<%[ Main File Daemon config file path (usually bacula-fd.conf): ]%>" /></div>
- <div class="field">
- <com:TCustomValidator ValidationGroup="ConfigGroup" ControlToValidate="FdCfgPath" ClientValidationFunction="bjsontools_validator" Display="Dynamic" Text="<%[ There is required to provide both binary file and config file paths. ]%>" />
- <com:TTextBox ID="FdCfgPath" CssClass="textbox" />
- </div>
- </div>
+ <div class="w3-col w3-twothird">
+ <com:TCheckBox
+ ID="BJSONUseSudo"
+ CssClass="w3-check"
+ /> <a href="javascript:void(0)" onclick="get_sudo_config('config');"><%[ Get sudo configuration ]%></a>
+ </div>
+ </div>
+ </fieldset>
+ <fieldset>
+ <legend>Director</legend>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third">
+ <com:TLabel
+ ForControl="BDirJSONPath"
+ Text="<%[ bdirjson binary file path: ]%>"
+ />
</div>
- <span class="config_test_loader" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/ajax-loader.gif" alt="<%[ Loading... ]%>" /></span>
- <com:TActiveLabel ID="BFdJSONPathTestOk" Display="None" CssClass="validate config_test_result" EnableViewState="false"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_ok.png" alt="<%[ OK ]%>" /> <%[ OK ]%></com:TActiveLabel>
- <com:TActiveLabel ID="BFdJSONPathTestErr" Display="None" CssClass="validator left" EnableViewState="false"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_err.png" alt="<%[ Connection error ]%>" /> <%[ Connection error ]%></com:TActiveLabel>
- </fieldset>
- <fieldset class="config_field">
- <legend>Bconsole</legend>
- <div class="config_lines">
- <div class="line left">
- <div class="text"><com:TLabel ForControl="BBconsJSONPath" Text="<%[ bbconsjson binary file path: ]%>" /></div>
- <div class="field">
- <com:TCustomValidator ValidationGroup="ConfigGroup" ControlToValidate="BBconsJSONPath" ClientValidationFunction="bjsontools_validator" Display="Dynamic" Text="<%[ There is required to provide both binary file and config file paths. ]%>" />
- <com:TTextBox ID="BBconsJSONPath" CssClass="textbox" />
- </div>
- </div>
- <div class="line left">
- <div class="text"><com:TLabel ForControl="BconsCfgPath" Text="<%[ Admin Bconsole config file path (usually bconsole.conf): ]%>" /></div>
- <div class="field">
- <com:TCustomValidator ValidationGroup="ConfigGroup" ControlToValidate="BconsCfgPath" ClientValidationFunction="bjsontools_validator" Display="Dynamic" Text="<%[ There is required to provide both binary file and config file paths. ]%>" />
- <com:TTextBox ID="BconsCfgPath" CssClass="textbox" />
- </div>
- </div>
+ <div class="w3-col w3-twothird">
+ <com:TTextBox
+ ID="BDirJSONPath"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <span class="config_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <com:TActiveLabel
+ ID="BDirJSONPathTestOk"
+ Display="None"
+ CssClass="w3-text-green"
+ EnableViewState="false"
+ >
+ <i class="fas fa-check" title="<%[ OK ]%>"></i> <%[ OK ]%>
+ </com:TActiveLabel>
+ <com:TCustomValidator
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="BDirJSONPath"
+ ClientValidationFunction="bjsontools_validator"
+ Display="Dynamic"
+ Text="<%[ There is required to provide both binary file and config file paths. ]%>"
+ />
+ <com:TActiveLabel
+ ID="BDirJSONPathTestErr"
+ Display="None"
+ CssClass="w3-text-red"
+ EnableViewState="false"
+ >
+ <i class="fas fa-exclamation-circle" title="<%[ Error ]%>"></i> <%[ Connection error ]%>
+ </com:TActiveLabel>
</div>
- <span class="config_test_loader" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/ajax-loader.gif" alt="<%[ Loading... ]%>" /></span>
- <com:TActiveLabel ID="BBconsJSONPathTestOk" Display="None" CssClass="validate config_test_result" EnableViewState="false"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_ok.png" alt="<%[ OK ]%>" /> <%[ OK ]%></com:TActiveLabel>
- <com:TActiveLabel ID="BBconsJSONPathTestErr" Display="None" CssClass="validator left" EnableViewState="false"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_err.png" alt="<%[ Connection error ]%>" /> <%[ Connection error ]%></com:TActiveLabel>
- </fieldset>
- <div class="left button">
- <com:BActiveButton ID="TestJSONToolsConfig" ValidationGroup="ConfigGroup" Text="<%[ Test configuration ]%>" OnClick="testJSONToolsCfg">
- <prop:ClientSide.OnLoading>
- bjsontools_hide_test_results();
- $('.config_test_loader').show();
- </prop:ClientSide.OnLoading>
- <prop:ClientSide.OnComplete>
- $('.config_test_loader').hide();
- </prop:ClientSide.OnComplete>
- </com:BActiveButton>
</div>
- </div>
- </div>
- </com:TWizardStep>
- <com:TWizardStep ID="Step5" Title="<%[ Step 5 - enable actions for components ]%>" StepType="Auto">
- <p><%[ Do you want to setup start, stop and restart actions for Bacula components? If you define them, there will be possible to call these actions via API interface and by Baculum Web as well. ]%></p>
- <div class="line left">
- <com:TRadioButton ID="ActionsNo" GroupName="SelectActions" Attributes.onclick="$('#configure_actions').hide();" /> <com:TLabel ForControl="ActionsNo" Text="<%[ No ]%>" />
- </div>
- <div class="line left">
- <com:TRadioButton ID="ActionsYes" GroupName="SelectActions" Attributes.onclick="$('#configure_actions').show();" /> <com:TLabel ForControl="ActionsYes" Text="<%[ Yes ]%>" />
- </div>
- <div id="configure_actions" style="display: <%=($this->ActionsYes->Checked === true) ? 'block' : 'none';%>">
- <div id="actions_fields">
- <fieldset class="actions_field">
- <legend><%[ General configuration ]%></legend>
- <div class="actions_lines">
- <div class="line left">
- <div class="text"><com:TLabel ForControl="ActionsUseSudo" Text="<%[ Use sudo: ]%>" /></div>
- <div class="field">
- <com:TCheckBox ID="ActionsUseSudo" /> <a href="javascript:void(0)" onclick="get_sudo_config('actions');"><%[ Get sudo configuration ]%></a>
- </div>
- </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third">
+ <com:TLabel
+ ForControl="DirCfgPath"
+ Text="<%[ Main Director config file path (usually bacula-dir.conf): ]%>"
+ />
</div>
- </fieldset>
- <fieldset class="actions_field">
- <legend>Director</legend>
- <div class="actions_lines">
- <div class="line left">
- <div class="text"><com:TLabel ForControl="DirStartAction" Text="<%[ Director start command: ]%>" /></div>
- <div class="field">
- <com:TTextBox ID="DirStartAction" CssClass="textbox" />
- </div>
- <div class="button">
- <com:TActiveButton ID="TestDirStartActionCommand" ValidationGroup="ActionsGroup" Text="<%[ Start ]%>" OnCommand="testExecActionCommand" CommandParameter="dir_start">
- <prop:ClientSide.OnLoading>
- actions_hide_test_results('<%=$this->TestDirStartActionCommand->CommandParameter%>');
- $('#actions_test_result_dir_start .action_test_loader').show();
- </prop:ClientSide.OnLoading>
- <prop:ClientSide.OnComplete>
- $('#actions_test_result_dir_start .action_test_loader').hide();
- </prop:ClientSide.OnComplete>
- </com:TActiveButton>
- </div>
- <span id="actions_test_result_dir_start">
- <span class="action_test_loader" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/ajax-loader.gif" alt="<%[ Loading... ]%>" /></span>
- <span class="action_success" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_ok.png" alt="<%[ OK ]%>" /> <%[ OK ]%></span>
- <span class="action_error" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_err.png" alt="<%[ Error ]%>" /> <%[ Error ]%></span>
- <span class="action_result validator"></span>
- </span>
- </div>
- <div class="line left">
- <div class="text"><com:TLabel ForControl="DirStopAction" Text="<%[ Director stop command: ]%>" /></div>
- <div class="field">
- <com:TTextBox ID="DirStopAction" CssClass="textbox" />
- </div>
- <div class="button">
- <com:TActiveButton ID="TestDirStopActionCommand" ValidationGroup="ActionsGroup" Text="<%[ Stop ]%>" OnCommand="testExecActionCommand" CommandParameter="dir_stop">
- <prop:ClientSide.OnLoading>
- actions_hide_test_results('<%=$this->TestDirStopActionCommand->CommandParameter%>');
- $('#actions_test_result_dir_stop .action_test_loader').show();
- </prop:ClientSide.OnLoading>
- <prop:ClientSide.OnComplete>
- $('#actions_test_result_dir_stop .action_test_loader').hide();
- </prop:ClientSide.OnComplete>
- </com:TActiveButton>
- </div>
- <span id="actions_test_result_dir_stop">
- <span class="action_test_loader" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/ajax-loader.gif" alt="<%[ Loading... ]%>" /></span>
- <span class="action_success" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_ok.png" alt="<%[ OK ]%>" /> <%[ OK ]%></span>
- <span class="action_error" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_err.png" alt="<%[ Error ]%>" /> <%[ Error ]%></span>
- <span class="action_result validator"></span>
- </span>
- </div>
- <div class="line left">
- <div class="text"><com:TLabel ForControl="DirRestartAction" Text="<%[ Director restart command: ]%>" /></div>
- <div class="field">
- <com:TTextBox ID="DirRestartAction" CssClass="textbox" />
- </div>
- <div class="button">
- <com:TActiveButton ID="TestDirRestartActionCommand" ValidationGroup="ActionsGroup" Text="<%[ Restart ]%>" OnCommand="testExecActionCommand" CommandParameter="dir_restart">
- <prop:ClientSide.OnLoading>
- actions_hide_test_results('<%=$this->TestDirRestartActionCommand->CommandParameter%>');
- $('#actions_test_result_dir_restart .action_test_loader').show();
- </prop:ClientSide.OnLoading>
- <prop:ClientSide.OnComplete>
- $('#actions_test_result_dir_restart .action_test_loader').hide();
- </prop:ClientSide.OnComplete>
- </com:TActiveButton>
- </div>
- <span id="actions_test_result_dir_restart">
- <span class="action_test_loader" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/ajax-loader.gif" alt="<%[ Loading... ]%>" /></span>
- <span class="action_success" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_ok.png" alt="<%[ OK ]%>" /> <%[ OK ]%></span>
- <span class="action_error" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_err.png" alt="<%[ Error ]%>" /> <%[ Error ]%></span>
- <span class="action_result validator"></span>
- </span>
- </div>
+ <div class="w3-col w3-twothird">
+ <com:TTextBox
+ ID="DirCfgPath"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <com:TCustomValidator
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="DirCfgPath"
+ ClientValidationFunction="bjsontools_validator"
+ Display="Dynamic"
+ Text="<%[ There is required to provide both binary file and config file paths. ]%>"
+ />
</div>
- </fieldset>
- <fieldset class="actions_field">
- <legend>Storage Daemon</legend>
- <div class="actions_lines">
- <div class="line left">
- <div class="text"><com:TLabel ForControl="SdStartAction" Text="<%[ Storage Daemon start command: ]%>" /></div>
- <div class="field">
- <com:TTextBox ID="SdStartAction" CssClass="textbox" />
- </div>
- <div class="button">
- <com:TActiveButton ID="TestSdStartActionCommand" ValidationGroup="ActionsGroup" Text="<%[ Start ]%>" OnCommand="testExecActionCommand" CommandParameter="sd_start">
- <prop:ClientSide.OnLoading>
- actions_hide_test_results('<%=$this->TestSdStartActionCommand->CommandParameter%>');
- $('#actions_test_result_sd_start .action_test_loader').show();
- </prop:ClientSide.OnLoading>
- <prop:ClientSide.OnComplete>
- $('#actions_test_result_sd_start .action_test_loader').hide();
- </prop:ClientSide.OnComplete>
- </com:TActiveButton>
- </div>
- <span id="actions_test_result_sd_start">
- <span class="action_test_loader" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/ajax-loader.gif" alt="<%[ Loading... ]%>" /></span>
- <span class="action_success" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_ok.png" alt="<%[ OK ]%>" /> <%[ OK ]%></span>
- <span class="action_error" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_err.png" alt="<%[ Error ]%>" /> <%[ Error ]%></span>
- <span class="action_result validator"></span>
- </span>
- </div>
- <div class="line left">
- <div class="text"><com:TLabel ForControl="SdStopAction" Text="<%[ Storage Daemon stop command: ]%>" /></div>
- <div class="field">
- <com:TTextBox ID="SdStopAction" CssClass="textbox" />
- </div>
- <div class="button">
- <com:TActiveButton ID="TestSdStopActionCommand" ValidationGroup="ActionsGroup" Text="<%[ Stop ]%>" OnCommand="testExecActionCommand" CommandParameter="sd_stop">
- <prop:ClientSide.OnLoading>
- actions_hide_test_results('<%=$this->TestSdStopActionCommand->CommandParameter%>');
- $('#actions_test_result_sd_stop .action_test_loader').show();
- </prop:ClientSide.OnLoading>
- <prop:ClientSide.OnComplete>
- $('#actions_test_result_sd_stop .action_test_loader').hide();
- </prop:ClientSide.OnComplete>
- </com:TActiveButton>
- </div>
- <span id="actions_test_result_sd_stop">
- <span class="action_test_loader" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/ajax-loader.gif" alt="<%[ Loading... ]%>" /></span>
- <span class="action_success" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_ok.png" alt="<%[ OK ]%>" /> <%[ OK ]%></span>
- <span class="action_error" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_err.png" alt="<%[ Error ]%>" /> <%[ Error ]%></span>
- <span class="action_result validator"></span>
- </span>
- </div>
- <div class="line left">
- <div class="text"><com:TLabel ForControl="SdRestartAction" Text="<%[ Storage Daemon restart command: ]%>" /></div>
- <div class="field">
- <com:TTextBox ID="SdRestartAction" CssClass="textbox" />
- </div>
- <div class="button">
- <com:TActiveButton ID="TestSdRestartActionCommand" ValidationGroup="ActionsGroup" Text="<%[ Restart ]%>" OnCommand="testExecActionCommand" CommandParameter="sd_restart">
- <prop:ClientSide.OnLoading>
- actions_hide_test_results('<%=$this->TestSdRestartActionCommand->CommandParameter%>');
- $('#actions_test_result_sd_restart .action_test_loader').show();
- </prop:ClientSide.OnLoading>
- <prop:ClientSide.OnComplete>
- $('#actions_test_result_sd_restart .action_test_loader').hide();
- </prop:ClientSide.OnComplete>
- </com:TActiveButton>
- </div>
- <span id="actions_test_result_sd_restart">
- <span class="action_test_loader" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/ajax-loader.gif" alt="<%[ Loading... ]%>" /></span>
- <span class="action_success" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_ok.png" alt="<%[ OK ]%>" /> <%[ OK ]%></span>
- <span class="action_error" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_err.png" alt="<%[ Error ]%>" /> <%[ Error ]%></span>
- <span class="action_result validator"></span>
- </span>
- </div>
+ </div>
+ </fieldset>
+ <fieldset>
+ <legend>Storage Daemon</legend>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third">
+ <com:TLabel
+ ForControl="BSdJSONPath"
+ Text="<%[ bsdjson binary file path: ]%>"
+ />
</div>
- </fieldset>
- <fieldset class="actions_field">
- <legend>File Daemon/Client</legend>
- <div class="actions_lines">
- <div class="line left">
- <div class="text"><com:TLabel ForControl="FdStartAction" Text="<%[ File Daemon/Client start command: ]%>" /></div>
- <div class="field">
- <com:TTextBox ID="FdStartAction" CssClass="textbox" />
- </div>
- <div class="button">
- <com:TActiveButton ID="TestFdStartActionCommand" ValidationGroup="ActionsGroup" Text="<%[ Start ]%>" OnCommand="testExecActionCommand" CommandParameter="fd_start">
- <prop:ClientSide.OnLoading>
- actions_hide_test_results('<%=$this->TestFdStartActionCommand->CommandParameter%>');
- $('#actions_test_result_fd_start .action_test_loader').show();
- </prop:ClientSide.OnLoading>
- <prop:ClientSide.OnComplete>
- $('#actions_test_result_fd_start .action_test_loader').hide();
- </prop:ClientSide.OnComplete>
- </com:TActiveButton>
- </div>
- <span id="actions_test_result_fd_start">
- <span class="action_test_loader" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/ajax-loader.gif" alt="<%[ Loading... ]%>" /></span>
- <span class="action_success" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_ok.png" alt="<%[ OK ]%>" /> <%[ OK ]%></span>
- <span class="action_error" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_err.png" alt="<%[ Error ]%>" /> <%[ Error ]%></span>
- <span class="action_result validator"></span>
- </span>
- </div>
- <div class="line left">
- <div class="text"><com:TLabel ForControl="FdStopAction" Text="<%[ File Daemon/Client stop command: ]%>" /></div>
- <div class="field">
- <com:TTextBox ID="FdStopAction" CssClass="textbox" />
- </div>
- <div class="button">
- <com:TActiveButton ID="TestFdStopActionCommand" ValidationGroup="ActionsGroup" Text="<%[ Stop ]%>" OnCommand="testExecActionCommand" CommandParameter="fd_stop">
- <prop:ClientSide.OnLoading>
- actions_hide_test_results('<%=$this->TestFdStopActionCommand->CommandParameter%>');
- $('#actions_test_result_fd_stop .action_test_loader').show();
- </prop:ClientSide.OnLoading>
- <prop:ClientSide.OnComplete>
- $('#actions_test_result_fd_stop .action_test_loader').hide();
- </prop:ClientSide.OnComplete>
- </com:TActiveButton>
- </div>
- <span id="actions_test_result_fd_stop">
- <span class="action_test_loader" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/ajax-loader.gif" alt="<%[ Loading... ]%>" /></span>
- <span class="action_success" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_ok.png" alt="<%[ OK ]%>" /> <%[ OK ]%></span>
- <span class="action_error" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_err.png" alt="<%[ Error ]%>" /> <%[ Error ]%></span>
- <span class="action_result validator"></span>
- </span>
- </div>
- <div class="line left">
- <div class="text"><com:TLabel ForControl="FdRestartAction" Text="<%[ File Daemon/Client restart command: ]%>" /></div>
- <div class="field">
- <com:TTextBox ID="FdRestartAction" CssClass="textbox" />
- </div>
- <div class="button">
- <com:TActiveButton ID="TestFdRestartActionCommand" ValidationGroup="ActionsGroup" Text="<%[ Restart ]%>" OnCommand="testExecActionCommand" CommandParameter="fd_restart">
- <prop:ClientSide.OnLoading>
- actions_hide_test_results('<%=$this->TestFdRestartActionCommand->CommandParameter%>');
- $('#actions_test_result_fd_restart .action_test_loader').show();
- </prop:ClientSide.OnLoading>
- <prop:ClientSide.OnComplete>
- $('#actions_test_result_fd_restart .action_test_loader').hide();
- </prop:ClientSide.OnComplete>
- </com:TActiveButton>
- </div>
- <span id="actions_test_result_fd_restart">
- <span class="action_test_loader" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/ajax-loader.gif" alt="<%[ Loading... ]%>" /></span>
- <span class="action_success" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_ok.png" alt="<%[ OK ]%>" /> <%[ OK ]%></span>
- <span class="action_error" style="display: none"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_err.png" alt="<%[ Error ]%>" /> <%[ Error ]%></span>
- <span class="action_result validator"></span>
- </span>
- </div>
+ <div class="w3-col w3-twothird">
+ <com:TTextBox
+ ID="BSdJSONPath"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <span class="config_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <com:TCustomValidator
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="BSdJSONPath"
+ ClientValidationFunction="bjsontools_validator"
+ Display="Dynamic"
+ Text="<%[ There is required to provide both binary file and config file paths. ]%>"
+ />
+ <com:TActiveLabel
+ ID="BSdJSONPathTestOk"
+ Display="None"
+ CssClass="w3-text-green"
+ EnableViewState="false"
+ >
+ <i class="fas fa-check" title="<%[ OK ]%>"></i> <%[ OK ]%>
+ </com:TActiveLabel>
+ <com:TActiveLabel
+ ID="BSdJSONPathTestErr"
+ Display="None"
+ CssClass="w3-text-red"
+ EnableViewState="false"
+ >
+ <i class="fas fa-exclamation-circle" title="<%[ Error ]%>"></i> <%[ Connection error ]%>
+ </com:TActiveLabel>
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third">
+ <com:TLabel
+ ForControl="SdCfgPath"
+ Text="<%[ Main Storage Daemon config file path (usually bacula-sd.conf): ]%>"
+ />
+ </div>
+ <div class="w3-col w3-twothird">
+ <com:TTextBox
+ ID="SdCfgPath"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <com:TCustomValidator
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="SdCfgPath"
+ ClientValidationFunction="bjsontools_validator"
+ Display="Dynamic"
+ Text="<%[ There is required to provide both binary file and config file paths. ]%>"
+ />
+ </div>
+ </div>
+ </fieldset>
+ <fieldset>
+ <legend>File Daemon/Client</legend>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third">
+ <com:TLabel
+ ForControl="BFdJSONPath"
+ Text="<%[ bfdjson binary file path: ]%>"
+ />
</div>
- </fieldset>
+ <div class="w3-col w3-twothird">
+ <com:TTextBox
+ ID="BFdJSONPath"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <com:TCustomValidator
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="BFdJSONPath"
+ ClientValidationFunction="bjsontools_validator"
+ Display="Dynamic"
+ Text="<%[ There is required to provide both binary file and config file paths. ]%>"
+ />
+ <span class="config_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <com:TActiveLabel
+ ID="BFdJSONPathTestOk"
+ Display="None"
+ CssClass="w3-text-green"
+ EnableViewState="false"
+ >
+ <i class="fas fa-check" title="<%[ OK ]%>"></i> <%[ OK ]%>
+ </com:TActiveLabel>
+ <com:TActiveLabel
+ ID="BFdJSONPathTestErr"
+ Display="None"
+ CssClass="w3-text-red"
+ EnableViewState="false"
+ >
+ <i class="fas fa-exclamation-circle" title="<%[ Error ]%>"></i> <%[ Connection error ]%>
+ </com:TActiveLabel>
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third">
+ <com:TLabel
+ ForControl="FdCfgPath"
+ Text="<%[ Main File Daemon config file path (usually bacula-fd.conf): ]%>"
+ />
+ </div>
+ <div class="w3-col w3-twothird">
+ <com:TTextBox
+ ID="FdCfgPath"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <com:TCustomValidator
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="FdCfgPath"
+ ClientValidationFunction="bjsontools_validator"
+ Display="Dynamic"
+ Text="<%[ There is required to provide both binary file and config file paths. ]%>"
+ />
+ </div>
+ </div>
+ </fieldset>
+ <fieldset>
+ <legend>Bconsole</legend>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third">
+ <com:TLabel
+ ForControl="BBconsJSONPath"
+ Text="<%[ bbconsjson binary file path: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-twothird">
+ <com:TCustomValidator
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="BBconsJSONPath"
+ ClientValidationFunction="bjsontools_validator"
+ Display="Dynamic"
+ Text="<%[ There is required to provide both binary file and config file paths. ]%>"
+ />
+ <com:TTextBox
+ ID="BBconsJSONPath"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <span class="config_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <com:TActiveLabel
+ ID="BBconsJSONPathTestOk"
+ Display="None"
+ CssClass="w3-text-green"
+ EnableViewState="false"
+ >
+ <i class="fas fa-check" title="<%[ OK ]%>"></i> <%[ OK ]%>
+ </com:TActiveLabel>
+ <com:TActiveLabel
+ ID="BBconsJSONPathTestErr"
+ Display="None"
+ CssClass="w3-text-red"
+ EnableViewState="false"
+ >
+ <i class="fas fa-exclamation-circle" title="<%[ Error ]%>"></i> <%[ Connection error ]%>
+ </com:TActiveLabel>
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third">
+ <com:TLabel
+ ForControl="BconsCfgPath"
+ Text="<%[ Admin Bconsole config file path (usually bconsole.conf): ]%>"
+ />
+ </div>
+ <div class="w3-col w3-twothird">
+ <com:TTextBox
+ ID="BconsCfgPath"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <com:TCustomValidator
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="BconsCfgPath"
+ ClientValidationFunction="bjsontools_validator"
+ Display="Dynamic"
+ Text="<%[ There is required to provide both binary file and config file paths. ]%>"
+ />
+ </div>
+ </div>
+ </fieldset>
+ <div class="w3-center w3-margin-top">
+ <com:TActiveLinkButton
+ ID="TestJSONToolsConfig"
+ ValidationGroup="ConfigGroup"
+ OnClick="testJSONToolsCfg"
+ CssClass="w3-button w3-green"
+ >
+ <prop:ClientSide.OnLoading>
+ bjsontools_hide_test_results();
+ $('.config_test_loader').show();
+ </prop:ClientSide.OnLoading>
+ <prop:ClientSide.OnComplete>
+ $('.config_test_loader').hide();
+ </prop:ClientSide.OnComplete>
+ <i class="fas fa-play"></i> <%[ Test configuration ]%>
+ </com:TActiveLinkButton>
</div>
</div>
</com:TWizardStep>
- <com:TWizardStep ID="Step6" Title="<%[ Step 6 - authentication to API ]%>" StepType="Auto">
- <div class="line left" style="width:500px; margin: 0 auto">
+ <com:TWizardStep ID="Step5" Title="<%[ Step 5 - authentication to API ]%>" StepType="Auto">
+ <div class="w3-container w3-section">
<com:TActiveRadioButton
ID="AuthOAuth2"
GroupName="SelectAuth"
+ CssClass="w3-radio"
Attributes.onclick="$('#configure_basic_auth').hide();$('#configure_oauth2_auth').show();"
/>
<com:TLabel
Text="<%[ Use OAuth2 for authorization and authentication ]%>"
/>
</div>
- <div class="line left" style="width:500px; margin: 0 auto">
+ <div class="w3-container w3-section">
<com:TActiveRadioButton
ID="AuthBasic"
GroupName="SelectAuth"
+ CssClass="w3-radio"
Checked="true"
Attributes.onclick="$('#configure_oauth2_auth').hide();$('#configure_basic_auth').show();"
/>
</div>
<div id="configure_basic_auth" style="display: <%=($this->AuthBasic->Checked === true) ? '' : 'none';%>">
<com:TPanel Visible="<%=$this->first_run%>">
- <div class="line">
- <div class="text"><com:TLabel ForControl="APILogin" Text="<%[ Administration login: ]%>" /></div>
- <div class="field">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="APILogin" Text="<%[ Administration login: ]%>" /></div>
+ <div class="w3-col w3-twothird">
<com:TTextBox
ID="APILogin"
- CssClass="textbox"
+ CssClass="w3-input w3-border w3-show-inline-block"
CausesValidation="false"
+ Width="370px"
/>
<com:TRequiredFieldValidator
- CssClass="validator-block"
Display="Dynamic"
- ControlCssClass="invalidate"
ControlToValidate="APILogin"
ValidationGroup="Basic"
Text="<%[ Please enter login. ]%>"
/>
<com:TRegularExpressionValidator
- CssClass="validator-block"
Display="Dynamic"
- ControlCssClass="invalidate"
ControlToValidate="APILogin"
ValidationGroup="Basic"
RegularExpression="<%=BasicAPIUserConfig::USER_PATTERN%>"
/>
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIPassword" Text="<%[ Administration password: ]%>" /></div>
- <div class="field">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="APIPassword" Text="<%[ Administration password: ]%>" /></div>
+ <div class="w3-col w3-twothird">
<com:TTextBox
ID="APIPassword"
- CssClass="textbox"
+ CssClass="w3-input w3-border w3-show-inline-block"
TextMode="Password"
MaxLength="60"
PersistPassword="true"
+ Width="370px"
/>
<com:TRequiredFieldValidator
- CssClass="validator-block"
Display="Dynamic"
- ControlCssClass="invalidate"
ControlToValidate="APIPassword"
ValidationGroup="Basic"
Text="<%[ Please enter password. ]%>"
/>
<com:TRegularExpressionValidator
- CssClass="validator-block"
Display="Dynamic"
- ControlCssClass="invalidate"
ControlToValidate="APIPassword"
RegularExpression="[\S\s]{5,60}"
ValidationGroup="Basic"
/>
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="RetypeAPIPassword" Text="<%[ Retype administration password: ]%>" /></div>
- <div class="field">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="RetypeAPIPassword" Text="<%[ Retype administration password: ]%>" /></div>
+ <div class="w3-col w3-twothird">
<com:TTextBox
ID="RetypeAPIPassword"
- CssClass="textbox"
+ CssClass="w3-input w3-border w3-show-inline-block"
TextMode="Password"
MaxLength="60"
PersistPassword="true"
+ Width="370px"
/>
<com:TRequiredFieldValidator
ID="RetypePasswordRequireValidator"
- CssClass="validator-block"
Display="Dynamic"
- ControlCssClass="invalidate"
ControlToValidate="RetypeAPIPassword"
ValidationGroup="Basic"
Text="<%[ Please enter retype password. ]%>"
/>
<com:TRegularExpressionValidator
ID="RetypePasswordRegexpValidator"
- CssClass="validator-block"
Display="Dynamic"
- ControlCssClass="invalidate"
ControlToValidate="RetypeAPIPassword"
RegularExpression="[\S\s]{5,60}"
ValidationGroup="Basic"
/>
<com:TCompareValidator
ID="RetypePasswordCustomValidator"
- CssClass="validator-block"
Display="Dynamic"
- ControlCssClass="invalidate"
ControlToValidate="RetypeAPIPassword"
ControlToCompare="APIPassword"
ValidationGroup="Basic"
<com:TPanel Visible="<%=($this->first_run || $this->add_auth_params)%>">
<h3><%[ First client registration ]%></h3>
<h4><%[ Please do not forget to disable HTTP Basic auth in the API web server config. Othwerise OAuth2 will not work. ]%></h4>
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIOAuth2ClientId" Text="<%[ OAuth2 Client ID: ]%>" /></div>
- <div class="field">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="APIOAuth2ClientId" Text="<%[ OAuth2 Client ID: ]%>" /></div>
+ <div class="w3-col w3-twothird">
<com:TTextBox
ID="APIOAuth2ClientId"
- CssClass="textbox"
+ CssClass="w3-input w3-border w3-show-inline-block"
CausesValidation="false"
MaxLength="32"
+ Width="370px"
/>
<com:TRequiredFieldValidator
CssClass="validator-block"
<a href="javascript:void(0)" onclick="document.getElementById('<%=$this->APIOAuth2ClientId->ClientID%>').value = get_random_string('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', 32); return false;"><%[ generate ]%></a>
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIOAuth2ClientSecret" Text="<%[ OAuth2 Client Secret: ]%>" /></div>
- <div class="field">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="APIOAuth2ClientSecret" Text="<%[ OAuth2 Client Secret: ]%>" /></div>
+ <div class="w3-col w3-twothird">
<com:TTextBox
ID="APIOAuth2ClientSecret"
- CssClass="textbox"
+ CssClass="w3-input w3-border w3-show-inline-block"
CausesValidation="false"
MaxLength="50"
+ Width="370px"
/>
<com:TRequiredFieldValidator
CssClass="validator-block"
<a href="javascript:void(0)" onclick="document.getElementById('<%=$this->APIOAuth2ClientSecret->ClientID%>').value = get_random_string('ABCDEFabcdef0123456789', 40); return false;"><%[ generate ]%></a>
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIOAuth2RedirectURI" Text="<%[ OAuth2 Redirect URI (example: https://baculumgui:9095/web/redirect): ]%>" /></div>
- <div class="field">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="APIOAuth2RedirectURI" Text="<%[ OAuth2 Redirect URI (example: https://baculumgui:9095/web/redirect): ]%>" /></div>
+ <div class="w3-col w3-twothird">
<com:TTextBox
ID="APIOAuth2RedirectURI"
- CssClass="textbox"
+ CssClass="w3-input w3-border w3-show-inline-block"
CausesValidation="false"
+ Width="370px"
/>
<com:TRequiredFieldValidator
CssClass="validator-block"
/>
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIOAuth2Scope" Text="<%[ OAuth2 scopes (space separated): ]%>" /></div>
- <div class="field">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="APIOAuth2Scope" Text="<%[ OAuth2 scopes (space separated): ]%>" /></div>
+ <div class="w3-col w3-twothird">
<com:TTextBox
ID="APIOAuth2Scope"
- CssClass="textbox"
+ CssClass="w3-input w3-border w3-show-inline-block"
CausesValidation="false"
TextMode="MultiLine"
+ Width="370px"
/>
<a href="javascript:void(0)" onclick="set_scopes('<%=$this->APIOAuth2Scope->ClientID%>'); return false;" style="vertical-align: top"><%[ set all scopes ]%></a>
<com:TRequiredFieldValidator
/>
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIOAuth2BconsoleCfgPath" Text="<%[ Dedicated Bconsole config file path: ]%>" /></div>
- <div class="field">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="APIOAuth2BconsoleCfgPath" Text="<%[ Dedicated Bconsole config file path: ]%>" /></div>
+ <div class="w3-col w3-twothird">
<com:TTextBox
ID="APIOAuth2BconsoleCfgPath"
- CssClass="textbox"
+ CssClass="w3-input w3-border w3-show-inline-block"
CausesValidation="false"
ValidationGroup="OAuth2"
+ Width="370px"
/> <%[ (optional) ]%>
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIOAuth2Name" Text="<%[ Short name: ]%>" /></div>
- <div class="field">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="APIOAuth2Name" Text="<%[ Short name: ]%>" /></div>
+ <div class="w3-col w3-twothird">
<com:TTextBox
ID="APIOAuth2Name"
- CssClass="textbox"
+ CssClass="w3-input w3-border w3-show-inline-block"
CausesValidation="false"
+ Width="370px"
/> <%[ (optional) ]%>
</div>
</div>
} else if (oauth2.checked === true) {
validation_group = 'OAuth2';
}
- return Prado.Validation.validate(Prado.Validation.getForm(), validation_group);
+ var ret = true;
+ if (Prado.Validation) {
+ ret = Prado.Validation.validate(Prado.Validation.getForm(), validation_group);
+ }
+ return ret;
}
</script>
</com:TWizardStep>
<fieldset>
<legend><%[ Catalog API ]%></legend>
<div style="display: <%=($this->DatabaseYes->Checked ? 'block' : 'none')%>">
- <div class="line">
- <div class="text"><%[ Database type: ]%></div>
- <div class="field bold"><%=$this->getDbNameByType($this->DBType->SelectedValue)%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Database type: ]%></div>
+ <div class="w3-col w3-third"><strong><%=$this->getDbNameByType($this->DBType->SelectedValue)%></strong></div>
</div>
- <div class="line">
- <div class="text"><%[ Database name: ]%></div>
- <div class="field bold"><%=$this->DBName->Text%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Database name: ]%></div>
+ <div class="w3-col w3-third"><strong><%=$this->DBName->Text%></strong></div>
</div>
- <div class="line">
- <div class="text"><%[ Login: ]%></div>
- <div class="field bold"><%=$this->isSQLiteType($this->DBType->SelectedValue) === false ? $this->Login->Text : '-'%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Login: ]%></div>
+ <div class="w3-col w3-third"><strong><%=$this->isSQLiteType($this->DBType->SelectedValue) === false ? $this->Login->Text : '-'%></strong></div>
</div>
- <div class="line">
- <div class="text"><%[ Password: ]%></div>
- <div class="field bold"><%=$this->isSQLiteType($this->DBType->SelectedValue) === false ? preg_replace('/.{1}/', '*', $this->Password->Text) : '-'%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Password: ]%></div>
+ <div class="w3-col w3-third"><strong><%=$this->isSQLiteType($this->DBType->SelectedValue) === false ? preg_replace('/.{1}/', '*', $this->Password->Text) : '-'%></strong></div>
</div>
- <div class="line">
- <div class="text"><%[ IP address (or hostname): ]%></div>
- <div class="field bold"><%=$this->isSQLiteType($this->DBType->SelectedValue) === false ? $this->IP->Text : '-'%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ IP address (or hostname): ]%></div>
+ <div class="w3-col w3-third"><strong><%=$this->isSQLiteType($this->DBType->SelectedValue) === false ? $this->IP->Text : '-'%></strong></div>
</div>
- <div class="line">
- <div class="text"><%[ Database port: ]%></div>
- <div class="field bold"><%=$this->isSQLiteType($this->DBType->SelectedValue) === false ? $this->Port->Text : '-'%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Database port: ]%></div>
+ <div class="w3-col w3-third"><strong><%=$this->isSQLiteType($this->DBType->SelectedValue) === false ? $this->Port->Text : '-'%></strong></div>
</div>
- <div class="line">
- <div class="text"><%[ Database file path (SQLite only): ]%></div>
- <div class="field bold"><%=$this->isSQLiteType($this->DBType->SelectedValue) === true ? $this->DBPath->Text : '-'%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Database file path (SQLite only): ]%></div>
+ <div class="w3-col w3-third"><strong><%=$this->isSQLiteType($this->DBType->SelectedValue) === true ? $this->DBPath->Text : '-'%></strong></div>
</div>
</div>
<div style="display: <%=($this->DatabaseNo->Checked ? 'block' : 'none')%>">
- <div class="line">
- <div class="text"><%[ Catalog access: ]%></div>
- <div class="field bold"><%[ Disabled ]%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Catalog access: ]%></div>
+ <div class="w3-col w3-third"><strong><%[ Disabled ]%></strong></div>
</div>
</div>
</fieldset>
<fieldset>
<legend><%[ Console API ]%></legend>
<div style="display: <%=($this->ConsoleYes->Checked ? 'block' : 'none')%>">
- <div class="line">
- <div class="text"><%[ Bconsole binary file path: ]%></div>
- <div class="field bold"><%=$this->BconsolePath->Text%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Bconsole binary file path: ]%></div>
+ <div class="w3-col w3-third"><strong><%=$this->BconsolePath->Text%></strong></div>
</div>
- <div class="line">
- <div class="text"><%[ Bconsole admin config file path: ]%></div>
- <div class="field bold"><%=$this->BconsoleConfigPath->Text%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Bconsole admin config file path: ]%></div>
+ <div class="w3-col w3-third"><strong><%=$this->BconsoleConfigPath->Text%></strong></div>
</div>
- <div class="line">
- <div class="text"><%[ Use sudo for bconsole requests: ]%></div>
- <div class="field bold"><%=($this->UseSudo->Checked === true) ? 'yes' : 'no'%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Use sudo for bconsole requests: ]%></div>
+ <div class="w3-col w3-third"><strong><%=($this->UseSudo->Checked === true) ? 'yes' : 'no'%></strong></div>
</div>
</div>
<div style="display: <%=($this->ConsoleNo->Checked ? 'block' : 'none')%>">
- <div class="line">
- <div class="text"><%[ Console access: ]%></div>
- <div class="field bold"><%[ Disabled ]%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Console access: ]%></div>
+ <div class="w3-col w3-third"><strong><%[ Disabled ]%></strong></div>
</div>
</div>
</fieldset>
<fieldset>
<legend><%[ Config API ]%></legend>
<div style="display: <%=($this->ConfigYes->Checked ? 'block' : 'none')%>">
- <div class="line">
- <div class="text"><%[ Directory path for new config files: ]%></div>
- <div class="field bold"><%=$this->BConfigDir->Text%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Directory path for new config files: ]%></div>
+ <div class="w3-col w3-third"><strong><%=$this->BConfigDir->Text%></strong></div>
</div>
- <div class="line">
- <div class="text"><%[ Use sudo for Bacula JSON tools: ]%></div>
- <div class="field bold"><%=($this->BJSONUseSudo->Checked === true) ? 'yes' : 'no'%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Use sudo for Bacula JSON tools: ]%></div>
+ <div class="w3-col w3-third"><strong><%=($this->BJSONUseSudo->Checked === true) ? 'yes' : 'no'%></strong></div>
</div>
- <div class="line">
- <div class="text"><%[ bdirjson binary file path: ]%></div>
- <div class="field bold"><%=$this->BDirJSONPath->Text%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ bdirjson binary file path: ]%></div>
+ <div class="w3-col w3-third"><strong><%=$this->BDirJSONPath->Text%></strong></div>
</div>
- <div class="line">
- <div class="text"><%[ Main Director config file path: ]%></div>
- <div class="field bold"><%=$this->DirCfgPath->Text%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Main Director config file path: ]%></div>
+ <div class="w3-col w3-third"><strong><%=$this->DirCfgPath->Text%></strong></div>
</div>
- <div class="line">
- <div class="text"><%[ bsdjson binary file path: ]%></div>
- <div class="field bold"><%=$this->BSdJSONPath->Text%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ bsdjson binary file path: ]%></div>
+ <div class="w3-col w3-third"><strong><%=$this->BSdJSONPath->Text%></strong></div>
</div>
- <div class="line">
- <div class="text"><%[ Main Storage Daemon config file path: ]%></div>
- <div class="field bold"><%=$this->SdCfgPath->Text%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Main Storage Daemon config file path: ]%></div>
+ <div class="w3-col w3-third"><strong><%=$this->SdCfgPath->Text%></strong></div>
</div>
- <div class="line">
- <div class="text"><%[ bfdjson binary file path: ]%></div>
- <div class="field bold"><%=$this->BFdJSONPath->Text%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ bfdjson binary file path: ]%></div>
+ <div class="w3-col w3-third"><strong><%=$this->BFdJSONPath->Text%></strong></div>
</div>
- <div class="line">
- <div class="text"><%[ Main Client config file path: ]%></div>
- <div class="field bold"><%=$this->FdCfgPath->Text%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Main Client config file path: ]%></div>
+ <div class="w3-col w3-third"><strong><%=$this->FdCfgPath->Text%></strong></div>
</div>
- <div class="line">
- <div class="text"><%[ bbconsjson binary file path: ]%></div>
- <div class="field bold"><%=$this->BBconsJSONPath->Text%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ bbconsjson binary file path: ]%></div>
+ <div class="w3-col w3-third"><strong><%=$this->BBconsJSONPath->Text%></strong></div>
</div>
- <div class="line">
- <div class="text"><%[ Main Bconsole config file path: ]%></div>
- <div class="field bold"><%=$this->BconsCfgPath->Text%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Main Bconsole config file path: ]%></div>
+ <div class="w3-col w3-third"><strong><%=$this->BconsCfgPath->Text%></strong></div>
</div>
</div>
<div style="display: <%=($this->ConfigNo->Checked ? 'block' : 'none')%>">
- <div class="line">
- <div class="text"><%[ Config access: ]%></div>
- <div class="field bold"><%[ Disabled ]%></div>
- </div>
- </div>
- </fieldset>
- <fieldset>
- <legend><%[ Actions ]%></legend>
- <div style="display: <%=($this->ActionsYes->Checked ? 'block' : 'none')%>">
- <div class="line">
- <div class="text"><%[ Use sudo for actions: ]%></div>
- <div class="field bold"><%=($this->ActionsUseSudo->Checked === true) ? 'yes' : 'no'%></div>
- </div>
- <div class="line">
- <div class="text"><%[ Director start command: ]%></div>
- <div class="field bold"><%=$this->DirStartAction->Text%></div>
- </div>
- <div class="line">
- <div class="text"><%[ Director stop command: ]%></div>
- <div class="field bold"><%=$this->DirStopAction->Text%></div>
- </div>
- <div class="line">
- <div class="text"><%[ Director restart command: ]%></div>
- <div class="field bold"><%=$this->DirRestartAction->Text%></div>
- </div>
- <div class="line">
- <div class="text"><%[ Storage Daemon start command: ]%></div>
- <div class="field bold"><%=$this->SdStartAction->Text%></div>
- </div>
- <div class="line">
- <div class="text"><%[ Storage Daemon stop command: ]%></div>
- <div class="field bold"><%=$this->SdStopAction->Text%></div>
- </div>
- <div class="line">
- <div class="text"><%[ Storage Daemon restart command: ]%></div>
- <div class="field bold"><%=$this->SdRestartAction->Text%></div>
- </div>
- <div class="line">
- <div class="text"><%[ File Daemon/Client start command: ]%></div>
- <div class="field bold"><%=$this->FdStartAction->Text%></div>
- </div>
- <div class="line">
- <div class="text"><%[ File Daemon/Client stop command: ]%></div>
- <div class="field bold"><%=$this->FdStopAction->Text%></div>
- </div>
- <div class="line">
- <div class="text"><%[ File Daemon/Client restart command: ]%></div>
- <div class="field bold"><%=$this->FdRestartAction->Text%></div>
- </div>
- </div>
- <div style="display: <%=($this->ActionsNo->Checked ? 'block' : 'none')%>">
- <div class="line">
- <div class="text"><%[ Actions setting: ]%></div>
- <div class="field bold"><%[ Disabled ]%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Config access: ]%></div>
+ <div class="w3-col w3-third"><strong><%[ Disabled ]%></strong></div>
</div>
</div>
</fieldset>
<fieldset>
<legend><%[ Authentication to Baculum REST API ]%></legend>
- <div class="line">
- <div class="text"><%[ Authentication type: ]%></div>
- <div class="field bold">
- <%=$this->AuthBasic->Checked ? 'HTTP Basic' : ''%>
- <%=$this->AuthOAuth2->Checked ? 'OAuth2' : ''%>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Authentication type: ]%></div>
+ <div class="w3-col w3-third">
+ <strong>
+ <%=$this->AuthBasic->Checked ? 'HTTP Basic' : ''%>
+ <%=$this->AuthOAuth2->Checked ? 'OAuth2' : ''%>
+ </strong>
</div>
</div>
<com:TPanel Visible="<%=$this->first_run%>">
<div style="display: <%=$this->AuthBasic->Checked ? 'block' : 'none'%>">
- <div class="line">
- <div class="text"><%[ Administration login: ]%></div>
- <div class="field bold"><%=$this->APILogin->Text%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Administration login: ]%></div>
+ <div class="w3-col w3-third"><strong><%=$this->APILogin->Text%></strong></div>
</div>
- <div class="line">
- <div class="text"><%[ Administration password: ]%></div>
- <div class="field bold"><%=preg_replace('/.{1}/', '*', $this->APIPassword->Text)%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Administration password: ]%></div>
+ <div class="w3-col w3-third"><strong><%=preg_replace('/.{1}/', '*', $this->APIPassword->Text)%></strong></div>
</div>
</div>
</com:TPanel>
<com:TPanel Visible="<%=($this->first_run || $this->add_auth_params)%>">
<div style="display: <%=$this->AuthOAuth2->Checked ? 'block' : 'none'%>">
- <div class="line">
- <div class="text">Client ID:</div>
- <div class="field bold"><%=$this->APIOAuth2ClientId->Text%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third">Client ID:</div>
+ <div class="w3-col w3-third"><strong><%=$this->APIOAuth2ClientId->Text%></strong></div>
</div>
- <div class="line">
- <div class="text">Client Secret:</div>
- <div class="field bold"><%=preg_replace('/.{1}/', '*', $this->APIOAuth2ClientSecret->Text)%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third">Client Secret:</div>
+ <div class="w3-col w3-third"><strong><%=preg_replace('/.{1}/', '*', $this->APIOAuth2ClientSecret->Text)%></strong></div>
</div>
- <div class="line">
- <div class="text">Redirect URI:</div>
- <div class="field bold"><%=$this->APIOAuth2RedirectURI->Text%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third">Redirect URI:</div>
+ <div class="w3-col w3-third"><strong><%=$this->APIOAuth2RedirectURI->Text%></strong></div>
</div>
- <div class="line">
- <div class="text">Scope:</div>
- <div class="field bold"><%=$this->APIOAuth2Scope->Text%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third">Scope:</div>
+ <div class="w3-col w3-third"><strong><%=$this->APIOAuth2Scope->Text%></strong></div>
</div>
- <div class="line">
- <div class="text"><%[ Dedicated Bconsole config file path: ]%></div>
- <div class="field bold"><%=!empty($this->APIOAuth2BconsoleCfgPath->Text) ? $this->APIOAuth2BconsoleCfgPath->Text : '-'%></div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><%[ Dedicated Bconsole config file path: ]%></div>
+ <div class="w3-col w3-third"><strong><%=!empty($this->APIOAuth2BconsoleCfgPath->Text) ? $this->APIOAuth2BconsoleCfgPath->Text : '-'%></strong></div>
</div>
</div>
</com:TPanel>
ID="SudoConfigPopup"
Options.title="<%[ Sudo configuration ]%>"
Options.autoOpen="false",
- Options.minWidth="600"
+ Options.minWidth="820"
Options.minHeight="200"
>
<p><%[ Please copy appropriate sudo configuration and put it to a new sudoers.d file for example /etc/sudoers.d/baculum-api ]%></p>
'<%=$this->BSdJSONPath->ClientID%>',
'<%=$this->BFdJSONPath->ClientID%>',
'<%=$this->BBconsJSONPath->ClientID%>',
- ],
- actions: [
- '<%=$this->DirStartAction->ClientID%>',
- '<%=$this->DirStopAction->ClientID%>',
- '<%=$this->DirRestartAction->ClientID%>',
- '<%=$this->SdStartAction->ClientID%>',
- '<%=$this->SdStopAction->ClientID%>',
- '<%=$this->SdRestartAction->ClientID%>',
- '<%=$this->FdStartAction->ClientID%>',
- '<%=$this->FdStopAction->ClientID%>',
- '<%=$this->FdRestartAction->ClientID%>'
]
}
var val, pre;
* Bacula(R) - The Network Backup Solution
* Baculum - Bacula web interface
*
- * Copyright (C) 2013-2020 Kern Sibbald
+ * Copyright (C) 2013-2021 Kern Sibbald
*
* The main author of Baculum is Marcin Haba.
* The original author of Bacula is Kern Sibbald, with contributions
public function onLoad($param) {
parent::onLoad($param);
$this->Port->setViewState('port', $this->Port->Text);
- if(!$this->IsPostBack && !$this->IsCallBack) {
- if($this->first_run === true) {
- $this->DBName->Text = self::DEFAULT_DB_NAME;
- $this->Login->Text = self::DEFAULT_DB_LOGIN;
- $this->BconsolePath->Text = self::DEFAULT_BCONSOLE_BIN;
- $this->BconsoleConfigPath->Text = self::DEFAULT_BCONSOLE_CONF;
- $this->BDirJSONPath->Text = self::DEFAULT_BDIRJSON_BIN;
- $this->DirCfgPath->Text = self::DEFAULT_DIR_CONF;
- $this->BSdJSONPath->Text = self::DEFAULT_BSDJSON_BIN;
- $this->SdCfgPath->Text = self::DEFAULT_SD_CONF;
- $this->BFdJSONPath->Text = self::DEFAULT_BFDJSON_BIN;
- $this->FdCfgPath->Text = self::DEFAULT_FD_CONF;
- $this->BBconsJSONPath->Text = self::DEFAULT_BBCONJSON_BIN;
- $this->BconsCfgPath->Text = self::DEFAULT_BCONSOLE_CONF;
-
- $this->DirStartAction->Text = self::DEFAULT_ACTION_DIR_START;
- $this->DirStopAction->Text = self::DEFAULT_ACTION_DIR_STOP;
- $this->DirRestartAction->Text = self::DEFAULT_ACTION_DIR_RESTART;
- $this->SdStartAction->Text = self::DEFAULT_ACTION_SD_START;
- $this->SdStopAction->Text = self::DEFAULT_ACTION_SD_STOP;
- $this->SdRestartAction->Text = self::DEFAULT_ACTION_SD_RESTART;
- $this->FdStartAction->Text = self::DEFAULT_ACTION_FD_START;
- $this->FdStopAction->Text = self::DEFAULT_ACTION_FD_STOP;
- $this->FdRestartAction->Text = self::DEFAULT_ACTION_FD_RESTART;
+ if ($this->IsPostBack || $this->IsCallBack) {
+ return;
+ }
+ if ($this->first_run === true) {
+ $this->DBName->Text = self::DEFAULT_DB_NAME;
+ $this->Login->Text = self::DEFAULT_DB_LOGIN;
+ $this->BconsolePath->Text = self::DEFAULT_BCONSOLE_BIN;
+ $this->BconsoleConfigPath->Text = self::DEFAULT_BCONSOLE_CONF;
+ $this->BDirJSONPath->Text = self::DEFAULT_BDIRJSON_BIN;
+ $this->DirCfgPath->Text = self::DEFAULT_DIR_CONF;
+ $this->BSdJSONPath->Text = self::DEFAULT_BSDJSON_BIN;
+ $this->SdCfgPath->Text = self::DEFAULT_SD_CONF;
+ $this->BFdJSONPath->Text = self::DEFAULT_BFDJSON_BIN;
+ $this->FdCfgPath->Text = self::DEFAULT_FD_CONF;
+ $this->BBconsJSONPath->Text = self::DEFAULT_BBCONJSON_BIN;
+ $this->BconsCfgPath->Text = self::DEFAULT_BCONSOLE_CONF;
+
+ $this->DatabaseNo->Checked = true;
+ $this->ConsoleNo->Checked = true;
+ $this->ConfigNo->Checked = true;
+ } else {
+ // Database param settings
+ if ($this->config['db']['enabled'] == 1) {
+ $this->DatabaseYes->Checked = true;
+ $this->DatabaseNo->Checked = false;
+ } else {
+ $this->DatabaseYes->Checked = false;
$this->DatabaseNo->Checked = true;
- $this->ConsoleNo->Checked = true;
- $this->ConfigNo->Checked = true;
- $this->ActionsNo->Checked = true;
+ }
+ $this->DBType->SelectedValue = $this->config['db']['type'];
+ $this->DBName->Text = $this->config['db']['name'];
+ $this->Login->Text = $this->config['db']['login'];
+ $this->Password->Text = $this->config['db']['password'];
+ $this->IP->Text = $this->config['db']['ip_addr'];
+ $this->Port->Text = $this->config['db']['port'];
+ $this->Port->setViewState('port', $this->config['db']['port']);
+ $this->DBPath->Text = $this->config['db']['path'];
+
+ // Bconsole param settings
+ if ($this->config['bconsole']['enabled'] == 1) {
+ $this->ConsoleYes->Checked = true;
+ $this->ConsoleNo->Checked = false;
} else {
- // Database param settings
- if ($this->config['db']['enabled'] == 1) {
- $this->DatabaseYes->Checked = true;
- $this->DatabaseNo->Checked = false;
- } else {
- $this->DatabaseYes->Checked = false;
- $this->DatabaseNo->Checked = true;
- }
- $this->DBType->SelectedValue = $this->config['db']['type'];
- $this->DBName->Text = $this->config['db']['name'];
- $this->Login->Text = $this->config['db']['login'];
- $this->Password->Text = $this->config['db']['password'];
- $this->IP->Text = $this->config['db']['ip_addr'];
- $this->Port->Text = $this->config['db']['port'];
- $this->Port->setViewState('port', $this->config['db']['port']);
- $this->DBPath->Text = $this->config['db']['path'];
-
- // Bconsole param settings
- if ($this->config['bconsole']['enabled'] == 1) {
- $this->ConsoleYes->Checked = true;
- $this->ConsoleNo->Checked = false;
- } else {
- $this->ConsoleYes->Checked = false;
- $this->ConsoleNo->Checked = true;
- }
- $this->BconsolePath->Text = $this->config['bconsole']['bin_path'];
- $this->BconsoleConfigPath->Text = $this->config['bconsole']['cfg_path'];
- $this->UseSudo->Checked = $this->getPage()->config['bconsole']['use_sudo'] == 1;
-
- $api_config = $this->getModule('api_config');
+ $this->ConsoleYes->Checked = false;
+ $this->ConsoleNo->Checked = true;
+ }
+ $this->BconsolePath->Text = $this->config['bconsole']['bin_path'];
+ $this->BconsoleConfigPath->Text = $this->config['bconsole']['cfg_path'];
+ $this->UseSudo->Checked = $this->getPage()->config['bconsole']['use_sudo'] == 1;
- // JSONTools param settings
- if ($api_config->isJSONToolsEnabled() === true) {
- $this->ConfigYes->Checked = true;
- $this->ConfigNo->Checked = false;
- } else {
- $this->ConfigYes->Checked = false;
- $this->ConfigNo->Checked = true;
- }
- $this->BConfigDir->Text = $this->config['jsontools']['bconfig_dir'];
- $this->BJSONUseSudo->Checked = ($this->config['jsontools']['use_sudo'] == 1);
- $this->BDirJSONPath->Text = $this->config['jsontools']['bdirjson_path'];
- $this->DirCfgPath->Text = $this->config['jsontools']['dir_cfg_path'];
- $this->BSdJSONPath->Text = $this->config['jsontools']['bsdjson_path'];
- $this->SdCfgPath->Text = $this->config['jsontools']['sd_cfg_path'];
- $this->BFdJSONPath->Text = $this->config['jsontools']['bfdjson_path'];
- $this->FdCfgPath->Text = $this->config['jsontools']['fd_cfg_path'];
- $this->BBconsJSONPath->Text = $this->config['jsontools']['bbconsjson_path'];
- $this->BconsCfgPath->Text = $this->config['jsontools']['bcons_cfg_path'];
-
- if ($api_config->isActionsConfigured()) {
- // Action params
- if ($api_config->isActionsEnabled() === true) {
- $this->ActionsYes->Checked = true;
- $this->ActionsNo->Checked = false;
- } else {
- $this->ActionsYes->Checked = false;
- $this->ActionsNo->Checked = true;
- }
-
- $this->ActionsUseSudo->Checked = ($this->config['actions']['use_sudo'] == 1);
- $this->DirStartAction->Text = $this->config['actions']['dir_start'];
- $this->DirStopAction->Text = $this->config['actions']['dir_stop'];
- $this->DirRestartAction->Text = $this->config['actions']['dir_restart'];
- $this->SdStartAction->Text = $this->config['actions']['sd_start'];
- $this->SdStopAction->Text = $this->config['actions']['sd_stop'];
- $this->SdRestartAction->Text = $this->config['actions']['sd_restart'];
- $this->FdStartAction->Text = $this->config['actions']['fd_start'];
- $this->FdStopAction->Text = $this->config['actions']['fd_stop'];
- $this->FdRestartAction->Text = $this->config['actions']['fd_restart'];
- } else {
- $this->ActionsYes->Checked = false;
- $this->ActionsNo->Checked = true;
- $this->ActionsUseSudo->Checked = false;
- $this->DirStartAction->Text = self::DEFAULT_ACTION_DIR_START;
- $this->DirStopAction->Text = self::DEFAULT_ACTION_DIR_STOP;
- $this->DirRestartAction->Text = self::DEFAULT_ACTION_DIR_RESTART;
- $this->SdStartAction->Text = self::DEFAULT_ACTION_SD_START;
- $this->SdStopAction->Text = self::DEFAULT_ACTION_SD_STOP;
- $this->SdRestartAction->Text = self::DEFAULT_ACTION_SD_RESTART;
- $this->FdStartAction->Text = self::DEFAULT_ACTION_FD_START;
- $this->FdStopAction->Text = self::DEFAULT_ACTION_FD_STOP;
- $this->FdRestartAction->Text = self::DEFAULT_ACTION_FD_RESTART;
- }
+ $api_config = $this->getModule('api_config');
- if ($this->config['api']['auth_type'] === 'basic') {
- // API basic auth data
- $this->AuthBasic->Checked = true;
- $this->AuthOAuth2->Checked = false;
- } elseif ($this->config['api']['auth_type'] === 'oauth2') {
- // API oauth2 auth data
- $this->AuthBasic->Checked = false;
- $this->AuthOAuth2->Checked = true;
- }
+ // JSONTools param settings
+ if ($api_config->isJSONToolsEnabled() === true) {
+ $this->ConfigYes->Checked = true;
+ $this->ConfigNo->Checked = false;
+ } else {
+ $this->ConfigYes->Checked = false;
+ $this->ConfigNo->Checked = true;
+ }
+ $this->BConfigDir->Text = $this->config['jsontools']['bconfig_dir'];
+ $this->BJSONUseSudo->Checked = ($this->config['jsontools']['use_sudo'] == 1);
+ $this->BDirJSONPath->Text = $this->config['jsontools']['bdirjson_path'];
+ $this->DirCfgPath->Text = $this->config['jsontools']['dir_cfg_path'];
+ $this->BSdJSONPath->Text = $this->config['jsontools']['bsdjson_path'];
+ $this->SdCfgPath->Text = $this->config['jsontools']['sd_cfg_path'];
+ $this->BFdJSONPath->Text = $this->config['jsontools']['bfdjson_path'];
+ $this->FdCfgPath->Text = $this->config['jsontools']['fd_cfg_path'];
+ $this->BBconsJSONPath->Text = $this->config['jsontools']['bbconsjson_path'];
+ $this->BconsCfgPath->Text = $this->config['jsontools']['bcons_cfg_path'];
+
+ if ($this->config['api']['auth_type'] === 'basic') {
+ // API basic auth data
+ $this->AuthBasic->Checked = true;
+ $this->AuthOAuth2->Checked = false;
+ } elseif ($this->config['api']['auth_type'] === 'oauth2') {
+ // API oauth2 auth data
+ $this->AuthBasic->Checked = false;
+ $this->AuthOAuth2->Checked = true;
}
}
}
'api' => array(),
'db' => array(),
'bconsole' => array(),
- 'jsontools' => array(),
- 'actions' => array()
+ 'jsontools' => array()
);
if ($this->AuthBasic->Checked) {
$cfg_data['api']['auth_type'] = 'basic';
$cfg_data['jsontools']['fd_cfg_path'] = $this->FdCfgPath->Text;
$cfg_data['jsontools']['bbconsjson_path'] = $this->BBconsJSONPath->Text;
$cfg_data['jsontools']['bcons_cfg_path'] = $this->BconsCfgPath->Text;
- $cfg_data['actions']['enabled'] = (integer)($this->ActionsYes->Checked === true);
- $cfg_data['actions']['use_sudo'] = (integer)($this->ActionsUseSudo->Checked === true);
- $cfg_data['actions']['dir_start'] = $this->DirStartAction->Text;
- $cfg_data['actions']['dir_stop'] = $this->DirStopAction->Text;
- $cfg_data['actions']['dir_restart'] = $this->DirRestartAction->Text;
- $cfg_data['actions']['sd_start'] = $this->SdStartAction->Text;
- $cfg_data['actions']['sd_stop'] = $this->SdStopAction->Text;
- $cfg_data['actions']['sd_restart'] = $this->SdRestartAction->Text;
- $cfg_data['actions']['fd_start'] = $this->FdStartAction->Text;
- $cfg_data['actions']['fd_stop'] = $this->FdStopAction->Text;
- $cfg_data['actions']['fd_restart'] = $this->FdRestartAction->Text;
$ret = $this->getModule('api_config')->setConfig($cfg_data);
if ($ret) {
$this->PortValidator->Display = ($this->Port->Enabled === true) ? 'Dynamic' : 'None';
$this->IPValidator->Display = ($this->IP->Enabled === true) ? 'Dynamic' : 'None';
$this->DBPathValidator->Display = ($this->DBPath->Enabled === true) ? 'Dynamic' : 'None';
- $this->DbTestResultOk->Display = 'None';
$this->DbTestResultErr->Display = 'None';
$this->Step2Content->render($param->NewWriter);
}
try {
$is_validate = $this->getModule('db')->testDbConnection($db_params);
} catch (BAPIException $e) {
- $emsg = $e;
+ $emsg = $e->getErrorMessage();
}
}
- $this->DbTestResultOk->Display = ($is_validate === true) ? 'Dynamic' : 'None';
- if ($emsg instanceof BAPIException) {
+ if (!empty($emsg)) {
$this->DbTestResultErr->Text = $emsg;
}
- $this->DbTestResultErr->Display = ($is_validate === false) ? 'Dynamic' : 'None';
- $this->Step2Content->render($param->NewWriter);
+ if ($is_validate === true) {
+ $this->getCallbackClient()->show('db_test_result_ok');
+ $this->getCallbackClient()->hide('db_test_result_err');
+ $this->getCallbackClient()->hide($this->DbTestResultErr);
+ } else {
+ $this->getCallbackClient()->hide('db_test_result_ok');
+ $this->getCallbackClient()->show('db_test_result_err');
+ $this->getCallbackClient()->show($this->DbTestResultErr);
+ }
}
public function connectionBconsoleTest($sender, $param) {
if (!$is_validate) {
$this->BconsoleTestResultErr->Text = $result->output;
}
- $this->BconsoleTestResultOk->Display = ($is_validate === true) ? 'Dynamic' : 'None';
- $this->BconsoleTestResultErr->Display = ($is_validate === false) ? 'Dynamic' : 'None';
+ if ($is_validate === true) {
+ $this->getCallbackClient()->show('bconsole_test_result_ok');
+ $this->getCallbackClient()->hide('bconsole_test_result_err');
+ $this->getCallbackClient()->hide($this->BconsoleTestResultErr);
+ } else {
+ $this->getCallbackClient()->hide('bconsole_test_result_ok');
+ $this->getCallbackClient()->show('bconsole_test_result_err');
+ $this->getCallbackClient()->show($this->BconsoleTestResultErr);
+ }
}
public function testJSONToolsCfg($sender, $param) {
}
$param->setIsValid($valid);
}
-
- public function testExecActionCommand($sender, $param) {
- $action = $param->CommandParameter;
- $cmd = '';
- switch ($action) {
- case 'dir_start': $cmd = $this->DirStartAction->Text; break;
- case 'dir_stop': $cmd = $this->DirStopAction->Text; break;
- case 'dir_restart': $cmd = $this->DirRestartAction->Text; break;
- case 'sd_start': $cmd = $this->SdStartAction->Text; break;
- case 'sd_stop': $cmd = $this->SdStopAction->Text; break;
- case 'sd_restart': $cmd = $this->SdRestartAction->Text; break;
- case 'fd_start': $cmd = $this->FdStartAction->Text; break;
- case 'fd_stop': $cmd = $this->FdStopAction->Text; break;
- case 'fd_restart': $cmd = $this->FdRestartAction->Text; break;
- };
- $result = $this->getModule('comp_actions')->execCommand($cmd, $this->ActionsUseSudo->Checked);
- $this->getCallbackClient()->callClientFunction('set_action_command_output', array($action, (array)$result));
- }
}
?>
--- /dev/null
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum - Bacula web interface
+ *
+ * Copyright (C) 2013-2021 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.
+ */
+
+Prado::using('Application.API.Class.BaculumAPIPage');
+
+/**
+ * API OAuth2 clients page.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Panel
+ * @package Baculum API
+ */
+class APIOAuth2Clients extends BaculumAPIPage {
+
+ public function onInit($param) {
+ parent::onInit($param);
+
+ $config = $this->getModule('api_config')->getConfig();
+ if(count($config) === 0) {
+ // Config doesn't exist, go to wizard
+ $this->goToPage('APIInstallWizard');
+ return;
+ } elseif (!$this->IsCallback) {
+ $this->loadOAuth2Clients(null, null);
+ }
+ }
+
+ public function loadOAuth2Clients($sender, $param) {
+ $oauth2_cfg = $this->getModule('oauth2_config')->getConfig();
+ $clients = array_values($oauth2_cfg);
+ $this->getCallbackClient()->callClientFunction(
+ 'oAPIOAuth2Clients.load_oauth2_clients_cb',
+ [$clients]
+ );
+ $this->hideOAuth2ClientWindow($sender);
+ }
+
+ public function cancelOAuth2ClientWindow($sender, $param) {
+ $this->hideOAuth2ClientWindow($sender);
+ }
+
+ private function hideOAuth2ClientWindow($sender) {
+ if (is_object($sender)) {
+ if ($sender->ID === 'NewOAuth2Client') {
+ $this->getCallbackClient()->callClientFunction(
+ 'oAPIOAuth2Clients.show_new_client_window',
+ [false]
+ );
+ } elseif ($sender->ID === 'EditOAuth2Client') {
+ $this->getCallbackClient()->callClientFunction(
+ 'oAPIOAuth2Clients.show_edit_client_window',
+ [false]
+ );
+ }
+ }
+ }
+
+ public function deleteOAuth2Client($sender, $param) {
+ $config = $this->getModule('oauth2_config');
+ $clients = $config->getConfig();
+ $client_id = $param->getCallbackParameter();
+ if (key_exists($client_id, $clients)) {
+ unset($clients[$client_id]);
+ }
+ $config->setConfig($clients);
+ $this->loadOAuth2Clients(null, null);
+ }
+}
+?>
--- /dev/null
+<%@ MasterClass="Application.API.Layouts.Main" Theme="Baculum-v2"%>
+<com:TContent ID="Main">
+ <header class="w3-container w3-block">
+ <h5>
+ <i class="fas fa-user-shield"></i> <%[ OAuth2 clients ]%>
+ </h5>
+ </header>
+ <div class="w3-container">
+ <a href="javascript:void(0)" class="w3-button w3-green w3-margin-bottom" onclick="oAPIOAuth2Clients.show_new_client_window(true);">
+ <i class="fas fa-plus"></i> <%[ Add OAuth2 client ]%>
+ </a>
+ <table id="oauth2_client_list" class="w3-table w3-striped w3-hoverable w3-white w3-margin-bottom" style="width: 100%">
+ <thead>
+ <tr>
+ <th></th>
+ <th><%[ Name ]%></th>
+ <th><%[ Client ID ]%></th>
+ <th><%[ Redirect URI ]%></th>
+ <th><%[ Actions ]%></th>
+ </tr>
+ </thead>
+ <tbody id="oauth2_client_list_body"></tbody>
+ <tfoot>
+ <tr>
+ <th></th>
+ <th><%[ Name ]%></th>
+ <th><%[ Client ID ]%></th>
+ <th><%[ Redirect URI ]%></th>
+ <th><%[ Actions ]%></th>
+ </tr>
+ </tfoot>
+ </table>
+ </div>
+<script>
+var oOAuth2ClientList = {
+ ids: {
+ oauth2_client_list: 'oauth2_client_list',
+ oauth2_client_list_body: 'oauth2_client_list_body'
+ },
+ table: null,
+ data: [],
+ init: function() {
+ if (!this.table) {
+ this.set_table();
+ } else {
+ var page = this.table.page();
+ this.table.clear().rows.add(this.data).draw();
+ this.table.page(page).draw(false);
+ }
+ },
+ set_table: function() {
+ this.table = $('#' + this.ids.oauth2_client_list).DataTable({
+ data: this.data,
+ deferRender: true,
+ dom: 'lBfrtip',
+ stateSave: true,
+ buttons: [
+ 'copy', 'csv', 'colvis'
+ ],
+ columns: [
+ {
+ className: 'details-control',
+ orderable: false,
+ data: null,
+ defaultContent: '<button type="button" class="w3-button w3-blue"><i class="fa fa-angle-down"></i></button>'
+ },
+ {data: 'name'},
+ {data: 'client_id'},
+ {data: 'redirect_uri'},
+ {
+ data: 'client_id',
+ render: function(data, type, row) {
+ var span = document.createElement('SPAN');
+ span.className = 'w3-right';
+
+ var chpwd_btn = document.createElement('BUTTON');
+ chpwd_btn.className = 'w3-button w3-green';
+ chpwd_btn.type = 'button';
+ var i = document.createElement('I');
+ i.className = 'fas fa-edit';
+ var label = document.createTextNode(' <%[ Edit ]%>');
+ chpwd_btn.appendChild(i);
+ chpwd_btn.innerHTML += ' ';
+ chpwd_btn.appendChild(label);
+ chpwd_btn.setAttribute('onclick', 'oAPIOAuth2Clients.edit_client("' + data + '")');
+
+ var del_btn = document.createElement('BUTTON');
+ del_btn.className = 'w3-button w3-red w3-margin-left';
+ del_btn.type = 'button';
+ var i = document.createElement('I');
+ i.className = 'fas fa-trash-alt';
+ var label = document.createTextNode(' <%[ Delete ]%>');
+ del_btn.appendChild(i);
+ del_btn.innerHTML += ' ';
+ del_btn.appendChild(label);
+ del_btn.setAttribute('onclick', 'oAPIOAuth2Clients.delete_client("' + data + '")');
+
+ span.appendChild(chpwd_btn);
+ span.appendChild(del_btn);
+
+ return span.outerHTML;
+ }
+ }
+ ],
+ responsive: {
+ details: {
+ type: 'column'
+ }
+ },
+ columnDefs: [{
+ className: 'control',
+ orderable: false,
+ targets: 0
+ },
+ {
+ className: "dt-center",
+ targets: [ 4 ]
+ }],
+ order: [1, 'asc'],
+ });
+ }
+};
+</script>
+ <div id="new_oauth2_client_window" class="w3-modal">
+ <div class="w3-modal-content w3-animate-top w3-card-4">
+ <header class="w3-container w3-teal">
+ <span onclick="document.getElementById('new_oauth2_client_window').style.display = 'none';" class="w3-button w3-display-topright">×</span>
+ <h2><%[ Add client ]%></h2>
+ </header>
+ <div class="w3-container w3-margin-left w3-margin-right w3-text-teal">
+ <com:Application.Common.Portlets.NewAuthClient
+ ID="NewOAuth2Client"
+ Mode="add"
+ AuthType="oauth2"
+ OnSuccess="loadOAuth2Clients"
+ OnCancel="cancelOAuth2ClientWindow"
+ />
+ </div>
+ </div>
+ </div>
+ <div id="edit_oauth2_client_window" class="w3-modal">
+ <div class="w3-modal-content w3-animate-top w3-card-4">
+ <header class="w3-container w3-teal">
+ <span onclick="document.getElementById('edit_oauth2_client_window').style.display = 'none';" class="w3-button w3-display-topright">×</span>
+ <h2><%[ Edit client ]%></h2>
+ </header>
+ <div class="w3-container w3-margin-left w3-margin-right w3-text-teal">
+ <com:Application.Common.Portlets.NewAuthClient
+ ID="EditOAuth2Client"
+ Mode="edit"
+ AuthType="oauth2"
+ OnSuccess="loadOAuth2Clients"
+ OnCancel="cancelOAuth2ClientWindow"
+ />
+ </div>
+ </div>
+ </div>
+<com:TCallback ID="LoadClients" OnCallback="loadOAuth2Clients" />
+<com:TCallback ID="DeleteClient" OnCallback="deleteOAuth2Client" />
+<script>
+var oAPIOAuth2Clients = {
+ ids: {
+ new_user_window: 'new_oauth2_client_window',
+ new_oauth2_client_id: '<%=$this->NewOAuth2Client->APIOAuth2ClientId->ClientID%>',
+ edit_user_window: 'edit_oauth2_client_window',
+ edit_oauth2_client_secret: '<%=$this->EditOAuth2Client->APIOAuth2ClientSecret->ClientID%>'
+ },
+ new_obj: <%=$this->NewOAuth2Client->ClientID%>oNewAuthClient,
+ edit_obj: <%=$this->EditOAuth2Client->ClientID%>oNewAuthClient,
+ init: function() {
+ this.load_oauth2_clients();
+ },
+ show_new_client_window: function(show) {
+ oAPIOAuth2Clients.new_obj.hide_errors();
+ oAPIOAuth2Clients.new_obj.clear_oauth2_fields();
+ var win = document.getElementById(oAPIOAuth2Clients.ids.new_user_window);
+ if (show) {
+ win.style.display = 'block';
+ } else {
+ win.style.display = 'none';
+ }
+ document.getElementById(oAPIOAuth2Clients.ids.new_oauth2_client_id).focus();
+ },
+ show_edit_client_window: function(show) {
+ oAPIOAuth2Clients.edit_obj.hide_errors();
+ var win = document.getElementById(oAPIOAuth2Clients.ids.edit_user_window);
+ if (show) {
+ win.style.display = 'block';
+ } else {
+ win.style.display = 'none';
+ }
+ document.getElementById(oAPIOAuth2Clients.ids.edit_oauth2_client_secret).focus();
+ },
+ load_oauth2_clients: function() {
+ var cb = <%=$this->LoadClients->ActiveControl->Javascript%>;
+ cb.dispatch();
+ },
+ load_oauth2_clients_cb: function(clients) {
+ oOAuth2ClientList.data = clients;
+ oOAuth2ClientList.init();
+ },
+ get_client_props: function(client_id) {
+ var clients_len = oOAuth2ClientList.data.length;
+ var client = {};
+ for (var i = 0; i < clients_len; i++) {
+ if (oOAuth2ClientList.data[i].client_id === client_id) {
+ client = oOAuth2ClientList.data[i];
+ break;
+ }
+ }
+ return client;
+ },
+ edit_client: function(client_id) {
+ this.edit_obj.clear_oauth2_fields();
+ var props = this.get_client_props(client_id);
+ this.edit_obj.set_oauth2_props(props);
+ this.show_edit_client_window(true);
+ },
+ delete_client: function(username) {
+ if (!confirm('<%[ Are you sure? ]%>')) {
+ return false;
+ }
+ var cb = <%=$this->DeleteClient->ActiveControl->Javascript%>;
+ cb.setCallbackParameter(username);
+ cb.dispatch();
+ }
+};
+$(function() {
+ oAPIOAuth2Clients.init();
+});
+</script>
+ <com:TJuiDialog
+ ID="APIOAuth2EditPopup"
+ Options.Title="<%[ Edit OAuth2 client parameters ]%>"
+ Options.AutoOpen="False"
+ Options.Width="700px"
+ >
+ <com:TPanel DefaultButton="APIOAuth2SaveBtn">
+ <div class="line">
+ <div class="text"><com:TLabel ForControl="APIOAuth2ClientId" Text="<%[ OAuth2 Client ID: ]%>" /></div>
+ <div class="field">
+ <com:TActiveTextBox
+ ID="APIOAuth2ClientId"
+ CssClass="textbox"
+ ReadOnly="true"
+ />
+ </div>
+ </div>
+ <div class="line">
+ <div class="text"><com:TLabel ForControl="APIOAuth2ClientSecret" Text="<%[ OAuth2 Client Secret: ]%>" /></div>
+ <div class="field">
+ <com:TActiveTextBox
+ ID="APIOAuth2ClientSecret"
+ CssClass="textbox"
+ CausesValidation="false"
+ MaxLength="50"
+ />
+ <com:TRequiredFieldValidator
+ CssClass="validator-block"
+ Display="Dynamic"
+ ControlCssClass="invalidate"
+ ControlToValidate="APIOAuth2ClientSecret"
+ ValidationGroup="APIOAuth2Edit"
+ Text="<%[ Please enter Client Secret. ]%>"
+ />
+ <com:TRegularExpressionValidator
+ CssClass="validator-block"
+ Display="Dynamic"
+ ControlCssClass="invalidate"
+ ControlToValidate="APIOAuth2ClientSecret"
+ RegularExpression="<%=OAuth2::CLIENT_SECRET_PATTERN%>"
+ ValidationGroup="APIOAuth2Edit"
+ Text="<%[ Invalid Client Secret value. Client Secret may contain any character that is not a whitespace character. ]%>"
+ />
+ <a href="javascript:void(0)" onclick="document.getElementById('<%=$this->APIOAuth2ClientSecret->ClientID%>').value = get_random_string('ABCDEFabcdef0123456789', 40); return false;"><%[ generate ]%></a>
+ </div>
+ </div>
+ <div class="line">
+ <div class="text"><com:TLabel ForControl="APIOAuth2RedirectURI" Text="<%[ OAuth2 Redirect URI (example: https://baculumgui:9095/web/redirect): ]%>" /></div>
+ <div class="field">
+ <com:TActiveTextBox
+ ID="APIOAuth2RedirectURI"
+ CssClass="textbox"
+ CausesValidation="false"
+ />
+ <com:TRequiredFieldValidator
+ CssClass="validator-block"
+ Display="Dynamic"
+ ControlCssClass="invalidate"
+ ControlToValidate="APIOAuth2RedirectURI"
+ ValidationGroup="APIOAuth2Edit"
+ Text="<%[ Please enter Redirect URI. ]%>"
+ />
+ </div>
+ </div>
+ <div class="line">
+ <div class="text"><com:TLabel ForControl="APIOAuth2Scope" Text="<%[ OAuth2 scopes (space separated): ]%>" /></div>
+ <div class="field">
+ <com:TActiveTextBox
+ ID="APIOAuth2Scope"
+ CssClass="textbox"
+ CausesValidation="false"
+ TextMode="MultiLine"
+ />
+ <a href="javascript:void(0)" onclick="set_scopes('<%=$this->APIOAuth2Scope->ClientID%>'); return false;" style="vertical-align: top"><%[ set all scopes ]%></a>
+ <com:TRequiredFieldValidator
+ CssClass="validator-block"
+ Display="Dynamic"
+ ControlCssClass="invalidate"
+ ControlToValidate="APIOAuth2Scope"
+ ValidationGroup="APIOAuth2Edit"
+ Text="<%[ Please enter OAuth2 scopes. ]%>"
+ />
+ </div>
+ </div>
+ <div class="line">
+ <div class="text"><com:TLabel ForControl="APIOAuth2BconsoleCfgPath" Text="<%[ Dedicated Bconsole config file path: ]%>" /></div>
+ <div class="field">
+ <com:TActiveTextBox
+ ID="APIOAuth2BconsoleCfgPath"
+ CssClass="textbox"
+ CausesValidation="false"
+ /> <%[ (optional) ]%>
+ </div>
+ </div>
+ <div class="line">
+ <div class="text"><com:TLabel ForControl="APIOAuth2Name" Text="<%[ Short name: ]%>" /></div>
+ <div class="field">
+ <com:TActiveTextBox
+ ID="APIOAuth2Name"
+ CssClass="textbox"
+ CausesValidation="false"
+ /> <%[ (optional) ]%>
+ </div>
+ </div>
+ <div class="center">
+ <com:BButton
+ Text="<%[ Cancel ]%>"
+ CausesValidation="false"
+ Attributes.onclick="$('#<%=$this->APIOAuth2EditPopup->ClientID%>').dialog('close'); return false;"
+ />
+ <com:BActiveButton
+ ID="APIOAuth2SaveBtn"
+ ValidationGroup="APIOAuth2Edit"
+ OnCommand="TemplateControl.saveOAuth2Item"
+ Text="<%[ Save ]%>"
+ >
+ </com:BActiveButton>
+ </div>
+ </com:TPanel>
+ </com:TJuiDialog>
+</com:TContent>
--- /dev/null
+<%@ MasterClass="Application.API.Layouts.Main" Theme="Baculum-v2"%>
+<com:TContent ID="Main">
+ <header class="w3-container w3-block">
+ <h5>
+ <i class="fas fa-wrench"></i> <%[ API settings ]%>
+ </h5>
+ </header>
+ <div class="w3-bar w3-green w3-margin-bottom">
+ <button type="button" id="btn_settings_general" class="w3-bar-item w3-button tab_btn w3-grey" onclick="W3Tabs.open(this.id, 'settings_general');"><%[ General ]%></button>
+ <button type="button" id="btn_settings_catalog" class="w3-bar-item w3-button tab_btn" onclick="W3Tabs.open(this.id, 'settings_catalog');"><%[ Catalog ]%></button>
+ <button type="button" id="btn_settings_console" class="w3-bar-item w3-button tab_btn" onclick="W3Tabs.open(this.id, 'settings_console');"><%[ Console ]%></button>
+ <button type="button" id="btn_settings_config" class="w3-bar-item w3-button tab_btn" onclick="W3Tabs.open(this.id, 'settings_config');"><%[ Config ]%></button>
+ <button type="button" id="btn_settings_actions" class="w3-bar-item w3-button tab_btn" onclick="W3Tabs.open(this.id, 'settings_actions');"><%[ Actions ]%></button>
+ <button type="button" id="btn_settings_authentication" class="w3-bar-item w3-button tab_btn" onclick="W3Tabs.open(this.id, 'settings_authentication');"><%[ Authentication ]%></button>
+ </div>
+ <div class="w3-container tab_item" id="settings_general">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter"><com:TLabel ForControl="GeneralLang" Text="<%[ Language: ]%>" /></div>
+ <div class="w3-col w3-threequarter">
+ <com:TActiveDropDownList
+ ID="GeneralLang"
+ CssClass="w3-select w3-border"
+ Width="150px"
+ CausesValidation="false"
+ AutoPostBack="false"
+ >
+ <com:TListItem Value="en" Text="English" />
+ <com:TListItem Value="pl" Text="Polish" />
+ <com:TListItem Value="pt" Text="Portuguese" />
+ <com:TListItem Value="ru" Text="Russian" />
+ </com:TActiveDropDownList>
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter"><com:TLabel ForControl="GeneralDebug" Text="<%[ Debug: ]%>" /></div>
+ <div class="w3-col w3-threequarter">
+ <com:TActiveCheckBox
+ ID="GeneralDebug"
+ CssClass="w3-check"
+ />
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-center">
+ <com:TActiveLinkButton
+ ID="GeneralSave"
+ CssClass="w3-button w3-green"
+ OnCallback="saveGeneral"
+ >
+ <i class="fas fa-save"></i> <%[ Save ]%>
+ </com:TActiveLinkButton>
+ </div>
+ </div>
+ </div>
+ <div class="w3-container tab_item" id="settings_catalog" style="display: none">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter"><com:TLabel ForControl="DBEnabled" Text="<%[ Enabled: ]%>" /></div>
+ <div class="w3-col w3-threequarter">
+ <com:TActiveCheckBox
+ ID="DBEnabled"
+ CssClass="w3-check"
+ Attributes.onclick="$('#db_container').slideToggle('fast')"
+ />
+ </div>
+ </div>
+ <div id="db_container" style="display: <%=$this->DBEnabled->Checked ? 'block' : 'none'%>">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter"><com:TLabel ForControl="DBType" Text="<%[ Database type: ]%>" /></div>
+ <div class="w3-col w3-threequarter">
+ <com:TActiveDropDownList
+ ID="DBType"
+ CssClass="w3-select w3-border"
+ Width="170px"
+ OnTextChanged="setDBType"
+ CausesValidation="false"
+ >
+ <com:TListItem Value="none" Text="<%[ select database ]%>" />
+ <com:TListItem Value="pgsql" Text="PostgreSQL" />
+ <com:TListItem Value="mysql" Text="MySQL" />
+ <com:TListItem Value="sqlite" Text="SQLite" />
+ </com:TActiveDropDownList>
+ <com:TCompareValidator
+ Display="Dynamic"
+ ControlToValidate="DBType"
+ DataType="String"
+ ValueToCompare="none"
+ Operator="NotEqual"
+ ValidationGroup="DbGroup"
+ Text="<%[ Please select database type. ]%>"
+ />
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter"><com:TLabel ForControl="DBName" Text="<%[ Database name: ]%>" /></div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="DBName"
+ CssClass="w3-input w3-border"
+ Width="370px"
+ />
+ <com:TRequiredFieldValidator
+ Display="Dynamic"
+ ControlToValidate="DBName"
+ ValidationGroup="DbGroup"
+ Text="<%[ Please enter database name. ]%>"
+ />
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter"><com:TLabel ForControl="DBLogin" Text="<%[ Login: ]%>" /></div>
+ <div class="w3-col w3-threequarter">
+ <com:TActiveTextBox
+ ID="DBLogin"
+ CssClass="w3-input w3-border"
+ Width="370px"
+ />
+ <com:TRequiredFieldValidator
+ ID="LoginValidator"
+ Display="Dynamic"
+ ControlToValidate="DBLogin"
+ ValidationGroup="DbGroup"
+ Text="<%[ Please enter login. ]%>"
+ />
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter"><com:TLabel ForControl="DBPassword" Text="<%[ Password: ]%>" /></div>
+ <div class="w3-col w3-threequarter"><com:TActiveTextBox
+ ID="DBPassword"
+ CssClass="w3-input w3-border"
+ TextMode="Password"
+ PersistPassword="true"
+ Width="370px"
+ /></div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter"><com:TLabel ForControl="DBAddress" Text="<%[ IP address (or hostname): ]%>" /></div>
+ <div class="w3-col w3-threequarter">
+ <com:TActiveTextBox
+ ID="DBAddress"
+ CssClass="w3-input w3-border"
+ Width="370px"
+ />
+ <com:TRequiredFieldValidator
+ ID="IPValidator"
+ Display="Dynamic"
+ ControlToValidate="DBAddress"
+ ValidationGroup="DbGroup"
+ Text="<%[ Please enter IP address or hostname. ]%>"
+ />
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter"><com:TLabel ForControl="DBPort" Text="<%[ Port: ]%>" /></div>
+ <div class="w3-col w3-threequarter">
+ <com:TActiveTextBox
+ ID="DBPort"
+ CssClass="w3-input w3-border"
+ Width="100px"
+ MaxLength="5"
+ Enabled="false"
+ />
+ <com:TRequiredFieldValidator
+ ID="PortValidator"
+ Display="Dynamic"
+ ControlToValidate="DBPort"
+ ValidationGroup="DbGroup"
+ Text="<%[ Please enter database port. ]%>"
+ />
+ </div>
+ </div>
+ <com:TActivePanel
+ ID="DBPathField"
+ CssClass="w3-row w3-section"
+ Display="<%=!$this->IsCallBack && $this->getPage()->config['db']['type'] == 'sqlite' ? 'Fixed' : $this->DBPathField->Display%>">
+ <div class="w3-col w3-quarter"><com:TLabel ForControl="DBPath" Text="<%[ SQLite database path: ]%>" /></div>
+ <div class="w3-col w3-threequarter">
+ <com:TActiveTextBox
+ ID="DBPath"
+ CssClass="w3-input w3-border"
+ Enabled="false"
+ Width="370px"
+ />
+ <com:TRequiredFieldValidator
+ ID="DBPathValidator"
+ Display="Dynamic"
+ ControlToValidate="DBPath"
+ ValidationGroup="DbGroup"
+ Text="<%[ Please enter database path. ]%>"
+ />
+ </div>
+ </com:TActivePanel>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter" style="vertical-align: top"><com:TLabel ForControl="ConnectionTest" Text="<%[ Connection test: ]%>" CssClass="test_label" /></div>
+ <div class="w3-col w3-threequarter">
+ <table>
+ <tr>
+ <td align="center" valign="middle">
+ <com:TActiveLinkButton
+ ID="ConnectionTest"
+ CssClass="w3-button w3-green"
+ CausesValidation="false"
+ OnCallback="connectionDBTest"
+ >
+ <prop:ClientSide.OnLoading>
+ $('#db_test_result_ok').hide();
+ $('#db_test_result_err').hide();
+ $('#<%=$this->DbTestResultErr->ClientID%>').hide();
+ $('#db_test_loader').show();
+ </prop:ClientSide.OnLoading>
+ <prop:ClientSide.OnComplete>
+ $('#db_test_loader').hide();
+ </prop:ClientSide.OnComplete>
+ <i class="fas fa-play"></i> <%[ test ]%>
+ </com:TActiveLinkButton>
+ </td>
+ <td style="padding-left: 10px">
+ <span id="db_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <span id="db_test_result_ok" class="w3-text-green" style="display: none">
+ <i class="fas fa-check"></i> <%[ OK ]%>
+ </span>
+ <span id="db_test_result_err" class="w3-text-red" style="display: none">
+ <i class="fas fa-exclamation-circle"></i>
+ </span>
+ <com:TActiveLabel ID="DbTestResultErr" CssClass="w3-text-red" Display="None"><%[ Connection error ]%></com:TActiveLabel>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-center">
+ <com:TActiveLinkButton
+ ID="CatalogSave"
+ CssClass="w3-button w3-green"
+ OnCallback="saveCatalog"
+ ValidationGroup="DbGroup"
+ CausesValidation="true"
+ >
+ <i class="fas fa-save"></i> <%[ Save ]%>
+ </com:TActiveLinkButton>
+ </div>
+ </div>
+ </div>
+ <div class="w3-container tab_item" id="settings_console" style="display: none">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter"><com:TLabel ForControl="BconsoleEnabled" Text="<%[ Enabled: ]%>" /></div>
+ <div class="w3-col w3-threequarter">
+ <com:TActiveCheckBox
+ ID="BconsoleEnabled"
+ CssClass="w3-check"
+ Attributes.onclick="$('#bconsole_container').slideToggle('fast')"
+ />
+ </div>
+ </div>
+ <div id="bconsole_container" style="display: <%=$this->BconsoleEnabled->Checked ? 'block' : 'none'%>">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="BconsolePath"
+ Text="<%[ Bconsole binary file path: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="BconsolePath"
+ CssClass="w3-input w3-border"
+ CausesValidation="false"
+ ValidationGroup="BconsoleGroup"
+ Width="370px"
+ />
+ <com:TRequiredFieldValidator
+ Display="Dynamic"
+ ControlToValidate="BconsolePath"
+ Text="<%[ Please enter bconsole path. ]%>"
+ />
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="BconsoleConfigPath"
+ Text="<%[ Bconsole admin config file path: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="BconsoleConfigPath"
+ CssClass="w3-input w3-border"
+ CausesValidation="false"
+ ValidationGroup="BconsoleGroup"
+ Width="370px"
+ />
+ <com:TRequiredFieldValidator
+ Display="Dynamic"
+ ControlToValidate="BconsoleConfigPath"
+ Text="<%[ Please enter bconsole config file path. ]%>"
+ />
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="BconsoleUseSudo"
+ Text="<%[ Use sudo: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TCheckBox
+ ID="BconsoleUseSudo"
+ CssClass="w3-check"
+ /> <a href="javascript:void(0)" onclick="get_sudo_config('bconsole');"><%[ Get sudo configuration ]%></a>
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="BconsoleConnectionTest"
+ Text="<%[ Bconsole connection test: ]%>"
+ /></div>
+ <div class="w3-col w3-threequarter">
+ <table>
+ <tr>
+ <td>
+ <com:TActiveLinkButton
+ ID="BconsoleConnectionTest"
+ CssClass="w3-button w3-green"
+ CausesValidation="false"
+ OnCallback="connectionBconsoleTest"
+ >
+ <prop:ClientSide.OnLoading>
+ $('#bconsole_test_result_ok').hide();
+ $('#bconsole_test_result_err').hide();
+ $('#<%=$this->BconsoleTestResultErr->ClientID%>').hide();
+ $('#bconsole_test_loader').show();
+ </prop:ClientSide.OnLoading>
+ <prop:ClientSide.OnComplete>
+ $('#bconsole_test_loader').hide();
+ </prop:ClientSide.OnComplete>
+ <i class="fas fa-play"></i> <%[ test ]%>
+ </com:TActiveLinkButton>
+ </td>
+ <td style="padding-left: 10px">
+ <span id="bconsole_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <span id="bconsole_test_result_ok" class="w3-text-green" style="display: none">
+ <i class="fas fa-check"></i> <%[ OK ]%>
+ </span>
+ <span id="bconsole_test_result_err" class="w3-text-red" style="display: none">
+ <i class="fas fa-exclamation-circle"></i>
+ </span>
+ <com:TActiveLabel ID="BconsoleTestResultErr" CssClass="w3-text-red" Display="None"><%[ Connection error ]%></com:TActiveLabel>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-center">
+ <com:TActiveLinkButton
+ ID="BconsoleSave"
+ CssClass="w3-button w3-green"
+ OnCallback="saveBconsole"
+ ValidationGroup="BconsoleGroup"
+ CausesValidation="true"
+ >
+ <i class="fas fa-save"></i> <%[ Save ]%>
+ </com:TActiveLinkButton>
+ </div>
+ </div>
+ </div>
+ <div class="w3-container tab_item" id="settings_config" style="display: none">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter"><com:TLabel ForControl="ConfigEnabled" Text="<%[ Enabled: ]%>" /></div>
+ <div class="w3-col w3-threequarter">
+ <com:TActiveCheckBox
+ ID="ConfigEnabled"
+ CssClass="w3-check"
+ Attributes.onclick="$('#config_container').slideToggle('fast')"
+ />
+ </div>
+ </div>
+ <div id="config_container" style="display: <%=$this->ConfigEnabled->Checked ? 'block' : 'none'%>">
+ <fieldset>
+ <legend><%[ General configuration ]%></legend>
+ <div class="w3-row w3-section" title="<%[ In this directory Baculum API saves temporarily Bacula configuration files (mainly for validation purposes) just before they are written as real Bacula configuration files. ]%>">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="BConfigDir"
+ Text="<%[ Baculum working directory for Bacula config: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="BConfigDir"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <span class="config_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <com:TActiveLabel
+ ID="BConfigDirTestOk"
+ Display="None"
+ CssClass="w3-text-green"
+ EnableViewState="false"
+ >
+ <i class="fas fa-check" title="<%[ OK ]%>"></i> <%[ OK ]%>
+ </com:TActiveLabel>
+ <com:TActiveLabel
+ ID="BConfigDirTestErr"
+ Display="None"
+ CssClass="w3-text-red"
+ EnableViewState="false"
+ >
+ <!--i class="fas fa-exclamation-circle" title="<%[ Error ]%>"></i--> <%[ Error ]%>
+ </com:TActiveLabel>
+ <com:TRequiredFieldValidator
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="BConfigDir"
+ Display="Dynamic"
+ Text="<%[ Directory path field is required. ]%>"
+ />
+ <com:TActiveCustomValidator
+ ID="BConfigDirWritableTest"
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="BConfigDir"
+ Text="<%[ Provided directory path is not writable by web server. ]%>"
+ Display="Dynamic"
+ OnServerValidate="testConfigDir"
+ />
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="BJSONUseSudo"
+ Text="<%[ Use sudo: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TCheckBox
+ ID="BJSONUseSudo"
+ CssClass="w3-check"
+ /> <a href="javascript:void(0)" onclick="get_sudo_config('config');"><%[ Get sudo configuration ]%></a>
+ </div>
+ </div>
+ </fieldset>
+ <fieldset>
+ <legend>Director</legend>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="BDirJSONPath"
+ Text="<%[ bdirjson binary file path: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="BDirJSONPath"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <span class="config_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <com:TActiveLabel
+ ID="BDirJSONPathTestOk"
+ Display="None"
+ CssClass="w3-text-green"
+ EnableViewState="false"
+ >
+ <i class="fas fa-check" title="<%[ OK ]%>"></i> <%[ OK ]%>
+ </com:TActiveLabel>
+ <com:TCustomValidator
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="BDirJSONPath"
+ ClientValidationFunction="bjsontools_validator"
+ Display="Dynamic"
+ Text="<%[ There is required to provide both binary file and config file paths. ]%>"
+ />
+ <com:TActiveLabel
+ ID="BDirJSONPathTestErr"
+ Display="None"
+ CssClass="w3-text-red"
+ EnableViewState="false"
+ >
+ <i class="fas fa-exclamation-circle" title="<%[ Error ]%>"></i> <%[ Connection error ]%>
+ </com:TActiveLabel>
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="DirCfgPath"
+ Text="<%[ Main Director config file path (usually bacula-dir.conf): ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="DirCfgPath"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <com:TCustomValidator
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="DirCfgPath"
+ ClientValidationFunction="bjsontools_validator"
+ Display="Dynamic"
+ Text="<%[ There is required to provide both binary file and config file paths. ]%>"
+ />
+ </div>
+ </div>
+ </fieldset>
+ <fieldset>
+ <legend>Storage Daemon</legend>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="BSdJSONPath"
+ Text="<%[ bsdjson binary file path: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="BSdJSONPath"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <span class="config_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <com:TCustomValidator
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="BSdJSONPath"
+ ClientValidationFunction="bjsontools_validator"
+ Display="Dynamic"
+ Text="<%[ There is required to provide both binary file and config file paths. ]%>"
+ />
+ <com:TActiveLabel
+ ID="BSdJSONPathTestOk"
+ Display="None"
+ CssClass="w3-text-green"
+ EnableViewState="false"
+ >
+ <i class="fas fa-check" title="<%[ OK ]%>"></i> <%[ OK ]%>
+ </com:TActiveLabel>
+ <com:TActiveLabel
+ ID="BSdJSONPathTestErr"
+ Display="None"
+ CssClass="w3-text-red"
+ EnableViewState="false"
+ >
+ <i class="fas fa-exclamation-circle" title="<%[ Error ]%>"></i> <%[ Connection error ]%>
+ </com:TActiveLabel>
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="SdCfgPath"
+ Text="<%[ Main Storage Daemon config file path (usually bacula-sd.conf): ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="SdCfgPath"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <com:TCustomValidator
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="SdCfgPath"
+ ClientValidationFunction="bjsontools_validator"
+ Display="Dynamic"
+ Text="<%[ There is required to provide both binary file and config file paths. ]%>"
+ />
+ </div>
+ </div>
+ </fieldset>
+ <fieldset>
+ <legend>File Daemon/Client</legend>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="BFdJSONPath"
+ Text="<%[ bfdjson binary file path: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="BFdJSONPath"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <com:TCustomValidator
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="BFdJSONPath"
+ ClientValidationFunction="bjsontools_validator"
+ Display="Dynamic"
+ Text="<%[ There is required to provide both binary file and config file paths. ]%>"
+ />
+ <span class="config_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <com:TActiveLabel
+ ID="BFdJSONPathTestOk"
+ Display="None"
+ CssClass="w3-text-green"
+ EnableViewState="false"
+ >
+ <i class="fas fa-check" title="<%[ OK ]%>"></i> <%[ OK ]%>
+ </com:TActiveLabel>
+ <com:TActiveLabel
+ ID="BFdJSONPathTestErr"
+ Display="None"
+ CssClass="w3-text-red"
+ EnableViewState="false"
+ >
+ <i class="fas fa-exclamation-circle" title="<%[ Error ]%>"></i> <%[ Connection error ]%>
+ </com:TActiveLabel>
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="FdCfgPath"
+ Text="<%[ Main File Daemon config file path (usually bacula-fd.conf): ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="FdCfgPath"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <com:TCustomValidator
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="FdCfgPath"
+ ClientValidationFunction="bjsontools_validator"
+ Display="Dynamic"
+ Text="<%[ There is required to provide both binary file and config file paths. ]%>"
+ />
+ </div>
+ </div>
+ </fieldset>
+ <fieldset>
+ <legend>Bconsole</legend>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="BBconsJSONPath"
+ Text="<%[ bbconsjson binary file path: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TCustomValidator
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="BBconsJSONPath"
+ ClientValidationFunction="bjsontools_validator"
+ Display="Dynamic"
+ Text="<%[ There is required to provide both binary file and config file paths. ]%>"
+ />
+ <com:TTextBox
+ ID="BBconsJSONPath"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <span class="config_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <com:TActiveLabel
+ ID="BBconsJSONPathTestOk"
+ Display="None"
+ CssClass="w3-text-green"
+ EnableViewState="false"
+ >
+ <i class="fas fa-check" title="<%[ OK ]%>"></i> <%[ OK ]%>
+ </com:TActiveLabel>
+ <com:TActiveLabel
+ ID="BBconsJSONPathTestErr"
+ Display="None"
+ CssClass="w3-text-red"
+ EnableViewState="false"
+ >
+ <i class="fas fa-exclamation-circle" title="<%[ Error ]%>"></i> <%[ Connection error ]%>
+ </com:TActiveLabel>
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="BconsCfgPath"
+ Text="<%[ Admin Bconsole config file path (usually bconsole.conf): ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="BconsCfgPath"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <com:TCustomValidator
+ ValidationGroup="ConfigGroup"
+ ControlToValidate="BconsCfgPath"
+ ClientValidationFunction="bjsontools_validator"
+ Display="Dynamic"
+ Text="<%[ There is required to provide both binary file and config file paths. ]%>"
+ />
+ </div>
+ </div>
+ </fieldset>
+ <div class="w3-center w3-margin-top">
+ <com:TActiveLinkButton
+ ID="TestJSONToolsConfig"
+ ValidationGroup="ConfigGroup"
+ OnClick="testJSONToolsCfg"
+ CssClass="w3-button w3-green"
+ >
+ <prop:ClientSide.OnLoading>
+ bjsontools_hide_test_results();
+ $('.config_test_loader').show();
+ </prop:ClientSide.OnLoading>
+ <prop:ClientSide.OnComplete>
+ $('.config_test_loader').hide();
+ </prop:ClientSide.OnComplete>
+ <i class="fas fa-play"></i> <%[ Test configuration ]%>
+ </com:TActiveLinkButton>
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-center">
+ <com:TActiveLinkButton
+ ID="ConfigSave"
+ CssClass="w3-button w3-green"
+ OnCallback="saveConfig"
+ ValidationGroup="ConfigGroup"
+ CausesValidation="true"
+ >
+ <i class="fas fa-save"></i> <%[ Save ]%>
+ </com:TActiveLinkButton>
+ </div>
+ </div>
+ </div>
+ <div class="w3-container tab_item" id="settings_actions" style="display: none">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter"><com:TLabel ForControl="ActionsEnabled" Text="<%[ Enabled: ]%>" /></div>
+ <div class="w3-col w3-threequarter">
+ <com:TActiveCheckBox
+ ID="ActionsEnabled"
+ CssClass="w3-check"
+ Attributes.onclick="$('#actions_container').slideToggle('fast')"
+ />
+ </div>
+ </div>
+ <div id="actions_container" style="display: <%=$this->ActionsEnabled->Checked ? 'block' : 'none'%>">
+ <fieldset>
+ <legend><%[ General configuration ]%></legend>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="ActionsUseSudo"
+ Text="<%[ Use sudo: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TCheckBox
+ ID="ActionsUseSudo"
+ CssClass="w3-check"
+ /> <a href="javascript:void(0)" onclick="get_sudo_config('actions');"><%[ Get sudo configuration ]%></a>
+ </div>
+ </div>
+ </fieldset>
+ <fieldset>
+ <legend>Director</legend>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="DirStartAction"
+ Text="<%[ Director start command: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="DirStartAction"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <com:TActiveLinkButton
+ ID="TestDirStartActionCommand"
+ ValidationGroup="ActionsGroup"
+ Text=""
+ OnCommand="testExecActionCommand"
+ CommandParameter="dir_start"
+ CssClass="w3-button w3-green"
+ Width="105px"
+ >
+ <prop:ClientSide.OnLoading>
+ actions_hide_test_results('<%=$this->TestDirStartActionCommand->CommandParameter%>');
+ $('#actions_test_result_dir_start .action_test_loader').show();
+ </prop:ClientSide.OnLoading>
+ <prop:ClientSide.OnComplete>
+ $('#actions_test_result_dir_start .action_test_loader').hide();
+ </prop:ClientSide.OnComplete>
+ <i class="fas fa-play"></i> <%[ Start ]%>
+ </com:TActiveLinkButton>
+ <span id="actions_test_result_dir_start">
+ <span class="action_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <span class="action_success w3-text-green" style="display: none">
+ <i class="fas fa-check" title="<%[ OK ]%>"></i> <%[ OK ]%>
+ </span>
+ <span class="action_error w3-text-red" style="display: none">
+ <i class="fas fa-exclamation-circle" title="<%[ Error ]%>"></i> <%[ Error ]%>
+ </span>
+ <span class="action_result w3-text-red"></span>
+ </span>
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="DirStopAction"
+ Text="<%[ Director stop command: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="DirStopAction"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <com:TActiveLinkButton
+ ID="TestDirStopActionCommand"
+ ValidationGroup="ActionsGroup"
+ OnCommand="testExecActionCommand"
+ CommandParameter="dir_stop"
+ CssClass="w3-button w3-green"
+ Width="105px"
+ >
+ <prop:ClientSide.OnLoading>
+ actions_hide_test_results('<%=$this->TestDirStopActionCommand->CommandParameter%>');
+ $('#actions_test_result_dir_stop .action_test_loader').show();
+ </prop:ClientSide.OnLoading>
+ <prop:ClientSide.OnComplete>
+ $('#actions_test_result_dir_stop .action_test_loader').hide();
+ </prop:ClientSide.OnComplete>
+ <i class="fas fa-stop"></i> <%[ Stop ]%>
+ </com:TActiveLinkButton>
+ <span id="actions_test_result_dir_stop">
+ <span class="action_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <span class="action_success w3-text-green" style="display: none">
+ <i class="fas fa-check" title="<%[ OK ]%>"></i> <%[ OK ]%>
+ </span>
+ <span class="action_error w3-text-red" style="display: none">
+ <i class="fas fa-exclamation-circle" title="<%[ Error ]%>"></i> <%[ Error ]%>
+ </span>
+ <span class="action_result w3-text-red"></span>
+ </span>
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="DirRestartAction"
+ Text="<%[ Director restart command: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="DirRestartAction"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <com:TActiveLinkButton
+ ID="TestDirRestartActionCommand"
+ ValidationGroup="ActionsGroup"
+ OnCommand="testExecActionCommand"
+ CommandParameter="dir_restart"
+ CssClass="w3-button w3-green"
+ Width="105px"
+ >
+ <prop:ClientSide.OnLoading>
+ actions_hide_test_results('<%=$this->TestDirRestartActionCommand->CommandParameter%>');
+ $('#actions_test_result_dir_restart .action_test_loader').show();
+ </prop:ClientSide.OnLoading>
+ <prop:ClientSide.OnComplete>
+ $('#actions_test_result_dir_restart .action_test_loader').hide();
+ </prop:ClientSide.OnComplete>
+ <i class="fas fa-sync"></i> <%[ Restart ]%>
+ </com:TActiveLinkButton>
+ <span id="actions_test_result_dir_restart">
+ <span class="action_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <span class="action_success w3-text-green" style="display: none">
+ <i class="fas fa-check" title="<%[ OK ]%>"></i> <%[ OK ]%>
+ </span>
+ <span class="action_error w3-text-red" style="display: none">
+ <i class="fas fa-exclamation-circle" title="<%[ Error ]%>"></i> <%[ Error ]%>
+ </span>
+ <span class="action_result w3-text-red"></span>
+ </span>
+ </div>
+ </div>
+ </fieldset>
+ <fieldset>
+ <legend>Storage Daemon</legend>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="SdStartAction"
+ Text="<%[ Storage Daemon start command: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="SdStartAction"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <com:TActiveLinkButton
+ ID="TestSdStartActionCommand"
+ ValidationGroup="ActionsGroup"
+ OnCommand="testExecActionCommand"
+ CommandParameter="sd_start"
+ CssClass="w3-button w3-green"
+ Width="105px"
+ >
+ <prop:ClientSide.OnLoading>
+ actions_hide_test_results('<%=$this->TestSdStartActionCommand->CommandParameter%>');
+ $('#actions_test_result_sd_start .action_test_loader').show();
+ </prop:ClientSide.OnLoading>
+ <prop:ClientSide.OnComplete>
+ $('#actions_test_result_sd_start .action_test_loader').hide();
+ </prop:ClientSide.OnComplete>
+ <i class="fas fa-play"></i> <%[ Start ]%>
+ </com:TActiveLinkButton>
+ <span id="actions_test_result_sd_start">
+ <span class="action_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <span class="action_success w3-text-green" style="display: none">
+ <i class="fas fa-check" title="<%[ OK ]%>"></i> <%[ OK ]%>
+ </span>
+ <span class="action_error w3-text-red" style="display: none">
+ <i class="fas fa-exclamation-circle" title="<%[ Error ]%>"></i> <%[ Error ]%>
+ </span>
+ <span class="action_result w3-text-red"></span>
+ </span>
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="SdStopAction"
+ Text="<%[ Storage Daemon stop command: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="SdStopAction"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <com:TActiveLinkButton
+ ID="TestSdStopActionCommand"
+ ValidationGroup="ActionsGroup"
+ OnCommand="testExecActionCommand"
+ CommandParameter="sd_stop"
+ CssClass="w3-button w3-green"
+ Width="105px"
+ >
+ <prop:ClientSide.OnLoading>
+ actions_hide_test_results('<%=$this->TestSdStopActionCommand->CommandParameter%>');
+ $('#actions_test_result_sd_stop .action_test_loader').show();
+ </prop:ClientSide.OnLoading>
+ <prop:ClientSide.OnComplete>
+ $('#actions_test_result_sd_stop .action_test_loader').hide();
+ </prop:ClientSide.OnComplete>
+ <i class="fas fa-stop"></i> <%[ Stop ]%>
+ </com:TActiveLinkButton>
+ <span id="actions_test_result_sd_stop">
+ <span class="action_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <span class="action_success w3-text-green" style="display: none">
+ <i class="fas fa-check" title="<%[ OK ]%>"></i> <%[ OK ]%>
+ </span>
+ <span class="action_error w3-text-red" style="display: none">
+ <i class="fas fa-exclamation-circle" title="<%[ Error ]%>"></i> <%[ Error ]%>
+ </span>
+ <span class="action_result w3-text-red"></span>
+ </span>
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="SdRestartAction"
+ Text="<%[ Storage Daemon restart command: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="SdRestartAction"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <com:TActiveLinkButton
+ ID="TestSdRestartActionCommand"
+ ValidationGroup="ActionsGroup"
+ OnCommand="testExecActionCommand"
+ CommandParameter="sd_restart"
+ CssClass="w3-button w3-green"
+ Width="105px"
+ >
+ <prop:ClientSide.OnLoading>
+ actions_hide_test_results('<%=$this->TestSdRestartActionCommand->CommandParameter%>');
+ $('#actions_test_result_sd_restart .action_test_loader').show();
+ </prop:ClientSide.OnLoading>
+ <prop:ClientSide.OnComplete>
+ $('#actions_test_result_sd_restart .action_test_loader').hide();
+ </prop:ClientSide.OnComplete>
+ <i class="fas fa-sync"></i> <%[ Restart ]%>
+ </com:TActiveLinkButton>
+ <span id="actions_test_result_sd_restart">
+ <span class="action_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <span class="action_success w3-text-green" style="display: none">
+ <i class="fas fa-check" title="<%[ OK ]%>"></i> <%[ OK ]%>
+ </span>
+ <span class="action_error w3-text-red" style="display: none">
+ <i class="fas fa-exclamation-circle" title="<%[ Error ]%>"></i> <%[ Error ]%>
+ </span>
+ <span class="action_result w3-text-red"></span>
+ </span>
+ </div>
+ </div>
+ </fieldset>
+ <fieldset>
+ <legend>File Daemon/Client</legend>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="FdStartAction"
+ Text="<%[ File Daemon/Client start command: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="FdStartAction"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <com:TActiveLinkButton
+ ID="TestFdStartActionCommand"
+ ValidationGroup="ActionsGroup"
+ OnCommand="testExecActionCommand"
+ CommandParameter="fd_start"
+ CssClass="w3-button w3-green"
+ Width="105px"
+ >
+ <prop:ClientSide.OnLoading>
+ actions_hide_test_results('<%=$this->TestFdStartActionCommand->CommandParameter%>');
+ $('#actions_test_result_fd_start .action_test_loader').show();
+ </prop:ClientSide.OnLoading>
+ <prop:ClientSide.OnComplete>
+ $('#actions_test_result_fd_start .action_test_loader').hide();
+ </prop:ClientSide.OnComplete>
+ <i class="fas fa-play"></i> <%[ Start ]%>
+ </com:TActiveLinkButton>
+ <span id="actions_test_result_fd_start">
+ <span class="action_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <span class="action_success w3-text-green" style="display: none">
+ <i class="fas fa-check" title="<%[ OK ]%>"></i> <%[ OK ]%>
+ </span>
+ <span class="action_error w3-text-red" style="display: none">
+ <i class="fas fa-exclamation-circle" title="<%[ Error ]%>"></i> <%[ Error ]%>
+ </span>
+ <span class="action_result w3-text-red"></span>
+ </span>
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="FdStopAction"
+ Text="<%[ File Daemon/Client stop command: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="FdStopAction"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <com:TActiveLinkButton
+ ID="TestFdStopActionCommand"
+ ValidationGroup="ActionsGroup"
+ OnCommand="testExecActionCommand"
+ CommandParameter="fd_stop"
+ CssClass="w3-button w3-green"
+ Width="105px"
+ >
+ <prop:ClientSide.OnLoading>
+ actions_hide_test_results('<%=$this->TestFdStopActionCommand->CommandParameter%>');
+ $('#actions_test_result_fd_stop .action_test_loader').show();
+ </prop:ClientSide.OnLoading>
+ <prop:ClientSide.OnComplete>
+ $('#actions_test_result_fd_stop .action_test_loader').hide();
+ </prop:ClientSide.OnComplete>
+ <i class="fas fa-stop"></i> <%[ Stop ]%>
+ </com:TActiveLinkButton>
+ <span id="actions_test_result_fd_stop">
+ <span class="action_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <span class="action_success w3-text-green" style="display: none">
+ <i class="fas fa-check" title="<%[ OK ]%>"></i> <%[ OK ]%>
+ </span>
+ <span class="action_error w3-text-red" style="display: none">
+ <i class="fas fa-exclamation-circle" title="<%[ Error ]%>"></i> <%[ Error ]%>
+ </span>
+ <span class="action_result w3-text-red"></span>
+ </span>
+ </div>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter">
+ <com:TLabel
+ ForControl="FdRestartAction"
+ Text="<%[ File Daemon/Client restart command: ]%>"
+ />
+ </div>
+ <div class="w3-col w3-threequarter">
+ <com:TTextBox
+ ID="FdRestartAction"
+ CssClass="w3-input w3-border w3-show-inline-block"
+ Width="370px"
+ />
+ <com:TActiveLinkButton
+ ID="TestFdRestartActionCommand"
+ ValidationGroup="ActionsGroup"
+ OnCommand="testExecActionCommand"
+ CommandParameter="fd_restart"
+ CssClass="w3-button w3-green"
+ Width="105px"
+ >
+ <prop:ClientSide.OnLoading>
+ actions_hide_test_results('<%=$this->TestFdRestartActionCommand->CommandParameter%>');
+ $('#actions_test_result_fd_restart .action_test_loader').show();
+ </prop:ClientSide.OnLoading>
+ <prop:ClientSide.OnComplete>
+ $('#actions_test_result_fd_restart .action_test_loader').hide();
+ </prop:ClientSide.OnComplete>
+ <i class="fas fa-sync"></i> <%[ Restart ]%>
+ </com:TActiveLinkButton>
+ <span id="actions_test_result_fd_restart">
+ <span class="action_test_loader" style="display: none">
+ <i class="fas fa-sync fa-spin" title="<%[ Loading... ]%>"></i>
+ </span>
+ <span class="action_success w3-text-green" style="display: none">
+ <i class="fas fa-check" title="<%[ OK ]%>"></i> <%[ OK ]%>
+ </span>
+ <span class="action_error w3-text-red" style="display: none">
+ <i class="fas fa-exclamation-circle" title="<%[ Error ]%>"></i> <%[ Error ]%>
+ </span>
+ <span class="action_result w3-text-red"></span>
+ </span>
+ </div>
+ </div>
+ </fieldset>
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-center">
+ <com:TActiveLinkButton
+ ID="ActionsSave"
+ CssClass="w3-button w3-green"
+ OnCallback="saveActions"
+ ValidationGroup="ActionsGroup"
+ CausesValidation="true"
+ >
+ <i class="fas fa-save"></i> <%[ Save ]%>
+ </com:TActiveLinkButton>
+ </div>
+ </div>
+ </div>
+ <div class="w3-container tab_item" id="settings_authentication" style="display: none">
+ <div class="w3-container">
+ <com:TActiveRadioButton
+ ID="AuthOAuth2"
+ GroupName="SelectAuth"
+ CssClass="w3-radio"
+ />
+ <com:TLabel
+ ForControl="AuthOAuth2"
+ Text="<%[ Use OAuth2 for authorization and authentication ]%>"
+ />
+ </div>
+ <div class="w3-container">
+ <com:TActiveRadioButton
+ ID="AuthBasic"
+ GroupName="SelectAuth"
+ CssClass="w3-radio"
+ />
+ <com:TLabel
+ ForControl="AuthBasic"
+ Text="<%[ Use HTTP Basic authentication ]%>"
+ />
+ </div>
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-center">
+ <com:TActiveLinkButton
+ ID="AuthSave"
+ CssClass="w3-button w3-green"
+ OnCallback="saveAuth"
+ >
+ <i class="fas fa-save"></i> <%[ Save ]%>
+ </com:TActiveLinkButton>
+ </div>
+ </div>
+ </div>
+<com:TJuiDialog
+ ID="SudoConfigPopup"
+ Options.title="<%[ Sudo configuration ]%>"
+ Options.autoOpen="false",
+ Options.minWidth="820"
+ Options.minHeight="200"
+>
+ <p><%[ Please copy appropriate sudo configuration and put it to a new sudoers.d file for example /etc/sudoers.d/baculum-api ]%></p>
+ <p><strong><%[ Note ]%></strong> <%[ Please use visudo to add this configuration, otherwise please do remember to add empty line at the end of file. ]%>
+ <p><%[ Example sudo configuration for Apache web server user (RHEL, CentOS and others): ]%></p>
+ <pre id="sudo_config_apache"></pre>
+ <p><%[ Example sudo configuration for Lighttpd web server user (RHEL, CentOS and others): ]%></p>
+ <pre id="sudo_config_lighttpd"></pre>
+ <p><%[ Example sudo configuration for Apache and Lighttpd web servers user (Debian, Ubuntu and others): ]%></p>
+ <pre id="sudo_config_www_data"></pre>
+</com:TJuiDialog>
+<script>
+function get_sudo_config(type) {
+ var bin_fields = {
+ bconsole: [
+ '<%=$this->BconsolePath->ClientID%>'
+ ],
+ config: [
+ '<%=$this->BDirJSONPath->ClientID%>',
+ '<%=$this->BSdJSONPath->ClientID%>',
+ '<%=$this->BFdJSONPath->ClientID%>',
+ '<%=$this->BBconsJSONPath->ClientID%>',
+ ],
+ actions: [
+ '<%=$this->DirStartAction->ClientID%>',
+ '<%=$this->DirStopAction->ClientID%>',
+ '<%=$this->DirRestartAction->ClientID%>',
+ '<%=$this->SdStartAction->ClientID%>',
+ '<%=$this->SdStopAction->ClientID%>',
+ '<%=$this->SdRestartAction->ClientID%>',
+ '<%=$this->FdStartAction->ClientID%>',
+ '<%=$this->FdStopAction->ClientID%>',
+ '<%=$this->FdRestartAction->ClientID%>'
+ ]
+ }
+ var val, pre;
+ var cfg = '';
+ var users = ['apache', 'lighttpd', 'www-data'];
+ var fields = bin_fields.hasOwnProperty(type) ? bin_fields[type] : [];
+ for (var i = 0; i < users.length; i++) {
+ var pre = document.getElementById('sudo_config_' + users[i].replace(/-/g, '_'));
+ pre.textContent = 'Defaults:' + users[i] + ' !requiretty' + "\n";
+ for (var j = 0; j < fields.length; j++) {
+ val = document.getElementById(fields[j]).value.trim();
+ if (val) {
+ pre.textContent += users[i] + ' ALL = (root) NOPASSWD: ' + val + "\n";
+ }
+ }
+ }
+ $('#<%=$this->SudoConfigPopup->ClientID%>').dialog('open');
+}
+
+var bjsontools_fields = {
+ General: {
+ data: [],
+ test: [$('#<%=$this->BConfigDirTestOk->ClientID%>'), $('#<%=$this->BConfigDirTestErr->ClientID%>')]
+ },
+ Dir: {
+ data: [$('#<%=$this->BDirJSONPath->ClientID%>'), $('#<%=$this->DirCfgPath->ClientID%>')],
+ test: [$('#<%=$this->BDirJSONPathTestOk->ClientID%>'), $('#<%=$this->BDirJSONPathTestErr->ClientID%>')]
+ },
+ Sd: {
+ data: [$('#<%=$this->BSdJSONPath->ClientID%>'), $('#<%=$this->SdCfgPath->ClientID%>')],
+ test: [$('#<%=$this->BSdJSONPathTestOk->ClientID%>'), $('#<%=$this->BSdJSONPathTestErr->ClientID%>')]
+ },
+ Fd: {
+ data: [$('#<%=$this->BFdJSONPath->ClientID%>'), $('#<%=$this->FdCfgPath->ClientID%>')],
+ test: [$('#<%=$this->BFdJSONPathTestOk->ClientID%>'), $('#<%=$this->BFdJSONPathTestErr->ClientID%>')]
+ },
+ Bcons: {
+ data: [$('#<%=$this->BBconsJSONPath->ClientID%>'), $('#<%=$this->BconsCfgPath->ClientID%>')],
+ test: [$('#<%=$this->BBconsJSONPathTestOk->ClientID%>'), $('#<%=$this->BBconsJSONPathTestErr->ClientID%>')]
+ }
+};
+var bjsontools_get_field_type = function(field_id) {
+ var field_types = Object.keys(bjsontools_fields);
+ var type, field_type;
+ for (var i = 0; i < field_types.length; i++) {
+ type = field_types[i];
+ for (var j = 0; j < bjsontools_fields[type].data.length; j++) {
+ if (bjsontools_fields[type].data[j][0].id === field_id) {
+ field_type = type;
+ break;
+ }
+ }
+ if (field_type) {
+ break;
+ }
+ }
+ return field_type;
+};
+var bjsontools_validator = function(sender, parameter) {
+ var validation_css = 'validation-error';
+ var id_validating_field = sender.control.id;
+ var type = bjsontools_get_field_type(id_validating_field);
+ var invalid_fields = [];
+ for (var i = 0; i < bjsontools_fields[type].data.length; i++) {
+ bjsontools_fields[type].data[i].removeClass(validation_css);
+ if (!bjsontools_fields[type].data[i][0].value) {
+ invalid_fields.push(bjsontools_fields[type].data[i]);
+ }
+ }
+ var valid = (invalid_fields.length === 0 || invalid_fields.length === bjsontools_fields[type].data.length);
+ var is_validating_field_valid = true;
+ if (!valid) {
+ for (var i = 0; i < invalid_fields.length; i++) {
+ invalid_fields[i].addClass(validation_css);
+ if (invalid_fields[i][0].id === id_validating_field) {
+ is_validating_field_valid = false;
+ }
+ }
+ bjsontools_hide_test_results(type);
+ }
+ if (is_validating_field_valid === true) {
+ valid = true;
+ }
+
+ return valid;
+};
+
+// if field_type not given then all test results become hidden
+var bjsontools_hide_test_results = function(field_type) {
+ var field_types = Object.keys(bjsontools_fields);
+ var type;
+ for (var i = 0; i < field_types.length; i++) {
+ type = field_types[i];
+ for (var j = 0; j < bjsontools_fields[type].test.length; j++) {
+ if (!field_type || field_type === type) {
+ bjsontools_fields[type].test[j].hide();
+ }
+ }
+ }
+};
+var set_action_command_output = function(action, result) {
+ var result_el = document.querySelector('#actions_test_result_' + action + ' .action_result');
+ if (result.error === 0) {
+ var success = document.querySelector('#actions_test_result_' + action + ' .action_success');
+ success.style.display = '';
+ result_el.textContent = '';
+ } else {
+ var error = document.querySelector('#actions_test_result_' + action + ' .action_error');
+ error.style.display = '';
+ result_el.innerHTML = '<br />' + result.output.join('<br />');
+ }
+};
+
+var actions_hide_test_results = function(action) {
+ var loader = document.querySelector('#actions_test_result_' + action + ' .action_test_loader');
+ var success = document.querySelector('#actions_test_result_' + action + ' .action_success');
+ var error = document.querySelector('#actions_test_result_' + action + ' .action_error');
+ var result = document.querySelector('#actions_test_result_' + action + ' .action_result');
+ loader.style.display = 'none';
+ success.style.display = 'none'
+ error.style.display = 'none';
+ result.textContent = '';
+};
+
+function reload_page_cb() {
+ window.location.reload();
+}
+</script>
+</com:TContent>
--- /dev/null
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum - Bacula web interface
+ *
+ * Copyright (C) 2013-2021 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.
+ */
+
+Prado::using('Application.Common.Class.AuthBasic');
+Prado::using('Application.Common.Class.AuthOAuth2');
+Prado::using('Application.API.Class.BaculumAPIPage');
+Prado::using('Application.API.Class.BAPIException');
+
+/**
+ * API settings page.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Panel
+ * @package Baculum API
+ */
+class APISettings extends BaculumAPIPage {
+
+ public $config;
+
+ const DEFAULT_ACTION_DIR_START = '/usr/bin/systemctl start bacula-dir';
+ const DEFAULT_ACTION_DIR_STOP = '/usr/bin/systemctl stop bacula-dir';
+ const DEFAULT_ACTION_DIR_RESTART = '/usr/bin/systemctl restart bacula-dir';
+ const DEFAULT_ACTION_SD_START = '/usr/bin/systemctl start bacula-sd';
+ const DEFAULT_ACTION_SD_STOP = '/usr/bin/systemctl stop bacula-sd';
+ const DEFAULT_ACTION_SD_RESTART = '/usr/bin/systemctl restart bacula-sd';
+ const DEFAULT_ACTION_FD_START = '/usr/bin/systemctl start bacula-fd';
+ const DEFAULT_ACTION_FD_STOP = '/usr/bin/systemctl stop bacula-fd';
+ const DEFAULT_ACTION_FD_RESTART = '/usr/bin/systemctl restart bacula-fd';
+
+ public function onInit($param) {
+ parent::onInit($param);
+ $config = $this->getModule('api_config');
+ $this->config = $config->getConfig();
+ $this->loadGeneralSettings();
+ $this->loadDbSettings();
+ $this->loadBconsoleSettings();
+ $this->loadConfigSettings();
+ $this->loadActionsSettings();
+ $this->loadAuthSettings();
+ }
+
+ private function loadGeneralSettings() {
+ if ($this->IsPostBack || $this->IsCallBack) {
+ return;
+ }
+ $this->GeneralLang->SelectedValue= $this->config['api']['lang'];
+ $this->GeneralDebug->Checked = ($this->config['api']['debug'] == 1);
+ }
+
+ private function loadDbSettings() {
+ if ($this->IsPostBack || $this->IsCallBack) {
+ return;
+ }
+ $this->DBEnabled->Checked = ($this->config['db']['enabled'] == 1);
+ $this->DBType->SelectedValue = $this->config['db']['type'];
+ $this->DBName->Text = $this->config['db']['name'];
+ $this->DBLogin->Text = $this->config['db']['login'];
+ $this->DBPassword->Text = $this->config['db']['password'];
+ $this->DBAddress->Text = $this->config['db']['ip_addr'];
+ $this->DBPort->Text = $this->config['db']['port'];
+ $this->DBPath->Text = $this->config['db']['path'];
+ $this->setDBType(null, null);
+ }
+
+ private function loadBconsoleSettings() {
+ if ($this->IsPostBack || $this->IsCallBack) {
+ return;
+ }
+ $this->BconsoleEnabled->Checked = ($this->config['bconsole']['enabled'] == 1);
+ $this->BconsolePath->Text = $this->config['bconsole']['bin_path'];
+ $this->BconsoleConfigPath->Text = $this->config['bconsole']['cfg_path'];
+ $this->BconsoleUseSudo->Checked = ($this->config['bconsole']['use_sudo'] == 1);
+ }
+
+ private function loadConfigSettings() {
+ if ($this->IsPostBack || $this->IsCallBack) {
+ return;
+ }
+ $this->ConfigEnabled->Checked = ($this->config['jsontools']['enabled'] == 1);
+ if (key_exists('use_sudo', $this->config['jsontools'])) {
+ $this->BJSONUseSudo->Checked = $this->config['jsontools']['use_sudo'];
+ }
+ if (key_exists('bconfig_dir', $this->config['jsontools'])) {
+ $this->BConfigDir->Text = $this->config['jsontools']['bconfig_dir'];
+ }
+ if (key_exists('bdirjson_path', $this->config['jsontools'])) {
+ $this->BDirJSONPath->Text = $this->config['jsontools']['bdirjson_path'];
+ }
+ if (key_exists('dir_cfg_path', $this->config['jsontools'])) {
+ $this->DirCfgPath->Text = $this->config['jsontools']['dir_cfg_path'];
+ }
+ if (key_exists('bsdjson_path', $this->config['jsontools'])) {
+ $this->BSdJSONPath->Text = $this->config['jsontools']['bsdjson_path'];
+ }
+ if (key_exists('sd_cfg_path', $this->config['jsontools'])) {
+ $this->SdCfgPath->Text = $this->config['jsontools']['sd_cfg_path'];
+ }
+ if (key_exists('bfdjson_path', $this->config['jsontools'])) {
+ $this->BFdJSONPath->Text = $this->config['jsontools']['bfdjson_path'];
+ }
+ if (key_exists('fd_cfg_path', $this->config['jsontools'])) {
+ $this->FdCfgPath->Text = $this->config['jsontools']['fd_cfg_path'];
+ }
+ if (key_exists('bbconsjson_path', $this->config['jsontools'])) {
+ $this->BBconsJSONPath->Text = $this->config['jsontools']['bbconsjson_path'];
+ }
+ if (key_exists('bcons_cfg_path', $this->config['jsontools'])) {
+ $this->BconsCfgPath->Text = $this->config['jsontools']['bcons_cfg_path'];
+ }
+ }
+
+ private function loadActionsSettings() {
+ if ($this->IsPostBack || $this->IsCallBack) {
+ return;
+ }
+ if (!key_exists('actions', $this->config)) {
+ $this->DirStartAction->Text = self::DEFAULT_ACTION_DIR_START;
+ $this->DirStopAction->Text = self::DEFAULT_ACTION_DIR_STOP;
+ $this->DirRestartAction->Text = self::DEFAULT_ACTION_DIR_RESTART;
+ $this->SdStartAction->Text = self::DEFAULT_ACTION_SD_START;
+ $this->SdStopAction->Text = self::DEFAULT_ACTION_SD_STOP;
+ $this->SdRestartAction->Text = self::DEFAULT_ACTION_SD_RESTART;
+ $this->FdStartAction->Text = self::DEFAULT_ACTION_FD_START;
+ $this->FdStopAction->Text = self::DEFAULT_ACTION_FD_STOP;
+ $this->FdRestartAction->Text = self::DEFAULT_ACTION_FD_RESTART;
+ return;
+ }
+
+ if (key_exists('enabled', $this->config['actions'])) {
+ $this->ActionsEnabled->Checked = ($this->config['actions']['enabled'] == 1);
+ }
+ if (key_exists('use_sudo', $this->config['actions'])) {
+ $this->ActionsUseSudo->Checked = $this->config['actions']['use_sudo'];
+ }
+ if (key_exists('dir_start', $this->config['actions'])) {
+ $this->DirStartAction->Text = $this->config['actions']['dir_start'];
+ }
+ if (key_exists('dir_stop', $this->config['actions'])) {
+ $this->DirStopAction->Text = $this->config['actions']['dir_stop'];
+ }
+ if (key_exists('dir_restart', $this->config['actions'])) {
+ $this->DirRestartAction->Text = $this->config['actions']['dir_restart'];
+ }
+ if (key_exists('sd_start', $this->config['actions'])) {
+ $this->SdStartAction->Text = $this->config['actions']['sd_start'];
+ }
+ if (key_exists('sd_stop', $this->config['actions'])) {
+ $this->SdStopAction->Text = $this->config['actions']['sd_stop'];
+ }
+ if (key_exists('sd_restart', $this->config['actions'])) {
+ $this->SdRestartAction->Text = $this->config['actions']['sd_restart'];
+ }
+ if (key_exists('fd_start', $this->config['actions'])) {
+ $this->FdStartAction->Text = $this->config['actions']['fd_start'];
+ }
+ if (key_exists('fd_stop', $this->config['actions'])) {
+ $this->FdStopAction->Text = $this->config['actions']['fd_stop'];
+ }
+ if (key_exists('fd_restart', $this->config['actions'])) {
+ $this->FdRestartAction->Text = $this->config['actions']['fd_restart'];
+ }
+ }
+
+ private function loadAuthSettings() {
+ if ($this->IsPostBack || $this->IsCallBack) {
+ return;
+ }
+ if ($this->config['api']['auth_type'] === AuthBasic::NAME) {
+ $this->AuthBasic->Checked = true;
+ } elseif ($this->config['api']['auth_type'] === AuthOAuth2::NAME) {
+ $this->AuthOAuth2->Checked = true;
+ }
+ }
+
+ public function setDBType($sender, $param) {
+ $db = $this->DBType->SelectedValue;
+ $this->setDBLogin($db);
+ $this->setDBPassword($db);
+ $this->setDBAddress($db);
+ $this->setDBPort($db);
+ $this->setDBPath($db);
+ }
+
+ public function setDBLogin($db) {
+ $this->DBLogin->Enabled = ($db !== Database::SQLITE_TYPE);
+ }
+
+ public function setDBPassword($db) {
+ $this->DBPassword->Enabled = ($db !== Database::SQLITE_TYPE);
+
+ }
+
+ public function setDBAddress($db) {
+ $this->DBAddress->Enabled = ($db !== Database::SQLITE_TYPE);
+ }
+
+ public function setDBPort($db) {
+ $port = null;
+ if(Database::PGSQL_TYPE === $db) {
+ $port = 5432;
+ } elseif(Database::MYSQL_TYPE === $db) {
+ $port = 3306;
+ } elseif(Database::SQLITE_TYPE === $db) {
+ $port = null;
+ }
+
+ $prevPort = $this->DBPort->getViewState('port');
+
+ if(is_null($port)) {
+ $this->DBPort->Text = '';
+ $this->DBPort->Enabled = false;
+ } else {
+ $this->DBPort->Enabled = true;
+ $this->DBPort->Text = (empty($prevPort)) ? $port : $prevPort;
+ }
+ $this->DBPort->setViewState('port', '');
+ }
+
+ public function setDBPath($db) {
+ if ($db === Database::SQLITE_TYPE) {
+ $this->DBPath->Enabled = true;
+ $this->DBPathField->Display = 'Fixed';
+ } else {
+ $this->DBPath->Enabled = false;
+ $this->DBPathField->Display = 'Hidden';
+ }
+ }
+
+ public function connectionDBTest($sender, $param) {
+ $validation = false;
+ $db_params = array();
+ $db_params['type'] = $this->DBType->SelectedValue;
+ if($db_params['type'] === Database::MYSQL_TYPE || $db_params['type'] === Database::PGSQL_TYPE) {
+ $db_params['name'] = $this->DBName->Text;
+ $db_params['login'] = $this->DBLogin->Text;
+ $db_params['password'] = $this->DBPassword->Text;
+ $db_params['ip_addr'] = $this->DBAddress->Text;
+ $db_params['port'] = $this->DBPort->Text;
+ $validation = true;
+ } elseif($db_params['type'] === Database::SQLITE_TYPE && !empty($this->DBPath->Text)) {
+ $db_params['path'] = $this->DBPath->Text;
+ $validation = true;
+ }
+
+ $is_validate = false;
+ $emsg = '';
+ if ($validation === true) {
+ try {
+ $is_validate = $this->getModule('db')->testDbConnection($db_params);
+ } catch (BAPIException $e) {
+ $emsg = $e->getErrorMessage();
+ }
+ }
+ if (!empty($emsg)) {
+ $this->DbTestResultErr->Text = $emsg;
+ }
+ if ($is_validate === true) {
+ $this->getCallbackClient()->show('db_test_result_ok');
+ $this->getCallbackClient()->hide('db_test_result_err');
+ $this->getCallbackClient()->hide($this->DbTestResultErr);
+ } else {
+ $this->getCallbackClient()->hide('db_test_result_ok');
+ $this->getCallbackClient()->show('db_test_result_err');
+ $this->getCallbackClient()->show($this->DbTestResultErr);
+ }
+ }
+
+ public function connectionBconsoleTest($sender, $param) {
+ $emsg = '';
+ $result = $this->getModule('bconsole')->testBconsoleCommand(
+ array('version'),
+ $this->BconsolePath->Text,
+ $this->BconsoleConfigPath->Text,
+ $this->BconsoleUseSudo->Checked
+ );
+ $is_validate = ($result->exitcode === 0);
+ if (!$is_validate) {
+ $this->BconsoleTestResultErr->Text = $result->output;
+ }
+ if ($is_validate === true) {
+ $this->getCallbackClient()->show('bconsole_test_result_ok');
+ $this->getCallbackClient()->hide('bconsole_test_result_err');
+ $this->getCallbackClient()->hide($this->BconsoleTestResultErr);
+ } else {
+ $this->getCallbackClient()->hide('bconsole_test_result_ok');
+ $this->getCallbackClient()->show('bconsole_test_result_err');
+ $this->getCallbackClient()->show($this->BconsoleTestResultErr);
+ }
+ }
+
+ public function testJSONToolsCfg($sender, $param) {
+ $jsontools = array(
+ 'dir' => array(
+ 'path' => $this->BDirJSONPath->Text,
+ 'cfg' => $this->DirCfgPath->Text,
+ 'ok_el' => $this->BDirJSONPathTestOk,
+ 'error_el' => $this->BDirJSONPathTestErr
+ ),
+ 'sd' => array(
+ 'path' => $this->BSdJSONPath->Text,
+ 'cfg' => $this->SdCfgPath->Text,
+ 'ok_el' => $this->BSdJSONPathTestOk,
+ 'error_el' => $this->BSdJSONPathTestErr
+ ),
+ 'fd' => array(
+ 'path' => $this->BFdJSONPath->Text,
+ 'cfg' => $this->FdCfgPath->Text,
+ 'ok_el' => $this->BFdJSONPathTestOk,
+ 'error_el' => $this->BFdJSONPathTestErr
+ ),
+ 'bcons' => array(
+ 'path' => $this->BBconsJSONPath->Text,
+ 'cfg' => $this->BconsCfgPath->Text,
+ 'ok_el' => $this->BBconsJSONPathTestOk,
+ 'error_el' => $this->BBconsJSONPathTestErr
+ )
+ );
+ $use_sudo = $this->BJSONUseSudo->Checked;
+
+ foreach ($jsontools as $type => $config) {
+ $config['ok_el']->Display = 'None';
+ $config['error_el']->Display = 'None';
+ if (!empty($config['path']) && !empty($config['cfg'])) {
+
+ $result = (object)$this->getModule('json_tools')->testJSONTool($config['path'], $config['cfg'], $use_sudo);
+ if ($result->exitcode === 0) {
+ // test passed
+ $config['ok_el']->Display = 'Dynamic';
+ } else {
+ // test failed
+ $config['error_el']->Text = implode("\n", $result->output);
+ $config['error_el']->Display = 'Dynamic';
+ }
+ }
+ }
+ }
+
+ public function testConfigDir($sender, $param) {
+ $valid = is_writeable($this->BConfigDir->Text);
+ $this->BConfigDirTestOk->Display = 'None';
+ $this->BConfigDirTestErr->Display = 'None';
+ $this->BConfigDirWritableTest->Display = 'None';
+ if ($valid === true) {
+ $this->BConfigDirTestOk->Display = 'Dynamic';
+ } else {
+ $this->BConfigDirWritableTest->Display = 'Dynamic';
+ $this->BConfigDirTestErr->Display = 'Dynamic';
+ }
+ $param->setIsValid($valid);
+ }
+
+ public function testExecActionCommand($sender, $param) {
+ $action = $param->CommandParameter;
+ $cmd = '';
+ switch ($action) {
+ case 'dir_start': $cmd = $this->DirStartAction->Text; break;
+ case 'dir_stop': $cmd = $this->DirStopAction->Text; break;
+ case 'dir_restart': $cmd = $this->DirRestartAction->Text; break;
+ case 'sd_start': $cmd = $this->SdStartAction->Text; break;
+ case 'sd_stop': $cmd = $this->SdStopAction->Text; break;
+ case 'sd_restart': $cmd = $this->SdRestartAction->Text; break;
+ case 'fd_start': $cmd = $this->FdStartAction->Text; break;
+ case 'fd_stop': $cmd = $this->FdStopAction->Text; break;
+ case 'fd_restart': $cmd = $this->FdRestartAction->Text; break;
+ };
+ $result = $this->getModule('comp_actions')->execCommand($cmd, $this->ActionsUseSudo->Checked);
+ $this->getCallbackClient()->callClientFunction('set_action_command_output', array($action, (array)$result));
+ }
+
+ public function saveGeneral($sender, $param) {
+ $reload_page = false;
+ if ($this->config['api']['lang'] != $this->GeneralLang->SelectedValue) {
+ $reload_page = true;
+ }
+ $this->config['api']['lang'] = $this->GeneralLang->SelectedValue;
+ $this->config['api']['debug'] = $this->GeneralDebug->Checked ? 1 : 0;
+ $this->getModule('api_config')->setConfig($this->config);
+ if ($reload_page) {
+ $this->getCallbackClient()->callClientFunction('reload_page_cb', []);
+ }
+ }
+
+ public function saveCatalog($sender, $param) {
+ $cfg = [
+ 'enabled' => ($this->DBEnabled->Checked ? 1 : 0),
+ 'type' => $this->DBType->SelectedValue,
+ 'name' => $this->DBName->Text,
+ 'login' => $this->DBLogin->Text,
+ 'password' => $this->DBPassword->Text,
+ 'ip_addr' => $this->DBAddress->Text,
+ 'port' => $this->DBPort->Text,
+ 'path' => ($this->DBType->SelectedValue === Database::SQLITE_TYPE) ? $this->DBPath->Text : ''
+ ];
+ $this->config['db'] = $cfg;
+ $this->getModule('api_config')->setConfig($this->config);
+ }
+
+ public function saveBconsole($sender, $param) {
+ $cfg = [
+ 'enabled' => ($this->BconsoleEnabled->Checked ? 1 : 0),
+ 'bin_path' => $this->BconsolePath->Text,
+ 'cfg_path' => $this->BconsoleConfigPath->Text,
+ 'use_sudo' => ($this->BconsoleUseSudo->Checked ? 1 : 0)
+ ];
+ $this->config['bconsole'] = $cfg;
+ $this->getModule('api_config')->setConfig($this->config);
+ }
+
+ public function saveConfig($sender, $param) {
+ $cfg = [
+ 'enabled' => ($this->ConfigEnabled->Checked ? 1 : 0),
+ 'use_sudo' => ($this->BJSONUseSudo->Checked ? 1 : 0),
+ 'bconfig_dir' => $this->BConfigDir->Text,
+ 'bdirjson_path' => $this->BDirJSONPath->Text,
+ 'dir_cfg_path' => $this->DirCfgPath->Text,
+ 'bsdjson_path' => $this->BSdJSONPath->Text,
+ 'sd_cfg_path' => $this->SdCfgPath->Text,
+ 'bfdjson_path' => $this->BFdJSONPath->Text,
+ 'fd_cfg_path' => $this->FdCfgPath->Text,
+ 'bbconsjson_path' => $this->BBconsJSONPath->Text,
+ 'bcons_cfg_path' => $this->BconsCfgPath->Text
+ ];
+ $this->config['jsontools'] = $cfg;
+ $this->getModule('api_config')->setConfig($this->config);
+ }
+
+ public function saveActions($sender, $param) {
+ $cfg = [
+ 'enabled' => ($this->ActionsEnabled->Checked ? 1 : 0),
+ 'use_sudo' => ($this->ActionsUseSudo->Checked ? 1 : 0),
+ 'dir_start' => $this->DirStartAction->Text,
+ 'dir_stop' => $this->DirStopAction->Text,
+ 'dir_restart' => $this->DirRestartAction->Text,
+ 'sd_start' => $this->SdStartAction->Text,
+ 'sd_stop' => $this->SdStopAction->Text,
+ 'sd_restart' => $this->SdRestartAction->Text,
+ 'fd_start' => $this->FdStartAction->Text,
+ 'fd_stop' => $this->FdStopAction->Text,
+ 'fd_restart' => $this->FdRestartAction->Text
+ ];
+ $this->config['actions'] = $cfg;
+ $this->getModule('api_config')->setConfig($this->config);
+ }
+
+ public function saveAuth($sender, $param) {
+ $auth_type = AuthBasic::NAME;
+ if ($this->AuthOAuth2->Checked) {
+ $auth_type = AuthOAuth2::NAME;
+ } elseif ($this->AuthBasic->Checked) {
+ $auth_type = AuthBasic::NAME;
+ }
+ $this->config['api']['auth_type'] = $auth_type;
+ $this->getModule('api_config')->setConfig($this->config);
+ }
+}
+?>
<urls>
<!-- Pages -->
- <url ServiceParameter="APIInstallWizard" pattern="panel/config/" />
<url ServiceParameter="APIHome" pattern="panel/" />
+ <url ServiceParameter="APIInstallWizard" pattern="panel/config/" />
+ <url ServiceParameter="APIBasicUsers" pattern="panel/basic/" />
+ <url ServiceParameter="APIOAuth2Clients" pattern="panel/oauth2/" />
+ <url ServiceParameter="APISettings" pattern="panel/settings/" />
</urls>
--- /dev/null
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum - Bacula web interface
+ *
+ * Copyright (C) 2013-2021 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.
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TActiveLinkButton');
+Prado::using('Application.Common.Portlets.PortletTemplate');
+
+/**
+ * Main side-bar control.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Control
+ * @package Baculum API
+ */
+class APISideBar extends PortletTemplate {
+ /**
+ * Reload URL is used to refresh page after logout with Basic auth.
+ */
+ public $reload_url = '';
+
+ public function onInit($param) {
+ parent::onInit($param);
+ $fake_pwd = $this->getModule('crypto')->getRandomString();
+ // must be different than currently logged in Basic user
+ $user = (isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : '') . '1';
+
+ // do a login try with different user and password to logout current user
+ $this->reload_url = $this->getPage()->getFullLoginUrl($user, $fake_pwd);
+ }
+
+ public function logout($sender, $param) {
+ /**
+ * This status code 401 is necessary to stop comming AJAX requests
+ * and to bring the login prompt on.
+ */
+ $this->Response->setStatusCode(401);
+ }
+}
+?>
--- /dev/null
+<!-- Sidebar/menu -->
+<nav class="w3-sidebar w3-white w3-animate-left w3-margin-bottom" style="z-index:3; width:250px;" id="sidebar">
+ <div class="w3-container w3-row w3-section">
+ <div class="w3-col s3">
+ <img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/avatar2.png" class="w3-circle w3-margin-right" style="width: 33px" />
+ </div>
+ <div class="w3-col s9 w3-bar">
+ <span><%[ Welcome ]%><strong><%=isset($_SERVER['PHP_AUTH_USER']) ? ', ' . $_SERVER['PHP_AUTH_USER'] : ''%></strong></span><br>
+ <script>var main_side_bar_reload_url = '<%=$this->reload_url%>';</script>
+ <com:TActiveLinkButton
+ ID="Logout"
+ OnClick="logout"
+ CssClass="w3-bar-item w3-button"
+ ToolTip="<%[ Logout ]%>"
+ >
+ <prop:ClientSide.OnComplete>
+ if (!window.chrome || window.navigator.webdriver) {
+ window.location.href = main_side_bar_reload_url;
+ } else if (window.chrome) {
+ // For chrome this reload is required to show login Basic auth prompt
+ window.location.reload();
+ }
+ </prop:ClientSide.OnComplete>
+ <i class="fa fa-power-off"></i>
+ </com:TActiveLinkButton>
+ </div>
+ </div>
+ <div class="w3-container w3-black">
+ <h5>Baculum API Menu</h5>
+ </div>
+ <div class="w3-bar-block" style="margin-bottom: 45px;">
+ <div class="w3-black" style="height: 3px"></div>
+ <a href="<%=$this->Service->constructUrl('APIHome')%>" class="w3-bar-item w3-button w3-padding<%=$this->Service->getRequestedPagePath() == 'APIHome' ? ' w3-blue': ''%>"><i class="fas fa-tachometer-alt fa-fw"></i> <%[ Dashboard ]%></a>
+ <a href="<%=$this->Service->constructUrl('APIBasicUsers')%>" class="w3-bar-item w3-button w3-padding<%=$this->Service->getRequestedPagePath() == 'APIBasicUsers' ? ' w3-blue': ''%>"><i class="fa fa-users fa-fw"></i> <%[ Basic users ]%></a>
+ <a href="<%=$this->Service->constructUrl('APIOAuth2Clients')%>" class="w3-bar-item w3-button w3-padding<%=$this->Service->getRequestedPagePath() == 'APIOAuth2Clients' ? ' w3-blue': ''%>"><i class="fa fa-user-shield fa-fw"></i> <%[ OAuth2 clients ]%></a>
+ <a href="<%=$this->Service->constructUrl('APISettings')%>" class="w3-bar-item w3-button w3-padding<%=$this->Service->getRequestedPagePath() == 'APISettings' ? ' w3-blue': ''%>"><i class="fa fa-wrench fa-fw"></i> <%[ Settings ]%></a>
+ <a href="<%=$this->Service->constructUrl('APIInstallWizard')%>" class="w3-bar-item w3-button w3-padding<%=$this->Service->getRequestedPagePath() == 'APIInstallWizard' ? ' w3-blue': ''%>"><i class="fa fa-hat-wizard fa-fw"></i> <%[ Configuration wizard ]%></a>
+ </div>
+</nav>
+<!-- Overlay effect when opening sidebar on small screens -->
+<div class="w3-overlay w3-hide-large w3-animate-opacity" onclick="W3SideBar.close(); return false;" style="cursor:pointer" title="close side menu" id="overlay_bg"></div>
"name": "AGPLv3",
"url": "https://www.gnu.org/licenses/agpl-3.0-standalone.html"
},
- "version": "1.0.0"
+ "version": "2.0.0"
},
"server": {
"servers": [{
"description": "Bacula Client endpoints",
"externalDocs": {
"description": "Find out more",
- "url": "https://www.bacula.org/9.6.x-manuals/en/main/Configuring_Director.html#SECTION0021130000000000000000"
+ "url": "https://www.bacula.org/11.0.x-manuals/en/main/Client_File_daemon_Configur.html#SECTION0022100000000000000000"
}
},
{
"description": "Bacula Job endpoints",
"externalDocs": {
"description": "Find out more",
- "url": "https://www.bacula.org/9.6.x-manuals/en/main/Configuring_Director.html#SECTION002130000000000000000"
+ "url": "https://www.bacula.org/11.0.x-manuals/en/main/Configuring_Director.html#SECTION0021300000000000000000"
}
},
{
"description": "Bacula Storage endpoints",
"externalDocs": {
"description": "Find out more",
- "url": "https://www.bacula.org/9.6.x-manuals/en/main/Configuring_Director.html#SECTION0021140000000000000000"
+ "url": "https://www.bacula.org/11.0.x-manuals/en/main/Configuring_Director.html#SECTION00211400000000000000000"
}
},
{
"description": "Bacula Pool endpoints",
"externalDocs": {
"description": "Find out more",
- "url": "https://www.bacula.org/9.6.x-manuals/en/main/Configuring_Director.html#SECTION0021160000000000000000"
+ "url": "https://www.bacula.org/11.0.x-manuals/en/main/Configuring_Director.html#SECTION00211600000000000000000"
}
},
{
"description": "Bacula Volume endpoints",
"externalDocs": {
"description": "Find out more",
- "url": "https://www.bacula.org/9.6.x-manuals/en/main/Basic_Volume_Management.html"
+ "url": "https://www.bacula.org/11.0.x-manuals/en/main/Basic_Volume_Management.html"
}
},
{
"description": "Bacula FileSet endpoints",
"externalDocs": {
"description": "Find out more",
- "url": "https://www.bacula.org/9.6.x-manuals/en/main/Configuring_Director.html#SECTION002170000000000000000"
+ "url": "https://www.bacula.org/11.0.x-manuals/en/main/Configuring_Director.html#SECTION0021700000000000000000"
}
},
{
"description": "Bacula Schedule endpoints",
"externalDocs": {
"description": "Find out more",
- "url": "https://www.bacula.org/9.6.x-manuals/en/main/Configuring_Director.html#SECTION002150000000000000000"
+ "url": "https://www.bacula.org/11.0.x-manuals/en/main/Configuring_Director.html#SECTION0021500000000000000000"
}
},
{
"description": "Bacula BVFS endpoints",
"externalDocs": {
"description": "Find out more",
- "url": "https://www.bacula.org/9.6.x-manuals/en/main/New_Features_in_5_2_13.html#SECTION001014000000000000000"
+ "url": "https://www.bacula.org/11.0.x-manuals/en/main/New_Features_in_5_2_13.html#SECTION0010140000000000000000"
}
},
{
"description": "Bacula joblog endpoints"
},
{
- "name": "status",
- "description": "Bacula status endpoints"
- }],
+ "name": "directors",
+ "description": "Bacula director endpoints",
+ "externalDocs": {
+ "description": "Find out more",
+ "url": "https://www.bacula.org/11.0.x-manuals/en/main/Configuring_Director.html"
+ }
+ }
+ ],
"paths": {
- "/api/v1/clients": {
+ "/api/v2/clients": {
"get": {
"tags": ["clients"],
"summary": "Client list",
}]
}
},
- "/api/v1/clients/{clientid}": {
+ "/api/v2/clients/{clientid}": {
"get": {
"tags": ["clients"],
"summary": "Find client by ClientId",
}]
}
},
- "/api/v1/clients/{clientid}/show": {
+ "/api/v2/clients/{clientid}/show": {
"get": {
"tags": ["clients"],
"summary": "Show client",
]
}
},
- "/api/v1/clients/{clientid}/status": {
+ "/api/v2/clients/{clientid}/status": {
"get": {
"tags": ["clients"],
"summary": "Client status",
"type": "array",
"items": {
"type": "string",
- "description": "Client status"
+ "description": "Client status output"
}
},
"error": {
}
}
},
- "parameters": [{
- "$ref": "#/components/parameters/ClientId"
- }]
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/ClientId"
+ },
+ {
+ "$ref": "#/components/parameters/Output"
+ },
+ {
+ "name": "type",
+ "in": "query",
+ "description": "Output type using together with output=json parameter.",
+ "schema": {
+ "type": "string",
+ "enum": ["header", "running", "terminated"]
+ }
+ }
+ ]
}
},
- "/api/v1/clients/{clientid}/jobs": {
+ "/api/v2/clients/{clientid}/jobs": {
"get": {
"tags": ["clients"],
"summary": "Jobs for client",
}]
}
},
- "/api/v1/clients/{clientid}/ls": {
+ "/api/v2/clients/{clientid}/ls": {
"get": {
"tags": ["clients"],
"summary": "List Client files/directories",
]
}
},
- "/api/v1/clients/{clientid}/bandwidth": {
+ "/api/v2/clients/{clientid}/bandwidth": {
"put": {
"tags": ["clients"],
"summary": "Set Client bandwidth limit",
]
}
},
- "/api/v1/clients/show": {
+ "/api/v2/clients/show": {
"get": {
"tags": ["clients"],
"summary": "Show clients",
]
}
},
- "/api/v1/jobs": {
+ "/api/v2/jobs": {
"get": {
"tags": ["jobs"],
"summary": "Job list",
]
}
},
- "/api/v1/jobs/{jobid}": {
+ "/api/v2/jobs/{jobid}": {
"get": {
"tags": ["jobs"],
"summary": "Find job by JobId",
]
}
},
- "/api/v1/jobs/{jobid}/cancel": {
+ "/api/v2/jobs/{jobid}/cancel": {
"put": {
"tags": ["jobs"],
"summary": "Cancel job",
"description": "Cancel running job.",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"responses": {
"200": {
"description": "Cancel command output",
]
}
},
- "/api/v1/jobs/{jobid}/show": {
+ "/api/v2/jobs/{jobid}/show": {
"get": {
"tags": ["jobs"],
"summary": "Show job",
]
}
},
- "/api/v1/jobs/{jobid}/bandwidth": {
+ "/api/v2/jobs/{jobid}/bandwidth": {
"put": {
"tags": ["jobs"],
"summary": "Set Job bandwidth limit",
]
}
},
- "/api/v1/jobs/{jobid}/files": {
+ "/api/v2/jobs/{jobid}/files": {
"get": {
"tags": ["jobs"],
"summary": "Show job files and directories",
]
}
},
- "/api/v1/jobs/files": {
+ "/api/v2/jobs/files": {
"get": {
"tags": ["jobs"],
"summary": "Search jobs by file criteria",
]
}
},
- "/api/v1/jobs/resnames": {
+ "/api/v2/jobs/resnames": {
"get": {
"tags": ["jobs"],
"summary": "Job resource names",
]
}
},
- "/api/v1/jobs/recent/{jobname}": {
+ "/api/v2/jobs/recent/{jobname}": {
"get": {
"tags": ["jobs"],
"summary": "Get most recent jobids for job to restore",
]
}
},
- "/api/v1/jobs/estimate": {
+ "/api/v2/jobs/estimate": {
"get": {
"tags": ["jobs"],
"summary": "Get estimate output",
"post": {
"tags": ["jobs"],
"summary": "Estimate job bytes and files",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"description": "Estimate job bytes and files before real job run. There can be used (id OR name) and (clientid OR client)",
"responses": {
"200": {
},
"parameters": [
{
- "name": "create[id]",
+ "name": "id",
"in": "body",
"description": "Job identifier",
"required": true,
}
},
{
- "name": "create[name]",
+ "name": "name",
"in": "body",
"description": "Job name (can be used instead id)",
"required": true,
}
},
{
- "name": "create[clientid]",
+ "name": "clientid",
"in": "body",
"description": "Client identifier",
"required": true,
}
},
{
- "name": "create[client]",
+ "name": "client",
"in": "body",
"description": "Client name (can be used instead clientid)",
"required": true,
}
},
{
- "name": "create[fileset]",
+ "name": "fileset",
"in": "body",
"description": "FileSet name",
"required": true,
}
},
{
- "name": "create[accurate]",
+ "name": "accurate",
"in": "body",
"description": "Accurate mode, 1 if enabled, otherwise 0",
"required": false,
]
}
},
- "/api/v1/jobs/run": {
+ "/api/v2/jobs/run": {
"post": {
"tags": ["jobs"],
"summary": "Run job",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"description": "Run job with specific parameters. There can be used (id OR name) and (clientid OR client)",
"responses": {
"200": {
},
"parameters": [
{
- "name": "create[id]",
+ "name": "id",
"in": "body",
"description": "Job identifier",
"required": true,
}
},
{
- "name": "create[name]",
+ "name": "name",
"in": "body",
"description": "Job name (can be used instead id)",
"required": true,
}
},
{
- "name": "create[clientid]",
+ "name": "level",
+ "in": "body",
+ "description": "Job level",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "enum": ["F","I", "D", "B", "f", "V", "C", "O", "d"]
+ }
+ },
+ {
+ "name": "clientid",
"in": "body",
"description": "Client identifier",
"required": true,
}
},
{
- "name": "create[client]",
+ "name": "client",
"in": "body",
"description": "Client name (can be used instead clientid)",
"required": true,
}
},
{
- "name": "create[storageid]",
+ "name": "storageid",
"in": "body",
"description": "Storage identifier",
"required": true,
}
},
{
- "name": "create[storage]",
+ "name": "storage",
"in": "body",
"description": "Storage name (can be used instead storageid)",
"required": true,
}
},
{
- "name": "create[poolid]",
+ "name": "poolid",
"in": "body",
"description": "Pool identifier",
"required": true,
}
},
{
- "name": "create[pool]",
+ "name": "pool",
"in": "body",
"description": "Pool name (can be used instead poolid)",
"required": true,
}
},
{
- "name": "create[filesetid]",
+ "name": "filesetid",
"in": "body",
"description": "FileSet identifier",
"required": true,
}
},
{
- "name": "create[fileset]",
+ "name": "fileset",
"in": "body",
"description": "FileSet name (can be used instead filesetid)",
"required": true,
}
},
{
- "name": "create[priority]",
+ "name": "priority",
"in": "body",
"description": "Job priority",
"required": false,
}
},
{
- "name": "create[accurate]",
+ "name": "accurate",
"in": "body",
"description": "Accurate mode, 1 if enabled, otherwise 0",
"required": false,
}
},
{
- "name": "create[jobid]",
+ "name": "jobid",
"in": "body",
"description": "Job identifier for verify job",
"required": false,
}
},
{
- "name": "create[verifyjob]",
+ "name": "verifyjob",
"in": "body",
"description": "Verify job name",
"required": false,
]
}
},
- "/api/v1/jobs/show": {
+ "/api/v2/jobs/show": {
"get": {
"tags": ["jobs"],
"summary": "Show jobs",
]
}
},
- "/api/v1/jobs/totals": {
+ "/api/v2/jobs/totals": {
"get": {
"tags": ["jobs"],
"summary": "Show job total bytes and files",
}
}
},
- "/api/v1/jobs/restore": {
+ "/api/v2/jobs/restore": {
"post": {
"tags": ["jobs"],
"summary": "Restore job",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"description": "Restore backup job.",
"responses": {
"200": {
},
"parameters": [
{
- "name": "create[id]",
+ "name": "id",
"in": "body",
"description": "Job identifier (for full restore)",
"required": false,
}
},
{
- "name": "create[clientid]",
+ "name": "clientid",
"in": "body",
"description": "Client identifier",
"required": true,
}
},
{
- "name": "create[client]",
+ "name": "client",
"in": "body",
"description": "Client name (can be used instead clientid)",
"required": true,
}
},
{
- "name": "create[where]",
+ "name": "where",
"in": "body",
"description": "Where to restore files",
"required": true,
}
},
{
- "name": "create[rpath]",
+ "name": "rpath",
"in": "body",
"description": "Rpath (restore path)",
"required": false,
}
},
{
- "name": "create[full]",
+ "name": "full",
"in": "body",
"description": "Full restore all files",
"required": false,
}
},
{
- "name": "create[filesetid]",
+ "name": "filesetid",
"in": "body",
"description": "FileSet identifier (for full restore)",
"required": false,
}
},
{
- "name": "create[fileset]",
+ "name": "fileset",
"in": "body",
"description": "FileSet (can be used instead of filesetid) (for full restore)",
"required": false,
}
},
{
- "name": "create[restorejob]",
+ "name": "restorejob",
"in": "body",
"description": "Restore job name",
"required": false,
}
},
{
- "name": "create[strip_prefix]",
+ "name": "strip_prefix",
"in": "body",
"description": "Strip prefix in restored paths",
"required": false,
}
},
{
- "name": "create[add_prefix]",
+ "name": "add_prefix",
"in": "body",
"description": "Add prefix to restored paths",
"required": false,
}
},
{
- "name": "create[add_suffix]",
+ "name": "add_suffix",
"in": "body",
"description": "Add suffix to restored paths",
"required": false,
}
},
{
- "name": "create[regex_where]",
+ "name": "regex_where",
"in": "body",
"description": "Use regex to file relocation",
"required": false,
]
}
},
- "/api/v1/storages": {
+ "/api/v2/storages": {
"get": {
"tags": ["storages"],
"summary": "Storage list",
}]
}
},
- "/api/v1/storages/{storageid}": {
+ "/api/v2/storages/{storageid}": {
"get": {
"tags": ["storages"],
"summary": "Find storage by StorageId",
}]
}
},
- "/api/v1/storages/{storageid}/show": {
+ "/api/v2/storages/{storageid}/show": {
"get": {
"tags": ["storages"],
"summary": "Show storage",
]
}
},
- "/api/v1/storages/{storageid}/status": {
+ "/api/v2/storages/{storageid}/status": {
"get": {
"tags": ["storages"],
"summary": "Storage status",
"type": "array",
"items": {
"type": "string",
- "description": "Storage status"
+ "description": "Storage status output"
}
},
"error": {
"type": "integer",
"description": "Error code",
- "enum": [0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 1000]
+ "enum": [0, 1, 2, 3, 4, 5, 6, 7, 11, 20, 1000]
}
}
}
}
}
},
- "parameters": [{
- "$ref": "#/components/parameters/StorageId"
- }]
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/StorageId"
+ },
+ {
+ "$ref": "#/components/parameters/Output"
+ },
+ {
+ "name": "type",
+ "in": "query",
+ "description": "Output type using together with output=json parameter.",
+ "schema": {
+ "type": "string",
+ "enum": ["header", "running", "devices", "terminated"]
+ }
+ }
+ ]
}
},
- "/api/v1/storages/{storageid}/mount": {
+ "/api/v2/storages/{storageid}/mount": {
"get": {
"tags": ["storages"],
"summary": "Mount storage",
]
}
},
- "/api/v1/storages/{storageid}/umount": {
+ "/api/v2/storages/{storageid}/umount": {
"get": {
"tags": ["storages"],
"summary": "Umount storage",
]
}
},
- "/api/v1/storages/{storageid}/release": {
+ "/api/v2/storages/{storageid}/release": {
"get": {
"tags": ["storages"],
"summary": "Release storage",
]
}
},
- "/api/v1/storages/show": {
+ "/api/v2/storages/show": {
"get": {
"tags": ["storages"],
"summary": "Show storages",
]
}
},
- "/api/v1/pools": {
+ "/api/v2/pools": {
"get": {
"tags": ["pools"],
"summary": "Pool list",
}]
}
},
- "/api/v1/pools/{poolid}": {
+ "/api/v2/pools/{poolid}": {
"get": {
"tags": ["pools"],
"summary": "Find pool by PoolId",
}]
}
},
- "/api/v1/pools/{poolid}/volumes": {
+ "/api/v2/pools/{poolid}/volumes": {
"get": {
"tags": ["pools"],
"summary": "Get all volumes in pool",
}]
}
},
- "/api/v1/pools/{poolid}/show": {
+ "/api/v2/pools/{poolid}/show": {
"get": {
"tags": ["pools"],
"summary": "Show pool",
}]
}
},
- "/api/v1/pools/{poolid}/update": {
+ "/api/v2/pools/{poolid}/update": {
"put": {
"tags": ["pools"],
"summary": "Update pool properties",
"description": "Update properties in specific pool",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"responses": {
"200": {
"description": "Update pool output",
}]
}
},
- "/api/v1/pools/{poolid}/update/volumes": {
+ "/api/v2/pools/{poolid}/update/volumes": {
"put": {
"tags": ["pools"],
"summary": "Update properties all volumes in pool",
"description": "Update properties all volumes in specific pool",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"responses": {
"200": {
"description": "Update all volumes in pool output",
}]
}
},
- "/api/v1/pools/show": {
+ "/api/v2/pools/show": {
"get": {
"tags": ["pools"],
"summary": "Show pools",
]
}
},
- "/api/v1/volumes": {
+ "/api/v2/volumes": {
"get": {
"tags": ["volumes"],
"summary": "Volume list",
}]
}
},
- "/api/v1/volumes/{mediaid}": {
+ "/api/v2/volumes/{mediaid}": {
"get": {
"tags": ["volumes"],
"summary": "Find volume by MediaId",
"tags": ["volumes"],
"summary": "Update volume properties",
"description": "Update specific volume properties.",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"responses": {
"200": {
"description": "Update volume output",
"$ref": "#/components/parameters/MediaId"
},
{
- "name": "update[volstatus]",
+ "name": "volstatus",
"in": "body",
"description": "Volume status",
"required": false,
}
},
{
- "name": "update[poolid]",
+ "name": "poolid",
"in": "body",
"description": "Update Volume Pool by Pool identifier",
"required": false,
}
},
{
- "name": "update[volretention]",
+ "name": "volretention",
"in": "body",
"description": "Volume retention time",
"required": false,
}
},
{
- "name": "update[voluseduration]",
+ "name": "voluseduration",
"in": "body",
"description": "Volume use duration time",
"required": false,
}
},
{
- "name": "update[maxvoljobs]",
+ "name": "maxvoljobs",
"in": "body",
"description": "Maximum volume jobs",
"required": false,
}
},
{
- "name": "update[maxvolfiles]",
+ "name": "maxvolfiles",
"in": "body",
"description": "Maximum volume files",
"required": false,
}
},
{
- "name": "update[maxvolbytes]",
+ "name": "maxvolbytes",
"in": "body",
"description": "Maximum volume bytes",
"required": false,
}
},
{
- "name": "update[slot]",
+ "name": "slot",
"in": "body",
"description": "Volume slot",
"required": false,
}
},
{
- "name": "update[recycle]",
+ "name": "recycle",
"in": "body",
"description": "Volume recycle flag",
"required": false,
}
},
{
- "name": "update[enabled]",
+ "name": "enabled",
"in": "body",
"description": "Volume enabled flag",
"required": false,
}
},
{
- "name": "update[inchanger]",
+ "name": "inchanger",
"in": "body",
"description": "Volume InChanger flag",
"required": false,
]
}
},
- "/api/v1/volumes/{mediaid}/prune": {
+ "/api/v2/volumes/{mediaid}/prune": {
"put": {
"tags": ["volumes"],
"summary": "Prune volume",
"description": "Do prunning on volume.",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"responses": {
"200": {
"description": "Prune volume output",
]
}
},
- "/api/v1/volumes/{mediaid}/purge": {
+ "/api/v2/volumes/{mediaid}/purge": {
"put": {
"tags": ["volumes"],
"summary": "Purge volume",
"description": "Do purging on volume.",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"responses": {
"200": {
"description": "Purge volume output",
]
}
},
- "/api/v1/volumes/{mediaid}/jobs": {
+ "/api/v2/volumes/{mediaid}/jobs": {
"get": {
"tags": ["volumes"],
"summary": "Jobs on volume",
}]
}
},
- "/api/v1/volumes/required/{jobid}/{fileid}": {
+ "/api/v2/volumes/required/{jobid}/{fileid}": {
"get": {
"tags": ["volumes"],
"summary": "Get volumes required to restore file",
]
}
},
- "/api/v1/volumes/label": {
+ "/api/v2/volumes/label": {
"get": {
"tags": ["volumes"],
"summary": "Get label volume output",
"tags": ["volumes"],
"summary": "Label volume",
"description": "Label volume with specified name (without using barcode).",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"responses": {
"200": {
"description": "Label volume with specified name (without barcode)",
},
"parameters": [
{
- "name": "create[volume]",
+ "name": "volume",
"in": "body",
"description": "Volume name",
"required": true,
}
},
{
- "name": "create[slot]",
+ "name": "slot",
"in": "body",
"description": "Slot number",
"required": true,
}
},
{
- "name": "create[drive]",
+ "name": "drive",
"in": "body",
"description": "Drive number",
"required": true,
}
},
{
- "name": "create[storageid]",
+ "name": "storageid",
"in": "body",
"description": "Storage identifier",
"required": true,
}
},
{
- "name": "create[storage]",
+ "name": "storage",
"in": "body",
"description": "Storage name can be used instead of storageid",
"required": true,
}
},
{
- "name": "create[poolid]",
+ "name": "poolid",
"in": "body",
"description": "Pool identifier",
"required": true,
}
},
{
- "name": "create[pool]",
+ "name": "pool",
"in": "body",
"description": "Pool name can be used instead of poolid",
"required": true,
]
}
},
- "/api/v1/volumes/label/barcodes": {
+ "/api/v2/volumes/label/barcodes": {
"get": {
"tags": ["volumes"],
"summary": "Get label barcodes volume output",
"tags": ["volumes"],
"summary": "Label volume using barcodes",
"description": "Label volume with specified name (with using barcode).",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"responses": {
"200": {
"description": "Label volume with specified name (with barcode)",
},
"parameters": [
{
- "name": "create[slots]",
+ "name": "slots",
"in": "body",
"description": "Slots numbers or slots range (ex. 1-3,5,10)",
"required": true,
}
},
{
- "name": "create[drive]",
+ "name": "drive",
"in": "body",
"description": "Drive number",
"required": true,
}
},
{
- "name": "create[storageid]",
+ "name": "storageid",
"in": "body",
"description": "Storage identifier",
"required": true,
}
},
{
- "name": "create[storage]",
+ "name": "storage",
"in": "body",
"description": "Storage name can be used instead of storageid",
"required": true,
}
},
{
- "name": "create[poolid]",
+ "name": "poolid",
"in": "body",
"description": "Pool identifier",
"required": true,
}
},
{
- "name": "create[pool]",
+ "name": "pool",
"in": "body",
"description": "Pool name can be used instead of poolid",
"required": true,
]
}
},
- "/api/v1/volumes/update": {
+ "/api/v2/volumes/update": {
"get": {
"tags": ["volumes"],
"summary": "Get update slots output",
"tags": ["volumes"],
"summary": "Update slots",
"description": "Update volume slots (without using barcode).",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"responses": {
"200": {
"description": "Update volume slots (without barcode)",
},
"parameters": [
{
- "name": "update[slots]",
+ "name": "slots",
"in": "body",
"description": "Slots numbers or slots range (ex. 1-3,5,10)",
"required": true,
}
},
{
- "name": "update[drive]",
+ "name": "drive",
"in": "body",
"description": "Drive number",
"required": true,
}
},
{
- "name": "update[storageid]",
+ "name": "storageid",
"in": "body",
"description": "Storage identifier",
"required": true,
}
},
{
- "name": "update[storage]",
+ "name": "storage",
"in": "body",
"description": "Storage name can be used instead of storageid",
"required": true,
]
}
},
- "/api/v1/volumes/update/barcodes": {
+ "/api/v2/volumes/update/barcodes": {
"get": {
"tags": ["volumes"],
"summary": "Get update slots output using barcodes",
"tags": ["volumes"],
"summary": "Update slots using barcodes",
"description": "Update volume slots (with using barcode).",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"responses": {
"200": {
"description": "Update volume slots (with barcode)",
},
"parameters": [
{
- "name": "update[slots]",
+ "name": "slots",
"in": "body",
"description": "Slots numbers or slots range (ex. 1-3,5,10)",
"required": true,
}
},
{
- "name": "update[drive]",
+ "name": "drive",
"in": "body",
"description": "Drive number",
"required": true,
}
},
{
- "name": "update[storageid]",
+ "name": "storageid",
"in": "body",
"description": "Storage identifier",
"required": true,
}
},
{
- "name": "update[storage]",
+ "name": "storage",
"in": "body",
"description": "Storage name can be used instead of storageid",
"required": true,
]
}
},
- "/api/v1/filesets": {
+ "/api/v2/filesets": {
"get": {
"tags": ["filesets"],
"summary": "FileSet list",
}]
}
},
- "/api/v1/filesets/{filesetid}": {
+ "/api/v2/filesets/{filesetid}": {
"get": {
"tags": ["filesets"],
"summary": "Find FileSet by FileSetId",
}]
}
},
- "/api/v1/filesets/resnames": {
+ "/api/v2/filesets/resnames": {
"get": {
"tags": ["filesets"],
"summary": "FileSet resource names",
}
}
},
- "/api/v1/schedules/resnames": {
+ "/api/v2/schedules/resnames": {
"get": {
"tags": ["schedules"],
"summary": "Schedule resource names",
}
}
},
- "/api/v1/schedules/status": {
+ "/api/v2/schedules/status": {
"get": {
"tags": ["schedules"],
"summary": "Schedule status",
]
}
},
- "/api/v1/bvfs/update": {
+ "/api/v2/bvfs/update": {
"put": {
"tags": ["bvfs"],
"summary": "Update BVFS cache",
"description": "Update BVFS cache for specific jobs identifiers",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"responses": {
"200": {
"description": "BVFS update command output",
}
}
},
- "/api/v1/bvfs/lsdirs": {
+ "/api/v2/bvfs/lsdirs": {
"get": {
"tags": ["bvfs"],
"summary": "BVFS list directories",
]
}
},
- "/api/v1/bvfs/lsfiles": {
+ "/api/v2/bvfs/lsfiles": {
"get": {
"tags": ["bvfs"],
"summary": "BVFS list files",
]
}
},
- "/api/v1/bvfs/versions": {
+ "/api/v2/bvfs/versions": {
"get": {
"tags": ["bvfs"],
"summary": "BVFS list file versions",
]
}
},
- "/api/v1/bvfs/getjobids": {
+ "/api/v2/bvfs/getjobids": {
"get": {
"tags": ["bvfs"],
"summary": "BVFS get particular jobids to restore",
]
}
},
- "/api/v1/bvfs/restore": {
+ "/api/v2/bvfs/restore": {
"post": {
"tags": ["bvfs"],
"summary": "Prepare BVFS restore",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"description": "Prepare BVFS restore",
"responses": {
"200": {
},
"parameters": [
{
- "name": "create[path]",
+ "name": "path",
"in": "body",
"description": "Path in format b2[0-9]+",
"required": true,
}
},
{
- "name": "create[jobids]",
+ "name": "jobids",
"in": "body",
"description": "Comma separated job identifiers",
"required": true,
}
},
{
- "name": "create[fileid]",
+ "name": "fileid",
"in": "body",
"description": "Comma seprated file identifiers",
"required": false,
}
},
{
- "name": "create[dirid]",
+ "name": "dirid",
"in": "body",
"description": "Comma seprated directory identifiers",
"required": false,
}
},
{
- "name": "create[findex]",
+ "name": "findex",
"in": "body",
"description": "Comma seprated directory file indexes",
"required": false,
]
}
},
- "/api/v1/bvfs/clear": {
+ "/api/v2/bvfs/clear": {
"put": {
"tags": ["bvfs"],
"summary": "Clear BVFS cache",
"description": "Clear BVFS cache",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"responses": {
"200": {
"description": "BVFS clear cache command output",
}
}
},
- "/api/v1/bvfs/cleanup": {
+ "/api/v2/bvfs/cleanup": {
"put": {
"tags": ["bvfs"],
"summary": "Cleanup BVFS (remove temporary table)",
"description": "Cleanup BVFS",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"responses": {
"200": {
"description": "BVFS cleanup output",
},
"parameters": [
{
- "name": "update[path]",
+ "name": "path",
"in": "body",
"description": "Path in format b2[0-9]+",
"required": true,
]
}
},
- "/api/v1/config": {
+ "/api/v2/config": {
"get": {
"tags": ["config"],
"summary": "Get components information",
}
}
},
- "/api/v1/config/{component_type}": {
+ "/api/v2/config/{component_type}": {
"get": {
"tags": ["config"],
"summary": "Get component config",
"tags": ["config"],
"summary": "Set component config",
"description": "Set specific component config",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"responses": {
"200": {
"description": "Set config status",
"$ref": "#/components/parameters/ComponentType"
},
{
- "name": "update[config]",
+ "name": "config",
"in": "body",
"description": "Config in JSON form to set",
"required": true,
]
}
},
- "/api/v1/config/{component_type}/{resource_type}": {
+ "/api/v2/config/{component_type}/{resource_type}": {
"get": {
"tags": ["config"],
"summary": "Get component resources config",
"tags": ["config"],
"summary": "Set component resources config",
"description": "Set specific component resources config",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"responses": {
"200": {
"description": "Set resources config",
"$ref": "#/components/parameters/ResourceType"
},
{
- "name": "update[config]",
+ "name": "config",
"in": "body",
"description": "Config in JSON form to set",
"required": true,
]
}
},
- "/api/v1/config/{component_type}/{resource_type}/{resource_name}": {
+ "/api/v2/config/{component_type}/{resource_type}/{resource_name}": {
"get": {
"tags": ["config"],
"summary": "Get component resource config",
"tags": ["config"],
"summary": "Set component resource config",
"description": "Set specific component resource config",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"responses": {
"200": {
"description": "Set single resource config",
"$ref": "#/components/parameters/ResourceName"
},
{
- "name": "update[config]",
+ "name": "config",
"in": "body",
"description": "Config in JSON form to set",
"required": true,
]
}
},
- "/api/v1/joblog/{jobid}": {
+ "/api/v2/joblog/{jobid}": {
"get": {
"tags": ["joblog"],
"summary": "Get job log for jobid",
}]
}
},
- "/api/v1/joblog/messages": {
+ "/api/v2/joblog/messages": {
"get": {
"tags": ["joblog"],
"summary": "Get console messages log.",
}]
}
},
- "/api/v1/status/director": {
+ "/api/v2/directors/{director_name}/status": {
"get": {
- "tags": ["status"],
+ "tags": ["directors"],
"summary": "Get director status",
"description": "Get director status",
"responses": {
},
"parameters": [
{
- "name": "type",
- "in": "query",
- "description": "Output type (header, scheduled, running, terminated)",
- "schema": {
- "type": "string"
- }
- }
- ]
- }
- },
- "/api/v1/status/storage": {
- "get": {
- "tags": ["status"],
- "summary": "Get storage status",
- "description": "Get storage status",
- "responses": {
- "200": {
- "description": "Storage status output",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "output": {
- "description": "Storage status output",
- "type": "object",
- "properties": {
- "header": {
- "description": "Status header",
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "name": {
- "description": "Storage name",
- "type": "string"
- },
- "version": {
- "description": "Storage version",
- "type": "string"
- },
- "uname": {
- "description": "Storage uname",
- "type": "string"
- },
- "started_epoch": {
- "description": "Started epoch",
- "type": "string"
- },
- "started": {
- "description": "Started time",
- "type": "string"
- },
- "jobs_run": {
- "description": "Jobs run",
- "type": "string"
- },
- "jobs_running": {
- "description": "Jobs running",
- "type": "string"
- },
- "ndevices": {
- "description": "Number of devices",
- "type": "string"
- },
- "nautochgr": {
- "description": "Number of autochangers",
- "type": "string"
- },
- "plugins": {
- "description": "Plugins",
- "type": "string"
- },
- "drivers": {
- "description": "Drivers",
- "type": "string"
- }
- }
- }
- },
- "devices": {
- "description": "Storage devices",
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "name": {
- "description": "Device name",
- "type": "string"
- },
- "archive_device": {
- "description": "Archive device",
- "type": "string"
- },
- "type": {
- "description": "Device type",
- "type": "string"
- },
- "media_type": {
- "description": "Media type",
- "type": "string"
- },
- "open": {
- "description": "Open",
- "type": "string"
- },
- "writers": {
- "description": "Writers",
- "type": "string"
- },
- "maximum_concurrent_jobs": {
- "description": "Maximum concurrent jobs",
- "type": "string"
- },
- "maximum_volume_size": {
- "description": "Maximum volume size",
- "type": "string"
- },
- "read_only": {
- "description": "Read only",
- "type": "string"
- },
- "autoselect": {
- "description": "Auto select",
- "type": "string"
- },
- "enabled": {
- "description": "Enabled",
- "type": "string"
- },
- "free_space": {
- "description": "Free space",
- "type": "string"
- },
- "total_space": {
- "description": "Total space",
- "type": "string"
- },
- "devno": {
- "description": "Device number",
- "type": "string"
- },
- "mounted": {
- "description": "Mounted",
- "type": "string"
- },
- "waiting": {
- "description": "Waiting",
- "type": "string"
- },
- "volume": {
- "description": "Volume name",
- "type": "string"
- },
- "pool": {
- "description": "Pool name",
- "type": "string"
- },
- "blocked_desc": {
- "description": "Blocked description",
- "type": "string"
- },
- "blocked": {
- "description": "Blocked",
- "type": "string"
- },
- "append": {
- "description": "Append",
- "type": "string"
- },
- "bytes": {
- "description": "Bytes",
- "type": "string"
- },
- "blocks": {
- "description": "Blocks",
- "type": "string"
- },
- "file": {
- "description": "File",
- "type": "string"
- },
- "block": {
- "description": "Block",
- "type": "string"
- }
- }
- }
- },
- "running": {
- "description": "Running jobs",
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "jobid": {
- "description": "Job identifier",
- "type": "string"
- },
- "job": {
- "description": "Job uname",
- "type": "string"
- },
- "level": {
- "description": "Job level",
- "type": "string"
- },
- "type": {
- "description": "Job type",
- "type": "string"
- },
- "status": {
- "description": "Job status letter",
- "type": "string"
- },
- "status_desc": {
- "description": "Status description",
- "type": "string"
- },
- "jobbytes": {
- "description": "jobbytes",
- "type": "string"
- },
- "jobfiles": {
- "description": "Job files",
- "type": "string"
- },
- "starttime_epoch": {
- "description": "Start time epoch",
- "type": "string"
- },
- "starttime": {
- "description": "Start time",
- "type": "string"
- },
- "errors": {
- "description": "Errors",
- "type": "string"
- },
- "newbsr": {
- "description": "New BSR",
- "type": "string"
- },
- "read_volume": {
- "description": "Read volume",
- "type": "string"
- },
- "read_pool": {
- "description": "Read pool",
- "type": "string"
- },
- "read_device": {
- "description": "Read device",
- "type": "string"
- },
- "write_volume": {
- "description": "Write volume",
- "type": "string"
- },
- "write_pool": {
- "description": "Write pool",
- "type": "string"
- },
- "write_device": {
- "description": "Write device",
- "type": "string"
- },
- "spooling": {
- "description": "Spooling",
- "type": "string"
- },
- "despooling": {
- "description": "Despooling",
- "type": "string"
- },
- "despool_wait": {
- "description": "Despool wait",
- "type": "string"
- },
- "avebytes_sec": {
- "description": "Averate bytes/second",
- "type": "string"
- },
- "lastbytes_sec": {
- "description": "Last bytes/second",
- "type": "string"
- }
- }
- }
- },
- "terminated": {
- "description": "Terminated jobs",
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "jobid": {
- "description": "Job identifier",
- "type": "string"
- },
- "level": {
- "description": "Job level",
- "type": "string"
- },
- "type": {
- "description": "Job type",
- "type": "string"
- },
- "status": {
- "description": "Job status letter",
- "type": "string"
- },
- "status_desc": {
- "description": "Status description",
- "type": "string"
- },
- "jobbytes": {
- "description": "jobbytes",
- "type": "string"
- },
- "jobfiles": {
- "description": "Job files",
- "type": "string"
- },
- "job": {
- "description": "Job uname",
- "type": "string"
- },
- "name": {
- "description": "Job name",
- "type": "string"
- },
- "starttime_epoch": {
- "description": "Start time epoch",
- "type": "string"
- },
- "starttime": {
- "description": "Start time",
- "type": "string"
- },
- "endtime_epoch": {
- "description": "End time epoch",
- "type": "string"
- },
- "endtime": {
- "description": "End time",
- "type": "string"
- },
- "errors": {
- "description": "Errors",
- "type": "string"
- }
- }
- }
- }
- }
- },
- "error": {
- "type": "integer",
- "description": "Error code",
- "enum": [0, 1, 2, 3, 4, 5, 6, 7, 11, 1000]
- }
- }
- }
- }
- }
- }
- },
- "parameters": [
- {
- "name": "name",
- "in": "query",
- "description": "Storage name to get status",
+ "name": "director_name",
+ "in": "path",
+ "description": "Director name",
+ "required": true,
"schema": {
"type": "string"
}
},
{
- "name": "type",
- "in": "query",
- "description": "Output type (header, devices, running, terminated)",
- "schema": {
- "type": "string"
- }
- }
- ]
- }
- },
- "/api/v1/status/client": {
- "get": {
- "tags": ["status"],
- "summary": "Get client status",
- "description": "Get client status",
- "responses": {
- "200": {
- "description": "Client status output",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "output": {
- "description": "Client status output",
- "type": "object",
- "properties": {
- "header": {
- "description": "Status header",
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "name": {
- "description": "Client name",
- "type": "string"
- },
- "version": {
- "description": "Client version",
- "type": "string"
- },
- "uname": {
- "description": "Client uname",
- "type": "string"
- },
- "started_epoch": {
- "description": "Started epoch",
- "type": "string"
- },
- "started": {
- "description": "Started time",
- "type": "string"
- },
- "jobs_run": {
- "description": "Jobs run",
- "type": "string"
- },
- "jobs_running": {
- "description": "Jobs running",
- "type": "string"
- },
- "winver": {
- "description": "Winver",
- "type": "string"
- },
- "debug": {
- "description": "Debug state",
- "type": "string"
- },
- "trace": {
- "description": "Trace state",
- "type": "string"
- },
- "bwlimit": {
- "description": "Bandwidth limit",
- "type": "string"
- },
- "plugins": {
- "description": "Plugins",
- "type": "string"
- }
- }
- }
- },
- "running": {
- "description": "Running jobs",
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "jobid": {
- "description": "Job identifier",
- "type": "string"
- },
- "job": {
- "description": "Job uname",
- "type": "string"
- },
- "vss": {
- "description": "VSS state",
- "type": "string"
- },
- "level": {
- "description": "Job level",
- "type": "string"
- },
- "type": {
- "description": "Job type",
- "type": "string"
- },
- "status": {
- "description": "Job status letter",
- "type": "string"
- },
- "jobbytes": {
- "description": "jobbytes",
- "type": "string"
- },
- "jobfiles": {
- "description": "Job files",
- "type": "string"
- },
- "starttime_epoch": {
- "description": "Start time epoch",
- "type": "string"
- },
- "starttime": {
- "description": "Start time",
- "type": "string"
- },
- "errors": {
- "description": "Errors",
- "type": "string"
- },
- "bytes_sec": {
- "description": "Averate bytes/second",
- "type": "string"
- },
- "readbytes": {
- "description": "Bytes read",
- "type": "string"
- },
- "files_examined": {
- "description": "Examined files count",
- "type": "string"
- },
- "processing_file": {
- "description": "Processing file",
- "type": "string"
- },
- "sdreadseqno": {
- "description": "SD read seq number",
- "type": "string"
- },
- "fd": {
- "description": "FD",
- "type": "string"
- },
- "bwlimit": {
- "description": "Bandwidth limit",
- "type": "string"
- },
- "sdtls": {
- "description": "SD Tls option",
- "type": "string"
- }
- }
- }
- },
- "terminated": {
- "description": "Terminated jobs",
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "jobid": {
- "description": "Job identifier",
- "type": "string"
- },
- "level": {
- "description": "Job level",
- "type": "string"
- },
- "type": {
- "description": "Job type",
- "type": "string"
- },
- "status": {
- "description": "Job status letter",
- "type": "string"
- },
- "status_desc": {
- "description": "Status description",
- "type": "string"
- },
- "jobbytes": {
- "description": "Job bytes",
- "type": "string"
- },
- "jobfiles": {
- "description": "Job files",
- "type": "string"
- },
- "job": {
- "description": "Job uname",
- "type": "string"
- },
- "name": {
- "description": "Job name",
- "type": "string"
- },
- "starttime_epoch": {
- "description": "Start time epoch",
- "type": "string"
- },
- "starttime": {
- "description": "Start time",
- "type": "string"
- },
- "endtime_epoch": {
- "description": "End time epoch",
- "type": "string"
- },
- "endtime": {
- "description": "End time",
- "type": "string"
- },
- "errors": {
- "description": "Errors",
- "type": "string"
- }
- }
- }
- }
- }
- },
- "error": {
- "type": "integer",
- "description": "Error code",
- "enum": [0, 1, 2, 3, 4, 5, 6, 7, 11, 1000]
- }
- }
- }
- }
- }
- }
- },
- "parameters": [
- {
- "name": "name",
- "in": "query",
- "description": "Client name to get status",
- "schema": {
- "type": "string"
- }
+ "$ref": "#/components/parameters/Output"
},
{
"name": "type",
"in": "query",
- "description": "Output type (header, running, terminated)",
+ "description": "Output type using together with output=json parameter.",
"schema": {
- "type": "string"
+ "type": "string",
+ "enum": ["header", "scheduled", "running", "terminated"]
}
}
]
}
},
- "/api/v1/oauth2/clients": {
+ "/api/v2/oauth2/clients": {
"get": {
"tags": ["oauth2"],
"summary": "OAuth2 client account list",
}
}
},
- "/api/v1/oauth2/clients/{client_id}": {
+ "/api/v2/oauth2/clients/{client_id}": {
"get": {
"tags": ["oauth2"],
"summary": "Specific OAuth2 client account config",
"tags": ["oauth2"],
"summary": "Set OAuth2 client settings",
"description": "Set specific OAuth2 client settings",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"responses": {
"200": {
"description": "Set OAuth2 client settings",
"tags": ["oauth2"],
"summary": "Create OAuth2 client settings",
"description": "Create specific OAuth2 client settings",
- "consumes": [ "application/x-www-form-urlencoded" ],
+ "consumes": [ "application/json" ],
"responses": {
"200": {
"description": "Create OAuth2 client settings",
* Bacula(R) - The Network Backup Solution
* Baculum - Bacula web interface
*
- * Copyright (C) 2013-2019 Kern Sibbald
+ * Copyright (C) 2013-2021 Kern Sibbald
*
* The main author of Baculum is Marcin Haba.
* The original author of Bacula is Kern Sibbald, with contributions
*/
class AuthBasic extends AuthBase implements AuthModule {
+ /**
+ * Generic name (used e.g. in config files).
+ */
+ const NAME = 'basic';
+
/**
* Request header value pattern.
*/
* Bacula(R) - The Network Backup Solution
* Baculum - Bacula web interface
*
- * Copyright (C) 2013-2019 Kern Sibbald
+ * Copyright (C) 2013-2021 Kern Sibbald
*
* The main author of Baculum is Marcin Haba.
* The original author of Bacula is Kern Sibbald, with contributions
*/
class AuthOAuth2 extends AuthBase implements AuthModule {
+ /**
+ * Generic name (used e.g. in config files).
+ */
+ const NAME = 'oauth2';
+
/**
* Get auth type.
*
* Bacula(R) - The Network Backup Solution
* Baculum - Bacula web interface
*
- * Copyright (C) 2013-2020 Kern Sibbald
+ * Copyright (C) 2013-2021 Kern Sibbald
*
* The main author of Baculum is Marcin Haba.
* The original author of Bacula is Kern Sibbald, with contributions
*/
class BClientScript extends TClientScript {
- const SCRIPTS_VERSION = 16;
+ const SCRIPTS_VERSION = 17;
public function getScriptUrl()
{
* Bacula(R) - The Network Backup Solution
* Baculum - Bacula web interface
*
- * Copyright (C) 2013-2020 Kern Sibbald
+ * Copyright (C) 2013-2021 Kern Sibbald
*
* The main author of Baculum is Marcin Haba.
* The original author of Bacula is Kern Sibbald, with contributions
}
private function getRequestedUrl() {
- $url = $this->getRequest()->getPathInfo();
- return $url;
+ return $this->getRequest()->getPathInfo();
}
}
?>
--- /dev/null
+var Cookies = {
+ default_exipration_time: 31536000000, // 1 year in miliseconds
+ set_cookie: function(name, value, expiration) {
+ var date = new Date();
+ date.setTime(date.getTime() + this.default_exipration_time);
+ var expires = 'expires=' + date.toUTCString();
+ document.cookie = name + '=' + value + '; ' + expires;
+ },
+ get_cookie: function(name) {
+ name += '=';
+ var values = document.cookie.split(';');
+ var cookie_val = null;
+ var value;
+ for (var i = 0; i < values.length; i++) {
+ value = values[i];
+ while (value.charAt(0) == ' ') {
+ value = value.substr(1);
+ }
+ if (value.indexOf(name) == 0) {
+ cookie_val = value.substring(name.length, value.length);
+ break;
+ }
+ }
+ return cookie_val;
+ }
+}
+
+var W3TabsCommon = {
+ open: function(btn_id, item_id) {
+ var tab_items = document.getElementsByClassName(this.css.tab_item);
+ for (var i = 0; i < tab_items.length; i++) {
+ if (tab_items[i].id === item_id) {
+ tab_items[i].style.display = 'block';
+ } else {
+ tab_items[i].style.display = 'none';
+ }
+ }
+ var tab_btns = document.getElementsByClassName(this.css.tab_btn);
+ for (var i = 0; i < tab_btns.length; i++) {
+ if (tab_btns[i].id === btn_id && !tab_btns[i].classList.contains(this.css.tab_item_hover)) {
+ tab_btns[i].classList.add(this.css.tab_item_hover);
+ } else if (tab_btns[i].id !== btn_id && tab_btns[i].classList.contains(this.css.tab_item_hover)) {
+ tab_btns[i].classList.remove(this.css.tab_item_hover);
+ }
+ }
+ },
+ is_open: function(item_id) {
+ var display = document.getElementById(item_id).style.display;
+ return (display === 'block' || display === '');
+ }
+};
+
+var W3Tabs = {
+ css: {
+ tab_btn: 'tab_btn',
+ tab_item: 'tab_item',
+ tab_item_hover: 'w3-grey'
+ },
+ open: function(btn_id, item_id) {
+ W3TabsCommon.open.call(this, btn_id, item_id);
+ },
+ is_open: function(item_id) {
+ return W3TabsCommon.is_open(item_id);
+ }
+};
+
+var W3SubTabs = {
+ css: {
+ tab_btn: 'subtab_btn',
+ tab_item: 'subtab_item',
+ tab_item_hover: 'w3-border-red'
+ },
+ open: function(btn_id, item_id) {
+ W3TabsCommon.open.call(this, btn_id, item_id);
+ }
+};
+
+var W3SideBar = {
+ ids: {
+ sidebar: 'sidebar',
+ overlay_bg: 'overlay_bg'
+ },
+ css: {
+ page_main: '.page_main_el'
+ },
+ cookies: {
+ side_bar_hide: 'baculum_side_bar_hide'
+ },
+ init: function() {
+ this.sidebar = document.getElementById(this.ids.sidebar);
+ if (!this.sidebar) {
+ // don't initialize for pages without sidebar
+ return;
+ }
+ this.overlay_bg = document.getElementById(this.ids.overlay_bg);
+ this.page_main = $(this.css.page_main);
+ var hide = Cookies.get_cookie(this.cookies.side_bar_hide);
+ if (hide == 1) {
+ this.close();
+ }
+ if (!this.sidebar) {
+ // on pages without sidebar always show page main elements with 100% width.
+ this.page_main.css({'margin-left': '0', 'width': '100%'});
+ }
+ this.set_events();
+ },
+ set_events: function() {
+ if (this.sidebar) {
+ this.sidebar.addEventListener('touchstart', handle_touch_start);
+ this.sidebar.addEventListener('touchmove', function(e) {
+ handle_touch_move(e, {
+ 'swipe_left': function() {
+ this.close();
+ }.bind(this)
+ });
+ }.bind(this));
+ }
+ },
+ open: function() {
+ if (this.sidebar.style.display === 'block' || this.sidebar.style.display === '') {
+ this.close();
+ } else {
+ Cookies.set_cookie('baculum_side_bar_hide', 0);
+ this.sidebar.style.display = 'block';
+ this.overlay_bg.style.display = 'block';
+ this.page_main.css({'margin-left': '250px', 'width': 'calc(100% - 250px)'});
+ }
+ },
+ close: function() {
+ Cookies.set_cookie('baculum_side_bar_hide', 1);
+ this.sidebar.style.display = 'none';
+ this.overlay_bg.style.display = 'none';
+ this.page_main.css({'margin-left': '0', 'width': '100%'});
+ }
+};
+
+var touch_start_x = null;
+var touch_start_y = null;
+
+function handle_touch_start(e) {
+ // browser API or jQuery
+ var first_touch = e.touches || e.originalEvent.touches
+ touch_start_x = first_touch[0].clientX;
+ touch_start_y = first_touch[0].clientY;
+}
+
+function handle_touch_move(e, callbacks) {
+ if (!touch_start_x || !touch_start_y || typeof(callbacks) !== 'object') {
+ // no touch type event or no callbacks
+ return;
+ }
+
+ var touch_end_x = e.touches[0].clientX;
+ var touch_end_y = e.touches[0].clientY;
+
+ var touch_diff_x = touch_start_x - touch_end_x;
+ var touch_diff_y = touch_start_y - touch_end_y;
+
+ if (Math.abs(touch_diff_x) > Math.abs(touch_diff_y)) {
+ if (touch_diff_x > 0 && callbacks.hasOwnProperty('swipe_left')) {
+ // left swipe
+ callbacks.swipe_left();
+ } else if (callbacks.hasOwnProperty('swipe_right')) {
+ // right swipe
+ callbacks.swipe_right();
+ }
+ } else {
+ if (touch_diff_y > 0 && callbacks.hasOwnProperty('swipe_up')) {
+ // up swipe
+ callbacks.swipe_up()
+ } else if (callbacks.hasOwnProperty('swipe_down')) {
+ // down swipe
+ callbacks.swipe_down()
+ }
+ }
+
+ // reset values
+ touch_start_x = null;
+ touch_start_y = null;
+}
+
+function set_global_listeners() {
+ document.addEventListener('keydown', function(e) {
+ var key_code = e.keyCode || e.which;
+ switch (key_code) {
+ case 27: { // escape
+ $('.w3-modal').filter(':visible').hide(); // hide modals
+ break;
+ }
+ }
+ });
+}
+
+
+var get_random_string = function(allowed, len) {
+ var random_string = '';
+ for(var i = 0; i < len; i++) {
+ random_string += allowed.charAt(Math.floor(Math.random() * allowed.length));
+ }
+ return random_string;
+}
+
+var OAuth2Scopes = [
+ 'console',
+ 'jobs',
+ 'directors',
+ 'clients',
+ 'storages',
+ 'volumes',
+ 'pools',
+ 'bvfs',
+ 'joblog',
+ 'filesets',
+ 'schedules',
+ 'config',
+ 'actions',
+ 'oauth2'
+];
+var set_scopes = function(field_id) {
+ document.getElementById(field_id).value = OAuth2Scopes.join(' ');
+}
+
+function copy_to_clipboard(text) {
+ var input = document.createElement('INPUT');
+ document.body.appendChild(input);
+ input.value = text;
+ input.focus();
+ input.setSelectionRange(0, text.length);
+ document.execCommand('copy');
+ document.body.removeChild(input);
+}
+
+$(function() {
+ W3SideBar.init();
+ set_global_listeners();
+});
* Bacula(R) - The Network Backup Solution
* Baculum - Bacula web interface
*
- * Copyright (C) 2013-2020 Kern Sibbald
+ * Copyright (C) 2013-2021 Kern Sibbald
*
* The main author of Baculum is Marcin Haba.
* The original author of Bacula is Kern Sibbald, with contributions
* Bacula(R) is a registered trademark of Kern Sibbald.
*/
+Prado::using('System.Web.UI.ActiveControls.TActiveHiddenField');
Prado::using('System.Web.UI.ActiveControls.TActiveLabel');
+Prado::using('System.Web.UI.ActiveControls.TActiveLinkButton');
Prado::using('System.Web.UI.ActiveControls.TActiveButton');
Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
Prado::using('System.Web.UI.TTemplateControl');
Prado::using('Application.Common.Class.OAuth2');
+Prado::using('Application.Common.Class.BasicUserConfig');
Prado::using('Application.Common.Portlets.PortletTemplate');
/**
private $show_buttons = true;
- private $auth_types = array('basic', 'oauth2');
+ private $auth_types = ['basic', 'oauth2'];
private $auth_type;
- public function addNewAuthClient($sender, $param) {
- $this->NewAuthClientAddOk->Display = 'None';
- $this->NewAuthClientAddError->Display = 'None';
- $this->NewAuthClientAddExists->Display = 'None';
+ private $modes = ['add', 'edit'];
+
+ // @TODO: Move it to a common class
+ const AUTH_TYPE_BASIC = 'basic';
+ const AUTH_TYPE_OAUTH2 = 'oauth2';
+
+ const MODE_TYPE_ADD = 'add';
+ const MODE_TYPE_EDIT = 'edit';
+
+ const MODE = 'Mode';
+
+ public function saveNewAuthClient($sender, $param) {
+ $this->NewAuthClientError->Display = 'None';
+ $this->NewAuthClientExists->Display = 'None';
$result = false;
$exists = false;
$config = $this->getModule('api_config')->getConfig();
- if ($this->getAuthType() === 'basic') {
- $users = $this->getModule('basic_apiuser')->getUsers();
- if (!key_exists($this->APIBasicLogin->Text, $users)) {
+ if ($this->getAuthType() === self::AUTH_TYPE_BASIC) {
+ if ($this->Mode == self::MODE_TYPE_ADD) {
+ $users = $this->getModule('basic_apiuser')->getUsers();
+ if (!key_exists($this->APIBasicLogin->Text, $users)) {
+ $result = $this->getModule('basic_apiuser')->setUsersConfig(
+ $this->APIBasicLogin->Text,
+ $this->APIBasicPassword->Text
+ );
+ } else {
+ $exists = true;
+ }
+ } elseif ($this->Mode === self::MODE_TYPE_EDIT) {
$result = $this->getModule('basic_apiuser')->setUsersConfig(
- $this->APIBasicLogin->Text,
+ $this->APIBasicLoginHidden->Value,
$this->APIBasicPassword->Text
);
- } else {
- $exists = true;
}
- } elseif ($this->getAuthType() === 'oauth2') {
+ } elseif ($this->getAuthType() === self::AUTH_TYPE_OAUTH2) {
$oauth2_cfg = $this->getModule('oauth2_config')->getConfig();
- if (!key_exists($this->APIOAuth2ClientId->Text, $oauth2_cfg)) {
- $oauth2_cfg[$this->APIOAuth2ClientId->Text] = array();
- $oauth2_cfg[$this->APIOAuth2ClientId->Text]['client_id'] = $this->APIOAuth2ClientId->Text;
- $oauth2_cfg[$this->APIOAuth2ClientId->Text]['client_secret'] = $this->APIOAuth2ClientSecret->Text;
- $oauth2_cfg[$this->APIOAuth2ClientId->Text]['redirect_uri'] = $this->APIOAuth2RedirectURI->Text;
- $oauth2_cfg[$this->APIOAuth2ClientId->Text]['scope'] = $this->APIOAuth2Scope->Text;
- $oauth2_cfg[$this->APIOAuth2ClientId->Text]['bconsole_cfg_path'] = $this->APIOAuth2BconsoleCfgPath->Text;
- $oauth2_cfg[$this->APIOAuth2ClientId->Text]['name'] = $this->APIOAuth2Name->Text;
+ if ($this->Mode == self::MODE_TYPE_ADD) {
+ if (!key_exists($this->APIOAuth2ClientId->Text, $oauth2_cfg)) {
+ $oauth2_cfg[$this->APIOAuth2ClientId->Text] = [
+ 'client_id' => $this->APIOAuth2ClientId->Text,
+ 'client_secret' => $this->APIOAuth2ClientSecret->Text,
+ 'redirect_uri' => $this->APIOAuth2RedirectURI->Text,
+ 'scope' => $this->APIOAuth2Scope->Text,
+ 'bconsole_cfg_path' => $this->APIOAuth2BconsoleCfgPath->Text,
+ 'name' => $this->APIOAuth2Name->Text
+ ];
+ $result = $this->getModule('oauth2_config')->setConfig($oauth2_cfg);
+ } else {
+ $exists = true;
+ }
+ } elseif ($this->Mode == self::MODE_TYPE_EDIT) {
+ $oauth2_cfg[$this->APIOAuth2ClientIdHidden->Value] = [
+ 'client_id' => $this->APIOAuth2ClientIdHidden->Value,
+ 'client_secret' => $this->APIOAuth2ClientSecret->Text,
+ 'redirect_uri' => $this->APIOAuth2RedirectURI->Text,
+ 'scope' => $this->APIOAuth2Scope->Text,
+ 'bconsole_cfg_path' => $this->APIOAuth2BconsoleCfgPath->Text,
+ 'name' => $this->APIOAuth2Name->Text
+ ];
$result = $this->getModule('oauth2_config')->setConfig($oauth2_cfg);
- } else {
- $exists = true;
}
}
- if ($exists === true) {
- $this->NewAuthClientAddExists->Display = 'Dynamic';
- } elseif ($result === true) {
- $this->NewAuthClientAddOk->Display = 'Dynamic';
- } else {
- $this->NewAuthClientAddError->Display = 'Dynamic';
+ $cb = true;
+ if ($exists) {
+ $this->NewAuthClientExists->Display = 'Dynamic';
+ $cb = false;
+ } elseif ($result !== true) {
+ $this->NewAuthClientError->Display = 'Dynamic';
+ $cb = false;
}
- $this->onCallback($param);
+ if ($cb) {
+ $this->onSuccess($param);
+ $this->clearForm();
+ }
+ }
+
+ public function cancelNewAuthClient($sender, $param) {
+ $this->onCancel($param);
+ }
+
+ public function clearForm() {
+ $this->APIBasicLogin->Text = '';
+ $this->APIBasicPassword->Text = '';
+ $this->RetypeAPIBasicPassword->Text = '';
+ $this->APIOAuth2ClientId->Text = '';
+ $this->APIOAuth2ClientSecret->Text = '';
+ $this->APIOAuth2RedirectURI->Text = '';
+ $this->APIOAuth2Scope->Text = '';
+ $this->APIOAuth2BconsoleCfgPath->Text = '';
+ $this->APIOAuth2Name->Text = '';
}
public function setShowButtons($show) {
return $this->auth_type;
}
- public function onCallback($param) {
- $this->raiseEvent('OnCallback', $this, $param);
+ public function setMode($mode) {
+ if (in_array($mode, $this->modes)) {
+ $this->setViewState(self::MODE, $mode);
+ }
+ }
+
+ public function getMode() {
+ return $this->getViewState(self::MODE, $this->modes[0]);
+ }
+
+ public function onSuccess($param) {
+ $this->raiseEvent('OnSuccess', $this, $param);
+ }
+
+ public function onCancel($param) {
+ $this->clearForm();
+ $this->raiseEvent('OnCancel', $this, $param);
}
public function bubbleEvent($sender, $param) {
-<div class="center">
- <com:TActiveLabel ID="NewAuthClientAddOk" Display="None" CssClass="validate" EnableViewState="false"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_ok.png" alt="Validate" /> <strong><%[ User added successfully. ]%></strong></com:TActiveLabel>
- <com:TActiveLabel ID="NewAuthClientAddError" Display="None" CssClass="validator" EnableViewState="false"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_err.png" alt="" /> <strong><%[ Problem during save to config file. Please check users config file permission. ]%></strong></com:TActiveLabel>
- <com:TActiveLabel ID="NewAuthClientAddExists" Display="None" CssClass="validator" EnableViewState="false"><img src="<%=$this->getPage()->getTheme()->getBaseUrl()%>/icon_err.png" alt="" /> <strong><%[ Given user already exists in config file. ]%></strong></com:TActiveLabel>
+<div class="w3-center">
+ <com:TActiveLabel ID="NewAuthClientError" Display="None" CssClass="w3-text-red" EnableViewState="false"><i class="fas fa-exclamation-circle"></i> <strong><%[ Problem during save to config file. Please check users config file permission. ]%></strong></com:TActiveLabel>
+ <com:TActiveLabel ID="NewAuthClientExists" Display="None" CssClass="w3-text-red" EnableViewState="false"><i class="fas fa-exclamation-circle"></i> <strong><%[ Given user already exists in config file. ]%></strong></com:TActiveLabel>
</div>
<com:TPanel ID="AuthPanel" DefaultButton="NewAuthClient">
-<div id="<%=$this->ClientID%>new_auth_client" style="display: none">
- <div style="display: <%=($this->getAuthType() == 'basic' ? '' : 'none')%>">
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIBasicLogin" Text="<%[ API Login: ]%>" /></div>
- <div class="field">
+<div class="w3-container">
+ <div class="w3-padding" style="display: <%=($this->getAuthType() == 'basic' ? '' : 'none')%>">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter"><com:TLabel ForControl="APIBasicLogin" Text="<%[ API Login: ]%>" /></div>
+ <div class="w3-col w3-threequarter">
<com:TActiveTextBox
ID="APIBasicLogin"
- CssClass="textbox"
+ CssClass="w3-input w3-border"
CausesValidation="false"
+ ReadOnly="<%=$this->Mode == 'edit'%>"
+ Style="width: 70%"
+ />
+ <com:TActiveHiddenField
+ ID="APIBasicLoginHidden"
/>
<com:TRequiredFieldValidator
- CssClass="validator-block"
Display="Dynamic"
- ControlCssClass="invalidate"
ControlToValidate="APIBasicLogin"
ValidationGroup="<%=$this->ClientID%>Basic"
Text="<%[ Please enter API login. ]%>"
/>
+ <com:TRegularExpressionValidator
+ ValidationGroup="<%=$this->ClientID%>Basic"
+ ControlToValidate="APIBasicLogin"
+ RegularExpression="<%=BasicUserConfig::USER_PATTERN%>"
+ ErrorMessage="<%[ Invalid user. User may contain a-z A-Z 0-9 characters. ]%>"
+ Display="Dynamic"
+ />
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIBasicPassword" Text="<%[ API Password: ]%>" /></div>
- <div class="field">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter"><com:TLabel ForControl="APIBasicPassword" Text="<%[ API Password: ]%>" /></div>
+ <div class="w3-col w3-threequarter">
<com:TActiveTextBox
ID="APIBasicPassword"
TextMode="Password"
MaxLength="60"
- CssClass="textbox"
+ CssClass="w3-input w3-border"
+ Style="width: 70%"
CausesValidation="false"
PersistPassword="true"
/>
/>
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="RetypeAPIBasicPassword" Text="<%[ Retype password: ]%>" /></div>
- <div class="field">
- <com:TTextBox
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-quarter"><com:TLabel ForControl="RetypeAPIBasicPassword" Text="<%[ Retype password: ]%>" /></div>
+ <div class="w3-col w3-threequarter">
+ <com:TActiveTextBox
ID="RetypeAPIBasicPassword"
- CssClass="textbox"
+ CssClass="w3-input w3-border"
+ Style="width: 70%"
TextMode="Password"
MaxLength="60"
PersistPassword="true"
</div>
</div>
<div style="display: <%=($this->getAuthType() == 'oauth2' ? '' : 'none')%>">
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIOAuth2ClientId" Text="<%[ OAuth2 Client ID: ]%>" /></div>
- <div class="field">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="APIOAuth2ClientId" Text="<%[ OAuth2 Client ID: ]%>" /></div>
+ <div class="w3-col w3-twothird">
<com:TTextBox
ID="APIOAuth2ClientId"
- CssClass="textbox"
+ CssClass="w3-input w3-border"
+ Style="width: 70%"
CausesValidation="false"
+ ReadOnly="<%=$this->Mode == 'edit'%>"
MaxLength="32"
/>
+ <com:TActiveHiddenField
+ ID="APIOAuth2ClientIdHidden"
+ />
<com:TRequiredFieldValidator
CssClass="validator-block"
Display="Dynamic"
ValidationGroup="<%=$this->ClientID%>OAuth2"
Text="<%[ Invalid Client ID value. Client ID may contain a-z A-Z 0-9 - _ characters. ]%>"
/>
- <a href="javascript:void(0)" onclick="document.getElementById('<%=$this->APIOAuth2ClientId->ClientID%>').value = get_random_string('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', 32); return false;"><%[ generate ]%></a>
+ <a href="javascript:void(0)" onclick="document.getElementById('<%=$this->APIOAuth2ClientId->ClientID%>').value = get_random_string('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', 32); return false;" style="display: <%=$this->Mode == 'edit' ? 'none': 'inline'%>"><%[ generate ]%></a>
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIOAuth2ClientSecret" Text="<%[ OAuth2 Client Secret: ]%>" /></div>
- <div class="field">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="APIOAuth2ClientSecret" Text="<%[ OAuth2 Client Secret: ]%>" /></div>
+ <div class="w3-col w3-twothird">
<com:TTextBox
ID="APIOAuth2ClientSecret"
- CssClass="textbox"
+ CssClass="w3-input w3-border"
+ Style="width: 70%"
CausesValidation="false"
MaxLength="50"
/>
<a href="javascript:void(0)" onclick="document.getElementById('<%=$this->APIOAuth2ClientSecret->ClientID%>').value = get_random_string('ABCDEFabcdef0123456789', 40); return false;"><%[ generate ]%></a>
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIOAuth2RedirectURI" Text="<%[ OAuth2 Redirect URI (example: https://baculumgui:9095/web/redirect): ]%>" /></div>
- <div class="field">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="APIOAuth2RedirectURI" Text="<%[ OAuth2 Redirect URI (example: https://baculumgui:9095/web/redirect): ]%>" /></div>
+ <div class="w3-col w3-twothird">
<com:TTextBox
ID="APIOAuth2RedirectURI"
- CssClass="textbox"
+ CssClass="w3-input w3-border"
+ Style="width: 70%"
CausesValidation="false"
/>
<com:TRequiredFieldValidator
/>
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIOAuth2Scope" Text="<%[ OAuth2 scopes (space separated): ]%>" /></div>
- <div class="field">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="APIOAuth2Scope" Text="<%[ OAuth2 scopes (space separated): ]%>" /></div>
+ <div class="w3-col w3-twothird">
<com:TTextBox
ID="APIOAuth2Scope"
- CssClass="textbox"
+ CssClass="w3-input w3-border"
+ Style="width: 70%"
CausesValidation="false"
TextMode="MultiLine"
/>
/>
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIOAuth2BconsoleCfgPath" Text="<%[ Dedicated Bconsole config file path: ]%>" /></div>
- <div class="field">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="APIOAuth2BconsoleCfgPath" Text="<%[ Dedicated Bconsole config file path: ]%>" /></div>
+ <div class="w3-col w3-twothird">
<com:TTextBox
ID="APIOAuth2BconsoleCfgPath"
- CssClass="textbox"
+ CssClass="w3-input w3-border"
+ Style="width: 70%"
CausesValidation="false"
/> <%[ (optional) ]%>
</div>
</div>
- <div class="line">
- <div class="text"><com:TLabel ForControl="APIOAuth2Name" Text="<%[ Short name: ]%>" /></div>
- <div class="field">
+ <div class="w3-row w3-section">
+ <div class="w3-col w3-third"><com:TLabel ForControl="APIOAuth2Name" Text="<%[ Short name: ]%>" /></div>
+ <div class="w3-col w3-twothird">
<com:TTextBox
ID="APIOAuth2Name"
- CssClass="textbox"
+ CssClass="w3-input w3-border"
+ Style="width: 70%"
CausesValidation="false"
/> <%[ (optional) ]%>
</div>
</div>
</div>
- <div class="center" style="width: 550px;<%=($this->getShowButtons() ? '' : 'display: none;')%>">
- <com:BButton
- Text="<%[ Cancel ]%>"
- CausesValidation="false"
- Attributes.onclick="$('#<%=$this->ClientID%>new_auth_client').slideUp(); return false;"
- />
- <com:BActiveButton
+ <div class="w3-center w3-section" style="<%=($this->getShowButtons() ? '' : 'display: none;')%>">
+ <com:TActiveLinkButton
+ CssClass="w3-button w3-red"
+ OnCallback="TemplateControl.cancelNewAuthClient"
+ >
+ <i class="fas fa-times"></i> <%[ Cancel ]%>
+ </com:TActiveLinkButton>
+ <com:TActiveLinkButton
ID="NewAuthClient"
ValidationGroup="<%=$this->ClientID%>NewAuthClientGroup"
- OnCommand="TemplateControl.addNewAuthClient"
- Text="<%[ Add ]%>"
- Attributes.onclick="return <%=$this->ClientID%>fields_validation()"
+ OnCommand="TemplateControl.saveNewAuthClient"
+ Attributes.onclick="return <%=$this->ClientID%>oNewAuthClient.fields_validation()"
+ CssClass="w3-button w3-green"
>
<prop:ClientSide.OnPreDispatch>
- $('#<%=$this->NewAuthClientAddOk->ClientID%>').hide();
- $('#<%=$this->NewAuthClientAddError->ClientID%>').hide();
- $('#<%=$this->NewAuthClientAddExists->ClientID%>').hide();
+ $('#<%=$this->NewAuthClientError->ClientID%>').hide();
+ $('#<%=$this->NewAuthClientExists->ClientID%>').hide();
</prop:ClientSide.OnPreDispatch>
<prop:ClientSide.OnComplete>
- var msg_ok = $('#<%=$this->NewAuthClientAddOk->ClientID%>');
- if (msg_ok.is(':visible')) {
- $('#<%=$this->ClientID%>new_auth_client').slideUp();
- setTimeout(function() {
- $('#<%=$this->NewAuthClientAddOk->ClientID%>').slideUp();
- }, 5000);
- }
+ $('#<%=$this->ClientID%>new_auth_client').hide();
</prop:ClientSide.OnComplete>
- </com:BActiveButton>
+ <i class="fas fa-save"></i> <%[ Save ]%>
+ </com:TActiveLinkButton>
</div>
</div>
</com:TPanel>
<script type="text/javascript">
- var <%=$this->ClientID%>fields_validation = function() {
- var basic = <%=($this->getAuthType() === 'basic' ? 1 : 0)%>;
- var oauth2 = <%=($this->getAuthType() === 'oauth2' ? 1 : 0)%>;
+var <%=$this->ClientID%>oNewAuthClient = {
+ mode: '<%=$this->Mode%>',
+ ids: {
+ basic: {
+ username: '<%=$this->APIBasicLogin->ClientID%>',
+ username_hidden: '<%=$this->APIBasicLoginHidden->ClientID%>',
+ password: '<%=$this->APIBasicPassword->ClientID%>',
+ password_retype: '<%=$this->RetypeAPIBasicPassword->ClientID%>'
+ },
+ oauth2: {
+ client_id: '<%=$this->APIOAuth2ClientId->ClientID%>',
+ client_id_hidden: '<%=$this->APIOAuth2ClientIdHidden->ClientID%>',
+ client_secret: '<%=$this->APIOAuth2ClientSecret->ClientID%>',
+ redirect_uri: '<%=$this->APIOAuth2RedirectURI->ClientID%>',
+ scope: '<%=$this->APIOAuth2Scope->ClientID%>',
+ bconsole_cfg_path: '<%=$this->APIOAuth2BconsoleCfgPath->ClientID%>',
+ name: '<%=$this->APIOAuth2Name->ClientID%>'
+ },
+ errors: {
+ generic: '<%=$this->NewAuthClientError->ClientID%>',
+ exists: '<%=$this->NewAuthClientExists->ClientID%>'
+ }
+ },
+ set_basic_props: function(props) {
+ if (!props || typeof(props) != 'object') {
+ return false;
+ }
+ if (props.hasOwnProperty('username')) {
+ document.getElementById(this.ids.basic.username).value = props.username;
+ document.getElementById(this.ids.basic.username_hidden).value = props.username;
+ }
+ },
+ set_oauth2_props: function(props) {
+ if (!props || typeof(props) != 'object') {
+ return false;
+ }
+ if (props.hasOwnProperty('client_id')) {
+ document.getElementById(this.ids.oauth2.client_id).value = props.client_id;
+ document.getElementById(this.ids.oauth2.client_id_hidden).value = props.client_id;
+ }
+ if (props.hasOwnProperty('client_secret')) {
+ document.getElementById(this.ids.oauth2.client_secret).value = props.client_secret;
+ }
+ if (props.hasOwnProperty('redirect_uri')) {
+ document.getElementById(this.ids.oauth2.redirect_uri).value = props.redirect_uri;
+ }
+ if (props.hasOwnProperty('scope')) {
+ document.getElementById(this.ids.oauth2.scope).value = props.scope;
+ }
+ if (props.hasOwnProperty('bconsole_cfg_path')) {
+ document.getElementById(this.ids.oauth2.bconsole_cfg_path).value = props.bconsole_cfg_path;
+ }
+ if (props.hasOwnProperty('name')) {
+ document.getElementById(this.ids.oauth2.name).value = props.name;
+ }
+ },
+ clear_basic_fields: function() {
+ document.getElementById(this.ids.basic.username).value = '';
+ document.getElementById(this.ids.basic.username_hidden).value = '';
+ document.getElementById(this.ids.basic.password).value = '';
+ document.getElementById(this.ids.basic.password_retype).value = '';
+ },
+ clear_oauth2_fields: function() {
+ document.getElementById(this.ids.oauth2.client_id).value = '';
+ document.getElementById(this.ids.oauth2.client_id_hidden).value = '';
+ document.getElementById(this.ids.oauth2.client_secret).value = '';
+ document.getElementById(this.ids.oauth2.redirect_uri).value = '';
+ document.getElementById(this.ids.oauth2.scope).value = '';
+ document.getElementById(this.ids.oauth2.bconsole_cfg_path).value = '';
+ document.getElementById(this.ids.oauth2.name).value = '';
+ },
+ hide_errors: function() {
+ document.getElementById(this.ids.errors.generic).style.display = 'none';
+ document.getElementById(this.ids.errors.exists).style.display = 'none';
+ },
+ fields_validation: function() {
+ var basic = <%=($this->getAuthType() === NewAuthClient::AUTH_TYPE_BASIC ? 1 : 0)%>;
+ var oauth2 = <%=($this->getAuthType() === NewAuthClient::AUTH_TYPE_OAUTH2 ? 1 : 0)%>;
var validation_group;
if (basic) {
validation_group = '<%=$this->ClientID%>Basic';
}
return Prado.Validation.validate(Prado.Validation.getForm(), validation_group);
}
+};
</script>
* Bacula(R) - The Network Backup Solution
* Baculum - Bacula web interface
*
- * Copyright (C) 2013-2020 Kern Sibbald
+ * Copyright (C) 2013-2021 Kern Sibbald
*
* The main author of Baculum is Marcin Haba.
* The original author of Bacula is Kern Sibbald, with contributions
/**
* API version used by Web
*/
- const API_VERSION = 'v1';
+ const API_VERSION = 'v2';
/**
* OAuth2 authorization endpoints
$host_cfg = $this->getHostParams($host);
$uri = $this->getURIResource($host, $params);
$ch = $this->getConnection($host_cfg);
- $data = http_build_query(array('update' => $options));
+ $data = json_encode($options);
curl_setopt($ch, CURLOPT_URL, $uri);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge(
$host_cfg = $this->getHostParams($host);
$uri = $this->getURIResource($host, $params);
$ch = $this->getConnection($host_cfg);
- $data = http_build_query(array('create' => $options));
+ $data = json_encode($options);
curl_setopt($ch, CURLOPT_URL, $uri);
curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge($this->getAPIHeaders($host, $host_cfg), array('Expect:')));
curl_setopt($ch, CURLOPT_POST, true);
Formatters.set_formatters();
}
-var Cookies = {
- default_exipration_time: 31536000000, // 1 year in miliseconds
- set_cookie: function(name, value, expiration) {
- var date = new Date();
- date.setTime(date.getTime() + this.default_exipration_time);
- var expires = 'expires=' + date.toUTCString();
- document.cookie = name + '=' + value + '; ' + expires;
- },
- get_cookie: function(name) {
- name += '=';
- var values = document.cookie.split(';');
- var cookie_val = null;
- var value;
- for (var i = 0; i < values.length; i++) {
- value = values[i];
- while (value.charAt(0) == ' ') {
- value = value.substr(1);
- }
- if (value.indexOf(name) == 0) {
- cookie_val = value.substring(name.length, value.length);
- break;
- }
- }
- return cookie_val;
- }
-}
-
var JobStatus = {
st: {
ok: ['T', 'D'],
}
};
-var W3SideBar = {
- ids: {
- sidebar: 'sidebar',
- overlay_bg: 'overlay_bg'
- },
- css: {
- page_main: '.page_main_el'
- },
- cookies: {
- side_bar_hide: 'baculum_side_bar_hide'
- },
- init: function() {
- this.sidebar = document.getElementById(this.ids.sidebar);
- if (!this.sidebar) {
- // don't initialize for pages without sidebar
- return;
- }
- this.overlay_bg = document.getElementById(this.ids.overlay_bg);
- this.page_main = $(this.css.page_main);
- var hide = Cookies.get_cookie(this.cookies.side_bar_hide);
- if (hide == 1) {
- this.close();
- }
- if (!this.sidebar) {
- // on pages without sidebar always show page main elements with 100% width.
- this.page_main.css({'margin-left': '0', 'width': '100%'});
- }
- this.set_events();
- },
- set_events: function() {
- if (this.sidebar) {
- this.sidebar.addEventListener('touchstart', handle_touch_start);
- this.sidebar.addEventListener('touchmove', function(e) {
- handle_touch_move(e, {
- 'swipe_left': function() {
- this.close();
- }.bind(this)
- });
- }.bind(this));
- }
- },
- open: function() {
- if (this.sidebar.style.display === 'block' || this.sidebar.style.display === '') {
- this.close();
- } else {
- Cookies.set_cookie('baculum_side_bar_hide', 0);
- this.sidebar.style.display = 'block';
- this.overlay_bg.style.display = 'block';
- this.page_main.css({'margin-left': '250px', 'width': 'calc(100% - 250px)'});
- }
- },
- close: function() {
- Cookies.set_cookie('baculum_side_bar_hide', 1);
- this.sidebar.style.display = 'none';
- this.overlay_bg.style.display = 'none';
- this.page_main.css({'margin-left': '0', 'width': '100%'});
- }
-};
-
-W3TabsCommon = {
- open: function(btn_id, item_id) {
- var tab_items = document.getElementsByClassName(this.css.tab_item);
- for (var i = 0; i < tab_items.length; i++) {
- if (tab_items[i].id === item_id) {
- tab_items[i].style.display = 'block';
- } else {
- tab_items[i].style.display = 'none';
- }
- }
- var tab_btns = document.getElementsByClassName(this.css.tab_btn);
- for (var i = 0; i < tab_btns.length; i++) {
- if (tab_btns[i].id === btn_id && !tab_btns[i].classList.contains(this.css.tab_item_hover)) {
- tab_btns[i].classList.add(this.css.tab_item_hover);
- } else if (tab_btns[i].id !== btn_id && tab_btns[i].classList.contains(this.css.tab_item_hover)) {
- tab_btns[i].classList.remove(this.css.tab_item_hover);
- }
- }
- },
- is_open: function(item_id) {
- var display = document.getElementById(item_id).style.display;
- return (display === 'block' || display === '');
- }
-};
-
-W3Tabs = {
- css: {
- tab_btn: 'tab_btn',
- tab_item: 'tab_item',
- tab_item_hover: 'w3-grey'
- },
- open: function(btn_id, item_id) {
- W3TabsCommon.open.call(this, btn_id, item_id);
- },
- is_open: function(item_id) {
- return W3TabsCommon.is_open(item_id);
- }
-};
-
-W3SubTabs = {
- css: {
- tab_btn: 'subtab_btn',
- tab_item: 'subtab_item',
- tab_item_hover: 'w3-border-red'
- },
- open: function(btn_id, item_id) {
- W3TabsCommon.open.call(this, btn_id, item_id);
- }
-};
-var OAuth2Scopes = [
- 'console',
- 'jobs',
- 'directors',
- 'clients',
- 'storages',
- 'volumes',
- 'pools',
- 'bvfs',
- 'joblog',
- 'filesets',
- 'schedules',
- 'config',
- 'status',
- 'actions',
- 'oauth2'
-];
-var set_scopes = function(field_id) {
- document.getElementById(field_id).value = OAuth2Scopes.join(' ');
-}
-
function estimate_job(jobs, job, level) {
var bytes = 0;
var files = 0;
$('#' + element).show();
}
-
-function get_random_string(allowed, len) {
- var random_string = "";
- for(var i = 0; i < len; i++) {
- random_string += allowed.charAt(Math.floor(Math.random() * allowed.length));
- }
- return random_string;
-}
-
function clear_node(selector) {
var node = $(selector);
for (var i = 0; i < node.length; i++) {
$('.w3-spin').removeClass('w3-spin').addClass('fa-spin');
}
-var touch_start_x = null;
-var touch_start_y = null;
-
-function handle_touch_start(e) {
- // browser API or jQuery
- var first_touch = e.touches || e.originalEvent.touches
- touch_start_x = first_touch[0].clientX;
- touch_start_y = first_touch[0].clientY;
-}
-
-function handle_touch_move(e, callbacks) {
- if (!touch_start_x || !touch_start_y || typeof(callbacks) !== 'object') {
- // no touch type event or no callbacks
- return;
- }
-
- var touch_end_x = e.touches[0].clientX;
- var touch_end_y = e.touches[0].clientY;
-
- var touch_diff_x = touch_start_x - touch_end_x;
- var touch_diff_y = touch_start_y - touch_end_y;
-
- if (Math.abs(touch_diff_x) > Math.abs(touch_diff_y)) {
- if (touch_diff_x > 0 && callbacks.hasOwnProperty('swipe_left')) {
- // left swipe
- callbacks.swipe_left();
- } else if (callbacks.hasOwnProperty('swipe_right')) {
- // right swipe
- callbacks.swipe_right();
- }
- } else {
- if (touch_diff_y > 0 && callbacks.hasOwnProperty('swipe_up')) {
- // up swipe
- callbacks.swipe_up()
- } else if (callbacks.hasOwnProperty('swipe_down')) {
- // down swipe
- callbacks.swipe_down()
- }
- }
-
- // reset values
- touch_start_x = null;
- touch_start_y = null;
-}
-
function sort_natural(a, b) {
a = a.toString();
b = b.toString();
return table_toolbar;
}
-function set_global_listeners() {
- document.addEventListener('keydown', function(e) {
- var key_code = e.keyCode || e.which;
- switch (key_code) {
- case 27: { // escape
- $('.w3-modal').filter(':visible').hide(); // hide modals
- break;
- }
- }
- });
-}
-
$(function() {
- W3SideBar.init();
set_sbbr_compatibility();
set_icon_css();
- set_global_listeners();
});
<body class="w3-light-grey">
<com:TForm>
<com:TClientScript PradoScripts="ajax, effects" />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/misc.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/fontawesome.min.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/datatables.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/dataTables.responsive.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/responsive.jqueryui.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/dataTables.buttons.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/buttons.html5.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/buttons.colVis.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/dataTables.select.js %> />
<com:BClientScript ScriptUrl=<%~ ../JavaScript/flotr2.js %> />
- <com:BClientScript ScriptUrl=<%~ ../JavaScript/fontawesome.min.js %> />
- <com:BClientScript ScriptUrl=<%~ ../JavaScript/datatables.js %> />
- <com:BClientScript ScriptUrl=<%~ ../JavaScript/dataTables.responsive.js %> />
- <com:BClientScript ScriptUrl=<%~ ../JavaScript/responsive.jqueryui.js %> />
- <com:BClientScript ScriptUrl=<%~ ../JavaScript/dataTables.buttons.js %> />
- <com:BClientScript ScriptUrl=<%~ ../JavaScript/buttons.html5.js %> />
- <com:BClientScript ScriptUrl=<%~ ../JavaScript/buttons.colVis.js %> />
- <com:BClientScript ScriptUrl=<%~ ../JavaScript/dataTables.select.js %> />
<com:BClientScript ScriptUrl=<%~ ../JavaScript/bacula-config.js %> />
<com:BClientScript ScriptUrl=<%~ ../JavaScript/misc.js %> />
<com:BClientScript ScriptUrl=<%~ ../JavaScript/graph.js %> />
<com:THead Title="Baculum - Bacula Web Interface" ShortcutIcon="<%=$this->getPage()->getTheme()->getBaseUrl()%>/favicon.ico" />
<body id="message-body">
<com:TForm>
- <com:BClientScript ScriptUrl=<%~ ../JavaScript/fontawesome.min.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/fontawesome.min.js %> />
<com:TContentPlaceHolder ID="Message" />
</com:TForm>
</body>
</com:THead>
<body class="w3-light-grey">
<com:TForm>
- <com:BClientScript ScriptUrl=<%~ ../JavaScript/fontawesome.min.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/fontawesome.min.js %> />
<!-- Top container -->
<div class="w3-bar w3-top w3-black w3-large" style="z-index:4">
<span class="w3-bar-item w3-right">
</script>
<com:TForm>
<com:TClientScript PradoScripts="ajax, effects" />
- <com:BClientScript ScriptUrl=<%~ ../JavaScript/fontawesome.min.js %> />
- <com:BClientScript ScriptUrl=<%~ ../JavaScript/datatables.js %> />
- <com:BClientScript ScriptUrl=<%~ ../JavaScript/dataTables.responsive.js %> />
- <com:BClientScript ScriptUrl=<%~ ../JavaScript/responsive.jqueryui.js %> />
- <com:BClientScript ScriptUrl=<%~ ../JavaScript/dataTables.buttons.js %> />
- <com:BClientScript ScriptUrl=<%~ ../JavaScript/buttons.html5.js %> />
- <com:BClientScript ScriptUrl=<%~ ../JavaScript/buttons.colVis.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/misc.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/fontawesome.min.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/datatables.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/dataTables.responsive.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/responsive.jqueryui.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/dataTables.buttons.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/buttons.html5.js %> />
+ <com:BClientScript ScriptUrl=<%~ ../../Common/JavaScript/buttons.colVis.js %> />
<com:BClientScript ScriptUrl=<%~ ../JavaScript/opentip.js %> />
<com:BClientScript ScriptUrl=<%~ ../JavaScript/tooltip.js %> />
<com:BClientScript ScriptUrl=<%~ ../JavaScript/misc.js %> />
* Bacula(R) - The Network Backup Solution
* Baculum - Bacula web interface
*
- * Copyright (C) 2013-2020 Kern Sibbald
+ * Copyright (C) 2013-2021 Kern Sibbald
*
* The main author of Baculum is Marcin Haba.
* The original author of Bacula is Kern Sibbald, with contributions
public function status($sender, $param) {
$raw_status = $this->getModule('api')->get(
- array('clients', $this->getClientId(), 'status')
+ ['clients', $this->getClientId(), 'status']
)->output;
$this->ClientLog->Text = implode(PHP_EOL, $raw_status);
- $query_str = '?name=' . rawurlencode($this->getClientName()) . '&type=header';
+ $query_str = '?output=json&type=header';
$graph_status = $this->getModule('api')->get(
- array('status', 'client', $query_str)
+ ['clients', $this->getClientId(), 'status', $query_str]
);
$client_status = array(
'header' => array(),
}
}
- $query_str = '?name=' . rawurlencode($this->getClientName()) . '&type=running';
+ $query_str = '?output=json&type=running';
$graph_status = $this->getModule('api')->get(
- array('status', 'client', $query_str)
+ ['clients', $this->getClientId(), 'status', $query_str]
);
if ($graph_status->error === 0) {
$client_status['running'] = $graph_status->output;
* Bacula(R) - The Network Backup Solution
* Baculum - Bacula web interface
*
- * Copyright (C) 2013-2020 Kern Sibbald
+ * Copyright (C) 2013-2021 Kern Sibbald
*
* The main author of Baculum is Marcin Haba.
* The original author of Bacula is Kern Sibbald, with contributions
)->output;
$this->StorageLog->Text = implode(PHP_EOL, $raw_status);
- $query_str = '?name=' . rawurlencode($this->getStorageName()) . '&type=header';
+ $query_str = '?output=json&type=header';
$graph_status = $this->getModule('api')->get(
- ['status', 'storage', $query_str]
+ ['storages', $this->getStorageId(), 'status', $query_str]
);
$storage_status = [
'header' => [],
}
// running
- $query_str = '?name=' . rawurlencode($this->getStorageName()) . '&type=running';
+ $query_str = '?output=json&type=running';
$graph_status = $this->getModule('api')->get(
- array('status', 'storage', $query_str)
+ ['storages', $this->getStorageId(), 'status', $query_str]
);
if ($graph_status->error === 0) {
$storage_status['running'] = $graph_status->output;
}
// terminated
- $query_str = '?name=' . rawurlencode($this->getStorageName()) . '&type=terminated';
+ $query_str = '?output=json&type=terminated';
$graph_status = $this->getModule('api')->get(
- array('status', 'storage', $query_str)
+ ['storages', $this->getStorageId(), 'status', $query_str]
);
if ($graph_status->error === 0) {
$storage_status['terminated'] = $graph_status->output;
}
// devices
- $query_str = '?name=' . rawurlencode($this->getStorageName()) . '&type=devices';
+ $query_str = '?output=json&type=devices';
$graph_status = $this->getModule('api')->get(
- array('status', 'storage', $query_str)
+ ['storages', $this->getStorageId(), 'status', $query_str]
);
if ($graph_status->error === 0) {
$storage_status['devices'] = $graph_status->output;
+++ /dev/null
-body {
- background-color: #b5c9d3;
- background-image: url('../background.png');
- background-repeat: repeat-x;
- font-family: Arial, Helvetica, sans-serif;
- color: white;
-}
-
-body.api {
- background-image: none;
- background-color: #444445;
- color: white;
-}
-
-a {
- font-size: 12px;
- color: white;
- padding: 3px 4px;
- text-decoration: none;
-}
-
-a:hover {
- text-decoration: underline;
-}
-
-
-input.invalidate, select.invalidate {
- border: 1px solid red;
-}
-
-input[type=text], input[type=password], select, textarea {
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- padding: 5px;
-}
-
-input[type=checkbox] {
- height: 16px;
- width: 16px;
-}
-
-input.textbox, select.textbox, textarea.textbox {
- width: 300px;
- border: 1px solid black;
- font-size: 11pt !important;
- display: table-cell;
-}
-
-input.textbox-short, select.textbox-short {
- width: 80px;
- border: 1px solid black;
- font-size: 11pt;
- display: table-cell;
-}
-
-input.textbox-auto, select.textbox-auto, textarea.textbox-auto {
- border: 1px solid black;
- font-size: 14px;
- display: table-cell;
-}
-
-textarea.textbox-auto {
- resize: vertical;
- width: 100%;
- font-size: 11px;
-}
-
-input.bbutton {
- font-size: 12px !important;
- vertical-align: baseline;
- -webkit-appearance: none;
- text-shadow: 0 1px 1px #7b2121;
- font-family: "times, serif" !important;
- font-weight: 600;
- color: white;
- height: 28px;
- line-height: 26px;
- cursor: pointer;
- display: inline-block;
- width: auto;
- margin: 5px 8px;
- padding: 0 16px;
- min-width: 65px;
- border-radius: 4px;
- border: 1px solid #8f2626;
- background: #ca3838;
- background-image: linear-gradient(#df8989, #d03232);
-}
-
-input.bbutton:hover {
- padding: 0 16px;
- box-shadow: inset 0 0 3px #faeded;
- background: #ff7474;
- border: 1px solid #8f2626;
-}
-
-.center {
- text-align: center !important;
-}
-
-.left {
- text-align: left !important;
-}
-
-.right {
- text-align: right;
-}
-
-.api_button, .api_select {
- font-weight: bold;
- border: 1px solid #212121;
- border-radius: 4px;
- height: 37px;
- display: inline-block;
- vertical-align: super;
-}
-
-.api_button {
- color: #1a1b1d;
- background-color: #ffeb3b;
-}
-
-.api_button:hover {
- color: black;
- background-color: white;
- cursor: pointer;
- transition: all 0.3s linear;
-}
-
-.validator, .validate, .validator-block, .validator-info {
- color: #f58589 !important;
- font-size: 10pt;
- /*margin-left: 5px;*/
-}
-
-.validator-info {
- color: white !important;
-}
-
-.validator-block {
- display: block;
-}
-
-.block {
- display: block !important;
-}
-
-.validate {
- color: #96c600 !important;
-}
-
-.line {
- min-height: 35px;
- clear: both;
-}
-
-.text {
- width: 240px;
- display: table-cell;
- vertical-align: middle;
- font-size: 14px;
-}
-
-.field {
- display: table-cell;
-}
-
-.field-full {
- display: block;
- min-height: 200px;
- width: 98%;
-}
-
-.footer {
- font-size: 12px;
- text-align: right;
- margin-top: 5px;
-}
-
-/* API server OAuth2 progress bar */
-
-#progress_label {
- position: absolute;
- top: 114px;
- transform: translate(-50%, -50%);
- font-weight: bold;
-}
-
-#api_command {
- border-radius: 5px;
- height: 26px;
- width: 617px;
- font-size: 25px;
- color: #444444;
- padding: 9px 10px 2px 9px;
-}
-
-#api_output {
- margin-top: 20px;
- border-radius: 6px;
- border: 1px solid white;
- width: 75%;
-}
-
-#api_result {
- margin: 0 auto;
- white-space: pre-wrap;
- word-wrap: break-word;
- font-size: 13px;
-}
-
-.api_button, .api_select {
- font-weight: bold;
- border: 1px solid #212121;
- border-radius: 4px;
- height: 37px;
- display: inline-block;
- vertical-align: super;
-}
-
-.api_button {
- color: #1a1b1d;
- background-color: #ffeb3b;
-}
-
-.api_button:hover {
- color: black;
- background-color: white;
- cursor: pointer;
- transition: all 0.3s linear;
-}
-
-#api_refresh {
- margin-left: 10px;
- cursor: pointer;
-}
-
-/**
- * Override jQuery-UI theming.
- */
-
-.ui-widget-content td a, .ui-widget-content div a {
- color: white !important;
- text-decoration: underline !important;
-}
-
-.ui-dialog-content div a {
- color: black !important;
- text-decoration: underline !important;
-}
-
-.ui-tabs {
- font-size: 12px !important;
-}
-
-.ui-tabs .ui-tabs-panel {
- background-color: #444445 !important;
- color: white !important;
- font-size: 15px !important;
-}
-
-.tab-grid {
- border-spacing: 0 !important;
-}
-
-.tab-grid td {
- border-top: 1px solid white !important;
- padding: 8px !important;
-}
-
-.error {
- color: red;
-}
-
-fieldset {
- margin-bottom: 15px;
- font-size: 14px;
-}
-
-fieldset .line {
- min-height: initial;
- height: 25px;
-}
-
-fieldset .text {
- width: 250px;
-}
-
-legend {
- font-size: 12px;
- font-weight: bold;
- color: white;
-}
-
-img {
- vertical-align: middle;
- border: none;
-}
-
-h4 {
- margin: 6px 0;
-}
-
-.test_label {
- display: inline-block;
- height: 34px;
-}
-
-.config_lines {
- width: 590px;
- float: left;
-}
-.actions_lines {
- width: 743px;
-}
-
-.config_lines div.field {
- width: 280px !important;
-}
-
-.actions_lines div.field {
- width: 332px !important;
-}
-
-#config_fields, #actions_fields {
- width: 732px;
- margin: 0 auto;
- padding-top: 7px;
-}
-
-#actions_fields {
- width: 810px;
-}
-
-#actions_fields .button {
- display: inline-block;
- min-width: 50px;
-}
-
-#actions_fields .button input[type="submit"] {
- min-width: 60px;
-}
-
-#actions_fields .action_test_loader, #actions_fields .action_success, #actions_fields .action_error {
- margin-left: 11px;
-}
-
-#config_fields div.button {
- padding-left: 247px;
-}
-
-fieldset.config_field {
- width: 667px;
-}
-
-fieldset.actions_field {
- width: 745px;
-}
-
-fieldset.config_field .line, fieldset.actions_field .line {
- height: auto;
- min-height: 35px !important;
- padding-top: 2px;
- padding-bottom: 2px;
-}
-
-span.config_test_loader, span.config_test_result {
- line-height: 75px;
-}
+++ /dev/null
-.wizard {
- min-height: 547px;
- width: 1024px;
- margin: 50px auto;
- font-family: Arial;
- color: white;
- background-color: #585756;
- background-image: url('../step-head.png');
- background-repeat: repeat-x;
- border: 1px solid black;
- border-radius: 15px;
-}
-
-.steps {
- padding: 8px 20px;
- background-image: none;
- min-height: 520px;
-}
-
-.steps div.line {
- text-align: center;
-}
-
-.steps div.text, .steps div.field {
- display: inline-block;
- text-align: left;
-}
-
-.steps div.field {
- width: 420px;
-}
-
-.navigation {
- text-align: center;
- padding: 5px 0;
- background-image: url('../wizard-bottom-1.png');
- background-repeat: repeat-x;
- border-bottom-left-radius: 14px;
- border-bottom-right-radius: 14px;
- }
-
-.step {
- float: left;
- height: 45px;
- width: 124px;
- font-size: 15px;
- text-align: center;
- position: relative;
- }
-
-.step div {
- position: absolute;
- top: 50%;
- left: 45%;
- transform: translate(-50%, -50%);
- width: 115px;
- }
-
-.step-normal, .step-active, .step-prev-active, .step-first-active, .step-first-next-active {
- background-repeat: no-repeat;
- background-position: right center;
- }
-
- .step-first {
- width: 126px;
- background-image: url('../step-first.png');
- }
-
- .step-first-active {
- width: 126px;
- background-image: url('../step-first-active.png');
- }
-
- .step-first-next-active{
- width: 126px;
- background-image: url('../step-first-next-active.png');
- }
-
-.step-last {
- width: 130px;
- background-image: url('../step-last-1.png');
- }
-
- .step-last-active {
- width: 130px;
- background-image: url('../step-last-active-1.png');
- }
-
- .step-last-next-active{
- width: 130px;
- background-image: url('../step-last-next-active.png');
- }
-
-.step-normal, .step-prev-active {
- background-image: url('../step.png');
- }
-
-.step-active{
- background-image: url('../step-active.png');
- }
-
-.step-prev-active {
- background-image: url('../step-prev-active.png');
- }
-
-#title {
- clear: left;
- font-size: 14px;
- font-weight: bold;
- background-image: url('../wizard-header-1.png');
- background-repeat: repeat-x;
- padding: 4px;
-}
-
-div.button-cancel {
- float: right;
- margin-right: 28px
-}
-
-div.button-prev-next {
- margin-left: 84px
-}
-
-a.link {
- color: #3f4449;
- font-weight: bold;
- text-decoration: none;
-}
-
-a.link:hover {
- text-decoration: underline;
-}
width: 32px;
cursor: help;
}
+
+/* API server OAuth2 progress bar */
+
+#progress_label {
+ position: absolute;
+ width: 100%;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ font-weight: bold;
+}