diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-14 13:17:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-14 13:17:48 +0000 |
commit | e6d4dfc040bbe3cb80a2ce65b82493b557f751fc (patch) | |
tree | 40bd6366b01b06f4d96fc8638f23a772263cb5e9 /library/Director/Web/Controller | |
parent | Releasing progress-linux version 1.10.2-2~progress7.99u1. (diff) | |
download | icingaweb2-module-director-e6d4dfc040bbe3cb80a2ce65b82493b557f751fc.tar.xz icingaweb2-module-director-e6d4dfc040bbe3cb80a2ce65b82493b557f751fc.zip |
Merging upstream version 1.11.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/Director/Web/Controller')
8 files changed, 122 insertions, 279 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())); |