From: Marcin Haba Date: Sat, 27 Feb 2021 21:55:53 +0000 (+0100) Subject: baculum: Implement API version 2 X-Git-Tag: Release-11.0.2~52 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=10479852a237539cdd2af7dec6de6ce7e97eb634;p=thirdparty%2Fbacula.git baculum: Implement API version 2 APIv2 changes: - Send request body parameters to the API in JSON format instead of POST form parameters. - Drop using the create[] and update[] surrounds in the POST and PUT request body parameters. - Move the /api/v1/status/{director|storage|client}/ endpoints to: = /api/v2/clients/{clientid}/status, = /api/v2/storages/{storageid}/status, = /api/v2/directors/{director_name}/status. - Stop using OAuth2 'status' scope. - API version 1 is still possible to use and it is preserved. Nothing changes here. - New and modern API admin panel. --- diff --git a/gui/baculum/LICENSE b/gui/baculum/LICENSE index 9e83459af..83e320b04 100644 --- a/gui/baculum/LICENSE +++ b/gui/baculum/LICENSE @@ -815,13 +815,13 @@ THE SOFTWARE. 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 @@ -852,7 +852,7 @@ The Buttons DataTables plugin uses FileSaver.js for saving files on 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 @@ -862,7 +862,7 @@ 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 diff --git a/gui/baculum/Makefile b/gui/baculum/Makefile index c994ba273..0ecf60ec8 100644 --- a/gui/baculum/Makefile +++ b/gui/baculum/Makefile @@ -48,14 +48,17 @@ webdatadirsrc = $(datadir)/$(webdir)/Class \ 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 \ diff --git a/gui/baculum/protected/API/Class/APIInterfaces.php b/gui/baculum/protected/API/Class/APIInterfaces.php new file mode 100644 index 000000000..8c581306d --- /dev/null +++ b/gui/baculum/protected/API/Class/APIInterfaces.php @@ -0,0 +1,44 @@ + + * @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(); +} +?> diff --git a/gui/baculum/protected/API/Class/APIServer.php b/gui/baculum/protected/API/Class/APIServer.php new file mode 100644 index 000000000..e3e150802 --- /dev/null +++ b/gui/baculum/protected/API/Class/APIServer.php @@ -0,0 +1,76 @@ + + * @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\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; + } +} diff --git a/gui/baculum/protected/API/Class/APIServerV1.php b/gui/baculum/protected/API/Class/APIServerV1.php new file mode 100644 index 000000000..35be0af34 --- /dev/null +++ b/gui/baculum/protected/API/Class/APIServerV1.php @@ -0,0 +1,118 @@ + + * @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; $igetServerObj()->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); + } +} +?> diff --git a/gui/baculum/protected/API/Class/APIServerV2.php b/gui/baculum/protected/API/Class/APIServerV2.php new file mode 100644 index 000000000..ba9b86dbb --- /dev/null +++ b/gui/baculum/protected/API/Class/APIServerV2.php @@ -0,0 +1,90 @@ + + * @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); + } +} +?> diff --git a/gui/baculum/protected/API/Class/BaculumAPIPage.php b/gui/baculum/protected/API/Class/BaculumAPIPage.php index 32b0b401d..432e319db 100644 --- a/gui/baculum/protected/API/Class/BaculumAPIPage.php +++ b/gui/baculum/protected/API/Class/BaculumAPIPage.php @@ -3,7 +3,7 @@ * 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 @@ -38,7 +38,14 @@ class BaculumAPIPage extends BaculumPage { 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; } } diff --git a/gui/baculum/protected/API/Class/BaculumAPIServer.php b/gui/baculum/protected/API/Class/BaculumAPIServer.php index 0caf54830..4713b6b25 100644 --- a/gui/baculum/protected/API/Class/BaculumAPIServer.php +++ b/gui/baculum/protected/API/Class/BaculumAPIServer.php @@ -3,7 +3,7 @@ * 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 @@ -29,6 +29,7 @@ Prado::using('Application.API.Class.BAPIException'); 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. @@ -43,7 +44,7 @@ abstract class BaculumAPIServer extends TPage { /** * 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. @@ -174,22 +175,36 @@ abstract class BaculumAPIServer extends TPage { 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; } } @@ -208,7 +223,7 @@ abstract class BaculumAPIServer extends TPage { $this->output = GenericError::MSG_ERROR_INTERNAL_ERROR . ' ' . $e->getErrorMessage(); $this->error = GenericError::ERROR_INTERNAL_ERROR; } - } + } } /** @@ -268,89 +283,6 @@ abstract class BaculumAPIServer extends TPage { 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; $iset($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. diff --git a/gui/baculum/protected/API/Class/StatusClient.php b/gui/baculum/protected/API/Class/StatusClient.php index ece87ecf9..3a48fc00b 100644 --- a/gui/baculum/protected/API/Class/StatusClient.php +++ b/gui/baculum/protected/API/Class/StatusClient.php @@ -3,7 +3,7 @@ * 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 @@ -55,10 +55,11 @@ class StatusClient extends ComponentStatusModule { ); 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; } diff --git a/gui/baculum/protected/API/JavaScript/misc.js b/gui/baculum/protected/API/JavaScript/misc.js deleted file mode 100644 index 0b6a33963..000000000 --- a/gui/baculum/protected/API/JavaScript/misc.js +++ /dev/null @@ -1,28 +0,0 @@ -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(' '); -} diff --git a/gui/baculum/protected/API/Lang/en/messages.mo b/gui/baculum/protected/API/Lang/en/messages.mo index df1528f7c..701f1bc3f 100644 Binary files a/gui/baculum/protected/API/Lang/en/messages.mo and b/gui/baculum/protected/API/Lang/en/messages.mo differ diff --git a/gui/baculum/protected/API/Lang/en/messages.po b/gui/baculum/protected/API/Lang/en/messages.po index 79112edb1..0ea4a2c07 100644 --- a/gui/baculum/protected/API/Lang/en/messages.po +++ b/gui/baculum/protected/API/Lang/en/messages.po @@ -20,14 +20,14 @@ msgstr "Language" 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" @@ -230,8 +230,8 @@ msgstr "Use sudo for bconsole requests:" 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:" @@ -311,9 +311,6 @@ msgstr "Please do not forget to disable HTTP Basic auth in the API web server co msgid "Refresh token" msgstr "Refresh token" -msgid "New HTTP Basic user" -msgstr "New HTTP Basic user" - msgid "New OAuth2 client" msgstr "New OAuth2 client" @@ -344,18 +341,9 @@ msgstr "Problem during save to config file. Please check users config file permi 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" @@ -428,8 +416,8 @@ msgstr "Authentication to Baculum REST API" 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" @@ -509,3 +497,71 @@ msgstr "Note" 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" diff --git a/gui/baculum/protected/API/Lang/pl/messages.mo b/gui/baculum/protected/API/Lang/pl/messages.mo index bc2c65b16..462ba5835 100644 Binary files a/gui/baculum/protected/API/Lang/pl/messages.mo and b/gui/baculum/protected/API/Lang/pl/messages.mo differ diff --git a/gui/baculum/protected/API/Lang/pl/messages.po b/gui/baculum/protected/API/Lang/pl/messages.po index 8e516d697..65372ade7 100644 --- a/gui/baculum/protected/API/Lang/pl/messages.po +++ b/gui/baculum/protected/API/Lang/pl/messages.po @@ -24,14 +24,14 @@ msgstr "Język" 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" @@ -234,8 +234,8 @@ msgstr "Użyj sudo dla zapytań bconsole:" 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." @@ -315,9 +315,6 @@ msgstr "Proszę nie zapomnieć wyłączyć autentykację HTTP Basic w pliku konf 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" @@ -348,18 +345,9 @@ msgstr "Wystąpił problem podczas zapisywania konfiguracji do pliku konfiguracy 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" @@ -432,8 +420,8 @@ msgstr "Uwierzytelnianie do Baculum REST 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" @@ -513,3 +501,71 @@ msgstr "Uwaga" 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ę" diff --git a/gui/baculum/protected/API/Lang/pt/messages.mo b/gui/baculum/protected/API/Lang/pt/messages.mo index 4ba9c6880..654255582 100644 Binary files a/gui/baculum/protected/API/Lang/pt/messages.mo and b/gui/baculum/protected/API/Lang/pt/messages.mo differ diff --git a/gui/baculum/protected/API/Lang/pt/messages.po b/gui/baculum/protected/API/Lang/pt/messages.po index ad3d71e3f..d764ea724 100644 --- a/gui/baculum/protected/API/Lang/pt/messages.po +++ b/gui/baculum/protected/API/Lang/pt/messages.po @@ -24,14 +24,14 @@ msgstr "Idioma" 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" @@ -234,8 +234,8 @@ msgstr "Utilizar sudo para executar bconsole:" 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:" @@ -315,9 +315,6 @@ msgstr "Não se esqueça de desativar a autenticação HTTP Basic na configuraç 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" @@ -348,18 +345,9 @@ msgstr "Problema durante a gravação do arquivo de configuração. Verifique a 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" @@ -432,8 +420,8 @@ msgstr "Autenticação REST API do Baculum" 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" @@ -513,3 +501,71 @@ msgstr "Nota" 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" diff --git a/gui/baculum/protected/API/Lang/ru/messages.mo b/gui/baculum/protected/API/Lang/ru/messages.mo index 1a7a6be2b..b728cd0a5 100644 Binary files a/gui/baculum/protected/API/Lang/ru/messages.mo and b/gui/baculum/protected/API/Lang/ru/messages.mo differ diff --git a/gui/baculum/protected/API/Lang/ru/messages.po b/gui/baculum/protected/API/Lang/ru/messages.po index c8a21ca4a..c538812f6 100644 --- a/gui/baculum/protected/API/Lang/ru/messages.po +++ b/gui/baculum/protected/API/Lang/ru/messages.po @@ -26,14 +26,14 @@ msgstr "Язык" 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 - выбор языка" @@ -236,8 +236,8 @@ msgstr "Использовать sudo для запросов bconsole:" 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:" @@ -317,9 +317,6 @@ msgstr "Не забудьте отключить базовую аутентиф msgid "Refresh token" msgstr "Обновить токен" -msgid "New HTTP Basic user" -msgstr "Новый базовый пользователь HTTP" - msgid "New OAuth2 client" msgstr "Новый OAuth2 клиент" @@ -350,18 +347,9 @@ msgstr "Возникла проблема при сохранении конфи 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." @@ -434,8 +422,8 @@ msgstr "Аутентификация в Baculum REST 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 "Действия" @@ -515,3 +503,71 @@ 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" diff --git a/gui/baculum/protected/API/Layouts/Main.tpl b/gui/baculum/protected/API/Layouts/Main.tpl index ba24a0c88..d7821667e 100644 --- a/gui/baculum/protected/API/Layouts/Main.tpl +++ b/gui/baculum/protected/API/Layouts/Main.tpl @@ -1,11 +1,41 @@ - - - + + + + + + + - - + + /> + /> + /> + /> + /> + /> + /> + /> + /> + +
+ + + + +
+ +
+ +
<%[ Version: ]%> <%=Params::BACULUM_VERSION%>
+
+
-
<%[ Version: ]%> <%=Params::BACULUM_VERSION%>
+ diff --git a/gui/baculum/protected/API/Layouts/Wizard.tpl b/gui/baculum/protected/API/Layouts/Wizard.tpl index 0966bbcb5..2e7e5a5f7 100644 --- a/gui/baculum/protected/API/Layouts/Wizard.tpl +++ b/gui/baculum/protected/API/Layouts/Wizard.tpl @@ -3,6 +3,7 @@ + /> diff --git a/gui/baculum/protected/API/Pages/API/ClientStatus.php b/gui/baculum/protected/API/Pages/API/ClientStatus.php index 1c2b09282..46a40d2e0 100644 --- a/gui/baculum/protected/API/Pages/API/ClientStatus.php +++ b/gui/baculum/protected/API/Pages/API/ClientStatus.php @@ -3,7 +3,7 @@ * 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 @@ -20,6 +20,8 @@ * Bacula(R) is a registered trademark of Kern Sibbald. */ +Prado::using('Application.API.Class.ConsoleOutputPage'); + /** * Client status. * @@ -27,29 +29,70 @@ * @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'] + ); } } diff --git a/gui/baculum/protected/API/Pages/API/DirectorStatus.php b/gui/baculum/protected/API/Pages/API/DirectorStatus.php new file mode 100644 index 000000000..8daa0d566 --- /dev/null +++ b/gui/baculum/protected/API/Pages/API/DirectorStatus.php @@ -0,0 +1,88 @@ + + * @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'] + ); + } +} + +?> diff --git a/gui/baculum/protected/API/Pages/API/StorageStatus.php b/gui/baculum/protected/API/Pages/API/StorageStatus.php index 42b60deaa..8874e44f4 100644 --- a/gui/baculum/protected/API/Pages/API/StorageStatus.php +++ b/gui/baculum/protected/API/Pages/API/StorageStatus.php @@ -3,7 +3,7 @@ * 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 @@ -19,6 +19,8 @@ * * Bacula(R) is a registered trademark of Kern Sibbald. */ + +Prado::using('Application.API.Class.ConsoleOutputPage'); /** * Storage status command endpoint. @@ -27,33 +29,69 @@ * @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'] + ); } } diff --git a/gui/baculum/protected/API/Pages/API/config.xml b/gui/baculum/protected/API/Pages/API/config.xml index 766f2af5a..6381b73f5 100644 --- a/gui/baculum/protected/API/Pages/API/config.xml +++ b/gui/baculum/protected/API/Pages/API/config.xml @@ -10,6 +10,10 @@ + + + + diff --git a/gui/baculum/protected/API/Pages/API/endpoints.xml b/gui/baculum/protected/API/Pages/API/endpoints.xml index 2b18c7530..bccbc1e19 100644 --- a/gui/baculum/protected/API/Pages/API/endpoints.xml +++ b/gui/baculum/protected/API/Pages/API/endpoints.xml @@ -6,6 +6,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gui/baculum/protected/API/Pages/Panel/APIBasicUsers.php b/gui/baculum/protected/API/Pages/Panel/APIBasicUsers.php new file mode 100644 index 000000000..e4688b03c --- /dev/null +++ b/gui/baculum/protected/API/Pages/Panel/APIBasicUsers.php @@ -0,0 +1,93 @@ + + * @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); + } +} +?> diff --git a/gui/baculum/protected/API/Pages/Panel/APIBasicUsers.tpl b/gui/baculum/protected/API/Pages/Panel/APIBasicUsers.tpl new file mode 100644 index 000000000..f71ee2ce4 --- /dev/null +++ b/gui/baculum/protected/API/Pages/Panel/APIBasicUsers.tpl @@ -0,0 +1,218 @@ +<%@ MasterClass="Application.API.Layouts.Main" Theme="Baculum-v2"%> + +
+
+ <%[ Basic users ]%> +
+
+
+ +  <%[ Add user ]%> + + + + + + + + + + + + + + + + + +
<%[ Username ]%><%[ Actions ]%>
<%[ Username ]%><%[ Actions ]%>
+
+ +
+
+
+ × +

<%[ Add user ]%>

+
+
+ +
+
+
+
+
+
+ × +

<%[ Edit user ]%>

+
+
+ +
+
+
+ + + +
diff --git a/gui/baculum/protected/API/Pages/Panel/APIHome.page b/gui/baculum/protected/API/Pages/Panel/APIHome.page index 153b84bef..31f7cd4df 100644 --- a/gui/baculum/protected/API/Pages/Panel/APIHome.page +++ b/gui/baculum/protected/API/Pages/Panel/APIHome.page @@ -1,29 +1,37 @@ -<%@ MasterClass="Application.API.Layouts.Main" Theme="Baculum-v1"%> +<%@ MasterClass="Application.API.Layouts.Main" Theme="Baculum-v2"%> - /> -

<%[ Welcome on the Baculum API default page ]%>

-
- -
+
+

<%[ Welcome on the Baculum API default page ]%>

+
+
+ <%[ Baculum API Client ]%> +
+
+

<%[ Here you can try one from API commands ]%>

- + <%[ Starting... ]%> - <%[ Refresh token ]%> + + + + + +
- @@ -248,21 +59,23 @@ 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%>, @@ -270,7 +83,6 @@ this.set_events(); this.set_auth_params(); this.init_auth(); - this.init_tabs(); this.change_auth_params(); }, init_auth: function() { @@ -287,12 +99,9 @@ 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... ]%>'); @@ -346,7 +155,14 @@ 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)); }, @@ -370,6 +186,9 @@ }, 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}; @@ -389,10 +208,27 @@ }.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() { diff --git a/gui/baculum/protected/API/Pages/Panel/APIHome.php b/gui/baculum/protected/API/Pages/Panel/APIHome.php index 30f9aef3e..d9d684486 100644 --- a/gui/baculum/protected/API/Pages/Panel/APIHome.php +++ b/gui/baculum/protected/API/Pages/Panel/APIHome.php @@ -3,7 +3,7 @@ * 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 @@ -45,9 +45,8 @@ class APIHome extends BaculumAPIPage { $this->goToPage('APIInstallWizard'); return; } elseif (!$this->IsCallback) { - $this->loadBasicUsers(null, null); - $this->loadOAuth2Users(null, null); $this->setAuthParams(null, null); + $this->loadAuthParams(null, null); } } @@ -82,20 +81,6 @@ class APIHome extends BaculumAPIPage { $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(); @@ -114,67 +99,5 @@ class APIHome extends BaculumAPIPage { $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); - } } ?> diff --git a/gui/baculum/protected/API/Pages/Panel/APIInstallWizard.page b/gui/baculum/protected/API/Pages/Panel/APIInstallWizard.page index fd078c026..8ef6fc3d4 100644 --- a/gui/baculum/protected/API/Pages/Panel/APIInstallWizard.page +++ b/gui/baculum/protected/API/Pages/Panel/APIInstallWizard.page @@ -1,66 +1,149 @@ -<%@ MasterClass="Application.API.Layouts.Wizard" Theme="Baculum-v1"%> +<%@ MasterClass="Application.API.Layouts.Wizard" Theme="Baculum-v2"%> - /> -
-
-
-
-
-
+
+
+
+
+
+

+
-
-
+
+
+
+
+

+
-
-
+
+
+
+
+

+
-
-
+
+
+
+
+
+
+

+
-
-
+
+
+
+
+

+
-
-
+
+
+
+
+

+
-
<%=$this->Parent->ActiveStep->Title%>
+
+
+
+

<%=$this->Parent->ActiveStep->Title%>

- -
getPage()->first_run === false ? 'class="button-prev-next"' : ''%>>
+
+ +  <%[ Cancel ]%> + + + <%[ Next ]%>  + +
- -
getPage()->first_run === false ? 'class="button-prev-next"' : ''%>> - - +
+ +  <%[ Cancel ]%> + + +  <%[ Previous ]%> + + + <%[ Next ]%>  +
+ - -
getPage()->first_run === false ? 'class="button-prev-next"' : ''%>> - - +
+ +  <%[ Cancel ]%> + + +  <%[ Previous ]%> + + +  <%[ Save ]%> +
-
-
-
- +
+
+
+ @@ -72,20 +155,30 @@

<%[ Do you want to setup and to share the Bacula Catalog Database access for this API instance? ]%>

-
- +
+
-
- +
+
-
-
-
+
+
+
-
-
-
- +
+
+
+
-
-
-
- +
+
+
+
-
-
-
+
+
-
-
-
- +
+
+
+
-
-
-
- +
+
+
+ -
-
- +
+
+
-
-
-
- +
+
+
+
-
- + - $('#<%=$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(); - $('#<%=$this->DbTestLoader->ClientID%>').hide(); + $('#db_test_loader').hide(); - +  <%[ test ]%> + - <%[ Loading... ]%> - Validate <%[ OK ]%> - Invalidate <%[ Connection error ]%> + + + + + <%[ Connection error ]%>
-
@@ -943,209 +1088,160 @@
<%[ Catalog API ]%>
-
-
<%[ Database type: ]%>
-
<%=$this->getDbNameByType($this->DBType->SelectedValue)%>
+
+
<%[ Database type: ]%>
+
<%=$this->getDbNameByType($this->DBType->SelectedValue)%>
-
-
<%[ Database name: ]%>
-
<%=$this->DBName->Text%>
+
+
<%[ Database name: ]%>
+
<%=$this->DBName->Text%>
-
-
<%[ Login: ]%>
-
<%=$this->isSQLiteType($this->DBType->SelectedValue) === false ? $this->Login->Text : '-'%>
+
+
<%[ Login: ]%>
+
<%=$this->isSQLiteType($this->DBType->SelectedValue) === false ? $this->Login->Text : '-'%>
-
-
<%[ Password: ]%>
-
<%=$this->isSQLiteType($this->DBType->SelectedValue) === false ? preg_replace('/.{1}/', '*', $this->Password->Text) : '-'%>
+
+
<%[ Password: ]%>
+
<%=$this->isSQLiteType($this->DBType->SelectedValue) === false ? preg_replace('/.{1}/', '*', $this->Password->Text) : '-'%>
-
-
<%[ IP address (or hostname): ]%>
-
<%=$this->isSQLiteType($this->DBType->SelectedValue) === false ? $this->IP->Text : '-'%>
+
+
<%[ IP address (or hostname): ]%>
+
<%=$this->isSQLiteType($this->DBType->SelectedValue) === false ? $this->IP->Text : '-'%>
-
-
<%[ Database port: ]%>
-
<%=$this->isSQLiteType($this->DBType->SelectedValue) === false ? $this->Port->Text : '-'%>
+
+
<%[ Database port: ]%>
+
<%=$this->isSQLiteType($this->DBType->SelectedValue) === false ? $this->Port->Text : '-'%>
-
-
<%[ Database file path (SQLite only): ]%>
-
<%=$this->isSQLiteType($this->DBType->SelectedValue) === true ? $this->DBPath->Text : '-'%>
+
+
<%[ Database file path (SQLite only): ]%>
+
<%=$this->isSQLiteType($this->DBType->SelectedValue) === true ? $this->DBPath->Text : '-'%>
-
-
<%[ Catalog access: ]%>
-
<%[ Disabled ]%>
+
+
<%[ Catalog access: ]%>
+
<%[ Disabled ]%>
<%[ Console API ]%>
-
-
<%[ Bconsole binary file path: ]%>
-
<%=$this->BconsolePath->Text%>
+
+
<%[ Bconsole binary file path: ]%>
+
<%=$this->BconsolePath->Text%>
-
-
<%[ Bconsole admin config file path: ]%>
-
<%=$this->BconsoleConfigPath->Text%>
+
+
<%[ Bconsole admin config file path: ]%>
+
<%=$this->BconsoleConfigPath->Text%>
-
-
<%[ Use sudo for bconsole requests: ]%>
-
<%=($this->UseSudo->Checked === true) ? 'yes' : 'no'%>
+
+
<%[ Use sudo for bconsole requests: ]%>
+
<%=($this->UseSudo->Checked === true) ? 'yes' : 'no'%>
-
-
<%[ Console access: ]%>
-
<%[ Disabled ]%>
+
+
<%[ Console access: ]%>
+
<%[ Disabled ]%>
<%[ Config API ]%>
-
-
<%[ Directory path for new config files: ]%>
-
<%=$this->BConfigDir->Text%>
+
+
<%[ Directory path for new config files: ]%>
+
<%=$this->BConfigDir->Text%>
-
-
<%[ Use sudo for Bacula JSON tools: ]%>
-
<%=($this->BJSONUseSudo->Checked === true) ? 'yes' : 'no'%>
+
+
<%[ Use sudo for Bacula JSON tools: ]%>
+
<%=($this->BJSONUseSudo->Checked === true) ? 'yes' : 'no'%>
-
-
<%[ bdirjson binary file path: ]%>
-
<%=$this->BDirJSONPath->Text%>
+
+
<%[ bdirjson binary file path: ]%>
+
<%=$this->BDirJSONPath->Text%>
-
-
<%[ Main Director config file path: ]%>
-
<%=$this->DirCfgPath->Text%>
+
+
<%[ Main Director config file path: ]%>
+
<%=$this->DirCfgPath->Text%>
-
-
<%[ bsdjson binary file path: ]%>
-
<%=$this->BSdJSONPath->Text%>
+
+
<%[ bsdjson binary file path: ]%>
+
<%=$this->BSdJSONPath->Text%>
-
-
<%[ Main Storage Daemon config file path: ]%>
-
<%=$this->SdCfgPath->Text%>
+
+
<%[ Main Storage Daemon config file path: ]%>
+
<%=$this->SdCfgPath->Text%>
-
-
<%[ bfdjson binary file path: ]%>
-
<%=$this->BFdJSONPath->Text%>
+
+
<%[ bfdjson binary file path: ]%>
+
<%=$this->BFdJSONPath->Text%>
-
-
<%[ Main Client config file path: ]%>
-
<%=$this->FdCfgPath->Text%>
+
+
<%[ Main Client config file path: ]%>
+
<%=$this->FdCfgPath->Text%>
-
-
<%[ bbconsjson binary file path: ]%>
-
<%=$this->BBconsJSONPath->Text%>
+
+
<%[ bbconsjson binary file path: ]%>
+
<%=$this->BBconsJSONPath->Text%>
-
-
<%[ Main Bconsole config file path: ]%>
-
<%=$this->BconsCfgPath->Text%>
+
+
<%[ Main Bconsole config file path: ]%>
+
<%=$this->BconsCfgPath->Text%>
-
-
<%[ Config access: ]%>
-
<%[ Disabled ]%>
-
-
-
-
- <%[ Actions ]%> -
-
-
<%[ Use sudo for actions: ]%>
-
<%=($this->ActionsUseSudo->Checked === true) ? 'yes' : 'no'%>
-
-
-
<%[ Director start command: ]%>
-
<%=$this->DirStartAction->Text%>
-
-
-
<%[ Director stop command: ]%>
-
<%=$this->DirStopAction->Text%>
-
-
-
<%[ Director restart command: ]%>
-
<%=$this->DirRestartAction->Text%>
-
-
-
<%[ Storage Daemon start command: ]%>
-
<%=$this->SdStartAction->Text%>
-
-
-
<%[ Storage Daemon stop command: ]%>
-
<%=$this->SdStopAction->Text%>
-
-
-
<%[ Storage Daemon restart command: ]%>
-
<%=$this->SdRestartAction->Text%>
-
-
-
<%[ File Daemon/Client start command: ]%>
-
<%=$this->FdStartAction->Text%>
-
-
-
<%[ File Daemon/Client stop command: ]%>
-
<%=$this->FdStopAction->Text%>
-
-
-
<%[ File Daemon/Client restart command: ]%>
-
<%=$this->FdRestartAction->Text%>
-
-
-
-
-
<%[ Actions setting: ]%>
-
<%[ Disabled ]%>
+
+
<%[ Config access: ]%>
+
<%[ Disabled ]%>
<%[ Authentication to Baculum REST API ]%> -
-
<%[ Authentication type: ]%>
-
- <%=$this->AuthBasic->Checked ? 'HTTP Basic' : ''%> - <%=$this->AuthOAuth2->Checked ? 'OAuth2' : ''%> +
+
<%[ Authentication type: ]%>
+
+ + <%=$this->AuthBasic->Checked ? 'HTTP Basic' : ''%> + <%=$this->AuthOAuth2->Checked ? 'OAuth2' : ''%> +
-
-
<%[ Administration login: ]%>
-
<%=$this->APILogin->Text%>
+
+
<%[ Administration login: ]%>
+
<%=$this->APILogin->Text%>
-
-
<%[ Administration password: ]%>
-
<%=preg_replace('/.{1}/', '*', $this->APIPassword->Text)%>
+
+
<%[ Administration password: ]%>
+
<%=preg_replace('/.{1}/', '*', $this->APIPassword->Text)%>
-
-
Client ID:
-
<%=$this->APIOAuth2ClientId->Text%>
+
+
Client ID:
+
<%=$this->APIOAuth2ClientId->Text%>
-
-
Client Secret:
-
<%=preg_replace('/.{1}/', '*', $this->APIOAuth2ClientSecret->Text)%>
+
+
Client Secret:
+
<%=preg_replace('/.{1}/', '*', $this->APIOAuth2ClientSecret->Text)%>
-
-
Redirect URI:
-
<%=$this->APIOAuth2RedirectURI->Text%>
+
+
Redirect URI:
+
<%=$this->APIOAuth2RedirectURI->Text%>
-
-
Scope:
-
<%=$this->APIOAuth2Scope->Text%>
+
+
Scope:
+
<%=$this->APIOAuth2Scope->Text%>
-
-
<%[ Dedicated Bconsole config file path: ]%>
-
<%=!empty($this->APIOAuth2BconsoleCfgPath->Text) ? $this->APIOAuth2BconsoleCfgPath->Text : '-'%>
+
+
<%[ Dedicated Bconsole config file path: ]%>
+
<%=!empty($this->APIOAuth2BconsoleCfgPath->Text) ? $this->APIOAuth2BconsoleCfgPath->Text : '-'%>
@@ -1156,7 +1252,7 @@ ID="SudoConfigPopup" Options.title="<%[ Sudo configuration ]%>" Options.autoOpen="false", - Options.minWidth="600" + Options.minWidth="820" Options.minHeight="200" >

<%[ Please copy appropriate sudo configuration and put it to a new sudoers.d file for example /etc/sudoers.d/baculum-api ]%>

@@ -1285,17 +1381,6 @@ function get_sudo_config(type) { '<%=$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; diff --git a/gui/baculum/protected/API/Pages/Panel/APIInstallWizard.php b/gui/baculum/protected/API/Pages/Panel/APIInstallWizard.php index a615747e7..dfe8720f0 100644 --- a/gui/baculum/protected/API/Pages/Panel/APIInstallWizard.php +++ b/gui/baculum/protected/API/Pages/Panel/APIInstallWizard.php @@ -3,7 +3,7 @@ * 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 @@ -94,130 +94,86 @@ class APIInstallWizard extends BaculumAPIPage { 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; } } } @@ -237,8 +193,7 @@ class APIInstallWizard extends BaculumAPIPage { 'api' => array(), 'db' => array(), 'bconsole' => array(), - 'jsontools' => array(), - 'actions' => array() + 'jsontools' => array() ); if ($this->AuthBasic->Checked) { $cfg_data['api']['auth_type'] = 'basic'; @@ -270,17 +225,6 @@ class APIInstallWizard extends BaculumAPIPage { $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) { @@ -388,7 +332,6 @@ class APIInstallWizard extends BaculumAPIPage { $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); } @@ -415,15 +358,21 @@ class APIInstallWizard extends BaculumAPIPage { 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) { @@ -438,8 +387,15 @@ class APIInstallWizard extends BaculumAPIPage { 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) { @@ -502,23 +458,5 @@ class APIInstallWizard extends BaculumAPIPage { } $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)); - } } ?> diff --git a/gui/baculum/protected/API/Pages/Panel/APIOAuth2Clients.php b/gui/baculum/protected/API/Pages/Panel/APIOAuth2Clients.php new file mode 100644 index 000000000..153577738 --- /dev/null +++ b/gui/baculum/protected/API/Pages/Panel/APIOAuth2Clients.php @@ -0,0 +1,88 @@ + + * @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); + } +} +?> diff --git a/gui/baculum/protected/API/Pages/Panel/APIOAuth2Clients.tpl b/gui/baculum/protected/API/Pages/Panel/APIOAuth2Clients.tpl new file mode 100644 index 000000000..4a7e5a87e --- /dev/null +++ b/gui/baculum/protected/API/Pages/Panel/APIOAuth2Clients.tpl @@ -0,0 +1,352 @@ +<%@ MasterClass="Application.API.Layouts.Main" Theme="Baculum-v2"%> + +
+
+ <%[ OAuth2 clients ]%> +
+
+
+ +  <%[ Add OAuth2 client ]%> + + + + + + + + + + + + + + + + + + + + + +
<%[ Name ]%><%[ Client ID ]%><%[ Redirect URI ]%><%[ Actions ]%>
<%[ Name ]%><%[ Client ID ]%><%[ Redirect URI ]%><%[ Actions ]%>
+
+ +
+
+
+ × +

<%[ Add client ]%>

+
+
+ +
+
+
+
+
+
+ × +

<%[ Edit client ]%>

+
+
+ +
+
+
+ + + + + +
+
+
+ +
+
+
+
+
+ + + + <%[ generate ]%> +
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
+ <%[ (optional) ]%> +
+
+
+
+
+ <%[ (optional) ]%> +
+
+
+ + + +
+
+
+
diff --git a/gui/baculum/protected/API/Pages/Panel/APISettings.page b/gui/baculum/protected/API/Pages/Panel/APISettings.page new file mode 100644 index 000000000..e4dc9cfdb --- /dev/null +++ b/gui/baculum/protected/API/Pages/Panel/APISettings.page @@ -0,0 +1,1401 @@ +<%@ MasterClass="Application.API.Layouts.Main" Theme="Baculum-v2"%> + +
+
+ <%[ API settings ]%> +
+
+
+ + + + + + +
+
+
+
+
+ + + + + + +
+
+
+
+
+ +
+
+
+
+ +  <%[ Save ]%> + +
+
+
+ + + + + + +

<%[ Please copy appropriate sudo configuration and put it to a new sudoers.d file for example /etc/sudoers.d/baculum-api ]%>

+

<%[ Note ]%> <%[ Please use visudo to add this configuration, otherwise please do remember to add empty line at the end of file. ]%> +

<%[ Example sudo configuration for Apache web server user (RHEL, CentOS and others): ]%>

+

+	

<%[ Example sudo configuration for Lighttpd web server user (RHEL, CentOS and others): ]%>

+

+	

<%[ Example sudo configuration for Apache and Lighttpd web servers user (Debian, Ubuntu and others): ]%>

+

+
+ +
diff --git a/gui/baculum/protected/API/Pages/Panel/APISettings.php b/gui/baculum/protected/API/Pages/Panel/APISettings.php new file mode 100644 index 000000000..5516ffd60 --- /dev/null +++ b/gui/baculum/protected/API/Pages/Panel/APISettings.php @@ -0,0 +1,475 @@ + + * @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); + } +} +?> diff --git a/gui/baculum/protected/API/Pages/Panel/endpoints.xml b/gui/baculum/protected/API/Pages/Panel/endpoints.xml index d4b74bc33..81e24edbe 100644 --- a/gui/baculum/protected/API/Pages/Panel/endpoints.xml +++ b/gui/baculum/protected/API/Pages/Panel/endpoints.xml @@ -1,5 +1,8 @@ - + + + + diff --git a/gui/baculum/protected/API/Portlets/APISideBar.php b/gui/baculum/protected/API/Portlets/APISideBar.php new file mode 100644 index 000000000..cafc4206f --- /dev/null +++ b/gui/baculum/protected/API/Portlets/APISideBar.php @@ -0,0 +1,57 @@ + + * @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); + } +} +?> diff --git a/gui/baculum/protected/API/Portlets/APISideBar.tpl b/gui/baculum/protected/API/Portlets/APISideBar.tpl new file mode 100644 index 000000000..ff2934380 --- /dev/null +++ b/gui/baculum/protected/API/Portlets/APISideBar.tpl @@ -0,0 +1,41 @@ + + + +
diff --git a/gui/baculum/protected/API/openapi_baculum.json b/gui/baculum/protected/API/openapi_baculum.json index 1c981320e..af963dca8 100644 --- a/gui/baculum/protected/API/openapi_baculum.json +++ b/gui/baculum/protected/API/openapi_baculum.json @@ -12,7 +12,7 @@ "name": "AGPLv3", "url": "https://www.gnu.org/licenses/agpl-3.0-standalone.html" }, - "version": "1.0.0" + "version": "2.0.0" }, "server": { "servers": [{ @@ -250,7 +250,7 @@ "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" } }, { @@ -258,7 +258,7 @@ "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" } }, { @@ -266,7 +266,7 @@ "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" } }, { @@ -274,7 +274,7 @@ "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" } }, { @@ -282,7 +282,7 @@ "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" } }, { @@ -290,7 +290,7 @@ "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" } }, { @@ -298,7 +298,7 @@ "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" } }, { @@ -306,7 +306,7 @@ "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" } }, { @@ -318,11 +318,16 @@ "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", @@ -354,7 +359,7 @@ }] } }, - "/api/v1/clients/{clientid}": { + "/api/v2/clients/{clientid}": { "get": { "tags": ["clients"], "summary": "Find client by ClientId", @@ -386,7 +391,7 @@ }] } }, - "/api/v1/clients/{clientid}/show": { + "/api/v2/clients/{clientid}/show": { "get": { "tags": ["clients"], "summary": "Show client", @@ -481,7 +486,7 @@ ] } }, - "/api/v1/clients/{clientid}/status": { + "/api/v2/clients/{clientid}/status": { "get": { "tags": ["clients"], "summary": "Client status", @@ -498,7 +503,7 @@ "type": "array", "items": { "type": "string", - "description": "Client status" + "description": "Client status output" } }, "error": { @@ -512,12 +517,26 @@ } } }, - "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", @@ -549,7 +568,7 @@ }] } }, - "/api/v1/clients/{clientid}/ls": { + "/api/v2/clients/{clientid}/ls": { "get": { "tags": ["clients"], "summary": "List Client files/directories", @@ -597,7 +616,7 @@ ] } }, - "/api/v1/clients/{clientid}/bandwidth": { + "/api/v2/clients/{clientid}/bandwidth": { "put": { "tags": ["clients"], "summary": "Set Client bandwidth limit", @@ -645,7 +664,7 @@ ] } }, - "/api/v1/clients/show": { + "/api/v2/clients/show": { "get": { "tags": ["clients"], "summary": "Show clients", @@ -690,7 +709,7 @@ ] } }, - "/api/v1/jobs": { + "/api/v2/jobs": { "get": { "tags": ["jobs"], "summary": "Job list", @@ -779,7 +798,7 @@ ] } }, - "/api/v1/jobs/{jobid}": { + "/api/v2/jobs/{jobid}": { "get": { "tags": ["jobs"], "summary": "Find job by JobId", @@ -861,12 +880,12 @@ ] } }, - "/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", @@ -906,7 +925,7 @@ ] } }, - "/api/v1/jobs/{jobid}/show": { + "/api/v2/jobs/{jobid}/show": { "get": { "tags": ["jobs"], "summary": "Show job", @@ -950,7 +969,7 @@ ] } }, - "/api/v1/jobs/{jobid}/bandwidth": { + "/api/v2/jobs/{jobid}/bandwidth": { "put": { "tags": ["jobs"], "summary": "Set Job bandwidth limit", @@ -998,7 +1017,7 @@ ] } }, - "/api/v1/jobs/{jobid}/files": { + "/api/v2/jobs/{jobid}/files": { "get": { "tags": ["jobs"], "summary": "Show job files and directories", @@ -1097,7 +1116,7 @@ ] } }, - "/api/v1/jobs/files": { + "/api/v2/jobs/files": { "get": { "tags": ["jobs"], "summary": "Search jobs by file criteria", @@ -1224,7 +1243,7 @@ ] } }, - "/api/v1/jobs/resnames": { + "/api/v2/jobs/resnames": { "get": { "tags": ["jobs"], "summary": "Job resource names", @@ -1262,7 +1281,7 @@ ] } }, - "/api/v1/jobs/recent/{jobname}": { + "/api/v2/jobs/recent/{jobname}": { "get": { "tags": ["jobs"], "summary": "Get most recent jobids for job to restore", @@ -1344,7 +1363,7 @@ ] } }, - "/api/v1/jobs/estimate": { + "/api/v2/jobs/estimate": { "get": { "tags": ["jobs"], "summary": "Get estimate output", @@ -1389,7 +1408,7 @@ "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": { @@ -1419,7 +1438,7 @@ }, "parameters": [ { - "name": "create[id]", + "name": "id", "in": "body", "description": "Job identifier", "required": true, @@ -1428,7 +1447,7 @@ } }, { - "name": "create[name]", + "name": "name", "in": "body", "description": "Job name (can be used instead id)", "required": true, @@ -1438,7 +1457,7 @@ } }, { - "name": "create[clientid]", + "name": "clientid", "in": "body", "description": "Client identifier", "required": true, @@ -1447,7 +1466,7 @@ } }, { - "name": "create[client]", + "name": "client", "in": "body", "description": "Client name (can be used instead clientid)", "required": true, @@ -1457,7 +1476,7 @@ } }, { - "name": "create[fileset]", + "name": "fileset", "in": "body", "description": "FileSet name", "required": true, @@ -1467,7 +1486,7 @@ } }, { - "name": "create[accurate]", + "name": "accurate", "in": "body", "description": "Accurate mode, 1 if enabled, otherwise 0", "required": false, @@ -1478,11 +1497,11 @@ ] } }, - "/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": { @@ -1512,7 +1531,7 @@ }, "parameters": [ { - "name": "create[id]", + "name": "id", "in": "body", "description": "Job identifier", "required": true, @@ -1521,7 +1540,7 @@ } }, { - "name": "create[name]", + "name": "name", "in": "body", "description": "Job name (can be used instead id)", "required": true, @@ -1531,7 +1550,17 @@ } }, { - "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, @@ -1540,7 +1569,7 @@ } }, { - "name": "create[client]", + "name": "client", "in": "body", "description": "Client name (can be used instead clientid)", "required": true, @@ -1550,7 +1579,7 @@ } }, { - "name": "create[storageid]", + "name": "storageid", "in": "body", "description": "Storage identifier", "required": true, @@ -1559,7 +1588,7 @@ } }, { - "name": "create[storage]", + "name": "storage", "in": "body", "description": "Storage name (can be used instead storageid)", "required": true, @@ -1569,7 +1598,7 @@ } }, { - "name": "create[poolid]", + "name": "poolid", "in": "body", "description": "Pool identifier", "required": true, @@ -1578,7 +1607,7 @@ } }, { - "name": "create[pool]", + "name": "pool", "in": "body", "description": "Pool name (can be used instead poolid)", "required": true, @@ -1588,7 +1617,7 @@ } }, { - "name": "create[filesetid]", + "name": "filesetid", "in": "body", "description": "FileSet identifier", "required": true, @@ -1597,7 +1626,7 @@ } }, { - "name": "create[fileset]", + "name": "fileset", "in": "body", "description": "FileSet name (can be used instead filesetid)", "required": true, @@ -1607,7 +1636,7 @@ } }, { - "name": "create[priority]", + "name": "priority", "in": "body", "description": "Job priority", "required": false, @@ -1616,7 +1645,7 @@ } }, { - "name": "create[accurate]", + "name": "accurate", "in": "body", "description": "Accurate mode, 1 if enabled, otherwise 0", "required": false, @@ -1625,7 +1654,7 @@ } }, { - "name": "create[jobid]", + "name": "jobid", "in": "body", "description": "Job identifier for verify job", "required": false, @@ -1634,7 +1663,7 @@ } }, { - "name": "create[verifyjob]", + "name": "verifyjob", "in": "body", "description": "Verify job name", "required": false, @@ -1646,7 +1675,7 @@ ] } }, - "/api/v1/jobs/show": { + "/api/v2/jobs/show": { "get": { "tags": ["jobs"], "summary": "Show jobs", @@ -1691,7 +1720,7 @@ ] } }, - "/api/v1/jobs/totals": { + "/api/v2/jobs/totals": { "get": { "tags": ["jobs"], "summary": "Show job total bytes and files", @@ -1730,11 +1759,11 @@ } } }, - "/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": { @@ -1764,7 +1793,7 @@ }, "parameters": [ { - "name": "create[id]", + "name": "id", "in": "body", "description": "Job identifier (for full restore)", "required": false, @@ -1773,7 +1802,7 @@ } }, { - "name": "create[clientid]", + "name": "clientid", "in": "body", "description": "Client identifier", "required": true, @@ -1782,7 +1811,7 @@ } }, { - "name": "create[client]", + "name": "client", "in": "body", "description": "Client name (can be used instead clientid)", "required": true, @@ -1792,7 +1821,7 @@ } }, { - "name": "create[where]", + "name": "where", "in": "body", "description": "Where to restore files", "required": true, @@ -1801,7 +1830,7 @@ } }, { - "name": "create[rpath]", + "name": "rpath", "in": "body", "description": "Rpath (restore path)", "required": false, @@ -1811,7 +1840,7 @@ } }, { - "name": "create[full]", + "name": "full", "in": "body", "description": "Full restore all files", "required": false, @@ -1820,7 +1849,7 @@ } }, { - "name": "create[filesetid]", + "name": "filesetid", "in": "body", "description": "FileSet identifier (for full restore)", "required": false, @@ -1829,7 +1858,7 @@ } }, { - "name": "create[fileset]", + "name": "fileset", "in": "body", "description": "FileSet (can be used instead of filesetid) (for full restore)", "required": false, @@ -1838,7 +1867,7 @@ } }, { - "name": "create[restorejob]", + "name": "restorejob", "in": "body", "description": "Restore job name", "required": false, @@ -1848,7 +1877,7 @@ } }, { - "name": "create[strip_prefix]", + "name": "strip_prefix", "in": "body", "description": "Strip prefix in restored paths", "required": false, @@ -1857,7 +1886,7 @@ } }, { - "name": "create[add_prefix]", + "name": "add_prefix", "in": "body", "description": "Add prefix to restored paths", "required": false, @@ -1866,7 +1895,7 @@ } }, { - "name": "create[add_suffix]", + "name": "add_suffix", "in": "body", "description": "Add suffix to restored paths", "required": false, @@ -1875,7 +1904,7 @@ } }, { - "name": "create[regex_where]", + "name": "regex_where", "in": "body", "description": "Use regex to file relocation", "required": false, @@ -1886,7 +1915,7 @@ ] } }, - "/api/v1/storages": { + "/api/v2/storages": { "get": { "tags": ["storages"], "summary": "Storage list", @@ -1918,7 +1947,7 @@ }] } }, - "/api/v1/storages/{storageid}": { + "/api/v2/storages/{storageid}": { "get": { "tags": ["storages"], "summary": "Find storage by StorageId", @@ -1950,7 +1979,7 @@ }] } }, - "/api/v1/storages/{storageid}/show": { + "/api/v2/storages/{storageid}/show": { "get": { "tags": ["storages"], "summary": "Show storage", @@ -1991,7 +2020,7 @@ ] } }, - "/api/v1/storages/{storageid}/status": { + "/api/v2/storages/{storageid}/status": { "get": { "tags": ["storages"], "summary": "Storage status", @@ -2008,13 +2037,13 @@ "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] } } } @@ -2022,12 +2051,26 @@ } } }, - "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", @@ -2074,7 +2117,7 @@ ] } }, - "/api/v1/storages/{storageid}/umount": { + "/api/v2/storages/{storageid}/umount": { "get": { "tags": ["storages"], "summary": "Umount storage", @@ -2118,7 +2161,7 @@ ] } }, - "/api/v1/storages/{storageid}/release": { + "/api/v2/storages/{storageid}/release": { "get": { "tags": ["storages"], "summary": "Release storage", @@ -2162,7 +2205,7 @@ ] } }, - "/api/v1/storages/show": { + "/api/v2/storages/show": { "get": { "tags": ["storages"], "summary": "Show storages", @@ -2210,7 +2253,7 @@ ] } }, - "/api/v1/pools": { + "/api/v2/pools": { "get": { "tags": ["pools"], "summary": "Pool list", @@ -2242,7 +2285,7 @@ }] } }, - "/api/v1/pools/{poolid}": { + "/api/v2/pools/{poolid}": { "get": { "tags": ["pools"], "summary": "Find pool by PoolId", @@ -2274,7 +2317,7 @@ }] } }, - "/api/v1/pools/{poolid}/volumes": { + "/api/v2/pools/{poolid}/volumes": { "get": { "tags": ["pools"], "summary": "Get all volumes in pool", @@ -2306,7 +2349,7 @@ }] } }, - "/api/v1/pools/{poolid}/show": { + "/api/v2/pools/{poolid}/show": { "get": { "tags": ["pools"], "summary": "Show pool", @@ -2342,12 +2385,12 @@ }] } }, - "/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", @@ -2379,12 +2422,12 @@ }] } }, - "/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", @@ -2416,7 +2459,7 @@ }] } }, - "/api/v1/pools/show": { + "/api/v2/pools/show": { "get": { "tags": ["pools"], "summary": "Show pools", @@ -2461,7 +2504,7 @@ ] } }, - "/api/v1/volumes": { + "/api/v2/volumes": { "get": { "tags": ["volumes"], "summary": "Volume list", @@ -2493,7 +2536,7 @@ }] } }, - "/api/v1/volumes/{mediaid}": { + "/api/v2/volumes/{mediaid}": { "get": { "tags": ["volumes"], "summary": "Find volume by MediaId", @@ -2528,7 +2571,7 @@ "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", @@ -2560,7 +2603,7 @@ "$ref": "#/components/parameters/MediaId" }, { - "name": "update[volstatus]", + "name": "volstatus", "in": "body", "description": "Volume status", "required": false, @@ -2569,7 +2612,7 @@ } }, { - "name": "update[poolid]", + "name": "poolid", "in": "body", "description": "Update Volume Pool by Pool identifier", "required": false, @@ -2578,7 +2621,7 @@ } }, { - "name": "update[volretention]", + "name": "volretention", "in": "body", "description": "Volume retention time", "required": false, @@ -2587,7 +2630,7 @@ } }, { - "name": "update[voluseduration]", + "name": "voluseduration", "in": "body", "description": "Volume use duration time", "required": false, @@ -2596,7 +2639,7 @@ } }, { - "name": "update[maxvoljobs]", + "name": "maxvoljobs", "in": "body", "description": "Maximum volume jobs", "required": false, @@ -2605,7 +2648,7 @@ } }, { - "name": "update[maxvolfiles]", + "name": "maxvolfiles", "in": "body", "description": "Maximum volume files", "required": false, @@ -2614,7 +2657,7 @@ } }, { - "name": "update[maxvolbytes]", + "name": "maxvolbytes", "in": "body", "description": "Maximum volume bytes", "required": false, @@ -2623,7 +2666,7 @@ } }, { - "name": "update[slot]", + "name": "slot", "in": "body", "description": "Volume slot", "required": false, @@ -2632,7 +2675,7 @@ } }, { - "name": "update[recycle]", + "name": "recycle", "in": "body", "description": "Volume recycle flag", "required": false, @@ -2643,7 +2686,7 @@ } }, { - "name": "update[enabled]", + "name": "enabled", "in": "body", "description": "Volume enabled flag", "required": false, @@ -2654,7 +2697,7 @@ } }, { - "name": "update[inchanger]", + "name": "inchanger", "in": "body", "description": "Volume InChanger flag", "required": false, @@ -2667,12 +2710,12 @@ ] } }, - "/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", @@ -2706,12 +2749,12 @@ ] } }, - "/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", @@ -2745,7 +2788,7 @@ ] } }, - "/api/v1/volumes/{mediaid}/jobs": { + "/api/v2/volumes/{mediaid}/jobs": { "get": { "tags": ["volumes"], "summary": "Jobs on volume", @@ -2777,7 +2820,7 @@ }] } }, - "/api/v1/volumes/required/{jobid}/{fileid}": { + "/api/v2/volumes/required/{jobid}/{fileid}": { "get": { "tags": ["volumes"], "summary": "Get volumes required to restore file", @@ -2842,7 +2885,7 @@ ] } }, - "/api/v1/volumes/label": { + "/api/v2/volumes/label": { "get": { "tags": ["volumes"], "summary": "Get label volume output", @@ -2888,7 +2931,7 @@ "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)", @@ -2917,7 +2960,7 @@ }, "parameters": [ { - "name": "create[volume]", + "name": "volume", "in": "body", "description": "Volume name", "required": true, @@ -2926,7 +2969,7 @@ } }, { - "name": "create[slot]", + "name": "slot", "in": "body", "description": "Slot number", "required": true, @@ -2936,7 +2979,7 @@ } }, { - "name": "create[drive]", + "name": "drive", "in": "body", "description": "Drive number", "required": true, @@ -2946,7 +2989,7 @@ } }, { - "name": "create[storageid]", + "name": "storageid", "in": "body", "description": "Storage identifier", "required": true, @@ -2956,7 +2999,7 @@ } }, { - "name": "create[storage]", + "name": "storage", "in": "body", "description": "Storage name can be used instead of storageid", "required": true, @@ -2966,7 +3009,7 @@ } }, { - "name": "create[poolid]", + "name": "poolid", "in": "body", "description": "Pool identifier", "required": true, @@ -2976,7 +3019,7 @@ } }, { - "name": "create[pool]", + "name": "pool", "in": "body", "description": "Pool name can be used instead of poolid", "required": true, @@ -2988,7 +3031,7 @@ ] } }, - "/api/v1/volumes/label/barcodes": { + "/api/v2/volumes/label/barcodes": { "get": { "tags": ["volumes"], "summary": "Get label barcodes volume output", @@ -3034,7 +3077,7 @@ "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)", @@ -3063,7 +3106,7 @@ }, "parameters": [ { - "name": "create[slots]", + "name": "slots", "in": "body", "description": "Slots numbers or slots range (ex. 1-3,5,10)", "required": true, @@ -3072,7 +3115,7 @@ } }, { - "name": "create[drive]", + "name": "drive", "in": "body", "description": "Drive number", "required": true, @@ -3082,7 +3125,7 @@ } }, { - "name": "create[storageid]", + "name": "storageid", "in": "body", "description": "Storage identifier", "required": true, @@ -3092,7 +3135,7 @@ } }, { - "name": "create[storage]", + "name": "storage", "in": "body", "description": "Storage name can be used instead of storageid", "required": true, @@ -3102,7 +3145,7 @@ } }, { - "name": "create[poolid]", + "name": "poolid", "in": "body", "description": "Pool identifier", "required": true, @@ -3112,7 +3155,7 @@ } }, { - "name": "create[pool]", + "name": "pool", "in": "body", "description": "Pool name can be used instead of poolid", "required": true, @@ -3124,7 +3167,7 @@ ] } }, - "/api/v1/volumes/update": { + "/api/v2/volumes/update": { "get": { "tags": ["volumes"], "summary": "Get update slots output", @@ -3170,7 +3213,7 @@ "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)", @@ -3199,7 +3242,7 @@ }, "parameters": [ { - "name": "update[slots]", + "name": "slots", "in": "body", "description": "Slots numbers or slots range (ex. 1-3,5,10)", "required": true, @@ -3209,7 +3252,7 @@ } }, { - "name": "update[drive]", + "name": "drive", "in": "body", "description": "Drive number", "required": true, @@ -3219,7 +3262,7 @@ } }, { - "name": "update[storageid]", + "name": "storageid", "in": "body", "description": "Storage identifier", "required": true, @@ -3229,7 +3272,7 @@ } }, { - "name": "update[storage]", + "name": "storage", "in": "body", "description": "Storage name can be used instead of storageid", "required": true, @@ -3241,7 +3284,7 @@ ] } }, - "/api/v1/volumes/update/barcodes": { + "/api/v2/volumes/update/barcodes": { "get": { "tags": ["volumes"], "summary": "Get update slots output using barcodes", @@ -3287,7 +3330,7 @@ "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)", @@ -3316,7 +3359,7 @@ }, "parameters": [ { - "name": "update[slots]", + "name": "slots", "in": "body", "description": "Slots numbers or slots range (ex. 1-3,5,10)", "required": true, @@ -3326,7 +3369,7 @@ } }, { - "name": "update[drive]", + "name": "drive", "in": "body", "description": "Drive number", "required": true, @@ -3336,7 +3379,7 @@ } }, { - "name": "update[storageid]", + "name": "storageid", "in": "body", "description": "Storage identifier", "required": true, @@ -3346,7 +3389,7 @@ } }, { - "name": "update[storage]", + "name": "storage", "in": "body", "description": "Storage name can be used instead of storageid", "required": true, @@ -3358,7 +3401,7 @@ ] } }, - "/api/v1/filesets": { + "/api/v2/filesets": { "get": { "tags": ["filesets"], "summary": "FileSet list", @@ -3390,7 +3433,7 @@ }] } }, - "/api/v1/filesets/{filesetid}": { + "/api/v2/filesets/{filesetid}": { "get": { "tags": ["filesets"], "summary": "Find FileSet by FileSetId", @@ -3422,7 +3465,7 @@ }] } }, - "/api/v1/filesets/resnames": { + "/api/v2/filesets/resnames": { "get": { "tags": ["filesets"], "summary": "FileSet resource names", @@ -3455,7 +3498,7 @@ } } }, - "/api/v1/schedules/resnames": { + "/api/v2/schedules/resnames": { "get": { "tags": ["schedules"], "summary": "Schedule resource names", @@ -3488,7 +3531,7 @@ } } }, - "/api/v1/schedules/status": { + "/api/v2/schedules/status": { "get": { "tags": ["schedules"], "summary": "Schedule status", @@ -3580,12 +3623,12 @@ ] } }, - "/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", @@ -3614,7 +3657,7 @@ } } }, - "/api/v1/bvfs/lsdirs": { + "/api/v2/bvfs/lsdirs": { "get": { "tags": ["bvfs"], "summary": "BVFS list directories", @@ -3697,7 +3740,7 @@ ] } }, - "/api/v1/bvfs/lsfiles": { + "/api/v2/bvfs/lsfiles": { "get": { "tags": ["bvfs"], "summary": "BVFS list files", @@ -3780,7 +3823,7 @@ ] } }, - "/api/v1/bvfs/versions": { + "/api/v2/bvfs/versions": { "get": { "tags": ["bvfs"], "summary": "BVFS list file versions", @@ -3873,7 +3916,7 @@ ] } }, - "/api/v1/bvfs/getjobids": { + "/api/v2/bvfs/getjobids": { "get": { "tags": ["bvfs"], "summary": "BVFS get particular jobids to restore", @@ -3917,11 +3960,11 @@ ] } }, - "/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": { @@ -3951,7 +3994,7 @@ }, "parameters": [ { - "name": "create[path]", + "name": "path", "in": "body", "description": "Path in format b2[0-9]+", "required": true, @@ -3960,7 +4003,7 @@ } }, { - "name": "create[jobids]", + "name": "jobids", "in": "body", "description": "Comma separated job identifiers", "required": true, @@ -3969,7 +4012,7 @@ } }, { - "name": "create[fileid]", + "name": "fileid", "in": "body", "description": "Comma seprated file identifiers", "required": false, @@ -3978,7 +4021,7 @@ } }, { - "name": "create[dirid]", + "name": "dirid", "in": "body", "description": "Comma seprated directory identifiers", "required": false, @@ -3987,7 +4030,7 @@ } }, { - "name": "create[findex]", + "name": "findex", "in": "body", "description": "Comma seprated directory file indexes", "required": false, @@ -3998,12 +4041,12 @@ ] } }, - "/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", @@ -4032,12 +4075,12 @@ } } }, - "/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", @@ -4066,7 +4109,7 @@ }, "parameters": [ { - "name": "update[path]", + "name": "path", "in": "body", "description": "Path in format b2[0-9]+", "required": true, @@ -4077,7 +4120,7 @@ ] } }, - "/api/v1/config": { + "/api/v2/config": { "get": { "tags": ["config"], "summary": "Get components information", @@ -4127,7 +4170,7 @@ } } }, - "/api/v1/config/{component_type}": { + "/api/v2/config/{component_type}": { "get": { "tags": ["config"], "summary": "Get component config", @@ -4168,7 +4211,7 @@ "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", @@ -4197,7 +4240,7 @@ "$ref": "#/components/parameters/ComponentType" }, { - "name": "update[config]", + "name": "config", "in": "body", "description": "Config in JSON form to set", "required": true, @@ -4208,7 +4251,7 @@ ] } }, - "/api/v1/config/{component_type}/{resource_type}": { + "/api/v2/config/{component_type}/{resource_type}": { "get": { "tags": ["config"], "summary": "Get component resources config", @@ -4252,7 +4295,7 @@ "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", @@ -4284,7 +4327,7 @@ "$ref": "#/components/parameters/ResourceType" }, { - "name": "update[config]", + "name": "config", "in": "body", "description": "Config in JSON form to set", "required": true, @@ -4295,7 +4338,7 @@ ] } }, - "/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", @@ -4342,7 +4385,7 @@ "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", @@ -4377,7 +4420,7 @@ "$ref": "#/components/parameters/ResourceName" }, { - "name": "update[config]", + "name": "config", "in": "body", "description": "Config in JSON form to set", "required": true, @@ -4388,7 +4431,7 @@ ] } }, - "/api/v1/joblog/{jobid}": { + "/api/v2/joblog/{jobid}": { "get": { "tags": ["joblog"], "summary": "Get job log for jobid", @@ -4433,7 +4476,7 @@ }] } }, - "/api/v1/joblog/messages": { + "/api/v2/joblog/messages": { "get": { "tags": ["joblog"], "summary": "Get console messages log.", @@ -4476,9 +4519,9 @@ }] } }, - "/api/v1/status/director": { + "/api/v2/directors/{director_name}/status": { "get": { - "tags": ["status"], + "tags": ["directors"], "summary": "Get director status", "description": "Get director status", "responses": { @@ -4759,652 +4802,30 @@ }, "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", @@ -5433,7 +4854,7 @@ } } }, - "/api/v1/oauth2/clients/{client_id}": { + "/api/v2/oauth2/clients/{client_id}": { "get": { "tags": ["oauth2"], "summary": "Specific OAuth2 client account config", @@ -5476,7 +4897,7 @@ "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", @@ -5561,7 +4982,7 @@ "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", diff --git a/gui/baculum/protected/Common/Class/AuthBasic.php b/gui/baculum/protected/Common/Class/AuthBasic.php index ac38351f5..0c5988c29 100644 --- a/gui/baculum/protected/Common/Class/AuthBasic.php +++ b/gui/baculum/protected/Common/Class/AuthBasic.php @@ -3,7 +3,7 @@ * 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 @@ -32,6 +32,11 @@ Prado::using('Application.Common.Class.Interfaces'); */ class AuthBasic extends AuthBase implements AuthModule { + /** + * Generic name (used e.g. in config files). + */ + const NAME = 'basic'; + /** * Request header value pattern. */ diff --git a/gui/baculum/protected/Common/Class/AuthOAuth2.php b/gui/baculum/protected/Common/Class/AuthOAuth2.php index 416eae05c..d77ac5094 100644 --- a/gui/baculum/protected/Common/Class/AuthOAuth2.php +++ b/gui/baculum/protected/Common/Class/AuthOAuth2.php @@ -3,7 +3,7 @@ * 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 @@ -33,6 +33,11 @@ Prado::using('Application.Common.Class.OAuth2'); */ class AuthOAuth2 extends AuthBase implements AuthModule { + /** + * Generic name (used e.g. in config files). + */ + const NAME = 'oauth2'; + /** * Get auth type. * diff --git a/gui/baculum/protected/Common/Class/BClientScript.php b/gui/baculum/protected/Common/Class/BClientScript.php index 5de8b14d5..dc667c763 100644 --- a/gui/baculum/protected/Common/Class/BClientScript.php +++ b/gui/baculum/protected/Common/Class/BClientScript.php @@ -3,7 +3,7 @@ * 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 @@ -31,7 +31,7 @@ Prado::using('System.Web.UI.WebControls.TClientScript'); */ class BClientScript extends TClientScript { - const SCRIPTS_VERSION = 16; + const SCRIPTS_VERSION = 17; public function getScriptUrl() { diff --git a/gui/baculum/protected/Common/Class/BaculumUrlMapping.php b/gui/baculum/protected/Common/Class/BaculumUrlMapping.php index 0c54fd9b9..af774c75a 100644 --- a/gui/baculum/protected/Common/Class/BaculumUrlMapping.php +++ b/gui/baculum/protected/Common/Class/BaculumUrlMapping.php @@ -3,7 +3,7 @@ * 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 @@ -101,8 +101,7 @@ class BaculumUrlMapping extends TUrlMapping { } private function getRequestedUrl() { - $url = $this->getRequest()->getPathInfo(); - return $url; + return $this->getRequest()->getPathInfo(); } } ?> diff --git a/gui/baculum/protected/Web/JavaScript/buttons.colVis.js b/gui/baculum/protected/Common/JavaScript/buttons.colVis.js similarity index 100% rename from gui/baculum/protected/Web/JavaScript/buttons.colVis.js rename to gui/baculum/protected/Common/JavaScript/buttons.colVis.js diff --git a/gui/baculum/protected/Web/JavaScript/buttons.html5.js b/gui/baculum/protected/Common/JavaScript/buttons.html5.js similarity index 100% rename from gui/baculum/protected/Web/JavaScript/buttons.html5.js rename to gui/baculum/protected/Common/JavaScript/buttons.html5.js diff --git a/gui/baculum/protected/Web/JavaScript/dataTables.buttons.js b/gui/baculum/protected/Common/JavaScript/dataTables.buttons.js similarity index 100% rename from gui/baculum/protected/Web/JavaScript/dataTables.buttons.js rename to gui/baculum/protected/Common/JavaScript/dataTables.buttons.js diff --git a/gui/baculum/protected/Web/JavaScript/dataTables.responsive.js b/gui/baculum/protected/Common/JavaScript/dataTables.responsive.js similarity index 100% rename from gui/baculum/protected/Web/JavaScript/dataTables.responsive.js rename to gui/baculum/protected/Common/JavaScript/dataTables.responsive.js diff --git a/gui/baculum/protected/Web/JavaScript/dataTables.select.js b/gui/baculum/protected/Common/JavaScript/dataTables.select.js similarity index 100% rename from gui/baculum/protected/Web/JavaScript/dataTables.select.js rename to gui/baculum/protected/Common/JavaScript/dataTables.select.js diff --git a/gui/baculum/protected/Web/JavaScript/datatables.js b/gui/baculum/protected/Common/JavaScript/datatables.js similarity index 100% rename from gui/baculum/protected/Web/JavaScript/datatables.js rename to gui/baculum/protected/Common/JavaScript/datatables.js diff --git a/gui/baculum/protected/Web/JavaScript/fontawesome.min.js b/gui/baculum/protected/Common/JavaScript/fontawesome.min.js similarity index 100% rename from gui/baculum/protected/Web/JavaScript/fontawesome.min.js rename to gui/baculum/protected/Common/JavaScript/fontawesome.min.js diff --git a/gui/baculum/protected/Common/JavaScript/misc.js b/gui/baculum/protected/Common/JavaScript/misc.js new file mode 100644 index 000000000..73f9ae38d --- /dev/null +++ b/gui/baculum/protected/Common/JavaScript/misc.js @@ -0,0 +1,236 @@ +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(); +}); diff --git a/gui/baculum/protected/Web/JavaScript/responsive.jqueryui.js b/gui/baculum/protected/Common/JavaScript/responsive.jqueryui.js similarity index 100% rename from gui/baculum/protected/Web/JavaScript/responsive.jqueryui.js rename to gui/baculum/protected/Common/JavaScript/responsive.jqueryui.js diff --git a/gui/baculum/protected/Common/Portlets/NewAuthClient.php b/gui/baculum/protected/Common/Portlets/NewAuthClient.php index 212300ad3..409fdd017 100644 --- a/gui/baculum/protected/Common/Portlets/NewAuthClient.php +++ b/gui/baculum/protected/Common/Portlets/NewAuthClient.php @@ -3,7 +3,7 @@ * 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 @@ -20,11 +20,14 @@ * 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'); /** @@ -38,52 +41,102 @@ class NewAuthClient extends 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) { @@ -105,8 +158,23 @@ class NewAuthClient extends PortletTemplate { 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) { diff --git a/gui/baculum/protected/Common/Portlets/NewAuthClient.tpl b/gui/baculum/protected/Common/Portlets/NewAuthClient.tpl index ef20eb4da..f9e4bd13c 100644 --- a/gui/baculum/protected/Common/Portlets/NewAuthClient.tpl +++ b/gui/baculum/protected/Common/Portlets/NewAuthClient.tpl @@ -1,37 +1,47 @@ -
- Validate <%[ User added successfully. ]%> - <%[ Problem during save to config file. Please check users config file permission. ]%> - <%[ Given user already exists in config file. ]%> +
+ <%[ Problem during save to config file. Please check users config file permission. ]%> + <%[ Given user already exists in config file. ]%>
-