summaryrefslogtreecommitdiffstats
path: root/library/Director/Web
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-14 13:17:47 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-14 13:17:47 +0000
commit5419d4428c86c488a43124f85e5407d7cbae6541 (patch)
tree772c4221a20fd7d1b3e7e67c6e21755a50e80fd7 /library/Director/Web
parentAdding upstream version 1.10.2. (diff)
downloadicingaweb2-module-director-upstream.tar.xz
icingaweb2-module-director-upstream.zip
Adding upstream version 1.11.1.upstream/1.11.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/Director/Web')
-rw-r--r--library/Director/Web/Controller/ActionController.php26
-rw-r--r--library/Director/Web/Controller/BranchHelper.php40
-rw-r--r--library/Director/Web/Controller/Extension/DirectorDb.php3
-rw-r--r--library/Director/Web/Controller/Extension/RestApi.php3
-rw-r--r--library/Director/Web/Controller/Extension/SingleObjectApiHandler.php236
-rw-r--r--library/Director/Web/Controller/ObjectController.php30
-rw-r--r--library/Director/Web/Controller/ObjectsController.php28
-rw-r--r--library/Director/Web/Controller/TemplateController.php35
-rw-r--r--library/Director/Web/Form/CloneImportSourceForm.php30
-rw-r--r--library/Director/Web/Form/CloneSyncRuleForm.php26
-rw-r--r--library/Director/Web/Form/CsrfToken.php2
-rw-r--r--library/Director/Web/Form/DbSelectorForm.php2
-rw-r--r--library/Director/Web/Form/DirectorForm.php2
-rw-r--r--library/Director/Web/Form/DirectorObjectForm.php14
-rw-r--r--library/Director/Web/Form/Element/DataFilter.php20
-rw-r--r--library/Director/Web/Form/Element/ExtensibleSet.php2
-rw-r--r--library/Director/Web/Form/IcingaObjectFieldLoader.php2
-rw-r--r--library/Director/Web/Form/IplElement/ExtensibleSetElement.php6
-rw-r--r--library/Director/Web/Form/QuickForm.php4
-rw-r--r--library/Director/Web/SelfService.php14
-rw-r--r--library/Director/Web/Table/ActivityLogTable.php19
-rw-r--r--library/Director/Web/Table/ApplyRulesTable.php107
-rw-r--r--library/Director/Web/Table/BasketSnapshotTable.php5
-rw-r--r--library/Director/Web/Table/BranchActivityTable.php13
-rw-r--r--library/Director/Web/Table/ChoicesTable.php4
-rw-r--r--library/Director/Web/Table/CustomvarTable.php6
-rw-r--r--library/Director/Web/Table/CustomvarVariantsTable.php6
-rw-r--r--library/Director/Web/Table/DatafieldTable.php17
-rw-r--r--library/Director/Web/Table/DependencyTemplateUsageTable.php12
-rw-r--r--library/Director/Web/Table/DeploymentLogTable.php3
-rw-r--r--library/Director/Web/Table/GroupMemberTable.php18
-rw-r--r--library/Director/Web/Table/HostTemplateUsageTable.php8
-rw-r--r--library/Director/Web/Table/IcingaServiceSetServiceTable.php31
-rw-r--r--library/Director/Web/Table/IntlZfQueryBasedTable.php51
-rw-r--r--library/Director/Web/Table/NotificationTemplateUsageTable.php12
-rw-r--r--library/Director/Web/Table/ObjectSetTable.php68
-rw-r--r--library/Director/Web/Table/ObjectsTable.php77
-rw-r--r--library/Director/Web/Table/ObjectsTableService.php6
-rw-r--r--library/Director/Web/Table/ObjectsTableSetMembers.php255
-rw-r--r--library/Director/Web/Table/ReadOnlyFormAvpTable.php113
-rw-r--r--library/Director/Web/Table/ServiceTemplateUsageTable.php26
-rw-r--r--library/Director/Web/Table/SyncRunTable.php9
-rw-r--r--library/Director/Web/Table/TableWithBranchSupport.php3
-rw-r--r--library/Director/Web/Table/TemplateUsageTable.php104
-rw-r--r--library/Director/Web/Table/TemplatesTable.php22
-rw-r--r--library/Director/Web/Tabs/InfraTabs.php7
-rw-r--r--library/Director/Web/Tabs/MainTabs.php5
-rw-r--r--library/Director/Web/Tabs/ObjectTabs.php35
-rw-r--r--library/Director/Web/Tabs/ObjectsTabs.php58
-rw-r--r--library/Director/Web/Tree/TemplateTreeRenderer.php2
-rw-r--r--library/Director/Web/Widget/ActivityLogInfo.php46
-rw-r--r--library/Director/Web/Widget/AdditionalTableActions.php5
-rw-r--r--library/Director/Web/Widget/BranchedObjectHint.php48
-rw-r--r--library/Director/Web/Widget/BranchedObjectsHint.php7
-rw-r--r--library/Director/Web/Widget/DeploymentInfo.php27
-rw-r--r--library/Director/Web/Widget/IcingaObjectInspection.php2
56 files changed, 1036 insertions, 726 deletions
diff --git a/library/Director/Web/Controller/ActionController.php b/library/Director/Web/Controller/ActionController.php
index 6282a16..e851d82 100644
--- a/library/Director/Web/Controller/ActionController.php
+++ b/library/Director/Web/Controller/ActionController.php
@@ -4,10 +4,14 @@ namespace Icinga\Module\Director\Web\Controller;
use gipfl\Translation\StaticTranslator;
use Icinga\Application\Benchmark;
+use Icinga\Application\Modules\Module;
use Icinga\Data\Paginatable;
use Icinga\Exception\NotFoundError;
use Icinga\Exception\ProgrammingError;
-use Icinga\Module\Director\Monitoring;
+use Icinga\Module\Director\Integration\Icingadb\IcingadbBackend;
+use Icinga\Module\Director\Integration\BackendInterface;
+use Icinga\Module\Director\Integration\MonitoringModule\Monitoring;
+use Icinga\Module\Director\ProvidedHook\Icingadb\IcingadbSupport;
use Icinga\Module\Director\Web\Controller\Extension\CoreApi;
use Icinga\Module\Director\Web\Controller\Extension\DirectorDb;
use Icinga\Module\Director\Web\Controller\Extension\RestApi;
@@ -36,8 +40,8 @@ abstract class ActionController extends Controller implements ControlsAndContent
/** @var UrlParams Hint for IDE, somehow does not work in web */
protected $params;
- /** @var Monitoring */
- private $monitoring;
+ /** @var BackendInterface */
+ private $backend;
/**
* @throws SecurityException
@@ -219,7 +223,7 @@ abstract class ActionController extends Controller implements ControlsAndContent
// Hint -> $this->view->compact is the only way since v2.8.0
if ($this->view->compact || $this->getOriginalUrl()->getParam('view') === 'compact') {
if ($this->view->controls) {
- $this->controls()->getAttributes()->add('style', 'display: none;');
+ $this->controls()->getAttributes()->add('class', 'compact');
}
}
} else {
@@ -240,14 +244,18 @@ abstract class ActionController extends Controller implements ControlsAndContent
}
/**
- * @return Monitoring
+ * @return BackendInterface
*/
- protected function monitoring()
+ protected function backend(): BackendInterface
{
- if ($this->monitoring === null) {
- $this->monitoring = new Monitoring;
+ if ($this->backend === null) {
+ if (Module::exists('icingadb') && IcingadbSupport::useIcingaDbAsBackend()) {
+ $this->backend = new IcingadbBackend();
+ } else {
+ $this->backend = new Monitoring($this->getAuth());
+ }
}
- return $this->monitoring;
+ return $this->backend;
}
}
diff --git a/library/Director/Web/Controller/BranchHelper.php b/library/Director/Web/Controller/BranchHelper.php
index ac2a480..89aa6c1 100644
--- a/library/Director/Web/Controller/BranchHelper.php
+++ b/library/Director/Web/Controller/BranchHelper.php
@@ -3,12 +3,13 @@
namespace Icinga\Module\Director\Web\Controller;
use Icinga\Module\Director\Data\Db\DbObjectStore;
-use Icinga\Module\Director\Data\Db\DbObjectTypeRegistry;
use Icinga\Module\Director\Db\Branch\Branch;
use Icinga\Module\Director\Db\Branch\BranchStore;
use Icinga\Module\Director\Db\Branch\BranchSupport;
+use Icinga\Module\Director\Db\Branch\PreferredBranchSupport;
use Icinga\Module\Director\Objects\IcingaObject;
use Icinga\Module\Director\Web\Widget\NotInBranchedHint;
+use Ramsey\Uuid\UuidInterface;
trait BranchHelper
{
@@ -18,15 +19,21 @@ trait BranchHelper
/** @var BranchStore */
protected $branchStore;
+ /** @var ?bool */
+ protected $hasPreferredBranch = null;
+
/**
- * @return false|\Ramsey\Uuid\UuidInterface
+ * @return ?UuidInterface
*/
- protected function getBranchUuid()
+ protected function getBranchUuid(): ?UuidInterface
{
return $this->getBranch()->getUuid();
}
- protected function getBranch()
+ /**
+ * @return Branch
+ */
+ protected function getBranch(): Branch
{
if ($this->branch === null) {
/** @var ActionController $this */
@@ -39,7 +46,7 @@ trait BranchHelper
/**
* @return BranchStore
*/
- protected function getBranchStore()
+ protected function getBranchStore(): BranchStore
{
if ($this->branchStore === null) {
$this->branchStore = new BranchStore($this->db());
@@ -48,12 +55,15 @@ trait BranchHelper
return $this->branchStore;
}
- protected function hasBranch()
+ /**
+ * @return bool
+ */
+ protected function hasBranch(): bool
{
return $this->getBranchUuid() !== null;
}
- protected function enableStaticObjectLoader($table)
+ protected function enableStaticObjectLoader($table): void
{
if (BranchSupport::existsForTableName($table)) {
IcingaObject::setDbObjectStore(new DbObjectStore($this->db(), $this->getBranch()));
@@ -64,7 +74,7 @@ trait BranchHelper
* @param string $subject
* @return bool
*/
- protected function showNotInBranch($subject)
+ protected function showNotInBranch($subject): bool
{
if ($this->getBranch()->isBranch()) {
$this->content()->add(new NotInBranchedHint($subject, $this->getBranch(), $this->Auth()));
@@ -73,4 +83,18 @@ trait BranchHelper
return false;
}
+
+ protected function hasPreferredBranch(): bool
+ {
+ if ($this->hasPreferredBranch === null) {
+ $implementation = Branch::optionalHook();
+ if ($implementation instanceof PreferredBranchSupport) {
+ $this->hasPreferredBranch = $implementation->hasPreferredBranch($this->Auth());
+ } else {
+ $this->hasPreferredBranch = false;
+ }
+ }
+
+ return $this->hasPreferredBranch;
+ }
}
diff --git a/library/Director/Web/Controller/Extension/DirectorDb.php b/library/Director/Web/Controller/Extension/DirectorDb.php
index 03bec81..c36e358 100644
--- a/library/Director/Web/Controller/Extension/DirectorDb.php
+++ b/library/Director/Web/Controller/Extension/DirectorDb.php
@@ -2,6 +2,7 @@
namespace Icinga\Module\Director\Web\Controller\Extension;
+use Icinga\Module\Director\Auth\Restriction;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Web\Controller\ActionController;
use Icinga\Module\Director\Web\Window;
@@ -65,7 +66,7 @@ trait DirectorDb
$auth = $this->Auth();
$available = $this->listAvailableDbResourceNames();
- if ($resourceNames = $auth->getRestrictions('director/db_resource')) {
+ if ($resourceNames = $auth->getRestrictions(Restriction::DB_RESOURCE)) {
$names = [];
foreach ($resourceNames as $rNames) {
foreach ($this->splitList($rNames) as $name) {
diff --git a/library/Director/Web/Controller/Extension/RestApi.php b/library/Director/Web/Controller/Extension/RestApi.php
index 3158f49..fb10c86 100644
--- a/library/Director/Web/Controller/Extension/RestApi.php
+++ b/library/Director/Web/Controller/Extension/RestApi.php
@@ -4,6 +4,7 @@ namespace Icinga\Module\Director\Web\Controller\Extension;
use Icinga\Exception\AuthenticationException;
use Icinga\Exception\NotFoundError;
+use Icinga\Module\Director\Auth\Permission;
use Icinga\Module\Director\Exception\JsonException;
use Icinga\Web\Response;
use InvalidArgumentException;
@@ -55,7 +56,7 @@ trait RestApi
*/
protected function assertApiPermission()
{
- if (! $this->hasPermission('director/api')) {
+ if (! $this->hasPermission(Permission::API)) {
throw new AuthenticationException('You are not allowed to access this API');
}
}
diff --git a/library/Director/Web/Controller/Extension/SingleObjectApiHandler.php b/library/Director/Web/Controller/Extension/SingleObjectApiHandler.php
deleted file mode 100644
index bc51548..0000000
--- a/library/Director/Web/Controller/Extension/SingleObjectApiHandler.php
+++ /dev/null
@@ -1,236 +0,0 @@
-<?php
-
-namespace Icinga\Module\Director\Web\Controller\Extension;
-
-use Exception;
-use Icinga\Exception\IcingaException;
-use Icinga\Exception\InvalidPropertyException;
-use Icinga\Exception\NotFoundError;
-use Icinga\Module\Director\Forms\IcingaDeleteObjectForm;
-use Icinga\Module\Director\Objects\IcingaObject;
-use Icinga\Web\Request;
-use Icinga\Web\Response;
-
-class SingleObjectApiHandler
-{
- use DirectorDb;
-
- /** @var IcingaObject */
- private $object;
-
- /** @var string */
- private $type;
-
- /** @var Request */
- private $request;
-
- /** @var Response */
- private $response;
-
- /** @var \Icinga\Web\UrlParams */
- private $params;
-
- public function __construct($type, Request $request, Response $response)
- {
- $this->type = $type;
- $this->request = $request;
- $this->response = $response;
- $this->params = $request->getUrl()->getParams();
- }
-
- public function runFailSafe()
- {
- try {
- $this->loadObject();
- $this->run();
- } catch (NotFoundError $e) {
- $this->sendJsonError($e->getMessage(), 404);
- } catch (Exception $e) {
- $response = $this->response;
- if ($response->getHttpResponseCode() === 200) {
- $response->setHttpResponseCode(500);
- }
-
- $this->sendJsonError($e->getMessage());
- }
- }
-
- protected function retrieveObject()
- {
- $this->requireObject();
- $this->sendJson(
- $this->object->toPlainObject(
- $this->params->shift('resolved'),
- ! $this->params->shift('withNull'),
- $this->params->shift('properties')
- )
- );
- }
-
- protected function deleteObject()
- {
- $this->requireObject();
- $obj = $this->object->toPlainObject(false, true);
- $form = new IcingaDeleteObjectForm();
- $form->setObject($this->object)
- ->setRequest($this->request)
- ->onSuccess();
-
- $this->sendJson($obj);
- }
-
- protected function storeObject()
- {
- $data = json_decode($this->request->getRawBody());
-
- if ($data === null) {
- $this->response->setHttpResponseCode(400);
- throw new IcingaException(
- 'Invalid JSON: %s' . $this->request->getRawBody(),
- $this->getLastJsonError()
- );
- } else {
- $data = (array) $data;
- }
-
- if ($object = $this->object) {
- if ($this->request->getMethod() === 'POST') {
- $object->setProperties($data);
- } else {
- $data = array_merge([
- 'object_type' => $object->object_type,
- 'object_name' => $object->object_name
- ], $data);
- $object->replaceWith(
- IcingaObject::createByType($this->type, $data, $db)
- );
- }
- } else {
- $object = IcingaObject::createByType($this->type, $data, $db);
- }
-
- if ($object->hasBeenModified()) {
- $status = $object->hasBeenLoadedFromDb() ? 200 : 201;
- $object->store();
- $this->response->setHttpResponseCode($status);
- } else {
- $this->response->setHttpResponseCode(304);
- }
-
- $this->sendJson($object->toPlainObject(false, true));
- }
-
- public function run()
- {
- switch ($this->request->getMethod()) {
- case 'DELETE':
- $this->deleteObject();
- break;
-
- case 'POST':
- case 'PUT':
- $this->storeObject();
- break;
-
- case 'GET':
- $this->retrieveObject();
- break;
-
- default:
- $this->response->setHttpResponseCode(400);
- throw new IcingaException(
- 'Unsupported method: %s',
- $this->request->getMethod()
- );
- }
- }
-
- protected function requireObject()
- {
- if (! $this->object) {
- $this->response->setHttpResponseCode(404);
- if (! $this->params->get('name')) {
- throw new NotFoundError('You need to pass a "name" parameter to access a specific object');
- } else {
- throw new NotFoundError('No such object available');
- }
- }
- }
-
- // TODO: just return json_last_error_msg() for PHP >= 5.5.0
- protected function getLastJsonError()
- {
- switch (json_last_error()) {
- case JSON_ERROR_DEPTH:
- return 'The maximum stack depth has been exceeded';
- case JSON_ERROR_CTRL_CHAR:
- return 'Control character error, possibly incorrectly encoded';
- case JSON_ERROR_STATE_MISMATCH:
- return 'Invalid or malformed JSON';
- case JSON_ERROR_SYNTAX:
- return 'Syntax error';
- case JSON_ERROR_UTF8:
- return 'Malformed UTF-8 characters, possibly incorrectly encoded';
- default:
- return 'An error occured when parsing a JSON string';
- }
- }
-
- protected function sendJson($object)
- {
- $this->response->setHeader('Content-Type', 'application/json', true);
- $this->_helper->layout()->disableLayout();
- $this->_helper->viewRenderer->setNoRender(true);
- echo json_encode($object, JSON_PRETTY_PRINT) . "\n";
- }
-
- protected function sendJsonError($message, $code = null)
- {
- $response = $this->response;
-
- if ($code !== null) {
- $response->setHttpResponseCode((int) $code);
- }
-
- $this->sendJson((object) ['error' => $message]);
- }
-
- protected function loadObject()
- {
- if ($this->object === null) {
- if ($name = $this->params->get('name')) {
- $this->object = IcingaObject::loadByType(
- $this->type,
- $name,
- $this->db()
- );
-
- if (! $this->allowsObject($this->object)) {
- $this->object = null;
- throw new NotFoundError('No such object available');
- }
- } elseif ($id = $this->params->get('id')) {
- $this->object = IcingaObject::loadByType(
- $this->type,
- (int) $id,
- $this->db()
- );
- } elseif ($this->request->isApiRequest()) {
- if ($this->request->isGet()) {
- $this->response->setHttpResponseCode(422);
-
- throw new InvalidPropertyException(
- 'Cannot load object, missing parameters'
- );
- }
- }
- }
-
- return $this->object;
- }
-
- protected function allowsObject(IcingaObject $object)
- {
- return true;
- }
-}
diff --git a/library/Director/Web/Controller/ObjectController.php b/library/Director/Web/Controller/ObjectController.php
index 0c06937..994a717 100644
--- a/library/Director/Web/Controller/ObjectController.php
+++ b/library/Director/Web/Controller/ObjectController.php
@@ -10,6 +10,7 @@ use Icinga\Exception\ProgrammingError;
use Icinga\Module\Director\Data\Db\DbObjectTypeRegistry;
use Icinga\Module\Director\Db\Branch\Branch;
use Icinga\Module\Director\Db\Branch\BranchedObject;
+use Icinga\Module\Director\Db\Branch\BranchSupport;
use Icinga\Module\Director\Db\Branch\UuidLookup;
use Icinga\Module\Director\Deployment\DeploymentInfo;
use Icinga\Module\Director\DirectorObject\Automation\ExportInterface;
@@ -61,8 +62,11 @@ abstract class ObjectController extends ActionController
public function init()
{
- parent::init();
$this->enableStaticObjectLoader($this->getTableName());
+ if (! $this->getRequest()->isApiRequest()) {
+ $this->loadOptionalObject();
+ }
+ parent::init();
if ($this->getRequest()->isApiRequest()) {
$this->initializeRestApi();
} else {
@@ -97,7 +101,6 @@ abstract class ObjectController extends ActionController
protected function initializeWebRequest()
{
- $this->loadOptionalObject();
if ($this->getRequest()->getActionName() === 'add') {
$this->addSingleTab(
sprintf($this->translate('Add %s'), ucfirst($this->getType())),
@@ -151,8 +154,11 @@ abstract class ObjectController extends ActionController
$this->addObject();
}
$branch = $this->getBranch();
- if ($branch->isBranch() && ! $this->getRequest()->isApiRequest()) {
- $this->content()->add(new BranchedObjectHint($branch, $this->Auth()));
+ if (! $this->getRequest()->isApiRequest()) {
+ $hasPreferred = $this->hasPreferredBranch();
+ if ($branch->isBranch() || $hasPreferred) {
+ $this->content()->add(new BranchedObjectHint($branch, $this->Auth(), null, $hasPreferred));
+ }
}
$form->handleRequest();
@@ -267,7 +273,7 @@ abstract class ObjectController extends ActionController
if ($id = $this->params->get('field_id')) {
$form->loadObject([
- "${type}_id" => $object->id,
+ "{$type}_id" => $object->id,
'datafield_id' => $id
]);
@@ -362,7 +368,7 @@ abstract class ObjectController extends ActionController
$this->actions()->add([
Link::create(
$this->translate('Usage'),
- "director/${type}template/usage",
+ "director/{$type}template/usage",
['name' => $object->getObjectName()],
['class' => 'icon-sitemap']
)
@@ -558,8 +564,16 @@ abstract class ObjectController extends ActionController
if (! $this->allowsObject($object)) {
throw new NotFoundError('No such object available');
}
- if ($showHint && $branch->isBranch() && $object->isObject() && ! $this->getRequest()->isApiRequest()) {
- $this->content()->add(new BranchedObjectHint($branch, $this->Auth(), $branchedObject));
+ if ($showHint) {
+ $hasPreferredBranch = $this->hasPreferredBranch();
+ if (($hasPreferredBranch || $branch->isBranch())
+ && $object->isObject()
+ && ! $this->getRequest()->isApiRequest()
+ ) {
+ $this->content()->add(
+ new BranchedObjectHint($branch, $this->Auth(), $branchedObject, $hasPreferredBranch)
+ );
+ }
}
return $object;
diff --git a/library/Director/Web/Controller/ObjectsController.php b/library/Director/Web/Controller/ObjectsController.php
index 8c10b44..c4c96c5 100644
--- a/library/Director/Web/Controller/ObjectsController.php
+++ b/library/Director/Web/Controller/ObjectsController.php
@@ -13,6 +13,7 @@ use Icinga\Module\Director\Forms\IcingaMultiEditForm;
use Icinga\Module\Director\Objects\IcingaCommand;
use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Objects\IcingaObject;
+use Icinga\Module\Director\Objects\IcingaService;
use Icinga\Module\Director\RestApi\IcingaObjectsHandler;
use Icinga\Module\Director\Web\ActionBar\ObjectsActionBar;
use Icinga\Module\Director\Web\ActionBar\TemplateActionBar;
@@ -84,8 +85,9 @@ abstract class ObjectsController extends ActionController
} elseif ($request->getActionName() === 'applyrules') {
$table->filterObjectType('apply');
}
+ /** @var ?string $search */
$search = $this->params->get('q');
- if ($search !== null && \strlen($search) > 0) {
+ if ($search) {
$table->search($search);
}
@@ -110,7 +112,7 @@ abstract class ObjectsController extends ActionController
$type = $this->getType();
if ($this->params->get('format') === 'json') {
$filename = sprintf(
- "director-${type}_%s.json",
+ "director-{$type}_%s.json",
date('YmdHis')
);
$this->getResponse()->setHeader('Content-disposition', "attachment; filename=$filename", true);
@@ -124,7 +126,7 @@ abstract class ObjectsController extends ActionController
->addTitle($this->translate(ucfirst($this->getPluralType())))
->actions(new ObjectsActionBar($this->getBaseObjectUrl(), $this->url()));
- $this->content()->add(new BranchedObjectsHint($this->getBranch(), $this->Auth()));
+ $this->content()->add(new BranchedObjectsHint($this->getBranch(), $this->Auth(), $this->hasPreferredBranch()));
if ($type === 'command' && $this->params->get('type') === 'external_object') {
$this->tabs()->activate('external');
@@ -143,8 +145,7 @@ abstract class ObjectsController extends ActionController
*/
protected function getTable()
{
- $table = ObjectsTable::create($this->getType(), $this->db())
- ->setAuth($this->getAuth())
+ $table = ObjectsTable::create($this->getType(), $this->db(), $this->getAuth())
->setBranchUuid($this->getBranchUuid())
->setBaseObjectUrl($this->getBaseObjectUrl());
@@ -157,7 +158,7 @@ abstract class ObjectsController extends ActionController
*/
protected function getApplyRulesTable()
{
- $table = new ApplyRulesTable($this->db());
+ $table = (new ApplyRulesTable($this->db()))->setBranch($this->getBranch());
$table->setType($this->getType())
->setBaseObjectUrl($this->getBaseObjectUrl());
$this->eventuallyFilterCommand($table);
@@ -235,7 +236,7 @@ abstract class ObjectsController extends ActionController
if ($this->params->get('format') === 'json') {
$filename = sprintf(
- "director-${type}-templates_%s.json",
+ "director-{$type}-templates_%s.json",
date('YmdHis')
);
$this->getResponse()->setHeader('Content-disposition', "attachment; filename=$filename", true);
@@ -290,7 +291,7 @@ abstract class ObjectsController extends ActionController
if ($this->params->get('format') === 'json') {
$filename = sprintf(
- "director-${type}-applyrules_%s.json",
+ "director-{$type}-applyrules_%s.json",
date('YmdHis')
);
$this->getResponse()->setHeader('Content-disposition', "attachment; filename=$filename", true);
@@ -313,7 +314,7 @@ abstract class ObjectsController extends ActionController
->add(
Link::create(
$this->translate('Add'),
- "${baseUrl}/add",
+ "{$baseUrl}/add",
['type' => 'apply'],
[
'title' => sprintf(
@@ -354,7 +355,7 @@ abstract class ObjectsController extends ActionController
$this->actions()->add(
Link::create(
$this->translate('Add'),
- "director/${type}set/add",
+ "director/{$type}set/add",
null,
[
'title' => sprintf(
@@ -409,7 +410,12 @@ abstract class ObjectsController extends ActionController
$objects[$name] = $class::load($name, $db);
} elseif ($col === 'uuid') {
$object = $store->load($table, Uuid::fromString($ex->getExpression()));
- $objects[$object->getObjectName()] = $object;
+ if ($object instanceof IcingaService) {
+ $host = $object->getRelated('host');
+ $objects[$host->getObjectName() . ': ' . $object->getObjectName()] = $object;
+ } else {
+ $objects[$object->getObjectName()] = $object;
+ }
} else {
throw new InvalidArgumentException("'$col' is no a valid key component for '$type'");
}
diff --git a/library/Director/Web/Controller/TemplateController.php b/library/Director/Web/Controller/TemplateController.php
index c368a82..4f0898a 100644
--- a/library/Director/Web/Controller/TemplateController.php
+++ b/library/Director/Web/Controller/TemplateController.php
@@ -3,6 +3,7 @@
namespace Icinga\Module\Director\Web\Controller;
use gipfl\Web\Widget\Hint;
+use Icinga\Module\Director\Auth\Permission;
use Icinga\Module\Director\DirectorObject\Automation\ExportInterface;
use Icinga\Module\Director\Exception\NestingError;
use Icinga\Module\Director\Objects\IcingaCommand;
@@ -10,6 +11,7 @@ use Icinga\Module\Director\Objects\IcingaObject;
use Icinga\Module\Director\Web\Controller\Extension\DirectorDb;
use Icinga\Module\Director\Web\Table\ApplyRulesTable;
use Icinga\Module\Director\Web\Table\ObjectsTable;
+use Icinga\Module\Director\Web\Table\ObjectsTableSetMembers;
use Icinga\Module\Director\Web\Table\TemplatesTable;
use Icinga\Module\Director\Web\Table\TemplateUsageTable;
use Icinga\Module\Director\Web\Tabs\ObjectTabs;
@@ -23,6 +25,8 @@ abstract class TemplateController extends CompatController
{
use DirectorDb;
+ use BranchHelper;
+
/** @var IcingaObject */
protected $template;
@@ -39,9 +43,29 @@ abstract class TemplateController extends CompatController
$template->getObjectName()
)->addBackToUsageLink($template);
- ObjectsTable::create($this->getType(), $this->db())
- ->setAuth($this->Auth())
+ ObjectsTable::create($this->getType(), $this->db(), $this->Auth())
+ ->setBranch($this->getBranch())
+ ->setBaseObjectUrl($this->getBaseObjectUrl())
+ ->filterTemplate($template, $this->getInheritance())
+ ->renderTo($this);
+ }
+
+ public function setmembersAction()
+ {
+ $template = $this->requireTemplate();
+ $plural = $this->getTranslatedPluralType();
+ $this
+ ->addSingleTab($plural)
+ ->setAutorefreshInterval(10)
+ ->addTitle(
+ $this->translate('%s in service sets based on %s'),
+ $plural,
+ $template->getObjectName()
+ )->addBackToUsageLink($template);
+
+ ObjectsTableSetMembers::create($this->getType(), $this->db(), $this->Auth())
->setBaseObjectUrl($this->getBaseObjectUrl())
+ ->setBranch($this->getBranch())
->filterTemplate($template, $this->getInheritance())
->renderTo($this);
}
@@ -60,6 +84,7 @@ abstract class TemplateController extends CompatController
ApplyRulesTable::create($type, $this->db())
->setBaseObjectUrl($this->getBaseObjectUrl())
+ ->setBranch($this->getBranch())
->filterTemplate($template, $this->params->get('inheritance', 'direct'))
->renderTo($this);
}
@@ -93,7 +118,7 @@ abstract class TemplateController extends CompatController
$this->actions()->add(
Link::create(
$this->translate('Back'),
- "director/${type}template/usage",
+ "director/{$type}template/usage",
['name' => $template->getObjectName()],
['class' => 'icon-left-big']
)
@@ -152,7 +177,7 @@ abstract class TemplateController extends CompatController
)]
));
}
- if ($auth->hasPermission('director/admin')) {
+ if ($auth->hasPermission(Permission::ADMIN)) {
$list->addItem(new FormattedString(
$this->translate('Create a new %s inheriting from this one'),
[Link::create(
@@ -188,7 +213,7 @@ abstract class TemplateController extends CompatController
try {
$this->content()->add(
- TemplateUsageTable::forTemplate($template)
+ TemplateUsageTable::forTemplate($template, $this->Auth(), $this->getBranch())
);
} catch (NestingError $e) {
$this->content()->add(Hint::error($e->getMessage()));
diff --git a/library/Director/Web/Form/CloneImportSourceForm.php b/library/Director/Web/Form/CloneImportSourceForm.php
index 0849dd4..46dc7a3 100644
--- a/library/Director/Web/Form/CloneImportSourceForm.php
+++ b/library/Director/Web/Form/CloneImportSourceForm.php
@@ -2,8 +2,10 @@
namespace Icinga\Module\Director\Web\Form;
+use gipfl\Web\Form;
use Icinga\Module\Director\Data\Exporter;
-use ipl\Html\Form;
+use Icinga\Module\Director\Data\ObjectImporter;
+use Icinga\Module\Director\Db;
use ipl\Html\FormDecorator\DdDtDecorator;
use gipfl\Translation\TranslationHelper;
use gipfl\IcingaWeb2\Url;
@@ -36,37 +38,25 @@ class CloneImportSourceForm extends Form
]);
}
- /**
- * @return \Icinga\Module\Director\Db
- */
- protected function getTargetDb()
- {
- return $this->source->getConnection();
- }
-
- /**
- * @throws \Icinga\Module\Director\Exception\DuplicateKeyException
- */
public function onSuccess()
{
- $db = $this->getTargetDb();
+ $db = $this->source->getConnection();
+ assert($db instanceof Db);
$export = (new Exporter($db))->export($this->source);
$newName = $this->getElement('source_name')->getValue();
$export->source_name = $newName;
- unset($export->originalId);
+ unset($export->uuid);
+
if (ImportSource::existsWithName($newName, $db)) {
$this->getElement('source_name')->addMessage('Name already exists');
}
- $this->newSource = ImportSource::import($export, $db);
+ $importer = new ObjectImporter($db);
+ $this->newSource = $importer->import(ImportSource::class, $export);
$this->newSource->store();
}
public function getSuccessUrl()
{
- if ($this->newSource === null) {
- return parent::getSuccessUrl();
- } else {
- return Url::fromPath('director/importsource', ['id' => $this->newSource->get('id')]);
- }
+ return Url::fromPath('director/importsource', ['id' => $this->newSource->get('id')]);
}
}
diff --git a/library/Director/Web/Form/CloneSyncRuleForm.php b/library/Director/Web/Form/CloneSyncRuleForm.php
index f90b593..ccd61ec 100644
--- a/library/Director/Web/Form/CloneSyncRuleForm.php
+++ b/library/Director/Web/Form/CloneSyncRuleForm.php
@@ -2,8 +2,10 @@
namespace Icinga\Module\Director\Web\Form;
+use gipfl\Web\Form;
use Icinga\Module\Director\Data\Exporter;
-use ipl\Html\Form;
+use Icinga\Module\Director\Data\ObjectImporter;
+use Icinga\Module\Director\Db;
use ipl\Html\FormDecorator\DdDtDecorator;
use gipfl\Translation\TranslationHelper;
use gipfl\IcingaWeb2\Url;
@@ -37,40 +39,30 @@ class CloneSyncRuleForm extends Form
}
/**
- * @return \Icinga\Module\Director\Db
- */
- protected function getTargetDb()
- {
- return $this->rule->getConnection();
- }
-
- /**
* @throws \Icinga\Exception\NotFoundError
* @throws \Icinga\Module\Director\Exception\DuplicateKeyException
*/
public function onSuccess()
{
- $db = $this->getTargetDb();
+ $db = $this->rule->getConnection();
+ assert($db instanceof Db);
$exporter = new Exporter($db);
$export = $exporter->export($this->rule);
$newName = $this->getValue('rule_name');
$export->rule_name = $newName;
- unset($export->originalId);
+ unset($export->uuid);
if (SyncRule::existsWithName($newName, $db)) {
$this->getElement('rule_name')->addMessage('Name already exists');
}
- $this->newRule = SyncRule::import($export, $db);
+ $importer = new ObjectImporter($db);
+ $this->newRule = $importer->import(SyncRule::class, $export);
$this->newRule->store();
}
public function getSuccessUrl()
{
- if ($this->newRule === null) {
- return parent::getSuccessUrl();
- } else {
- return Url::fromPath('director/syncrule', ['id' => $this->newRule->get('id')]);
- }
+ return Url::fromPath('director/syncrule', ['id' => $this->newRule->get('id')]);
}
}
diff --git a/library/Director/Web/Form/CsrfToken.php b/library/Director/Web/Form/CsrfToken.php
index 24edf88..f6c29ec 100644
--- a/library/Director/Web/Form/CsrfToken.php
+++ b/library/Director/Web/Form/CsrfToken.php
@@ -17,7 +17,7 @@ class CsrfToken
return false;
}
- list($seed, $token) = explode('|', $elementValue);
+ list($seed, $token) = explode('|', $token);
if (!is_numeric($seed)) {
return false;
diff --git a/library/Director/Web/Form/DbSelectorForm.php b/library/Director/Web/Form/DbSelectorForm.php
index 52fe5ea..8b4f432 100644
--- a/library/Director/Web/Form/DbSelectorForm.php
+++ b/library/Director/Web/Form/DbSelectorForm.php
@@ -69,7 +69,7 @@ class DbSelectorForm extends Form
$params = [];
}
- if (array_key_exists($name, $params)) {
+ if (is_array($params) && array_key_exists($name, $params)) {
return $params[$name];
}
diff --git a/library/Director/Web/Form/DirectorForm.php b/library/Director/Web/Form/DirectorForm.php
index 145be5b..36c0577 100644
--- a/library/Director/Web/Form/DirectorForm.php
+++ b/library/Director/Web/Form/DirectorForm.php
@@ -34,7 +34,7 @@ abstract class DirectorForm extends QuickForm
public static function load()
{
return new static([
- 'icingaModule' => Icinga::App()->getModuleManager()->getModule('director')
+ 'icingaModule' => Icinga::app()->getModuleManager()->getModule('director')
]);
}
diff --git a/library/Director/Web/Form/DirectorObjectForm.php b/library/Director/Web/Form/DirectorObjectForm.php
index b70bd7b..abbd4f0 100644
--- a/library/Director/Web/Form/DirectorObjectForm.php
+++ b/library/Director/Web/Form/DirectorObjectForm.php
@@ -5,6 +5,7 @@ namespace Icinga\Module\Director\Web\Form;
use Exception;
use gipfl\IcingaWeb2\Url;
use Icinga\Authentication\Auth;
+use Icinga\Module\Director\Auth\Permission;
use Icinga\Module\Director\Data\Db\DbObjectStore;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Data\Db\DbObject;
@@ -443,7 +444,7 @@ abstract class DirectorObjectForm extends DirectorForm
$this->setInheritedValue(
$el,
$object->getRelatedObjectName($k, $v),
- $origins->{"${k}_id"}
+ $origins->{"{$k}_id"}
);
}
}
@@ -540,7 +541,9 @@ abstract class DirectorObjectForm extends DirectorForm
'inherited_groups',
'applied_groups',
'users',
+ 'users_var',
'user_groups',
+ 'user_groups_var',
'apply_to',
'command_id', // Notification
'notification_interval',
@@ -788,7 +791,9 @@ abstract class DirectorObjectForm extends DirectorForm
return;
}
- $post = $values = $this->getRequest()->getPost();
+ /** @var array $post */
+ $post = $this->getRequest()->getPost();
+ $values = $post;
foreach ($post as $key => $value) {
if (preg_match('/^(.+?)_(\d+)__(MOVE_DOWN|MOVE_UP|REMOVE)$/', $key, $m)) {
@@ -1239,7 +1244,7 @@ abstract class DirectorObjectForm extends DirectorForm
if ($this->hasBeenSent()) {
$this->addError($this->translate('No template has been chosen'));
} else {
- if ($this->hasPermission('director/admin')) {
+ if ($this->hasPermission(Permission::ADMIN)) {
$html = $this->translate('Please define a related template first');
} else {
$html = $this->translate('No related template has been provided yet');
@@ -1274,7 +1279,7 @@ abstract class DirectorObjectForm extends DirectorForm
'required' => $required,
'spellcheck' => 'false',
'hideOptions' => $choiceNames,
- 'suggest' => "${type}templates",
+ 'suggest' => "{$type}templates",
// 'multiOptions' => $this->optionallyAddFromEnum($enum),
'sorted' => true,
'value' => $this->presetImports,
@@ -1516,6 +1521,7 @@ abstract class DirectorObjectForm extends DirectorForm
return [];
}
+ /** @var int|string $id */
$id = $object->get('id');
if (array_key_exists($id, $tpl)) {
diff --git a/library/Director/Web/Form/Element/DataFilter.php b/library/Director/Web/Form/Element/DataFilter.php
index adae07d..7beb651 100644
--- a/library/Director/Web/Form/Element/DataFilter.php
+++ b/library/Director/Web/Form/Element/DataFilter.php
@@ -2,6 +2,7 @@
namespace Icinga\Module\Director\Web\Form\Element;
+use gipfl\Json\JsonString;
use Icinga\Data\Filter\Filter;
use Icinga\Data\Filter\FilterChain;
use Icinga\Data\Filter\FilterExpression;
@@ -268,13 +269,13 @@ class DataFilter extends FormElement
return Filter::expression(
$entry['column'],
'=',
- json_encode(true)
+ $this->jsonEncode(true)
);
} elseif ($entry['sign'] === 'false') {
return Filter::expression(
$entry['column'],
'=',
- json_encode(false)
+ $this->jsonEncode(false)
);
} elseif ($entry['sign'] === 'in') {
if (array_key_exists('value', $entry)) {
@@ -291,13 +292,13 @@ class DataFilter extends FormElement
return Filter::expression(
$entry['column'],
'=',
- json_encode($value)
+ $this->jsonEncode($value)
);
} elseif ($entry['sign'] === 'contains') {
$value = array_key_exists('value', $entry) ? $entry['value'] : null;
return Filter::expression(
- json_encode($value),
+ $this->jsonEncode($value),
'=',
$entry['column']
);
@@ -307,11 +308,20 @@ class DataFilter extends FormElement
return Filter::expression(
$entry['column'],
$entry['sign'],
- json_encode($value)
+ $this->jsonEncode($value)
);
}
}
+ protected function jsonEncode($string)
+ {
+ return preg_replace(
+ ['/&/u', '/\|/u', '/!/u', '/=/u', '/>/u', '/</u'],
+ ['\u0026', '\u007c', '\u0021', '\u003d', '\u003e', '\u003c'],
+ JsonString::encode($string)
+ );
+ }
+
protected function entryAction($entry)
{
if (array_key_exists('action', $entry)) {
diff --git a/library/Director/Web/Form/Element/ExtensibleSet.php b/library/Director/Web/Form/Element/ExtensibleSet.php
index f3c968f..e443b06 100644
--- a/library/Director/Web/Form/Element/ExtensibleSet.php
+++ b/library/Director/Web/Form/Element/ExtensibleSet.php
@@ -28,7 +28,7 @@ class ExtensibleSet extends FormElement
if (! is_array($value)) {
throw new InvalidArgumentException(sprintf(
'ExtensibleSet expects to work with Arrays, got %s',
- var_export($value, 1)
+ var_export($value, true)
));
}
$value = array_filter($value, 'strlen');
diff --git a/library/Director/Web/Form/IcingaObjectFieldLoader.php b/library/Director/Web/Form/IcingaObjectFieldLoader.php
index c900edf..ae00855 100644
--- a/library/Director/Web/Form/IcingaObjectFieldLoader.php
+++ b/library/Director/Web/Form/IcingaObjectFieldLoader.php
@@ -613,7 +613,7 @@ class IcingaObjectFieldLoader
$fields = [];
/** @var HostFieldHook|ServiceFieldHook $hook */
$type = ucfirst($object->getShortTableName());
- foreach (Hook::all("Director\\${type}Field") as $hook) {
+ foreach (Hook::all("Director\\{$type}Field") as $hook) {
if ($hook->wants($object)) {
$id = $object->get('id');
$spec = $hook->getFieldSpec($object);
diff --git a/library/Director/Web/Form/IplElement/ExtensibleSetElement.php b/library/Director/Web/Form/IplElement/ExtensibleSetElement.php
index a4dbb20..b723d47 100644
--- a/library/Director/Web/Form/IplElement/ExtensibleSetElement.php
+++ b/library/Director/Web/Form/IplElement/ExtensibleSetElement.php
@@ -26,6 +26,8 @@ class ExtensibleSetElement extends BaseHtmlElement
private $description;
+ private $descriptions;
+
private $multiOptions;
private $validOptions;
@@ -109,7 +111,7 @@ class ExtensibleSetElement extends BaseHtmlElement
if (null !== $value && ! is_array($value)) {
throw new ProgrammingError(
'Got unexpected value, no array: %s',
- var_export($value, 1)
+ var_export($value, true)
);
}
@@ -323,7 +325,7 @@ class ExtensibleSetElement extends BaseHtmlElement
} else {
return \sprintf(
$this->translate('%s (not an Array!)'),
- \var_export($this->inherited, 1)
+ \var_export($this->inherited, true)
);
}
}
diff --git a/library/Director/Web/Form/QuickForm.php b/library/Director/Web/Form/QuickForm.php
index 91c8f00..6100ec9 100644
--- a/library/Director/Web/Form/QuickForm.php
+++ b/library/Director/Web/Form/QuickForm.php
@@ -620,6 +620,10 @@ abstract class QuickForm extends QuickBaseForm
$this->hasBeenSent = true;
} elseif ($req->isPost()) {
$post = $req->getPost();
+ if (! CsrfToken::isValid($post[self::CSRF])) {
+ throw new Exception('Invalid CSRF token provided');
+ }
+
$this->hasBeenSent = array_key_exists(self::ID, $post) &&
$post[self::ID] === $this->getName();
} else {
diff --git a/library/Director/Web/SelfService.php b/library/Director/Web/SelfService.php
index 33756b7..723cbf6 100644
--- a/library/Director/Web/SelfService.php
+++ b/library/Director/Web/SelfService.php
@@ -155,19 +155,6 @@ class SelfService
['class' => 'logfile'],
$wizard->renderIcinga4WindowsWizardCommand($key)
),
- Html::tag('h3', $this->translate('Icinga 2 Powershell Module')),
- Html::tag('p', Html::sprintf(
- $this->translate('In case you\'re using the legacy %s, please run:'),
- Html::tag('a', [
- 'href' => 'https://github.com/Icinga/icinga2-powershell-module',
- 'target' => '_blank',
- ], $this->translate('Icinga 2 Powershell Module'))
- )),
- Html::tag(
- 'pre',
- ['class' => 'logfile'],
- $wizard->renderPowershellModuleInstaller($key)
- ),
];
}
@@ -264,6 +251,7 @@ class SelfService
null,
['class' => 'icon-download', 'target' => '_blank']
),
+
Html::tag('p', null, $this->translate('Just download and run this script on your Linux Client Machine:')),
Html::tag('pre', $class, $wizard->renderLinuxInstaller())
]);
diff --git a/library/Director/Web/Table/ActivityLogTable.php b/library/Director/Web/Table/ActivityLogTable.php
index 5460bc2..a57b86e 100644
--- a/library/Director/Web/Table/ActivityLogTable.php
+++ b/library/Director/Web/Table/ActivityLogTable.php
@@ -2,14 +2,15 @@
namespace Icinga\Module\Director\Web\Table;
-use gipfl\Format\LocalTimeFormat;
+use DateTime;
use gipfl\IcingaWeb2\Link;
-use gipfl\IcingaWeb2\Table\ZfQueryBasedTable;
+use Icinga\Module\Director\Auth\Permission;
use Icinga\Module\Director\Util;
+use IntlDateFormatter;
use ipl\Html\Html;
use ipl\Html\HtmlElement;
-class ActivityLogTable extends ZfQueryBasedTable
+class ActivityLogTable extends IntlZfQueryBasedTable
{
protected $filters = [];
@@ -27,9 +28,6 @@ class ActivityLogTable extends ZfQueryBasedTable
'object_type',
];
- /** @var LocalTimeFormat */
- protected $timeFormat;
-
protected $ranges = [];
/** @var ?object */
@@ -44,7 +42,6 @@ class ActivityLogTable extends ZfQueryBasedTable
public function __construct($db)
{
parent::__construct($db);
- $this->timeFormat = new LocalTimeFormat();
}
public function assemble()
@@ -96,7 +93,9 @@ class ActivityLogTable extends ZfQueryBasedTable
if (! $this->hasObjectFilter) {
$columns[] = $this->makeRangeInfo($row->id);
}
- $columns[] = $this::td($this->timeFormat->getTime($row->ts_change_time));
+
+
+ $columns[] = $this::td($this->getTime($row->ts_change_time));
return $this::tr($columns)->addAttributes(['class' => $action]);
}
@@ -107,7 +106,7 @@ class ActivityLogTable extends ZfQueryBasedTable
*/
protected function renderDayIfNew($timestamp)
{
- $day = $this->getDateFormatter()->getFullDay($timestamp);
+ $day = $this->getDateFormatter()->format((new DateTime())->setTimestamp($timestamp));
if ($this->lastDay !== $day) {
$this->nextHeader()->add(
@@ -206,7 +205,7 @@ class ActivityLogTable extends ZfQueryBasedTable
$type = substr($type, 7);
}
- if (Util::hasPermission('director/showconfig')) {
+ if (Util::hasPermission(Permission::SHOW_CONFIG)) {
// Later on replacing, service_set -> serviceset
// multi column key :(
diff --git a/library/Director/Web/Table/ApplyRulesTable.php b/library/Director/Web/Table/ApplyRulesTable.php
index a861bac..a5379b5 100644
--- a/library/Director/Web/Table/ApplyRulesTable.php
+++ b/library/Director/Web/Table/ApplyRulesTable.php
@@ -6,6 +6,7 @@ use Icinga\Authentication\Auth;
use Icinga\Data\Filter\Filter;
use Icinga\Exception\IcingaException;
use Icinga\Module\Director\Db;
+use Icinga\Module\Director\Db\DbSelectParenthesis;
use Icinga\Module\Director\Db\DbUtil;
use Icinga\Module\Director\Db\IcingaObjectFilterHelper;
use Icinga\Module\Director\IcingaConfig\AssignRenderer;
@@ -20,6 +21,8 @@ use Zend_Db_Select as ZfSelect;
class ApplyRulesTable extends ZfQueryBasedTable
{
+ use TableWithBranchSupport;
+
protected $searchColumns = [
'o.object_name',
'o.assign_filter',
@@ -94,10 +97,14 @@ class ApplyRulesTable extends ZfQueryBasedTable
// NOT (YET) static::td($this->createActionLinks($row))->setSeparator(' ')
]);
+ $classes = $this->getRowClasses($row);
+
if ($row->disabled === 'y') {
- $tr->getAttributes()->add('class', 'disabled');
+ $classes[] = 'disabled';
}
+ $tr->getAttributes()->add('class', $classes);
+
return $tr;
}
@@ -117,7 +124,8 @@ class ApplyRulesTable extends ZfQueryBasedTable
$this->getQuery(),
$template,
'o',
- $inheritance
+ $inheritance,
+ $this->branchUuid
);
return $this;
@@ -146,7 +154,7 @@ class ApplyRulesTable extends ZfQueryBasedTable
$links = [];
$links[] = Link::create(
Icon::create('sitemap'),
- "${baseUrl}template/applytargets",
+ "{$baseUrl}template/applytargets",
['id' => $row->id],
['title' => $this->translate('Show affected Objects')]
);
@@ -196,6 +204,15 @@ class ApplyRulesTable extends ZfQueryBasedTable
return FilterRenderer::applyToQuery($filter, $query);
}
+ protected function getRowClasses($row)
+ {
+ // TODO: remove isset, to figure out where it is missing
+ if (isset($row->branch_uuid) && $row->branch_uuid !== null) {
+ return ['branch_modified'];
+ }
+ return [];
+ }
+
/**
* @return IcingaObject
@@ -216,6 +233,7 @@ class ApplyRulesTable extends ZfQueryBasedTable
'id' => 'o.id',
'uuid' => 'o.uuid',
'object_name' => 'o.object_name',
+ 'object_type' => 'o.object_type',
'disabled' => 'o.disabled',
'assign_filter' => 'o.assign_filter',
'apply_for' => '(NULL)',
@@ -224,17 +242,92 @@ class ApplyRulesTable extends ZfQueryBasedTable
if ($table === 'icinga_service') {
$columns['apply_for'] = 'o.apply_for';
}
+
+ $conn = $this->connection();
$query = $this->db()->select()->from(
['o' => $table],
$columns
- )->where(
- "object_type = 'apply'"
)->order('o.object_name');
- if ($this->type === 'service') {
- $query->where('service_set_id IS NULL');
+ if ($this->branchUuid) {
+ $columns = $this->branchifyColumns($columns);
+ $columns['branch_uuid'] = 'bo.branch_uuid';
+ if ($conn->isPgsql()) {
+ $columns['imports'] = 'CONCAT(\'[\', ARRAY_TO_STRING(ARRAY_AGG'
+ . '(CONCAT(\'"\', sub_o.object_name, \'"\')), \',\'), \']\')';
+ } else {
+ $columns['imports'] = 'CONCAT(\'[\', '
+ . 'GROUP_CONCAT(CONCAT(\'"\', sub_o.object_name, \'"\')), \']\')';
+ }
+
+ $this->stripSearchColumnAliases();
+
+ $query->reset('columns');
+ $right = clone($query);
+
+ $query->columns($columns)
+ ->joinLeft(
+ ['oi' => $table . '_inheritance'],
+ 'o.id = oi.' . $this->getType() . '_id',
+ []
+ )->joinLeft(
+ ['sub_o' => $table],
+ 'sub_o.id = oi.parent_' . $this->getType() . '_id',
+ []
+ )->group(['o.id', 'bo.uuid', 'bo.branch_uuid']);
+
+ $query->joinLeft(
+ ['bo' => "branched_$table"],
+ // TODO: PgHexFunc
+ $this->db()->quoteInto(
+ 'bo.uuid = o.uuid AND bo.branch_uuid = ?',
+ DbUtil::quoteBinaryLegacy($this->branchUuid->getBytes(), $this->db())
+ ),
+ []
+ )->where("(bo.branch_deleted IS NULL OR bo.branch_deleted = 'n')");
+
+ if ($this->type === 'service') {
+ $query->where('o.service_set_id IS NULL AND bo.service_set IS NULL');
+ }
+
+ $columns['imports'] = 'bo.imports';
+
+ $right->columns($columns)
+ ->joinRight(
+ ['bo' => "branched_$table"],
+ 'bo.uuid = o.uuid',
+ []
+ )
+ ->where('o.uuid IS NULL')
+ ->where('bo.branch_uuid = ?', $conn->quoteBinary($this->branchUuid->getBytes()));
+
+ $query = $this->db()->select()->union([
+ 'l' => new DbSelectParenthesis($query),
+ 'r' => new DbSelectParenthesis($right),
+ ]);
+
+ $query = $this->db()->select()->from(['u' => $query]);
+ $query->order('object_name')->limit(100);
+ } else {
+ if ($this->type === 'service') {
+ $query->where('service_set_id IS NULL');
+ }
}
+ $query->where(
+ "object_type = 'apply'"
+ );
+
+ $this->applyRestrictions($query);
+
return $this->applyRestrictions($query);
}
+
+ /**
+ * @return Db
+ */
+ public function connection()
+ {
+ return parent::connection();
+ }
}
diff --git a/library/Director/Web/Table/BasketSnapshotTable.php b/library/Director/Web/Table/BasketSnapshotTable.php
index 08f808a..6fe0e16 100644
--- a/library/Director/Web/Table/BasketSnapshotTable.php
+++ b/library/Director/Web/Table/BasketSnapshotTable.php
@@ -4,13 +4,12 @@ namespace Icinga\Module\Director\Web\Table;
use ipl\Html\Html;
use gipfl\IcingaWeb2\Link;
-use gipfl\IcingaWeb2\Table\ZfQueryBasedTable;
use Icinga\Date\DateFormatter;
use Icinga\Module\Director\Core\Json;
use Icinga\Module\Director\DirectorObject\Automation\Basket;
use RuntimeException;
-class BasketSnapshotTable extends ZfQueryBasedTable
+class BasketSnapshotTable extends IntlZfQueryBasedTable
{
use DbHelper;
@@ -67,7 +66,7 @@ class BasketSnapshotTable extends ZfQueryBasedTable
if (! is_object($summary) && ! is_array($summary)) {
throw new RuntimeException(sprintf(
'Got invalid basket summary: %s ',
- var_export($summary, 1)
+ var_export($summary, true)
));
}
diff --git a/library/Director/Web/Table/BranchActivityTable.php b/library/Director/Web/Table/BranchActivityTable.php
index e7131ef..cbf940d 100644
--- a/library/Director/Web/Table/BranchActivityTable.php
+++ b/library/Director/Web/Table/BranchActivityTable.php
@@ -2,15 +2,14 @@
namespace Icinga\Module\Director\Web\Table;
-use gipfl\Format\LocalTimeFormat;
+use Icinga\Module\Director\Auth\Permission;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Db\Branch\BranchActivity;
use Icinga\Module\Director\Util;
use gipfl\IcingaWeb2\Link;
-use gipfl\IcingaWeb2\Table\ZfQueryBasedTable;
use Ramsey\Uuid\UuidInterface;
-class BranchActivityTable extends ZfQueryBasedTable
+class BranchActivityTable extends IntlZfQueryBasedTable
{
protected $extraParams = [];
@@ -20,16 +19,12 @@ class BranchActivityTable extends ZfQueryBasedTable
/** @var ?UuidInterface */
protected $objectUuid;
- /** @var LocalTimeFormat */
- protected $timeFormat;
-
protected $linkToObject = true;
public function __construct(UuidInterface $branchUuid, $db, UuidInterface $objectUuid = null)
{
$this->branchUuid = $branchUuid;
$this->objectUuid = $objectUuid;
- $this->timeFormat = new LocalTimeFormat();
parent::__construct($db);
}
@@ -45,7 +40,7 @@ class BranchActivityTable extends ZfQueryBasedTable
$activity = BranchActivity::fromDbRow($row);
return $this::tr([
$this::td($this->makeBranchLink($activity))->setSeparator(' '),
- $this::td($this->timeFormat->getTime($ts))
+ $this::td($this->getTime($ts))
])->addAttributes(['class' => ['action-' . $activity->getAction(), 'branched']]);
}
@@ -75,7 +70,7 @@ class BranchActivityTable extends ZfQueryBasedTable
{
$type = preg_replace('/^icinga_/', '', $activity->getObjectTable());
- if (Util::hasPermission('director/showconfig')) {
+ if (Util::hasPermission(Permission::SHOW_CONFIG)) {
// Later on replacing, service_set -> serviceset
return [
'[' . $activity->getAuthor() . ']',
diff --git a/library/Director/Web/Table/ChoicesTable.php b/library/Director/Web/Table/ChoicesTable.php
index 4ba2460..9574520 100644
--- a/library/Director/Web/Table/ChoicesTable.php
+++ b/library/Director/Web/Table/ChoicesTable.php
@@ -44,7 +44,7 @@ class ChoicesTable extends ZfQueryBasedTable
public function renderRow($row)
{
$type = $this->getType();
- $url = Url::fromPath("director/templatechoice/${type}", [
+ $url = Url::fromPath("director/templatechoice/{$type}", [
'name' => $row->object_name
]);
@@ -56,7 +56,7 @@ class ChoicesTable extends ZfQueryBasedTable
protected function prepareQuery()
{
$type = $this->getType();
- $table = "icinga_${type}_template_choice";
+ $table = "icinga_{$type}_template_choice";
return $this->db()
->select()
->from(['o' => $table], 'object_name')
diff --git a/library/Director/Web/Table/CustomvarTable.php b/library/Director/Web/Table/CustomvarTable.php
index f9a3844..1aead19 100644
--- a/library/Director/Web/Table/CustomvarTable.php
+++ b/library/Director/Web/Table/CustomvarTable.php
@@ -91,11 +91,11 @@ class CustomvarTable extends ZfQueryBasedTable
$columns["cnt_$type"] = 'COUNT(*)';
$columns["distinct_$type"] = 'COUNT(DISTINCT varvalue)';
return $db->select()->from(
- ['v' => "icinga_${type}_var"],
+ ['v' => "icinga_{$type}_var"],
$columns
)->join(
- ['o' => "icinga_${type}"],
- "o.id = v.${type}_id",
+ ['o' => "icinga_{$type}"],
+ "o.id = v.{$type}_id",
[]
)->where('o.object_type != ?', 'external_object')->group('varname');
}
diff --git a/library/Director/Web/Table/CustomvarVariantsTable.php b/library/Director/Web/Table/CustomvarVariantsTable.php
index 80fca70..8447e36 100644
--- a/library/Director/Web/Table/CustomvarVariantsTable.php
+++ b/library/Director/Web/Table/CustomvarVariantsTable.php
@@ -108,11 +108,11 @@ class CustomvarVariantsTable extends ZfQueryBasedTable
$columns["cnt_$type"] = 'COUNT(*)';
$columns['format'] = 'v.format';
return $db->select()->from(
- ['v' => "icinga_${type}_var"],
+ ['v' => "icinga_{$type}_var"],
$columns
)->join(
- ['o' => "icinga_${type}"],
- "o.id = v.${type}_id",
+ ['o' => "icinga_{$type}"],
+ "o.id = v.{$type}_id",
[]
)->where(
'v.varname = ?',
diff --git a/library/Director/Web/Table/DatafieldTable.php b/library/Director/Web/Table/DatafieldTable.php
index 4b321d7..0062626 100644
--- a/library/Director/Web/Table/DatafieldTable.php
+++ b/library/Director/Web/Table/DatafieldTable.php
@@ -5,12 +5,13 @@ namespace Icinga\Module\Director\Web\Table;
use gipfl\IcingaWeb2\Link;
use gipfl\IcingaWeb2\Table\ZfQueryBasedTable;
use Zend_Db_Adapter_Abstract as ZfDbAdapter;
+use Zend_Db_Expr as DbExpr;
use Zend_Db_Select as ZfDbSelect;
class DatafieldTable extends ZfQueryBasedTable
{
protected $searchColumns = [
- 'df.varname',
+ 'lc_varname',
'df.caption',
];
@@ -19,6 +20,7 @@ class DatafieldTable extends ZfQueryBasedTable
return [
'id' => 'df.id',
'varname' => 'df.varname',
+ 'lc_varname' => new DbExpr('LOWER(df.varname)'),
'caption' => 'df.caption',
'description' => 'df.description',
'datatype' => 'df.datatype',
@@ -88,6 +90,15 @@ class DatafieldTable extends ZfQueryBasedTable
)->group('df.id')->group('df.varname')->group('dfc.category_name')->order('caption ASC');
}
+ public function search($search)
+ {
+ if ($search !== null) {
+ $search = strtolower($search);
+ }
+
+ return parent::search($search);
+ }
+
/**
* @param $type
* @param ZfDbAdapter $db
@@ -96,7 +107,7 @@ class DatafieldTable extends ZfQueryBasedTable
*/
protected function makeDatafieldSub($type, ZfDbAdapter $db)
{
- return $db->select()->from("icinga_${type}_field", [
+ return $db->select()->from("icinga_{$type}_field", [
'cnt' => 'COUNT(*)',
'datafield_id'
])->group('datafield_id');
@@ -110,7 +121,7 @@ class DatafieldTable extends ZfQueryBasedTable
*/
protected function makeVarSub($type, ZfDbAdapter $db)
{
- return $db->select()->from("icinga_${type}_var", [
+ return $db->select()->from("icinga_{$type}_var", [
'cnt' => 'COUNT(*)',
'varname'
])->group('varname');
diff --git a/library/Director/Web/Table/DependencyTemplateUsageTable.php b/library/Director/Web/Table/DependencyTemplateUsageTable.php
index d7537c5..2c1de50 100644
--- a/library/Director/Web/Table/DependencyTemplateUsageTable.php
+++ b/library/Director/Web/Table/DependencyTemplateUsageTable.php
@@ -2,6 +2,8 @@
namespace Icinga\Module\Director\Web\Table;
+use Icinga\Module\Director\Db;
+
class DependencyTemplateUsageTable extends TemplateUsageTable
{
public function getTypes()
@@ -12,11 +14,15 @@ class DependencyTemplateUsageTable extends TemplateUsageTable
];
}
- protected function getTypeSummaryDefinitions()
+ protected function getSummaryTables(string $templateType, Db $connection)
{
return [
- 'templates' => $this->getSummaryLine('template'),
- 'applyrules' => $this->getSummaryLine('apply'),
+ 'templates' => TemplatesTable::create(
+ $templateType,
+ $connection
+ ),
+ 'applyrules' => ApplyRulesTable::create($templateType, $connection)
+ ->setBranchUuid($this->branchUuid)
];
}
}
diff --git a/library/Director/Web/Table/DeploymentLogTable.php b/library/Director/Web/Table/DeploymentLogTable.php
index 2d5cb94..4849218 100644
--- a/library/Director/Web/Table/DeploymentLogTable.php
+++ b/library/Director/Web/Table/DeploymentLogTable.php
@@ -3,10 +3,9 @@
namespace Icinga\Module\Director\Web\Table;
use gipfl\IcingaWeb2\Link;
-use gipfl\IcingaWeb2\Table\ZfQueryBasedTable;
use Icinga\Date\DateFormatter;
-class DeploymentLogTable extends ZfQueryBasedTable
+class DeploymentLogTable extends IntlZfQueryBasedTable
{
use DbHelper;
diff --git a/library/Director/Web/Table/GroupMemberTable.php b/library/Director/Web/Table/GroupMemberTable.php
index b0814ad..c24c6af 100644
--- a/library/Director/Web/Table/GroupMemberTable.php
+++ b/library/Director/Web/Table/GroupMemberTable.php
@@ -109,7 +109,7 @@ class GroupMemberTable extends ZfQueryBasedTable
];
}
- $url = Url::fromPath("director/${type}", $params);
+ $url = Url::fromPath("director/{$type}", $params);
$tr = $this::tr();
@@ -163,7 +163,7 @@ class GroupMemberTable extends ZfQueryBasedTable
'o.id',
'o.object_type',
'o.object_name',
- 'membership_type' => "CASE WHEN go.${type}_id IS NULL THEN 'apply' ELSE 'direct' END"
+ 'membership_type' => "CASE WHEN go.{$type}_id IS NULL THEN 'apply' ELSE 'direct' END"
];
if ($this->group === null) {
@@ -176,19 +176,19 @@ class GroupMemberTable extends ZfQueryBasedTable
}
$query = $this->db()->select()->from(
- ['gro' => "icinga_${type}group_${type}_resolved"],
+ ['gro' => "icinga_{$type}group_{$type}_resolved"],
$columns
)->join(
- ['o' => "icinga_${type}"],
- "o.id = gro.${type}_id",
+ ['o' => "icinga_{$type}"],
+ "o.id = gro.{$type}_id",
[]
)->join(
- ['g' => "icinga_${type}group"],
- "gro.${type}group_id = g.id",
+ ['g' => "icinga_{$type}group"],
+ "gro.{$type}group_id = g.id",
[]
)->joinLeft(
- ['go' => "icinga_${type}group_${type}"],
- "go.${type}_id = o.id AND go.${type}group_id = g.id",
+ ['go' => "icinga_{$type}group_{$type}"],
+ "go.{$type}_id = o.id AND go.{$type}group_id = g.id",
[]
)->order('o.object_name');
diff --git a/library/Director/Web/Table/HostTemplateUsageTable.php b/library/Director/Web/Table/HostTemplateUsageTable.php
index 2d1ee2f..672691f 100644
--- a/library/Director/Web/Table/HostTemplateUsageTable.php
+++ b/library/Director/Web/Table/HostTemplateUsageTable.php
@@ -11,12 +11,4 @@ class HostTemplateUsageTable extends TemplateUsageTable
'objects' => $this->translate('Objects'),
];
}
-
- protected function getTypeSummaryDefinitions()
- {
- return [
- 'templates' => $this->getSummaryLine('template'),
- 'objects' => $this->getSummaryLine('object'),
- ];
- }
}
diff --git a/library/Director/Web/Table/IcingaServiceSetServiceTable.php b/library/Director/Web/Table/IcingaServiceSetServiceTable.php
index c205e66..2c3dbc4 100644
--- a/library/Director/Web/Table/IcingaServiceSetServiceTable.php
+++ b/library/Director/Web/Table/IcingaServiceSetServiceTable.php
@@ -12,6 +12,7 @@ use Icinga\Module\Director\Objects\IcingaServiceSet;
use gipfl\IcingaWeb2\Link;
use gipfl\IcingaWeb2\Table\ZfQueryBasedTable;
use gipfl\IcingaWeb2\Url;
+use Ramsey\Uuid\Uuid;
class IcingaServiceSetServiceTable extends ZfQueryBasedTable
{
@@ -122,9 +123,12 @@ class IcingaServiceSetServiceTable extends ZfQueryBasedTable
];
$url = 'director/host/servicesetservice';
} else {
+ if (is_resource($row->uuid)) {
+ $row->uuid =stream_get_contents($row->uuid);
+ }
+
$params = [
- 'name' => $row->service,
- 'set' => $row->service_set
+ 'uuid' => Uuid::fromBytes($row->uuid)->toString(),
];
$url = 'director/service';
}
@@ -194,14 +198,28 @@ class IcingaServiceSetServiceTable extends ZfQueryBasedTable
$connection = $this->connection();
assert($connection instanceof Db);
$builder = new ServiceSetQueryBuilder($connection, $this->branchUuid);
- return $builder->selectServicesForSet($this->set)->limit(100);
+ $query = $builder->selectServicesForSet($this->set);
+ $alias = $this->branchUuid ? 'u' : 'o';
+
+ if ($this->affectedHost) {
+ if ($hostId = $this->affectedHost->get('id')) {
+ $query->joinLeft(
+ ['hsb' => 'icinga_host_service_blacklist'],
+ $this->db()->quoteInto("$alias.id = hsb.service_id AND hsb.host_id = ?", $hostId),
+ []
+ )->columns([
+ 'blacklisted' => "CASE WHEN hsb.service_id IS NULL THEN 'n' ELSE 'y' END"
+ ]);
+ }
+ }
+
+ return $query->limit(100);
}
protected function createFakeRemoveLinkForReadonlyView()
{
return Html::tag('span', [
- 'class' => 'icon-paste',
- 'style' => 'float: right; font-weight: normal',
+ 'class' => ['icon-paste', 'seviceset-obj-link'],
], $this->host->getObjectName());
}
@@ -209,8 +227,7 @@ class IcingaServiceSetServiceTable extends ZfQueryBasedTable
{
$hostname = $host->getObjectName();
return Link::create($hostname, 'director/host/services', ['name' => $hostname], [
- 'class' => 'icon-paste',
- 'style' => 'float: right; font-weight: normal',
+ 'class' => ['icon-paste', 'seviceset-obj-link'],
'data-base-target' => '_next',
'title' => sprintf(
$this->translate('This set has been inherited from %s'),
diff --git a/library/Director/Web/Table/IntlZfQueryBasedTable.php b/library/Director/Web/Table/IntlZfQueryBasedTable.php
new file mode 100644
index 0000000..81ef14c
--- /dev/null
+++ b/library/Director/Web/Table/IntlZfQueryBasedTable.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace Icinga\Module\Director\Web\Table;
+
+use DateTime;
+use gipfl\IcingaWeb2\Table\ZfQueryBasedTable;
+use IntlDateFormatter;
+use Locale;
+
+abstract class IntlZfQueryBasedTable extends ZfQueryBasedTable
+{
+ protected function getDateFormatter()
+ {
+ return (new IntlDateFormatter(
+ Locale::getDefault(),
+ IntlDateFormatter::FULL,
+ IntlDateFormatter::NONE
+ ));
+ }
+
+ /**
+ * @param int $timestamp
+ */
+ protected function renderDayIfNew($timestamp)
+ {
+ $day = $this->getDateFormatter()->format((new DateTime())->setTimestamp($timestamp));
+
+ if ($this->lastDay !== $day) {
+ $this->nextHeader()->add(
+ $this::th($day, [
+ 'colspan' => 2,
+ 'class' => 'table-header-day'
+ ])
+ );
+
+ $this->lastDay = $day;
+ $this->nextBody();
+ }
+ }
+
+ protected function getTime(int $timeStamp)
+ {
+ $timeFormatter = $this->getDateFormatter();
+
+ $timeFormatter->setPattern(
+ in_array(Locale::getDefault(), ['en_US', 'en_US.UTF-8']) ? 'h:mm:ss a': 'H:mm:ss'
+ );
+
+ return $timeFormatter->format((new DateTime())->setTimestamp($timeStamp));
+ }
+}
diff --git a/library/Director/Web/Table/NotificationTemplateUsageTable.php b/library/Director/Web/Table/NotificationTemplateUsageTable.php
index da411a3..d8cd3d8 100644
--- a/library/Director/Web/Table/NotificationTemplateUsageTable.php
+++ b/library/Director/Web/Table/NotificationTemplateUsageTable.php
@@ -2,6 +2,8 @@
namespace Icinga\Module\Director\Web\Table;
+use Icinga\Module\Director\Db;
+
class NotificationTemplateUsageTable extends TemplateUsageTable
{
public function getTypes()
@@ -12,11 +14,15 @@ class NotificationTemplateUsageTable extends TemplateUsageTable
];
}
- protected function getTypeSummaryDefinitions()
+ protected function getSummaryTables(string $templateType, Db $connection)
{
return [
- 'templates' => $this->getSummaryLine('template'),
- 'applyrules' => $this->getSummaryLine('apply', 'o.host_id IS NULL'),
+ 'templates' => TemplatesTable::create(
+ $templateType,
+ $connection
+ ),
+ 'applyrules' => ApplyRulesTable::create($templateType, $connection)
+ ->setBranchUuid($this->branchUuid)
];
}
}
diff --git a/library/Director/Web/Table/ObjectSetTable.php b/library/Director/Web/Table/ObjectSetTable.php
index 2773841..4df9bdd 100644
--- a/library/Director/Web/Table/ObjectSetTable.php
+++ b/library/Director/Web/Table/ObjectSetTable.php
@@ -2,7 +2,9 @@
namespace Icinga\Module\Director\Web\Table;
+use gipfl\IcingaWeb2\Zf1\Db\FilterRenderer;
use Icinga\Authentication\Auth;
+use Icinga\Data\Filter\Filter;
use Icinga\Module\Director\Db;
use gipfl\IcingaWeb2\Link;
use gipfl\IcingaWeb2\Table\ZfQueryBasedTable;
@@ -28,6 +30,8 @@ class ObjectSetTable extends ZfQueryBasedTable
/** @var Auth */
private $auth;
+ protected $queries = [];
+
public static function create($type, Db $db, Auth $auth)
{
$table = new static($db);
@@ -53,7 +57,7 @@ class ObjectSetTable extends ZfQueryBasedTable
'uuid' => Uuid::fromBytes(Db\DbUtil::binaryResult($row->uuid))->toString(),
];
- $url = Url::fromPath("director/${type}set", $params);
+ $url = Url::fromPath("director/{$type}set", $params);
$classes = $this->getRowClasses($row);
$tr = static::tr([
@@ -85,7 +89,7 @@ class ObjectSetTable extends ZfQueryBasedTable
{
$type = $this->getType();
- $table = "icinga_${type}_set";
+ $table = "icinga_{$type}_set";
$columns = [
'id' => 'os.id',
'uuid' => 'os.uuid',
@@ -106,15 +110,15 @@ class ObjectSetTable extends ZfQueryBasedTable
['os' => $table],
$columns
)->joinLeft(
- ['o' => "icinga_${type}"],
- "o.${type}_set_id = os.id",
+ ['o' => "icinga_{$type}"],
+ "o.{$type}_set_id = os.id",
[]
);
$nameFilter = new FilterByNameRestriction(
$this->connection(),
$this->auth,
- "${type}_set"
+ "{$type}_set"
);
$nameFilter->applyToQuery($query, 'os');
/** @var Db $conn */
@@ -145,7 +149,20 @@ class ObjectSetTable extends ZfQueryBasedTable
$query->group('bos.uuid')->group('os.uuid')->group('os.id')->group('bos.branch_uuid');
$right->group('bos.uuid')->group('os.uuid')->group('os.id')->group('bos.branch_uuid');
}
-
+ $right->joinLeft(
+ ['bo' => "branched_icinga_{$type}"],
+ "bo.{$type}_set = bos.object_name",
+ []
+ )->group(['bo.object_name', 'o.object_name']);
+ $query->joinLeft(
+ ['bo' => "branched_icinga_{$type}"],
+ "bo.{$type}_set = bos.object_name",
+ []
+ )->group(['bo.object_name', 'o.object_name']);
+ $this->queries = [
+ $query,
+ $right
+ ];
$query = $this->db()->select()->union([
'l' => new DbSelectParenthesis($query),
'r' => new DbSelectParenthesis($right),
@@ -168,16 +185,16 @@ class ObjectSetTable extends ZfQueryBasedTable
->group('assign_filter')
->group('description')
->group('count_services');
- };
+ }
} else {
// Disabled for now, check for correctness:
// $query->joinLeft(
- // ['osi' => "icinga_${type}_set_inheritance"],
- // "osi.parent_${type}_set_id = os.id",
+ // ['osi' => "icinga_{$type}_set_inheritance"],
+ // "osi.parent_{$type}_set_id = os.id",
// []
// )->joinLeft(
- // ['oso' => "icinga_${type}_set"],
- // "oso.id = oso.${type}_set_id",
+ // ['oso' => "icinga_{$type}_set"],
+ // "oso.id = oso.{$type}_set_id",
// []
// );
// 'count_hosts' => 'COUNT(DISTINCT oso.id)',
@@ -196,11 +213,40 @@ class ObjectSetTable extends ZfQueryBasedTable
->group('os.assign_filter')
->group('os.description');
};
+ $this->queries = [$query];
}
return $query;
}
+ public function search($search)
+ {
+ if (! empty($search)) {
+ $columns = $this->getSearchColumns();
+ if (strpos($search, ' ') === false) {
+ $filter = Filter::matchAny();
+ foreach ($columns as $column) {
+ $filter->addFilter(Filter::expression($column, '=', "*$search*"));
+ }
+ } else {
+ $filter = Filter::matchAll();
+ foreach (explode(' ', $search) as $s) {
+ $sub = Filter::matchAny();
+ foreach ($columns as $column) {
+ $sub->addFilter(Filter::expression($column, '=', "*$s*"));
+ }
+ $filter->addFilter($sub);
+ }
+ }
+
+ foreach ($this->queries as $query) {
+ FilterRenderer::applyToQuery($filter, $query);
+ }
+ }
+
+ return $this;
+ }
+
/**
* @return Db
*/
diff --git a/library/Director/Web/Table/ObjectsTable.php b/library/Director/Web/Table/ObjectsTable.php
index 792cb6d..4ad1166 100644
--- a/library/Director/Web/Table/ObjectsTable.php
+++ b/library/Director/Web/Table/ObjectsTable.php
@@ -14,6 +14,7 @@ use gipfl\IcingaWeb2\Link;
use gipfl\IcingaWeb2\Table\ZfQueryBasedTable;
use gipfl\IcingaWeb2\Url;
use Ramsey\Uuid\Uuid;
+use Zend_Db_Adapter_Pdo_Pgsql;
use Zend_Db_Select as ZfSelect;
class ObjectsTable extends ZfQueryBasedTable
@@ -50,12 +51,18 @@ class ObjectsTable extends ZfQueryBasedTable
/** @var Auth */
private $auth;
+ public function __construct($db, Auth $auth)
+ {
+ $this->auth = $auth;
+ parent::__construct($db);
+ }
+
/**
* @param $type
* @param Db $db
* @return static
*/
- public static function create($type, Db $db)
+ public static function create($type, Db $db, Auth $auth)
{
$class = __NAMESPACE__ . '\\ObjectsTable' . ucfirst($type);
if (! class_exists($class)) {
@@ -63,7 +70,7 @@ class ObjectsTable extends ZfQueryBasedTable
}
/** @var static $table */
- $table = new $class($db);
+ $table = new $class($db, $auth);
$table->type = $type;
return $table;
}
@@ -84,20 +91,6 @@ class ObjectsTable extends ZfQueryBasedTable
return $this;
}
- /**
- * @return Auth
- */
- public function getAuth()
- {
- return $this->auth;
- }
-
- public function setAuth(Auth $auth)
- {
- $this->auth = $auth;
- return $this;
- }
-
public function filterObjectType($type)
{
$this->filterObjectType = $type;
@@ -124,11 +117,17 @@ class ObjectsTable extends ZfQueryBasedTable
IcingaObject $template,
$inheritance = Db\IcingaObjectFilterHelper::INHERIT_DIRECT
) {
+ if ($this->branchUuid) {
+ $tableAlias = 'u';
+ } else {
+ $tableAlias = 'o';
+ }
IcingaObjectFilterHelper::filterByTemplate(
$this->getQuery(),
$template,
- 'o',
- $inheritance
+ $tableAlias,
+ $inheritance,
+ $this->branchUuid
);
return $this;
@@ -142,7 +141,7 @@ class ObjectsTable extends ZfQueryBasedTable
protected function renderObjectNameColumn($row)
{
$type = $this->baseObjectUrl;
- $url = Url::fromPath("director/${type}", [
+ $url = Url::fromPath("director/{$type}", [
'uuid' => Uuid::fromBytes($row->uuid)->toString()
]);
@@ -227,11 +226,10 @@ class ObjectsTable extends ZfQueryBasedTable
{
/** @var Db $db */
$db = $this->connection();
- $auth = $this->getAuth();
return [
- new HostgroupRestriction($db, $auth),
- new FilterByNameRestriction($db, $auth, $this->getDummyObject()->getShortTableName())
+ new HostgroupRestriction($db, $this->auth),
+ new FilterByNameRestriction($db, $this->auth, $this->getDummyObject()->getShortTableName())
];
}
@@ -279,7 +277,39 @@ class ObjectsTable extends ZfQueryBasedTable
$conn->quoteBinary($this->branchUuid->getBytes())
),
[]
- )->where("(bo.branch_deleted IS NULL OR bo.branch_deleted = 'n')");
+ );
+
+ // keep the imported templates as columns
+ $leftColumns = $columns;
+ $rightColumns = $columns;
+
+ if ($this->db() instanceof Zend_Db_Adapter_Pdo_Pgsql) {
+ $leftColumns['imports'] = 'CONCAT(\'[\', ARRAY_TO_STRING(ARRAY_AGG'
+ . '(CONCAT(\'"\', sub_o.object_name, \'"\')), \',\'), \']\')';
+ } else {
+ $leftColumns['imports'] = 'CONCAT(\'[\', '
+ . 'GROUP_CONCAT(CONCAT(\'"\', sub_o.object_name, \'"\')), \']\')';
+ }
+
+ $query->reset('columns');
+
+ $query->columns($leftColumns)
+ ->joinLeft(
+ ['oi' => $table . '_inheritance'],
+ 'o.id = oi.' . $this->getType() . '_id',
+ []
+ )->joinLeft(
+ ['sub_o' => $table],
+ 'sub_o.id = oi.parent_' . $this->getType() . '_id',
+ []
+ )->group(['o.id', 'bo.uuid', 'bo.branch_uuid']);
+
+ $rightColumns['imports'] = 'bo.imports';
+
+ $right->reset('columns');
+ $right->columns($rightColumns);
+
+ $query->where("(bo.branch_deleted IS NULL OR bo.branch_deleted = 'n')");
$this->applyObjectTypeFilter($query, $right);
$right->joinRight(
['bo' => "branched_$table"],
@@ -298,6 +328,7 @@ class ObjectsTable extends ZfQueryBasedTable
$query->order('object_name')->limit(100);
} else {
$this->applyObjectTypeFilter($query);
+ $query = $this->applyRestrictions($query);
$query->order('o.object_name')->limit(100);
}
diff --git a/library/Director/Web/Table/ObjectsTableService.php b/library/Director/Web/Table/ObjectsTableService.php
index 2d4ad41..c9bce72 100644
--- a/library/Director/Web/Table/ObjectsTableService.php
+++ b/library/Director/Web/Table/ObjectsTableService.php
@@ -203,8 +203,14 @@ class ObjectsTableService extends ObjectsTable
'hsb.service_id = o.id AND hsb.host_id = o.host_id',
[]
)->where('o.service_set_id IS NULL')
+ ->group(['o.id', 'h.id','hsb.service_id', 'hsb.host_id'])
->order('o.object_name')->order('h.object_name');
+ if ($this->branchUuid) {
+ $subQuery->where('bo.service_set IS NULL')
+ ->group(['bo.uuid', 'bo.branch_uuid']);
+ }
+
if ($this->host) {
if ($this->branchUuid) {
$subQuery->where('COALESCE(h.object_name, bo.host) = ?', $this->host->getObjectName());
diff --git a/library/Director/Web/Table/ObjectsTableSetMembers.php b/library/Director/Web/Table/ObjectsTableSetMembers.php
new file mode 100644
index 0000000..6b18ac9
--- /dev/null
+++ b/library/Director/Web/Table/ObjectsTableSetMembers.php
@@ -0,0 +1,255 @@
+<?php
+
+namespace Icinga\Module\Director\Web\Table;
+
+use Icinga\Authentication\Auth;
+use Icinga\Module\Director\Db;
+use gipfl\IcingaWeb2\Link;
+use gipfl\IcingaWeb2\Table\ZfQueryBasedTable;
+use gipfl\IcingaWeb2\Url;
+use Icinga\Module\Director\Db\DbSelectParenthesis;
+use Icinga\Module\Director\Db\IcingaObjectFilterHelper;
+use Icinga\Module\Director\Objects\IcingaObject;
+use Icinga\Module\Director\Restriction\FilterByNameRestriction;
+use Ramsey\Uuid\Uuid;
+
+class ObjectsTableSetMembers extends ZfQueryBasedTable
+{
+ use TableWithBranchSupport;
+
+ protected $searchColumns = [
+ 'os.object_name',
+ 'o.object_name',
+ ];
+
+ private $type;
+
+ /** @var IcingaObject */
+ protected $dummyObject;
+
+ protected $baseObjectUrl;
+
+ /** @var Auth */
+ private $auth;
+
+ public static function create($type, Db $db, Auth $auth)
+ {
+ $table = new static($db);
+ $table->type = $type;
+ $table->auth = $auth;
+ return $table;
+ }
+
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ public function getColumnsToBeRendered()
+ {
+ return [
+ 'os.object_name' => 'Service Set',
+ 'o.object_name' => 'Service Name'
+ ];
+ }
+
+ public function setBaseObjectUrl($url)
+ {
+ $this->baseObjectUrl = $url;
+
+ return $this;
+ }
+
+ protected function getRowClasses($row)
+ {
+ // TODO: remove isset, to figure out where it is missing
+ if (isset($row->branch_uuid) && $row->branch_uuid !== null) {
+ return ['branch_modified'];
+ }
+ return [];
+ }
+
+ /**
+ * Should be triggered from renderRow, still unused.
+ *
+ * @param IcingaObject $template
+ * @param string $inheritance
+ * @return $this
+ * @throws \Icinga\Exception\ProgrammingError
+ */
+ public function filterTemplate(
+ IcingaObject $template,
+ $inheritance = IcingaObjectFilterHelper::INHERIT_DIRECT
+ ) {
+ IcingaObjectFilterHelper::filterByTemplate(
+ $this->getQuery(),
+ $template,
+ 'o',
+ $inheritance,
+ $this->branchUuid
+ );
+
+ return $this;
+ }
+
+
+ public function renderRow($row)
+ {
+ $url = Url::fromPath('director/service/edit', [
+ 'name' => $row->object_name,
+ 'uuid' => Uuid::fromBytes($row->uuid)->toString(),
+ ]);
+
+ return static::tr([
+ static::td([
+ Link::create($row->service_set, $url),
+ ]),
+ static::td($row->object_name),
+ ])->addAttributes(['class' => $this->getRowClasses($row)]);
+ }
+
+ /**
+ * @return IcingaObject
+ */
+ protected function getDummyObject()
+ {
+ if ($this->dummyObject === null) {
+ $type = $this->type;
+ $this->dummyObject = IcingaObject::createByType($type);
+ }
+ return $this->dummyObject;
+ }
+
+ protected function prepareQuery()
+ {
+ $table = $this->getDummyObject()->getTableName();
+ $type = $this->getType();
+
+ $columns = [
+ 'id' => 'o.id',
+ 'uuid' => 'o.uuid',
+ 'service_set' => 'os.object_name',
+ 'object_name' => 'o.object_name',
+ 'object_type' => 'os.object_type',
+ 'assign_filter' => 'os.assign_filter',
+ 'description' => 'os.description',
+ ];
+
+ $query = $this->db()->select()->from(
+ ['o' => $table],
+ $columns
+ )->joinLeft(
+ ['os' => "icinga_{$type}_set"],
+ "o.{$type}_set_id = os.id",
+ []
+ )->where('o.host_id IS NULL');
+
+ $nameFilter = new FilterByNameRestriction(
+ $this->connection(),
+ $this->auth,
+ "{$type}_set"
+ );
+ $nameFilter->applyToQuery($query, 'os');
+
+ if ($this->branchUuid) {
+ $columns['branch_uuid'] = 'bos.branch_uuid';
+ $conn = $this->connection();
+ if ($conn->isPgsql()) {
+ $columns['imports'] = 'CONCAT(\'[\', ARRAY_TO_STRING(ARRAY_AGG'
+ . '(CONCAT(\'"\', sub_o.object_name, \'"\')), \',\'), \']\')';
+ } else {
+ $columns['imports'] = 'CONCAT(\'[\', '
+ . 'GROUP_CONCAT(CONCAT(\'"\', sub_o.object_name, \'"\')), \']\')';
+ }
+
+ $columns = $this->branchifyColumns($columns);
+ $this->stripSearchColumnAliases();
+
+ $query->reset('columns');
+ $right = clone($query);
+ $conn = $this->connection();
+
+ $query->columns($columns)->joinLeft(
+ ['bos' => "branched_icinga_{$type}_set"],
+ // TODO: PgHexFunc
+ $this->db()->quoteInto(
+ 'bos.uuid = os.uuid AND bos.branch_uuid = ?',
+ $conn->quoteBinary($this->branchUuid->getBytes())
+ ),
+ []
+ )->joinLeft(
+ ['oi' => $table . '_inheritance'],
+ 'o.id = oi.' . $this->getType() . '_id',
+ []
+ )->joinLeft(
+ ['sub_o' => $table],
+ 'sub_o.id = oi.parent_' . $this->getType() . '_id',
+ []
+ )->where("(bos.branch_deleted IS NULL OR bos.branch_deleted = 'n')");
+
+ $columns['imports'] = 'bo.imports';
+ $right->columns($columns)->joinRight(
+ ['bos' => "branched_icinga_{$type}_set"],
+ 'bos.uuid = os.uuid',
+ []
+ )
+ ->where('os.uuid IS NULL')
+ ->where('bos.branch_uuid = ?', $conn->quoteBinary($this->branchUuid->getBytes()));
+ $query->group('COALESCE(os.uuid, bos.uuid)');
+ $right->group('COALESCE(os.uuid, bos.uuid)');
+ if ($conn->isPgsql()) {
+ // This is ugly, might want to modify the query - even a subselect looks better
+ $query->group('bos.uuid')->group('os.uuid')->group('os.id')->group('bos.branch_uuid')->group('o.id');
+ $right->group('bos.uuid')->group('os.uuid')->group('os.id')->group('bos.branch_uuid')->group('o.id');
+ }
+ $right->joinLeft(
+ ['bo' => "branched_icinga_{$type}"],
+ "bo.{$type}_set = bos.object_name",
+ []
+ )->group(['bo.object_name', 'o.object_name', 'bo.uuid', 'bo.imports']);
+ $query->joinLeft(
+ ['bo' => "branched_icinga_{$type}"],
+ "bo.{$type}_set = bos.object_name",
+ []
+ )->group(['bo.object_name', 'o.object_name', 'bo.uuid']);
+
+ $query = $this->db()->select()->union([
+ 'l' => new DbSelectParenthesis($query),
+ 'r' => new DbSelectParenthesis($right),
+ ]);
+ $query = $this->db()->select()->from(['u' => $query]);
+ $query->order('object_name')->limit(100);
+
+ $query
+ ->group('uuid')
+ ->where('object_type = ?', 'template')
+ ->order('object_name');
+ if ($conn->isPgsql()) {
+ $query
+ ->group('uuid')
+ ->group('id')
+ ->group('imports')
+ ->group('branch_uuid')
+ ->group('object_name')
+ ->group('object_type')
+ ->group('assign_filter')
+ ->group('description')
+ ->group('service_set');
+ }
+ } else {
+ $query
+ ->where('o.object_type = ?', 'object')
+ ->order('os.object_name');
+ }
+
+ return $query;
+ }
+
+ /**
+ * @return Db
+ */
+ public function connection()
+ {
+ return parent::connection();
+ }
+}
diff --git a/library/Director/Web/Table/ReadOnlyFormAvpTable.php b/library/Director/Web/Table/ReadOnlyFormAvpTable.php
deleted file mode 100644
index c3b44f3..0000000
--- a/library/Director/Web/Table/ReadOnlyFormAvpTable.php
+++ /dev/null
@@ -1,113 +0,0 @@
-<?php
-
-namespace Icinga\Module\Director\Web\Table;
-
-use Icinga\Module\Director\PlainObjectRenderer;
-use Icinga\Module\Director\Web\Form\QuickForm;
-use Zend_Form_Element as ZfElement;
-use Zend_Form_DisplayGroup as ZfDisplayGroup;
-
-class ReadOnlyFormAvpTable
-{
- protected $form;
-
- public function __construct(QuickForm $form)
- {
- $this->form = $form;
- }
-
- protected function renderDisplayGroups(QuickForm $form)
- {
- $html = '';
-
- foreach ($form->getDisplayGroups() as $group) {
- $elements = $this->filterGroupElements($group);
-
- if (empty($elements)) {
- continue;
- }
-
- $html .= '<tr><th colspan="2" style="text-align: right">' . $group->getLegend() . '</th></tr>';
- $html .= $this->renderElements($elements);
- }
-
- return $html;
- }
-
- /**
- * @param ZfDisplayGroup $group
- * @return ZfElement[]
- */
- protected function filterGroupElements(ZfDisplayGroup $group)
- {
- $blacklist = array('disabled', 'assign_filter');
- $elements = array();
- /** @var ZfElement $element */
- foreach ($group->getElements() as $element) {
- if ($element->getValue() === null) {
- continue;
- }
-
- if ($element->getType() === 'Zend_Form_Element_Hidden') {
- continue;
- }
-
- if (in_array($element->getName(), $blacklist)) {
- continue;
- }
-
-
- $elements[] = $element;
- }
-
- return $elements;
- }
-
- protected function renderElements($elements)
- {
- $html = '';
- foreach ($elements as $element) {
- $html .= $this->renderElement($element);
- }
-
- return $html;
- }
-
- /**
- * @param ZfElement $element
- *
- * @return string
- */
- protected function renderElement(ZfElement $element)
- {
- $value = $element->getValue();
- return '<tr><th>'
- . $this->escape($element->getLabel())
- . '</th><td>'
- . $this->renderValue($value)
- . '</td></tr>';
- }
-
- protected function renderValue($value)
- {
- if (is_string($value)) {
- return $this->escape($value);
- } elseif (is_array($value)) {
- return $this->escape(implode(', ', $value));
- }
- return $this->escape(PlainObjectRenderer::render($value));
- }
-
- protected function escape($string)
- {
- return htmlspecialchars($string);
- }
-
- public function render()
- {
- $this->form->initializeForObject();
- return '<table class="name-value-table">' . "\n"
- . $this->renderDisplayGroups($this->form)
- . '</table>';
- }
-}
diff --git a/library/Director/Web/Table/ServiceTemplateUsageTable.php b/library/Director/Web/Table/ServiceTemplateUsageTable.php
index 82f9643..c2806f6 100644
--- a/library/Director/Web/Table/ServiceTemplateUsageTable.php
+++ b/library/Director/Web/Table/ServiceTemplateUsageTable.php
@@ -2,6 +2,9 @@
namespace Icinga\Module\Director\Web\Table;
+use Icinga\Authentication\Auth;
+use Icinga\Module\Director\Db;
+
class ServiceTemplateUsageTable extends TemplateUsageTable
{
public function getTypes()
@@ -10,18 +13,27 @@ class ServiceTemplateUsageTable extends TemplateUsageTable
'templates' => $this->translate('Templates'),
'objects' => $this->translate('Objects'),
'applyrules' => $this->translate('Apply Rules'),
- // 'setmembers' => $this->translate('Set Members'),
+ 'setmembers' => $this->translate('Set Members'),
];
}
- protected function getTypeSummaryDefinitions()
+ protected function getSummaryTables(string $templateType, Db $connection)
{
+ $auth = Auth::getInstance();
return [
- 'templates' => $this->getSummaryLine('template'),
- 'objects' => $this->getSummaryLine('object'),
- 'applyrules' => $this->getSummaryLine('apply', 'o.service_set_id IS NULL'),
- // TODO: re-enable
- // 'setmembers' => $this->getSummaryLine('apply', 'o.service_set_id IS NOT NULL'),
+ 'templates' => TemplatesTable::create(
+ $templateType,
+ $connection
+ ),
+ 'objects' => ObjectsTable::create($templateType, $connection, $this->auth)
+ ->setBranchUuid($this->branchUuid),
+ 'applyrules' => ApplyRulesTable::create($templateType, $connection)
+ ->setBranchUuid($this->branchUuid),
+ 'setmembers' => ObjectsTableSetMembers::create(
+ $templateType,
+ $connection,
+ $auth
+ )
];
}
}
diff --git a/library/Director/Web/Table/SyncRunTable.php b/library/Director/Web/Table/SyncRunTable.php
index e08aad7..19f2678 100644
--- a/library/Director/Web/Table/SyncRunTable.php
+++ b/library/Director/Web/Table/SyncRunTable.php
@@ -2,22 +2,17 @@
namespace Icinga\Module\Director\Web\Table;
-use gipfl\Format\LocalTimeFormat;
use Icinga\Module\Director\Objects\SyncRule;
use gipfl\IcingaWeb2\Link;
-use gipfl\IcingaWeb2\Table\ZfQueryBasedTable;
-class SyncRunTable extends ZfQueryBasedTable
+class SyncRunTable extends IntlZfQueryBasedTable
{
/** @var SyncRule */
protected $rule;
- protected $timeFormat;
-
public function __construct(SyncRule $rule)
{
parent::__construct($rule->getConnection());
- $this->timeFormat = new LocalTimeFormat();
$this->getAttributes()
->set('data-base-target', '_self')
->add('class', 'history');
@@ -31,7 +26,7 @@ class SyncRunTable extends ZfQueryBasedTable
return $this::tr([
$this::td($this->makeSummary($row)),
$this::td(new Link(
- $this->timeFormat->getTime($time),
+ $this->getTime($time),
'director/syncrule/history',
[
'id' => $row->rule_id,
diff --git a/library/Director/Web/Table/TableWithBranchSupport.php b/library/Director/Web/Table/TableWithBranchSupport.php
index 7c5b15c..9e412c3 100644
--- a/library/Director/Web/Table/TableWithBranchSupport.php
+++ b/library/Director/Web/Table/TableWithBranchSupport.php
@@ -56,6 +56,9 @@ trait TableWithBranchSupport
$result[$alias] = $column;
}
+ if (isset($result['count_services'])) {
+ $result['count_services'] = 'COUNT(DISTINCT COALESCE(o.uuid, bo.uuid))';
+ }
return $result;
}
diff --git a/library/Director/Web/Table/TemplateUsageTable.php b/library/Director/Web/Table/TemplateUsageTable.php
index 66e56ea..376a499 100644
--- a/library/Director/Web/Table/TemplateUsageTable.php
+++ b/library/Director/Web/Table/TemplateUsageTable.php
@@ -2,9 +2,12 @@
namespace Icinga\Module\Director\Web\Table;
+use Icinga\Authentication\Auth;
use Icinga\Exception\ProgrammingError;
+use Icinga\Module\Director\Db;
+use Icinga\Module\Director\Db\Branch\Branch;
+use Icinga\Module\Director\Db\IcingaObjectFilterHelper;
use Icinga\Module\Director\Objects\IcingaObject;
-use Icinga\Module\Director\Resolver\TemplateTree;
use gipfl\IcingaWeb2\Link;
use ipl\Html\Table;
use gipfl\Translation\TranslationHelper;
@@ -13,10 +16,17 @@ class TemplateUsageTable extends Table
{
use TranslationHelper;
+ use TableWithBranchSupport;
+
+ /** @var Auth */
+ protected $auth;
+
protected $defaultAttributes = ['class' => 'pivot'];
protected $objectType;
+ protected $searchColumns = [];
+
public function getTypes()
{
return [
@@ -25,26 +35,22 @@ class TemplateUsageTable extends Table
];
}
- protected function getTypeSummaryDefinitions()
- {
- return [
- 'templates' => $this->getSummaryLine('template'),
- 'objects' => $this->getSummaryLine('object'),
- ];
- }
-
/**
* @param IcingaObject $template
+ * @param Branch|null $branch
+ *
* @return TemplateUsageTable
+ *
+ * @throws ProgrammingError
*/
- public static function forTemplate(IcingaObject $template)
+ public static function forTemplate(IcingaObject $template, Auth $auth, Branch $branch = null)
{
$type = ucfirst($template->getShortTableName());
- $class = __NAMESPACE__ . "\\${type}TemplateUsageTable";
+ $class = __NAMESPACE__ . "\\{$type}TemplateUsageTable";
if (class_exists($class)) {
- return new $class($template);
+ return new $class($template, $auth, $branch);
} else {
- return new static($template);
+ return new static($template, $auth, $branch);
}
}
@@ -58,8 +64,9 @@ class TemplateUsageTable extends Table
];
}
- protected function __construct(IcingaObject $template)
+ protected function __construct(IcingaObject $template, Auth $auth, Branch $branch = null)
{
+ $this->auth = $auth;
if ($template->get('object_type') !== 'template') {
throw new ProgrammingError(
@@ -68,6 +75,7 @@ class TemplateUsageTable extends Table
);
}
+ $this->setBranch($branch);
$this->objectType = $objectType = $template->getShortTableName();
$types = $this->getTypes();
$usage = $this->getUsageSummary($template);
@@ -85,7 +93,7 @@ class TemplateUsageTable extends Table
Table::td(
Link::create(
$count,
- "director/${objectType}template/$type",
+ "director/{$objectType}template/$type",
[
'name' => $template->getObjectName(),
'inheritance' => $inheritance
@@ -98,6 +106,7 @@ class TemplateUsageTable extends Table
}
if ($used) {
+ $this->getHeader()->add(Table::row($this->getColumnsToBeRendered(), null, 'th'));
$this->add($rows);
} else {
$this->add($this->translate('This template is not in use'));
@@ -106,52 +115,51 @@ class TemplateUsageTable extends Table
protected function getUsageSummary(IcingaObject $template)
{
- $id = $template->getAutoincId();
$connection = $template->getConnection();
$db = $connection->getDbAdapter();
- $oType = $this->objectType;
- $tree = new TemplateTree($oType, $connection);
- $ids = $tree->listDescendantIdsFor($template);
- if (empty($ids)) {
- $ids = [0];
+
+ $types = array_keys($this->getTypes());
+ $direct = [];
+ $indirect = [];
+ $templateType = $template->getShortTableName();
+
+ foreach ($this->getSummaryTables($templateType, $connection) as $type => $summaryTable) {
+ $directTable = clone $summaryTable;
+ $inDirectTable = clone $summaryTable;
+
+ $direct[$type] = $db->query(
+ $directTable
+ ->filterTemplate($template, IcingaObjectFilterHelper::INHERIT_DIRECT)
+ ->getQuery()
+ )->rowCount();
+ $indirect[$type] = $db->query(
+ $inDirectTable
+ ->filterTemplate($template, IcingaObjectFilterHelper::INHERIT_INDIRECT)
+ ->getQuery()
+ )->rowCount();
}
- $baseQuery = $db->select()->from(
- ['o' => 'icinga_' . $oType],
- $this->getTypeSummaryDefinitions()
- )->joinLeft(
- ['oi' => "icinga_${oType}_inheritance"],
- "oi.${oType}_id = o.id",
- []
- );
-
- $query = clone($baseQuery);
- $direct = $db->fetchRow(
- $query->where("oi.parent_${oType}_id = ?", $id)
- );
- $query = clone($baseQuery);
- $indirect = $db->fetchRow(
- $query->where("oi.parent_${oType}_id IN (?)", $ids)
- );
- //$indirect->templates = count($ids) - 1;
$total = [];
- $types = array_keys($this->getTypes());
foreach ($types as $type) {
- $total[$type] = $direct->$type + $indirect->$type;
+ $total[$type] = $direct[$type] + $indirect[$type];
}
return (object) [
- 'direct' => $direct,
- 'indirect' => $indirect,
+ 'direct' => (object) $direct,
+ 'indirect' => (object) $indirect,
'total' => (object) $total
];
}
- protected function getSummaryLine($type, $extra = null)
+ protected function getSummaryTables(string $templateType, Db $connection)
{
- if ($extra !== null) {
- $extra = " AND $extra";
- }
- return "COALESCE(SUM(CASE WHEN o.object_type = '${type}'${extra} THEN 1 ELSE 0 END), 0)";
+ return [
+ 'templates' => TemplatesTable::create(
+ $templateType,
+ $connection
+ ),
+ 'objects' => ObjectsTable::create($templateType, $connection, $this->auth)
+ ->setBranchUuid($this->branchUuid)
+ ];
}
}
diff --git a/library/Director/Web/Table/TemplatesTable.php b/library/Director/Web/Table/TemplatesTable.php
index be195b2..d6582fd 100644
--- a/library/Director/Web/Table/TemplatesTable.php
+++ b/library/Director/Web/Table/TemplatesTable.php
@@ -36,8 +36,8 @@ class TemplatesTable extends ZfQueryBasedTable implements FilterableByUsage
{
$type = $this->type;
$this->enableMultiSelect(
- "director/${type}s/edittemplates",
- "director/${type}template",
+ "director/{$type}s/edittemplates",
+ "director/{$type}template",
['name']
);
}
@@ -60,12 +60,12 @@ class TemplatesTable extends ZfQueryBasedTable implements FilterableByUsage
$name,
Html::tag(
'span',
- ['style' => 'font-style: italic'],
+ ['class' => 'font-italic'],
$this->translate(' - not in use -')
)
];
- $url = Url::fromPath("director/${type}template/usage", [
+ $url = Url::fromPath("director/{$type}template/usage", [
'name' => $name
]);
@@ -101,8 +101,8 @@ class TemplatesTable extends ZfQueryBasedTable implements FilterableByUsage
{
$type = $this->getType();
$this->getQuery()->where(
- "(EXISTS (SELECT ${type}_id FROM icinga_${type}_inheritance"
- . " WHERE parent_${type}_id = o.id))"
+ "(EXISTS (SELECT {$type}_id FROM icinga_{$type}_inheritance"
+ . " WHERE parent_{$type}_id = o.id))"
);
}
@@ -110,8 +110,8 @@ class TemplatesTable extends ZfQueryBasedTable implements FilterableByUsage
{
$type = $this->getType();
$this->getQuery()->where(
- "(NOT EXISTS (SELECT ${type}_id FROM icinga_${type}_inheritance"
- . " WHERE parent_${type}_id = o.id))"
+ "(NOT EXISTS (SELECT {$type}_id FROM icinga_{$type}_inheritance"
+ . " WHERE parent_{$type}_id = o.id))"
);
}
@@ -135,8 +135,8 @@ class TemplatesTable extends ZfQueryBasedTable implements FilterableByUsage
protected function prepareQuery()
{
$type = $this->getType();
- $used = "CASE WHEN EXISTS(SELECT 1 FROM icinga_${type}_inheritance oi"
- . " WHERE oi.parent_${type}_id = o.id) THEN 'y' ELSE 'n' END";
+ $used = "CASE WHEN EXISTS(SELECT 1 FROM icinga_{$type}_inheritance oi"
+ . " WHERE oi.parent_{$type}_id = o.id) THEN 'y' ELSE 'n' END";
$columns = [
'object_name' => 'o.object_name',
@@ -145,7 +145,7 @@ class TemplatesTable extends ZfQueryBasedTable implements FilterableByUsage
'is_used' => $used,
];
$query = $this->db()->select()->from(
- ['o' => "icinga_${type}"],
+ ['o' => "icinga_{$type}"],
$columns
)->where(
"o.object_type = 'template'"
diff --git a/library/Director/Web/Tabs/InfraTabs.php b/library/Director/Web/Tabs/InfraTabs.php
index 8a65c4e..ea7a0cc 100644
--- a/library/Director/Web/Tabs/InfraTabs.php
+++ b/library/Director/Web/Tabs/InfraTabs.php
@@ -5,6 +5,7 @@ namespace Icinga\Module\Director\Web\Tabs;
use Icinga\Authentication\Auth;
use gipfl\Translation\TranslationHelper;
use gipfl\IcingaWeb2\Widget\Tabs;
+use Icinga\Module\Director\Auth\Permission;
class InfraTabs extends Tabs
{
@@ -24,21 +25,21 @@ class InfraTabs extends Tabs
{
$auth = $this->auth;
- if ($auth->hasPermission('director/audit')) {
+ if ($auth->hasPermission(Permission::AUDIT)) {
$this->add('activitylog', [
'label' => $this->translate('Activity Log'),
'url' => 'director/config/activities'
]);
}
- if ($auth->hasPermission('director/deploy')) {
+ if ($auth->hasPermission(Permission::DEPLOY)) {
$this->add('deploymentlog', [
'label' => $this->translate('Deployments'),
'url' => 'director/config/deployments'
]);
}
- if ($auth->hasPermission('director/admin')) {
+ if ($auth->hasPermission(Permission::ADMIN)) {
$this->add('infrastructure', [
'label' => $this->translate('Infrastructure'),
'url' => 'director/dashboard',
diff --git a/library/Director/Web/Tabs/MainTabs.php b/library/Director/Web/Tabs/MainTabs.php
index 5ea2e9b..48ffa7c 100644
--- a/library/Director/Web/Tabs/MainTabs.php
+++ b/library/Director/Web/Tabs/MainTabs.php
@@ -5,6 +5,7 @@ namespace Icinga\Module\Director\Web\Tabs;
use gipfl\Translation\TranslationHelper;
use gipfl\IcingaWeb2\Widget\Tabs;
use Icinga\Authentication\Auth;
+use Icinga\Module\Director\Auth\Permission;
use Icinga\Module\Director\Web\Widget\Daemon\BackgroundDaemonState;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Health;
@@ -26,7 +27,7 @@ class MainTabs extends Tabs
'label' => $this->translate('Overview'),
'url' => 'director'
]);
- if ($this->auth->hasPermission('director/admin')) {
+ if ($this->auth->hasPermission(Permission::ADMIN)) {
$this->add('health', [
'label' => $this->translate('Health'),
'url' => 'director/health'
@@ -39,7 +40,7 @@ class MainTabs extends Tabs
public function render()
{
- if ($this->auth->hasPermission('director/admin')) {
+ if ($this->auth->hasPermission(Permission::ADMIN)) {
if ($this->getActiveName() !== 'health') {
$state = $this->getHealthState();
if ($state->isProblem()) {
diff --git a/library/Director/Web/Tabs/ObjectTabs.php b/library/Director/Web/Tabs/ObjectTabs.php
index cbd3f15..c355304 100644
--- a/library/Director/Web/Tabs/ObjectTabs.php
+++ b/library/Director/Web/Tabs/ObjectTabs.php
@@ -3,6 +3,7 @@
namespace Icinga\Module\Director\Web\Tabs;
use Icinga\Authentication\Auth;
+use Icinga\Module\Director\Auth\Permission;
use Icinga\Module\Director\Objects\IcingaObject;
use gipfl\Translation\TranslationHelper;
use gipfl\IcingaWeb2\Widget\Tabs;
@@ -46,10 +47,10 @@ class ObjectTabs extends Tabs
protected function addTabsForNewObject()
{
$type = $this->type;
- $this->add('add', array(
+ $this->add('add', [
'url' => sprintf('director/%s/add', $type),
'label' => sprintf($this->translate('Add %s'), ucfirst($type)),
- ));
+ ]);
}
protected function addTabsForExistingObject()
@@ -59,14 +60,12 @@ class ObjectTabs extends Tabs
$object = $this->object;
$params = $object->getUrlParams();
- if (! $object->isExternal()
- || in_array($object->getShortTableName(), $this->allowedExternals)
- ) {
- $this->add('modify', array(
+ if (! $object->isExternal() || in_array($object->getShortTableName(), $this->allowedExternals)) {
+ $this->add('modify', [
'url' => sprintf('director/%s', $type),
'urlParams' => $params,
'label' => $this->translate(ucfirst($type))
- ));
+ ]);
}
if ($object->getShortTableName() === 'host') {
$this->add('services', [
@@ -76,19 +75,17 @@ class ObjectTabs extends Tabs
]);
}
- if ($auth->hasPermission('director/showconfig')) {
- if ($object->getShortTableName() !== 'service'
- || $object->get('service_set_id') === null
- ) {
- $this->add('render', array(
+ if ($auth->hasPermission(Permission::SHOW_CONFIG)) {
+ if ($object->getShortTableName() !== 'service' || $object->get('service_set_id') === null) {
+ $this->add('render', [
'url' => sprintf('director/%s/render', $type),
'urlParams' => $params,
'label' => $this->translate('Preview'),
- ));
+ ]);
}
}
- if ($auth->hasPermission('director/audit')) {
+ if ($auth->hasPermission(Permission::AUDIT)) {
$this->add('history', array(
'url' => sprintf('director/%s/history', $type),
'urlParams' => $params,
@@ -96,7 +93,7 @@ class ObjectTabs extends Tabs
));
}
- if ($auth->hasPermission('director/admin') && $this->hasFields()) {
+ if ($auth->hasPermission(Permission::ADMIN) && $this->hasFields()) {
$this->add('fields', array(
'url' => sprintf('director/%s/fields', $type),
'urlParams' => $params,
@@ -117,7 +114,7 @@ class ObjectTabs extends Tabs
if ($object->supportsRanges()) {
$this->add('ranges', [
- 'url' => "director/${type}/ranges",
+ 'url' => "director/{$type}/ranges",
'urlParams' => $params,
'label' => $this->translate('Ranges')
]);
@@ -138,11 +135,11 @@ class ObjectTabs extends Tabs
]);
}
- if ($object->getShortTableName() === 'host' && $auth->hasPermission('director/hosts')) {
+ if ($object->getShortTableName() === 'host' && $auth->hasPermission(Permission::HOSTS)) {
$this->add('agent', [
- 'url' => 'director/host/agent',
+ 'url' => 'director/host/agent',
'urlParams' => $params,
- 'label' => $this->translate('Agent')
+ 'label' => $this->translate('Agent')
]);
}
}
diff --git a/library/Director/Web/Tabs/ObjectsTabs.php b/library/Director/Web/Tabs/ObjectsTabs.php
index 4f9e5a8..9d2a737 100644
--- a/library/Director/Web/Tabs/ObjectsTabs.php
+++ b/library/Director/Web/Tabs/ObjectsTabs.php
@@ -3,6 +3,7 @@
namespace Icinga\Module\Director\Web\Tabs;
use Icinga\Authentication\Auth;
+use Icinga\Module\Director\Auth\Permission;
use Icinga\Module\Director\Objects\IcingaObject;
use gipfl\Translation\TranslationHelper;
use gipfl\IcingaWeb2\Widget\Tabs;
@@ -21,65 +22,66 @@ class ObjectsTabs extends Tabs
$plType = strtolower(preg_replace('/cys$/', 'cies', $shortName . 's'));
$plType = str_replace('_', '-', $plType);
- if ($auth->hasPermission("director/${plType}")) {
- $this->add('index', array(
+ if ($auth->hasPermission("director/{$plType}")) {
+ $this->add('index', [
'url' => sprintf('director/%s', $plType),
'label' => $this->translate(ucfirst($plType)),
- ));
+ ]);
}
if ($object->getShortTableName() === 'command') {
- $this->add('external', array(
- 'url' => sprintf('director/%s', strtolower($plType)),
+ $this->add('external', [
+ 'url' => sprintf('director/%s', strtolower($plType)),
'urlParams' => ['type' => 'external_object'],
- 'label' => $this->translate('External'),
- ));
+ 'label' => $this->translate('External'),
+ ]);
}
- if ($auth->hasPermission('director/admin') || (
+ if ($auth->hasPermission(Permission::ADMIN)
+ || (
$object->getShortTableName() === 'notification'
- && $auth->hasPermission('director/notifications')
+ && $auth->hasPermission(Permission::NOTIFICATIONS)
) || (
$object->getShortTableName() === 'scheduled_downtime'
- && $auth->hasPermission('director/scheduled-downtimes')
+ && $auth->hasPermission(Permission::SCHEDULED_DOWNTIMES)
)) {
if ($object->supportsApplyRules()) {
- $this->add('applyrules', array(
- 'url' => sprintf('director/%s/applyrules', $plType),
+ $this->add('applyrules', [
+ 'url' => sprintf('director/%s/applyrules', $plType),
'label' => $this->translate('Apply')
- ));
+ ]);
}
}
- if ($auth->hasPermission('director/admin') && $type !== 'zone') {
+ if ($auth->hasPermission(Permission::ADMIN) && $type !== 'zone') {
if ($object->supportsImports()) {
- $this->add('templates', array(
- 'url' => sprintf('director/%s/templates', $plType),
+ $this->add('templates', [
+ 'url' => sprintf('director/%s/templates', $plType),
'label' => $this->translate('Templates'),
- ));
+ ]);
}
if ($object->supportsGroups()) {
- $this->add('groups', array(
- 'url' => sprintf('director/%sgroups', $typeUrl),
+ $this->add('groups', [
+ 'url' => sprintf('director/%sgroups', $typeUrl),
'label' => $this->translate('Groups')
- ));
+ ]);
}
}
- if ($auth->hasPermission('director/admin')) {
+ if ($auth->hasPermission(Permission::ADMIN)) {
if ($object->supportsChoices()) {
- $this->add('choices', array(
- 'url' => sprintf('director/templatechoices/%s', $shortName),
+ $this->add('choices', [
+ 'url' => sprintf('director/templatechoices/%s', $shortName),
'label' => $this->translate('Choices')
- ));
+ ]);
}
}
- if ($object->supportsSets() && $auth->hasPermission("director/${typeUrl}sets")) {
- $this->add('sets', array(
- 'url' => sprintf('director/%s/sets', $plType),
+ if ($object->supportsSets() && $auth->hasPermission("director/{$typeUrl}sets")) {
+ $this->add('sets', [
+ 'url' => sprintf('director/%s/sets', $plType),
'label' => $this->translate('Sets')
- ));
+ ]);
}
}
}
diff --git a/library/Director/Web/Tree/TemplateTreeRenderer.php b/library/Director/Web/Tree/TemplateTreeRenderer.php
index e238ded..8b23518 100644
--- a/library/Director/Web/Tree/TemplateTreeRenderer.php
+++ b/library/Director/Web/Tree/TemplateTreeRenderer.php
@@ -71,7 +71,7 @@ class TemplateTreeRenderer extends BaseHtmlElement
} else {
$li->add(Link::create(
$tree['name'],
- "director/${type}template/usage",
+ "director/{$type}template/usage",
array('name' => $tree['name']),
array('class' => 'icon-' .$type)
));
diff --git a/library/Director/Web/Widget/ActivityLogInfo.php b/library/Director/Web/Widget/ActivityLogInfo.php
index 8454b26..2b64fd4 100644
--- a/library/Director/Web/Widget/ActivityLogInfo.php
+++ b/library/Director/Web/Widget/ActivityLogInfo.php
@@ -3,7 +3,10 @@
namespace Icinga\Module\Director\Web\Widget;
use gipfl\Json\JsonString;
+use Icinga\Module\Director\Data\FieldReferenceLoader;
+use Icinga\Module\Director\DirectorObject\Automation\BasketSnapshotFieldResolver;
use Icinga\Module\Director\Objects\DirectorActivityLog;
+use Icinga\Module\Director\Web\Form\IcingaObjectFieldLoader;
use ipl\Html\HtmlDocument;
use ipl\Html\HtmlElement;
use Icinga\Date\DateFormatter;
@@ -83,8 +86,7 @@ class ActivityLogInfo extends HtmlDocument
/** @var Url $url */
$url = $url->without('checksum')->without('show');
$div = Html::tag('div', [
- 'class' => 'pagination-control',
- 'style' => 'float: right; width: 5em'
+ 'class' => ['pagination-control', 'activity-log-control'],
]);
$ul = Html::tag('ul', ['class' => 'nav tab-nav']);
@@ -434,11 +436,30 @@ class ActivityLogInfo extends HtmlDocument
{
if ($object instanceof IcingaService) {
return $this->previewService($object);
+ } elseif ($object instanceof IcingaServiceSet) {
+ return $this->previewServiceSet($object);
} else {
return $object->toSingleIcingaConfig();
}
}
+ /**
+ * Render service set to be previewed
+ *
+ * @param IcingaServiceSet $object
+ *
+ * @return IcingaConfig
+ */
+ protected function previewServiceSet(IcingaServiceSet $object)
+ {
+ $config = $object->toSingleIcingaConfig();
+ foreach ($object->getCachedServices() as $service) {
+ $service->renderToConfig($config);
+ }
+
+ return $config;
+ }
+
protected function previewService(IcingaService $service)
{
if (($set = $service->get('service_set')) !== null) {
@@ -625,10 +646,27 @@ class ActivityLogInfo extends HtmlDocument
$newProps['object_type'] = $props->object_type;
}
- return IcingaObject::createByType(
+ $object = IcingaObject::createByType(
$type,
$newProps,
$this->db
- )->setProperties((array) $props);
+ );
+
+ if ($type === 'icinga_service_set' && isset($props->services)) {
+ $services = [];
+ foreach ($props->services as $service) {
+ $services[$service->object_name] = IcingaObject::createByType(
+ 'icinga_service',
+ (array) $service,
+ $this->db
+ );
+ }
+
+ /** @var IcingaServiceSet $object */
+ $object->setCachedServices($services);
+ unset($props->services);
+ }
+
+ return $object->setProperties((array) $props);
}
}
diff --git a/library/Director/Web/Widget/AdditionalTableActions.php b/library/Director/Web/Widget/AdditionalTableActions.php
index 978f399..7495189 100644
--- a/library/Director/Web/Widget/AdditionalTableActions.php
+++ b/library/Director/Web/Widget/AdditionalTableActions.php
@@ -2,6 +2,7 @@
namespace Icinga\Module\Director\Web\Widget;
+use Icinga\Module\Director\Auth\Permission;
use ipl\Html\Html;
use ipl\Html\HtmlDocument;
use gipfl\IcingaWeb2\Icon;
@@ -35,10 +36,10 @@ class AdditionalTableActions
public function appendTo(HtmlDocument $parent)
{
$links = [];
- if ($this->hasPermission('director/admin')) {
+ if ($this->hasPermission(Permission::ADMIN)) {
$links[] = $this->createDownloadJsonLink();
}
- if ($this->hasPermission('director/showsql')) {
+ if ($this->hasPermission(Permission::SHOW_SQL)) {
$links[] = $this->createShowSqlToggle();
}
diff --git a/library/Director/Web/Widget/BranchedObjectHint.php b/library/Director/Web/Widget/BranchedObjectHint.php
index ec16094..c50f923 100644
--- a/library/Director/Web/Widget/BranchedObjectHint.php
+++ b/library/Director/Web/Widget/BranchedObjectHint.php
@@ -15,33 +15,45 @@ class BranchedObjectHint extends HtmlDocument
{
use TranslationHelper;
- public function __construct(Branch $branch, Auth $auth, BranchedObject $object = null)
+ public function __construct(Branch $branch, Auth $auth, BranchedObject $object = null, $hasPreferredBranch = false)
{
if (! $branch->isBranch()) {
- return;
- }
- $hook = Branch::requireHook();
-
- $name = $branch->getName();
- if (substr($name, 0, 1) === '/') {
- $label = $this->translate('this configuration branch');
+ if ($hasPreferredBranch) {
+ $main = true;
+ $hintMethod = 'warning';
+ $link = $this->translate('the main configuration branch');
+ $deployHint = ' ' . $this->translate('This will be part of the next deployment');
+ } else {
+ return;
+ }
} else {
- $label = $name;
+ $main = false;
+ $hintMethod = 'info';
+ $deployHint = ' ' . $this->translate('This will not be part of any deployment, unless being merged');
+ $hook = Branch::requireHook();
+ $name = $branch->getName();
+ if (substr($name, 0, 1) === '/') {
+ $label = $this->translate('this configuration branch');
+ } else {
+ $label = $name;
+ }
+ $link = $hook->linkToBranch($branch, $auth, $label);
}
- $link = $hook->linkToBranch($branch, $auth, $label);
+
if ($object === null) {
- $this->add(Hint::info(Html::sprintf($this->translate(
- 'This object will be created in %s. It will not be part of any deployment'
- . ' unless being merged'
- ), $link)));
+ $this->add(Hint::$hintMethod(Html::sprintf($this->translate(
+ 'This object will be created in %s.'
+ ) . $deployHint, $link)));
return;
}
if (! $object->hasBeenTouchedByBranch()) {
- $this->add(Hint::info(Html::sprintf($this->translate(
- 'Your changes will be stored in %s. The\'ll not be part of any deployment'
- . ' unless being merged'
- ), $link)));
+ $this->add(Hint::$hintMethod(Html::sprintf($this->translate(
+ 'Your changes are going to be stored in %s.'
+ ) . $deployHint, $link)));
+ return;
+ }
+ if ($main) {
return;
}
diff --git a/library/Director/Web/Widget/BranchedObjectsHint.php b/library/Director/Web/Widget/BranchedObjectsHint.php
index d689178..3f00f9e 100644
--- a/library/Director/Web/Widget/BranchedObjectsHint.php
+++ b/library/Director/Web/Widget/BranchedObjectsHint.php
@@ -13,9 +13,14 @@ class BranchedObjectsHint extends HtmlDocument
{
use TranslationHelper;
- public function __construct(Branch $branch, Auth $auth)
+ public function __construct(Branch $branch, Auth $auth, $hasPreferredBranch = false)
{
if (! $branch->isBranch()) {
+ if ($hasPreferredBranch) {
+ $this->add(Hint::warning($this->translate(
+ "You're currently in the master branch, your changes will make part of the next Deployment"
+ )));
+ }
return;
}
$hook = Branch::requireHook();
diff --git a/library/Director/Web/Widget/DeploymentInfo.php b/library/Director/Web/Widget/DeploymentInfo.php
index 110200f..1f87abc 100644
--- a/library/Director/Web/Widget/DeploymentInfo.php
+++ b/library/Director/Web/Widget/DeploymentInfo.php
@@ -2,6 +2,7 @@
namespace Icinga\Module\Director\Web\Widget;
+use Icinga\Module\Director\Auth\Permission;
use ipl\Html\HtmlDocument;
use Icinga\Authentication\Auth;
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
@@ -55,7 +56,7 @@ class DeploymentInfo extends HtmlDocument
'url' => $request->getUrl()
))->activate('deployment');
- if ($dep->config_checksum !== null && $auth->hasPermission('director/showconfig')) {
+ if ($dep->config_checksum !== null && $auth->hasPermission(Permission::SHOW_CONFIG)) {
$tabs->add('config', array(
'label' => $this->translate('Config'),
'url' => 'director/config/files',
@@ -72,7 +73,8 @@ class DeploymentInfo extends HtmlDocument
protected function createInfoTable()
{
$dep = $this->deployment;
- $table = new NameValueTable();
+ $table = (new NameValueTable())
+ ->addAttributes(['class' => 'deployment-details']);
$table->addNameValuePairs([
$this->translate('Deployment time') => $dep->start_time,
$this->translate('Sent to') => $dep->peer_identity,
@@ -135,16 +137,21 @@ class DeploymentInfo extends HtmlDocument
} else {
return [$this->translate('Unknown, failed to collect related information'), new Icon('help')];
}
- } elseif ($dep->startup_succeeded === 'y') {
- return $this->colored('green', [$this->translate('Succeeded'), new Icon('ok')]);
} else {
- return $this->colored('red', [$this->translate('Failed'), new Icon('cancel')]);
- }
- }
+ $div = Html::tag('div')->setSeparator(' ');
- protected function colored($color, array $content)
- {
- return Html::tag('div', ['style' => "color: $color;"], $content)->setSeparator(' ');
+ if ($dep->startup_succeeded === 'y') {
+ $div
+ ->addAttributes(['class' => 'succeeded'])
+ ->add([$this->translate('Succeeded'), new Icon('ok')]);
+ } else {
+ $div
+ ->addAttributes(['class' => 'failed'])
+ ->add([$this->translate('Failed'), new Icon('cancel')]);
+ }
+
+ return $div;
+ }
}
public function render()
diff --git a/library/Director/Web/Widget/IcingaObjectInspection.php b/library/Director/Web/Widget/IcingaObjectInspection.php
index 61f3567..d9cf69d 100644
--- a/library/Director/Web/Widget/IcingaObjectInspection.php
+++ b/library/Director/Web/Widget/IcingaObjectInspection.php
@@ -205,7 +205,7 @@ class IcingaObjectInspection extends BaseHtmlElement
$this->add(Html::tag('p')->add(Html::sprintf(
'The configuration for this object has been rendered by Icinga'
. ' Director %s to %s',
- DateFormatter::timeAgo(strtotime($deployment->start_time, false)),
+ DateFormatter::timeAgo(strtotime($deployment->start_time)),
$this->linkToSourceLocation($deployment, $source)
)));
}