diff options
Diffstat (limited to '')
-rw-r--r-- | application/controllers/NavigationController.php | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/application/controllers/NavigationController.php b/application/controllers/NavigationController.php new file mode 100644 index 0000000..b0babc3 --- /dev/null +++ b/application/controllers/NavigationController.php @@ -0,0 +1,447 @@ +<?php +/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */ + +namespace Icinga\Controllers; + +use Exception; +use Icinga\Application\Config; +use Icinga\Exception\NotFoundError; +use Icinga\Data\DataArray\ArrayDatasource; +use Icinga\Data\Filter\FilterMatchCaseInsensitive; +use Icinga\Forms\ConfirmRemovalForm; +use Icinga\Forms\Navigation\NavigationConfigForm; +use Icinga\Web\Controller; +use Icinga\Web\Form; +use Icinga\Web\Menu; +use Icinga\Web\Navigation\Navigation; +use Icinga\Web\Notification; +use Icinga\Web\Url; + +/** + * Navigation configuration + */ +class NavigationController extends Controller +{ + /** + * The global navigation item type configuration + * + * @var array + */ + protected $itemTypeConfig; + + /** + * {@inheritdoc} + */ + public function init() + { + parent::init(); + $this->itemTypeConfig = Navigation::getItemTypeConfiguration(); + } + + /** + * Return the label for the given navigation item type + * + * @param string $type + * + * @return string $type if no label can be found + */ + protected function getItemLabel($type) + { + return isset($this->itemTypeConfig[$type]['label']) ? $this->itemTypeConfig[$type]['label'] : $type; + } + + /** + * Return a list of available navigation item types + * + * @return array + */ + protected function listItemTypes() + { + $types = array(); + foreach ($this->itemTypeConfig as $type => $options) { + $types[$type] = isset($options['label']) ? $options['label'] : $type; + } + + return $types; + } + + /** + * Return all shared navigation item configurations + * + * @param string $owner A username if only items shared by a specific user are desired + * + * @return array + */ + protected function fetchSharedNavigationItemConfigs($owner = null) + { + $configs = array(); + foreach ($this->itemTypeConfig as $type => $_) { + $config = Config::navigation($type); + $config->getConfigObject()->setKeyColumn('name'); + $query = $config->select(); + if ($owner !== null) { + $query->applyFilter(new FilterMatchCaseInsensitive('owner', '=', $owner)); + } + + foreach ($query as $itemConfig) { + $configs[] = $itemConfig; + } + } + + return $configs; + } + + /** + * Return all user navigation item configurations + * + * @param string $username + * + * @return array + */ + protected function fetchUserNavigationItemConfigs($username) + { + $configs = array(); + foreach ($this->itemTypeConfig as $type => $_) { + $config = Config::navigation($type, $username); + $config->getConfigObject()->setKeyColumn('name'); + foreach ($config->select() as $itemConfig) { + $configs[] = $itemConfig; + } + } + + return $configs; + } + + /** + * Show the current user a list of his/her navigation items + */ + public function indexAction() + { + $user = $this->Auth()->getUser(); + $ds = new ArrayDatasource(array_merge( + $this->fetchSharedNavigationItemConfigs($user->getUsername()), + $this->fetchUserNavigationItemConfigs($user->getUsername()) + )); + $query = $ds->select(); + + $this->view->types = $this->listItemTypes(); + $this->view->items = $query; + + $this->view->title = $this->translate('Navigation'); + $this->getTabs() + ->add( + 'account', + array( + 'title' => $this->translate('Update your account'), + 'label' => $this->translate('My Account'), + 'url' => 'account' + ) + ) + ->add( + 'navigation', + array( + 'active' => true, + 'title' => $this->translate('List and configure your own navigation items'), + 'label' => $this->translate('Navigation'), + 'url' => 'navigation' + ) + ) + ->add( + 'devices', + array( + 'title' => $this->translate('List of devices you are logged in'), + 'label' => $this->translate('My Devices'), + 'url' => 'my-devices' + ) + ); + $this->setupSortControl( + array( + 'type' => $this->translate('Type'), + 'owner' => $this->translate('Shared'), + 'name' => $this->translate('Navigation') + ), + $query + ); + } + + /** + * List all shared navigation items + */ + public function sharedAction() + { + $this->assertPermission('config/navigation'); + $ds = new ArrayDatasource($this->fetchSharedNavigationItemConfigs()); + $query = $ds->select(); + + $removeForm = new Form(); + $removeForm->setUidDisabled(); + $removeForm->setAttrib('class', 'inline'); + $removeForm->addElement('hidden', 'name', array( + 'decorators' => array('ViewHelper') + )); + $removeForm->addElement('hidden', 'redirect', array( + 'value' => Url::fromPath('navigation/shared'), + 'decorators' => array('ViewHelper') + )); + $removeForm->addElement('button', 'btn_submit', array( + 'escape' => false, + 'type' => 'submit', + 'class' => 'link-button spinner', + 'value' => 'btn_submit', + 'decorators' => array('ViewHelper'), + 'label' => $this->view->icon('trash'), + 'title' => $this->translate('Unshare this navigation item') + )); + + $this->view->removeForm = $removeForm; + $this->view->types = $this->listItemTypes(); + $this->view->items = $query; + + $this->view->title = $this->translate('Shared Navigation'); + $this->getTabs()->add( + 'navigation/shared', + array( + 'title' => $this->translate('List and configure shared navigation items'), + 'label' => $this->translate('Shared Navigation'), + 'url' => 'navigation/shared' + ) + )->activate('navigation/shared'); + $this->setupSortControl( + array( + 'type' => $this->translate('Type'), + 'owner' => $this->translate('Owner'), + 'name' => $this->translate('Shared Navigation') + ), + $query + ); + } + + /** + * Add a navigation item + */ + public function addAction() + { + $form = new NavigationConfigForm(); + $form->setRedirectUrl('navigation'); + $form->setUser($this->Auth()->getUser()); + $form->setItemTypes($this->listItemTypes()); + $form->addDescription($this->translate('Create a new navigation item, such as a menu entry or dashlet.')); + + // TODO: Fetch all "safe" parameters from the url and populate them + $form->setDefaultUrl(rawurldecode($this->params->get('url', ''))); + + $form->setOnSuccess(function (NavigationConfigForm $form) { + $data = $form::transformEmptyValuesToNull($form->getValues()); + + try { + $form->add($data); + } catch (Exception $e) { + $form->error($e->getMessage()); + return false; + } + + if ($form->save()) { + if ($data['type'] === 'menu-item') { + $form->getResponse()->setRerenderLayout(); + } + + Notification::success(t('Navigation item successfully created')); + return true; + } + + return false; + }); + $form->handleRequest(); + + $this->view->title = $this->translate('Navigation'); + $this->renderForm($form, $this->translate('New Navigation Item')); + } + + /** + * Edit a navigation item + */ + public function editAction() + { + $itemName = $this->params->getRequired('name'); + $itemType = $this->params->getRequired('type'); + $referrer = $this->params->get('referrer', 'index'); + + $user = $this->Auth()->getUser(); + if ($user->can('config/navigation')) { + $itemOwner = $this->params->get('owner', $user->getUsername()); + } else { + $itemOwner = $user->getUsername(); + } + + $form = new NavigationConfigForm(); + $form->setUser($user); + $form->setShareConfig(Config::navigation($itemType)); + $form->setUserConfig(Config::navigation($itemType, $itemOwner)); + $form->setRedirectUrl($referrer === 'shared' ? 'navigation/shared' : 'navigation'); + $form->setOnSuccess(function (NavigationConfigForm $form) use ($itemName) { + $data = $form::transformEmptyValuesToNull($form->getValues()); + + try { + $form->edit($itemName, $data); + } catch (NotFoundError $e) { + throw $e; + } catch (Exception $e) { + $form->error($e->getMessage()); + return false; + } + + if ($form->save()) { + if (isset($data['type']) && $data['type'] === 'menu-item') { + $form->getResponse()->setRerenderLayout(); + } + + Notification::success(sprintf(t('Navigation item "%s" successfully updated'), $itemName)); + return true; + } + + return false; + }); + + try { + $form->load($itemName); + $form->handleRequest(); + } catch (NotFoundError $_) { + $this->httpNotFound(sprintf($this->translate('Navigation item "%s" not found'), $itemName)); + } + + $this->view->title = $this->translate('Navigation'); + $this->renderForm($form, $this->translate('Update Navigation Item')); + } + + /** + * Remove a navigation item + */ + public function removeAction() + { + $itemName = $this->params->getRequired('name'); + $itemType = $this->params->getRequired('type'); + $user = $this->Auth()->getUser(); + + $navigationConfigForm = new NavigationConfigForm(); + $navigationConfigForm->setUser($user); + $navigationConfigForm->setShareConfig(Config::navigation($itemType)); + $navigationConfigForm->setUserConfig(Config::navigation($itemType, $user->getUsername())); + + $form = new ConfirmRemovalForm(); + $form->setRedirectUrl('navigation'); + $form->setOnSuccess(function (ConfirmRemovalForm $form) use ($itemName, $navigationConfigForm) { + try { + $itemConfig = $navigationConfigForm->delete($itemName); + } catch (NotFoundError $e) { + Notification::success(sprintf(t('Navigation Item "%s" not found. No action required'), $itemName)); + return true; + } catch (Exception $e) { + $form->error($e->getMessage()); + return false; + } + + if ($navigationConfigForm->save()) { + if ($itemConfig->type === 'menu-item') { + $form->getResponse()->setRerenderLayout(); + } + + Notification::success(sprintf(t('Navigation Item "%s" successfully removed'), $itemName)); + return true; + } + + return false; + }); + $form->handleRequest(); + + $this->view->title = $this->translate('Navigation'); + $this->renderForm($form, $this->translate('Remove Navigation Item')); + } + + /** + * Unshare a navigation item + */ + public function unshareAction() + { + $this->assertPermission('config/navigation'); + $this->assertHttpMethod('POST'); + + // TODO: I'd like these being form fields + $itemType = $this->params->getRequired('type'); + $itemOwner = $this->params->getRequired('owner'); + + $navigationConfigForm = new NavigationConfigForm(); + $navigationConfigForm->setUser($this->Auth()->getUser()); + $navigationConfigForm->setShareConfig(Config::navigation($itemType)); + $navigationConfigForm->setUserConfig(Config::navigation($itemType, $itemOwner)); + + $form = new Form(array( + 'onSuccess' => function ($form) use ($navigationConfigForm) { + $itemName = $form->getValue('name'); + + try { + $newConfig = $navigationConfigForm->unshare($itemName); + if ($navigationConfigForm->save()) { + if ($newConfig->getSection($itemName)->type === 'menu-item') { + $form->getResponse()->setRerenderLayout(); + } + + Notification::success(sprintf( + t('Navigation item "%s" has been unshared'), + $form->getValue('name') + )); + } else { + // TODO: It failed obviously to write one of the configs, so we're leaving the user in + // a inconsistent state. Luckily, it's nothing lost but possibly duplicated... + Notification::error(sprintf( + t('Failed to unshare navigation item "%s"'), + $form->getValue('name') + )); + } + } catch (NotFoundError $e) { + throw $e; + } catch (Exception $e) { + Notification::error($e->getMessage()); + } + + $redirect = $form->getValue('redirect'); + if (! empty($redirect)) { + $form->setRedirectUrl(htmlspecialchars_decode($redirect)); + } + + return true; + } + )); + $form->setUidDisabled(); + $form->setSubmitLabel('btn_submit'); // Required to ensure that isSubmitted() is called + $form->addElement('hidden', 'name', array('required' => true)); + $form->addElement('hidden', 'redirect'); + + try { + $form->handleRequest(); + } catch (NotFoundError $_) { + $this->httpNotFound(sprintf($this->translate('Navigation item "%s" not found'), $form->getValue('name'))); + } + } + + public function dashboardAction() + { + $name = $this->params->getRequired('name'); + + $this->getTabs()->add('dashboard', array( + 'active' => true, + 'label' => ucwords($name), + 'url' => Url::fromRequest() + )); + + $menu = new Menu(); + + $navigation = $menu->findItem($name); + + if ($navigation === null) { + $this->httpNotFound($this->translate('Navigation not found')); + } + + $this->view->navigation = $navigation; + $this->view->title = $navigation->getLabel(); + } +} |