From e0d7dbd02e935138dff74123f5cb65134e15025a Mon Sep 17 00:00:00 2001 From: Ivo Kurzemnieks Date: Fri, 3 Jul 2020 17:47:39 +0300 Subject: ..F....... [ZBXNEXT-2754] renamed routes and controllers related XML export to just export, added a new export button with styles and replaced the old export button --- ui/app/controllers/CControllerExport.php | 123 +++++++++++++++++++++ ui/app/controllers/CControllerExportXml.php | 120 -------------------- ui/app/views/administration.mediatype.list.php | 13 +-- ui/app/views/administration.valuemap.list.php | 13 +-- ui/app/views/layout.export.php | 29 +++++ ui/app/views/layout.xml.php | 29 ----- ui/assets/styles/blue-theme.css | 23 +++- ui/assets/styles/dark-theme.css | 23 +++- ui/assets/styles/hc-dark.css | 23 +++- ui/assets/styles/hc-light.css | 23 +++- ui/include/classes/api/services/CConfiguration.php | 4 +- .../export/writers/CExportWriterFactory.php | 23 ++++ ui/include/classes/html/CActionButtonList.php | 62 ++++++----- ui/include/classes/html/CButtonDropdown.php | 3 +- ui/include/classes/html/CButtonExport.php | 57 ++++++++++ ui/include/classes/mvc/CRouter.php | 12 +- ui/include/defines.inc.php | 2 + ui/include/views/configuration.host.list.php | 13 +-- ui/include/views/configuration.template.list.php | 13 +-- ui/include/views/monitoring.screen.list.php | 13 +-- ui/include/views/monitoring.sysmap.list.php | 13 +-- 21 files changed, 397 insertions(+), 237 deletions(-) create mode 100644 ui/app/controllers/CControllerExport.php delete mode 100644 ui/app/controllers/CControllerExportXml.php create mode 100644 ui/app/views/layout.export.php delete mode 100644 ui/app/views/layout.xml.php create mode 100644 ui/include/classes/html/CButtonExport.php (limited to 'ui') diff --git a/ui/app/controllers/CControllerExport.php b/ui/app/controllers/CControllerExport.php new file mode 100644 index 00000000000..c5d6cb551be --- /dev/null +++ b/ui/app/controllers/CControllerExport.php @@ -0,0 +1,123 @@ + 'required|string', + 'backurl' => 'required|string', + 'valuemapids' => 'not_empty|array_db valuemaps.valuemapid', + 'hosts' => 'not_empty|array_db hosts.hostid', + 'mediatypeids' => 'not_empty|array_db media_type.mediatypeid', + 'screens' => 'not_empty|array_db screens.screenid', + 'maps' => 'not_empty|array_db sysmaps.sysmapid', + 'templates' => 'not_empty|array_db hosts.hostid', + 'format' => 'in '.implode(',', [CExportWriterFactory::YAML, CExportWriterFactory::XML, CExportWriterFactory::JSON]) + ]; + + $ret = $this->validateInput($fields); + + if (!$ret) { + $this->setResponse(new CControllerResponseFatal()); + } + + return $ret; + } + + protected function checkPermissions() { + switch ($this->getInput('action')) { + case 'export.mediatypes': + case 'export.valuemaps': + return (CWebUser::$data['type'] >= USER_TYPE_SUPER_ADMIN); + + case 'export.hosts': + case 'export.templates': + return (CWebUser::$data['type'] >= USER_TYPE_ZABBIX_ADMIN); + + case 'export.screens': + case 'export.sysmaps': + return (CWebUser::$data['type'] >= USER_TYPE_ZABBIX_USER); + + default: + return false; + } + } + + protected function doAction() { + $action = $this->getInput('action'); + $format = $this->getInput('format', CExportWriterFactory::YAML); + + switch ($action) { + case 'export.valuemaps': + $export = new CConfigurationExport(['valueMaps' => $this->getInput('valuemapids', [])]); + break; + + case 'export.hosts': + $export = new CConfigurationExport(['hosts' => $this->getInput('hosts', [])]); + break; + + case 'export.mediatypes': + $export = new CConfigurationExport(['mediaTypes' => $this->getInput('mediatypeids', [])]); + break; + + case 'export.screens': + $export = new CConfigurationExport(['screens' => $this->getInput('screens', [])]); + break; + + case 'export.sysmaps': + $export = new CConfigurationExport(['maps' => $this->getInput('maps', [])]); + break; + + case 'export.templates': + $export = new CConfigurationExport(['templates' => $this->getInput('templates', [])]); + break; + + default: + $this->setResponse(new CControllerResponseFatal()); + + return; + } + + $export->setBuilder(new CConfigurationExportBuilder()); + $export->setWriter(CExportWriterFactory::getWriter($format)); + + $export_data = $export->export(); + + if ($export_data === false) { + // Access denied. + + $response = new CControllerResponseRedirect( + $this->getInput('backurl', 'zabbix.php?action=dashboard.view')); + + $response->setMessageError(_('No permissions to referred object or it does not exist!')); + } + else { + $response = new CControllerResponseData([ + 'main_block' => $export_data, + 'content_type' => CExportWriterFactory::getContentType($format), + 'page' => ['file' => 'zbx_export_'.substr($action, 7).'.'.$format] + ]); + } + + $this->setResponse($response); + } +} diff --git a/ui/app/controllers/CControllerExportXml.php b/ui/app/controllers/CControllerExportXml.php deleted file mode 100644 index 6b1238b7008..00000000000 --- a/ui/app/controllers/CControllerExportXml.php +++ /dev/null @@ -1,120 +0,0 @@ - 'required|string', - 'backurl' => 'required|string', - 'valuemapids' => 'not_empty|array_db valuemaps.valuemapid', - 'hosts' => 'not_empty|array_db hosts.hostid', - 'mediatypeids' => 'not_empty|array_db media_type.mediatypeid', - 'screens' => 'not_empty|array_db screens.screenid', - 'maps' => 'not_empty|array_db sysmaps.sysmapid', - 'templates' => 'not_empty|array_db hosts.hostid' - ]; - - $ret = $this->validateInput($fields); - - if (!$ret) { - $this->setResponse(new CControllerResponseFatal()); - } - - return $ret; - } - - protected function checkPermissions() { - switch ($this->getInput('action')) { - case 'export.mediatypes.xml': - case 'export.valuemaps.xml': - return (CWebUser::$data['type'] >= USER_TYPE_SUPER_ADMIN); - - case 'export.hosts.xml': - case 'export.templates.xml': - return (CWebUser::$data['type'] >= USER_TYPE_ZABBIX_ADMIN); - - case 'export.screens.xml': - case 'export.sysmaps.xml': - return (CWebUser::$data['type'] >= USER_TYPE_ZABBIX_USER); - - default: - return false; - } - } - - protected function doAction() { - $action = $this->getInput('action'); - - switch ($action) { - case 'export.valuemaps.xml': - $export = new CConfigurationExport(['valueMaps' => $this->getInput('valuemapids', [])]); - break; - - case 'export.hosts.xml': - $export = new CConfigurationExport(['hosts' => $this->getInput('hosts', [])]); - break; - - case 'export.mediatypes.xml': - $export = new CConfigurationExport(['mediaTypes' => $this->getInput('mediatypeids', [])]); - break; - - case 'export.screens.xml': - $export = new CConfigurationExport(['screens' => $this->getInput('screens', [])]); - break; - - case 'export.sysmaps.xml': - $export = new CConfigurationExport(['maps' => $this->getInput('maps', [])]); - break; - - case 'export.templates.xml': - $export = new CConfigurationExport(['templates' => $this->getInput('templates', [])]); - break; - - default: - $this->setResponse(new CControllerResponseFatal()); - - return; - } - - $export->setBuilder(new CConfigurationExportBuilder()); - $export->setWriter(CExportWriterFactory::getWriter(CExportWriterFactory::XML)); - - $export_data = $export->export(); - - if ($export_data === false) { - // Access denied. - - $response = new CControllerResponseRedirect( - $this->getInput('backurl', 'zabbix.php?action=dashboard.view')); - - $response->setMessageError(_('No permissions to referred object or it does not exist!')); - } - else { - $response = new CControllerResponseData([ - 'main_block' => $export_data, - 'page' => ['file' => 'zbx_export_' . substr($action, 7)] - ]); - } - - $this->setResponse($response); - } -} diff --git a/ui/app/views/administration.mediatype.list.php b/ui/app/views/administration.mediatype.list.php index d812ef30675..6f8aa6cec7e 100644 --- a/ui/app/views/administration.mediatype.list.php +++ b/ui/app/views/administration.mediatype.list.php @@ -161,14 +161,13 @@ $mediaTypeForm->addItem([ new CActionButtonList('action', 'mediatypeids', [ 'mediatype.enable' => ['name' => _('Enable'), 'confirm' => _('Enable selected media types?')], 'mediatype.disable' => ['name' => _('Disable'), 'confirm' => _('Disable selected media types?')], - 'mediatype.export' => ['name' => _('Export'), 'redirect' => - (new CUrl('zabbix.php')) - ->setArgument('action', 'export.mediatypes.xml') - ->setArgument('backurl', (new CUrl('zabbix.php')) + 'mediatype.export' => [ + 'content' => new CButtonExport('export.mediatypes', + (new CUrl('zabbix.php')) ->setArgument('action', 'mediatype.list') - ->setArgument('page', $data['page'] == 1 ? null : $data['page']) - ->getUrl()) - ->getUrl() + ->setArgument('page', ($data['page'] == 1) ? null : $data['page']) + ->getUrl() + ) ], 'mediatype.delete' => ['name' => _('Delete'), 'confirm' => _('Delete selected media types?')] ], 'mediatype') diff --git a/ui/app/views/administration.valuemap.list.php b/ui/app/views/administration.valuemap.list.php index df4bb0d9803..1184af2060a 100644 --- a/ui/app/views/administration.valuemap.list.php +++ b/ui/app/views/administration.valuemap.list.php @@ -87,14 +87,13 @@ $form->addItem([ $table, $data['paging'], new CActionButtonList('action', 'valuemapids', [ - 'valuemap.export' => ['name' => _('Export'), 'redirect' => - (new CUrl('zabbix.php')) - ->setArgument('action', 'export.valuemaps.xml') - ->setArgument('backurl', (new CUrl('zabbix.php')) + 'valuemap.export' => [ + 'content' => new CButtonExport('export.valuemaps', + (new CUrl('zabbix.php')) ->setArgument('action', 'valuemap.list') - ->setArgument('page', $data['page'] == 1 ? null : $data['page']) - ->getUrl()) - ->getUrl() + ->setArgument('page', ($data['page'] == 1) ? null : $data['page']) + ->getUrl() + ) ], 'valuemap.delete' => ['name' => _('Delete'), 'confirm' => _('Delete selected value maps?')] ]) diff --git a/ui/app/views/layout.export.php b/ui/app/views/layout.export.php new file mode 100644 index 00000000000..a0db647bb66 --- /dev/null +++ b/ui/app/views/layout.export.php @@ -0,0 +1,29 @@ + API_OBJECT, 'fields' => [ - 'format' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'in' => implode(',', [CExportWriterFactory::XML, CExportWriterFactory::JSON])], + 'format' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'in' => implode(',', [CExportWriterFactory::YAML, CExportWriterFactory::XML, CExportWriterFactory::JSON])], 'options' => ['type' => API_OBJECT, 'flags' => API_REQUIRED, 'fields' => [ 'groups' => ['type' => API_IDS], 'hosts' => ['type' => API_IDS], @@ -69,7 +69,7 @@ class CConfiguration extends CApiService { */ public function import($params) { $api_input_rules = ['type' => API_OBJECT, 'fields' => [ - 'format' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'in' => implode(',', [CImportReaderFactory::XML, CImportReaderFactory::JSON])], + 'format' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'in' => implode(',', [CExportWriterFactory::YAML, CImportReaderFactory::XML, CImportReaderFactory::JSON])], 'source' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED], 'rules' => ['type' => API_OBJECT, 'flags' => API_REQUIRED, 'fields' => [ 'applications' => ['type' => API_OBJECT, 'fields' => [ diff --git a/ui/include/classes/export/writers/CExportWriterFactory.php b/ui/include/classes/export/writers/CExportWriterFactory.php index ed36c368f9f..12150399bdb 100644 --- a/ui/include/classes/export/writers/CExportWriterFactory.php +++ b/ui/include/classes/export/writers/CExportWriterFactory.php @@ -23,6 +23,7 @@ class CExportWriterFactory { const XML = 'xml'; const JSON = 'json'; + const YAML = 'yml'; /** * Get the writer object for specified type. @@ -42,6 +43,28 @@ class CExportWriterFactory { case self::JSON: return new CJsonExportWriter(); + case self::YAML: + return null; + + default: + throw new Exception('Incorrect export writer type.'); + } + } + + public static function getContentType($type) { + switch ($type) { + case self::XML: + // See https://www.ietf.org/rfc/rfc2376.txt + return 'text/xml'; + + case self::JSON: + // See https://www.ietf.org/rfc/rfc4627.txt + return 'application/json'; + + case self::YAML: + // See https://github.com/rails/rails/blob/d41d586/actionpack/lib/action_dispatch/http/mime_types.rb#L39 + return 'text/yaml'; + default: throw new Exception('Incorrect export writer type.'); } diff --git a/ui/include/classes/html/CActionButtonList.php b/ui/include/classes/html/CActionButtonList.php index 11aef41e777..87a13d7d470 100644 --- a/ui/include/classes/html/CActionButtonList.php +++ b/ui/include/classes/html/CActionButtonList.php @@ -61,6 +61,7 @@ class CActionButtonList extends CObject { * @param string $buttons_data[]['name'] Button caption. * @param string $buttons_data[]['confirm'] Confirmation text (optional). * @param string $buttons_data[]['redirect'] Redirect URL (optional). + * @param CTag $buttons_data[]['content'] A HTML tag. For example a CButton wrapped in CList object. * @param string|null $name_prefix Prefix for sessionStorage used for storing currently selected * checkboxes. */ @@ -69,36 +70,41 @@ class CActionButtonList extends CObject { $this->name_prefix = $name_prefix ? $name_prefix : null; foreach ($buttons_data as $action => $button_data) { - $button = (new CSubmit($action_name, $button_data['name'])) - ->addClass(ZBX_STYLE_BTN_ALT) - ->removeAttribute('id'); - - if (array_key_exists('redirect', $button_data)) { - $button - // Removing parameters not to conflict with the redirecting URL. - ->removeAttribute('name') - ->removeAttribute('value') - ->onClick('var $_form = jQuery(this).closest("form");'. - // Save the original form action. - 'if (!$_form.data("action")) {'. - '$_form.data("action", $_form.attr("action"));'. - '}'. - '$_form.attr("action", '.json_encode($button_data['redirect']).');' - ); + if (array_key_exists('content', $button_data)) { + $button = $button_data['content']; } else { - $button - ->setAttribute('value', $action) - ->onClick('var $_form = jQuery(this).closest("form");'. - // Restore the original form action, if previously saved. - 'if ($_form.data("action")) {'. - '$_form.attr("action", $_form.data("action"));'. - '}' - ); - } - - if (array_key_exists('confirm', $button_data)) { - $button->setAttribute('confirm', $button_data['confirm']); + $button = (new CSubmit($action_name, $button_data['name'])) + ->addClass(ZBX_STYLE_BTN_ALT) + ->removeAttribute('id'); + + if (array_key_exists('redirect', $button_data)) { + $button + // Removing parameters not to conflict with the redirecting URL. + ->removeAttribute('name') + ->removeAttribute('value') + ->onClick('var $_form = jQuery(this).closest("form");'. + // Save the original form action. + 'if (!$_form.data("action")) {'. + '$_form.data("action", $_form.attr("action"));'. + '}'. + '$_form.attr("action", '.json_encode($button_data['redirect']).');' + ); + } + else { + $button + ->setAttribute('value', $action) + ->onClick('var $_form = jQuery(this).closest("form");'. + // Restore the original form action, if previously saved. + 'if ($_form.data("action")) {'. + '$_form.attr("action", $_form.data("action"));'. + '}' + ); + } + + if (array_key_exists('confirm', $button_data)) { + $button->setAttribute('confirm', $button_data['confirm']); + } } $this->buttons[$action] = $button; diff --git a/ui/include/classes/html/CButtonDropdown.php b/ui/include/classes/html/CButtonDropdown.php index b90f50e225b..63256d1d947 100644 --- a/ui/include/classes/html/CButtonDropdown.php +++ b/ui/include/classes/html/CButtonDropdown.php @@ -29,7 +29,6 @@ class CButtonDropdown extends CButton { /** * Button style names. */ - public const ZBX_STYLE_BTN_TOGGLE = 'btn-dropdown-toggle'; public const ZBX_STYLE_BTN_VALUE = 'dropdown-value'; /** @@ -54,7 +53,7 @@ class CButtonDropdown extends CButton { $this->setId(uniqid('btn-dropdown-')); $this->addClass(ZBX_STYLE_BTN_ALT); - $this->addClass(self::ZBX_STYLE_BTN_TOGGLE); + $this->addClass(ZBX_STYLE_BTN_TOGGLE); $this->dropdown_items = $items; if ($value !== null) { diff --git a/ui/include/classes/html/CButtonExport.php b/ui/include/classes/html/CButtonExport.php new file mode 100644 index 00000000000..4ee58a0c3a0 --- /dev/null +++ b/ui/include/classes/html/CButtonExport.php @@ -0,0 +1,57 @@ +removeAttribute('id') + ->removeAttribute('name') + ->removeAttribute('value') + ->addClass(ZBX_STYLE_BTN_ALT) + ->onClick('var $_form = jQuery(this).closest("form");'. + // Save the original form action. + 'if (!$_form.data("action")) {'. + '$_form.data("action", $_form.attr("action"));'. + '}'. + '$_form.attr("action", '.json_encode( + (new CUrl('zabbix.php')) + ->setArgument('action', $action) + ->setArgument('format', CExportWriterFactory::XML) + ->setArgument('backurl', $back_url) + ->getUrl() + ).');' + ), + (new CButton('export')) + ->addClass(ZBX_STYLE_BTN_ALT) + ->addClass(ZBX_STYLE_BTN_TOGGLE) + ]); + + $this->addClass(ZBX_STYLE_BTN_SPLIT); + } +} diff --git a/ui/include/classes/mvc/CRouter.php b/ui/include/classes/mvc/CRouter.php index 3fdb49db5b5..758a38580cd 100644 --- a/ui/include/classes/mvc/CRouter.php +++ b/ui/include/classes/mvc/CRouter.php @@ -78,12 +78,12 @@ class CRouter { 'dashboard.widget.rfrate' => ['CControllerDashboardWidgetRfRate', 'layout.json', null], 'dashboard.widget.sanitize' => ['CControllerDashboardWidgetSanitize', 'layout.json', null], 'discovery.view' => ['CControllerDiscoveryView', 'layout.htmlpage', 'monitoring.discovery.view'], - 'export.hosts.xml' => ['CControllerExportXml', 'layout.xml', null], - 'export.mediatypes.xml' => ['CControllerExportXml', 'layout.xml', null], - 'export.screens.xml' => ['CControllerExportXml', 'layout.xml', null], - 'export.sysmaps.xml' => ['CControllerExportXml', 'layout.xml', null], - 'export.templates.xml' => ['CControllerExportXml', 'layout.xml', null], - 'export.valuemaps.xml' => ['CControllerExportXml', 'layout.xml', null], + 'export.hosts' => ['CControllerExport', 'layout.export', null], + 'export.mediatypes' => ['CControllerExport', 'layout.export', null], + 'export.screens' => ['CControllerExport', 'layout.export', null], + 'export.sysmaps' => ['CControllerExport', 'layout.export', null], + 'export.templates' => ['CControllerExport', 'layout.export', null], + 'export.valuemaps' => ['CControllerExport', 'layout.export', null], 'favourite.create' => ['CControllerFavouriteCreate', 'layout.javascript', null], 'favourite.delete' => ['CControllerFavouriteDelete', 'layout.javascript', null], 'gui.edit' => ['CControllerGuiEdit', 'layout.htmlpage', 'administration.gui.edit'], diff --git a/ui/include/defines.inc.php b/ui/include/defines.inc.php index f33397d04df..bd07e20cd98 100644 --- a/ui/include/defines.inc.php +++ b/ui/include/defines.inc.php @@ -1570,6 +1570,8 @@ define('ZBX_STYLE_ARROW_UP', 'arrow-up'); define('ZBX_STYLE_BLUE', 'blue'); define('ZBX_STYLE_BTN_ADD_FAV', 'btn-add-fav'); define('ZBX_STYLE_BTN_ALT', 'btn-alt'); +define('ZBX_STYLE_BTN_SPLIT', 'btn-split'); +define('ZBX_STYLE_BTN_TOGGLE', 'btn-dropdown-toggle'); define('ZBX_STYLE_BTN_BACK_MAP', 'btn-back-map'); define('ZBX_STYLE_BTN_BACK_MAP_CONTAINER', 'btn-back-map-container'); define('ZBX_STYLE_BTN_BACK_MAP_CONTENT', 'btn-back-map-content'); diff --git a/ui/include/views/configuration.host.list.php b/ui/include/views/configuration.host.list.php index c3e08f229de..510a368e6bb 100644 --- a/ui/include/views/configuration.host.list.php +++ b/ui/include/views/configuration.host.list.php @@ -466,13 +466,12 @@ $form->addItem([ [ 'host.massenable' => ['name' => _('Enable'), 'confirm' => _('Enable selected hosts?')], 'host.massdisable' => ['name' => _('Disable'), 'confirm' => _('Disable selected hosts?')], - 'host.export' => ['name' => _('Export'), 'redirect' => - (new CUrl('zabbix.php')) - ->setArgument('action', 'export.hosts.xml') - ->setArgument('backurl', (new CUrl('hosts.php')) - ->setArgument('page', $data['page'] == 1 ? null : $data['page']) - ->getUrl()) - ->getUrl() + 'host.export' => [ + 'content' => new CButtonExport('export.hosts', + (new CUrl('hosts.php')) + ->setArgument('page', ($data['page'] == 1) ? null : $data['page']) + ->getUrl() + ) ], 'host.massupdateform' => ['name' => _('Mass update')], 'host.massdelete' => ['name' => _('Delete'), 'confirm' => _('Delete selected hosts?')] diff --git a/ui/include/views/configuration.template.list.php b/ui/include/views/configuration.template.list.php index da7b56faf3e..8b35412c0b2 100644 --- a/ui/include/views/configuration.template.list.php +++ b/ui/include/views/configuration.template.list.php @@ -311,13 +311,12 @@ $form->addItem([ $data['paging'], new CActionButtonList('action', 'templates', [ - 'template.export' => ['name' => _('Export'), 'redirect' => - (new CUrl('zabbix.php')) - ->setArgument('action', 'export.templates.xml') - ->setArgument('backurl', (new CUrl('templates.php')) - ->setArgument('page', $data['page'] == 1 ? null : $data['page']) - ->getUrl()) - ->getUrl() + 'template.export' => [ + 'content' => new CButtonExport('export.templates', + (new CUrl('templates.php')) + ->setArgument('page', ($data['page'] == 1) ? null : $data['page']) + ->getUrl() + ) ], 'template.massupdateform' => ['name' => _('Mass update')], 'template.massdelete' => ['name' => _('Delete'), 'confirm' => _('Delete selected templates?')], diff --git a/ui/include/views/monitoring.screen.list.php b/ui/include/views/monitoring.screen.list.php index 4d53f7359a6..cd669a4e130 100644 --- a/ui/include/views/monitoring.screen.list.php +++ b/ui/include/views/monitoring.screen.list.php @@ -121,13 +121,12 @@ foreach ($data['screens'] as $screen) { $buttons = []; if (!$data['templateid']) { - $buttons['screen.export'] = ['name' => _('Export'), 'redirect' => - (new CUrl('zabbix.php')) - ->setArgument('action', 'export.screens.xml') - ->setArgument('backurl', (new CUrl('screenconf.php')) - ->setArgument('page', $data['page'] == 1 ? null : $data['page']) - ->getUrl()) - ->getUrl() + $buttons['screen.export'] = [ + 'content' => new CButtonExport('export.screens', + (new CUrl('screenconf.php')) + ->setArgument('page', ($data['page'] == 1) ? null : $data['page']) + ->getUrl() + ) ]; } diff --git a/ui/include/views/monitoring.sysmap.list.php b/ui/include/views/monitoring.sysmap.list.php index f77680965ad..30b5b05ed4d 100644 --- a/ui/include/views/monitoring.sysmap.list.php +++ b/ui/include/views/monitoring.sysmap.list.php @@ -94,13 +94,12 @@ $sysmapForm->addItem([ $sysmapTable, $this->data['paging'], new CActionButtonList('action', 'maps', [ - 'map.export' => ['name' => _('Export'), 'redirect' => - (new CUrl('zabbix.php')) - ->setArgument('action', 'export.sysmaps.xml') - ->setArgument('backurl', (new CUrl('sysmaps.php')) - ->setArgument('page', $data['page'] == 1 ? null : $data['page']) - ->getUrl()) - ->getUrl() + 'map.export' => [ + 'content' => new CButtonExport('export.sysmaps', + (new CUrl('sysmaps.php')) + ->setArgument('page', ($data['page'] == 1) ? null : $data['page']) + ->getUrl() + ) ], 'map.massdelete' => ['name' => _('Delete'), 'confirm' => _('Delete selected maps?')] ]) -- cgit v1.2.3 From f0fff69ec4634b44aa5d6b600b00a49734f718e0 Mon Sep 17 00:00:00 2001 From: Ivo Kurzemnieks Date: Tue, 7 Jul 2020 14:50:15 +0300 Subject: ..F....... [ZBXNEXT-2754] changed split button elements to inline blocks, added another callback to dropdown menu, changed default format to YAML, removed unused defines --- ui/assets/styles/blue-theme.css | 28 +++++++++++----------- ui/assets/styles/dark-theme.css | 28 +++++++++++----------- ui/assets/styles/hc-dark.css | 28 +++++++++++----------- ui/assets/styles/hc-light.css | 28 +++++++++++----------- ui/include/classes/html/CButtonDropdown.php | 5 +++- ui/include/classes/html/CButtonExport.php | 36 +++++++++++++++++++++++++++-- ui/include/debug.inc.php | 2 +- ui/include/defines.inc.php | 10 -------- ui/js/init.js | 3 +-- ui/js/menupopup.js | 33 +++++++++++++++++++++----- 10 files changed, 123 insertions(+), 78 deletions(-) (limited to 'ui') diff --git a/ui/assets/styles/blue-theme.css b/ui/assets/styles/blue-theme.css index 06e335f47ea..7fe4b24bd04 100644 --- a/ui/assets/styles/blue-theme.css +++ b/ui/assets/styles/blue-theme.css @@ -5443,20 +5443,20 @@ table.preprocessing-test-results .rel-container { background-position: -399px -510px; } .btn-split { - display: inline-flex; + display: inline-block; position: relative; - vertical-align: top; } - .btn-split li button { - margin: 0 -1px 0 0; - border-radius: 0; } - .btn-split li:first-child button { - border-radius: 2px 0 0 2px; } - .btn-split li:last-child button { - border-radius: 0 2px 2px 0; - margin-right: 10px; } - .btn-split li:only-child button { - border-radius: 2px; - margin-right: 10px; } + margin-right: 10px; } + .btn-split li { + display: inline-block; } + .btn-split li button { + margin: 0 -1px 0 0; + border-radius: 0; } + .btn-split li:first-child button { + border-radius: 2px 0 0 2px; } + .btn-split li:last-child button { + border-radius: 0 2px 2px 0; } + .btn-split li:only-child button { + border-radius: 2px; } .btn-dropdown-toggle { white-space: nowrap; @@ -5478,7 +5478,7 @@ table.preprocessing-test-results .rel-container { .btn-dropdown-toggle::after { position: absolute; top: 7px; - right: 17px; + right: 6px; width: 10px; height: 10px; content: ''; diff --git a/ui/assets/styles/dark-theme.css b/ui/assets/styles/dark-theme.css index c2730e9ef11..4ad027f3465 100644 --- a/ui/assets/styles/dark-theme.css +++ b/ui/assets/styles/dark-theme.css @@ -5454,20 +5454,20 @@ table.preprocessing-test-results .rel-container { background-position: -399px -510px; } .btn-split { - display: inline-flex; + display: inline-block; position: relative; - vertical-align: top; } - .btn-split li button { - margin: 0 -1px 0 0; - border-radius: 0; } - .btn-split li:first-child button { - border-radius: 2px 0 0 2px; } - .btn-split li:last-child button { - border-radius: 0 2px 2px 0; - margin-right: 10px; } - .btn-split li:only-child button { - border-radius: 2px; - margin-right: 10px; } + margin-right: 10px; } + .btn-split li { + display: inline-block; } + .btn-split li button { + margin: 0 -1px 0 0; + border-radius: 0; } + .btn-split li:first-child button { + border-radius: 2px 0 0 2px; } + .btn-split li:last-child button { + border-radius: 0 2px 2px 0; } + .btn-split li:only-child button { + border-radius: 2px; } .btn-dropdown-toggle { white-space: nowrap; @@ -5489,7 +5489,7 @@ table.preprocessing-test-results .rel-container { .btn-dropdown-toggle::after { position: absolute; top: 7px; - right: 17px; + right: 6px; width: 10px; height: 10px; content: ''; diff --git a/ui/assets/styles/hc-dark.css b/ui/assets/styles/hc-dark.css index aaadf43ca8d..6c96b825f42 100644 --- a/ui/assets/styles/hc-dark.css +++ b/ui/assets/styles/hc-dark.css @@ -5398,20 +5398,20 @@ table.preprocessing-test-results .rel-container { background-position: -399px -510px; } .btn-split { - display: inline-flex; + display: inline-block; position: relative; - vertical-align: top; } - .btn-split li button { - margin: 0 -1px 0 0; - border-radius: 0; } - .btn-split li:first-child button { - border-radius: 2px 0 0 2px; } - .btn-split li:last-child button { - border-radius: 0 2px 2px 0; - margin-right: 10px; } - .btn-split li:only-child button { - border-radius: 2px; - margin-right: 10px; } + margin-right: 10px; } + .btn-split li { + display: inline-block; } + .btn-split li button { + margin: 0 -1px 0 0; + border-radius: 0; } + .btn-split li:first-child button { + border-radius: 2px 0 0 2px; } + .btn-split li:last-child button { + border-radius: 0 2px 2px 0; } + .btn-split li:only-child button { + border-radius: 2px; } .btn-dropdown-toggle { white-space: nowrap; @@ -5433,7 +5433,7 @@ table.preprocessing-test-results .rel-container { .btn-dropdown-toggle::after { position: absolute; top: 7px; - right: 17px; + right: 6px; width: 10px; height: 10px; content: ''; diff --git a/ui/assets/styles/hc-light.css b/ui/assets/styles/hc-light.css index 1887eb9b5df..2bb51ef030e 100644 --- a/ui/assets/styles/hc-light.css +++ b/ui/assets/styles/hc-light.css @@ -5398,20 +5398,20 @@ table.preprocessing-test-results .rel-container { background-position: -399px -510px; } .btn-split { - display: inline-flex; + display: inline-block; position: relative; - vertical-align: top; } - .btn-split li button { - margin: 0 -1px 0 0; - border-radius: 0; } - .btn-split li:first-child button { - border-radius: 2px 0 0 2px; } - .btn-split li:last-child button { - border-radius: 0 2px 2px 0; - margin-right: 10px; } - .btn-split li:only-child button { - border-radius: 2px; - margin-right: 10px; } + margin-right: 10px; } + .btn-split li { + display: inline-block; } + .btn-split li button { + margin: 0 -1px 0 0; + border-radius: 0; } + .btn-split li:first-child button { + border-radius: 2px 0 0 2px; } + .btn-split li:last-child button { + border-radius: 0 2px 2px 0; } + .btn-split li:only-child button { + border-radius: 2px; } .btn-dropdown-toggle { white-space: nowrap; @@ -5433,7 +5433,7 @@ table.preprocessing-test-results .rel-container { .btn-dropdown-toggle::after { position: absolute; top: 7px; - right: 17px; + right: 6px; width: 10px; height: 10px; content: ''; diff --git a/ui/include/classes/html/CButtonDropdown.php b/ui/include/classes/html/CButtonDropdown.php index 63256d1d947..4ca0518716d 100644 --- a/ui/include/classes/html/CButtonDropdown.php +++ b/ui/include/classes/html/CButtonDropdown.php @@ -73,7 +73,10 @@ class CButtonDropdown extends CButton { ->setId(zbx_formatDomId($name.'[btn]')) ->setMenuPopup([ 'type' => 'dropdown', - 'data' => ['items' => $this->dropdown_items] + 'data' => [ + 'items' => $this->dropdown_items, + 'toggle_class' => ZBX_STYLE_BTN_TOGGLE + ] ])) ->addItem((new CInput('hidden', $name, $this->getAttribute('value'))) ->addClass(self::ZBX_STYLE_BTN_VALUE) diff --git a/ui/include/classes/html/CButtonExport.php b/ui/include/classes/html/CButtonExport.php index 4ee58a0c3a0..3b993eca24c 100644 --- a/ui/include/classes/html/CButtonExport.php +++ b/ui/include/classes/html/CButtonExport.php @@ -42,14 +42,46 @@ class CButtonExport extends CList { '$_form.attr("action", '.json_encode( (new CUrl('zabbix.php')) ->setArgument('action', $action) - ->setArgument('format', CExportWriterFactory::XML) + ->setArgument('format', CExportWriterFactory::YAML) ->setArgument('backurl', $back_url) ->getUrl() ).');' ), - (new CButton('export')) + (new CButton('export', '​')) ->addClass(ZBX_STYLE_BTN_ALT) ->addClass(ZBX_STYLE_BTN_TOGGLE) + ->setMenuPopup([ + 'type' => 'dropdown', + 'data' => [ + 'submit_form' => true, + 'items' => [ + [ + 'label' => _('YAML'), + 'url' => (new CUrl('zabbix.php')) + ->setArgument('action', $action) + ->setArgument('format', CExportWriterFactory::YAML) + ->setArgument('backurl', $back_url) + ->getUrl() + ], + [ + 'label' => _('XML'), + 'url' => (new CUrl('zabbix.php')) + ->setArgument('action', $action) + ->setArgument('format', CExportWriterFactory::XML) + ->setArgument('backurl', $back_url) + ->getUrl() + ], + [ + 'label' => _('JSON'), + 'url' => (new CUrl('zabbix.php')) + ->setArgument('action', $action) + ->setArgument('format', CExportWriterFactory::JSON) + ->setArgument('backurl', $back_url) + ->getUrl() + ] + ] + ] + ]) ]); $this->addClass(ZBX_STYLE_BTN_SPLIT); diff --git a/ui/include/debug.inc.php b/ui/include/debug.inc.php index 00fcf9ccef5..07152c8bb44 100644 --- a/ui/include/debug.inc.php +++ b/ui/include/debug.inc.php @@ -97,7 +97,7 @@ function sdFile($data, $persist = false, $fileName = 'debug.txt') { fclose($fileStream); } -function sdff($msg, $fileName = '/tmp/zabbix.log') { +function sdff($msg, $fileName = 'C:/Development/zabbix-src/feature/ZBXNEXT-2754-5.1/ui/conf/log.txt') { $fileStreem = @fopen($fileName, 'a'); if (is_array($msg)) { $toImplode = []; diff --git a/ui/include/defines.inc.php b/ui/include/defines.inc.php index bd07e20cd98..a6a1bad8a7e 100644 --- a/ui/include/defines.inc.php +++ b/ui/include/defines.inc.php @@ -1267,16 +1267,6 @@ define('SERVER_CHECK_INTERVAL', 10); define('DATE_TIME_FORMAT_SECONDS_XML', 'Y-m-d\TH:i:s\Z'); -// XML export|import tags -define('XML_TAG_MACRO', 'macro'); -define('XML_TAG_HOST', 'host'); -define('XML_TAG_HOSTINVENTORY', 'host_inventory'); -define('XML_TAG_ITEM', 'item'); -define('XML_TAG_TRIGGER', 'trigger'); -define('XML_TAG_GRAPH', 'graph'); -define('XML_TAG_GRAPH_ELEMENT', 'graph_element'); -define('XML_TAG_DEPENDENCY', 'dependency'); - define('ZBX_DEFAULT_IMPORT_HOST_GROUP', 'Imported hosts'); // XML import flags diff --git a/ui/js/init.js b/ui/js/init.js index 5db35d0761b..0a5b2b9020f 100644 --- a/ui/js/init.js +++ b/ui/js/init.js @@ -255,8 +255,7 @@ jQuery(function($) { return { of: $obj, my: 'left top', - at: 'left top+24', - collision: 'none' + at: 'left bottom' }; case 'submenu': diff --git a/ui/js/menupopup.js b/ui/js/menupopup.js index 6a814ab7fe1..1a7c9906907 100644 --- a/ui/js/menupopup.js +++ b/ui/js/menupopup.js @@ -915,20 +915,41 @@ function getMenuPopupDropdown(options, trigger_elem) { var items = []; jQuery.each(options.items, function(i, item) { - items.push({ + var row = { label: item.label, - url: item.url || 'javascript:void(0);', - class: item.class, - clickCallback: () => { + url: item.url || 'javascript:void(0);' + }; + + if (item.class) { + row.class = item.class; + } + + if (options.toggle_class) { + row.clickCallback = () => { jQuery(trigger_elem) .removeClass() - .addClass(['btn-alt', 'btn-dropdown-toggle', item.class].join(' ')); + .addClass(['btn-alt', options.toggle_class, item.class].join(' ')); jQuery('input[type=hidden]', jQuery(trigger_elem).parent()) .val(item.value) .trigger('change'); } - }); + } + else if (options.submit_form) { + row.url = 'javascript:void(0);'; + row.clickCallback = () => { + var $_form = trigger_elem.closest('form'); + + if (!$_form.data("action")) { + $_form.data("action", $_form.attr("action")); + } + + $_form.attr("action", item.url); + $_form.submit(); + } + } + + items.push(row); }); return [{ -- cgit v1.2.3 From 0570e373f39b3dd0dd025d5b77ef75f424784725 Mon Sep 17 00:00:00 2001 From: Ivo Kurzemnieks Date: Tue, 7 Jul 2020 14:53:09 +0300 Subject: ..F....... [ZBXNEXT-2754] reverted changes made in debug --- ui/include/debug.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ui') diff --git a/ui/include/debug.inc.php b/ui/include/debug.inc.php index 07152c8bb44..00fcf9ccef5 100644 --- a/ui/include/debug.inc.php +++ b/ui/include/debug.inc.php @@ -97,7 +97,7 @@ function sdFile($data, $persist = false, $fileName = 'debug.txt') { fclose($fileStream); } -function sdff($msg, $fileName = 'C:/Development/zabbix-src/feature/ZBXNEXT-2754-5.1/ui/conf/log.txt') { +function sdff($msg, $fileName = '/tmp/zabbix.log') { $fileStreem = @fopen($fileName, 'a'); if (is_array($msg)) { $toImplode = []; -- cgit v1.2.3 From 68e9eb53eed6b2d1ede1f014ba80f6ac53826912 Mon Sep 17 00:00:00 2001 From: Ivo Kurzemnieks Date: Wed, 8 Jul 2020 16:54:38 +0300 Subject: A......... [ZBXNEXT-2754] added YAML import/export writer and reader --- .../export/writers/CExportWriterFactory.php | 16 +++---- .../classes/export/writers/CYamlExportWriter.php | 37 +++++++++++++++ .../import/readers/CImportReaderFactory.php | 16 +++++-- .../classes/import/readers/CYamlImportReader.php | 54 ++++++++++++++++++++++ .../import/validators/CXmlValidatorGeneral.php | 5 +- 5 files changed, 115 insertions(+), 13 deletions(-) create mode 100644 ui/include/classes/export/writers/CYamlExportWriter.php create mode 100644 ui/include/classes/import/readers/CYamlImportReader.php (limited to 'ui') diff --git a/ui/include/classes/export/writers/CExportWriterFactory.php b/ui/include/classes/export/writers/CExportWriterFactory.php index 12150399bdb..83b4aef53a3 100644 --- a/ui/include/classes/export/writers/CExportWriterFactory.php +++ b/ui/include/classes/export/writers/CExportWriterFactory.php @@ -21,9 +21,9 @@ class CExportWriterFactory { + const YAML = 'yml'; const XML = 'xml'; const JSON = 'json'; - const YAML = 'yml'; /** * Get the writer object for specified type. @@ -37,15 +37,15 @@ class CExportWriterFactory { */ public static function getWriter($type) { switch ($type) { + case self::YAML: + return new CYamlExportWriter(); + case self::XML: return new CXmlExportWriter(); case self::JSON: return new CJsonExportWriter(); - case self::YAML: - return null; - default: throw new Exception('Incorrect export writer type.'); } @@ -53,6 +53,10 @@ class CExportWriterFactory { public static function getContentType($type) { switch ($type) { + case self::YAML: + // See https://github.com/rails/rails/blob/d41d586/actionpack/lib/action_dispatch/http/mime_types.rb#L39 + return 'text/yaml'; + case self::XML: // See https://www.ietf.org/rfc/rfc2376.txt return 'text/xml'; @@ -61,10 +65,6 @@ class CExportWriterFactory { // See https://www.ietf.org/rfc/rfc4627.txt return 'application/json'; - case self::YAML: - // See https://github.com/rails/rails/blob/d41d586/actionpack/lib/action_dispatch/http/mime_types.rb#L39 - return 'text/yaml'; - default: throw new Exception('Incorrect export writer type.'); } diff --git a/ui/include/classes/export/writers/CYamlExportWriter.php b/ui/include/classes/export/writers/CYamlExportWriter.php new file mode 100644 index 00000000000..0609ed07cdf --- /dev/null +++ b/ui/include/classes/export/writers/CYamlExportWriter.php @@ -0,0 +1,37 @@ +format) { - case 'xml': + case CImportReaderFactory::XML: $is_valid_tag = ($tag === $prefix.($index == 0 ? '' : $index) || $tag === $index); break; - case 'json': + case CImportReaderFactory::YAML: + case CImportReaderFactory::JSON: $is_valid_tag = ctype_digit(strval($tag)); break; -- cgit v1.2.3 From 30495b01432c56d526673aee5411b938d0f55e31 Mon Sep 17 00:00:00 2001 From: Ivo Kurzemnieks Date: Wed, 8 Jul 2020 17:52:28 +0300 Subject: ..F....... [ZBXNEXT-2754] added PHPLibYAML extension check in setup and system information --- ui/include/classes/setup/CFrontendSetup.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'ui') diff --git a/ui/include/classes/setup/CFrontendSetup.php b/ui/include/classes/setup/CFrontendSetup.php index 6699dc1e10b..bafa1a5fe6a 100644 --- a/ui/include/classes/setup/CFrontendSetup.php +++ b/ui/include/classes/setup/CFrontendSetup.php @@ -33,6 +33,7 @@ class CFrontendSetup { const MIN_PHP_MAX_INPUT_TIME = 300; const MIN_PHP_GD_VERSION = '2.0'; const MIN_PHP_LIBXML_VERSION = '2.6.15'; + const MIN_PHP_LIBYAML_VERION = '2.0.2'; // See https://pecl.php.net/package/yaml const REQUIRED_PHP_ARG_SEPARATOR_OUTPUT = '&'; /** @@ -77,6 +78,7 @@ class CFrontendSetup { $result[] = $this->checkPhpGdJpeg(); $result[] = $this->checkPhpGdGif(); $result[] = $this->checkPhpGdFreeType(); + $result[] = $this->checkPhpLibYAML(); $result[] = $this->checkPhpLibxml(); $result[] = $this->checkPhpXmlWriter(); $result[] = $this->checkPhpXmlReader(); @@ -478,6 +480,27 @@ class CFrontendSetup { ]; } + /** + * Checks for PHP LibYAML extension. + * + * @return array + */ + public function checkPhpLibYAML() { + if (!$current = phpversion('yaml')) { + $current = _('unknown'); + } + + $check = version_compare($current, self::MIN_PHP_LIBYAML_VERION, '>='); + + return [ + 'name' => _('PHP LibYAML'), + 'current' => $current, + 'required' => self::MIN_PHP_LIBYAML_VERION, + 'result' => $check ? self::CHECK_OK : self::CHECK_FATAL, + 'error' => _('PHP LibYAML extension missing.') + ]; + } + /** * Checks for PHP libxml extension. * -- cgit v1.2.3 From 092f40837e2ee9a7f8e4d746e43ccf87ed218923 Mon Sep 17 00:00:00 2001 From: Miks Kronkalns Date: Fri, 10 Jul 2020 15:04:04 +0300 Subject: ..F....... [ZBXNEXT-2754] fixed coding style --- ui/app/controllers/CControllerExport.php | 2 +- ui/app/views/layout.export.php | 2 +- ui/include/classes/export/writers/CExportWriterFactory.php | 12 +++++++++++- ui/include/classes/export/writers/CYamlExportWriter.php | 4 ++-- ui/include/classes/import/readers/CYamlImportReader.php | 12 +++++++----- ui/include/classes/setup/CFrontendSetup.php | 2 +- 6 files changed, 23 insertions(+), 11 deletions(-) (limited to 'ui') diff --git a/ui/app/controllers/CControllerExport.php b/ui/app/controllers/CControllerExport.php index c5d6cb551be..50a659165ba 100644 --- a/ui/app/controllers/CControllerExport.php +++ b/ui/app/controllers/CControllerExport.php @@ -113,7 +113,7 @@ class CControllerExport extends CController { else { $response = new CControllerResponseData([ 'main_block' => $export_data, - 'content_type' => CExportWriterFactory::getContentType($format), + 'mime_type' => CExportWriterFactory::getMimeType($format), 'page' => ['file' => 'zbx_export_'.substr($action, 7).'.'.$format] ]); } diff --git a/ui/app/views/layout.export.php b/ui/app/views/layout.export.php index a0db647bb66..38a1b1d88fd 100644 --- a/ui/app/views/layout.export.php +++ b/ui/app/views/layout.export.php @@ -23,7 +23,7 @@ * @var CView $this */ -header('Content-Type: '.$data['content_type'].'; charset=utf-8'); +header('Content-Type: '.$data['mime_type'].'; charset=utf-8'); header('Content-Disposition: attachment; filename="'.$data['page']['file'].'"'); echo $data['main_block']; diff --git a/ui/include/classes/export/writers/CExportWriterFactory.php b/ui/include/classes/export/writers/CExportWriterFactory.php index 83b4aef53a3..6f0e07ac15e 100644 --- a/ui/include/classes/export/writers/CExportWriterFactory.php +++ b/ui/include/classes/export/writers/CExportWriterFactory.php @@ -51,7 +51,17 @@ class CExportWriterFactory { } } - public static function getContentType($type) { + /** + * Get content mime-type for specified type. + * + * @static + * @throws Exception + * + * @param string $type + * + * @return string + */ + public static function getMimeType(string $type): string { switch ($type) { case self::YAML: // See https://github.com/rails/rails/blob/d41d586/actionpack/lib/action_dispatch/http/mime_types.rb#L39 diff --git a/ui/include/classes/export/writers/CYamlExportWriter.php b/ui/include/classes/export/writers/CYamlExportWriter.php index 0609ed07cdf..13b0f2cc140 100644 --- a/ui/include/classes/export/writers/CYamlExportWriter.php +++ b/ui/include/classes/export/writers/CYamlExportWriter.php @@ -1,4 +1,4 @@ - Date: Fri, 10 Jul 2020 17:15:22 +0300 Subject: A.F....... [ZBXNEXT-2754] changed default file extension from yml to yaml --- ui/include/classes/export/writers/CExportWriterFactory.php | 2 +- ui/include/classes/import/readers/CImportReaderFactory.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'ui') diff --git a/ui/include/classes/export/writers/CExportWriterFactory.php b/ui/include/classes/export/writers/CExportWriterFactory.php index 6f0e07ac15e..d2e9235c70b 100644 --- a/ui/include/classes/export/writers/CExportWriterFactory.php +++ b/ui/include/classes/export/writers/CExportWriterFactory.php @@ -21,7 +21,7 @@ class CExportWriterFactory { - const YAML = 'yml'; + const YAML = 'yaml'; const XML = 'xml'; const JSON = 'json'; diff --git a/ui/include/classes/import/readers/CImportReaderFactory.php b/ui/include/classes/import/readers/CImportReaderFactory.php index 0888aa04df6..56bf1a0bd9c 100644 --- a/ui/include/classes/import/readers/CImportReaderFactory.php +++ b/ui/include/classes/import/readers/CImportReaderFactory.php @@ -21,7 +21,7 @@ class CImportReaderFactory { - const YAML = 'yml'; + const YAML = 'yaml'; const XML = 'xml'; const JSON = 'json'; @@ -63,6 +63,7 @@ class CImportReaderFactory { */ public static function fileExt2ImportFormat($ext) { switch ($ext) { + case 'yaml': case 'yml': return CImportReaderFactory::YAML; -- cgit v1.2.3 From e8f59a8c788f122ee1c0c8ff71eb20613bad00e1 Mon Sep 17 00:00:00 2001 From: Ivo Kurzemnieks Date: Thu, 16 Jul 2020 18:00:03 +0300 Subject: A......... [ZBXNEXT-2754] added import/export string normalizer --- ui/include/classes/api/services/CConfiguration.php | 4 +- ui/include/classes/export/CConfigurationExport.php | 3 +- .../classes/export/CConfigurationExportBuilder.php | 9 +- .../converters/CArrayKeysImportConverter.php | 75 ----------------- .../import/converters/CImportDataNormalizer.php | 98 ++++++++++++++++++++++ .../classes/import/validators/C50XmlValidator.php | 14 ++-- 6 files changed, 116 insertions(+), 87 deletions(-) delete mode 100644 ui/include/classes/import/converters/CArrayKeysImportConverter.php create mode 100644 ui/include/classes/import/converters/CImportDataNormalizer.php (limited to 'ui') diff --git a/ui/include/classes/api/services/CConfiguration.php b/ui/include/classes/api/services/CConfiguration.php index 0554c6d3962..45efc60fb02 100644 --- a/ui/include/classes/api/services/CConfiguration.php +++ b/ui/include/classes/api/services/CConfiguration.php @@ -177,8 +177,8 @@ class CConfiguration extends CApiService { // Add default values in place of missed tags. $data = (new CDefaultImportConverter($schema))->convert($data); - // Normalize array keys. - $data = (new CArrayKeysImportConverter($schema))->convert($data); + // Normalize array keys and strings. + $data = (new CImportDataNormalizer($schema))->normalize($data); // Transform converter. $data = (new CTransformImportConverter($schema))->convert($data); diff --git a/ui/include/classes/export/CConfigurationExport.php b/ui/include/classes/export/CConfigurationExport.php index da061e0ca18..2400d62eb14 100644 --- a/ui/include/classes/export/CConfigurationExport.php +++ b/ui/include/classes/export/CConfigurationExport.php @@ -136,7 +136,8 @@ class CConfigurationExport { try { $this->gatherData(); - $schema = (new CImportValidatorFactory('xml')) + // Parameter in CImportValidatorFactory is irrelavant here, since export does not validate data. + $schema = (new CImportValidatorFactory(CExportWriterFactory::YAML)) ->getObject(ZABBIX_EXPORT_VERSION) ->getSchema(); diff --git a/ui/include/classes/export/CConfigurationExportBuilder.php b/ui/include/classes/export/CConfigurationExportBuilder.php index 0e0596df9f4..eaf73bf0022 100644 --- a/ui/include/classes/export/CConfigurationExportBuilder.php +++ b/ui/include/classes/export/CConfigurationExportBuilder.php @@ -44,11 +44,11 @@ class CConfigurationExportBuilder { } /** - * Build XML data. + * Build data structure. * * @param array $schema Tag schema from validation class. * @param array $data Export data. - * @param string $main_tag XML tag (for error reporting). + * @param string $main_tag Main element (for error reporting). * * @return array */ @@ -66,6 +66,7 @@ class CConfigurationExportBuilder { $store = []; foreach ($rules as $tag => $val) { $is_required = $val['type'] & XML_REQUIRED; + $is_string = $val['type'] & XML_STRING; $is_array = $val['type'] & XML_ARRAY; $is_indexed_array = $val['type'] & XML_INDEXED_ARRAY; $has_data = array_key_exists($tag, $row); @@ -99,6 +100,10 @@ class CConfigurationExportBuilder { continue; } + if ($is_string && $value !== null) { + $value = str_replace("\r\n", "\n", $value); + } + if (array_key_exists('in', $val)) { if (!array_key_exists($value, $val['in'])) { throw new Exception(_s('Invalid tag "%1$s": %2$s.', $tag, diff --git a/ui/include/classes/import/converters/CArrayKeysImportConverter.php b/ui/include/classes/import/converters/CArrayKeysImportConverter.php deleted file mode 100644 index ddaf6c8f657..00000000000 --- a/ui/include/classes/import/converters/CArrayKeysImportConverter.php +++ /dev/null @@ -1,75 +0,0 @@ -rules = $schema; - } - - public function convert($data) { - $data['zabbix_export'] = $this->normalizeArrayKeys($data['zabbix_export'], $this->rules); - - return $data; - } - - /** - * Convert array keys to numeric. - * - * @param mixed $data Import data. - * @param array $rules XML rules. - * - * @return array - */ - protected function normalizeArrayKeys($data, array $rules) { - if (!is_array($data)) { - return $data; - } - - if ($rules['type'] & XML_ARRAY) { - foreach ($rules['rules'] as $tag => $tag_rules) { - if (array_key_exists('ex_rules', $tag_rules)) { - $tag_rules = call_user_func($tag_rules['ex_rules'], $data); - } - - if (array_key_exists($tag, $data)) { - $data[$tag] = $this->normalizeArrayKeys($data[$tag], $tag_rules); - } - } - } - elseif ($rules['type'] & XML_INDEXED_ARRAY) { - $prefix = $rules['prefix']; - - foreach ($data as $tag => $value) { - $data[$tag] = $this->normalizeArrayKeys($value, $rules['rules'][$prefix]); - } - - $data = array_values($data); - } - - return $data; - } -} diff --git a/ui/include/classes/import/converters/CImportDataNormalizer.php b/ui/include/classes/import/converters/CImportDataNormalizer.php new file mode 100644 index 00000000000..795b8696927 --- /dev/null +++ b/ui/include/classes/import/converters/CImportDataNormalizer.php @@ -0,0 +1,98 @@ +rules = $schema; + } + + public function normalize($data) { + $data['zabbix_export'] = $this->normalizeArrayKeys($data['zabbix_export']); + $data['zabbix_export'] = $this->normalizeStrings($data['zabbix_export']); + + return $data; + } + + /** + * Convert array keys to numeric. + * + * @param mixed $data Import data. + * + * @return array + */ + protected function normalizeArrayKeys($data) { + if (!is_array($data)) { + return $data; + } + + if ($this->rules['type'] & XML_ARRAY) { + foreach ($this->rules['rules'] as $tag => $tag_rules) { + if (array_key_exists('ex_rules', $tag_rules)) { + $tag_rules = call_user_func($tag_rules['ex_rules'], $data); + } + + if (array_key_exists($tag, $data)) { + $data[$tag] = $this->normalizeArrayKeys($data[$tag], $tag_rules); + } + } + } + elseif ($this->rules['type'] & XML_INDEXED_ARRAY) { + $prefix = $this->rules['prefix']; + + foreach ($data as $tag => $value) { + $data[$tag] = $this->normalizeArrayKeys($value, $this->rules['rules'][$prefix]); + } + + $data = array_values($data); + } + + return $data; + } + + /** + * Add CR to string type fields. + * + * @param mixed $data Import data. + * + * @return mixed + */ + protected function normalizeStrings($data) { + if ($this->rules['type'] & XML_STRING) { + $data = str_replace("\r\n", "\n", $data); + + if (array_key_exists('flags', $this->rules) && $this->rules['flags'] & self::EOL_LF) { + } + else { + $data = str_replace("\n", "\r\n", $data); + } + } + + return $data; + } +} diff --git a/ui/include/classes/import/validators/C50XmlValidator.php b/ui/include/classes/import/validators/C50XmlValidator.php index 7b9a8653c36..43c7965067b 100644 --- a/ui/include/classes/import/validators/C50XmlValidator.php +++ b/ui/include/classes/import/validators/C50XmlValidator.php @@ -457,7 +457,7 @@ class C50XmlValidator { 'preprocessing' => ['type' => XML_INDEXED_ARRAY, 'prefix' => 'step', 'rules' => [ 'step' => ['type' => XML_ARRAY, 'rules' => [ 'type' => ['type' => XML_STRING | XML_REQUIRED, 'in' => $this->PREPROCESSING_STEP_TYPE], - 'params' => ['type' => XML_STRING | XML_REQUIRED], + 'params' => ['type' => XML_STRING | XML_REQUIRED, 'flags' => CImportDataNormalizer::EOL_LF], 'error_handler' => ['type' => XML_STRING, 'default' => CXmlConstantValue::ORIGINAL_ERROR, 'in' => $this->ITEM_PREPROCESSING_ERROR_HANDLER], 'error_handler_params' => ['type' => XML_STRING, 'default' => ''] ]] @@ -598,7 +598,7 @@ class C50XmlValidator { 'preprocessing' => ['type' => XML_INDEXED_ARRAY, 'prefix' => 'step', 'rules' => [ 'step' => ['type' => XML_ARRAY, 'rules' => [ 'type' => ['type' => XML_STRING | XML_REQUIRED, 'in' => $this->PREPROCESSING_STEP_TYPE], - 'params' => ['type' => XML_STRING | XML_REQUIRED], + 'params' => ['type' => XML_STRING | XML_REQUIRED, 'flags' => CImportDataNormalizer::EOL_LF], 'error_handler' => ['type' => XML_STRING, 'default' => CXmlConstantValue::ORIGINAL_ERROR, 'in' => $this->ITEM_PREPROCESSING_ERROR_HANDLER], 'error_handler_params' => ['type' => XML_STRING, 'default' => ''] ]] @@ -811,7 +811,7 @@ class C50XmlValidator { 'preprocessing' => ['type' => XML_INDEXED_ARRAY, 'prefix' => 'step', 'rules' => [ 'step' => ['type' => XML_ARRAY, 'rules' => [ 'type' => ['type' => XML_STRING | XML_REQUIRED, 'in' => $this->PREPROCESSING_STEP_TYPE_DRULE], - 'params' => ['type' => XML_STRING | XML_REQUIRED], + 'params' => ['type' => XML_STRING | XML_REQUIRED, 'flags' => CImportDataNormalizer::EOL_LF], 'error_handler' => ['type' => XML_STRING, 'default' => CXmlConstantValue::ORIGINAL_ERROR, 'in' => $this->ITEM_PREPROCESSING_ERROR_HANDLER], 'error_handler_params' => ['type' => XML_STRING, 'default' => ''] ]] @@ -1068,7 +1068,7 @@ class C50XmlValidator { 'preprocessing' => ['type' => XML_INDEXED_ARRAY, 'prefix' => 'step', 'rules' => [ 'step' => ['type' => XML_ARRAY, 'rules' => [ 'type' => ['type' => XML_STRING | XML_REQUIRED, 'in' => $this->PREPROCESSING_STEP_TYPE], - 'params' => ['type' => XML_STRING | XML_REQUIRED], + 'params' => ['type' => XML_STRING | XML_REQUIRED, 'flags' => CImportDataNormalizer::EOL_LF], 'error_handler' => ['type' => XML_STRING, 'default' => CXmlConstantValue::ORIGINAL_ERROR, 'in' => $this->ITEM_PREPROCESSING_ERROR_HANDLER], 'error_handler_params' => ['type' => XML_STRING, 'default' => ''] ]] @@ -1207,7 +1207,7 @@ class C50XmlValidator { 'preprocessing' => ['type' => XML_INDEXED_ARRAY, 'prefix' => 'step', 'rules' => [ 'step' => ['type' => XML_ARRAY, 'rules' => [ 'type' => ['type' => XML_STRING | XML_REQUIRED, 'in' => $this->PREPROCESSING_STEP_TYPE], - 'params' => ['type' => XML_STRING | XML_REQUIRED], + 'params' => ['type' => XML_STRING | XML_REQUIRED, 'flags' => CImportDataNormalizer::EOL_LF], 'error_handler' => ['type' => XML_STRING, 'default' => CXmlConstantValue::ORIGINAL_ERROR, 'in' => $this->ITEM_PREPROCESSING_ERROR_HANDLER], 'error_handler_params' => ['type' => XML_STRING, 'default' => ''] ]] @@ -1418,7 +1418,7 @@ class C50XmlValidator { 'preprocessing' => ['type' => XML_INDEXED_ARRAY, 'prefix' => 'step', 'rules' => [ 'step' => ['type' => XML_ARRAY, 'rules' => [ 'type' => ['type' => XML_STRING | XML_REQUIRED, 'in' => $this->PREPROCESSING_STEP_TYPE_DRULE], - 'params' => ['type' => XML_STRING | XML_REQUIRED], + 'params' => ['type' => XML_STRING | XML_REQUIRED, 'flags' => CImportDataNormalizer::EOL_LF], 'error_handler' => ['type' => XML_STRING, 'default' => CXmlConstantValue::ORIGINAL_ERROR, 'in' => $this->ITEM_PREPROCESSING_ERROR_HANDLER], 'error_handler_params' => ['type' => XML_STRING, 'default' => ''] ]] @@ -2259,7 +2259,7 @@ class C50XmlValidator { switch ($data['type']) { case CXmlConstantName::SCRIPT: case CXmlConstantValue::MEDIA_TYPE_SCRIPT: - return ['type' => XML_STRING, 'default' => '', 'preprocessor' => [$this, 'scriptParameterPreprocessor'], 'export' => [$this, 'scriptParameterExport']]; + return ['type' => XML_STRING, 'flags' => CImportDataNormalizer::EOL_LF, 'default' => '', 'preprocessor' => [$this, 'scriptParameterPreprocessor'], 'export' => [$this, 'scriptParameterExport']]; case CXmlConstantName::WEBHOOK: case CXmlConstantValue::MEDIA_TYPE_WEBHOOK: -- cgit v1.2.3 From 1f98cf1742c890163fb6e15ef49d9836f22e1022 Mon Sep 17 00:00:00 2001 From: Ivo Kurzemnieks Date: Fri, 17 Jul 2020 15:27:30 +0300 Subject: ..F....... [ZBXNEXT-2754] minor code improvements --- .../classes/import/converters/CImportDataNormalizer.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'ui') diff --git a/ui/include/classes/import/converters/CImportDataNormalizer.php b/ui/include/classes/import/converters/CImportDataNormalizer.php index 795b8696927..cf54cc77e73 100644 --- a/ui/include/classes/import/converters/CImportDataNormalizer.php +++ b/ui/include/classes/import/converters/CImportDataNormalizer.php @@ -1,4 +1,4 @@ -rules['type'] & XML_STRING) { $data = str_replace("\r\n", "\n", $data); - - if (array_key_exists('flags', $this->rules) && $this->rules['flags'] & self::EOL_LF) { - } - else { - $data = str_replace("\n", "\r\n", $data); - } + $data = (array_key_exists('flags', $this->rules) && $this->rules['flags'] & self::EOL_LF) + ? str_replace("\n", "\r\n", $data) + : $data; } return $data; -- cgit v1.2.3 From deea0015ab92cbd2c4b91781b7016d154d47aaad Mon Sep 17 00:00:00 2001 From: Ivo Kurzemnieks Date: Fri, 17 Jul 2020 15:56:41 +0300 Subject: ..F....... [ZBXNEXT-2754] fixed invalid if condition --- ui/include/classes/import/converters/CImportDataNormalizer.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ui') diff --git a/ui/include/classes/import/converters/CImportDataNormalizer.php b/ui/include/classes/import/converters/CImportDataNormalizer.php index cf54cc77e73..c658dc348a2 100644 --- a/ui/include/classes/import/converters/CImportDataNormalizer.php +++ b/ui/include/classes/import/converters/CImportDataNormalizer.php @@ -86,8 +86,8 @@ class CImportDataNormalizer { if ($this->rules['type'] & XML_STRING) { $data = str_replace("\r\n", "\n", $data); $data = (array_key_exists('flags', $this->rules) && $this->rules['flags'] & self::EOL_LF) - ? str_replace("\n", "\r\n", $data) - : $data; + ? $data + : str_replace("\n", "\r\n", $data); } return $data; -- cgit v1.2.3 From a051452c840db254e1a859cd6e813e07c47a32f8 Mon Sep 17 00:00:00 2001 From: Ivo Kurzemnieks Date: Mon, 20 Jul 2020 10:07:05 +0300 Subject: A......... [ZBXNEXT-2754] fixed map export not validating schema --- ui/include/classes/export/CConfigurationExport.php | 2 +- ui/include/classes/export/CConfigurationExportBuilder.php | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'ui') diff --git a/ui/include/classes/export/CConfigurationExport.php b/ui/include/classes/export/CConfigurationExport.php index 2400d62eb14..e594ace334d 100644 --- a/ui/include/classes/export/CConfigurationExport.php +++ b/ui/include/classes/export/CConfigurationExport.php @@ -175,7 +175,7 @@ class CConfigurationExport { } if ($this->data['maps']) { - $this->builder->buildMaps($this->data['maps']); + $this->builder->buildMaps($schema['rules']['maps'], $this->data['maps']); } if ($this->data['mediaTypes']) { diff --git a/ui/include/classes/export/CConfigurationExportBuilder.php b/ui/include/classes/export/CConfigurationExportBuilder.php index eaf73bf0022..952f14199bc 100644 --- a/ui/include/classes/export/CConfigurationExportBuilder.php +++ b/ui/include/classes/export/CConfigurationExportBuilder.php @@ -345,7 +345,7 @@ class CConfigurationExportBuilder { * * @param array $maps */ - public function buildMaps(array $maps) { + public function buildMaps(array $schema, array $maps) { $this->data['maps'] = []; CArrayHelper::sort($maps, ['name']); @@ -388,6 +388,8 @@ class CConfigurationExportBuilder { 'links' => $this->formatMapLinks($map['links'], $tmpSelements) ]; } + + $this->data['maps'] = $this->build($schema, $this->data['maps'], 'maps'); } /** -- cgit v1.2.3 From bbe505776cb6cc40c96c15dbbd351e071942c692 Mon Sep 17 00:00:00 2001 From: Miks Kronkalns Date: Mon, 20 Jul 2020 10:44:38 +0300 Subject: ..F....... [ZBXNEXT-2754] fixed coding style --- ui/include/classes/export/CConfigurationExportBuilder.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'ui') diff --git a/ui/include/classes/export/CConfigurationExportBuilder.php b/ui/include/classes/export/CConfigurationExportBuilder.php index 952f14199bc..b69458660c3 100644 --- a/ui/include/classes/export/CConfigurationExportBuilder.php +++ b/ui/include/classes/export/CConfigurationExportBuilder.php @@ -343,7 +343,8 @@ class CConfigurationExportBuilder { /** * Format maps. * - * @param array $maps + * @param array $schema Tag schema from validation class. + * @param array $maps Export data. */ public function buildMaps(array $schema, array $maps) { $this->data['maps'] = []; -- cgit v1.2.3 From 4004ed5cc7eff29a4a1d5567fd048bd5b3b5a484 Mon Sep 17 00:00:00 2001 From: Ivo Kurzemnieks Date: Mon, 20 Jul 2020 13:22:46 +0300 Subject: A......... [ZBXNEXT-2754] fixed array key normalizer, undefined indexes while exporting and unrelated typo --- ui/include/classes/export/CConfigurationExport.php | 12 ++++++++---- .../classes/import/converters/CImportDataNormalizer.php | 17 +++++++++-------- ui/include/classes/import/importers/CMapImporter.php | 2 +- 3 files changed, 18 insertions(+), 13 deletions(-) (limited to 'ui') diff --git a/ui/include/classes/export/CConfigurationExport.php b/ui/include/classes/export/CConfigurationExport.php index e594ace334d..86ab460560e 100644 --- a/ui/include/classes/export/CConfigurationExport.php +++ b/ui/include/classes/export/CConfigurationExport.php @@ -1443,10 +1443,14 @@ class CConfigurationExport { break; } - $selement['iconid_off'] = $selement['iconid_off'] > 0 ? $images[$selement['iconid_off']] : ''; - $selement['iconid_on'] = $selement['iconid_on'] > 0 ? $images[$selement['iconid_on']] : ''; - $selement['iconid_disabled'] = $selement['iconid_disabled'] > 0 ? $images[$selement['iconid_disabled']] : ''; - $selement['iconid_maintenance'] = $selement['iconid_maintenance'] > 0 ? $images[$selement['iconid_maintenance']] : ''; + $selement['iconid_off'] = ($selement['iconid_off'] > 0) ? $images[$selement['iconid_off']] : []; + $selement['iconid_on'] = ($selement['iconid_on'] > 0) ? $images[$selement['iconid_on']] : []; + $selement['iconid_disabled'] = ($selement['iconid_disabled'] > 0) + ? $images[$selement['iconid_disabled']] + : []; + $selement['iconid_maintenance'] = ($selement['iconid_maintenance'] > 0) + ? $images[$selement['iconid_maintenance']] + : []; } unset($selement); diff --git a/ui/include/classes/import/converters/CImportDataNormalizer.php b/ui/include/classes/import/converters/CImportDataNormalizer.php index c658dc348a2..b0a57683ded 100644 --- a/ui/include/classes/import/converters/CImportDataNormalizer.php +++ b/ui/include/classes/import/converters/CImportDataNormalizer.php @@ -33,7 +33,7 @@ class CImportDataNormalizer { } public function normalize($data) { - $data['zabbix_export'] = $this->normalizeArrayKeys($data['zabbix_export']); + $data['zabbix_export'] = $this->normalizeArrayKeys($data['zabbix_export'], $this->rules); $data['zabbix_export'] = $this->normalizeStrings($data['zabbix_export']); return $data; @@ -43,16 +43,17 @@ class CImportDataNormalizer { * Convert array keys to numeric. * * @param mixed $data Import data. + * @param array $rules Schema rules. * - * @return array + * @return mixed */ - protected function normalizeArrayKeys($data) { + protected function normalizeArrayKeys($data, array $rules) { if (!is_array($data)) { return $data; } - if ($this->rules['type'] & XML_ARRAY) { - foreach ($this->rules['rules'] as $tag => $tag_rules) { + if ($rules['type'] & XML_ARRAY) { + foreach ($rules['rules'] as $tag => $tag_rules) { if (array_key_exists('ex_rules', $tag_rules)) { $tag_rules = call_user_func($tag_rules['ex_rules'], $data); } @@ -62,11 +63,11 @@ class CImportDataNormalizer { } } } - elseif ($this->rules['type'] & XML_INDEXED_ARRAY) { - $prefix = $this->rules['prefix']; + elseif ($rules['type'] & XML_INDEXED_ARRAY) { + $prefix = $rules['prefix']; foreach ($data as $tag => $value) { - $data[$tag] = $this->normalizeArrayKeys($value, $this->rules['rules'][$prefix]); + $data[$tag] = $this->normalizeArrayKeys($value, $rules['rules'][$prefix]); } $data = array_values($data); diff --git a/ui/include/classes/import/importers/CMapImporter.php b/ui/include/classes/import/importers/CMapImporter.php index 2601eae46d7..a2226477e19 100644 --- a/ui/include/classes/import/importers/CMapImporter.php +++ b/ui/include/classes/import/importers/CMapImporter.php @@ -187,7 +187,7 @@ class CMapImporter extends CImporter { 'icon_off' => 'iconid_off', 'icon_on' => 'iconid_on', 'icon_disabled' => 'iconid_disabled', - 'icon_maintenance' => 'iconid_maintenance', + 'icon_maintenance' => 'iconid_maintenance' ]; foreach ($icons as $element => $field) { if (array_key_exists($element, $selement)) { -- cgit v1.2.3 From 661c802722d937c9b3fd90d468f4549730ef16b1 Mon Sep 17 00:00:00 2001 From: Natalja Karpinska Date: Fri, 24 Jul 2020 09:14:11 +0300 Subject: .......... [ZBXNEXT-2754] fixed tests, added yaml format in error message and additional pre-requisites checks on setup page --- ui/tests/api_json/testConfiguration.php | 8 ++++---- ui/tests/selenium/testFormAdministrationGeneralInstallation.php | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'ui') diff --git a/ui/tests/api_json/testConfiguration.php b/ui/tests/api_json/testConfiguration.php index 615f02a9c0d..49fb742d2c0 100644 --- a/ui/tests/api_json/testConfiguration.php +++ b/ui/tests/api_json/testConfiguration.php @@ -44,7 +44,7 @@ class testConfiguration extends CAPITest { ], 'format' => '' ], - 'expected_error' => 'Invalid parameter "/format": value must be one of xml, json.' + 'expected_error' => 'Invalid parameter "/format": value must be one of yaml, xml, json.' ], [ 'export' => [ @@ -55,7 +55,7 @@ class testConfiguration extends CAPITest { ], 'format' => 'test' ], - 'expected_error' => 'Invalid parameter "/format": value must be one of xml, json.' + 'expected_error' => 'Invalid parameter "/format": value must be one of yaml, xml, json.' ], [ 'export' => [ @@ -213,7 +213,7 @@ class testConfiguration extends CAPITest { ], 'source' => '{"zabbix_export":{"version":"3.2","date":"2016-12-09T07:29:55Z"}}' ], - 'expected_error' => 'Invalid parameter "/format": value must be one of xml, json.' + 'expected_error' => 'Invalid parameter "/format": value must be one of yaml, xml, json.' ], [ 'import' => [ @@ -225,7 +225,7 @@ class testConfiguration extends CAPITest { ], 'source' => '{"zabbix_export":{"version":"3.2","date":"2016-12-09T07:29:55Z"}}' ], - 'expected_error' => 'Invalid parameter "/format": value must be one of xml, json.' + 'expected_error' => 'Invalid parameter "/format": value must be one of yaml, xml, json.' ], [ 'import' => [ diff --git a/ui/tests/selenium/testFormAdministrationGeneralInstallation.php b/ui/tests/selenium/testFormAdministrationGeneralInstallation.php index 6546f148731..c92a4451eef 100644 --- a/ui/tests/selenium/testFormAdministrationGeneralInstallation.php +++ b/ui/tests/selenium/testFormAdministrationGeneralInstallation.php @@ -47,10 +47,13 @@ class testFormAdministrationGeneralInstallation extends CLegacyWebTest { 'PHP gd', 'PHP gd PNG support', 'PHP gd JPEG support', + 'PHP gd GIF support', 'PHP gd FreeType support', + 'PHP LibYAML', 'PHP libxml', 'PHP xmlwriter', 'PHP xmlreader', + 'PHP LDAP', 'PHP ctype', 'PHP session', 'PHP option "session.auto_start"', -- cgit v1.2.3 From 029fae1cf7cd5e783560a9172fab11cf96c326db Mon Sep 17 00:00:00 2001 From: Ivo Kurzemnieks Date: Fri, 24 Jul 2020 16:40:03 +0300 Subject: ..F....... [ZBXNEXT-2754] fixed import delete missing message --- ui/include/views/js/conf.import.js.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ui') diff --git a/ui/include/views/js/conf.import.js.php b/ui/include/views/js/conf.import.js.php index dd0329ac625..3bd335f6c67 100644 --- a/ui/include/views/js/conf.import.js.php +++ b/ui/include/views/js/conf.import.js.php @@ -28,7 +28,7 @@ jQuery(function($) { $('#import').click(function() { if ($('.deleteMissing:checked').length > 0) { - return confirm(); + return confirm(); } }); }); -- cgit v1.2.3 From 8c6dd74499bf62364c1ac7374b24bd4d258a1c6a Mon Sep 17 00:00:00 2001 From: Valdis Murzins Date: Fri, 24 Jul 2020 18:00:17 +0300 Subject: ..F....... [ZBXNEXT-2754] created button icon for chevron in css --- ui/assets/styles/blue-theme.css | 26 ++++++++++++++++++++++++++ ui/assets/styles/dark-theme.css | 26 ++++++++++++++++++++++++++ ui/assets/styles/hc-dark.css | 26 ++++++++++++++++++++++++++ ui/assets/styles/hc-light.css | 26 ++++++++++++++++++++++++++ ui/include/classes/html/CButtonExport.php | 2 +- ui/include/defines.inc.php | 1 + 6 files changed, 106 insertions(+), 1 deletion(-) (limited to 'ui') diff --git a/ui/assets/styles/blue-theme.css b/ui/assets/styles/blue-theme.css index b58a428823c..8b6e847946a 100644 --- a/ui/assets/styles/blue-theme.css +++ b/ui/assets/styles/blue-theme.css @@ -5460,6 +5460,32 @@ table.preprocessing-test-results .rel-container { .btn-split li:only-child button { border-radius: 2px; } +.btn-toggle-chevron { + position: relative; } + .btn-toggle-chevron[aria-expanded="true"] { + color: #ffffff; + background-color: #02659f; + border-color: #02659f; } + .btn-toggle-chevron::after { + content: ''; + position: absolute; + right: 8px; + top: calc(50% - 3px); + width: 5px; + height: 5px; + border-top: 1px solid #0275b8; + border-right: 1px solid #0275b8; + transform: rotate(135deg) translate(-1px, 1px); + transition: transform .3s; } + .btn-toggle-chevron[disabled]::after { + border-top-color: #acbbc2; + border-right-color: #acbbc2; } + .btn-toggle-chevron:enabled:active::after, .btn-toggle-chevron:enabled[aria-expanded="true"]::after { + transform: rotate(315deg) translate(-1px, 1px); } + .btn-toggle-chevron:enabled:hover::after, .btn-toggle-chevron:enabled:focus::after, .btn-toggle-chevron:enabled:active::after, .btn-toggle-chevron:enabled[aria-expanded="true"]::after { + border-top-color: #ffffff; + border-right-color: #ffffff; } + .btn-dropdown-toggle { white-space: nowrap; overflow: hidden; diff --git a/ui/assets/styles/dark-theme.css b/ui/assets/styles/dark-theme.css index d65b234023e..62e0d1eec8a 100644 --- a/ui/assets/styles/dark-theme.css +++ b/ui/assets/styles/dark-theme.css @@ -5471,6 +5471,32 @@ table.preprocessing-test-results .rel-container { .btn-split li:only-child button { border-radius: 2px; } +.btn-toggle-chevron { + position: relative; } + .btn-toggle-chevron[aria-expanded="true"] { + color: #f2f2f2; + background-color: #5e737e; + border-color: #5e737e; } + .btn-toggle-chevron::after { + content: ''; + position: absolute; + right: 8px; + top: calc(50% - 3px); + width: 5px; + height: 5px; + border-top: 1px solid #768d99; + border-right: 1px solid #768d99; + transform: rotate(135deg) translate(-1px, 1px); + transition: transform .3s; } + .btn-toggle-chevron[disabled]::after { + border-top-color: #525252; + border-right-color: #525252; } + .btn-toggle-chevron:enabled:active::after, .btn-toggle-chevron:enabled[aria-expanded="true"]::after { + transform: rotate(315deg) translate(-1px, 1px); } + .btn-toggle-chevron:enabled:hover::after, .btn-toggle-chevron:enabled:focus::after, .btn-toggle-chevron:enabled:active::after, .btn-toggle-chevron:enabled[aria-expanded="true"]::after { + border-top-color: #f2f2f2; + border-right-color: #f2f2f2; } + .btn-dropdown-toggle { white-space: nowrap; overflow: hidden; diff --git a/ui/assets/styles/hc-dark.css b/ui/assets/styles/hc-dark.css index 15925c1d9eb..6723d617323 100644 --- a/ui/assets/styles/hc-dark.css +++ b/ui/assets/styles/hc-dark.css @@ -5415,6 +5415,32 @@ table.preprocessing-test-results .rel-container { .btn-split li:only-child button { border-radius: 2px; } +.btn-toggle-chevron { + position: relative; } + .btn-toggle-chevron[aria-expanded="true"] { + color: #333333; + background-color: lightgray; + border-color: lightgray; } + .btn-toggle-chevron::after { + content: ''; + position: absolute; + right: 8px; + top: calc(50% - 3px); + width: 5px; + height: 5px; + border-top: 1px solid #ffffff; + border-right: 1px solid #ffffff; + transform: rotate(135deg) translate(-1px, 1px); + transition: transform .3s; } + .btn-toggle-chevron[disabled]::after { + border-top-color: #7d7d7d; + border-right-color: #7d7d7d; } + .btn-toggle-chevron:enabled:active::after, .btn-toggle-chevron:enabled[aria-expanded="true"]::after { + transform: rotate(315deg) translate(-1px, 1px); } + .btn-toggle-chevron:enabled:hover::after, .btn-toggle-chevron:enabled:focus::after, .btn-toggle-chevron:enabled:active::after, .btn-toggle-chevron:enabled[aria-expanded="true"]::after { + border-top-color: #333333; + border-right-color: #333333; } + .btn-dropdown-toggle { white-space: nowrap; overflow: hidden; diff --git a/ui/assets/styles/hc-light.css b/ui/assets/styles/hc-light.css index e0051c0f9d3..cac713f2a9f 100644 --- a/ui/assets/styles/hc-light.css +++ b/ui/assets/styles/hc-light.css @@ -5415,6 +5415,32 @@ table.preprocessing-test-results .rel-container { .btn-split li:only-child button { border-radius: 2px; } +.btn-toggle-chevron { + position: relative; } + .btn-toggle-chevron[aria-expanded="true"] { + color: #ffffff; + background-color: #484848; + border-color: #484848; } + .btn-toggle-chevron::after { + content: ''; + position: absolute; + right: 8px; + top: calc(50% - 3px); + width: 5px; + height: 5px; + border-top: 1px solid #000000; + border-right: 1px solid #000000; + transform: rotate(135deg) translate(-1px, 1px); + transition: transform .3s; } + .btn-toggle-chevron[disabled]::after { + border-top-color: #999999; + border-right-color: #999999; } + .btn-toggle-chevron:enabled:active::after, .btn-toggle-chevron:enabled[aria-expanded="true"]::after { + transform: rotate(315deg) translate(-1px, 1px); } + .btn-toggle-chevron:enabled:hover::after, .btn-toggle-chevron:enabled:focus::after, .btn-toggle-chevron:enabled:active::after, .btn-toggle-chevron:enabled[aria-expanded="true"]::after { + border-top-color: #ffffff; + border-right-color: #ffffff; } + .btn-dropdown-toggle { white-space: nowrap; overflow: hidden; diff --git a/ui/include/classes/html/CButtonExport.php b/ui/include/classes/html/CButtonExport.php index 3b993eca24c..093efb78a45 100644 --- a/ui/include/classes/html/CButtonExport.php +++ b/ui/include/classes/html/CButtonExport.php @@ -49,7 +49,7 @@ class CButtonExport extends CList { ), (new CButton('export', '​')) ->addClass(ZBX_STYLE_BTN_ALT) - ->addClass(ZBX_STYLE_BTN_TOGGLE) + ->addClass(ZBX_STYLE_BTN_TOGGLE_CHEVRON) ->setMenuPopup([ 'type' => 'dropdown', 'data' => [ diff --git a/ui/include/defines.inc.php b/ui/include/defines.inc.php index 13441b83574..87b3fa844ac 100644 --- a/ui/include/defines.inc.php +++ b/ui/include/defines.inc.php @@ -1567,6 +1567,7 @@ define('ZBX_STYLE_ARROW_UP', 'arrow-up'); define('ZBX_STYLE_BLUE', 'blue'); define('ZBX_STYLE_BTN_ADD_FAV', 'btn-add-fav'); define('ZBX_STYLE_BTN_ALT', 'btn-alt'); +define('ZBX_STYLE_BTN_TOGGLE_CHEVRON', 'btn-toggle-chevron'); define('ZBX_STYLE_BTN_SPLIT', 'btn-split'); define('ZBX_STYLE_BTN_TOGGLE', 'btn-dropdown-toggle'); define('ZBX_STYLE_BTN_BACK_MAP', 'btn-back-map'); -- cgit v1.2.3 From 322053e9c36b14aa60566d65963cf59de73abe5f Mon Sep 17 00:00:00 2001 From: Ivo Kurzemnieks Date: Fri, 24 Jul 2020 18:33:10 +0300 Subject: A.F....... [ZBXNEXT-2754] added usage of configuration.export API in export controller, added error message when library is missing and added pretty print for JSON --- ui/app/controllers/CControllerExport.php | 43 ++++++++---------- ui/include/classes/api/services/CConfiguration.php | 53 +++++++++++++++++++++- .../classes/export/writers/CJsonExportWriter.php | 8 +++- 3 files changed, 78 insertions(+), 26 deletions(-) (limited to 'ui') diff --git a/ui/app/controllers/CControllerExport.php b/ui/app/controllers/CControllerExport.php index 50a659165ba..37bd77df536 100644 --- a/ui/app/controllers/CControllerExport.php +++ b/ui/app/controllers/CControllerExport.php @@ -64,31 +64,35 @@ class CControllerExport extends CController { protected function doAction() { $action = $this->getInput('action'); - $format = $this->getInput('format', CExportWriterFactory::YAML); + $params = [ + 'format' => $this->getInput('format', CExportWriterFactory::YAML), + 'prettyprint' => true, + 'options' => [] + ]; switch ($action) { case 'export.valuemaps': - $export = new CConfigurationExport(['valueMaps' => $this->getInput('valuemapids', [])]); + $params['options']['valueMaps'] = $this->getInput('valuemapids', []); break; case 'export.hosts': - $export = new CConfigurationExport(['hosts' => $this->getInput('hosts', [])]); + $params['options']['hosts'] = $this->getInput('hosts', []); break; case 'export.mediatypes': - $export = new CConfigurationExport(['mediaTypes' => $this->getInput('mediatypeids', [])]); + $params['options']['mediaTypes'] = $this->getInput('mediatypeids', []); break; case 'export.screens': - $export = new CConfigurationExport(['screens' => $this->getInput('screens', [])]); + $params['options']['screens'] = $this->getInput('screens', []); break; case 'export.sysmaps': - $export = new CConfigurationExport(['maps' => $this->getInput('maps', [])]); + $params['options']['maps'] = $this->getInput('maps', []); break; case 'export.templates': - $export = new CConfigurationExport(['templates' => $this->getInput('templates', [])]); + $params['options']['templates'] = $this->getInput('templates', []); break; default: @@ -97,26 +101,19 @@ class CControllerExport extends CController { return; } - $export->setBuilder(new CConfigurationExportBuilder()); - $export->setWriter(CExportWriterFactory::getWriter($format)); - - $export_data = $export->export(); - - if ($export_data === false) { - // Access denied. - - $response = new CControllerResponseRedirect( - $this->getInput('backurl', 'zabbix.php?action=dashboard.view')); + $result = API::Configuration()->export($params); - $response->setMessageError(_('No permissions to referred object or it does not exist!')); - } - else { + if ($result) { $response = new CControllerResponseData([ - 'main_block' => $export_data, - 'mime_type' => CExportWriterFactory::getMimeType($format), - 'page' => ['file' => 'zbx_export_'.substr($action, 7).'.'.$format] + 'main_block' => $result, + 'mime_type' => CExportWriterFactory::getMimeType($params['format']), + 'page' => ['file' => 'zbx_export_'.substr($action, 7).'.'.$params['format']] ]); } + else { + $response = new CControllerResponseRedirect($this->getInput('backurl', 'zabbix.php?action=dashboard.view')); + $response->setMessageError(_('Export failed')); + } $this->setResponse($response); } diff --git a/ui/include/classes/api/services/CConfiguration.php b/ui/include/classes/api/services/CConfiguration.php index 45efc60fb02..f88b0940205 100644 --- a/ui/include/classes/api/services/CConfiguration.php +++ b/ui/include/classes/api/services/CConfiguration.php @@ -32,6 +32,7 @@ class CConfiguration extends CApiService { public function export(array $params) { $api_input_rules = ['type' => API_OBJECT, 'fields' => [ 'format' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'in' => implode(',', [CExportWriterFactory::YAML, CExportWriterFactory::XML, CExportWriterFactory::JSON])], + 'prettyprint' => ['type' => API_BOOLEAN, 'default' => false], 'options' => ['type' => API_OBJECT, 'flags' => API_REQUIRED, 'fields' => [ 'groups' => ['type' => API_IDS], 'hosts' => ['type' => API_IDS], @@ -47,10 +48,34 @@ class CConfiguration extends CApiService { self::exception(ZBX_API_ERROR_PARAMETERS, $error); } + switch ($params['format']) { + case CExportWriterFactory::YAML: + $lib_yaml = (new CFrontendSetup())->checkPhpLibYAML(); + + if ($lib_yaml['result'] == CFrontendSetup::CHECK_FATAL) { + self::exception(ZBX_API_ERROR_INTERNAL, $lib_yaml['error']); + } + break; + + case CExportWriterFactory::XML: + $lib_xml = (new CFrontendSetup())->checkPhpLibxml(); + + if ($lib_xml['result'] == CFrontendSetup::CHECK_FATAL) { + self::exception(ZBX_API_ERROR_INTERNAL, $lib_xml['error']); + } + + $xml_writer = (new CFrontendSetup())->checkPhpXmlWriter(); + + if ($xml_writer['result'] == CFrontendSetup::CHECK_FATAL) { + self::exception(ZBX_API_ERROR_INTERNAL, $xml_writer['error']); + } + break; + } + $export = new CConfigurationExport($params['options']); $export->setBuilder(new CConfigurationExportBuilder()); $writer = CExportWriterFactory::getWriter($params['format']); - $writer->formatOutput(false); + $writer->formatOutput($params['prettyprint']); $export->setWriter($writer); $export_data = $export->export(); @@ -69,7 +94,7 @@ class CConfiguration extends CApiService { */ public function import($params) { $api_input_rules = ['type' => API_OBJECT, 'fields' => [ - 'format' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'in' => implode(',', [CExportWriterFactory::YAML, CImportReaderFactory::XML, CImportReaderFactory::JSON])], + 'format' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'in' => implode(',', [CImportReaderFactory::YAML, CImportReaderFactory::XML, CImportReaderFactory::JSON])], 'source' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED], 'rules' => ['type' => API_OBJECT, 'flags' => API_REQUIRED, 'fields' => [ 'applications' => ['type' => API_OBJECT, 'fields' => [ @@ -147,6 +172,30 @@ class CConfiguration extends CApiService { self::exception(ZBX_API_ERROR_PARAMETERS, $error); } + switch ($params['format']) { + case CImportReaderFactory::YAML: + $lib_yaml = (new CFrontendSetup())->checkPhpLibYAML(); + + if ($lib_yaml['result'] == CFrontendSetup::CHECK_FATAL) { + self::exception(ZBX_API_ERROR_INTERNAL, $lib_yaml['error']); + } + break; + + case CImportReaderFactory::XML: + $lib_xml = (new CFrontendSetup())->checkPhpLibxml(); + + if ($lib_xml['result'] == CFrontendSetup::CHECK_FATAL) { + self::exception(ZBX_API_ERROR_INTERNAL, $lib_xml['error']); + } + + $xml_reader = (new CFrontendSetup())->checkPhpXmlReader(); + + if ($xml_reader['result'] == CFrontendSetup::CHECK_FATAL) { + self::exception(ZBX_API_ERROR_INTERNAL, $xml_reader['error']); + } + break; + } + $importReader = CImportReaderFactory::getReader($params['format']); $data = $importReader->read($params['source']); diff --git a/ui/include/classes/export/writers/CJsonExportWriter.php b/ui/include/classes/export/writers/CJsonExportWriter.php index 3c2d530b36b..562b7dc4b75 100644 --- a/ui/include/classes/export/writers/CJsonExportWriter.php +++ b/ui/include/classes/export/writers/CJsonExportWriter.php @@ -32,6 +32,12 @@ class CJsonExportWriter extends CExportWriter { * @return string */ public function write(array $array) { - return json_encode($array, JSON_UNESCAPED_SLASHES); + $options = JSON_UNESCAPED_SLASHES; + + if ($this->formatOutput) { + $options |= JSON_PRETTY_PRINT; + } + + return json_encode($array, $options); } } -- cgit v1.2.3 From 329e84632761ce3fc981e3b9d533661868136caa Mon Sep 17 00:00:00 2001 From: Ivo Kurzemnieks Date: Fri, 24 Jul 2020 19:02:06 +0300 Subject: A......... [ZBXNEXT-2754] added special validation if yaml files contain gibberish --- ui/include/classes/import/readers/CYamlImportReader.php | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'ui') diff --git a/ui/include/classes/import/readers/CYamlImportReader.php b/ui/include/classes/import/readers/CYamlImportReader.php index 3eb5b398a78..8aad995f897 100644 --- a/ui/include/classes/import/readers/CYamlImportReader.php +++ b/ui/include/classes/import/readers/CYamlImportReader.php @@ -47,6 +47,16 @@ class CYamlImportReader extends CImportReader { restore_error_handler(); + /* + * Unfortunately yaml_parse() not always returns FALSE. If file is empty, it returns NULL and if file contains + * gibberish and not a "zabbix_export" array, $data contains same input string, but Import Validator expects + * $data to be an array. Create a custom error message for these cases. + */ + if (!is_array($data) && $data !== false) { + $data = false; + $error = _('Invalid file content'); + } + if ($data === false) { throw new ErrorException(_s('Cannot read YAML: %1$s.', $error)); } -- cgit v1.2.3 From afb6d977f2f3f190d397ff98cd895392e77586f9 Mon Sep 17 00:00:00 2001 From: Natalja Karpinska Date: Mon, 3 Aug 2020 16:19:42 +0300 Subject: .......... [ZBXNEXT-2754] added api tests for yaml format --- ui/tests/api_json/data/data_test.sql | 2 +- ui/tests/api_json/testConfiguration.php | 276 +++++++++++++++++++++++++++----- 2 files changed, 235 insertions(+), 43 deletions(-) (limited to 'ui') diff --git a/ui/tests/api_json/data/data_test.sql b/ui/tests/api_json/data/data_test.sql index 952aeee3428..1c818f6d4b5 100644 --- a/ui/tests/api_json/data/data_test.sql +++ b/ui/tests/api_json/data/data_test.sql @@ -242,7 +242,7 @@ INSERT INTO interface (interfaceid, hostid, main, type, useip, ip, dns, port) VA INSERT INTO hosts (hostid, host, status, description) VALUES (99003, 'Api active proxy in action', 5, ''); INSERT INTO hosts (hostid, host, status, description) VALUES (99004, 'Api active proxy with host', 5, ''); INSERT INTO hosts (hostid, proxy_hostid, host, name, status, description) VALUES (99005, 99004,'API Host monitored with proxy', 'API Host monitored with proxy', 0, ''); -INSERT INTO interface (interfaceid,hostid,main,type,useip,ip,dns,port) values (99003,99004,1,1,1,'127.0.0.1','','10050'); +INSERT INTO interface (interfaceid,hostid,main,type,useip,ip,dns,port) values (99003,99005,1,1,1,'127.0.0.1','','10050'); INSERT INTO actions (actionid, name, eventsource, evaltype, status, esc_period) VALUES (90, 'API action with proxy', 1, 0, 0, '1h'); INSERT INTO operations (operationid, actionid, operationtype, esc_period, esc_step_from, esc_step_to, evaltype) VALUES (90, 90, 0, 0, 1, 1, 0); INSERT INTO opmessage (operationid, default_msg, subject, message, mediatypeid) VALUES (90, 0, 'Discovery: {DISCOVERY.DEVICE.STATUS} {DISCOVERY.DEVICE.IPADDRESS}', 'Discovery rule: {DISCOVERY.RULE.NAME}', NULL); diff --git a/ui/tests/api_json/testConfiguration.php b/ui/tests/api_json/testConfiguration.php index 49fb742d2c0..31da167fb8e 100644 --- a/ui/tests/api_json/testConfiguration.php +++ b/ui/tests/api_json/testConfiguration.php @@ -25,12 +25,13 @@ class testConfiguration extends CAPITest { public static function export_fail_data() { return [ + // Check format parameter. [ 'export' => [ 'options' => [ 'hosts' => [ '50009' - ], + ] ] ], 'expected_error' => 'Invalid parameter "/": the parameter "format" is missing.' @@ -40,7 +41,7 @@ class testConfiguration extends CAPITest { 'options' => [ 'hosts' => [ '50009' - ], + ] ], 'format' => '' ], @@ -51,18 +52,19 @@ class testConfiguration extends CAPITest { 'options' => [ 'hosts' => [ '50009' - ], + ] ], - 'format' => 'test' + 'format' => 'æų' ], 'expected_error' => 'Invalid parameter "/format": value must be one of yaml, xml, json.' ], + // Check unexpected parameter. [ 'export' => [ 'options' => [ 'groups' => [ '50012' - ], + ] ], 'format' => 'test', 'hosts' => '50009' @@ -80,18 +82,70 @@ class testConfiguration extends CAPITest { ], 'expected_error' => 'Invalid parameter "/options": unexpected parameter "applications".' ], + [ + 'export' => [ + 'options' => [ + 'groups' => [ + '50009' + ], + 'group' => [ + '50009' + ] + ], + 'format' => 'xml' + ], + 'expected_error' => 'Invalid parameter "/options": unexpected parameter "group".' + ], + // Check missing options parameter. [ 'export' => [ 'format' => 'xml' ], 'expected_error' => 'Invalid parameter "/": the parameter "options" is missing.' + ], + // Check prettyprint parameter. + [ + 'export' => [ + 'options' => [ + 'groups' => [ + '50012' + ] + ], + 'format' => 'yaml', + 'prettyprint' => 'test' + ], + 'expected_error' => 'Invalid parameter "/prettyprint": a boolean is expected.' + ], + [ + 'export' => [ + 'options' => [ + 'groups' => [ + '50012' + ] + ], + 'format' => 'json', + 'prettyprint' => '' + ], + 'expected_error' => 'Invalid parameter "/prettyprint": a boolean is expected.' + ], + [ + 'export' => [ + 'options' => [ + 'groups' => [ + '50012' + ] + ], + 'format' => 'yaml', + 'prettyprint' => 'æų' + ], + 'expected_error' => 'Invalid parameter "/prettyprint": a boolean is expected.' ] ]; } /** - * @dataProvider export_fail_data - */ + * @dataProvider export_fail_data + */ public function testConfiguration_ExportFail($export, $expected_error) { $this->call('configuration.export', $export, $expected_error); } @@ -109,10 +163,10 @@ class testConfiguration extends CAPITest { } /** - * @dataProvider export_string_ids - */ + * @dataProvider export_string_ids + */ public function testConfiguration_ExportIdsNotNumber($options) { - $formats = ['xml', 'json']; + $formats = ['xml', 'json', 'yaml']; foreach ($formats as $parameter){ $this->call('configuration.export', @@ -120,7 +174,7 @@ class testConfiguration extends CAPITest { 'options' => [ $options => [ $options - ], + ] ], 'format' => $parameter ], @@ -132,40 +186,91 @@ class testConfiguration extends CAPITest { public static function export_success_data() { return [ [ - ['groups' => ['50012']] + [ + 'options' => [ + 'groups' => [] + ], + 'prettyprint' => true + ] + ], + [ + [ + 'options' => [ + 'groups' => ['11111111111111'] + ], + 'prettyprint' => true + ] ], [ - ['hosts' => ['50009']] + [ + 'options' => [ + 'groups' => ['50012'] + ], + 'prettyprint' => true + ] ], [ - ['images' => ['1']] + [ + 'options' => [ + 'hosts' => ['50009'] + ], + 'prettyprint' => false + ] + ], + [ + [ + 'options' => [ + 'groups' => ['50012'], + 'hosts' => ['50009'] + ] + ] ], [ - ['maps' => ['1']] + [ + 'options' => [ + 'images' => ['1'] + ] + ] ], [ - ['screens' => ['3']] + [ + 'options' => [ + 'maps' => ['1'] + ] + ] ], [ - ['templates' => ['10069']] + [ + 'options' => [ + 'screens' => ['3'] + ] + ] ], [ - ['valueMaps' => ['1']] + [ + 'options' => [ + 'templates' => ['10069'] + ] + ] ], + [ + [ + 'options' => [ + 'valueMaps' => ['1'] + ] + ] + ] ]; } /** - * @dataProvider export_success_data - */ + * @dataProvider export_success_data + */ public function testConfiguration_ExportSuccess($data) { - $formats = ['xml', 'json']; + $formats = ['xml', 'json', 'yaml']; - foreach ($formats as $parameter){ - $this->call('configuration.export', [ - 'options' => $data, - 'format' => $parameter - ]); + foreach ($formats as $parameter) { + $this->call('configuration.export', array_merge($data, ['format' => $parameter])); } } @@ -240,6 +345,19 @@ class testConfiguration extends CAPITest { ], 'expected_error' => 'Invalid parameter "/": unexpected parameter "hosts".' ], + [ + 'import' => [ + 'format' => 'json', + 'rules' => [ + 'groups' => [ + 'createMissing' => true + ] + ], + 'source' => '{"zabbix_export":{"version":"3.2","date":"2016-12-09T07:29:55Z"}}', + 'prettyprint' => true + ], + 'expected_error' => 'Invalid parameter "/": unexpected parameter "prettyprint".' + ], // Check rules. [ 'import' => [ @@ -290,8 +408,8 @@ class testConfiguration extends CAPITest { } /** - * @dataProvider import_fail_data - */ + * @dataProvider import_fail_data + */ public function testConfiguration_ImportFail($import, $expected_error) { $this->call('configuration.import', $import, $expected_error); } @@ -377,8 +495,8 @@ class testConfiguration extends CAPITest { } /** - * @dataProvider import_rules_parameters - */ + * @dataProvider import_rules_parameters + */ public function testConfiguration_ImportBooleanTypeAndUnexpectedParameters($import) { foreach ($import['expected'] as $expected) { $this->call('configuration.import', [ @@ -413,12 +531,12 @@ class testConfiguration extends CAPITest { return [ [[ 'format' => 'xml', - 'source' => '' , + 'source' => '', 'error' => 'Cannot read XML: XML is empty.' ]], [[ 'format' => 'xml', - 'source' => 'test' , + 'source' => 'test', 'error' => 'Cannot read XML: (4) Start tag expected, \'<\' not found [Line: 1 | Column: 1].' ]], [[ @@ -430,7 +548,7 @@ class testConfiguration extends CAPITest { [[ 'format' => 'xml', 'source' => ' - 2016-12-09T07:12:45Z' , + 2016-12-09T07:12:45Z', 'error' => 'Invalid tag "/zabbix_export/version": unsupported version number.' ]], [[ @@ -440,45 +558,92 @@ class testConfiguration extends CAPITest { // can be different error message text 'error_contains' => 'Cannot read XML:' ]], + // JSON format. [[ 'format' => 'json', - 'source' => '' , + 'source' => '', // can be different error message text 'Cannot read JSON: Syntax error.' or 'Cannot read JSON: No error.' 'error_contains' => 'Cannot read JSON: ' ]], [[ 'format' => 'json', - 'source' => 'test' , + 'source' => 'test', // can be different error message text 'Cannot read JSON: Syntax error.' or 'Cannot read JSON: boolean expected.' 'error_contains' => 'Cannot read JSON: ' ]], [[ 'format' => 'json', - 'source' => '{"zabbix_export":{"date":"2016-12-09T07:29:55Z"}}' , + 'source' => '{"zabbix_export":{"date":"2016-12-09T07:29:55Z"}}', 'error' => 'Invalid tag "/zabbix_export": the tag "version" is missing.' ]], [[ 'format' => 'json', - 'source' => '{"zabbix_export":{"version":"","date":"2016-12-09T07:29:55Z"}}' , + 'source' => '{"zabbix_export":{"version":"","date":"2016-12-09T07:29:55Z"}}', 'error' => 'Invalid tag "/zabbix_export/version": unsupported version number.' ]], [[ 'format' => 'json', - 'source' => '{"export":{"version":"3.2","date":"2016-12-09T07:29:55Z"}}' , + 'source' => '{"export":{"version":"3.2","date":"2016-12-09T07:29:55Z"}}', 'error' => 'Invalid tag "/": unexpected tag "export".' ]], [[ 'format' => 'json', - 'source' => '{"export":{"version":"3.2","date":"2016-12-09T07:29:55Z"}' , + 'source' => '{"zabbix_export":{"version":"3.2","date":"2016-12-09T07:29:55Z"}', // can be different error message text 'Cannot read JSON: Syntax error.' or 'Cannot read JSON: unexpected end of data.' 'error_contains' => 'Cannot read JSON: ' - ]] + ]], + // YAML format. + [[ + 'format' => 'yaml', + 'source' => '', + 'error_contains' => 'Cannot read YAML: Invalid file content.' + ]], + [[ + 'format' => 'yaml', + 'source' => 'æų', + 'error_contains' => 'Cannot read YAML: Invalid file content.' + ]], + [[ + 'format' => 'yaml', + 'source' => "---\nzabbix_export:\n date: \"2020-07-27T12:58:01Z\"\n", + 'error' => 'Invalid tag "/zabbix_export": the tag "version" is missing.' + ]], + [[ + 'format' => 'yaml', + 'source' => "---\nzabbix_export:\n version: \"5.0\"\ndate: \"2020-07-27T12:58:01Z\"\n", + 'error' => 'Invalid tag "/": unexpected tag "date".' + ]], + [[ + 'format' => 'yaml', + 'source' => "---\nzabbix_export:\n version: \"\"\n date: \"2020-07-27T12:58:01Z\"\n", + 'error' => 'Invalid tag "/zabbix_export/version": unsupported version number.' + ]], + [[ + 'format' => 'yaml', + 'source' => "---\nexport:\n version: \"4.0\"\n date: \"2020-08-03T11:38:33Z\"\n...\n", + 'error' => 'Invalid tag "/": unexpected tag "export".' + ]], + [[ + 'format' => 'yaml', + 'source' => '---\nzabbix_export:\n version: \"4.0\"\n date: \"2020-08-03T11:38:33Z', + 'error_contains' => 'Cannot read YAML: scanning error encountered during parsing' + ]], + [[ + 'format' => 'yaml', + 'source' => '\n5.02020-08-03T12:36:11Z\n', + 'error' => 'Cannot read YAML: Invalid file content.' + ]], + [[ + 'format' => 'yaml', + 'source' => '{\"zabbix_export\":{\"version\":\"5.0\",\"date\":\"2020-08-03T12:36:39Z\"}}', + 'error' => 'Cannot read YAML: scanning error encountered during parsing: found unexpected \':\' (line 1, column 19), context while scanning a plain scalar (line 1, column 2).' + ]], ]; } /** - * @dataProvider import_source - */ + * @dataProvider import_source + */ public function testConfiguration_ImportInvalidSource($data) { $result = $this->call('configuration.import', [ 'format' => $data['format'], @@ -524,6 +689,12 @@ class testConfiguration extends CAPITest { 'source' => '{"zabbix_export":{"version":"3.2","date":"2016-12-09T12:29:57Z","groups":[{"name":"API host group json import"}]}}', 'sql' => 'select * from hstgrp where name=\'API host group json import\'' ], + [ + 'format' => 'yaml', + 'parameter' => 'groups', + 'source' => "---\nzabbix_export:\n version: \"4.0\"\n date: \"2020-08-03T12:41:17Z\"\n groups:\n - name: API host group yaml import\n...\n", + 'sql' => 'select * from hstgrp where name=\'API host group yaml import\'' + ], [ 'format' => 'xml', 'parameter' => 'screens', @@ -548,6 +719,13 @@ class testConfiguration extends CAPITest { . '"hsize":"1","vsize":"1"}]}}', 'sql' => 'select * from screens where name=\'API screen json import\'' ], + [ + 'format' => 'yaml', + 'parameter' => 'screens', + 'source' => "---\nzabbix_export:\n version: \"4.0\"\n date: \"2020-08-03T12:44:35Z\"\n". + " screens:\n - name: API screen yaml import\n hsize: \"1\"\n vsize: \"1\"\n screen_items: []\n...\n", + 'sql' => 'select * from screens where name=\'API screen yaml import\'' + ], [ 'format' => 'xml', 'parameter' => 'valueMaps', @@ -575,6 +753,13 @@ class testConfiguration extends CAPITest { 'source' => '{"zabbix_export":{"version":"3.2","date":"2016-12-12T07:18:00Z","value_maps":[{"name":"API valueMap json import",' . '"mappings":[{"value":"1","newvalue":"Up"}]}]}}', 'sql' => 'select * from valuemaps where name=\'API valueMap json import\'' + ], + [ + 'format' => 'yaml', + 'parameter' => 'valueMaps', + 'source' => "---\nzabbix_export:\n version: \"4.0\"\n date: \"2020-08-03T12:47:05Z\"\n". + " value_maps:\n - name: API valueMap yaml import\n mappings:\n - value: One\n newvalue: Up\n...\n", + 'sql' => 'select * from valuemaps where name=\'API valueMap yaml import\'' ] ]; } @@ -623,6 +808,13 @@ class testConfiguration extends CAPITest { 'sql' => 'select * from hstgrp where name=\'API host group json import as non Super Admin\'', 'expected_error' => 'Only Super Admins can create host groups.' ], + [ + 'format' => 'yaml', + 'parameter' => 'groups', + 'source' => "---\nzabbix_export:\n version: \"4.0\"\n date: \"2020-08-03T12:41:17Z\"\n groups:\n - name: API host group yaml import as non Super Admin\n...\n", + 'sql' => 'select * from hstgrp where name=\'API host group yaml import as non Super Admin\'', + 'expected_error' => 'Only Super Admins can create host groups.' + ], [ 'format' => 'xml', 'parameter' => 'valueMaps', -- cgit v1.2.3 From 7c0974dbda30a9a22773cd0f9a844bef4ca590f6 Mon Sep 17 00:00:00 2001 From: Miks Kronkalns Date: Tue, 4 Aug 2020 09:51:30 +0300 Subject: ..F....... [ZBX-18106] fixed map navigation tree widget copying * commit '0fd2c9e7af9e9ff5eb2cf48cf3f27d2b5314d2db': ..F....... [ZBX-18106] fixed coding style ..F....... [ZBX-18106] reverted unneeded changes ..F....... [ZBX-18106] fixed map navigation tree widget copying (cherry picked from commit f2ca4f1a754570cdb0ec37b3be19284af4cd9f43) --- ui/js/class.cnavtree.js | 12 +++++++++++- ui/js/dashboard.grid.js | 7 ++++++- 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'ui') diff --git a/ui/js/class.cnavtree.js b/ui/js/class.cnavtree.js index 5ed44cafa32..c52a3ccfda3 100644 --- a/ui/js/class.cnavtree.js +++ b/ui/js/class.cnavtree.js @@ -1267,6 +1267,14 @@ jQuery(function($) { }); }, + // onWidgetCopy trigger method + onWidgetCopy: function() { + var $this = $(this); + return this.each(function() { + updateWidgetFields($this); + }); + }, + // onEditStart trigger method onEditStart: function() { var $this = $(this); @@ -1314,7 +1322,9 @@ jQuery(function($) { lastId: 0 }); - var triggers = ['onEditStart', 'beforeDashboardSave','beforeConfigLoad', 'onDashboardReady']; + var triggers = ['onEditStart', 'beforeDashboardSave', 'onWidgetCopy', 'beforeConfigLoad', + 'onDashboardReady' + ]; $.each(triggers, function(index, trigger) { $(".dashbrd-grid-container").dashboardGrid("addAction", trigger, diff --git a/ui/js/dashboard.grid.js b/ui/js/dashboard.grid.js index 64449797811..469b7d7b6e9 100644 --- a/ui/js/dashboard.grid.js +++ b/ui/js/dashboard.grid.js @@ -3853,7 +3853,7 @@ }, /** - * Function to store copied widget into storage handler. + * Function to store copied widget into storage buffer. * * @param {object} widget Widget object copied. * @@ -3861,6 +3861,11 @@ */ copyWidget: function(widget) { return this.each(function() { + var $this = $(this), + data = $this.data('dashboardGrid'); + + doAction('onWidgetCopy', $this, data, widget); + var w = { type: widget.type, pos: { -- cgit v1.2.3 From b0373f45adffee7bac5ed3dc563e87e8ff6e2131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20T=C4=81lbergs?= Date: Thu, 6 Aug 2020 09:56:23 +0300 Subject: A.F....... [ZBX-17468] fixed excess audit log record being added on host status update * commit '23e0443cc605602151b2c93c914a61063e5afcd3': A......... [ZBX-17468] fixed auditlog for host.create method A......... [ZBX-17468] removed redundant fields from API request 'output' section A......... [ZBX-17468] removed auditing readonly fields A......... [ZBX-17468] fixed using "extend" in hosts API ..F....... [ZBX-17468] fixed API hosts mass update auditlog .D........ [ZBX-17468] added change log entry (cherry picked from commit f00e13dba080b99f453b98db9331b3750f43395f) --- ui/hostgroups.php | 9 --------- ui/hosts.php | 28 ++++++--------------------- ui/include/classes/api/CAudit.php | 1 + ui/include/classes/api/services/CHost.php | 32 ++++++++++++++++++++----------- ui/include/hosts.inc.php | 27 -------------------------- 5 files changed, 28 insertions(+), 69 deletions(-) (limited to 'ui') diff --git a/ui/hostgroups.php b/ui/hostgroups.php index 4c828edc3ae..e8306e0ee8a 100644 --- a/ui/hostgroups.php +++ b/ui/hostgroups.php @@ -160,7 +160,6 @@ elseif (hasRequest('action')) { elseif (getRequest('action') == 'hostgroup.massenable' || getRequest('action') == 'hostgroup.massdisable') { $enable = (getRequest('action') == 'hostgroup.massenable'); $status = $enable ? HOST_STATUS_MONITORED : HOST_STATUS_NOT_MONITORED; - $auditAction = $enable ? AUDIT_ACTION_ENABLE : AUDIT_ACTION_DISABLE; $groupIds = getRequest('groups', []); @@ -180,14 +179,6 @@ elseif (hasRequest('action')) { 'hosts' => $hosts, 'status' => $status ]); - - if ($result) { - foreach ($hosts as $host) { - add_audit_ext($auditAction, AUDIT_RESOURCE_HOST, $host['hostid'], $host['host'], 'hosts', - ['status' => $host['status']], ['status' => $status] - ); - } - } } $result = DBend($result); diff --git a/ui/hosts.php b/ui/hosts.php index 9e40fc1dd51..3aa3ac8f780 100644 --- a/ui/hosts.php +++ b/ui/hosts.php @@ -839,16 +839,9 @@ elseif (hasRequest('add') || hasRequest('update')) { } if ($create) { - $hostIds = API::Host()->create($host); - - if ($hostIds) { - $hostId = reset($hostIds['hostids']); - } - else { + if (!API::Host()->create($host)) { throw new Exception(); } - - add_audit_ext(AUDIT_ACTION_ADD, AUDIT_RESOURCE_HOST, $hostId, $host['host'], null, null, null); } else { $host['hostid'] = $hostId; @@ -856,16 +849,6 @@ elseif (hasRequest('add') || hasRequest('update')) { if (!API::Host()->update($host)) { throw new Exception(); } - - $dbHostNew = API::Host()->get([ - 'output' => API_OUTPUT_EXTEND, - 'hostids' => $hostId, - 'editable' => true - ]); - $dbHostNew = reset($dbHostNew); - - add_audit_ext(AUDIT_ACTION_UPDATE, AUDIT_RESOURCE_HOST, $dbHostNew['hostid'], $dbHostNew['host'], 'hosts', - $dbHost, $dbHostNew); } // full clone @@ -1001,13 +984,14 @@ elseif (hasRequest('hosts') && hasRequest('action') && str_in_array(getRequest(' 'templated_hosts' => true, 'output' => ['hostid'] ]); - $actHosts = zbx_objectValues($actHosts, 'hostid'); if ($actHosts) { - DBstart(); + foreach ($actHosts as &$host) { + $host['status'] = $status; + } + unset($host); - $result = updateHostStatus($actHosts, $status); - $result = DBend($result); + $result = (bool) API::Host()->update($actHosts); if ($result) { uncheckTableRows(); diff --git a/ui/include/classes/api/CAudit.php b/ui/include/classes/api/CAudit.php index 0b4aaee8e77..bb1f7c6453f 100644 --- a/ui/include/classes/api/CAudit.php +++ b/ui/include/classes/api/CAudit.php @@ -35,6 +35,7 @@ class CAudit { AUDIT_RESOURCE_DISCOVERY_RULE => ['druleid', 'name', 'drules'], AUDIT_RESOURCE_GRAPH => ['graphid', 'name', 'graphs'], AUDIT_RESOURCE_GRAPH_PROTOTYPE => ['graphid', 'name', 'graphs'], + AUDIT_RESOURCE_HOST => ['hostid', 'name', 'hosts'], AUDIT_RESOURCE_HOST_GROUP => ['groupid', 'name', 'groups'], AUDIT_RESOURCE_HOST_PROTOTYPE => ['hostid', 'host', 'hosts'], AUDIT_RESOURCE_ICON_MAP => ['iconmapid', 'name', 'icon_map'], diff --git a/ui/include/classes/api/services/CHost.php b/ui/include/classes/api/services/CHost.php index cacba3db1b9..00f0bb06a44 100644 --- a/ui/include/classes/api/services/CHost.php +++ b/ui/include/classes/api/services/CHost.php @@ -700,7 +700,7 @@ class CHost extends CHostGeneral { $hostids = []; $ins_tags = []; - foreach ($hosts as $host) { + foreach ($hosts as &$host) { // If visible name is not given or empty it should be set to host name. if (!array_key_exists('name', $host) || !trim($host['name'])) { $host['name'] = $host['host']; @@ -768,6 +768,9 @@ class CHost extends CHostGeneral { DB::insert('host_inventory', [$hostInventory], false); } } + unset($host); + + $this->addAuditBulk(AUDIT_ACTION_ADD, AUDIT_RESOURCE_HOST, $hosts); if ($ins_tags) { DB::insert('host_tag', $ins_tags); @@ -971,7 +974,10 @@ class CHost extends CHostGeneral { sort($hostids); $db_hosts = $this->get([ - 'output' => ['hostid', 'host'], + 'output' => ['hostid', 'proxy_hostid', 'host', 'status', 'ipmi_authtype', 'ipmi_privilege', 'ipmi_username', + 'ipmi_password', 'name', 'description', 'tls_connect', 'tls_accept', 'tls_issuer', 'tls_subject', + 'tls_psk_identity', 'tls_psk', 'inventory_mode' + ], 'hostids' => $hostids, 'editable' => true, 'preservekeys' => true @@ -1117,12 +1123,8 @@ class CHost extends CHostGeneral { $updateInventory['inventory_mode'] = $data['inventory_mode']; } - if (isset($data['status'])) { - $updateStatus = $data['status']; - } - unset($data['hosts'], $data['groups'], $data['interfaces'], $data['templates_clear'], $data['templates'], - $data['macros'], $data['inventory'], $data['inventory_mode'], $data['status']); + $data['macros'], $data['inventory'], $data['inventory_mode']); if (!zbx_empty($data)) { DB::update('hosts', [ @@ -1131,10 +1133,6 @@ class CHost extends CHostGeneral { ]); } - if (isset($updateStatus)) { - updateHostStatus($hostids, $updateStatus); - } - /* * Update template linkage */ @@ -1326,6 +1324,18 @@ class CHost extends CHostGeneral { } } + $new_hosts = []; + foreach ($db_hosts as $hostid => $db_host) { + $new_host = $data + $db_host; + if ($new_host['status'] != $db_host['status']) { + info(_s('Updated status of host "%1$s".', $new_host['host'])); + } + + $new_hosts[] = $new_host; + } + + $this->addAuditBulk(AUDIT_ACTION_UPDATE, AUDIT_RESOURCE_HOST, $new_hosts, $db_hosts); + return ['hostids' => $inputHostIds]; } diff --git a/ui/include/hosts.inc.php b/ui/include/hosts.inc.php index ed8f83a4cfe..43a103bb9fc 100644 --- a/ui/include/hosts.inc.php +++ b/ui/include/hosts.inc.php @@ -533,33 +533,6 @@ function get_host_by_hostid($hostid, $no_error_message = 0) { return false; } -function updateHostStatus($hostids, $status) { - zbx_value2array($hostids); - - $hostIds = []; - $oldStatus = ($status == HOST_STATUS_MONITORED ? HOST_STATUS_NOT_MONITORED : HOST_STATUS_MONITORED); - - $db_hosts = DBselect( - 'SELECT h.hostid,h.host,h.status'. - ' FROM hosts h'. - ' WHERE '.dbConditionInt('h.hostid', $hostids). - ' AND h.status='.zbx_dbstr($oldStatus) - ); - while ($host = DBfetch($db_hosts)) { - $hostIds[] = $host['hostid']; - - $host_new = $host; - $host_new['status'] = $status; - add_audit_ext(AUDIT_ACTION_UPDATE, AUDIT_RESOURCE_HOST, $host['hostid'], $host['host'], 'hosts', $host, $host_new); - info(_s('Updated status of host "%1$s".', $host['host'])); - } - - return DB::update('hosts', [ - 'values' => ['status' => $status], - 'where' => ['hostid' => $hostIds] - ]); -} - /** * Get parent templates for each given application. * -- cgit v1.2.3 From bbb9d01adaad6b5c49d5a28297560eae92d86ee7 Mon Sep 17 00:00:00 2001 From: Ivo Kurzemnieks Date: Thu, 6 Aug 2020 18:30:49 +0300 Subject: ..F....... [ZBX-18132] added OpenSSL extension check in frontend setup and SAML authentication form * commit 'd70ac7d61413240362d67b0ad6f09304189f2606': ..F....... [ZBX-18132] added OpenSSL extension check in frontend setup and SAML authentication form --- .../controllers/CControllerAuthenticationEdit.php | 4 +++ .../CControllerAuthenticationUpdate.php | 10 ++++++ .../views/administration.authentication.edit.php | 38 +++++++++++----------- ui/include/classes/setup/CFrontendSetup.php | 18 ++++++++++ 4 files changed, 51 insertions(+), 19 deletions(-) (limited to 'ui') diff --git a/ui/app/controllers/CControllerAuthenticationEdit.php b/ui/app/controllers/CControllerAuthenticationEdit.php index 298c945b85a..8e30f6fe3fb 100644 --- a/ui/app/controllers/CControllerAuthenticationEdit.php +++ b/ui/app/controllers/CControllerAuthenticationEdit.php @@ -87,6 +87,7 @@ class CControllerAuthenticationEdit extends CController { protected function doAction() { $ldap_status = (new CFrontendSetup())->checkPhpLdapModule(); + $openssl_status = (new CFrontendSetup())->checkPhpOpenSsl(); $data = [ 'action_submit' => 'authentication.update', @@ -94,6 +95,7 @@ class CControllerAuthenticationEdit extends CController { 'ldap_error' => ($ldap_status['result'] == CFrontendSetup::CHECK_OK) ? '' : $ldap_status['error'], 'ldap_test_password' => '', 'ldap_test_user' => CWebUser::$data['alias'], + 'saml_error' => ($openssl_status['result'] == CFrontendSetup::CHECK_OK) ? '' : $openssl_status['error'], 'change_bind_password' => 0, 'form_refresh' => 0 ]; @@ -146,6 +148,8 @@ class CControllerAuthenticationEdit extends CController { $data['ldap_enabled'] = ($ldap_status['result'] == CFrontendSetup::CHECK_OK && $data['ldap_configured'] == ZBX_AUTH_LDAP_ENABLED); + $data['saml_enabled'] = ($openssl_status['result'] == CFrontendSetup::CHECK_OK + && $data['saml_auth_enabled'] == ZBX_AUTH_SAML_ENABLED); $response = new CControllerResponseData($data); $response->setTitle(_('Configuration of authentication')); diff --git a/ui/app/controllers/CControllerAuthenticationUpdate.php b/ui/app/controllers/CControllerAuthenticationUpdate.php index 53cac78e739..9dba61be15a 100644 --- a/ui/app/controllers/CControllerAuthenticationUpdate.php +++ b/ui/app/controllers/CControllerAuthenticationUpdate.php @@ -183,6 +183,14 @@ class CControllerAuthenticationUpdate extends CController { * @return bool */ private function validateSamlAuth() { + $openssl_status = (new CFrontendSetup())->checkPhpOpenSsl(); + + if ($openssl_status['result'] != CFrontendSetup::CHECK_OK) { + $this->response->setMessageError($openssl_status['error']); + + return false; + } + $saml_fields = ['saml_idp_entityid', 'saml_sso_url', 'saml_sp_entityid', 'saml_username_attribute']; $config = select_config(); $this->getInputs($config, $saml_fields); @@ -221,6 +229,7 @@ class CControllerAuthenticationUpdate extends CController { if (!$auth_valid) { $this->response->setFormData($this->getInputAll()); $this->setResponse($this->response); + return; } @@ -229,6 +238,7 @@ class CControllerAuthenticationUpdate extends CController { $this->response->setMessageOk(_('LDAP login successful')); $this->response->setFormData($this->getInputAll()); $this->setResponse($this->response); + return; } diff --git a/ui/app/views/administration.authentication.edit.php b/ui/app/views/administration.authentication.edit.php index 2489607b998..b20f0914324 100644 --- a/ui/app/views/administration.authentication.edit.php +++ b/ui/app/views/administration.authentication.edit.php @@ -138,38 +138,38 @@ $ldap_tab = (new CFormList('list_ldap')) ); // SAML authentication fields. -$is_saml_auth_enabled = ($data['saml_auth_enabled'] == ZBX_AUTH_SAML_ENABLED); - $saml_tab = (new CFormList('list_saml')) ->addRow(new CLabel(_('Enable SAML authentication'), 'saml_auth_enabled'), - (new CCheckBox('saml_auth_enabled', ZBX_AUTH_SAML_ENABLED)) - ->setChecked($is_saml_auth_enabled) - ->setUncheckedValue(ZBX_AUTH_LDAP_DISABLED) + $data['saml_error'] + ? (new CLabel($data['saml_error']))->addClass(ZBX_STYLE_RED) + : (new CCheckBox('saml_auth_enabled', ZBX_AUTH_SAML_ENABLED)) + ->setChecked($data['saml_auth_enabled'] == ZBX_AUTH_SAML_ENABLED) + ->setUncheckedValue(ZBX_AUTH_SAML_DISABLED) ) ->addRow((new CLabel(_('IdP entity ID'), 'saml_idp_entityid'))->setAsteriskMark(), (new CTextBox('saml_idp_entityid', $data['saml_idp_entityid'], false, DB::getFieldLength('config', 'saml_idp_entityid') )) - ->setEnabled($is_saml_auth_enabled) + ->setEnabled($data['saml_enabled']) ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) ->setAriaRequired() ) ->addRow((new CLabel(_('SSO service URL'), 'saml_sso_url'))->setAsteriskMark(), (new CTextBox('saml_sso_url', $data['saml_sso_url'], false, DB::getFieldLength('config', 'saml_sso_url'))) - ->setEnabled($is_saml_auth_enabled) + ->setEnabled($data['saml_enabled']) ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) ->setAriaRequired() ) ->addRow(new CLabel(_('SLO service URL'), 'saml_slo_url'), (new CTextBox('saml_slo_url', $data['saml_slo_url'], false, DB::getFieldLength('config', 'saml_slo_url'))) - ->setEnabled($is_saml_auth_enabled) + ->setEnabled($data['saml_enabled']) ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) ) ->addRow((new CLabel(_('Username attribute'), 'saml_username_attribute'))->setAsteriskMark(), (new CTextBox('saml_username_attribute', $data['saml_username_attribute'], false, DB::getFieldLength('config', 'saml_username_attribute') )) - ->setEnabled($is_saml_auth_enabled) + ->setEnabled($data['saml_enabled']) ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) ->setAriaRequired() ) @@ -177,7 +177,7 @@ $saml_tab = (new CFormList('list_saml')) (new CTextBox('saml_sp_entityid', $data['saml_sp_entityid'], false, DB::getFieldLength('config', 'saml_sp_entityid') )) - ->setEnabled($is_saml_auth_enabled) + ->setEnabled($data['saml_enabled']) ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) ->setAriaRequired() ) @@ -185,7 +185,7 @@ $saml_tab = (new CFormList('list_saml')) (new CTextBox('saml_nameid_format', $data['saml_nameid_format'], false, DB::getFieldLength('config', 'saml_nameid_format') )) - ->setEnabled($is_saml_auth_enabled) + ->setEnabled($data['saml_enabled']) ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) ->setAttribute('placeholder', 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient') ) @@ -196,31 +196,31 @@ $saml_tab = (new CFormList('list_saml')) ->setLabel(_('Messages')) ->setChecked($data['saml_sign_messages'] == 1) ->setUncheckedValue(0) - ->setEnabled($is_saml_auth_enabled) + ->setEnabled($data['saml_enabled']) ) ->addItem((new CCheckBox('saml_sign_assertions')) ->setLabel(_('Assertions')) ->setChecked($data['saml_sign_assertions'] == 1) ->setUncheckedValue(0) - ->setEnabled($is_saml_auth_enabled) + ->setEnabled($data['saml_enabled']) ) ->addItem((new CCheckBox('saml_sign_authn_requests')) ->setLabel(_('AuthN requests')) ->setChecked($data['saml_sign_authn_requests'] == 1) ->setUncheckedValue(0) - ->setEnabled($is_saml_auth_enabled) + ->setEnabled($data['saml_enabled']) ) ->addItem((new CCheckBox('saml_sign_logout_requests')) ->setLabel(_('Logout requests')) ->setChecked($data['saml_sign_logout_requests'] == 1) ->setUncheckedValue(0) - ->setEnabled($is_saml_auth_enabled) + ->setEnabled($data['saml_enabled']) ) ->addItem((new CCheckBox('saml_sign_logout_responses')) ->setLabel(_('Logout responses')) ->setChecked($data['saml_sign_logout_responses'] == 1) ->setUncheckedValue(0) - ->setEnabled($is_saml_auth_enabled) + ->setEnabled($data['saml_enabled']) ) ) ->addRow(_('Encrypt'), @@ -230,20 +230,20 @@ $saml_tab = (new CFormList('list_saml')) ->setLabel(_('Name ID')) ->setChecked($data['saml_encrypt_nameid'] == 1) ->setUncheckedValue(0) - ->setEnabled($is_saml_auth_enabled) + ->setEnabled($data['saml_enabled']) ) ->addItem((new CCheckBox('saml_encrypt_assertions')) ->setLabel(_('Assertions')) ->setChecked($data['saml_encrypt_assertions'] == 1) ->setUncheckedValue(0) - ->setEnabled($is_saml_auth_enabled) + ->setEnabled($data['saml_enabled']) ) ) ->addRow(new CLabel(_('Case sensitive login'), 'saml_case_sensitive'), (new CCheckBox('saml_case_sensitive')) ->setChecked($data['saml_case_sensitive'] == ZBX_AUTH_CASE_SENSITIVE) ->setUncheckedValue(ZBX_AUTH_CASE_INSENSITIVE) - ->setEnabled($is_saml_auth_enabled) + ->setEnabled($data['saml_enabled']) ); (new CWidget()) diff --git a/ui/include/classes/setup/CFrontendSetup.php b/ui/include/classes/setup/CFrontendSetup.php index e3105881095..ca7585525ac 100644 --- a/ui/include/classes/setup/CFrontendSetup.php +++ b/ui/include/classes/setup/CFrontendSetup.php @@ -82,6 +82,7 @@ class CFrontendSetup { $result[] = $this->checkPhpXmlWriter(); $result[] = $this->checkPhpXmlReader(); $result[] = $this->checkPhpLdapModule(); + $result[] = $this->checkPhpOpenSsl(); $result[] = $this->checkPhpCtype(); $result[] = $this->checkPhpSession(); $result[] = $this->checkPhpSessionAutoStart(); @@ -557,6 +558,23 @@ class CFrontendSetup { ]; } + /** + * Checks for PHP OpenSSL extension. + * + * @return array + */ + public function checkPhpOpenSsl() { + $current = extension_loaded('openssl'); + + return [ + 'name' => _('PHP OpenSSL'), + 'current' => $current ? _('on') : _('off'), + 'required' => null, + 'result' => $current ? self::CHECK_OK : self::CHECK_WARNING, + 'error' => _('PHP OpenSSL extension missing.') + ]; + } + /** * Checks for PHP ctype extension. * -- cgit v1.2.3 From 34f8fa0b5f32bc618c1baf0bb755057e92810219 Mon Sep 17 00:00:00 2001 From: Ivo Kurzemnieks Date: Thu, 6 Aug 2020 18:40:07 +0300 Subject: ..F....... [ZBX-18149] fixed discovered hosts showing links to host prototypes which should not possible * commit 'bf469ddc602a1f65b5240626cf5ee4d08e931aa9': ..F....... [ZBX-18149] removed accidentally added field to request ..F....... [ZBX-18149] fixed discovered hosts showing links to host prototypes which should not possible --- ui/host_discovery.php | 2 +- ui/include/views/configuration.host.discovery.list.php | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'ui') diff --git a/ui/host_discovery.php b/ui/host_discovery.php index 83fb13431e0..94074b9025b 100644 --- a/ui/host_discovery.php +++ b/ui/host_discovery.php @@ -817,7 +817,7 @@ else { // Select LLD rules. $options = [ 'output' => API_OUTPUT_EXTEND, - 'selectHosts' => ['hostid', 'name', 'status'], + 'selectHosts' => ['hostid', 'name', 'status', 'flags'], 'selectItems' => API_OUTPUT_COUNT, 'selectGraphs' => API_OUTPUT_COUNT, 'selectTriggers' => API_OUTPUT_COUNT, diff --git a/ui/include/views/configuration.host.discovery.list.php b/ui/include/views/configuration.host.discovery.list.php index d9a8c7f9d00..c0c2f56bbce 100644 --- a/ui/include/views/configuration.host.discovery.list.php +++ b/ui/include/views/configuration.host.discovery.list.php @@ -263,12 +263,14 @@ foreach ($data['discoveries'] as $discovery) { ), CViewHelper::showNum($discovery['graphs']) ], - [ - new CLink(_('Host prototypes'), - (new CUrl('host_prototypes.php'))->setArgument('parent_discoveryid', $discovery['itemid']) - ), - CViewHelper::showNum($discovery['hostPrototypes']) - ], + ($discovery['hosts'][0]['flags'] == ZBX_FLAG_DISCOVERY_NORMAL) + ? [ + new CLink(_('Host prototypes'), + (new CUrl('host_prototypes.php'))->setArgument('parent_discoveryid', $discovery['itemid']) + ), + CViewHelper::showNum($discovery['hostPrototypes']) + ] + : '', (new CDiv(CHtml::encode($discovery['key_'])))->addClass(ZBX_STYLE_WORDWRAP), $discovery['delay'], item_type2str($discovery['type']), -- cgit v1.2.3