diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-14 13:17:31 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-14 13:17:31 +0000 |
commit | f66ab8dae2f3d0418759f81a3a64dc9517a62449 (patch) | |
tree | fbff2135e7013f196b891bbde54618eb050e4aaf /library/Director/Web/Table/ObjectsTable.php | |
parent | Initial commit. (diff) | |
download | icingaweb2-module-director-f66ab8dae2f3d0418759f81a3a64dc9517a62449.tar.xz icingaweb2-module-director-f66ab8dae2f3d0418759f81a3a64dc9517a62449.zip |
Adding upstream version 1.10.2.upstream/1.10.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/Director/Web/Table/ObjectsTable.php')
-rw-r--r-- | library/Director/Web/Table/ObjectsTable.php | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/library/Director/Web/Table/ObjectsTable.php b/library/Director/Web/Table/ObjectsTable.php new file mode 100644 index 0000000..792cb6d --- /dev/null +++ b/library/Director/Web/Table/ObjectsTable.php @@ -0,0 +1,315 @@ +<?php + +namespace Icinga\Module\Director\Web\Table; + +use Icinga\Authentication\Auth; +use Icinga\Module\Director\Db; +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 Icinga\Module\Director\Restriction\HostgroupRestriction; +use Icinga\Module\Director\Restriction\ObjectRestriction; +use gipfl\IcingaWeb2\Link; +use gipfl\IcingaWeb2\Table\ZfQueryBasedTable; +use gipfl\IcingaWeb2\Url; +use Ramsey\Uuid\Uuid; +use Zend_Db_Select as ZfSelect; + +class ObjectsTable extends ZfQueryBasedTable +{ + use TableWithBranchSupport; + + /** @var ObjectRestriction[] */ + protected $objectRestrictions; + + protected $columns = [ + 'object_name' => 'o.object_name', + 'object_type' => 'o.object_type', + 'disabled' => 'o.disabled', + 'uuid' => 'o.uuid', + ]; + + protected $searchColumns = ['o.object_name']; + + protected $showColumns = ['object_name' => 'Name']; + + protected $filterObjectType = 'object'; + + protected $type; + + protected $baseObjectUrl; + + /** @var IcingaObject */ + protected $dummyObject; + + protected $leftSubQuery; + + protected $rightSubQuery; + + /** @var Auth */ + private $auth; + + /** + * @param $type + * @param Db $db + * @return static + */ + public static function create($type, Db $db) + { + $class = __NAMESPACE__ . '\\ObjectsTable' . ucfirst($type); + if (! class_exists($class)) { + $class = __CLASS__; + } + + /** @var static $table */ + $table = new $class($db); + $table->type = $type; + return $table; + } + + public function getType() + { + return $this->type; + } + + /** + * @param string $url + * @return $this + */ + public function setBaseObjectUrl($url) + { + $this->baseObjectUrl = $url; + + 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; + return $this; + } + + public function addObjectRestriction(ObjectRestriction $restriction) + { + $this->objectRestrictions[$restriction->getName()] = $restriction; + return $this; + } + + public function getColumns() + { + return $this->columns; + } + + public function getColumnsToBeRendered() + { + return $this->showColumns; + } + + public function filterTemplate( + IcingaObject $template, + $inheritance = Db\IcingaObjectFilterHelper::INHERIT_DIRECT + ) { + IcingaObjectFilterHelper::filterByTemplate( + $this->getQuery(), + $template, + 'o', + $inheritance + ); + + return $this; + } + + protected function getMainLinkLabel($row) + { + return $row->object_name; + } + + protected function renderObjectNameColumn($row) + { + $type = $this->baseObjectUrl; + $url = Url::fromPath("director/${type}", [ + 'uuid' => Uuid::fromBytes($row->uuid)->toString() + ]); + + return static::td(Link::create($this->getMainLinkLabel($row), $url)); + } + + protected function renderExtraColumns($row) + { + $columns = $this->getColumnsToBeRendered(); + unset($columns['object_name']); + $cols = []; + foreach ($columns as $key => & $label) { + $cols[] = static::td($row->$key); + } + + return $cols; + } + + public function renderRow($row) + { + if (isset($row->uuid) && is_resource($row->uuid)) { + $row->uuid = stream_get_contents($row->uuid); + } + $tr = static::tr([ + $this->renderObjectNameColumn($row), + $this->renderExtraColumns($row) + ]); + + $classes = $this->getRowClasses($row); + if ($row->disabled === 'y') { + $classes[] = 'disabled'; + } + if (! empty($classes)) { + $tr->getAttributes()->add('class', $classes); + } + + return $tr; + } + + 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 []; + } + + protected function applyObjectTypeFilter(ZfSelect $query, ZfSelect $right = null) + { + if ($right) { + $right->where( + 'bo.object_type = ?', + $this->filterObjectType + ); + } + return $query->where( + 'o.object_type = ?', + $this->filterObjectType + ); + } + + protected function applyRestrictions(ZfSelect $query) + { + foreach ($this->getRestrictions() as $restriction) { + $restriction->applyToQuery($query); + } + + return $query; + } + + protected function getRestrictions() + { + if ($this->objectRestrictions === null) { + $this->objectRestrictions = $this->loadRestrictions(); + } + + return $this->objectRestrictions; + } + + protected function loadRestrictions() + { + /** @var Db $db */ + $db = $this->connection(); + $auth = $this->getAuth(); + + return [ + new HostgroupRestriction($db, $auth), + new FilterByNameRestriction($db, $auth, $this->getDummyObject()->getShortTableName()) + ]; + } + + /** + * @return IcingaObject + */ + protected function getDummyObject() + { + if ($this->dummyObject === null) { + $type = $this->getType(); + $this->dummyObject = IcingaObject::createByType($type); + } + return $this->dummyObject; + } + + protected function prepareQuery() + { + $table = $this->getDummyObject()->getTableName(); + if ($this->branchUuid) { + $this->columns['branch_uuid'] = 'bo.branch_uuid'; + } + + $columns = $this->getColumns(); + if ($this->branchUuid) { + $columns = $this->branchifyColumns($columns); + $this->stripSearchColumnAliases(); + } + $query = $this->db()->select()->from(['o' => $table], $columns); + + if ($this->branchUuid) { + $right = clone($query); + // Hint: Right part has only those with object = null + // This means that restrictions on $right would hide all + // new rows. Dedicated restriction logic for the branch-only + // part of thw union are not required, we assume that restrictions + // for new objects have been checked once they have been created + $query = $this->applyRestrictions($query); + /** @var Db $conn */ + $conn = $this->connection(); + $query->joinLeft( + ['bo' => "branched_$table"], + // TODO: PgHexFunc + $this->db()->quoteInto( + 'bo.uuid = o.uuid AND bo.branch_uuid = ?', + $conn->quoteBinary($this->branchUuid->getBytes()) + ), + [] + )->where("(bo.branch_deleted IS NULL OR bo.branch_deleted = 'n')"); + $this->applyObjectTypeFilter($query, $right); + $right->joinRight( + ['bo' => "branched_$table"], + 'bo.uuid = o.uuid', + [] + ) + ->where('o.uuid IS NULL') + ->where('bo.branch_uuid = ?', $conn->quoteBinary($this->branchUuid->getBytes())); + $this->leftSubQuery = $query; + $this->rightSubQuery = $right; + $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 { + $this->applyObjectTypeFilter($query); + $query->order('o.object_name')->limit(100); + } + + return $query; + } + + public function removeQueryLimit() + { + $query = $this->getQuery(); + $query->reset($query::LIMIT_OFFSET); + $query->reset($query::LIMIT_COUNT); + + return $this; + } +} |