summaryrefslogtreecommitdiffstats
path: root/application/controllers/NavigationController.php
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--application/controllers/NavigationController.php447
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();
+ }
+}